diff --git a/.env b/.env
deleted file mode 100644
index 35922126745597afdcd4fd2015ae42930f6c5d8a..0000000000000000000000000000000000000000
--- a/.env
+++ /dev/null
@@ -1,6 +0,0 @@
-SIP_AUTH_PAPPERLAWEB_CLIENT_ID=pub_staging_website_website
-SIP_AUTH_PAPPERLAWEB_CLIENT_SECRET=MzrytATFFEZkTHmNjoMGFNbor
-SIP_AUTH_OIDC_ISSUER=https://auth.vseth.ethz.ch/auth/realms/VSETH
-
-NEXTAUTH_URL=http://localhost:3000
-NEXTAUTH_SECRET=asdf
diff --git a/.eslintrc.json b/.eslintrc.json
index bffb357a7122523ec94045523758c4b825b448ef..d2a18faf89f4b23fc45fdb69335630e7643a4a2f 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -1,3 +1,6 @@
 {
-  "extends": "next/core-web-vitals"
+  "extends": "next/core-web-vitals",
+  "rules": {
+    "react/no-unescaped-entities": "off"
+  }
 }
diff --git a/.gitignore b/.gitignore
index 8f322f0d8f49570a594b865ef8916c428a01afc1..45c1abce864b4fd390a16f4a8650a9c0d37827c6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -26,6 +26,7 @@ yarn-error.log*
 
 # local env files
 .env*.local
+.env
 
 # vercel
 .vercel
diff --git a/cinit.yml b/cinit.yml
index 08bb2159b74e955266b2ff56d77d677adc7464ca..820b0475f57e899c4bcbdf671ea84520e2af8b9d 100644
--- a/cinit.yml
+++ b/cinit.yml
@@ -16,6 +16,10 @@ programs:
       - SIP_AUTH_OIDC_ISSUER:
       - SIP_AUTH_WEBSITE_CLIENT_ID:
       - SIP_AUTH_WEBSITE_CLIENT_SECRET:
+      - MAILER_USERNAME:
+      - MAILER_PASSWORD:
+      - MAILER_HOST:
+      - MAILER_NAME:
   - name: 'Update DB Schema'
     workdir: '/website'
     path: 'bash'
@@ -30,4 +34,4 @@ programs:
       - SIP_MYSQL_ALT_SERVER:
       - SIP_MYSQL_ALT_PORT:
       - NEXTAUTH_URL:
-      - NEXTAUTH_SECRET:
+      - NEXTAUTH_SECRET:	
\ No newline at end of file
diff --git a/components/.navbar.jsx.swp b/components/.navbar.jsx.swp
deleted file mode 100644
index d07d131f2c2b7fb6ae14e67462c1725bf5d851fe..0000000000000000000000000000000000000000
Binary files a/components/.navbar.jsx.swp and /dev/null differ
diff --git a/components/about.jsx b/components/about.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..5b32fc86c92e41495dc81834c9a79fd4b0eb4e40
--- /dev/null
+++ b/components/about.jsx
@@ -0,0 +1,93 @@
+import dynamic from "next/dynamic";
+
+const OfficeMap = dynamic(() => import("../components/map"), {
+  ssr: false,
+});
+
+import Image from "next/image";
+import { useRouter } from "next/router";
+
+import { useTranslation } from "next-i18next";
+
+import parse from "html-react-parser";
+
+import { Alert, Button, Card, Grid, Space } from "@mantine/core";
+
+import { Icon, ICONS } from "vseth-canine-ui";
+
+import ContactForm from "../components/contactForm";
+import BoardMemberCard from "../components/boardMemberCard";
+
+import board from "../content/board.json";
+import about from "../content/about.json";
+
+export default function About() {
+  const { t } = useTranslation("common");
+  const { locale } = useRouter();
+
+  return (
+    <>
+      <h1>{t("about")}</h1>
+
+      <Grid style={{ justifyContent: "center" }}>
+        {board.map((entry, i) => (
+          <Grid.Col
+            key={i}
+            md={3}
+            sm={4}
+            xs={6}
+            style={{ display: "flex", flexDirection: "column" }}
+          >
+            <BoardMemberCard entry={entry} />
+          </Grid.Col>
+        ))}
+      </Grid>
+
+      <Space h="xl" />
+      <Space h="xl" />
+      <section id="address">
+        <Grid>
+          <Grid.Col md={4} sm={6} xs={12}>
+            <Alert title={t("aboutUs")}>
+              {about.description[locale || "en"]}
+            </Alert>
+            <Space h="md" />
+
+            <b>TheAlternative</b>
+            {about.address.map((line, i) => (
+              <p key={i} style={{ marginBottom: 0 }}>
+                {line}
+              </p>
+            ))}
+
+            <Space h="xs" />
+            {/* stolen from here: https://stackoverflow.com/questions/33577448/is-there-a-way-to-do-array-join-in-react */}
+            {about.links
+              .map((link, i) => (
+                <a target="_blank" href={link.url} key={i}>
+                  {link.text}
+                </a>
+              ))
+              .reduce(
+                (acc, x) =>
+                  acc === null ? (
+                    x
+                  ) : (
+                    <>
+                      {acc} | {x}
+                    </>
+                  ),
+                null
+              )}
+          </Grid.Col>
+          <Grid.Col md={4} sm={6} xs={12}>
+            <OfficeMap />
+          </Grid.Col>
+          <Grid.Col md={4} sm={6} xs={12}>
+            <ContactForm />
+          </Grid.Col>
+        </Grid>
+      </section>
+    </>
+  );
+}
diff --git a/components/bashguide.jsx b/components/bashguide.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..c68ec4bfc33f3b5459388cc08306a6ef7ee7452e
--- /dev/null
+++ b/components/bashguide.jsx
@@ -0,0 +1,2053 @@
+export default function BashGuide() {
+  return (
+    <>
+      {/* start pandoc */}
+      <h1 data-number={1} id="bash-quick-guide">
+        <span className="header-section-number">1</span> Bash Quick Guide
+      </h1>
+      <p>
+        Bash is an acronym for Bourne Again Shell. It is based on the Bourne
+        shell and is mostly compatible with its features.
+      </p>
+      <p>
+        Shells are command interpreters. They are applications that provide
+        users with the ability to give commands to their operating system
+        interactively, or to execute batches of commands quickly. In no way are
+        they required for the execution of programs; they are merely a layer
+        between system function calls and the user.
+      </p>
+      <p>
+        Think of a shell as a way for you to speak to your system. Your system
+        doesn’t need it for most of its work, but it is an excellent interface
+        between you and what your system can offer. It allows you to perform
+        basic math, run basic tests and execute applications. More importantly,
+        it allows you to combine these operations and connect applications to
+        each other to perform complex and automated tasks.
+      </p>
+      <p>
+        Bash is not your operating system. It is not your window manager. It is
+        not your terminal (but it often runs inside your terminal). It does not
+        control your mouse or keyboard. It does not configure your system,
+        activate your screen-saver, or open your files. It’s important to
+        understand that bash is only an interface for you to execute statements
+        (using bash syntax), either at the interactive bash prompt or via bash
+        scripts. The things that <em>actually happen</em> are usually caused by
+        other programs.
+      </p>
+      <p>
+        This guide is based on{" "}
+        <a href="http://mywiki.wooledge.org/BashGuide">
+          the bash guide in GreyCat’s wiki
+        </a>{" "}
+        and aims to be more concise, while still being accurate. It was produced
+        specifically for the Bash Workshop by{" "}
+        <a href="www.thealternative.ch">TheAlternative.ch</a>.
+      </p>
+      <p>
+        It is published under the{" "}
+        <a href="http://creativecommons.org/licenses/by-nc-sa/4.0/">
+          CC by-nc-sa 4.0 license
+        </a>
+        .
+      </p>
+      <h1 data-number={2} id="commands-and-arguments">
+        <span className="header-section-number">2</span> Commands and Arguments
+      </h1>
+      <p>
+        Bash reads commands from its input, which can be either a file or your
+        terminal. In general, each line is interpreted as a command followed by
+        its arguments.
+      </p>
+      <pre>
+        <code>
+          ls{"\n"}touch file1 file2 file3{"\n"}ls -l{"\n"}rm file1 file2 file3
+        </code>
+      </pre>
+      <p>
+        The first word is always the command that is executed. All subsequent
+        words are given to that command as argument.
+      </p>
+      <p>
+        Note that <em>options</em>, such as the <code>-l</code> option in the
+        example above, are not treated specially by bash. They are arguments
+        like any other. It is up to the program (<code>ls</code> in the above
+        case) to treat it as an option.
+      </p>
+      <p>
+        Words are delimited by whitespace (spaces or tabs). It does not matter
+        how many spaces there are between two words. For example, try
+      </p>
+      <pre>
+        <code>echo Hello{"            "}World</code>
+      </pre>
+      <p>
+        The process of splitting a line of text into words is called{" "}
+        <em>word splitting</em>. It is vital to be aware of it, especially when
+        you come across expansions later on.
+      </p>
+      <h2 data-number="2.1" id="preventing-word-splitting">
+        <span className="header-section-number">2.1</span> Preventing Word
+        Splitting
+      </h2>
+      <p>
+        Sometimes, you will want to pass arguments to commands that contain
+        whitespace. To do so, you can use quotes:
+      </p>
+      <pre>
+        <code>touch "Filename with spaces"</code>
+      </pre>
+      <p>
+        This command creates a single file named <em>Filename with spaces</em>.
+        The text within double quotes is protected from word splitting and hence
+        treated as a single word.
+      </p>
+      <p>Note that you can also use single quotes:</p>
+      <pre>
+        <code>touch 'Another filename with spaces'</code>
+      </pre>
+      <p>There is, however, an important difference between the two:</p>
+      <ul>
+        <li>
+          Double quotes prevent <strong>word splitting</strong>
+        </li>
+        <li>
+          Single quotes prevent <strong>word splitting and expansion</strong>
+        </li>
+      </ul>
+      <p>
+        When you use single quotes, the quoted text will never be changed by
+        bash. With double quotes, expansion will still happen. This doesn’t make
+        a difference in the above example, but as soon as you e.g.&nbsp;use
+        variables, it becomes important.
+      </p>
+      <p>
+        In general, it is considered good practice to use single quotes whenever
+        possible, and double quotes only when expansion is desired. In that
+        sense, the last example above can be considered “more correct”.
+      </p>
+      <h2 data-number="2.2" id="the-importance-of-spaces">
+        <span className="header-section-number">2.2</span> The Importance of
+        Spaces
+      </h2>
+      <p>
+        Bash contains various keywords and built-ins that aren’t immediately
+        recognizable as commands, such as the new test command:
+      </p>
+      <pre>
+        <code>[[ -f file ]]</code>
+      </pre>
+      <p>
+        The above code tests whether a file named “file” exists in the current
+        directory. Just like every line of bash code, it consists of a command
+        followed by its arguments. Here, the command is <code>[[</code>, while
+        the arguments are <code>-f</code>, <code>file</code> and <code>]]</code>
+        .
+      </p>
+      <p>
+        Many programmers of other languages would write the above command like
+        so:
+      </p>
+      <pre>
+        <code>[[-f file]]</code>
+      </pre>
+      <p>
+        This, though, is wrong: Bash will look for a command named{" "}
+        <code>[[-f</code>, which doesn’t exist, and issue an error message. This
+        kind of mistake is very common for beginners. It is advisable to always
+        use spaces after any kind of brackets in bash, even though there are
+        cases where they are not necessary.
+      </p>
+      <h2 data-number="2.3" id="scripts">
+        <span className="header-section-number">2.3</span> Scripts
+      </h2>
+      <p>
+        You have probably interacted with bash through a terminal before. You
+        would see a bash prompt, and you would issue one command after another.
+      </p>
+      <p>
+        Bash scripts are basically a sequence of commands stored in a file. They
+        are read and processed in order, one after the other.
+      </p>
+      <p>
+        Making a script is easy. Begin by making a new file, and put this on the
+        first line:
+      </p>
+      <pre>
+        <code>#!/bin/bash</code>
+      </pre>
+      <p>
+        This line is called an <em>interpreter directive</em>, or more commonly,
+        a <em>hashbang</em> or <em>shebang</em>. Your operating system uses it
+        to determine how this file can be run. In this case, the file is to be
+        run using <code>bash</code>, which is stored in the <code>/bin/</code>{" "}
+        directory.
+      </p>
+      <p>
+        After the shebang, you can add any command that you could also use in
+        your terminal. For example, you could add
+      </p>
+      <pre>
+        <code>echo 'Hello World'</code>
+      </pre>
+      <p>and then save the file as “myscript”</p>
+      <p>You can now run the file from the terminal by typing</p>
+      <pre>
+        <code>bash myscript</code>
+      </pre>
+      <p>
+        Here, you explicitly called bash and made it execute the script.{" "}
+        <code>bash</code> is used as the command, while <code>myscript</code> is
+        an argument. However, it’s also possible to use <code>myscript</code> as
+        a command directly.
+      </p>
+      <p>To do so, you must first make it executable:</p>
+      <pre>
+        <code>chmod +x myscript</code>
+      </pre>
+      <p>
+        Now that you have permission to execute this script directly, you can
+        type
+      </p>
+      <pre>
+        <code>./myscript</code>
+      </pre>
+      <p>to run it.</p>
+      <p>
+        The <code>./</code> is required to tell bash that the executable is
+        located in the current directory, rather than the system directory. We
+        will come back to this in the chapter on Variables.
+      </p>
+      <h1 data-number={3} id="variables-and-parameters">
+        <span className="header-section-number">3</span> Variables and
+        Parameters
+      </h1>
+      <p>
+        Variables and parameters can be used to store strings and retrieve them
+        later. <em>Variables</em> are the ones you create yourself, while{" "}
+        <em>special parameters</em> are pre-set by bash. <em>Parameters</em>{" "}
+        actually refers to both, but is often used synonymously to special
+        parameters.
+      </p>
+      <p>
+        To store a string in a variable, we use the <em>assignment syntax</em>:
+      </p>
+      <pre>
+        <code>varname=vardata</code>
+      </pre>
+      <p>
+        This sets the variable <code>varname</code> to contain the string{" "}
+        <code>vardata</code>.
+      </p>
+      <p>
+        Note that you cannot use spaces around the <code>=</code> sign. With the
+        spaces, bash would assume <code>varname</code> to be a command and then
+        pass <code>=</code> and <code>vardata</code> as arguments.
+      </p>
+      <p>
+        To access the string that is now stored in the variable{" "}
+        <code>varname</code>, we have to use <em>parameter expansion</em>. This
+        is the most common kind of expansion: A variable is replaced with its
+        content.
+      </p>
+      <p>If you want to print the variable’s value, you can type</p>
+      <pre>
+        <code>echo $varname</code>
+      </pre>
+      <p>
+        The <code>$</code> indicates that you want to use expansion on{" "}
+        <code>varname</code>, meaning it is replaced by its content. Note that
+        expansion happens before the command is run. Here’s what happens
+        step-by-step:
+      </p>
+      <ul>
+        <li>
+          Bash uses variable expansion, changing <code>echo $varname</code> to{" "}
+          <code>echo vardata</code>
+        </li>
+        <li>
+          Then, bash runs <code>echo</code> with <code>vardata</code> as its
+          parameter.
+        </li>
+      </ul>
+      <p>
+        The most important thing here is that{" "}
+        <strong>variable expansion happens before wordsplitting</strong>. That
+        means, if you have defined a variable like this:
+      </p>
+      <pre>
+        <code>myfile='bad song.mp3'</code>
+      </pre>
+      <p>and then run the command</p>
+      <pre>
+        <code>rm $myfile</code>
+      </pre>
+      <p>bash will expand this to</p>
+      <pre>
+        <code>rm bad song.mp3</code>
+      </pre>
+      <p>
+        Only now, word splitting occurs, and bash will call <code>rm</code> with
+        two arguments: <code>bad</code> and <code>song.mp3</code>. If you now
+        had a file called <code>song.mp3</code> in your current directory, that
+        one would be deleted instead.
+      </p>
+      <p>To prevent this from happening, you can use double quotes:</p>
+      <pre>
+        <code>rm "$myfile"</code>
+      </pre>
+      <p>This will be expanded to</p>
+      <pre>
+        <code>rm "bad song.mp3"</code>
+      </pre>
+      <p>
+        which is what we want. In this case, you have to use double quotes, as
+        single quotes would prevent expansion from happening altogether.
+      </p>
+      <p>
+        Not quoting variable and parameter expansions is a very common mistake
+        even among advanced bash programmers. It can cause bugs that are hard to
+        find and can be very dangerous.{" "}
+        <strong>Always quote your variable expansions.</strong>
+      </p>
+      <p>
+        You can also use variable expansions inside the variable assignment
+        itself. Consider this example:
+      </p>
+      <pre>
+        <code>
+          myvariable='blah'{"\n"}myvariable="$myvariable blah"{"\n"}echo
+          "$myvariable"
+        </code>
+      </pre>
+      <p>What will the output of this script be?</p>
+      <p>
+        First, the variable <code>myvariable</code> will get the value{" "}
+        <code>blah</code>. Then, <code>myvariable</code> is assigned to again,
+        which overwrites its former content. The assignment contains a variable
+        expansion, <code>"$myvariable blah"</code>. This is expanded to{" "}
+        <code>"blah blah"</code>, and that is going to be the new value of{" "}
+        <code>myvariable</code>. So the last command is expanded to{" "}
+        <code>echo "blah blah"</code>, and the output of the script is{" "}
+        <code>blah blah</code>.
+      </p>
+      <h2 data-number="3.1" id="special-parameters">
+        <span className="header-section-number">3.1</span> Special Parameters
+      </h2>
+      <p>
+        <em>Special parameters</em> are variables that are set by bash itself.
+        Most of those variables can’t be written to and they contain useful
+        information.
+      </p>
+      <table>
+        <colgroup>
+          <col style={{ width: "12%" }} />
+          <col style={{ width: "12%" }} />
+          <col style={{ width: "75%" }} />
+        </colgroup>
+        <thead>
+          <tr className="header">
+            <th>Parameter Name</th>
+            <th>Usage</th>
+            <th>Description</th>
+          </tr>
+        </thead>
+        <tbody>
+          <tr className="odd">
+            <td>
+              <code>0</code>
+            </td>
+            <td>
+              <code>"$0"</code>
+            </td>
+            <td>Contains the name of the current script</td>
+          </tr>
+          <tr className="even">
+            <td>
+              <code>1</code> <code>2</code> <code>3</code> etc.
+            </td>
+            <td>
+              <code>"$1"</code> etc.
+            </td>
+            <td>
+              Contains the arguments that were passed to the current script. The
+              number indicates the position of that argument (first, second…).
+              These parameters are also called positional parameters.
+            </td>
+          </tr>
+          <tr className="odd">
+            <td>
+              <code>*</code>
+            </td>
+            <td>
+              <code>"$*"</code>
+            </td>
+            <td>
+              Contains all the positional parameters. Double quoted, it expands
+              to a single word containing them all.
+            </td>
+          </tr>
+          <tr className="even">
+            <td>
+              <code>@</code>
+            </td>
+            <td>
+              <code>"$@"</code>
+            </td>
+            <td>
+              Contains all the positional parameters. Double quoted, it expands
+              to{" "}
+              <strong>several words, where each word is one parameter</strong>.
+              This is special syntax, it behaves differently from “normal”
+              expansion in quotes. It retains the arguments exactly as they were
+              passed to the script.
+            </td>
+          </tr>
+          <tr className="odd">
+            <td>
+              <code>#</code>
+            </td>
+            <td>
+              <code>"$#"</code>
+            </td>
+            <td>
+              Contains the number of parameters that were passed to the script
+            </td>
+          </tr>
+          <tr className="even">
+            <td>
+              <code>?</code>
+            </td>
+            <td>
+              <code>"$?"</code>
+            </td>
+            <td>Contains the exit code of the last executed command</td>
+          </tr>
+        </tbody>
+      </table>
+      <h2 data-number="3.2" id="environment-variables">
+        <span className="header-section-number">3.2</span> Environment Variables
+      </h2>
+      <p>
+        <em>Environment variables</em> are special variables that are already
+        set when you start bash. In fact, these variables aren’t specific to
+        bash - they are available in every program that runs on your system and
+        they can affect your system’s behaviour.
+      </p>
+      <p>
+        You can use the command <code>printenv</code> in your terminal to
+        display all the environment variables you have currently set. Most of
+        them contain some system configuration, like the variable{" "}
+        <code>LANG</code>, which designates your preferred language. Some
+        variables, like <code>TERM</code>, <code>BROWSER</code> or{" "}
+        <code>SHELL</code>, designate your preferred default programs (terminal,
+        web browser and shell, respectively. These may not be set on all
+        systems).
+      </p>
+      <p>
+        Some of these variables can be useful in your scripts. For example, the
+        variable <code>RANDOM</code> gives you a different random number every
+        time you read it.
+      </p>
+      <p>
+        Another important environment variable is <code>PATH</code>. It contains
+        a bunch of file paths, separated by colons. These paths designate where
+        your system will look for executables when you type a command. For
+        example, if you type <code>grep</code> in your terminal, your system
+        will search for an executable called <code>grep</code> in the
+        directories designated in your <code>PATH</code> variable. As soon as it
+        finds one, it will execute that. If it doesn’t find it, you will get a
+        “command not found” error message.
+      </p>
+      <p>
+        You can modify your environment variables, if you want. The guideline
+        here is to only mess with those variables of which you know what they
+        do, otherwise you might break something.
+      </p>
+      <p>
+        The place to modify these variables is your <code>~/.bash_profile</code>{" "}
+        file. This file contains some bash code that is executed whenever you
+        log in. For example, you could add the following line:
+      </p>
+      <pre>
+        <code>export BROWSER="firefox"</code>
+      </pre>
+      <p>
+        This would set your default browser to firefox. Note that on some
+        systems, there are other settings–for example in your Desktop
+        Environment–which can override these environment variables. You’ll have
+        to test whether this works.
+      </p>
+      <p>
+        Note the <code>export</code> keyword. This is a bash builtin that takes
+        a variable definition as its argument and puts it in your{" "}
+        <em>environment</em>. If you omit this, your new variable will just be
+        an ordinary variable, rather than an environment variable.
+      </p>
+      <h2 data-number="3.3" id="ambiguous-names">
+        <span className="header-section-number">3.3</span> Ambiguous Names
+      </h2>
+      <p>
+        Say you have a variable called <code>name</code> that is declared as
+        follows:
+      </p>
+      <pre>
+        <code>name='bat'</code>
+      </pre>
+      <p>
+        Now, you want to use this variable in order to print <em>batman</em>:
+      </p>
+      <pre>
+        <code>echo "$nameman"</code>
+      </pre>
+      <p>
+        If you try this, you will notice that it doesn’t work–that is because
+        bash will now look for a variable called <code>nameman</code>, which
+        doesn’t exist. Here’s what you can do instead:
+      </p>
+      <pre>
+        <code>
+          echo "${"{"}name{"}"}man"
+        </code>
+      </pre>
+      <p>
+        The curly braces tell bash where the variable name ends. This allows you
+        to add more characters at the end of a variable’s content.
+      </p>
+      <h1 data-number={4} id="globbing">
+        <span className="header-section-number">4</span> Globbing
+      </h1>
+      <p>
+        <em>Globs</em> are an important bash concept–mostly for their incredible
+        convenience. They are patterns that can be used to match filenames or
+        other strings.
+      </p>
+      <p>
+        Globs are composed of normal characters and metacharacters.
+        Metacharacters are characters that have a special meaning. These are the
+        metacharacters that can be used in globs:
+      </p>
+      <ul>
+        <li>
+          <code>*</code>: Matches any string, including the empty string
+          (i.e.&nbsp;nothing)
+        </li>
+        <li>
+          <code>?</code>: Matches any single character
+        </li>
+        <li>
+          <code>[...]</code>: Matches any one of the characters enclosed in the
+          brackets
+        </li>
+      </ul>
+      <p>
+        Bash sees the glob, for example <code>a*</code>. It expands this glob,
+        by looking in the current directory and matching it against all files
+        there. Any filenames that match the glob are gathered up and sorted, and
+        then the list of filenames is used in place of the glob. So if you have
+        three files <code>a</code>, <code>b</code> and <code>albert</code> in
+        the current directory, the glob is expanded to <code>a albert</code>.
+      </p>
+      <p>
+        A glob always has to match the entire filename. That means{" "}
+        <code>a*</code> will match <code>at</code> but not <code>bat</code>.
+      </p>
+      <p>
+        Note that globbing is special in that it happens{" "}
+        <em>after word splitting</em>. This means you never need to worry about
+        spaces in filenames when you use globbing, and quoting globs is not
+        necessary. In fact, quotes will prevent globbing from happening.
+      </p>
+      <h1 data-number={5} id="expansion">
+        <span className="header-section-number">5</span> Expansion
+      </h1>
+      <p>
+        We’ve already seen <em>parameter and variable expansion</em>, but that’s
+        not the only kind of expansion that happens in bash. In this chapter,
+        we’ll look at all kinds of expansion that aren’t covered elsewhere.
+      </p>
+      <h2 data-number="5.1" id="expansions-and-quotes">
+        <span className="header-section-number">5.1</span> Expansions and Quotes
+      </h2>
+      <p>
+        You already know that it is important to quote parameter and variable
+        expansions, but we also told you that quoting globs–which are, in fact,
+        just another form of expansion–is not necessary. So, which expansions
+        need to be quoted?
+      </p>
+      <p>The rule of thumb here is as follows:</p>
+      <ul>
+        <li>
+          Always quote <strong>paramater expansion</strong>,{" "}
+          <strong>command substitution</strong> and{" "}
+          <strong>arithmetic expansion</strong>
+        </li>
+        <li>
+          Never quote <strong>brace expansion</strong>,{" "}
+          <strong>tilde expansion</strong> and <strong>globs</strong>
+        </li>
+      </ul>
+      <p>
+        The handy thing here is: All the expansions that require quoting have a{" "}
+        <code>$</code> in their syntax. Parameter expansion is simply a{" "}
+        <code>$</code> followed by a parameter name. Command substitution starts
+        with a <code>$(</code>, and arithmetic expansion starts with{" "}
+        <code>$((</code>.
+      </p>
+      <p>
+        So, the rule of thumb breaks down to the following:{" "}
+        <strong>If there’s a dollar, you probably need quotes.</strong>
+      </p>
+      <p>
+        Now, what if you want to use two kinds of expansion in the same line,
+        but one requires quotes and the other doesn’t? Consider the following
+        script:
+      </p>
+      <pre>
+        <code>prefix='my picture'{"\n"}rm ~/pictures/$prefix*</code>
+      </pre>
+      <p>
+        Here, we use tilde expansion, parameter expansion and globbing in order
+        to remove all files that start with <code>my picture</code> in the
+        folder <code>/home/username/pictures/</code>. But because quotes prevent
+        tilde expansion and globbing, we cannot quote the entire expression.
+        This means that the parameter expansion, too, goes unquoted–and this is
+        fatal, because our variable contains a space. So what should we do?
+      </p>
+      <p>
+        The important thing to realize here is that quoting simply prevents word
+        splitting, but it does not actually designate something as a single
+        string. So we can do the following:
+      </p>
+      <pre>
+        <code>prefix='my picture'{"\n"}rm ~/pictures/"$prefix"*</code>
+      </pre>
+      <p>
+        Only the parameter expansion is quoted, so it is protected from word
+        splitting. But that does not automatically separate it from the rest of
+        the string. Note that there are no spaces between <code>"$prefix"</code>{" "}
+        and <code>~/pictures/</code>. Since word splitting only happens when
+        there are spaces, the entire thing will not be split. Here’s what
+        happens, in order:
+      </p>
+      <p>First, tilde expansion occurs:</p>
+      <pre>
+        <code>rm /home/username/pictures/"$prefix"/*</code>
+      </pre>
+      <p>Next, parameter expansion:</p>
+      <pre>
+        <code>rm /home/username/pictures/"my picture"*</code>
+      </pre>
+      <p>
+        At this point, word splitting happens. But since the only space in our
+        argument is in quotes, the argument remains intact.
+      </p>
+      <p>And last, globbing:</p>
+      <pre>
+        <code>
+          rm /home/username/pictures/"my picture"001.jpg
+          /home/username/pictures/"my picture"002.jpg
+        </code>
+      </pre>
+      <p>
+        Now, there’s one last step that happens which we didn’t mention before.
+        It’s called <em>quote removal</em>. All the quotes that were needed to
+        prevent word splitting are now ignored, which means that the arguments
+        that are finally given to <code>rm</code> are:
+      </p>
+      <ul>
+        <li>
+          <code>/home/username/pictures/my picture001.jpg</code>
+        </li>
+        <li>
+          <code>/home/username/pictures/my picture002.jpg</code>
+        </li>
+      </ul>
+      <p>and this is exactly what we wanted.</p>
+      <p>
+        So, remember: Quotes don’t need to be at the beginning or end of an
+        argument, and if you use several kinds of expansion together, you can
+        add quotes in the middle as required.
+      </p>
+      <h2 data-number="5.2" id="expansion-order">
+        <span className="header-section-number">5.2</span> Expansion Order
+      </h2>
+      <p>
+        All the kinds of expansion happen in a certain order. The order is as
+        follows:
+      </p>
+      <ul>
+        <li>Brace expansion</li>
+        <li>Tilde expansion</li>
+        <li>Parameter and variable expansion</li>
+        <li>Command substitution</li>
+        <li>Arithmetic expansion</li>
+        <li>Word splitting</li>
+        <li>Globbing</li>
+      </ul>
+      <h2 data-number="5.3" id="brace-expansion">
+        <span className="header-section-number">5.3</span> Brace Expansion
+      </h2>
+      <p>
+        <em>Brace expansions</em> are often used in conjunction with globs, but
+        they also have other uses. They always expand to all possible
+        permutations of their contents. Here’s an example:
+      </p>
+      <pre>
+        <code>
+          $ echo th{"{"}e,a{"}"}n{"\n"}then than{"\n"}$ echo {"{"}1..9{"}"}
+          {"\n"}1 2 3 4 5 6 7 8 9{"\n"}$ echo {"{"}0,1{"}"}
+          {"{"}0..9{"}"}
+          {"\n"}00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19
+        </code>
+      </pre>
+      <p>
+        Brace expansions are replaced by a list of words. They are often used in
+        conjunction with globs to match specific files but not others. For
+        example, if you want to delete pictures from your pictures folder with
+        filenames IMG020.jpg through IMG039.jpg, you could use the following
+        pattern:
+      </p>
+      <pre>
+        <code>
+          rm IMG0{"{"}2,3{"}"}*.jpg
+        </code>
+      </pre>
+      <p>Note that we don’t use quotes here. Quotes prevent brace expansion.</p>
+      <p>
+        Brace expansion happens before globbing, so in the above example, the
+        braces are expanded to
+      </p>
+      <pre>
+        <code>rm IMG02*.jpg IMG03*.jpg</code>
+      </pre>
+      <p>
+        We end up with two glob patterns, the first matches IMG020.jpg through
+        IMG029.jpg, and the second matches IMG030.jpg through IMG039.jpg.
+      </p>
+      <h2 data-number="5.4" id="tilde-expansion">
+        <span className="header-section-number">5.4</span> Tilde Expansion
+      </h2>
+      <p>
+        You have probably already seen and used the tilde in the terminal. It is
+        a shortcut to your home directory:
+      </p>
+      <pre>
+        <code>cd ~/files</code>
+      </pre>
+      <p>
+        This will be expanded to <code>cd /home/username/files</code>. Note that
+        tilde expansion only happens outside of quotes, so the following won’t
+        work:
+      </p>
+      <pre>
+        <code>cd "~/files"</code>
+      </pre>
+      <h2 data-number="5.5" id="parameter-and-variable-expansion">
+        <span className="header-section-number">5.5</span> Parameter and
+        Variable Expansion
+      </h2>
+      <p>
+        <em>Parameter and variable expansion</em> is explained in the chapter on
+        Variables and Parameters.
+      </p>
+      <p>
+        An important sidenote here is that Parameter expansion and Variable
+        expansion often refer to the same thing. The official name as per the
+        bash manual is <em>Parameter expansion</em>, but{" "}
+        <em>Variable expansion</em> is often used instead as it is less
+        misleading.
+      </p>
+      <h2 data-number="5.6" id="command-substitution">
+        <span className="header-section-number">5.6</span> Command Substitution
+      </h2>
+      <p>
+        <em>Command substitution</em> is a way of using a command’s output
+        inside your script. For example, let’s say you want to find out where
+        your script is executed, and then move a file to that location.
+      </p>
+      <pre>
+        <code>echo 'I am at'{"\n"}pwd</code>
+      </pre>
+      <p>
+        This script will simply print the directory it is called from. But you
+        want to move a file to that directory, which means you need to use it as
+        an argument to the <code>mv</code> command. For that, you need command
+        substitution:
+      </p>
+      <pre>
+        <code>mv ~/myfile "$( pwd )"</code>
+      </pre>
+      <p>
+        The <code>$(</code> introduces a command substitution. It works
+        similarly to variable expansion, but instead of putting a variable’s
+        content, it puts a command’s output in that place. In this example,{" "}
+        <code>pwd</code> is run, and the output is (for example){" "}
+        <code>/home/username/scripts/</code>. Then, the entire command is
+        expanded to
+      </p>
+      <pre>
+        <code>mv ~/myfile "/home/username/scripts/"</code>
+      </pre>
+      <p>
+        Note that with this kind of expansion, quotes are important. The path
+        returned by <code>pwd</code> might have contained a space, in which case
+        we need the argument to be properly quoted.
+      </p>
+      <h2 data-number="5.7" id="arithmetic-expansion">
+        <span className="header-section-number">5.7</span> Arithmetic Expansion
+      </h2>
+      <p>
+        <em>Arithmetic expansion</em> is explained in the chapter on arithmetic
+        evaluation.
+      </p>
+      <h2 data-number="5.8" id="globbing-1">
+        <span className="header-section-number">5.8</span> Globbing
+      </h2>
+      <p>
+        <em>Globbing</em> is so important, it has a chapter of its own.
+      </p>
+      <h1 data-number={6} id="tests-and-conditionals">
+        <span className="header-section-number">6</span> Tests and Conditionals
+      </h1>
+      <p>
+        Every command you run in your terminal or shell script has a return
+        value. That value is a number, and by convention, a return value of 0
+        means <em>success</em>, while any other number indicates an error.
+      </p>
+      <p>
+        You usually don’t see the return value after running a command. What you
+        do see is the command’s <em>output</em>. If you want to know a command’s
+        return value, you can read it by issuing
+      </p>
+      <pre>
+        <code>echo "$?"</code>
+      </pre>
+      <p>immediately after running that command.</p>
+      <p>
+        While you often don’t need to know a command’s return value, it can be
+        useful to construct conditionals and thereby achieve advanced logic.
+      </p>
+      <h2 data-number="6.1" id="control-operators-and">
+        <span className="header-section-number">6.1</span> Control Operators
+        (&amp;&amp; and ||)
+      </h2>
+      <p>
+        Control operators can be used to make a command’s execution depend on
+        another command’s success. This concept is called{" "}
+        <em>conditional execution</em>:
+      </p>
+      <pre>
+        <code>mkdir folder &amp;&amp; cd folder</code>
+      </pre>
+      <p>
+        In the above example, the <code>&amp;&amp;</code> operator is used to
+        connect two commands <code>mkdir folder</code> and{" "}
+        <code>cd folder</code>. Using this connection, bash will first execute{" "}
+        <code>mkdir folder</code>, and then execute <code>cd folder</code>{" "}
+        <em>only if the first command was successful</em>.
+      </p>
+      <pre>
+        <code>mkdir folder || echo 'Error: could not create folder'</code>
+      </pre>
+      <p>
+        In this example, the <code>||</code> operator is used to connect the
+        commands. Here, the second command is executed{" "}
+        <em>only if the first command failed</em>.
+      </p>
+      <p>
+        It is good practice to make your own scripts return an error
+        (i.e.&nbsp;something other than 0) whenever something goes wrong. To do
+        that, you can use this construct:
+      </p>
+      <pre>
+        <code>mkdir folder || exit 1</code>
+      </pre>
+      <p>
+        The <code>exit</code> command immediately stops the execution of your
+        script and makes it return the number you specified as an argument. In
+        this example, your script will attempt to create a folder. If that goes
+        wrong, it will immediately stop and return 1.
+      </p>
+      <p>
+        Control operators can be written more legibly by spreading them across
+        multiple lines:
+      </p>
+      <pre>
+        <code>
+          mkdir folder \{"\n"}
+          {"    "}|| exit 1
+        </code>
+      </pre>
+      <p>
+        The backslash at the end of the first line makes bash ignore that line
+        break and treat both lines as a single command plus arguments.
+      </p>
+      <h2 data-number="6.2" id="grouping-commands">
+        <span className="header-section-number">6.2</span> Grouping Commands
+      </h2>
+      <p>
+        Now, what if you want to execute multiple commands if the first one
+        fails? Going from the example above, when <code>mkdir folder</code>{" "}
+        fails, you might want to print an error message <em>and</em> return 1.
+      </p>
+      <p>
+        This can be done by enclosing these two commands in single curly braces:
+      </p>
+      <pre>
+        <code>
+          mkdir folder || {"{"} echo 'Could not create folder'; exit 1; {"}"}
+        </code>
+      </pre>
+      <p>
+        The two commands in curly braces are treated as an unit, and if the
+        first command fails, both will be executed.
+      </p>
+      <p>
+        Note that you need to include spaces between the curly braces and the
+        commands. If there were no spaces, bash would look for a command named{" "}
+        <code>{"{"}echo</code> and fail to find it.
+      </p>
+      <p>
+        There’s a semicolon separating the two commands. The semicolon has the
+        same function as a line break: it makes bash consider both parts as
+        individual commands-plus-arguments.
+      </p>
+      <p>The example above could be rewritten as follows:</p>
+      <pre>
+        <code>
+          mkdir folder || {"{"}
+          {"\n"}
+          {"    "}echo 'Could not create folder'{"\n"}
+          {"    "}exit 1{"\n"}
+          {"}"}
+        </code>
+      </pre>
+      <p>
+        Here, no semicolon is required, because there is a line break between
+        the two statements. Line breaks and semicolons can be used
+        interchangeably.
+      </p>
+      <h2 data-number="6.3" id="conditional-blocks-if-and">
+        <span className="header-section-number">6.3</span> Conditional Blocks
+        (if and [[)
+      </h2>
+      <p>
+        <code>if</code> is a shell keyword. It first executes a command and
+        looks at its return value. If it was 0 (success), it executes one list
+        of commands, and if it was something else (failure), it executes
+        another.
+      </p>
+      <p>It looks like this:</p>
+      <pre>
+        <code>
+          if true{"\n"}then {"\n"}
+          {"    "}echo 'It was true'{"\n"}else {"\n"}
+          {"    "}echo 'It was false'{"\n"}fi
+        </code>
+      </pre>
+      <p>
+        <code>true</code> is a bash builtin command that does nothing and
+        returns 0. <code>if</code> will run that command, see that it returned
+        0, and then execute the commands between the <code>then</code> and the{" "}
+        <code>else</code>.
+      </p>
+      <p>
+        In many programming languages, operators such as <code>&gt;</code>,{" "}
+        <code>&lt;</code> or <code>==</code> exist and can be used to compare
+        values. In bash, operators don’t exist. But since comparing values is so
+        common, there’s a special command that can do it:
+      </p>
+      <pre>
+        <code>[[ a = b ]]</code>
+      </pre>
+      <p>
+        <code>[[</code> is a command that takes as its arguments a comparison.
+        The last argument has to be a <code>]]</code>. It is made to look like a
+        comparison in double brackets, but it is, in fact, a command like any
+        other. It is also called the <em>new test command</em>. (The{" "}
+        <em>old test command</em>, often simply called <em>test</em>, exists as
+        well, so be careful not to confuse them).
+      </p>
+      <p>
+        For that reason, the spaces are absolutely needed. You cannot write
+        this:
+      </p>
+      <pre>
+        <code>[[a=b]]</code>
+      </pre>
+      <p>
+        This will make bash look for a command called <code>[[a=b]]</code>,
+        which doesn’t exist.
+      </p>
+      <p>
+        <code>[[</code> does not only support comparing strings. For example,{" "}
+        <code>[[ -f file ]]</code> will test whether a file named “file” exists.
+        Here’s a list of the most common tests you can use with <code>[[</code>:
+      </p>
+      <ul>
+        <li>
+          <code>-e FILE:</code> True if file exists.
+        </li>
+        <li>
+          <code>-f FILE:</code> True if file is a regular file.
+        </li>
+        <li>
+          <code>-d FILE:</code> True if file is a directory.
+        </li>
+        <li>
+          String operators: * <code>-z STRING:</code> True if the string is
+          empty (its length is zero). * <code>-n STRING:</code> True if the
+          string is not empty (its length is not zero). *{" "}
+          <code>STRING = STRING</code>: True if the string matches the glob
+          pattern (if you quote the glob pattern, the strings have to match
+          exactly). * <code>STRING != STRING</code>: True if the string does not
+          match the glob pattern (if you quote the glob pattern, the strings
+          just have to be different). * <code>STRING &lt; STRING</code>: True if
+          the first string sorts before the second. *{" "}
+          <code>STRING &gt; STRING</code>: True if the first string sorts after
+          the second.
+        </li>
+        <li>
+          <code>EXPR -a EXPR</code>: True if both expressions are true (logical
+          AND).
+        </li>
+        <li>
+          <code>EXPR -o EXPR</code>: True if either expression is true (logical
+          OR).
+        </li>
+        <li>
+          <code>! EXPR</code>: Inverts the result of the expression (logical
+          NOT).
+        </li>
+        <li>
+          <code>EXPR &amp;&amp; EXPR</code>: Much like the ‘-a’ operator of
+          test, but does not evaluate the second expression if the first already
+          turns out to be false.
+        </li>
+        <li>
+          <code>EXPR || EXPR</code>: Much like the ‘-o’ operator of test, but
+          does not evaluate the second expression if the first already turns out
+          to be true.
+        </li>
+        <li>
+          Numeric operators:
+          <ul>
+            <li>
+              <code>INT -eq INT</code>: True if both integers are equal.
+            </li>
+            <li>
+              <code>INT -ne INT</code>: True if the integers are not equal.
+            </li>
+            <li>
+              <code>INT -lt INT</code>: True if the first integer is less than
+              the second.
+            </li>
+            <li>
+              <code>INT -gt INT</code>: True if the first integer is greater
+              than the second.
+            </li>
+            <li>
+              <code>INT -le INT</code>: True if the first integer is less than
+              or equal to the second.
+            </li>
+            <li>
+              <code>INT -ge INT</code>: True if the first integer is greater
+              than or equal to the second.
+            </li>
+          </ul>
+        </li>
+      </ul>
+      <p>You might occasionally come across something like this:</p>
+      <pre>
+        <code>[ a = b ]</code>
+      </pre>
+      <p>
+        Here, we use single brackets instead of double brackets. This is, in
+        fact, an entirely different command, the <code>[</code> command or{" "}
+        <em>old test command</em>. It has the same purpose–comparing things–but
+        the <code>[[</code> command is newer, has more features, and is easier
+        to use. We strongly recommend using <code>[[</code> over <code>[</code>.
+      </p>
+      <h2 data-number="6.4" id="conditional-loops-while-until-and-for">
+        <span className="header-section-number">6.4</span> Conditional Loops
+        (while, until and for)
+      </h2>
+      <p>
+        Loops can be used to repeat a list of commands multiple times. In bash,
+        there are <code>while</code> loops and <code>for</code> loops.
+      </p>
+      <p>While loops look like this:</p>
+      <pre>
+        <code>
+          while true{"\n"}do{"\n"}
+          {"    "}echo 'Infinite loop'{"\n"}done
+        </code>
+      </pre>
+      <p>
+        The <code>while</code> keyword will execute the <code>true</code>{" "}
+        command, and if that returns 0, it executes all commands between the{" "}
+        <code>do</code> and <code>done</code>. After that, it starts over, until
+        the <code>true</code> command returns 1 (which it never does, which is
+        why this loop will run indefinitely).
+      </p>
+      <p>
+        The above example might not be immediately useful, but you could also do
+        something like this:
+      </p>
+      <pre>
+        <code>
+          while ping -c 1 -W 1 www.google.com{"\n"}do{"\n"}
+          {"    "}echo 'Google still works!'{"\n"}done
+        </code>
+      </pre>
+      <p>
+        There’s also a variation of the <code>while</code> loop, called{" "}
+        <code>until</code>. It works similarly, except it only runs its command
+        list when the first command <em>fails</em>:
+      </p>
+      <pre>
+        <code>
+          until ping -c 1 -W 1 www.google.com{"\n"}do{"\n"}
+          {"    "}echo 'Google isn'\''t working!'{"\n"}done
+        </code>
+      </pre>
+      <p>
+        <code>for</code> loops can be used to iterate over a list of strings:
+      </p>
+      <pre>
+        <code>
+          for var in 1 2 3{"\n"}do{"\n"}
+          {"    "}echo "$var"{"\n"}done
+        </code>
+      </pre>
+      <p>
+        After the <code>for</code>, you specify a variable name. After the{" "}
+        <code>in</code>, you list all the strings you want to iterate over.
+      </p>
+      <p>
+        The loop works by setting the variable you specified to all the values
+        from the list in turn, and then executing the command list for each of
+        them.
+      </p>
+      <p>
+        This is especially useful in combination with globs or brace expansions:
+      </p>
+      <pre>
+        <code>
+          echo 'This is a list of all my files starting with f:'{"\n"}for var in
+          f*
+          {"\n"}do{"\n"}
+          {"    "}echo "$var"{"\n"}done{"\n"}
+          {"\n"}echo 'And now I will count from 1 to 100:'{"\n"}for var in {"{"}
+          1..100{"}"}
+          {"\n"}do{"\n"}
+          {"    "}echo "$var"{"\n"}done
+        </code>
+      </pre>
+      <h2 data-number="6.5" id="choices-case-and-select">
+        <span className="header-section-number">6.5</span> Choices (case and
+        select)
+      </h2>
+      <p>
+        Sometimes, you want your script to behave differently depending on the
+        content of a variable. This could be implemented by taking a different
+        branch of an if statement for each state:
+      </p>
+      <pre>
+        <code>
+          if [[ "$LANG" = 'en' ]]{"\n"}then{"\n"}
+          {"    "}echo 'Hello!'{"\n"}elif [[ "$LANG" = 'de' ]]{"\n"}then{"\n"}
+          {"    "}echo 'Guten Tag!'{"\n"}elif [[ "$LANG" = 'it' ]]{"\n"}then
+          {"\n"}
+          {"    "}echo 'Ciao!'{"\n"}else{"\n"}
+          {"    "}echo 'I do not speak your language.'{"\n"}fi
+        </code>
+      </pre>
+      <p>
+        This is quite cumbersome to write. At the same time, constructs like
+        this are very common. For that reason, bash provides a keyword to
+        simplify it:
+      </p>
+      <pre>
+        <code>
+          case "$LANG" in{"\n"}
+          {"    "}en){"\n"}
+          {"        "}echo 'Hello!'{"\n"}
+          {"        "};;{"\n"}
+          {"    "}de) {"\n"}
+          {"        "}echo 'Guten Tag!'{"\n"}
+          {"        "};;{"\n"}
+          {"    "}it){"\n"}
+          {"        "}echo 'Ciao!'{"\n"}
+          {"        "};;{"\n"}
+          {"    "}*){"\n"}
+          {"        "}echo 'I do not speak your language.'{"\n"}
+          {"        "};;{"\n"}esac
+        </code>
+      </pre>
+      <p>
+        Each choice of the case statement consists of a string or glob pattern,
+        a <code>)</code>, a list of commands that is to be executed if the
+        string matches the pattern, and two semicolons to denote the end of a
+        list of commands.
+      </p>
+      <p>
+        The string after the keyword <code>case</code> is matched against each
+        glob pattern in order. The list of commands after the first match is
+        executed. After that, execution continues after the <code>esac</code>.
+      </p>
+      <p>
+        Since the string is matched against glob patterns, we can use{" "}
+        <code>*</code> in the end to catch anything that didn’t match before.
+      </p>
+      <p>
+        Another construct of choice is the <code>select</code> construct. It
+        looks and works similarly to a loop, but it also presents the user with
+        a predefined choice. You are encouraged to try running this example
+        yourself:
+      </p>
+      <pre>
+        <code>
+          echo 'Which one of these does not belong in the group?'{"\n"}select
+          choice in Apples Pears Crisps Lemons Kiwis{"\n"}do{"\n"}
+          {"    "}if [[ "$choice" = Crisps ]]{"\n"}
+          {"    "}then{"\n"}
+          {"        "}echo 'Correct! Crisps are not fruit.'{"\n"}
+          {"        "}break{"\n"}
+          {"    "}fi{"\n"}
+          {"    "}echo 'Wrong answer. Try again.'{"\n"}done
+        </code>
+      </pre>
+      <p>
+        The syntax of the <code>select</code> construct is very similar to{" "}
+        <code>for</code> loops. The difference is that instead of setting the
+        variable (<code>choice</code> in this example) to each value in turn,
+        the <code>select</code> construct lets the user choose which value is
+        used next. This also means that a <code>select</code> construct can run
+        indefinitely, because the user can keep selecting new choices. To avoid
+        being trapped in it, we have to explicitly use <code>break</code>.{" "}
+        <code>break</code> is a builtin command that makes bash jump out of the
+        current <code>do</code> block. Execution will continue after the{" "}
+        <code>done</code>. <code>break</code> also works in <code>for</code> and{" "}
+        <code>while</code> loops.
+      </p>
+      <p>
+        As you can see in the example above, we used an <code>if</code> command
+        inside a <code>select</code> command. All of these conditional
+        constructs (<code>if</code>, <code>for</code>, <code>while</code>,{" "}
+        <code>case</code> and <code>select</code>) can be nested indefinitely.
+      </p>
+      <h1 data-number={7} id="input-and-output">
+        <span className="header-section-number">7</span> Input and Output
+      </h1>
+      <p>
+        Input and output in bash is very flexible and, consequentially, complex.
+        We will only look at the most widely used components.
+      </p>
+      <h2 data-number="7.1" id="command-line-arguments">
+        <span className="header-section-number">7.1</span> Command-line
+        Arguments
+      </h2>
+      <p>
+        For many bash scripts, the first input we care about are the arguments
+        given to it via the command line. As we saw in the chapter on
+        Parameters, these arguments are contained in some{" "}
+        <em>special parameters</em>. These are called{" "}
+        <em>positional parameters</em>. The first parameter is referred to with{" "}
+        <code>$1</code>, the second with <code>$2</code>, and so on. After
+        number 9, you have to enclose the numbers in curly braces:{" "}
+        <code>
+          ${"{"}10{"}"}
+        </code>
+        ,{" "}
+        <code>
+          ${"{"}11{"}"}
+        </code>{" "}
+        and so on.
+      </p>
+      <p>
+        In addition to referring to them one at a time, you may also refer to
+        the entire set of positional parameters with the <code>"$@"</code>{" "}
+        substitution. The double quotes here are{" "}
+        <strong>extremely important</strong>. If you don’t use the double
+        quotes, each one of the positional parameters will undergo word
+        splitting and globbing. You don’t want that. By using the quotes, you
+        tell Bash that you want to preserve each parameter as a separate word.
+      </p>
+      <p>
+        There are even more ways to deal with parameters. For example, it is
+        very common for commands to accept <em>options</em>, which are single
+        letters starting with a <code>-</code>. For example, <code>ls -l</code>{" "}
+        calls the <code>ls</code> program with the <code>-l</code> option, which
+        makes it output more information. Usually, multiple options can be
+        combined, as in <code>ls -la</code>, which is equivalent to{" "}
+        <code>ls -l -a</code>.
+      </p>
+      <p>
+        You might want to create your own scripts that accept some options. Bash
+        has the so called <code>getopts</code> builtin command to parse passed
+        options.
+      </p>
+      <pre>
+        <code>
+          while getopts 'hlf:' opt{"\n"}do {"\n"}
+          {"    "}case "$opt" in{"\n"}
+          {"    "}h|\?){"\n"}
+          {"        "}echo 'available options: -h -l -f [filename]'{"\n"}
+          {"        "};;{"\n"}
+          {"    "}f){"\n"}
+          {"        "}file="$OPTARG"{"\n"}
+          {"        "};;{"\n"}
+          {"    "}l){"\n"}
+          {"        "}list=true{"\n"}
+          {"        "};;{"\n"}
+          {"    "}esac{"\n"}done{"\n"}
+          {"\n"}shift "$(( OPTIND - 1 ))"
+        </code>
+      </pre>
+      <p>
+        As you can see, we use <code>getopts</code> within a while loop.{" "}
+        <code>getopts</code> will return 0 as long as there are more options
+        remaining and something else if there are no more options. That makes it
+        perfectly suitable for a loop.
+      </p>
+      <p>
+        <code>getopts</code> takes two arguments, the <em>optstring</em> and the{" "}
+        <em>variable name</em>. The optstring contains all the letters that are
+        valid options. In our example, these are <code>h</code>, <code>l</code>{" "}
+        and <code>f</code>.
+      </p>
+      <p>
+        The <code>f</code> is followed by a colon. This indicates that the f
+        option requires an argument. The script could for example be called like
+        so:
+      </p>
+      <pre>
+        <code>myscript -f file.txt</code>
+      </pre>
+      <p>
+        <code>getopts</code> will set the variable that you specified as its
+        second argument to the letter of the option it found first. If the
+        option required an argument, the variable <code>OPTARG</code> is set to
+        whatever the argument was. In the example above, a case statement is
+        used to react to the different options.
+      </p>
+      <p>
+        There’s also a special option <code>?</code>. Whenever{" "}
+        <code>getopts</code> finds an option that is not present in the
+        optstring, it sets the shell variable (<code>opt</code> in the example)
+        to <code>?</code>. In the case statement above, that triggers the help
+        message.
+      </p>
+      <p>
+        After all options are parsed, the remaining arguments are “moved” such
+        that they are now in <code>$1</code>, <code>$2</code>… even though
+        previously, these positional parameters were occupied by the options.
+      </p>
+      <p>
+        Also note the line <code>shift "$(( OPTIND - 1 ))"</code> at the end.
+        The <code>shift</code> builtin can be used to discard command-line
+        arguments. Its argument is a number and designates how many arguments we
+        want to discard.
+      </p>
+      <p>
+        This is needed because we don’t know how many options the user will pass
+        to our script. If there are more positional parameters after all the
+        options, we have no way of knowing at which number they start.
+        Fortunately, <code>getopts</code> also sets the shell variable{" "}
+        <code>OPTIND</code>, in which it stores the index of the option it’s
+        going to parse next.
+      </p>
+      <p>
+        So after parsing all the option, we just discard the first{" "}
+        <code>OPTIND - 1</code> options, and the remaining arguments now start
+        from <code>$1</code> onwards.
+      </p>
+      <h2 data-number="7.2" id="file-descriptors">
+        <span className="header-section-number">7.2</span> File Descriptors
+      </h2>
+      <p>
+        <em>File descriptors</em> are the way programs refer to files, or other
+        things that work like files (such as pipes, devices, or terminals). You
+        can think of them as pointers that point to data locations. Through
+        these pointers, programs can write to or read from these locations.
+      </p>
+      <p>By default, every program has three file descriptors:</p>
+      <ul>
+        <li>Standard Input (stdin): File Descriptor 0</li>
+        <li>Standard Output (stdout): File Descriptor 1</li>
+        <li>Standard Error (stderr): File Descriptor 2</li>
+      </ul>
+      <p>
+        When you run a script in the terminal, then stdin contains everything
+        you type in that terminal. stdout and stderr both point to the terminal,
+        and everything that is written to these two is displayed as text in the
+        terminal. stdout is where programs send their normal information, and
+        stderr is where they send their error messages.
+      </p>
+      <p>
+        Let’s make these definitions a little more concrete. Consider this
+        example:
+      </p>
+      <pre>
+        <code>
+          echo 'What is your name?'{"\n"}read name{"\n"}echo "Good day, $name.
+          Would you like some tea?"
+        </code>
+      </pre>
+      <p>
+        You already know <code>echo</code>. It simply prints its argument to{" "}
+        <em>stdout</em>. Since stdout is connected to your terminal, you will
+        see that message there.
+      </p>
+      <p>
+        <code>read</code> is a command that reads one line of text from{" "}
+        <em>stdin</em> and stores it in a variable, which we specified to be{" "}
+        <code>name</code>. Because stdin is connected to what you type in your
+        terminal, it will let you type a line of text, and as soon as you press
+        enter, that line will be stored in the variable.
+      </p>
+      <p>So what about stderr? Consider this example:</p>
+      <pre>
+        <code>ehco 'Hello!'</code>
+      </pre>
+      <p>
+        The command <code>ehco</code> does not exist. If you run this, bash will
+        print an error message to <em>stderr</em>. Because stderr is connected
+        to your terminal, you will see that message there.
+      </p>
+      <h2 data-number="7.3" id="redirection">
+        <span className="header-section-number">7.3</span> Redirection
+      </h2>
+      <p>
+        <em>Redirection</em> is the most basic form of input/output manipulation
+        in bash. It is used to change the source or destination of{" "}
+        <em>File descriptors</em>, i.e.&nbsp;connect them to something other
+        than your terminal. For example, you can send a command’s output to a
+        file instead.
+      </p>
+      <pre>
+        <code>
+          echo 'It was a dark and stormy night. Too dark to write.' &gt; story
+        </code>
+      </pre>
+      <p>
+        The <code>&gt;</code> operator begins an <em>output redirection</em>. It
+        redirects the <em>stdout</em> file descriptor of the command to the
+        left, and connects it to a file called “story”. That means if you run
+        this, you will not see the output of <code>echo</code>—after all, stdout
+        no longer points to your terminal.
+      </p>
+      <p>
+        Note that <code>&gt;</code> will just open the file you specify without
+        checking whether it already exists first. If the file already exists,
+        its contents will be overwritten and you will lose whatever was stored
+        in there before. <strong>Be careful.</strong>
+      </p>
+      <p>
+        If you don’t want to overwrite the existing content of a file, but
+        rather append your output to the end of that file, you can use{" "}
+        <code>&gt;&gt;</code> instead of <code>&gt;</code>.
+      </p>
+      <p>
+        Now, let’s look at <em>input redirection</em>. For that, we first
+        introduce a command named <code>cat</code>. <code>cat</code> is often
+        used to display the contents of a file, like so:
+      </p>
+      <pre>
+        <code>cat myfile</code>
+      </pre>
+      <p>
+        If <code>cat</code> is called without an argument, however, it will
+        simply read from <em>stdin</em> and print that directly to{" "}
+        <em>stdout</em>.
+      </p>
+      <p>
+        Try the following: Run <code>cat</code>, without arguments, in your
+        terminal. Then type some characters and hit enter. Can you figure out
+        what is happening?
+      </p>
+      <p>
+        <em>Input redirection</em> uses the <code>&lt;</code> operator. It works
+        as follows:
+      </p>
+      <pre>
+        <code>cat &lt; story</code>
+      </pre>
+      <p>
+        The <code>&lt;</code> operator will take a command’s <em>stdin</em> file
+        descriptor and point it to a file, “story” in this example. This means{" "}
+        <code>cat</code> now ignores your terminal and reads from “story”
+        instead. Note that this has the same effect as typing{" "}
+        <code>cat story</code>.
+      </p>
+      <p>
+        If you want to redirect <em>stderr</em> instead of <em>stdout</em>, you
+        can do as follows:
+      </p>
+      <pre>
+        <code>ehco 'Hello!' 2&gt; errors</code>
+      </pre>
+      <p>
+        If you run this, you won’t see any error message, even though the
+        command <code>ehco</code> doesn’t exist. That’s because <em>stderr</em>{" "}
+        is no longer connected to your terminal, but to a file called “errors”
+        instead.
+      </p>
+      <p>
+        Now that you know about redirection, there is one subtlety that you have
+        to be aware of: You can’t have two file descriptors point to the same
+        file.
+      </p>
+      <p>
+        If you wanted to log a command’s complete output–stdout <em>and</em>{" "}
+        stderr–you might be tempted to do something like this:
+      </p>
+      <pre>
+        <code>mycommand &gt; logfile 2&gt; logfile</code>
+      </pre>
+      <p>
+        However, this is a <strong>bad</strong> idea. The two file descriptors
+        will now both point to the same file <em>independently</em>, which
+        causes them to constantly overwrite each other’s text.
+      </p>
+      <p>
+        If you still want to point both stdout and stderr to the same file, you
+        can do it like this:
+      </p>
+      <pre>
+        <code>mycommand &gt; logfile 2&gt;&amp;1</code>
+      </pre>
+      <p>
+        Here, we use the <code>&gt;&amp;</code> syntax to duplicate file
+        descriptor 1. In this scenario, we no longer have two file descriptors
+        pointing to one file. Instead, we have only one file descriptor that
+        acts as both stdout and stderr at the same time.
+      </p>
+      <p>
+        To help remember the syntax, you can think of <code>&amp;1</code> as
+        “where 1 is”, and of the <code>2&gt;</code> as “point 2 to”. The whole
+        thing, <code>2&gt;&amp;1</code>, then becomes “point 2 to wherever 1
+        is”. This also makes it clear that <code>&gt; logfile</code> has to come{" "}
+        <em>before</em> <code>2&gt;&amp;1</code>: First you point 1 to
+        “logfile”, and only then you can point 2 to where 1 is.
+      </p>
+      <p>
+        There’s also a quick way to completely get rid of a command’s output
+        using redirections. Consider this:
+      </p>
+      <pre>
+        <code>mycommand &gt; /dev/null 2&gt;&amp;1</code>
+      </pre>
+      <p>
+        <code>/dev/null</code> is a special file in your file system that you
+        can write to, but the things you write to it are not stored. So,{" "}
+        <code>mycommand</code>’s output is written somewhere where it’s not
+        stored or processed in any way. It is discarded completely.
+      </p>
+      <p>
+        You could also leave out the <code>2&gt;&amp;1</code>. Then, you’d still
+        see error messages, but discard the normal output.
+      </p>
+      <h2 data-number="7.4" id="pipes">
+        <span className="header-section-number">7.4</span> Pipes
+      </h2>
+      <p>
+        Now that you know how to manipulate <em>file descriptors</em> to direct
+        output to files, it’s time to learn another type of I/O redirection.
+      </p>
+      <p>
+        The <code>|</code> operator can be used to connect one command’s{" "}
+        <em>stdout</em> to another command’s <em>stdin</em>. Have a look at
+        this:
+      </p>
+      <pre>
+        <code>echo 'This is a beautiful day!' | sed 's/beauti/wonder'</code>
+      </pre>
+      <p>
+        The <code>sed</code> command (“sed” is short for “stream editor”) is a
+        utility that can be used to manipulate text “on the fly”. It reads text
+        from stdin, edits it according to some commands, and then prints the
+        result to stdout. It is very powerful. Here, we use it to replace
+        “beauti” with “wonder”.
+      </p>
+      <p>
+        First, the <code>echo</code> command writes some text to it’s stdout.
+        The <code>|</code> operator connected <code>echo</code>’s stout to{" "}
+        <code>sed</code>’s stdin, so everything <code>echo</code> sends there is
+        immediately picked up by <code>sed</code>. <code>sed</code> will then
+        edit the text and print the result to its own stdout. <code>sed</code>’s
+        stdout is still connected to your terminal, so this is what you see.
+      </p>
+      <h1 data-number={8} id="compound-commands">
+        <span className="header-section-number">8</span> Compound Commands
+      </h1>
+      <p>
+        <em>Compound commands</em> is a catch-all phrase covering several
+        different concepts. We’ve already seen <code>if</code>, <code>for</code>
+        , <code>while</code>, <code>case</code>, <code>select</code> and the{" "}
+        <code>[[</code> keyword, which all fall into this category. Now we’ll
+        look at a few more.
+      </p>
+      <h2 data-number="8.1" id="subshells">
+        <span className="header-section-number">8.1</span> Subshells
+      </h2>
+      <p>
+        <em>Subshells</em> can be used to encapsulate a command’s effect. If a
+        command has undesired side effects, you can execute it in a subshell.
+        Once the subshell command ends, all side effects will be gone.
+      </p>
+      <p>
+        To execute a command (or several commands) in a subshell, enclose them
+        in parenthesis:
+      </p>
+      <pre>
+        <code>
+          ( {"\n"}
+          {"    "}cd /tmp {"\n"}
+          {"    "}pwd{"\n"}){"\n"}pwd
+        </code>
+      </pre>
+      <p>
+        The <code>cd</code> and the first <code>pwd</code> commands are executed
+        in a subshell. All side effects in that subshell won’t affect the second{" "}
+        <code>pwd</code> command. Changing the current directory is such a side
+        effect–even though we use <code>cd</code> to go to the <code>/tmp</code>{" "}
+        folder, we jump back to our original folder as soon as the subshell
+        ends.
+      </p>
+      <h2 data-number="8.2" id="command-grouping">
+        <span className="header-section-number">8.2</span> Command Grouping
+      </h2>
+      <p>
+        You can group several commands together by enclosing them in curly
+        braces. This makes bash consider them as a unit with regard to pipes,
+        redirections and control flow:
+      </p>
+      <pre>
+        <code>
+          {"{"}
+          {"\n"}
+          {"    "}echo 'Logfile of my backup'{"\n"}
+          {"    "}rsync -av . /backup{"\n"}
+          {"    "}echo "Backup finished with exit code $#"{"\n"}
+          {"}"} &gt; backup.log 2&gt;&amp;1
+        </code>
+      </pre>
+      <p>
+        This redirects stdout and stderr of <em>all three commands</em> to a
+        file called backup.log. Note that while this looks similar to subshells,
+        it is not the same. Side effects that happen within the curly braces
+        will still be present outside of them.
+      </p>
+      <h2 data-number="8.3" id="arithmetic-evaluation">
+        <span className="header-section-number">8.3</span> Arithmetic Evaluation
+      </h2>
+      <p>
+        So far, we’ve only been manipulating strings in bash. Sometimes, though,
+        it is also necessary to manipulate numbers. This is done through
+        arithmetic evaluation.
+      </p>
+      <p>
+        Say you want to add the numbers 5 and 4. You might do something like
+        this:
+      </p>
+      <pre>
+        <code>a=5+4</code>
+      </pre>
+      <p>
+        However, this will result in the variable <code>a</code> containing the
+        string <code>5+4</code>, rather than the number <code>9</code>. Instead,
+        you should do this:
+      </p>
+      <pre>
+        <code>(( a=5+4 ))</code>
+      </pre>
+      <p>
+        The double parenthesis indicate that something arithmetic is happening.
+        In fact, <code>((</code> is a bash keyword, much like <code>[[</code>.
+      </p>
+      <p>
+        <code>((</code> can also be used to do arithmetic comparison:
+      </p>
+      <pre>
+        <code>
+          if (( 5 &gt; 9 )){"\n"}then{"\n"}
+          {"    "}echo '5 is greater than 9'{"\n"}else {"\n"}
+          {"    "}echo '5 is not greater than 9'{"\n"}fi
+        </code>
+      </pre>
+      <p>
+        It is important not to confuse <code>((</code> and <code>[[</code>.{" "}
+        <code>[[</code> is for comparing strings (among other things), while{" "}
+        <code>((</code> is only for comparing numbers.
+      </p>
+      <p>
+        There’s also <em>arithmetic substitution</em>, which works similarly to{" "}
+        <em>command substitution</em>:
+      </p>
+      <pre>
+        <code>echo "There are $(( 60 * 60 * 24 )) seconds in a day."</code>
+      </pre>
+      <h1 data-number={9} id="functions">
+        <span className="header-section-number">9</span> Functions
+      </h1>
+      <p>
+        Inside a bash script, functions are very handy. They are lists of
+        commands–much like a normal script–except they don’t reside in their own
+        file. They do however take arguments, just like scripts.
+      </p>
+      <p>Functions can be defined like this:</p>
+      <pre>
+        <code>
+          sum() {"{"}
+          {"\n"}
+          {"    "}echo "$1 + $2 = $(( $1 + $2 ))"{"\n"}
+          {"}"}
+        </code>
+      </pre>
+      <p>
+        If you put this in a script file and run it, absolutely nothing will
+        happen. The function <code>sum</code> has been defined, but it is never
+        used.
+      </p>
+      <p>
+        You can use your function like any other command, but you have to define
+        it <em>before</em> you use it:
+      </p>
+      <pre>
+        <code>
+          sum() {"{"}
+          {"\n"}
+          {"    "}echo "$1 + $2 = $(( $1 + $2 ))"{"\n"}
+          {"}"}
+          {"\n"}sum 1 2{"\n"}sum 3 9{"\n"}sum 6283 3141
+        </code>
+      </pre>
+      <p>
+        As you can see, you can use the function <code>sum</code> multiple
+        times, but you only need to define it once. This is useful in larger
+        scripts, where a certain task has to be performed multiple times.
+        Whenever you catch yourself writing the same or very similar code twice
+        in the same script, you should consider using a function.
+      </p>
+      <h1 data-number={10} id="useful-commands">
+        <span className="header-section-number">10</span> Useful Commands
+      </h1>
+      <p>
+        This chapter provides an overview of useful commands that you can use in
+        your scripts. It is nowhere near complete, and serves only to provide a
+        brief overview. If you want to know more about a specific command, you
+        should read its manpage.
+      </p>
+      <p>
+        <strong>grep</strong>
+      </p>
+      <p>
+        <code>grep</code> can be used to search for a string within a file, or
+        within the output of a command.
+      </p>
+      <pre>
+        <code>
+          # searches logfile.txt for lines containing the word error{"\n"}grep
+          'error' logfile.txt{"  "}
+          {"\n"}
+          {"\n"}# searches the directory 'folder' for files {"\n"}# containing
+          the word 'analysis'{"\n"}grep 'analysis' folder/{"   "}
+          {"\n"}
+          {"\n"}# searches the output of 'xrandr' for lines that say
+          'connected'. {"\n"}# only matches whole words, so 'disconnected' will
+          not match.{"\n"}
+          xrandr | grep -w 'connected'{" "}
+        </code>
+      </pre>
+      <p>
+        <code>grep</code> returns 0 if it finds something, and returns an error
+        if it doesn’t. This makes it useful for conditionals.
+      </p>
+      <p>
+        <strong>sed</strong>
+      </p>
+      <p>
+        <code>sed</code> can be used to edit text “on the fly”. It uses its own
+        scripting language to describe modifications to be made to the text,
+        which makes it extremely powerful. Here, we provide examples for the
+        most common usages of sed:
+      </p>
+      <pre>
+        <code>
+          # replaces the first occurrence of 'find' in every line by 'replace'
+          {"\n"}
+          sed 's/find/replace' inputfile {"\n"}
+          {"\n"}# replaces every occurrence of 'find' in every line by 'replace'
+          {"\n"}sed 's/find/replace/g' inputfile {"\n"}
+          {"\n"}# deletes the first occurrence of 'find' in every line{"\n"}sed
+          's/find//' inputfile {"\n"}
+          {"\n"}# deletes every occurrence of 'find' in every line{"\n"}sed
+          's/find//g' inputfile {"\n"}
+          {"\n"}# displays only the 12th line{"\n"}sed '12q;d' inputfile{" "}
+        </code>
+      </pre>
+      <p>
+        <code>sed</code> is often used in combination with pipes to format the
+        output or get rid of unwanted characters.
+      </p>
+      <p>
+        <strong>curl and wget</strong>
+      </p>
+      <p>
+        <code>curl</code> and <code>wget</code> are two commands that can be
+        used to access websites or other content from the web. The difference is
+        that <code>wget</code> will simply download the content to a file, while{" "}
+        <code>curl</code> will output it to the console.
+      </p>
+      <pre>
+        <code>
+          curl http://www.thealternative.ch{"\n"}wget
+          http://files.project21.ch/LinuxDays-Public/16FS-install-guide.pdf
+        </code>
+      </pre>
+      <p>
+        <strong>xrandr</strong>
+      </p>
+      <p>
+        <code>xrandr</code> can be used to manipulate your video outputs,
+        i.e.&nbsp;enabling and disabling monitors or setting their screen
+        resolution and orientation.
+      </p>
+      <pre>
+        <code>
+          # list all available outputs and their status info{"\n"}xrandr{"  "}
+          {"\n"}
+          {"\n"}# enables output HDMI-1{"\n"}xrandr --output HDMI-1 --auto{" "}
+          {"\n"}
+          {"\n"}# puts output HDMI-1 to the left of output LVDS-1{"\n"}xrandr
+          --output HDMI-1 --left-of LVDS-1 {"\n"}
+          {"\n"}# disables output LVDS-1{"\n"}xrandr --output LVDS-1 --off{" "}
+        </code>
+      </pre>
+      <p>
+        <strong>ImageMagick (convert)</strong>
+      </p>
+      <p>
+        The <code>convert</code> command makes it possible to do image
+        processing from the commandline.
+      </p>
+      <pre>
+        <code>
+          # scale fullHDWallpaper.jpg to specified resolution{"\n"}convert
+          fullHDWallpaper.jpg -scale 3200x1800 evenBiggerWallpaper.jpg {"\n"}
+          {"\n"}# "automagically" adjusts the gamma level of somePicture.jpg
+          {"\n"}
+          convert somePicture.jpg -auto-gamma someOtherPicture.jpg {"\n"}
+          {"\n"}# transform image to black and white{"\n"}convert
+          colorfulPicture.jpg -monochrome blackWhitePicture.jpg{" "}
+        </code>
+      </pre>
+      <p>
+        It is extremely powerful and has lots of options. A good resource is the{" "}
+        <a href="http://www.imagemagick.org">official website</a>. It also
+        provides examples for most options.
+      </p>
+      <p>
+        <strong>notify-send</strong>
+      </p>
+      <p>
+        <code>notify-send</code> can be used to display a desktop notification
+        with some custom text:
+      </p>
+      <pre>
+        <code>
+          notify-send 'Battery warning' 'Your battery level is below 10%'
+        </code>
+      </pre>
+      <p>
+        The first argument is the notification’s title, the second is its
+        description.
+      </p>
+      <p>
+        <code>notify-send</code> requires a <em>notification daemon</em> to be
+        running, else it won’t work. Most desktop environments come with a
+        notification daemon set up and running. If you can’t see your
+        notifications, it might be that you don’t have such a daemon.
+      </p>
+      <p>
+        <strong>find</strong>
+      </p>
+      <p>
+        <code>find</code> can be used to find files in a directory structure.
+      </p>
+      <pre>
+        <code>
+          # finds all files in the current directory and all subdirectories that
+          end
+          {"\n"}# in .png{"\n"}find -name '*.png' {"\n"}
+          {"\n"}# finds all files ending in .tmp and removes them. {"{"}
+          {"}"} is replaced by the{"\n"}# file's name when executing the
+          command.
+          {"\n"}# Note that we don't use globbing here, but instead pass the *
+          to find.{"\n"}# find will then interpret the * as a wildcard.{"\n"}
+          find -name '*.tmp' -exec rm '{"{"}
+          {"}"}'{"\n"}
+          {"\n"}# finds all files in the directory 'files' and prints their size
+          and path{"\n"}find 'files/' -printf '%s %p\n'{" "}
+        </code>
+      </pre>
+      <p>
+        <code>find</code> has many options that allow you to perform arbitrary
+        actions on the files it found or pretty-print the output.
+      </p>
+      <p>
+        <strong>sort</strong>
+      </p>
+      <p>
+        <code>sort</code> sorts lines of text files, or lines it reads from{" "}
+        <em>stdin</em>.
+      </p>
+      <pre>
+        <code>
+          sort listOfNames.txt # sorts all lines in listOfNames.txt
+          alphabetically
+        </code>
+      </pre>
+      <p>
+        <strong>head and tail</strong>
+      </p>
+      <p>
+        <code>head</code> and <code>tail</code> can be used to show the
+        beginning or the end of a long stream of text, respectively.
+      </p>
+      <pre>
+        <code>
+          # display the last few lines of the dmesg log{"\n"}dmesg | tail {"\n"}
+          {"\n"}# display only the first few lines of a very long text file
+          {"\n"}
+          head verylongtext.txt{" "}
+        </code>
+      </pre>
+      <p>
+        <strong>jshon</strong>
+      </p>
+      <p>
+        <code>jshon</code> is a very simple command-line json parser. It can
+        read data in json format and return specific values.
+      </p>
+      <p>
+        Its most important options are <code>-e</code> and <code>-a</code>.{" "}
+        <code>-e</code> extracts the value of a given key from a json array or
+        object:
+      </p>
+      <pre>
+        <code>
+          # Find the object with key "title" from a json object stored in the
+          file "json"{"\n"}jshon -e 'title' &lt; 'json'
+        </code>
+      </pre>
+      <p>
+        The <code>-a</code> option maps all remaining options across the
+        currently selected element. It has to be combined with other options,
+        for example the <code>-e</code> option.
+      </p>
+      <pre>
+        <code>
+          # Find the names of all elements stored in the json object in file
+          "json"
+          {"\n"}jshon -a -e 'name' &lt; 'json'
+        </code>
+      </pre>
+      <p>
+        <strong>shuf</strong>
+      </p>
+      <p>
+        <code>shuf</code> randomly permutates the lines of its input,
+        effectively <em>shuffling</em> them.
+      </p>
+      <pre>
+        <code>
+          # Shuffle the lines of file "playlist"{"\n"}shuf 'playlist'{"\n"}
+          {"\n"}# Get a random line from file "quotes"{"\n"}shuf -n 1 'quotes'
+        </code>
+      </pre>
+      <p>
+        <strong>tee</strong>
+      </p>
+      <p>
+        <code>tee</code> takes input from <em>stdin</em> and writes it to a
+        file:
+      </p>
+      <pre>
+        <code>sudo zypper up | tee 'updatelog'</code>
+      </pre>
+      <p>Note that this is equivalent to</p>
+      <pre>
+        <code>sudo zypper up &gt; 'updatelog'</code>
+      </pre>
+      <p>
+        <code>tee</code> is useful when you want to write to a file that
+        requires root access. Then you can do the following:
+      </p>
+      <pre>
+        <code>echo 'some configuration' | sudo tee '/etc/systemconfig'</code>
+      </pre>
+      <p>
+        A normal redirection wouldn’t work in this case, as that would open the
+        file as a normal user instead of root.{" "}
+        <strong>Please be careful when modifying system files.</strong>
+      </p>
+      <p>
+        <strong>sleep</strong>
+      </p>
+      <p>
+        <code>sleep</code> pauses the execution of your script for a number of
+        seconds. It basically takes a number as an argument, then does nothing
+        for that number of seconds, and then returns. It can be useful if you
+        want to make your script do something in a loop, but want to throttle
+        the speed a little.
+      </p>
+      <pre>
+        <code>
+          # prints "Get back to work" once per second. {"\n"}# Note that 'true'
+          is a command that always returns 0.{"\n"}while true{"\n"}do{"\n"}
+          {"    "}echo 'Get back to work!'{"\n"}
+          {"    "}sleep 1{"\n"}done
+        </code>
+      </pre>
+      <p>
+        <strong>mplayer or mpv</strong>
+      </p>
+      <p>
+        <code>mplayer</code> and <code>mpv</code> are media players that can be
+        used from the console. <code>mpv</code> is based on <code>mplayer</code>{" "}
+        and a lot more modern, but they can do essentially the same.
+      </p>
+      <pre>
+        <code>
+          # play file "music.mp3"{"\n"}mplayer 'music.mp3'{"\n"}mpv 'music.mp3'
+          {"\n"}
+          {"\n"}# play file "alarm.mp3" in an infinite loop{"\n"}mplayer -loop 0
+          'alarm.mp3'{"\n"}mplayer --loop=inf 'alarm.mp3'{"\n"}
+          {"\n"}# play a youtube video{"\n"}# this only works with mpv and
+          requires youtube-dl to be installed{"\n"}mpv
+          'https://www.youtube.com/watch?v=lAIGb1lfpBw'
+        </code>
+      </pre>
+      <p>
+        <strong>xdotool</strong>
+      </p>
+      <p>
+        <code>xdotool</code> can simulate keypresses. With this command, you can
+        write macros that perform actions for you. It allows you to write
+        scripts that interact with GUI programs.
+      </p>
+      <pre>
+        <code>
+          # press ctrl+s (in order to save a document){"\n"}xdotool key
+          'Control+s'
+          {"\n"}
+          {"\n"}# type "hello"{"\n"}xdotool type 'hello'
+        </code>
+      </pre>
+      {/* end pandoc */}
+    </>
+  );
+}
diff --git a/components/boardMemberCard.jsx b/components/boardMemberCard.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..e77bc6bdcf00928fa6aad35c65add761ed93ac70
--- /dev/null
+++ b/components/boardMemberCard.jsx
@@ -0,0 +1,56 @@
+import { useRouter } from "next/router";
+
+import { Avatar, Button, Paper, Text, useMantineTheme } from "@mantine/core";
+
+import { Icon, ICONS } from "vseth-canine-ui";
+
+import { getAccentColor } from "../utilities/colors";
+
+export default function BoardMemberCard({ entry }) {
+  const theme = useMantineTheme();
+  const { locale, push } = useRouter();
+
+  const sendMail = (address) => {
+    push("mailto:" + address);
+  };
+
+  return (
+    <Paper
+      radius="md"
+      withBorder
+      p="lg"
+      style={{
+        display: "flex",
+        flexDirection: "column",
+        justifyContent: "space-between",
+        flexGrow: 1,
+      }}
+      shadow="sm"
+    >
+      <div>
+        <Avatar src={entry.image} size={120} radius={20} mx="auto" />
+        <Text ta="center" fz="lg" weight={500} mt="md">
+          {entry.name}
+        </Text>
+        <Text ta="center" c="dimmed" fz="sm">
+          {entry.mail ? entry.mail.replace("@", " [ät] ") + " • " : ""}
+          {entry.role[locale || "en"]}
+        </Text>
+      </div>
+
+      {entry.mail && (
+        <div>
+          <Button
+            leftIcon={<Icon icon={ICONS.EMAIL} color={getAccentColor(theme)} />}
+            variant="default"
+            fullWidth
+            mt="md"
+            onClick={() => sendMail(entry.mail)}
+          >
+            Send message
+          </Button>
+        </div>
+      )}
+    </Paper>
+  );
+}
diff --git a/components/contactForm.jsx b/components/contactForm.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..3bdc8285b0c07882bc7ddb7a76aaf4c18141ad25
--- /dev/null
+++ b/components/contactForm.jsx
@@ -0,0 +1,118 @@
+import { useState } from "react";
+
+import { useTranslation } from "next-i18next";
+
+import axios from "axios";
+
+import {
+  Alert,
+  Button,
+  Checkbox,
+  Grid,
+  Space,
+  Textarea,
+  TextInput,
+} from "@mantine/core";
+import { showNotification } from "@mantine/notifications";
+
+export default function ContactForm() {
+  const { t } = useTranslation("common");
+
+  const [name, setName] = useState("");
+  const [mail, setMail] = useState("");
+  const [message, setMessage] = useState("");
+  const [human, setHuman] = useState(false);
+  const [robot, setRobot] = useState(false);
+
+  const handleSubmit = async () => {
+    if (!validate()) {
+      showNotification({
+        title: t("formIncomplete"),
+        message: t("formIncompleteText"),
+        color: "red",
+      });
+      return;
+    }
+
+    const response = await axios.post("/api/contact", {
+      name: name,
+      mail: mail,
+      message: message,
+      human: human,
+      robot: robot,
+    });
+
+    if (response.data.message == "mailSuccess") {
+      showNotification({
+        title: t("mailSuccess"),
+        message: t("mailSuccessText"),
+        color: "green",
+      });
+    } else {
+      showNotification({
+        title: t("mailFailure"),
+        message: t("mailFailureText"),
+        color: "red",
+      });
+    }
+  };
+
+  const validate = () => {
+    if (name == "") return false;
+    if (mail == "") return false;
+    if (message == "") return false;
+    return true;
+  };
+
+  return (
+    <>
+      <Grid>
+        <Grid.Col xs={12} sm={6}>
+          <TextInput
+            value={name}
+            onChange={(e) => setName(e.target.value)}
+            label={t("name")}
+            withAsterisk
+            placeholder="Maxime Musterfrau"
+          />
+        </Grid.Col>
+        <Grid.Col xs={12} sm={6}>
+          <TextInput
+            value={mail}
+            onChange={(e) => setMail(e.target.value)}
+            label={t("mail")}
+            withAsterisk
+            placeholder="maxmu@student.ethz.ch"
+          />
+        </Grid.Col>
+        <Grid.Col xs={12}>
+          <Textarea
+            value={message}
+            onChange={(e) => setMessage(e.target.value)}
+            label={t("message")}
+            withAsterisk
+            minRows={5}
+          />
+        </Grid.Col>
+        <Grid.Col xs={12}>
+          <Checkbox
+            value={human}
+            onChange={() => setHuman(!human)}
+            label={t("human")}
+          />
+          <Space h="xs" />
+          <Checkbox
+            value={robot}
+            onChange={() => setRobot(!robot)}
+            label={t("robot")}
+          />
+        </Grid.Col>
+        <Grid.Col xs={12}>
+          <Button onClick={handleSubmit} variant="contained">
+            {t("submit")}
+          </Button>
+        </Grid.Col>
+      </Grid>
+    </>
+  );
+}
diff --git a/components/editor.jsx b/components/editor.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..7bceb145eb3a2747abf346da506a92e8bc3893e3
--- /dev/null
+++ b/components/editor.jsx
@@ -0,0 +1,39 @@
+import { RichTextEditor } from "@mantine/tiptap";
+
+export default function Editor({ editor }) {
+  return (
+    <RichTextEditor editor={editor}>
+      <RichTextEditor.Toolbar sticky>
+        <RichTextEditor.ControlsGroup>
+          <RichTextEditor.Bold />
+          <RichTextEditor.Italic />
+          <RichTextEditor.Underline />
+          <RichTextEditor.Strikethrough />
+          <RichTextEditor.ClearFormatting />
+          <RichTextEditor.Code />
+        </RichTextEditor.ControlsGroup>
+
+        <RichTextEditor.ControlsGroup>
+          <RichTextEditor.H1 />
+          <RichTextEditor.H2 />
+          <RichTextEditor.H3 />
+          <RichTextEditor.H4 />
+        </RichTextEditor.ControlsGroup>
+
+        <RichTextEditor.ControlsGroup>
+          <RichTextEditor.Blockquote />
+          <RichTextEditor.Hr />
+          <RichTextEditor.BulletList />
+          <RichTextEditor.OrderedList />
+        </RichTextEditor.ControlsGroup>
+
+        <RichTextEditor.ControlsGroup>
+          <RichTextEditor.Link />
+          <RichTextEditor.Unlink />
+        </RichTextEditor.ControlsGroup>
+      </RichTextEditor.Toolbar>
+
+      <RichTextEditor.Content />
+    </RichTextEditor>
+  );
+}
diff --git a/components/eventCard.jsx b/components/eventCard.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..8aa3daa92b72dc839b0a394f6b7949ccbd41c5cb
--- /dev/null
+++ b/components/eventCard.jsx
@@ -0,0 +1,213 @@
+import { useRouter } from "next/router";
+
+import { useSession, signIn } from "next-auth/react";
+
+import { useTranslation } from "next-i18next";
+
+import {
+  Alert,
+  Button,
+  Card,
+  Group,
+  List,
+  Space,
+  useMantineTheme,
+} from "@mantine/core";
+
+import { Icon, ICONS } from "vseth-canine-ui";
+
+import parse from "html-react-parser";
+
+import hasAccess from "../utilities/hasAccess";
+import { getAccentColor } from "../utilities/colors";
+import { formatDateFromDB, formatTimeFromDB } from "../utilities/dates";
+import { isRegistered } from "../utilities/signUp";
+
+import { gql, useMutation } from "@apollo/client";
+
+const addSignUpMutation = gql`
+  mutation addSignUp($id: Int) {
+    addSignUp(id: $id)
+  }
+`;
+
+const removeSignUpMutation = gql`
+  mutation removeSignUp($id: Int) {
+    removeSignUp(id: $id)
+  }
+`;
+
+export default function EventCard({
+  event,
+  setEvent,
+  setOpen,
+  refetch,
+  setSignUpOpen,
+}) {
+  const [addSignUp] = useMutation(addSignUpMutation);
+  const [removeSignUp] = useMutation(removeSignUpMutation);
+
+  const { data: session } = useSession();
+  const { t } = useTranslation("common");
+  const theme = useMantineTheme();
+
+  const { locale } = useRouter();
+
+  const accentColor = getAccentColor(theme);
+  const signedUp = isRegistered(session, event);
+
+  const signUp = async (id) => {
+    if (!session) signIn();
+    await addSignUp({
+      variables: {
+        id: event.id,
+      },
+    });
+    refetch();
+  };
+
+  const signOff = async (id) => {
+    await removeSignUp({
+      variables: {
+        id: event.id,
+      },
+    });
+    refetch();
+  };
+
+  const editEvent = (event) => {
+    setEvent(event);
+    setOpen(true);
+  };
+
+  const viewSignUps = (event) => {
+    setEvent(event);
+    setSignUpOpen(true);
+  };
+
+  return (
+    <Card
+      shadow="md"
+      radius="md"
+      style={{
+        display: "flex",
+        justifyContent: "space-between",
+        flexDirection: "column",
+        width: "100%",
+        color: event.isStammtisch ? "gray" : "",
+      }}
+      withBorder
+    >
+      <div>
+        <Group>
+          <h2 style={{ margin: 0 }}>{event.title}</h2>
+        </Group>
+
+        {signedUp && (
+          <>
+            <Space h="xs" />
+            <Alert
+              color="green"
+              variant="light"
+              icon={<Icon icon={ICONS.CHECK} color="green" />}
+              title={t("signedUpTitle")}
+            >
+              {t("signedUpText")}
+            </Alert>
+          </>
+        )}
+
+        <Space h="lg" />
+        <List
+          spacing="md"
+          size="md"
+          center
+          style={{ color: event.isStammtisch ? "gray" : "" }}
+        >
+          {event.speaker && (
+            <List.Item
+              icon={<Icon icon={ICONS.USER} color="#f28a20" size={16} />}
+            >
+              <p>{event.speaker}</p>
+            </List.Item>
+          )}
+          <List.Item
+            icon={<Icon icon={ICONS.LOCATION} color="#f28a20" size={16} />}
+          >
+            <p>{event.place}</p>
+          </List.Item>
+          <List.Item
+            icon={<Icon icon={ICONS.CALENDAR} color="#f28a20" size={16} />}
+          >
+            <p>{formatDateFromDB(event.date, locale)}</p>
+          </List.Item>
+          <List.Item
+            icon={<Icon icon={ICONS.CLOCK} color="#f28a20" size={16} />}
+          >
+            <p>{formatTimeFromDB(event.startTime, event.endTime)}</p>
+          </List.Item>
+        </List>
+        <Space h="lg" />
+
+        <p>{parse(event.description)}</p>
+      </div>
+      <div>
+        {!event.isStammtisch && (
+          <Group style={{ verticalAlign: "middle", marginTop: "20px" }}>
+            {event.signUp ? (
+              <Button
+                href={event.signUp}
+                target="_blank"
+                rightIcon={<Icon icon={ICONS.RIGHT} color="#f28a20" />}
+                component="a"
+              >
+                {t("externalSignUp")}
+              </Button>
+            ) : (
+              <>
+                {signedUp ? (
+                  <Button
+                    onClick={() => signOff(event.id)}
+                    leftIcon={<Icon icon={ICONS.USER_MINUS} color="white" />}
+                  >
+                    {t("signOff")}
+                  </Button>
+                ) : (
+                  <Button
+                    onClick={() => signUp(event.id)}
+                    leftIcon={<Icon icon={ICONS.USER_PLUS} color="#f28a20" />}
+                    style={{ color: "#f28a20" }}
+                  >
+                    {t("signUp")}
+                  </Button>
+                )}
+              </>
+            )}
+          </Group>
+        )}
+        <Group grow mt="md" style={{ verticalAlign: "middle" }}>
+          {hasAccess(session, true) && (
+            <>
+              <Button
+                leftIcon={<Icon icon={ICONS.EDIT} color={accentColor} />}
+                variant="light"
+                onClick={() => editEvent(event)}
+              >
+                {t("editEvent")}
+              </Button>
+              {!event.isStammtisch && (
+                <Button
+                  leftIcon={<Icon icon={ICONS.LIST} color={accentColor} />}
+                  variant="light"
+                  onClick={() => viewSignUps(event)}
+                >
+                  {t("viewParticipants")}
+                </Button>
+              )}
+            </>
+          )}
+        </Group>
+      </div>
+    </Card>
+  );
+}
diff --git a/components/eventModal.jsx b/components/eventModal.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..30222b2a77c3715d5fdcf984b746cfed7a148457
--- /dev/null
+++ b/components/eventModal.jsx
@@ -0,0 +1,276 @@
+import { useEffect } from "react";
+
+import { useTranslation } from "next-i18next";
+
+import {
+  Button,
+  Checkbox,
+  Divider,
+  Grid,
+  Modal,
+  Select,
+  Space,
+  Text,
+  Textarea,
+  TextInput,
+} from "@mantine/core";
+
+import { useForm } from "@mantine/form";
+import { DatePicker, TimeRangeInput } from "@mantine/dates";
+
+import { useEditor } from "@tiptap/react";
+import { Link } from "@mantine/tiptap";
+import StarterKit from "@tiptap/starter-kit";
+import Underline from "@tiptap/extension-underline";
+
+import Editor from "../components/editor";
+
+import templates from "../content/eventTemplates.json";
+
+import { gql, useMutation } from "@apollo/client";
+
+const addEventMutation = gql`
+  mutation addEvent(
+    $title: String
+    $speaker: String
+    $description: String
+    $date: DateTime
+    $time: [DateTime]
+    $place: String
+    $signUp: String
+    $isStammtisch: Boolean
+  ) {
+    addEvent(
+      title: $title
+      speaker: $speaker
+      description: $description
+      date: $date
+      time: $time
+      place: $place
+      signUp: $signUp
+      isStammtisch: $isStammtisch
+    )
+  }
+`;
+
+const editEventMutation = gql`
+  mutation editEvent(
+    $id: Int
+    $title: String
+    $speaker: String
+    $description: String
+    $date: DateTime
+    $time: [DateTime]
+    $place: String
+    $signUp: String
+    $isStammtisch: Boolean
+  ) {
+    editEvent(
+      id: $id
+      title: $title
+      speaker: $speaker
+      description: $description
+      date: $date
+      time: $time
+      place: $place
+      signUp: $signUp
+      isStammtisch: $isStammtisch
+    )
+  }
+`;
+
+export default function EventModal({ open, close, event, refetch }) {
+  const [addEvent] = useMutation(addEventMutation);
+  const [editEvent] = useMutation(editEventMutation);
+
+  const { t } = useTranslation("common");
+
+  const initialValues = {
+    title: "",
+    speaker: "",
+    date: null,
+    time: null,
+    place: "",
+    signUp: "",
+    isStammtisch: false,
+  };
+
+  const form = useForm({
+    initialValues: initialValues,
+
+    validate: {
+      title: (value) => (value ? null : t("ENotEmpty")),
+      date: (value) => (value ? null : t("ENotEmpty")),
+      time: (value) => (value ? null : t("ENotEmpty")),
+      place: (value) => (value ? null : t("ENotEmpty")),
+    },
+  });
+
+  const content = "";
+
+  const editor = useEditor({
+    extensions: [StarterKit, Underline, Link],
+    content,
+  });
+
+  const templatesFmt = templates.map((template) => ({
+    label: template.title,
+    value: template.title,
+  }));
+
+  const setTemplate = (t) => {
+    const template = templates.filter((temp) => temp.title === t)[0];
+    let timeArr = [new Date(), new Date()];
+    if (template.time) {
+      timeArr[0].setHours(
+        Number(template.time[0].split(":")[0]),
+        Number(template.time[0].split(":")[1]),
+        0
+      );
+      timeArr[1].setHours(
+        Number(template.time[1].split(":")[0]),
+        Number(template.time[1].split(":")[1]),
+        0
+      );
+    }
+
+    form.setValues({
+      ...template,
+      time: template.time ? [...timeArr] : null,
+    });
+    editor.commands.setContent(template.description);
+  };
+
+  const setEvent = () => {
+    if (event) {
+      form.setValues({
+        ...event,
+        date: new Date(event.date),
+        time: [new Date(event.startTime), new Date(event.endTime)],
+      });
+      if (editor) editor.commands.setContent(event.description);
+    } else {
+      form.setValues(initialValues);
+      if (editor) editor.commands.setContent(content);
+    }
+  };
+
+  useEffect(() => {
+    setEvent();
+  }, [open]);
+
+  const submit = async (values) => {
+    if (event) {
+      const res = await editEvent({
+        variables: {
+          id: event.id,
+          ...values,
+          description: editor.getHTML(),
+        },
+      });
+      if (res.data.editEvent) {
+        refetch();
+        close();
+      }
+    } else {
+      const res = await addEvent({
+        variables: {
+          ...values,
+          description: editor.getHTML(),
+        },
+      });
+      if (res.data.addEvent) {
+        refetch();
+        close();
+      }
+    }
+  };
+
+  return (
+    <Modal opened={open} onClose={close} fz="xl" size="xl">
+      <Text variant="h2" fw={700}>
+        {event ? t("editEvent") : t("addEvent")}
+      </Text>
+
+      <Space h="xl" />
+
+      <Select
+        data={templatesFmt}
+        placeholder={t("loadTemplate")}
+        onChange={(e) => setTemplate(e)}
+      />
+
+      <Space h="xl" />
+
+      <Divider />
+
+      <Space h="xs" />
+
+      <form onSubmit={form.onSubmit((values) => submit(values))}>
+        <Grid>
+          <Grid.Col sm={12} md={6}>
+            <TextInput
+              withAsterisk
+              label={t("title")}
+              placeholder="Introduction to Free Software"
+              {...form.getInputProps("title")}
+            />
+          </Grid.Col>
+          <Grid.Col sm={12} md={6}>
+            <TextInput
+              withAsterisk
+              label={t("speaker")}
+              placeholder="Maxime Musterfrau"
+              {...form.getInputProps("speaker")}
+            />
+          </Grid.Col>
+          <Grid.Col sm={12}>
+            <Text fz="sm">{t("description")}</Text>
+            {editor && <Editor editor={editor} />}
+          </Grid.Col>
+          <Grid.Col sm={12} md={6}>
+            <DatePicker
+              placeholder="January 1, 1970"
+              label={t("date")}
+              withAsterisk
+              {...form.getInputProps("date")}
+            />
+          </Grid.Col>
+          <Grid.Col sm={12} md={6}>
+            <TimeRangeInput
+              label={t("time")}
+              withAsterisk
+              clearable
+              {...form.getInputProps("time")}
+            />
+          </Grid.Col>
+          <Grid.Col sm={12} md={6}>
+            <TextInput
+              withAsterisk
+              label={t("place")}
+              placeholder="ETH HG F 7"
+              {...form.getInputProps("place")}
+            />
+          </Grid.Col>
+          <Grid.Col sm={12} md={6}>
+            <TextInput
+              label={t("signUp")}
+              placeholder="https://..."
+              {...form.getInputProps("signUp")}
+            />
+          </Grid.Col>
+          <Grid.Col sm={12} md={3}>
+            <Checkbox
+              mt="xl"
+              label={t("stammtisch")}
+              {...form.getInputProps("isStammtisch", { type: "checkbox" })}
+            />
+          </Grid.Col>
+          <Grid.Col sm={12}>
+            <Button type="submit">{t("submit")}</Button>
+          </Grid.Col>
+        </Grid>
+      </form>
+    </Modal>
+  );
+}
diff --git a/components/events.jsx b/components/events.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..7e795528bda5de4d4d14722d7318931d17ca8469
--- /dev/null
+++ b/components/events.jsx
@@ -0,0 +1,100 @@
+import { useState } from "react";
+
+import { useTranslation } from "next-i18next";
+
+import { Button, Grid, Space, useMantineTheme } from "@mantine/core";
+
+import { Icon, ICONS } from "vseth-canine-ui";
+
+import EventModal from "../components/eventModal";
+import SignUpsModal from "../components/signUpsModal";
+import EventCard from "../components/eventCard";
+import { getAccentColor } from "../utilities/colors";
+
+import { gql, useQuery } from "@apollo/client";
+
+const getFutureEventsQuery = gql`
+  query getFutureEvents {
+    getFutureEvents {
+      id
+      title
+      speaker
+      description
+      date
+      startTime
+      endTime
+      place
+      signUp
+      isStammtisch
+      signUps {
+        sub
+        firstName
+        lastName
+        email
+      }
+    }
+  }
+`;
+
+export default function Events() {
+  const { data: events, refetch } = useQuery(getFutureEventsQuery);
+  const [open, setOpen] = useState(false);
+  const [signUpOpen, setSignUpOpen] = useState(false);
+  const [event, setEvent] = useState(null);
+
+  const theme = useMantineTheme();
+  const { t } = useTranslation("common");
+
+  const addEvent = () => {
+    setEvent(null);
+    setOpen(true);
+  };
+
+  return (
+    <>
+      <h1>{t("events")}</h1>
+
+      <Button
+        leftIcon={<Icon icon={ICONS.PLUS} color={getAccentColor(theme)} />}
+        onClick={addEvent}
+        variant="default"
+      >
+        {t("addEvent")}
+      </Button>
+
+      <EventModal
+        open={open}
+        event={event}
+        close={() => setOpen(false)}
+        refetch={refetch}
+      />
+      <SignUpsModal
+        open={signUpOpen}
+        event={event}
+        close={() => setSignUpOpen(false)}
+      />
+
+      <Space h="xl" />
+      <Grid>
+        {events &&
+          events.getFutureEvents.map((e) => (
+            <Grid.Col
+              md={4}
+              sm={6}
+              xs={12}
+              key={e.id}
+              style={{ display: "flex" }}
+            >
+              <EventCard
+                event={e}
+                setEvent={setEvent}
+                setOpen={setOpen}
+                refetch={refetch}
+                setSignUpOpen={setSignUpOpen}
+              />
+            </Grid.Col>
+          ))}
+      </Grid>
+    </>
+  );
+}
diff --git a/components/header.jsx b/components/header.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..2db25ea1f5dd6f86ab7d1dc5967c8cc65f8899cd
--- /dev/null
+++ b/components/header.jsx
@@ -0,0 +1,84 @@
+import { useRouter } from "next/router";
+import Image from "next/image";
+import dynamic from "next/dynamic";
+
+import {
+  ActionIcon,
+  Grid,
+  MediaQuery,
+  Space,
+  useMantineTheme,
+} from "@mantine/core";
+
+import { Icon, ICONS } from "vseth-canine-ui";
+
+import parse from "html-react-parser";
+
+const NoAdblockBanner = dynamic(() => import("../components/noAdblockBanner"), {
+  ssr: false,
+});
+import { getAccentColor } from "../utilities/colors";
+
+import content from "../content/texts.json";
+import tux from "../public/images/tux.png";
+
+export default function Header() {
+  const { locale } = useRouter();
+  const theme = useMantineTheme();
+
+  return (
+    <div
+      style={{
+        height: "calc(100vh - 112px)",
+        display: "flex",
+        flexDirection: "column",
+        justifyContent: "space-evenly",
+      }}
+    >
+      <NoAdblockBanner />
+      <Grid style={{ display: "flex", alignItems: "center" }}>
+        <Grid.Col xs={12} md={6}>
+          <div>
+            <Image
+              src={
+                theme.colorScheme === "dark"
+                  ? "https://static.vseth.ethz.ch/assets/vseth-0522-thealt/logo-inv.svg"
+                  : "/images/logo.svg"
+              }
+              width={0}
+              height={0}
+              sizes="100vw"
+              style={{ width: "30rem", maxWidth: "100%", height: "auto" }}
+              alt="TheAlternative Logo  "
+            />
+            <Space h="xl" />
+            <Space h="xl" />
+            {content.topSection.map((entry, i) => (
+              <p key={i}>{parse(entry[locale || "en"])}</p>
+            ))}
+          </div>
+        </Grid.Col>
+        <MediaQuery smallerThan="md" styles={{ display: "none" }}>
+          <Grid.Col md={6}>
+            <Image
+              src={tux}
+              width={0}
+              height={0}
+              sizes="100vw"
+              style={{ width: "100%", height: "auto" }}
+              alt="Tux, the Linux Mascot"
+            />
+          </Grid.Col>
+        </MediaQuery>
+      </Grid>
+      <a href="#events">
+        <ActionIcon
+          style={{ marginLeft: "auto", marginRight: "auto" }}
+          size="3rem"
+        >
+          <Icon icon={ICONS.DOWN} color={getAccentColor(theme)} size="2rem" />
+        </ActionIcon>
+      </a>
+    </div>
+  );
+}
diff --git a/components/installguide.jsx b/components/installguide.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..1b64ad2f3d721987477831ce85c56235e8f6f144
--- /dev/null
+++ b/components/installguide.jsx
@@ -0,0 +1,1443 @@
+export default function InstallGuide() {
+  return (
+    <>
+      <h1 data-number={1} id="introduction">
+        <span className="header-section-number">1</span> Introduction
+      </h1>
+      <p>
+        This is a concise guide to install Linux. It can be used as a standalone
+        guide, although we recommend that you attend our Install Events during
+        the LinuxDays so that experienced users can help you with your
+        installation.
+      </p>
+      <p>
+        The guide help you to create an install stick, prepare your existing
+        operating system and finally install Linux. We also included some links
+        to distribution-specific installation resources, for the most up-to-date
+        instructions.
+      </p>
+      <p>At the end of the guide, we include some software recommendations.</p>
+      <h2 data-number="1.1" id="overview">
+        <span className="header-section-number">1.1</span> Overview
+      </h2>
+      <p>Installing Linux is done in three steps:</p>
+      <ul>
+        <li>Flash an USB Stick with the Linux installer</li>
+        <li>Prepare your existing operating system</li>
+        <li>Install Linux</li>
+      </ul>
+      <p>
+        We will help you at each step. If you encounter problems or have
+        suggestions how to improve this guide feel free to reach out!
+      </p>
+      <h2 data-number="1.2" id="linuxdays-install-event">
+        <span className="header-section-number">1.2</span> LinuxDays Install
+        Event
+      </h2>
+      <p>
+        <em>
+          You can skip this part if you do not physically attend the install
+          events
+        </em>
+      </p>
+      <p>
+        Welcome to the LinuxDays Install Event! We are happy you could make it.
+      </p>
+      <h3 data-number="1.2.1" id="staff">
+        <span className="header-section-number">1.2.1</span> Staff
+      </h3>
+      <p>
+        Our staff is easily recognizable by their blue T-Shirts. Feel free to
+        ask them about Linux, TheAlternative, Free Software or anything else.
+      </p>
+      <p>
+        We will help you if you are unable to proceed with the install guide or
+        have any other questions. If we do not have an immediate answer, we know
+        who to ask or where to look it up.
+      </p>
+      <p>Also, feel free to stay and just chat :)</p>
+      <h3 data-number="1.2.2" id="demolaptops">
+        <span className="header-section-number">1.2.2</span> Demolaptops
+      </h3>
+      <p>
+        We have prepared some laptops with different distribution and desktop
+        environments. You can try them out, and decide what you like best.
+      </p>
+      <p>
+        If you do not really care or can not decide, we will try to recommend
+        something based on what you want to use Linux for.
+      </p>
+      <h3 data-number="1.2.3" id="usb-install-sticks-install-guide-copies">
+        <span className="header-section-number">1.2.3</span> USB Install Sticks
+        &amp; Install Guide Copies
+      </h3>
+      <p>
+        We have prepared USB Install Sticks so you can get started right away
+        with installing Linux.
+      </p>
+      <p>
+        Further, we have printed copies of the Install Guide if you rather have
+        a printed version than look at it on you phone.
+      </p>
+      <h3 data-number="1.2.4" id="anything-else">
+        <span className="header-section-number">1.2.4</span> Anything else?
+      </h3>
+      <p>We have adapters (like USB to LAN), hubs, mouse and keyboards, …</p>
+      <h1 data-number={2} id="flash-stick">
+        <span className="header-section-number">2</span> Flash Stick
+      </h1>
+      <p>You will prepare a stick from which you can install Linux from.</p>
+      <p>
+        <em>
+          If you are at one of our Install Events, we already prepared USB
+          sticks. Choose a distribution (read on) then come to the welcome desk
+          to get your stick.
+        </em>
+      </p>
+      <h2 data-number="2.1" id="choosing-a-distribution">
+        <span className="header-section-number">2.1</span> Choosing a
+        distribution
+      </h2>
+      <p>In the words of Richard Stallman:</p>
+      <blockquote>
+        <p>
+          What you’re referring to as Linux, is in fact, GNU/Linux, or as I’ve
+          recently taken to calling it, GNU plus Linux. Linux is not an
+          operating system unto itself, but rather another free component of a
+          fully functioning GNU system &gt; made useful by the GNU corelibs,
+          shell utilities and vital system components comprising a full OS as
+          defined by POSIX."
+        </p>
+      </blockquote>
+      <p>
+        In simpler terms: Linux by itself is not a full operating system (rather
+        than a vital technical part of it). You need to choose a distribution (a
+        “wrapper” around Linux) which will define to a large extend how you as a
+        user will interact with the operating system (like installing new
+        programs, how the desktop looks by default, …).
+      </p>
+      <p>
+        As choosing a distribution is heavily opiniated, we describe it here
+        very short. Feel free to reach out to us for a personal recommendation
+        based on your specific needs.
+      </p>
+      <p>
+        If you “just want Linux”, we recommend you go with{" "}
+        <a href="https://ubuntu.com/">Ubuntu</a>. As a more open but also very
+        stable alternative we recommend{" "}
+        <a href="https://getfedora.org/">Fedora</a>. Truly Free (as in Freedom!)
+        is <a href="https://www.freebsd.org/">FreeBSD</a>.
+      </p>
+      <p>
+        For each of these distributions we give you starting points for a
+        successful installation. If you want to install other distributions feel
+        free to do so; and we will do our best to help you. If you are an
+        enthusiast and want to try to install something more advanced (like{" "}
+        <a href="https://www.archlinux.org/">Arch Linux</a>) come join us :).
+      </p>
+      <h2 data-number="2.2" id="download-iso">
+        <span className="header-section-number">2.2</span> Download ISO
+      </h2>
+      <p>
+        You need to download an image containing the operating system installer.
+        Visit the webpage of your favourite distribution and download it.
+      </p>
+      <p>
+        If you have to choose from multiple versions, here some guidance of
+        commonly used terms:
+      </p>
+      <ul>
+        <li>
+          <code>amd64</code>, <code>i386</code>, … refers to the architecture of
+          your device. If you have a laptop / PC, it is very likely that you
+          need <code>amd64</code> (else you’d probably know it).
+        </li>
+        <li>
+          <code>LTS</code> stands for long term support; meaning this specific
+          version of the distribution will receive security updates for much
+          longer than other versions.
+        </li>
+      </ul>
+      <h2 data-number="2.3" id="create-install-usb-stick">
+        <span className="header-section-number">2.3</span> Create install USB
+        Stick
+      </h2>
+      <p>
+        Get a USB stick of at least 8 Gb (make sure you do not need the data on
+        it anymore!). Flash (=“Put”) the .iso file you have just downloaded on
+        the USB stick.
+      </p>
+      <p>
+        On windows, you can use <a href="https://rufus.ie/">rufus</a>. On macOS,
+        you can use <a href="https://www.balena.io/etcher/">etcher</a>.
+      </p>
+      <h1 data-number={3} id="prepare-windows-mac">
+        <span className="header-section-number">3</span> Prepare Windows / Mac
+      </h1>
+      <p>
+        If you want to keep your existing operating system (Windows or macOS)
+        you need to prepare it. This will allow you to “double-boot”, hence
+        choose at startup which operating system to run.
+      </p>
+      <p>
+        If you do not want to keep your existing operating system, you can skip
+        this section.
+      </p>
+      <h2 data-number="3.1" id="about-partitioning">
+        <span className="header-section-number">3.1</span> About Partitioning
+      </h2>
+      <p>
+        Disk partitioning is the separation of different regions on a hard drive
+        or an SSD. This separation is used to install two different operating
+        systems on a computer or simply to have different regions for different
+        purposes (like a partition for your data and one for the programs).
+      </p>
+      <p>
+        We recommend to have at least 40GB of space partitioned for Linux. If
+        you know you need programs for your studies (e.g.&nbsp;Matlab, which is
+        around 30GB), please have enough free disk space to install the desired
+        programs and probably some extra, just in case.
+      </p>
+      <p>
+        Be aware that repartitioning later is practically impossible, so try to
+        be on the safe side. If you do not have space constraints, with 100Gb
+        all you wildest wishes should be fulfillable.
+      </p>
+      <h2 data-number="3.2" id="windows-10">
+        <span className="header-section-number">3.2</span> Windows 10
+      </h2>
+      <p>If you have Windows (and want to keep it) follow on.</p>
+      <h3 data-number="3.2.1" id="making-space-for-linux">
+        <span className="header-section-number">3.2.1</span> Making Space for
+        Linux
+      </h3>
+      <p>Shrink Windows partition:</p>
+      <ul>
+        <li>
+          Open <code>create and format hard disk partitions</code> or{" "}
+          <code>diskmgmt.msc</code>.
+        </li>
+        <li>Look for the large Windows partition at the bottom.</li>
+        <li>
+          Right-click on it and select <code>Shrink Volume...</code>
+        </li>
+        <li>Shrink it so you have enough space available.</li>
+      </ul>
+      <p>
+        If you are unable to shrink the partition, use a tool like{" "}
+        <code>EaseUS Partition Master</code> or try it in the Linux installer.
+        Ask a helper for assistance.
+      </p>
+      <p>
+        If you do not have enough space, you can free up disk space with these
+        tips:
+      </p>
+      <ul>
+        <li>
+          Open <code>Disk Cleanup</code> and click on{" "}
+          <code>Clean up system files</code>. Select all that apply.
+        </li>
+        <li>
+          Open <code>Add or Remove Programs</code> and remove unneeded programs
+        </li>
+        <li>
+          Download <code>WinDirStat</code> from https://windirstat.net/ and find
+          where the large files are hiding
+        </li>
+      </ul>
+      <h3 data-number="3.2.2" id="disable-bitlocker">
+        <span className="header-section-number">3.2.2</span> Disable Bitlocker
+      </h3>
+      <p>
+        Bitlocker encrypts your disk, but unfortunately it is not compatible
+        with Linux boot loaders.
+      </p>
+      <p>Disable Bitlocker:</p>
+      <ul>
+        <li>
+          Open <code>cmd</code> as administrator: Press Windows Key, type{" "}
+          <code>cmd</code>, then right click on <code>Command Prompt</code> and
+          select <code>Run as administrator</code>)
+        </li>
+        <li>
+          Type <code>manage-bde -status</code> and look for{" "}
+          <code>Conversion Status: Fully Decrypted</code>
+        </li>
+        <li>
+          For any drive which is not <code>Fully Decrypted</code>, type{" "}
+          <code>manage-bde -unlock C:</code> (replace <code>C:</code> with the
+          drive you need to decrypt), and press Enter.
+        </li>
+        <li>
+          Wait for decryption to end (execute <code>manage-bde -status</code>{" "}
+          for status updates)
+        </li>
+      </ul>
+      <p>
+        You can also try to disable Bitlocker over the UI (look for{" "}
+        <code>Manage Bitlocker</code>) but it has been confusing to do so in the
+        last few years.
+      </p>
+      <h3 data-number="3.2.3" id="fast-boot">
+        <span className="header-section-number">3.2.3</span> Fast Boot
+      </h3>
+      <p>
+        <code>Fast boot</code> allows Windows to boot faster, but when it is
+        active, the windows file system will be inaccessible to other OSes (like
+        Linux).
+      </p>
+      <p>
+        You can avoid the <code>Fast boot</code> mode by explicitly choosing to{" "}
+        <code>Restart</code> (rather than <code>Shut down</code>) in windows.
+      </p>
+      <p>Alternatively, you can simply disable fast boot:</p>
+      <ul>
+        <li>Find the battery icon in the task bar</li>
+        <li>
+          Right-click and select <code>Power Options</code>
+        </li>
+        <li>
+          Select <code>Choose what the power buttons do</code>
+        </li>
+        <li>
+          Select <code>Change settings that are currently unavailable</code>
+        </li>
+        <li>
+          Remove the check mark at <code>Turn on fast startup</code>
+        </li>
+      </ul>
+      <h3 data-number="3.2.4" id="booting-the-installer">
+        <span className="header-section-number">3.2.4</span> Booting the
+        installer
+      </h3>
+      <p>Make sure your Linux install stick is plugged into your PC.</p>
+      <p>
+        Click <code>Restart</code> in the Windows start menu, while holding down
+        the <code>Shift</code> key. A <code>Please wait</code>-text appears,
+        after which Windows should enter the troubleshooting menu.
+      </p>
+      <p>
+        From this menu you can choose a startup device, or enter the UEFI
+        settings.
+      </p>
+      <ul>
+        <li>
+          To choose the startup device, select <code>Use a device</code>. As we
+          want to boot from the Linux USB stick choose <code>USB FDD</code> or
+          similar.
+        </li>
+        <li>
+          To enter the UEFI settings, select <code>Troubleshoot</code>,{" "}
+          <code>Advanced Options</code> and then{" "}
+          <code>UEFI Firmware Settings</code>.
+        </li>
+      </ul>
+      <p>
+        If none of this works, you can try to change the startup device
+        immediately after booting. This guide will explain how in the next
+        chapter.
+      </p>
+      <h2 data-number="3.3" id="macos">
+        <span className="header-section-number">3.3</span> macOS
+      </h2>
+      <p>
+        <span style={{ color: "red" }}>
+          {" "}
+          <em>
+            Note that on modern Apple computers it is generally not advisable to
+            install Linux (MacBooks after 2016 simply are not very compatible
+            with Linux.)
+          </em>{" "}
+        </span>
+      </p>
+      <p>
+        Up-to-date information on the status of Linux support on MacBooks can be
+        found <a href="https://github.com/Dunedan/mbp-2016-linux">here</a>.
+      </p>
+      <h3 data-number="3.3.1" id="shrink-your-os-x-partition">
+        <span className="header-section-number">3.3.1</span> Shrink your OS X
+        partition
+      </h3>
+      <p>
+        On OS X, we will resize your existing partition to make space for your
+        new Linux system.
+      </p>
+      <ul>
+        <li>
+          Go to <code>/Applications/Utilities</code> and open the{" "}
+          <code>Disk Utility</code>.
+        </li>
+        <li>
+          Select your main disk in the list to the left (usually the first or
+          the largest).
+        </li>
+        <li>
+          Select the tab <code>Partition</code>.
+        </li>
+        <li>
+          On the left side there is a white rectangle with some blue threshold
+          indicating the space consumed by Mac OS X.
+        </li>
+        <li>
+          Click and hold the lower right corner of that rectangle and draw the
+          cursor upwards, to shrink the volume.
+        </li>
+        <li>
+          The text on the right will give you information about the freed
+          memory.
+        </li>
+        <li>
+          Once you are satisfied, click <code>Apply</code> to confirm the
+          shrinking operation.
+        </li>
+      </ul>
+      <h3 data-number="3.3.2" id="install-refind">
+        <span className="header-section-number">3.3.2</span> Install rEFInd
+      </h3>
+      <p>
+        We will install the bootloader on OS X before the Linux installation.{" "}
+        <em>rEFInd</em> will boot your USB Install Medium as well as your
+        operating system later on.
+      </p>
+      <ul>
+        <li>
+          Browse the web for{" "}
+          <a href="http://www.rodsbooks.com/refind/getting.html">
+            http://www.rodsbooks.com/refind/getting.html
+          </a>{" "}
+          and scroll down a bit to click the link <em>A binary zip file</em>.
+        </li>
+        <li>
+          Once the download has completed, go to the <em>Download folder</em>{" "}
+          and extract the file.
+        </li>
+        <li>
+          Open a Mac terminal by going to <code>Application/Utilities</code> and
+          opening <code>Terminal</code>.
+        </li>
+        <li>
+          Type <code>cd</code> (with a space afterwards, but do{" "}
+          <strong>not</strong> press <em>Enter</em> yet) and drag the extracted
+          folder into the terminal.
+        </li>
+        <li>
+          Now, hit <em>Enter</em> and then type <code>./refind-install</code>.
+        </li>
+        <li>
+          When prompted for your password, enter it. (You won’t see what you
+          enter at the password prompt at all. You have to enter your password
+          blindly.)
+        </li>
+      </ul>
+      <h3 data-number="3.3.3" id="troubleshoot">
+        <span className="header-section-number">3.3.3</span> Troubleshoot
+      </h3>
+      <p>
+        In case you get an error message saying <em>ALERT: SIP ENABLED</em>, you
+        need to do the following:
+      </p>
+      <ul>
+        <li>
+          Turn off your Mac and start it again, pressing <code>Cmd + R</code>{" "}
+          immediately after turning it on again (you might want to hold it for a
+          while).
+        </li>
+        <li>
+          Your Mac should boot in <code>recovery mode</code>. Go to{" "}
+          <code>Utilities</code> and open up a terminal.
+        </li>
+        <li>
+          Now type: <code>csrutil disable</code>.
+        </li>
+        <li>
+          Then reboot back into your normal system and try to install{" "}
+          <em>rEFInd</em> again.
+        </li>
+        <li>
+          After installation, feel free to go once more into recovery and type{" "}
+          <code>csrutil enable</code>.
+        </li>
+      </ul>
+      <h3 data-number="3.3.4" id="booting-the-installer-1">
+        <span className="header-section-number">3.3.4</span> Booting the
+        installer
+      </h3>
+      <p>We will now boot from your USB Install Medium.</p>
+      <ul>
+        <li>Plug your USB Install Medium into your laptop.</li>
+        <li>
+          Reboot your machine and <em>rEFInd</em> should see the USB key.
+        </li>
+        <li>
+          Your USB installer may have several ways to boot. They all will show
+          up and have a little USB icon to the bottom right.
+        </li>
+        <li>
+          Usually the first USB installer is correct. If it doesn’t work, reboot
+          and try the others.
+        </li>
+        <li>
+          If your USB installer doesn’t show up, hit <code>Escape</code> to
+          refresh the list. It should show up now.
+        </li>
+        <li>
+          If you see multiple USB keys, try each of them until you find the
+          Linux installer.
+        </li>
+      </ul>
+      <h1 data-number={4} id="install">
+        <span className="header-section-number">4</span> Install
+      </h1>
+      <p>You are all set to install Linux on your device.</p>
+      <p>
+        If you have not yet done so; ensure you have backed up all your data! In
+        the (unlikely) case something goes terribly wrong, you can recover your
+        data.
+      </p>
+      <h2 data-number="4.1" id="boot-from-stick">
+        <span className="header-section-number">4.1</span> Boot from Stick
+      </h2>
+      <p>
+        You now want to boot from the USB stick (if you have not already done
+        so, depending on your existing operating system).
+      </p>
+      <p>
+        This step can be tricky, as the way to accomplish this is different over
+        different devices and brands. Generally you need to look for something
+        like “BIOS” or “startup device”. You then need to choose the USB stick
+        as the startup device.
+      </p>
+      <p>
+        You can enter the BIOS or change the startup device usually with the
+        function keys (such as F1, F8, F10, F12) or with other keys like ESC or
+        Enter.
+      </p>
+      <p>The most common keys by brand: - Lenovo: Enter - HP: Esc</p>
+      <h2 data-number="4.2" id="partitioning">
+        <span className="header-section-number">4.2</span> Partitioning
+      </h2>
+      <p>
+        This can either be done automatically by the Linux distributions
+        installer, or manually if you want more control over your setup. If you
+        are unsure about what setup you want, it might be best to follow the
+        automatic setup.
+      </p>
+      <figure>
+        <img
+          src="images/partitions.png"
+          alt="Example partitions for a system with Linux only"
+        />
+        <figcaption aria-hidden="true">
+          Example partitions for a system with Linux only
+        </figcaption>
+      </figure>
+      <figure>
+        <img
+          src="images/partitions2.jpg"
+          alt="Example partitions for a dual boot system"
+        />
+        <figcaption aria-hidden="true">
+          Example partitions for a dual boot system
+        </figcaption>
+      </figure>
+      <h3 data-number="4.2.1" id="automatic-setup">
+        <span className="header-section-number">4.2.1</span> Automatic setup
+      </h3>
+      <p>
+        The various installers usually offer an option to either install
+        alongside an existing operating system (Windows/Mac), or to use the
+        entire disk and erase previously installed systems. If you choose to
+        install alongside something else, there is usually an option to choose
+        how much space you want to allocate for the new system. Note that the
+        partition for the old system will also have to shrink by this amount.
+      </p>
+      <h3 data-number="4.2.2" id="manual-setup">
+        <span className="header-section-number">4.2.2</span> Manual setup
+      </h3>
+      <p>
+        If you want a manual setup these are some partitions you might consider:
+      </p>
+      <ul>
+        <li>
+          <code>/boot</code>: This is the boot partition for EFI. This already
+          exists and will be reused when installing your new operating system.
+        </li>
+        <li>
+          <code>/</code> (root). A root partition is required for all
+          installations. This is where all the operating system files live.
+        </li>
+        <li>
+          <code>/home</code>: Some users like to their home directory on a
+          different partition. This can make re-installation of a distribution
+          easier. However, this is entirely optional.
+        </li>
+        <li>
+          <code>/swap</code>: A swap partition is used as an extension for your
+          machines memory, if it ever fills up. Nowadays, a lot of people omit
+          this on personal computers.
+        </li>
+      </ul>
+      <p>
+        You will also be able to choose a file system for <code>/</code> and{" "}
+        <code>/home</code>. Almost always the <code>ext4</code> filesystem
+        should be used. If you know what you are doing, you can of course also
+        choose something else.
+      </p>
+      <h2 data-number="4.3" id="ubuntu">
+        <span className="header-section-number">4.3</span> Ubuntu
+      </h2>
+      <p>
+        We recommend to follow the{" "}
+        <a href="https://ubuntu.com/tutorials/tutorial-install-ubuntu-desktop">
+          official install-guide
+        </a>{" "}
+        for installing Ubuntu.
+      </p>
+      <p>
+        As further resources, we recommend the{" "}
+        <a href="https://wiki.ubuntu.com/">Ubuntu Wiki</a> and the{" "}
+        <a href="https://askubuntu.com/">askubuntu StackExchange</a>.
+      </p>
+      <h2 data-number="4.4" id="fedora">
+        <span className="header-section-number">4.4</span> Fedora
+      </h2>
+      <p>
+        The top-level documentation for Fedora can be found on the official{" "}
+        <a href="https://docs.fedoraproject.org/en-US/docs/">
+          Fedora docs website
+        </a>
+        .
+      </p>
+      <p>The following links are a good starting point:</p>
+      <ul>
+        <li>
+          The Fedora{" "}
+          <a href="https://docs.fedoraproject.org/en-US/fedora/f31/install-guide/Introduction/">
+            install guide
+          </a>
+        </li>
+        <li>
+          The{" "}
+          <a href="https://docs.fedoraproject.org/en-US/quick-docs/">
+            usage and customization guide
+          </a>
+        </li>
+        <li>
+          The guide for upgrading to a new{" "}
+          <a href="https://docs.fedoraproject.org/en-US/quick-docs/dnf-system-upgrade/">
+            release
+          </a>
+        </li>
+      </ul>
+      <h2 data-number="4.5" id="open-suse">
+        <span className="header-section-number">4.5</span> Open SUSE
+      </h2>
+      <p>
+        For getting started with OpenSuse we recommend going through{" "}
+        <a href="https://www.opensuse-guide.org">Unofficial openSUSE Guide</a>,
+        since it gives a good overview and can save you some time.
+      </p>
+      <p>
+        Also check out the{" "}
+        <a href="https://doc.opensuse.org/documentation/leap/startup/single-html/book.opensuse.startup/index.html">
+          Start-Up Guide
+        </a>{" "}
+        from their website and the{" "}
+        <a href="https://en.opensuse.org/Portal:Documentation">documentation</a>{" "}
+        if you have further questions or want to work with the official
+        material.
+      </p>
+      <h1 data-number={5} id="software">
+        <span className="header-section-number">5</span> Software
+      </h1>
+      <p>
+        These are software recommendations for Linux. Most of these are
+        graphical programs, but there are some programs that run in the terminal
+        only. Note that these programs have various licenses, some might not
+        even be “libre” software (due to them becoming closed source at a later
+        point, or this list having errors)!
+      </p>
+      <p>
+        Some programs are annotated if they are best used on GNOME or KDE. This
+        does not mean they cannot be used on the other environment, but the
+        visual integration might be lacking in these cases.
+      </p>
+      <h2 data-number="5.1" id="office">
+        <span className="header-section-number">5.1</span> Office
+      </h2>
+      <table>
+        <colgroup>
+          <col style={{ width: "33%" }} />
+          <col style={{ width: "33%" }} />
+          <col style={{ width: "33%" }} />
+        </colgroup>
+        <thead>
+          <tr className="header">
+            <th style={{ textAlign: "left" }}>Use case</th>
+            <th style={{ textAlign: "left" }}>Application</th>
+            <th style={{ textAlign: "left" }}>Comment</th>
+          </tr>
+        </thead>
+        <tbody>
+          <tr className="odd">
+            <td style={{ textAlign: "left" }}>Office suite</td>
+            <td style={{ textAlign: "left" }}>LibreOffice</td>
+            <td style={{ textAlign: "left" }} />
+          </tr>
+          <tr className="even">
+            <td style={{ textAlign: "left" }}>Office suite</td>
+            <td style={{ textAlign: "left" }}>OnlyOffice</td>
+            <td style={{ textAlign: "left" }}>
+              Looks much nicer than LibreOffice
+            </td>
+          </tr>
+          <tr className="odd">
+            <td style={{ textAlign: "left" }}>PDF viewer</td>
+            <td style={{ textAlign: "left" }}>Zathura</td>
+            <td style={{ textAlign: "left" }}>
+              All desktop environments include a PDF viewer. Zathura is another,
+              more simple option.
+            </td>
+          </tr>
+          <tr className="even">
+            <td style={{ textAlign: "left" }}>Note taking, PDF annotation</td>
+            <td style={{ textAlign: "left" }}>Xournal</td>
+            <td style={{ textAlign: "left" }} />
+          </tr>
+          <tr className="odd">
+            <td style={{ textAlign: "left" }}>LaTeX editor</td>
+            <td style={{ textAlign: "left" }}>
+              Texstudio, Texmaker, GNOME LaTeX
+            </td>
+            <td style={{ textAlign: "left" }}>
+              Texstudio/Texmaker are “what you see is what you get”, GNOME LaTeX
+              uses a “write, then compile” workflow.
+            </td>
+          </tr>
+          <tr className="even">
+            <td style={{ textAlign: "left" }}>Mindmapping</td>
+            <td style={{ textAlign: "left" }}>vym</td>
+            <td style={{ textAlign: "left" }} />
+          </tr>
+          <tr className="odd">
+            <td style={{ textAlign: "left" }}>Design/Publishing</td>
+            <td style={{ textAlign: "left" }}>Scribus</td>
+            <td style={{ textAlign: "left" }} />
+          </tr>
+          <tr className="even">
+            <td style={{ textAlign: "left" }}>Simple Text Editor</td>
+            <td style={{ textAlign: "left" }}>
+              Gedit/Geany (GNOME), Kwrite/Kate (KDE)
+            </td>
+            <td style={{ textAlign: "left" }} />
+          </tr>
+          <tr className="odd">
+            <td style={{ textAlign: "left" }}>Advanced Text Editor</td>
+            <td style={{ textAlign: "left" }}>vim, emacs</td>
+            <td style={{ textAlign: "left" }}>
+              These are a bit more difficult to learn, but are very popular with
+              power users.
+            </td>
+          </tr>
+          <tr className="even">
+            <td style={{ textAlign: "left" }}>File manager</td>
+            <td style={{ textAlign: "left" }}>
+              PCManFM, ranger/nnn (Terminal)
+            </td>
+            <td style={{ textAlign: "left" }}>
+              All desktop environments include a file manager, these are other
+              more advanced options.
+            </td>
+          </tr>
+          <tr className="odd">
+            <td style={{ textAlign: "left" }}>CAD</td>
+            <td style={{ textAlign: "left" }}>FreeCAD</td>
+            <td style={{ textAlign: "left" }} />
+          </tr>
+        </tbody>
+      </table>
+      <h2 data-number="5.2" id="graphics">
+        <span className="header-section-number">5.2</span> Graphics
+      </h2>
+      <table>
+        <colgroup>
+          <col style={{ width: "33%" }} />
+          <col style={{ width: "33%" }} />
+          <col style={{ width: "33%" }} />
+        </colgroup>
+        <thead>
+          <tr className="header">
+            <th style={{ textAlign: "left" }}>Use case</th>
+            <th style={{ textAlign: "left" }}>Application</th>
+            <th style={{ textAlign: "left" }}>Comment</th>
+          </tr>
+        </thead>
+        <tbody>
+          <tr className="odd">
+            <td style={{ textAlign: "left" }}>Image editing</td>
+            <td style={{ textAlign: "left" }}>GIMP, Pinta</td>
+            <td style={{ textAlign: "left" }}>
+              GIMP is a more fully featured editor, similar to Photoshop. Pinta
+              is inspired by Paint.NET.
+            </td>
+          </tr>
+          <tr className="even">
+            <td style={{ textAlign: "left" }}>Painting</td>
+            <td style={{ textAlign: "left" }}>Krita</td>
+            <td style={{ textAlign: "left" }} />
+          </tr>
+          <tr className="odd">
+            <td style={{ textAlign: "left" }}>3D Animation</td>
+            <td style={{ textAlign: "left" }}>Blender</td>
+            <td style={{ textAlign: "left" }} />
+          </tr>
+          <tr className="even">
+            <td style={{ textAlign: "left" }}>Photo management</td>
+            <td style={{ textAlign: "left" }}>Darktable, Digikam</td>
+            <td style={{ textAlign: "left" }} />
+          </tr>
+          <tr className="odd">
+            <td style={{ textAlign: "left" }}>Scanning</td>
+            <td style={{ textAlign: "left" }}>
+              Skanlite (KDE), SimpleScan (GNOME)
+            </td>
+            <td style={{ textAlign: "left" }} />
+          </tr>
+          <tr className="even">
+            <td style={{ textAlign: "left" }}>OCR (Text Recognition)</td>
+            <td style={{ textAlign: "left" }}>OCRGui, OCRmyPDF (Terminal)</td>
+            <td style={{ textAlign: "left" }} />
+          </tr>
+        </tbody>
+      </table>
+      <h2 data-number="5.3" id="multimedia">
+        <span className="header-section-number">5.3</span> Multimedia
+      </h2>
+      <table>
+        <colgroup>
+          <col style={{ width: "33%" }} />
+          <col style={{ width: "33%" }} />
+          <col style={{ width: "33%" }} />
+        </colgroup>
+        <thead>
+          <tr className="header">
+            <th style={{ textAlign: "left" }}>Use case</th>
+            <th style={{ textAlign: "left" }}>Application</th>
+            <th style={{ textAlign: "left" }}>Comment</th>
+          </tr>
+        </thead>
+        <tbody>
+          <tr className="odd">
+            <td style={{ textAlign: "left" }}>Video Player</td>
+            <td style={{ textAlign: "left" }}>mpv, VLC, Totem (GNOME)</td>
+            <td style={{ textAlign: "left" }}>
+              Desktop environments have a default video player, but mpv/VLC are
+              usually more powerful.
+            </td>
+          </tr>
+          <tr className="even">
+            <td style={{ textAlign: "left" }}>Audio editing</td>
+            <td style={{ textAlign: "left" }}>Audacity</td>
+            <td style={{ textAlign: "left" }} />
+          </tr>
+          <tr className="odd">
+            <td style={{ textAlign: "left" }}>MP3 tagging</td>
+            <td style={{ textAlign: "left" }}>Picard</td>
+            <td style={{ textAlign: "left" }} />
+          </tr>
+          <tr className="even">
+            <td style={{ textAlign: "left" }}>
+              Digital Audio Workstation (DAW)
+            </td>
+            <td style={{ textAlign: "left" }}>Ardour</td>
+            <td style={{ textAlign: "left" }} />
+          </tr>
+          <tr className="odd">
+            <td style={{ textAlign: "left" }}>YouTube downloader</td>
+            <td style={{ textAlign: "left" }}>youtube-dl (Terminal)</td>
+            <td style={{ textAlign: "left" }}>
+              Requires regular updates, because YouTube changes their website
+              rather often
+            </td>
+          </tr>
+          <tr className="even">
+            <td style={{ textAlign: "left" }}>Screen recording</td>
+            <td style={{ textAlign: "left" }}>OBS, SimpleScreenRecorder</td>
+            <td style={{ textAlign: "left" }}>
+              OBS is very powerful, SimpleScreenRecorder is more simple option.
+            </td>
+          </tr>
+        </tbody>
+      </table>
+      <h2 data-number="5.4" id="scientific">
+        <span className="header-section-number">5.4</span> Scientific
+      </h2>
+      <table>
+        <colgroup>
+          <col style={{ width: "33%" }} />
+          <col style={{ width: "33%" }} />
+          <col style={{ width: "33%" }} />
+        </colgroup>
+        <thead>
+          <tr className="header">
+            <th style={{ textAlign: "left" }}>Use case</th>
+            <th style={{ textAlign: "left" }}>Application</th>
+            <th style={{ textAlign: "left" }}>Comment</th>
+          </tr>
+        </thead>
+        <tbody>
+          <tr className="odd">
+            <td style={{ textAlign: "left" }}>Matlab</td>
+            <td style={{ textAlign: "left" }}>Python+Numpy, Octave</td>
+            <td style={{ textAlign: "left" }}>
+              Octave tries to be similar to Matlab, while Python+Numpy is rather
+              different.
+            </td>
+          </tr>
+          <tr className="even">
+            <td style={{ textAlign: "left" }}>Statistics</td>
+            <td style={{ textAlign: "left" }}>R, PSPP</td>
+            <td style={{ textAlign: "left" }} />
+          </tr>
+          <tr className="odd">
+            <td style={{ textAlign: "left" }}>ArcGIS</td>
+            <td style={{ textAlign: "left" }}>QGIS, GRASS GIS</td>
+            <td style={{ textAlign: "left" }} />
+          </tr>
+        </tbody>
+      </table>
+      <h2 data-number="5.5" id="internet">
+        <span className="header-section-number">5.5</span> Internet
+      </h2>
+      <table>
+        <colgroup>
+          <col style={{ width: "33%" }} />
+          <col style={{ width: "33%" }} />
+          <col style={{ width: "33%" }} />
+        </colgroup>
+        <thead>
+          <tr className="header">
+            <th style={{ textAlign: "left" }}>Use case</th>
+            <th style={{ textAlign: "left" }}>Application</th>
+            <th style={{ textAlign: "left" }}>Comment</th>
+          </tr>
+        </thead>
+        <tbody>
+          <tr className="odd">
+            <td style={{ textAlign: "left" }}>Web Browser</td>
+            <td style={{ textAlign: "left" }}>
+              Firefox, Chromium, qutebrowser
+            </td>
+            <td style={{ textAlign: "left" }}>
+              We recommend using Chromium instead of Google Chrome on Linux
+            </td>
+          </tr>
+          <tr className="even">
+            <td style={{ textAlign: "left" }}>Mail</td>
+            <td style={{ textAlign: "left" }}>
+              Thunderbird, KMail (KDE), Evolution (GNOME), mutt (Terminal)
+            </td>
+            <td style={{ textAlign: "left" }} />
+          </tr>
+          <tr className="odd">
+            <td style={{ textAlign: "left" }}>Instant Messaging</td>
+            <td style={{ textAlign: "left" }}>
+              Telegram, Pidgin, Empathy (GNOME)
+            </td>
+            <td style={{ textAlign: "left" }} />
+          </tr>
+          <tr className="even">
+            <td style={{ textAlign: "left" }}>Torrent client</td>
+            <td style={{ textAlign: "left" }}>
+              Transmission (GNOME), Ktorrent (KDE), Deluge, rtorrent (Terminal)
+            </td>
+            <td style={{ textAlign: "left" }} />
+          </tr>
+          <tr className="odd">
+            <td style={{ textAlign: "left" }}>Voice chat</td>
+            <td style={{ textAlign: "left" }}>Mumble, Empathy (GNOME)</td>
+            <td style={{ textAlign: "left" }} />
+          </tr>
+          <tr className="even">
+            <td style={{ textAlign: "left" }}>File synchronization</td>
+            <td style={{ textAlign: "left" }}>
+              Syncthing, Nextcloud, OwnCloud, Seafile
+            </td>
+            <td style={{ textAlign: "left" }} />
+          </tr>
+        </tbody>
+      </table>
+      <h2 data-number="5.6" id="system">
+        <span className="header-section-number">5.6</span> System
+      </h2>
+      <table>
+        <colgroup>
+          <col style={{ width: "33%" }} />
+          <col style={{ width: "33%" }} />
+          <col style={{ width: "33%" }} />
+        </colgroup>
+        <thead>
+          <tr className="header">
+            <th style={{ textAlign: "left" }}>Use case</th>
+            <th style={{ textAlign: "left" }}>Application</th>
+            <th style={{ textAlign: "left" }}>Comment</th>
+          </tr>
+        </thead>
+        <tbody>
+          <tr className="odd">
+            <td style={{ textAlign: "left" }}>Disk usage</td>
+            <td style={{ textAlign: "left" }}>
+              Baobab (GNOME), Filelight (KDE), ncdu (Terminal)
+            </td>
+            <td style={{ textAlign: "left" }} />
+          </tr>
+          <tr className="even">
+            <td style={{ textAlign: "left" }}>Virtualization</td>
+            <td style={{ textAlign: "left" }}>
+              virt-manager, VirtualBox, GNOME Boxes
+            </td>
+            <td style={{ textAlign: "left" }} />
+          </tr>
+          <tr className="odd">
+            <td style={{ textAlign: "left" }}>Backup</td>
+            <td style={{ textAlign: "left" }}>borg backup, Déjà Dup</td>
+            <td style={{ textAlign: "left" }} />
+          </tr>
+          <tr className="even">
+            <td style={{ textAlign: "left" }}>System monitor</td>
+            <td style={{ textAlign: "left" }}>htop (Terminal)</td>
+            <td style={{ textAlign: "left" }}>
+              The desktop environment have their own system monitor included.
+            </td>
+          </tr>
+        </tbody>
+      </table>
+      <h2 data-number="5.7" id="development">
+        <span className="header-section-number">5.7</span> Development
+      </h2>
+      <table>
+        <colgroup>
+          <col style={{ width: "33%" }} />
+          <col style={{ width: "33%" }} />
+          <col style={{ width: "33%" }} />
+        </colgroup>
+        <thead>
+          <tr className="header">
+            <th style={{ textAlign: "left" }}>Use case</th>
+            <th style={{ textAlign: "left" }}>Application</th>
+            <th style={{ textAlign: "left" }}>Comment</th>
+          </tr>
+        </thead>
+        <tbody>
+          <tr className="odd">
+            <td style={{ textAlign: "left" }}>IDE</td>
+            <td style={{ textAlign: "left" }}>
+              IntelliJ, Eclipse, Code::Blocks, Android Studio, Geany, Qt
+              Creator, Gnome Builder
+            </td>
+            <td style={{ textAlign: "left" }}>
+              Some of these might not be Free and Open Source!
+            </td>
+          </tr>
+        </tbody>
+      </table>
+      <h2 data-number="5.8" id="other">
+        <span className="header-section-number">5.8</span> Other
+      </h2>
+      <table>
+        <colgroup>
+          <col style={{ width: "33%" }} />
+          <col style={{ width: "33%" }} />
+          <col style={{ width: "33%" }} />
+        </colgroup>
+        <thead>
+          <tr className="header">
+            <th style={{ textAlign: "left" }}>Use case</th>
+            <th style={{ textAlign: "left" }}>Application</th>
+            <th style={{ textAlign: "left" }}>Comment</th>
+          </tr>
+        </thead>
+        <tbody>
+          <tr className="odd">
+            <td style={{ textAlign: "left" }}>Dropdown terminal</td>
+            <td style={{ textAlign: "left" }}>Guake (GNOME), Yakuake (KDE)</td>
+            <td style={{ textAlign: "left" }} />
+          </tr>
+          <tr className="even">
+            <td style={{ textAlign: "left" }}>Clipboard manager</td>
+            <td style={{ textAlign: "left" }}>
+              Glipper (GNOME), Clipman (XFCE)
+            </td>
+            <td style={{ textAlign: "left" }}>
+              The desktop environment each have their own clipboard manager.
+            </td>
+          </tr>
+        </tbody>
+      </table>
+      <h1 data-number={6} id="troubleshooting">
+        <span className="header-section-number">6</span> Troubleshooting
+      </h1>
+      <p>
+        A chapter for some advanced troubleshooting. If you need something
+        contained in this chapter, better ask some advanced user for help (or
+        one of our helpers if you are at our Install Event).
+      </p>
+      <h2 data-number="6.1" id="microsoft-surface">
+        <span className="header-section-number">6.1</span> Microsoft Surface
+      </h2>
+      <h3 data-number="6.1.1" id="something-doesnt-work">
+        <span className="header-section-number">6.1.1</span> Something doesn’t
+        work
+      </h3>
+      <p>
+        Microsoft Surface devices usually require a patched kernel.{" "}
+        <a href="https://github.com/linux-surface/linux-surface">
+          See this project
+        </a>{" "}
+        to install such a kernel.
+      </p>
+      <h2 data-number="6.2" id="wireless">
+        <span className="header-section-number">6.2</span> Wireless
+      </h2>
+      <h3 data-number="6.2.1" id="broadcom-on-ubuntu-doesnt-work">
+        <span className="header-section-number">6.2.1</span> Broadcom on Ubuntu
+        doesn’t work
+      </h3>
+      <p>
+        <a href="https://help.ubuntu.com/community/WifiDocs/Driver/bcm43xx">
+          See this.
+        </a>
+      </p>
+      <h3 data-number="6.2.2" id="installing-broadcom-firmware">
+        <span className="header-section-number">6.2.2</span> Installing Broadcom
+        Firmware
+      </h3>
+      <p>
+        <em>openSUSE:</em>
+      </p>
+      <p>
+        <code>sudo zypper install b43-fwcutter</code>{" "}
+        <code>sudo /usr/sbin/install_bcm43xx_firmware</code>
+      </p>
+      <p>
+        <a href="https://www.opensuse-guide.org/wlan.php">
+          See also this site.
+        </a>
+      </p>
+      <p>
+        <em>Ubuntu:</em>
+      </p>
+      <p>
+        <code>sudo apt install firmware-b43-installer</code>
+      </p>
+      <p>
+        <a href="http://linuxwireless.org/en/users/Drivers/b43/">
+          See also this site.
+        </a>
+      </p>
+      <h2 data-number="6.3" id="opensuse">
+        <span className="header-section-number">6.3</span> OpenSUSE
+      </h2>
+      <h3
+        data-number="6.3.1"
+        id="installing-broadcom-wireless-drivers-broadcom-wl"
+      >
+        <span className="header-section-number">6.3.1</span> Installing Broadcom
+        Wireless Drivers (broadcom-wl)
+      </h3>
+      <ul>
+        <li>
+          Add the packman repo: YaST -&gt; Software repos -&gt; Add -&gt; Select
+          community -&gt; repos -&gt; Next -&gt; Select packman -&gt; Finish
+        </li>
+        <li>
+          <code>zypper ref</code>
+        </li>
+        <li>
+          <code>zypper install broadcom-wl</code>
+        </li>
+      </ul>
+      <h2 data-number="6.4" id="graphics-drivers">
+        <span className="header-section-number">6.4</span> Graphics drivers
+      </h2>
+      <h2 data-number="6.5" id="system-hangs-at-boot-nvidia-present">
+        <span className="header-section-number">6.5</span> System hangs at boot
+        (NVIDIA present)
+      </h2>
+      <p>
+        Boot with <code>nomodeset</code> kernel parameter, then either install
+        proprietary NVIDIA drivers or disable the NVIDIA graphics entirely.
+      </p>
+      <h2 data-number="6.6" id="i-want-to-disable-the-nouveau-driver">
+        <span className="header-section-number">6.6</span> I want to disable the
+        Nouveau driver
+      </h2>
+      <p>
+        <code>
+          echo 'blacklist nouveau' | tee /etc/modprobe.d/blacklist.conf
+        </code>
+      </p>
+      <h2 data-number="6.7" id="acer">
+        <span className="header-section-number">6.7</span> Acer
+      </h2>
+      <p>
+        Some types of newer Acer notebooks need special settings for Secure Boot
+        in order to boot an installed GNU/Linux system at all. If you installed
+        eg. Ubuntu but it directly boots Windows without giving you a GRUB
+        selection screen, try the following guide:
+        https://askubuntu.com/questions/771455/dual-boot-ubuntu-with-windows-on-acer-aspire/771749#771749
+      </p>
+      <h2 data-number="6.8" id="system-1">
+        <span className="header-section-number">6.8</span> System
+      </h2>
+      <h3 data-number="6.8.1" id="chroot-into-an-installed-system">
+        <span className="header-section-number">6.8.1</span> chroot into an
+        installed system
+      </h3>
+      <p>
+        To chroot into an installed system from a live iso, do the following:
+      </p>
+      <ul>
+        <li>
+          <code>sudo su</code>
+        </li>
+        <li>
+          <code>mount /dev/sdaX /mnt</code>, where <code>sdaX</code> is your
+          root partition
+        </li>
+        <li>
+          If you have EFI: <code>mount /dev/sda1 /mnt/boot/efi</code> (assuming{" "}
+          <code>sda1</code> is your EFI partition)
+        </li>
+        <li>
+          <code>mount -t proc proc /mnt/proc/</code>
+        </li>
+        <li>
+          <code>mount -t sysfs sys /mnt/sys/</code>
+        </li>
+        <li>
+          <code>mount -o bind /dev /mnt/dev/</code>
+        </li>
+        <li>
+          <code>chroot /mnt /bin/bash</code>
+        </li>
+      </ul>
+      <h3 data-number="6.8.2" id="cleaning-up-boot-entries">
+        <span className="header-section-number">6.8.2</span> Cleaning up boot
+        entries
+      </h3>
+      <ul>
+        <li>
+          <code>efibootmgr</code> prints all boot entries.
+        </li>
+        <li>
+          <code>efibootmgr -o XXXX,YYYY,ZZZZ</code> sets the boot order.
+        </li>
+        <li>
+          <code>efibootmgr -b &lt;number&gt; -B</code> deletes an EFI boot
+          entry.
+        </li>
+      </ul>
+      <h3 data-number="6.8.3" id="drives-are-not-found-in-the-installer">
+        <span className="header-section-number">6.8.3</span> Drives are not
+        found in the installer
+      </h3>
+      <p>
+        Especially newer laptops (2018+) have options to switch between RAID and
+        AHCI boot mode.
+      </p>
+      <p>
+        If the laptop is running in RAID mode and Linux does not recognize its
+        drives, it will have to be switched to AHCI. Unfortunately, this also
+        means Windows needs to be reconfigured, otherwise it won’t boot anymore.
+      </p>
+      <ol type={1}>
+        <li>
+          Click the Start Button and type <code>cmd</code>
+        </li>
+        <li>
+          Right-click the result and select <em>Run as administrator</em>
+        </li>
+        <li>
+          Type this command and press <em>ENTER:</em>{" "}
+          <code>
+            bcdedit /set {"{"}current{"}"} safeboot minimal
+          </code>{" "}
+          (ALT: <code>bcdedit /set safeboot minimal</code>)
+        </li>
+        <li>Restart the computer and enter BIOS Setup</li>
+        <li>Change the SATA Operation mode to AHCI from either IDE or RAID</li>
+        <li>
+          Save changes and exit Setup and Windows will automatically boot to
+          Safe Mode.
+        </li>
+        <li>
+          Right-click the Windows Start Menu once more. Choose Command Prompt
+          (Admin).
+        </li>
+        <li>
+          Type this command and press ENTER:{" "}
+          <code>
+            bcdedit /deletevalue {"{"}current{"}"} safeboot
+          </code>{" "}
+          (ALT: bcdedit /deletevalue safeboot)
+        </li>
+        <li>
+          Reboot once more and Windows will automatically start with AHCI
+          drivers enabled.
+        </li>
+      </ol>
+      <h3 data-number="6.8.4" id="bit-efi-is-used">
+        <span className="header-section-number">6.8.4</span> 32-bit EFI is used
+      </h3>
+      <ul>
+        <li>No provided install image will boot.</li>
+        <li>Windows is installed in 32-bit mode.</li>
+        <li>Some older Macbooks have this configuration.</li>
+        <li>
+          To install 64-bit Linux (we never encountered an actual 32-bit CPU
+          with this problem!), manually replace the bootloader with a grub
+          standalone.{" "}
+          <a href="https://wiki.archlinux.org/index.php/Unified_Extensible_Firmware_Interface#Booting_64-bit_kernel_on_32-bit_UEFI">
+            See the Arch Wiki.
+          </a>
+        </li>
+      </ul>
+      <h3 data-number="6.8.5" id="i-need-to-turn-off-bitlocker">
+        <span className="header-section-number">6.8.5</span> I need to turn off
+        Bitlocker
+      </h3>
+      <p>
+        <strong>
+          Do not change any BIOS/UEFI settings before disabling BitLocker!
+        </strong>{" "}
+        You will have to provide the decryption key otherwise, which the user
+        typically has no access to.
+      </p>
+      <ul>
+        <li>
+          Launch a command prompt with administrator rights and use{" "}
+          <code>manage-bde -off C:</code>, where <code>C:</code> is the drive
+          you want to decrypt.
+        </li>
+        <li>
+          Use the command <code>manage-bde -status</code> to query the
+          decryption status.
+        </li>
+        <li>
+          You will need to wait until decryption is complete, which can take a
+          long time.
+        </li>
+      </ul>
+      <h3 data-number="6.8.6" id="unlock-bitlocker-encrypted-devices">
+        <span className="header-section-number">6.8.6</span> Unlock BitLocker
+        Encrypted Devices
+      </h3>
+      <p>
+        If you change any UEFI settings on a BitLocker encrypted device
+        (typically Surface devices), you will be prompted for the BitLocker key
+        on next boot.
+      </p>
+      <p>
+        Since Surface devices come encrypted out of the box, the user does
+        typically not have that key and Windows will refuse to boot. If this
+        happens, resetting the UEFI settings to factory settings should fix the
+        issue.
+      </p>
+      <p>
+        Alternatively, you can just enter the correct Bitlocker key. This works
+        only if the user has a Microsoft account linked to the device. You can
+        get the BitLocker key as follows:
+      </p>
+      <ul>
+        <li>
+          On another device, google for “BitLocker Recovery Key”. You should
+          find several Microsoft Support or FAQ pages on how to recover the key.
+        </li>
+        <li>
+          Search for a link saying “To get your recovery key, go to BitLocker
+          Recovery Keys” or similar. Go there.
+        </li>
+        <li>
+          Ask the user to sign in using their Microsoft account. The website
+          will then display their recovery key, which can be used to unlock the
+          device.
+        </li>
+      </ul>
+      <h3 data-number="6.8.7" id="system-will-not-boot-under-any-circumstance">
+        <span className="header-section-number">6.8.7</span> System will not
+        boot under any circumstance
+      </h3>
+      <p>
+        Some very bad firmwares just refuse to boot GRUB, however you configure
+        it. This “bootloader hack” can be applied in these cases.
+      </p>
+      <ul>
+        <li>
+          Try to boot the actual distro that has been installed by “using a
+          device” to boot. Do so by holding shift while clicking on “reboot” in
+          Windows.
+        </li>
+        <li>
+          If that doesn’t work, boot a live system and chroot into the installed
+          system.
+        </li>
+        <li>
+          Once booted or chrooted into the Linux system, become root (sudo su)
+          and go to <code>/boot/efi/EFI/Microsoft/Boot</code> and locate a file
+          named <code>bootmgfw.efi</code>. Rename it to{" "}
+          <code>bootmgfw-original.efi</code>.
+        </li>
+        <li>
+          Go to <code>/boot/efi/EFI/grub2</code> (sometimes also just{" "}
+          <code>grub</code>) and locate the file <code>grubx64.efi</code>. Copy
+          it over to <code>/boot/efi/EFI/Microsoft/Boot/</code>. If a file
+          called <code>shimx64.efi</code> exists, copy that one over as well.
+        </li>
+        <li>
+          Find the file <code>grub.cfg</code> in{" "}
+          <code>/boot/efi/EFI/grub2</code> and copy it over to{" "}
+          <code>/boot/efi/EFI/Microsoft/Boot/</code>.
+        </li>
+        <li>
+          Go back to <code>/boot/efi/EFI/Microsoft/Boot/</code>. If{" "}
+          <code>shimx64.efi</code> exists, rename it to{" "}
+          <code>bootmgfw.efi</code>. If it does not exist, rename{" "}
+          <code>grubx64.efi</code> to <code>bootmgfw.efi</code>.
+        </li>
+        <li>
+          Now go to <code>/boot/grub/</code>, or <code>/boot/opensuse/</code>{" "}
+          (the exact folder path may vary). Find the file <code>grub.cfg</code>{" "}
+          and open it. Find the <code>menuentry</code> block for Windows
+          (usually called “Windows Bootloader (on /dev/sdx)” or similar). Copy
+          the entire block.
+        </li>
+        <li>
+          Uninstall the package <code>os-prober</code>.
+        </li>
+        <li>
+          Now go to /etc/grub.d. If a file with <code>os-prober</code> in its
+          name exists, delete it.
+        </li>
+        <li>
+          Find the file <code>40-custom.cfg</code>. If it doesn’t exist, create
+          it. Paste the menuentry block you copied earlier in this file.
+        </li>
+        <li>
+          In the text you just pasted, look for <code>bootmgfw.efi</code> and
+          change it to <code>bootmgfw-original.efi</code>.
+        </li>
+        <li>Save the file.</li>
+        <li>
+          Run <code>grub-mkconfig -o /boot/grub/grub.cfg</code>. Make sure the
+          file path matches the path where you originally found the{" "}
+          <code>grub.cfg</code> you copied the menuentry from.
+        </li>
+        <li>
+          Reboot and verify that grub now loads properly. Also test whether
+          Windows boots!
+        </li>
+      </ul>
+    </>
+  );
+}
diff --git a/components/loginButton.jsx b/components/loginButton.jsx
index 6b6603407e3bae68ab0f0aa81a1fcf2a44b16ae0..212226b366b01e119011cb3d7af92655a5b56c6a 100644
--- a/components/loginButton.jsx
+++ b/components/loginButton.jsx
@@ -4,6 +4,8 @@ import { Button, useMantineTheme } from "@mantine/core";
 
 import { Icon, ICONS } from "vseth-canine-ui";
 
+import { getAccentColor } from "../utilities/colors";
+
 const LoginButton = () => {
   const { data: session } = useSession();
   const theme = useMantineTheme();
@@ -11,7 +13,7 @@ const LoginButton = () => {
   if (session) {
     return (
       <Button
-        leftIcon={<Icon icon={ICONS.LEAVE} color="#4f2a17" />}
+        leftIcon={<Icon icon={ICONS.LEAVE} color={getAccentColor(theme)} />}
         variant="light"
         onClick={() => signOut()}
       >
@@ -21,7 +23,7 @@ const LoginButton = () => {
   }
   return (
     <Button
-      leftIcon={<Icon icon={ICONS.ENTER} color="#4f2a17" />}
+      leftIcon={<Icon icon={ICONS.ENTER} color={getAccentColor(theme)} />}
       variant="light"
       onClick={() => signIn("keycloak")}
     >
diff --git a/components/map.jsx b/components/map.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..aed21aa98a2051010b758e28a7c8029e280e65ad
--- /dev/null
+++ b/components/map.jsx
@@ -0,0 +1,112 @@
+import React, { useState, useEffect, useRef } from "react";
+
+import { Box, Card } from "@mantine/core";
+
+import about from "../content/about.json";
+
+import { Feature, Map, View, Overlay } from "ol";
+import TileLayer from "ol/layer/Tile";
+import OSM from "ol/source/OSM";
+import VectorLayer from "ol/layer/Vector";
+import VectorSource from "ol/source/Vector";
+import Style from "ol/style/Style";
+import Point from "ol/geom/Point";
+import { fromLonLat } from "ol/proj";
+
+export default function OfficeMap() {
+  const [map, setMap] = useState();
+  const mapElement = useRef();
+  const overlayElement = useRef();
+
+  const lat = 47.378532;
+  const lon = 8.5488535;
+  const zoomLevel = 17;
+
+  const osmLayer = new TileLayer({
+    preload: Infinity,
+    source: new OSM(),
+  });
+
+  const iconFeature = new Feature({
+    geometry: new Point(fromLonLat([lon, lat])),
+    name: "TheAlternative Office",
+  });
+
+  const vectorSource = new VectorSource({
+    features: [iconFeature],
+  });
+
+  const vectorLayer = new VectorLayer({
+    source: vectorSource,
+  });
+
+  const initialMap = new Map({
+    layers: [osmLayer, vectorLayer],
+    view: new View({
+      center: fromLonLat([lon, lat]),
+      zoom: zoomLevel,
+    }),
+  });
+
+  useEffect(() => {
+    initialMap.setTarget(mapElement.current);
+    const overlay = new Overlay({
+      element: overlayElement.current,
+      position: fromLonLat([lon, lat]),
+      positioning: "bottom-center",
+      stopEvent: false,
+    });
+    initialMap.addOverlay(overlay);
+    setMap(initialMap);
+  }, []);
+
+  return (
+    <Card
+      shadow="md"
+      style={{
+        width: "100%",
+        paddingTop: "100%",
+        position: "relative",
+      }}
+      withBorder
+    >
+      <Box
+        style={{
+          position: "absolute",
+          top: 0,
+          left: 0,
+          right: 0,
+          bottom: 0,
+          display: "flex",
+          alignItems: "stretch",
+          flexDirection: "column",
+        }}
+      >
+        <div
+          style={{ height: "100vh", width: "100%" }}
+          ref={mapElement}
+          className="map-container"
+        />
+        <div
+          ref={overlayElement}
+          id="marker"
+          style={{
+            border: "1px solid #000",
+            borderRadius: ".2rem",
+            backgroundColor: "#fff",
+            opacity: "0.9",
+            padding: "10px",
+            marginBottom: "10px",
+          }}
+        >
+          <b style={{ color: "black" }}>TheAlternative</b>
+          {about.address.map((line, i) => (
+            <p key={i} style={{ color: "black", marginBottom: 0 }}>
+              {line}
+            </p>
+          ))}
+        </div>
+      </Box>
+    </Card>
+  );
+}
diff --git a/components/navbar.jsx b/components/navbar.jsx
index 12f350e2d18e48c2c6577e643bd10ff00fd98aad..4982547eafa928492df3865f60529f9f925afcb2 100644
--- a/components/navbar.jsx
+++ b/components/navbar.jsx
@@ -1,10 +1,11 @@
-import React, { ReactNode, useState } from "react";
+import React, { ReactNode, useState, useEffect } from "react";
 import Link from "next/link";
 import { useRouter } from "next/router";
 
 import { useTranslation } from "next-i18next";
 import { useSession } from "next-auth/react";
 
+import { ColorSchemeProvider, Group, MediaQuery } from "@mantine/core";
 import { NotificationsProvider } from "@mantine/notifications";
 
 import { ApolloProvider } from "@apollo/client";
@@ -20,6 +21,7 @@ import {
 import hasAccess from "../utilities/hasAccess";
 
 import LoginButton from "../components/loginButton";
+import ThemeSwitcher from "../components/themeSwitcher";
 
 export default function Navbar(props) {
   const router = useRouter();
@@ -30,22 +32,63 @@ export default function Navbar(props) {
   const theme = makeVsethTheme();
   const [selectedLanguage, setSelectedLanguage] = React.useState(locale);
 
+  const [colorScheme, setColorScheme] = useState("dark");
+  const toggleColorScheme = (value) =>
+    setColorScheme(value || (colorScheme === "dark" ? "light" : "dark"));
+  theme.colorScheme = colorScheme;
+
   /*
    * VSETH Colors: See https://s.aschoch.ch/canine-colors
    * theme.colors.vsethMain[7] is #009fe3 (cyan)
    */
   theme.colors.vsethMain[7] = "#244471";
-  theme.colors.vsethMain[0] = "#b7cae5"; // light color
+  theme.colors.vsethMain[0] = "#dee5ef"; // light color
   theme.colors.vsethMain[1] = "#b7cae5"; // light color
   theme.colors.vsethMain[8] = "#4f6d96"; // light color
 
+  theme.colors.orange = [
+    "#f28a20",
+    "#f28a20",
+    "#f28a20",
+    "#f28a20",
+    "#f28a20",
+    "#f28a20",
+    "#f28a20",
+    "#f28a20",
+    "#f28a20",
+    "#f28a20",
+  ];
+
+  // NOTE: This is a hack, as colors are hardcoded in vseth-canine
+  useEffect(() => {
+    const footerDiv = document.querySelector("footer>div");
+    const footerLogo = document.querySelector("footer img");
+    const selectItems = document.querySelector("header a");
+
+    if (colorScheme == "dark") {
+      footerDiv.classList.add("vseth-footer-dark");
+      footerLogo.classList.add("vseth-logo-dark");
+      if (selectItems) selectItems.classList.add("vseth-text-dark");
+    } else {
+      footerDiv.classList.remove("vseth-footer-dark");
+      footerLogo.classList.remove("vseth-logo-dark");
+      if (selectItems) selectItems.classList.remove("vseth-text-dark");
+    }
+  }, [colorScheme]);
+
   const { data } = useConfig(
     "https://static.vseth.ethz.ch/assets/vseth-0522-thealt/config.json"
   );
 
   const customDemoNav = [
     { title: t("main"), href: "/" },
-  ]
+    { title: t("bashGuide"), href: "/bash" },
+    { title: t("installGuide"), href: "/install" },
+    {
+      title: t("courses"),
+      href: "https://gitlab.ethz.ch/thealternative/courses",
+    },
+  ];
 
   // if (hasAccess(session, true)) {
   //   customDemoNav.push({ title: t("menu"), href: "/menu" });
@@ -54,40 +97,73 @@ export default function Navbar(props) {
 
   return (
     <React.StrictMode>
-      <VSETHThemeProvider theme={theme}>
-        <VSETHExternalApp
-          selectedLanguage={selectedLanguage}
-          onLanguageSelect={(lang) => {
-            setSelectedLanguage(lang);
-            router.push({ pathname, query }, asPath, { locale: lang });
-          }}
-          languages={data?.languages}
-          title={"TheAlternative"}
-          appNav={customDemoNav}
-          organizationNav={data.externalNav}
-          makeWrapper={(url, child) => (
-            <Link
-              href={url}
-              style={{ textDecoration: "none", color: "inherit" }}
-            >
-              {child}
-            </Link>
-          )}
-          privacyPolicy={data?.privacy}
-          disclaimer={data?.copyright}
-          //activeHref is the current active url path. Required to style the active page in the Nav
-          activeHref={"/"}
-          socialMedia={data?.socialMedia}
-          logo={"https://static.vseth.ethz.ch/assets/vseth-0522-thealt/logo-inv.svg"}
-          loginButton={<LoginButton />}
-          signet={"https://static.vseth.ethz.ch/assets/vseth-0522-thealt/signet-inv.svg"}
-          size="xl"
-        >
-          <ApolloProvider client={apolloClient}>
-            <NotificationsProvider>{props.children}</NotificationsProvider>
-          </ApolloProvider>
-        </VSETHExternalApp>
-      </VSETHThemeProvider>
+      <ColorSchemeProvider
+        colorScheme={colorScheme}
+        toggleColorScheme={toggleColorScheme}
+      >
+        <VSETHThemeProvider theme={theme}>
+          <VSETHExternalApp
+            selectedLanguage={selectedLanguage}
+            onLanguageSelect={(lang) => {
+              setSelectedLanguage(lang);
+              router.push({ pathname, query }, asPath, { locale: lang });
+            }}
+            languages={data?.languages}
+            title={"TheAlternative"}
+            appNav={customDemoNav}
+            organizationNav={data.externalNav}
+            makeWrapper={(url, child) => (
+              <>
+                <MediaQuery smallerThan="md" styles={{ display: "none" }}>
+                  <Link
+                    href={url}
+                    style={{
+                      textDecoration: "none",
+                      color:
+                        theme.colorScheme == "light" ? "#333333b3" : "#C1C2C5",
+                    }}
+                  >
+                    {child}
+                  </Link>
+                </MediaQuery>
+                <MediaQuery largerThan="md" styles={{ display: "none" }}>
+                  <Link
+                    href={url}
+                    style={{
+                      textDecoration: "none",
+                      color: "#C1C2C5",
+                    }}
+                  >
+                    {child}
+                  </Link>
+                </MediaQuery>
+              </>
+            )}
+            privacyPolicy={data?.privacy}
+            disclaimer={data?.copyright}
+            //activeHref is the current active url path. Required to style the active page in the Nav
+            activeHref={"/"}
+            socialMedia={data?.socialMedia}
+            logo={
+              "https://static.vseth.ethz.ch/assets/vseth-0522-thealt/logo-inv.svg"
+            }
+            loginButton={
+              <Group>
+                <ThemeSwitcher />
+                <LoginButton />
+              </Group>
+            }
+            signet={
+              "https://static.vseth.ethz.ch/assets/vseth-0522-thealt/signet-inv.svg"
+            }
+            size="xl"
+          >
+            <ApolloProvider client={apolloClient}>
+              <NotificationsProvider>{props.children}</NotificationsProvider>
+            </ApolloProvider>
+          </VSETHExternalApp>
+        </VSETHThemeProvider>
+      </ColorSchemeProvider>
     </React.StrictMode>
   );
 }
diff --git a/components/noAdblockBanner.jsx b/components/noAdblockBanner.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..7616a45c8a4c3c5423a2fc33777473a971c199ff
--- /dev/null
+++ b/components/noAdblockBanner.jsx
@@ -0,0 +1,31 @@
+import { useState, useEffect } from "react";
+
+import { Alert } from "@mantine/core";
+
+import { useTranslation } from "next-i18next";
+
+import parse from "html-react-parser";
+
+import { isAdblocking } from "adblock-hunter";
+
+export default function NoAdblockBanner() {
+  const { t } = useTranslation("common");
+
+  const [hasAdblock, setHasAdblock] = useState(true);
+
+  useEffect(() => {
+    isAdblocking().then((isAdblocking) => {
+      setHasAdblock(isAdblocking);
+    });
+  }, []);
+
+  return (
+    <>
+      {!hasAdblock && (
+        <Alert title={t("noAdblockTitle")} color="red">
+          {parse(t("noAdblockText"))}
+        </Alert>
+      )}
+    </>
+  );
+}
diff --git a/components/philosophy.jsx b/components/philosophy.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..07451a6001b289639b5cf3fb7d203f362bddca90
--- /dev/null
+++ b/components/philosophy.jsx
@@ -0,0 +1,35 @@
+import { useRouter } from "next/router";
+
+import { Blockquote, Space } from "@mantine/core";
+
+import parse from "html-react-parser";
+
+import philosophy from "../content/philosophy";
+
+export default function Philosophy() {
+  const { locale } = useRouter();
+
+  return (
+    <>
+      {philosophy.map((entry, i) => (
+        <div key={i}>
+          <h2 style={{ margin: 0 }}>{entry.title[locale || "en"]}</h2>
+
+          <Blockquote cite={"— " + entry.source} color="orange">
+            {entry.summary[locale || "en"]}
+          </Blockquote>
+
+          {entry.definition[locale || "en"].map((def, i) => (
+            <p key={i}>{parse(def)}</p>
+          ))}
+
+          <Space h="md" />
+          <p>{parse(entry.examples[locale || "en"])}</p>
+
+          <Space h="xl" />
+          <Space h="xl" />
+        </div>
+      ))}
+    </>
+  );
+}
diff --git a/components/signUpsModal.jsx b/components/signUpsModal.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..f877fd1660fbd7f27c25c74431d6561698b57177
--- /dev/null
+++ b/components/signUpsModal.jsx
@@ -0,0 +1,42 @@
+import { useTranslation } from "next-i18next";
+
+import { Button, Modal, Table } from "@mantine/core";
+
+export default function SignUpsModal({ open, close, event }) {
+  const { t } = useTranslation("common");
+
+  const copyMailAddresses = () => {
+    const addresses = event.signUps.map((signUp) => signUp.email).join(", ");
+    navigator.clipboard.writeText(addresses);
+  };
+
+  if (!event) return <></>;
+
+  return (
+    <Modal opened={open} onClose={close} size="xl">
+      <h2>{t("participants")}</h2>
+      <Table striped highlightOnHover>
+        <thead>
+          <tr>
+            <th>Name</th>
+            <th>Email</th>
+          </tr>
+        </thead>
+        <tbody>
+          {event.signUps.map((signUp, i) => (
+            <tr key={i}>
+              <td>
+                {signUp.firstName} {signUp.lastName}
+              </td>
+              <td>{signUp.email}</td>
+            </tr>
+          ))}
+        </tbody>
+      </Table>
+
+      <Button onClick={copyMailAddresses} mt="md">
+        {t("copyMailAddresses")}
+      </Button>
+    </Modal>
+  );
+}
diff --git a/components/themeSwitcher.jsx b/components/themeSwitcher.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..ed29c7e465d807aeae9cdd8a94df160091138dbe
--- /dev/null
+++ b/components/themeSwitcher.jsx
@@ -0,0 +1,28 @@
+import { Switch, useMantineTheme, useMantineColorScheme } from "@mantine/core";
+
+import { Icon, ICONS } from "vseth-canine-ui";
+
+export default function ThemeSwitcher() {
+  const theme = useMantineTheme();
+  const { colorScheme, toggleColorScheme } = useMantineColorScheme();
+  const dark = colorScheme === "dark";
+
+  return (
+    <Switch
+      size="md"
+      color="vsethMain"
+      offLabel={
+        <Icon
+          icon={ICONS.SUN}
+          size={16}
+          color={theme.colors[theme.primaryColor][theme.primaryShade]}
+        />
+      }
+      onLabel={<Icon icon={ICONS.MOON} size={16} color="#ffffff" />}
+      checked={dark}
+      onChange={() => {
+        toggleColorScheme();
+      }}
+    />
+  );
+}
diff --git a/components/toc.jsx b/components/toc.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..6e85d4da6c12fb188bb0d3ae1a13d867697e8001
--- /dev/null
+++ b/components/toc.jsx
@@ -0,0 +1,128 @@
+import { useState, useEffect } from "react";
+
+import {
+  createStyles,
+  Box,
+  Text,
+  Group,
+  rem,
+  useMantineTheme,
+} from "@mantine/core";
+
+import { Icon, ICONS } from "vseth-canine-ui";
+
+const useStyles = createStyles((theme) => ({
+  link: {
+    ...theme.fn.focusStyles(),
+    display: "block",
+    textDecoration: "none",
+    color: theme.colorScheme === "dark" ? theme.colors.dark[0] : theme.black,
+    lineHeight: 1.2,
+    fontSize: theme.fontSizes.sm,
+    padding: "5px",
+    borderTopRightRadius: theme.radius.lg,
+    borderBottomRightRadius: theme.radius.lg,
+    borderLeft: `2px solid ${
+      theme.colorScheme === "dark" ? theme.colors.dark[4] : theme.colors.gray[3]
+    }`,
+
+    "&:hover": {
+      backgroundColor:
+        theme.colorScheme === "dark"
+          ? theme.colors.dark[6]
+          : theme.colors.gray[0],
+    },
+  },
+
+  linkActive: {
+    fontWeight: 1000,
+    borderLeftColor:
+      theme.colors[theme.primaryColor][theme.colorScheme === "dark" ? 6 : 7],
+    color:
+      theme.colors[theme.primaryColor][theme.colorScheme === "dark" ? 2 : 7],
+
+    "&, &:hover": {
+      backgroundColor:
+        theme.colorScheme === "dark"
+          ? theme.fn.rgba(theme.colors[theme.primaryColor][9], 0.25)
+          : theme.colors[theme.primaryColor][0],
+    },
+  },
+}));
+
+export default function TOC() {
+  const [items, setItems] = useState([]);
+  const [active, setActive] = useState("");
+  const theme = useMantineTheme();
+  const { classes, cx } = useStyles();
+
+  const findClosestHeading = () => {
+    const headings = document.querySelectorAll("h1, h2, h3");
+    const currentPosition = window.scrollY;
+
+    let closestHeading = null;
+    let closestDistance = Infinity;
+
+    headings.forEach((heading) => {
+      const headingPosition =
+        heading.getBoundingClientRect().top + window.scrollY;
+      const distance = Math.abs(currentPosition - headingPosition);
+
+      if (distance < closestDistance) {
+        closestHeading = heading;
+        closestDistance = distance;
+      }
+    });
+
+    return closestHeading;
+  };
+
+  useEffect(() => {
+    const headings = [...document.querySelectorAll("h1, h2, h3")];
+    const links = headings.map((item) => ({
+      link: "#" + item.id,
+      label: item.innerText,
+      order: Number(item.localName[item.localName.length - 1]),
+    }));
+    setItems(links);
+
+    setActive("#" + findClosestHeading().id);
+    document.addEventListener("scroll", function (e) {
+      setActive("#" + findClosestHeading().id);
+    });
+  }, []);
+
+  const entries = items.map((item) => (
+    <Box
+      component="a"
+      href={item.link}
+      key={item.label}
+      className={cx(classes.link, {
+        [classes.linkActive]: active === item.link,
+      })}
+      sx={(theme) => ({
+        paddingLeft: `calc(${item.order} * ${theme.spacing.md}px)`,
+      })}
+    >
+      {item.label}
+    </Box>
+  ));
+
+  return (
+    <div
+      style={{
+        position: "sticky",
+        top: "2rem",
+        maxHeight: "calc(100vh - 2rem)",
+        overflowY: "auto",
+        marginBottom: "20px",
+      }}
+    >
+      <Group mb="md">
+        <Icon icon={ICONS.LIST} />
+        <Text>Table of contents</Text>
+      </Group>
+      {entries}
+    </div>
+  );
+}
diff --git a/content/about.json b/content/about.json
new file mode 100644
index 0000000000000000000000000000000000000000..9c5d978f60a013bd07a1c5a93f3c1249b0d44b5f
--- /dev/null
+++ b/content/about.json
@@ -0,0 +1,25 @@
+{
+  "description": {
+    "de": "Wir sind Absolvent*innen und Studierende aus verschiedenen Studienrichtungen. Gemeinsam bieten wir Kurse und andere Bildungsmaterialien für Open Source und Freie Software an. Unser Ziel ist es, die Einstiegshürde in diese Themen zu senken und gleichzeitig Spaß daran zu haben, anderen etwas beizubringen!",
+    "en": "We are graduates and undergraduates from different fields of study. Together, we provide courses and other educational materials for Open Source and Free Software. Our goal is to lower the entry barrier around these topics and simultaneously have fun teaching others!"
+  },
+  "address": [
+    "CAB E14",
+    "Universitätstrasse 6",
+    "8092 Zürich"
+  ],
+  "links": [
+    {
+      "text": "GitHub",
+      "url": "https://github.com/TheAlternativeZurich"
+    },
+    {
+      "text": "GitLab",
+      "url": "https://gitlab.ethz.ch/thealternative"
+    },
+    {
+      "text": "Mastodon",
+      "url": "https://linuxrocks.online/@TheAlternative"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/content/board.json b/content/board.json
new file mode 100644
index 0000000000000000000000000000000000000000..826bbfa442fc3173b4c45d36ab4b5fbce5218b6e
--- /dev/null
+++ b/content/board.json
@@ -0,0 +1,91 @@
+[
+  {
+    "name": "Noah Marti",
+    "role": {
+      "de": "Präsident",
+      "en": "President"
+    },
+    "image": "/images/board/placeholder.png",
+    "mail": "praesidium@thealternative.ch"
+  },
+  {
+    "name":  "Johanna Polzin",
+    "role": {
+      "de": "Vizepräsidentin / Stammtische",
+      "en": "Vice President / Stammtisch"
+    },
+    "image": "/images/board/placeholder_girl.png",
+    "mail": "praesidium@thealternative.ch"
+  },
+  {
+    "name": "Alexander Schoch",
+    "role": {
+      "de": "Events",
+      "en": "Events"
+    },
+    "image": "/images/board/alex.png",
+    "mail": "alexander.schoch@vseth.ethz.ch"
+  },
+  {
+    "name": "Jean-Claude Graf",
+    "role": {
+      "de": "Kommunikation",
+      "en": "Communication"
+    },
+    "image": "/images/board/jeanclaude.jpg",
+    "mail": "kommunikation@thealternative.ch"
+  },
+  {
+    "name": "Sophie Eisenring",
+    "role": {
+      "de": "Kommunikation: Design",
+      "en": "Communication: Design"
+    },
+    "image": "/images/board/sophie.png",
+    "mail": "kommunikation@thealternative.ch"
+  },
+  {
+    "name": "Jindřich Dušek",
+    "role": {
+      "de": "GNU/Linux Enjoyer",
+      "en": "GNU/Linux Enjoyer"
+    },
+    "image": "/images/board/jindra.png"
+  },
+  {
+    "name": "Corinne Furrer",
+    "role": {
+      "de": "Infrastruktur",
+      "en": "Infrastructure"
+    },
+    "image": "/images/board/placeholder_girl.png",
+    "mail": "server@thealternative.ch"
+  },
+  {
+    "name": " Fadri Lardon",
+    "role": {
+      "de": "Install Event / Support",
+      "en": "Install Event / Support"
+    },
+    "image": "/images/board/fadri.jpg",
+    "mail": "lardonf@student.ethz.ch"
+  },
+  {
+    "name": "Nicolas König",
+    "role": {
+      "de": "Aktives Mitglied",
+      "en": "Active Member"
+    },
+    "image": "/images/board/nicolas.jpg",
+    "mail": "koenigni@student.ethz.ch"
+  },
+  {
+    "name": "Gianni Gugolz",
+    "role": {
+      "de": "Aktives Mitglied",
+      "en": "Active Member"
+    },
+    "image": "/images/board/placeholder.png",
+    "mail": "ggugolz@student.ethz.ch"
+  }
+]
diff --git a/content/eventTemplates.json b/content/eventTemplates.json
new file mode 100644
index 0000000000000000000000000000000000000000..6aec7168d9559f06ec6207ea0d3a10153caf7769
--- /dev/null
+++ b/content/eventTemplates.json
@@ -0,0 +1,97 @@
+[
+  {
+    "title": "Stammtisch",
+    "description": "Join our Stammtisch! We meet in a casual atmosphere, have a drink and discuss upcoming technical trends. If you have troubles with Linux, bring your Laptop and we will be glad to help.",
+    "time": [
+      "18:00",
+      "22:00"
+    ],
+    "place": "ETH CAB E 14",
+    "isStammtisch": true
+  },
+  {
+    "title": "Introduction to Open Source Software",
+    "description": "<p>Discover the differences between Free and Open Source Software (FOSS) and proprietary software, and find out why these differences matter.</p><p>This captivating lecture will provide you with information about the advantages of Free Software licenses, as well as show you the historical background of the Linux kernel.</p><p>Additionally, we show why Free Software and Open Data is important even beyond the world of Linux.</p><p>Learn how you can regain full control over your data!</p>",
+    "time": [
+      "18:15",
+      "20:00"
+    ],
+    "isStammtisch": false
+  },
+  {
+    "title": "Introduction to Linux",
+    "description": "<p>In this course you will learn about the wide family of free operating systems based on the Linux kernel, some of the most useful software tools available for them, as well as the philosophy that made them so successful.</p><p>Find out how easy to use and yet powerful Linux systems are, discover their advantages when compared to other operating systems, and get to understand their basic structure and most important concepts.</p><p>Furthermore, discover different flavours of Linux and get a feeling for which distribution and desktop environment would be the right match for you.</p>",
+    "time": [
+      "18:15",
+      "20:00"
+    ],
+    "isStammtisch": false
+  },
+  {
+    "title": "Install Event (ETH)",
+    "speaker": "TheAlternative",
+    "description": "<p>Get started with Linux by installing it on your computer.</p><p>Of course, we'll help you: Bring your laptop and charger and we will personally assist you with the installation of Linux as well as with your first steps and basic customization.</p><p>You can choose to keep your existing operating system and install Linux next to it.</p><p>Still, it's important to back up your data before you come, just to be on the safe side.</p><p>You may of course stay longer than the indicated time should we encounter issues with installing Linux on your laptop.</p><p>ChromeBooks (all versions), Apple MacBook Pros (after Oct. 2016) and Apple MacBooks (12\" model) are not well supported by Linux due to hardware restrictions, and we do not recommend installing Linux on those devices.</p><p>If you intend to buy a new laptop to install Linux on, stay away from these devices altogether.</p>",
+    "time": [
+      "17:30",
+      "21:00"
+    ],
+    "place": "Student Project House (Clausiusstrasse 16, 8006 Zürich)",
+    "isStammtisch": false
+  },
+  {
+    "title": "Install Event (UZH)",
+    "speaker": "TheAlternative",
+    "description": "<p>Get started with Linux by installing it on your computer.</p><p>Of course, we'll help you: Bring your laptop and charger and we will personally assist you with the installation of Linux as well as with your first steps and basic customization.</p><p>You can choose to keep your existing operating system and install Linux next to it.</p><p>Still, it's important to back up your data before you come, just to be on the safe side.</p><p>You may of course stay longer than the indicated time should we encounter issues with installing Linux on your laptop.</p><p>ChromeBooks (all versions), Apple MacBook Pros (after Oct. 2016) and Apple MacBooks (12\" model) are not well supported by Linux due to hardware restrictions, and we do not recommend installing Linux on those devices.</p><p>If you intend to buy a new laptop to install Linux on, stay away from these devices altogether.</p>",
+    "time": [
+      "17:30",
+      "21:00"
+    ],
+    "isStammtisch": false
+  },
+  {
+    "title": "Console Toolkit",
+    "description": "<p>This event is a collaboration with Student Project House.</p><p>Linux is well-known for being configurable and fitting many different styles of use. But what can you do with it?</p><p>Our goal in the Linux Toolbox course is to introduce a large range of tools and to teach you how you can profit from them. We'll show you typical tasks that Linux is good at, such as renaming hundreds of files, searching and replacing text, automatic downloading etc.. This way, you'll be able to recognize those tasks in the wild and don't have to do them by hand.</p><p>Linux has many useful tools, so we don't intend to cover them all in detail. We'll instead take a sweeping glance to cover as many use cases as possible and provide you with learning resources if you want to delve deeper into a topic. Most of the course will take place on the command line, but no prerequisite knowledge is required.</p>",
+    "time": [
+      "18:15",
+      "20:00"
+    ],
+    "place": "Student Project House (Clausiusstrasse 16, 8006 Zürich)",
+    "isStammtisch": false
+  },
+  {
+    "title": "Git and GitLab",
+    "description": "<p>This event is a collaboration with Student Project House.</p><p>Git is the state-of-the-art version control system, taking away the pain of continuously changing file versions. Keep track of who changed what, when and why, and revert changes easily.</p><p>GitLab allows you to save the files to the cloud, giving you a secure backup location and enabling easy collaboration. Never lose your files again, and coordinate changes in even bigger projects with ease.</p><p>This course gives you a solid understanding of git and GitLab, including its basic concepts.</p><p>We will have exercise breaks where you can apply the concepts at your own pace.</p>",
+    "time": [
+      "18:15",
+      "20:00"
+    ],
+    "place": "Student Project House (Clausiusstrasse 16, 8006 Zürich)",
+    "isStammtisch": false
+  },
+  {
+    "title": "Bash",
+    "description": "<p>This event is a collaboration with Student Project House.</p><p>Learn how you can use Bash to program simple scripts that can save you a lot of work. Bash is a scripting language that is designed to interact with other programs and your system easily. Whether you want to backup your newest files to a hard drive or quickly download a lot of PDFs—with Bash, you can do it at a keystroke.</p>",
+    "time": [
+      "18:15",
+      "20:00"
+    ],
+    "place": "Student Project House (Clausiusstrasse 16, 8006 Zürich)",
+    "isStammtisch": false
+  },
+  {
+    "title": "Spotlight 1",
+    "time": [
+      "18:15",
+      "20:00"
+    ],
+    "isStammtisch": false
+  },
+  {
+    "title": "Spotlight 2",
+    "time": [
+      "18:15",
+      "20:00"
+    ],
+    "isStammtisch": false
+  }
+]
\ No newline at end of file
diff --git a/content/images/board/alex.png b/content/images/board/alex.png
new file mode 100644
index 0000000000000000000000000000000000000000..121c1f931456d2aa2a895669f4d34efd800b0eb1
Binary files /dev/null and b/content/images/board/alex.png differ
diff --git a/content/images/board/fadri.jpg b/content/images/board/fadri.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..2047705569646c434b5e4d783b67c943cd2593e2
Binary files /dev/null and b/content/images/board/fadri.jpg differ
diff --git a/content/images/board/jeanclaude.jpg b/content/images/board/jeanclaude.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..5d7bc0d20208568e3e85e20e5f4fa2dd9be08b90
Binary files /dev/null and b/content/images/board/jeanclaude.jpg differ
diff --git a/content/images/board/jindra.png b/content/images/board/jindra.png
new file mode 100644
index 0000000000000000000000000000000000000000..ab33c090480d96b919c0b737f8daf2892abd938c
Binary files /dev/null and b/content/images/board/jindra.png differ
diff --git a/content/images/board/nicolas.jpg b/content/images/board/nicolas.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..084b440a18844ba82e129ff52d8c09ecf6428ae6
Binary files /dev/null and b/content/images/board/nicolas.jpg differ
diff --git a/content/images/board/placeholder.png b/content/images/board/placeholder.png
new file mode 100644
index 0000000000000000000000000000000000000000..1aa55e6838eb027ae34020aa91a25e8932b44a9c
Binary files /dev/null and b/content/images/board/placeholder.png differ
diff --git a/content/images/board/placeholder_girl.png b/content/images/board/placeholder_girl.png
new file mode 100644
index 0000000000000000000000000000000000000000..3d905c6bd29cfbe53281471beda2378d5cfe0f90
Binary files /dev/null and b/content/images/board/placeholder_girl.png differ
diff --git a/content/images/board/sophie.png b/content/images/board/sophie.png
new file mode 100644
index 0000000000000000000000000000000000000000..6b7f34290d79ed55fdcfd9728082c3067c7d57e4
Binary files /dev/null and b/content/images/board/sophie.png differ
diff --git a/content/philosophy.json b/content/philosophy.json
new file mode 100644
index 0000000000000000000000000000000000000000..91850773e2fd59d257b4df3d7aa80cdf282b60b9
--- /dev/null
+++ b/content/philosophy.json
@@ -0,0 +1,102 @@
+[
+  {
+    "title": {
+      "de": "Open Source",
+      "en": "Open Source"
+    },
+    "summary": {
+      "de": "(übersetzt) Der Begriff \"Open Source\" bezieht sich auf etwas, das Personen verändern und verbreiten können, weil es öffentlich verfügbar ist.",
+      "en": "The term \"open source\" refers to something people can modify and share because its design is publicly accessible."
+    },
+    "source": "opensource.com",
+    "definition": {
+      "de": [
+        "Open-Source-Software ermutigt andere dazu, zu verstehen, wie etwas genau funktioniert: Das Innenleben des Programms wird veröffentlicht. Je nach der genauen Lizenz, die verwendet wird, darf der Benutzer das Werk auch ausführen, verändern und weitergeben.",
+        "Mit Open Source können Sie sicherstellen, dass das Programm nicht etwas auf Ihrem Gerät ausführt, was Sie nicht wollen, z. B. die Überwachung Ihrer Aktivitäten oder den Diebstahl Ihrer Rechenleistung für eigene Zwecke. Wenn Software als Open Source beworben wird, garantiert dies jedoch nicht unbedingt die Rechte zur Änderung und Weitergabe des Werks."
+      ],
+      "en": [
+        "Open Source software encourages others to understand how something works exactly: The inner workings of the program are published. Depending on the exact license used, the user may also be allowed to run, modify and distribute the work.",
+        "Using Open Source, you can check that the program does not execute something on your device you do not want; like surveilling your activities or stealing your computational power for its own purposes. However, when software is advertised as Open Source, it does not necessarily guarantee the rights to modify and distribute the work."
+      ]
+    },
+    "examples": {
+      "de": "Beispiele sind, u.a., <a target='_blank' href='https://www.mozilla.org/de/firefox/'>Firefox</a> und <a target='_blank' href='https://www.python.org/'>Python</a>.",
+      "en": "Examples include <a target='_blank' href='https://www.mozilla.org/de/firefox/'>Firefox</a> and <a target='_blank' href='https://www.python.org/'>Python</a>."
+    }
+  },
+  {
+    "title": {
+      "de": "Freie Software",
+      "en": "Free Software"
+    },
+    "summary": {
+      "de": "(übersetzt) Freie Software Entwickler garantieren, dass alle Benutzer den Quellcode studieren, verändern und teilen können.",
+      "en": "Free software developers guarantee [...] [that] any user can study the source code, modify it, and share the program."
+    },
+    "source": "fsf.org",
+    "definition": {
+      "de": [
+        "Freie Software <b>garantiert</b> das Recht, das Werk auszuführen, zu verändern und zu verbreiten. Abhängig von der genauen Lizenz kann erzwungen werden, dass alle abgeleitete Software auch die gleichen Rechte gewähren muss (dies wird <i>Copyleft</i> genannt).",
+        "Mit Freier Software können Sie sie an Ihre Bedürfnisse anpassen, z. B. indem Sie wichtige Funktionen für Ihre Arbeitsabläufe hinzufügen. Wenn Sie sich für eine Copyleft-Lizenz entscheiden, können Sie außerdem sicher sein, dass Ihre Arbeit allen künftigen Nutzern der Software in gleicher Weise zugute kommt."
+      ],
+      "en": [
+        "Free Software <b>guarantees</b> the rights to run, modify and distribute the work. Depending on the exact license used, it may be enforced that all derivative software must also grant the same rights (this is called <i>Copyleft</i>).",
+        "Using Free Software, you are allowed to adapt it to your needs; like adding functionality critical to your workflows. If you decide to use a Copyleft license, you can additionally be sure your work will benefit all future users of the software in the same way."
+      ]
+    },
+    "examples": {
+      "de": "Beispiele sind, u.a., <a target='_blank' href='https://www.videolan.org/vlc/index.de.html'>VLC Media Player</a> und <a target='_blank' href='https://www.linux.org/'>Linux</a>.",
+      "en": "Examples include <a target='_blank' href='https://www.videolan.org/vlc/index.de.html'>VLC Media Player</a> and <a target='_blank' href='https://www.linux.org/'>Linux</a>."
+    }
+  },
+  {
+    "title": {
+      "de": "Proprietäre Software",
+      "en": "Proprietary Software"
+    },
+    "summary": {
+      "de": "(übersetzt) Nur die Originalautoren von proprietärer Software dürfen diese Software legal kopieren, prüfen und verändern. Um urheberrechtlich geschützte Software zu verwenden, müssen Computernutzer (...) zustimmen, dass sie nichts mit der Software tun werden, was die Autoren der Software nicht ausdrücklich erlaubt haben.",
+      "en": "Only the original authors of proprietary software can legally copy, inspect, and alter that software. To use proprietary software, computer users must agree (...) that they will not do anything with the software that the software's authors have not expressly permitted."
+    },
+    "source": "opensource.com",
+    "definition": {
+      "de": [
+        "Proprietäre Software schränkt die Möglichkeiten der Nutzer, mit der auf ihrem Gerät laufenden Software zu interagieren, stark ein und erlaubt es ihnen nicht, den Quellcode zu lesen, zu ändern oder weiterzugeben.",
+        "Wenn Sie proprietäre Software verwenden, laufen Sie Gefahr, wichtige Funktionen für Ihren Arbeitsablauf zu verlieren (weil der Eigentümer sie nicht mehr zur Verfügung stellt), Ihre Dateien nicht mehr öffnen zu können (weil ein Dateityp nicht mehr unterstützt wird) oder überhöhte Lizenzgebühren zu zahlen (weil es keine vergleichbaren Alternativen gibt)."
+      ],
+      "en": [
+        "Proprietary Software severely restricts how users can interact with the software running on their device and does not allow them to read, modify or distribute its source code.",
+        "Using Proprietary Software, you are in danger to lose functionality critical to your workflow (because the owner chose not to provide it anymore), to no longer be able to open your files (because a filetype is no longer supported) or to pay excessive license fees (because there are no comparable alternatives)."
+      ]
+    },
+    "examples": {
+      "de": "Beispiele sind, u.a., <a target='_blank' href='https://www.microsoft.com/de-ch/windows'>Windows</a> and <a target='_blank' href='https://get.adobe.com/de/reader'>Adobe Reader</a>",
+      "en": "Examples include <a target='_blank' href='https://www.microsoft.com/de-ch/windows'>Windows</a> and <a target='_blank' href='https://get.adobe.com/de/reader'>Adobe Reader</a>"
+    }
+  },
+  {
+    "title": {
+      "de": "Datenschutz",
+      "en": "Privacy"
+    },
+    "summary": {
+      "de": "(übersetzt) Niemand darf willkürlichen Eingriffen in sein Privatleben, seine Familie, seine Wohnung oder seinen Schriftverkehr sowie Angriffen auf seine Ehre und seinen Ruf ausgesetzt werden",
+      "en": "No one shall be subjected to arbitrary interference with his privacy, family, home or correspondence, nor to attacks upon his honor and reputation."
+    },
+    "source": "Article 12 of Universal Declaration of Human Rights (1948)",
+    "definition": {
+      "de": [
+        "Die Privatsphäre ist von grundlegender Bedeutung, um sich selbst und die Menschen in Ihrem Umfeld vor Manipulationen zu schützen.",
+        "Die meisten Webseiten und Programme verfolgen alles, was Sie tun oder anklicken. Verwenden Sie Open-Source-Software und <a target='_blank' href='https://addons.mozilla.org/de/firefox/addon/ublock-origin/'>Adblocker</a>, um einigermaßen sicher zu sein, dass Sie nicht Opfer einer Überwachung werden. Stellen Sie Anonymität als Standard ein, um zu vermeiden, dass diejenigen auffallen, die anonym bleiben müssen."
+      ],
+      "en": [
+        " Privacy is fundamental to protect yourself and those around you from manipulation.",
+        "Most webpages and programs track anything you do or click. Use Open Source Software and <a target='_blank' href='https://addons.mozilla.org/de/firefox/addon/ublock-origin/'>Adblockers</a> to be reasonably sure that you are not a victim of surveillance. Make anonymity the default to avoid making those stand out who must stay anonymous."
+      ]
+    },
+    "examples": {
+      "de": "Facebook verrät mehr über Ihre Persönlichkeit als Ihre Freunde es könnten [<a target='_blank' href='https://www.pnas.org/content/112/4/1036'>Paper</a>], stellen Sie sich also vor, was Ihr Browserverlauf über Sie verrät.<br />Eine Firma namens Cambridge Analytica (und wahrscheinlich viele andere) nutzt diese Technik, um Wahlergebnisse zu beeinflussen [<a target='_blank' href='https://www.tagesanzeiger.ch/ausland/europa/diese-firma-weiss-was-sie-denken/story/17474918'>Tagesanzeiger</a>]<br />Edward Snowden nutzte einen Anonymitätsdienst, der sich darauf verlässt, dass viele \"normale\" Menschen das System nutzen, um keinen Verdacht zu erregen [<a target='_blank' href='https://twitter.com/Snowden/status/1165297667490103302'>Twitter</a>].",
+      "en": "Facebook reveals more about your personality than your friends could [<a target='_blank' href='https://www.pnas.org/content/112/4/1036'>Paper</a>], so imagine what your browser history tells about you.<br />A firm called Cambridge Analytica (and probably many others) use this technique to influence outcomes of elections [<a target='_blank' href='https://www.tagesanzeiger.ch/ausland/europa/diese-firma-weiss-was-sie-denken/story/17474918'>Tagesanzeiger</a>].<br />Edward Snowden used an anonymity service that relies on many \"ordinary\" people using the system to avoid suspicion [<a target='_blank' href='https://twitter.com/Snowden/status/1165297667490103302'>Twitter</a>]."
+    }
+  }
+]
\ No newline at end of file
diff --git a/entrypoint.sh b/entrypoint.sh
index 1b78650254a290fce39e20392dd327bf1efe95dc..bf7368213eb717d957b262d5eeac666adb9ce41a 100644
--- a/entrypoint.sh
+++ b/entrypoint.sh
@@ -1,5 +1,6 @@
 #!/bin/bash
 
-echo "DATABASE_URL=mysql://$SIP_MYSQL_PPLW_USER:$SIP_MYSQL_PPLW_PW@$SIP_MYSQL_PPLW_SERVER:$SIP_MYSQL_PPLW_PORT/$SIP_MYSQL_PPLW_NAME?schema=public" > .env
+echo "DATABASE_URL=mysql://$SIP_MYSQL_ALT_USER:$SIP_MYSQL_ALT_PW@$SIP_MYSQL_ALT_SERVER:$SIP_MYSQL_ALT_PORT/$SIP_MYSQL_ALT_NAME?schema=public" > .env
 
+npx prisma generate
 npm run start
diff --git a/graphql/context.js b/graphql/context.js
new file mode 100644
index 0000000000000000000000000000000000000000..b0326799274dd58debf90a382a646f7cbb9e3738
--- /dev/null
+++ b/graphql/context.js
@@ -0,0 +1,11 @@
+import { PrismaClient } from "@prisma/client";
+import prisma from "../lib/prisma";
+
+import { NextApiRequest, NextApiResponse } from "next";
+
+export async function createContext(req, res) {
+  return {
+    prisma,
+  };
+}
+
diff --git a/graphql/resolvers.js b/graphql/resolvers.js
new file mode 100644
index 0000000000000000000000000000000000000000..ed3f0b85ec434cb7794818d2a749f9cb29dff4cd
--- /dev/null
+++ b/graphql/resolvers.js
@@ -0,0 +1,95 @@
+import prisma from "../lib/prisma";
+import { getServerSession } from "next-auth/next";
+import { authOptions } from "../pages/api/auth/[...nextauth]";
+
+import hasAccess from "../utilities/hasAccess";
+import { isInFuture } from '../utilities/dates';
+
+export const resolvers = {
+  Query: {
+    getEvents: async () => {
+      const events = await prisma.event.findMany();
+      return events;
+    },
+    getFutureEvents: async (_, data, { session }) => {
+      const events = await prisma.event.findMany({
+        include: {
+          signUps: {
+            select: {
+              sub: true,
+              firstName: hasAccess(session, true),
+              lastName: hasAccess(session, true),
+              email: hasAccess(session, true)
+            }
+          },
+        }
+      });
+      const futureEvents = events.filter((event) => isInFuture(event));
+      return futureEvents;
+    },
+  },
+  Mutation: {
+    addEvent: async (_, data, { session }) => {
+      if (!hasAccess(session, true)) return false;
+
+      const {time, ...dataWithoutTime} = data;
+      const event = await prisma.event.create({
+        data: {
+          ...dataWithoutTime,
+          startTime: data.time[0],
+          endTime: data.time[1]
+        },
+      });
+      return event ? true : false;
+    },
+    editEvent: async (_, data, { session }) => {
+      if (!hasAccess(session, true)) return false;
+
+      const {time, ...dataWithoutTime} = data;
+      const event = await prisma.event.update({
+        where: { id: data.id },
+        data: {
+          ...dataWithoutTime,
+          startTime: data.time[0],
+          endTime: data.time[1]
+        },
+      });
+      return event ? true : false;
+    },
+    addSignUp: async(_, { id }, { session }) => {
+      if(!hasAccess(session, false)) return false;
+
+      const signUp = await prisma.signUp.create({
+        data: {
+          eventId: id,
+          sub: session.info.payload.sub,
+          firstName: session.info.payload.given_name,
+          lastName: session.info.payload.family_name,
+          email: session.info.payload.email
+        }
+      });
+
+      return signUp ? true : false;
+    },
+    removeSignUp: async(_, { id }, { session }) => {
+      if(!hasAccess(session, false)) return false;
+
+      const signUp = await prisma.signUp.findMany({
+        where: {
+          eventId: id,
+          sub: session.info.payload.sub
+        }
+      });
+
+      if(signUp.length == 0) return false;
+
+      await prisma.signUp.delete({
+        where: {
+          id: signUp[0].id
+        }
+      });
+
+      return true;
+    }
+  },
+};
diff --git a/graphql/schema.js b/graphql/schema.js
new file mode 100644
index 0000000000000000000000000000000000000000..74a0f41866bad7f48b8f750cda26492fa03d7a1a
--- /dev/null
+++ b/graphql/schema.js
@@ -0,0 +1,41 @@
+import { DateTime } from 'graphql-scalars';
+
+export const typeDefs = `
+  scalar DateTime
+
+  type Event {
+    id: Int
+    title: String
+    speaker: String
+    description: String
+    date: DateTime
+    startTime: DateTime
+    endTime: DateTime
+    place: String
+    signUp: String
+    isStammtisch: Boolean
+    signUps: [SignUp]
+  }
+
+  type SignUp {
+    id: Int
+    sub: String
+    firstName: String
+    lastName: String
+    email: String
+    event: Event
+  }
+
+  type Query {
+    getEvents: [Event]
+    getFutureEvents: [Event]
+  }
+
+  type Mutation {
+    addEvent(title: String, speaker: String, description: String, date: DateTime, time: [DateTime], place: String, signUp: String, isStammtisch: Boolean): Boolean
+    editEvent(id: Int, title: String, speaker: String, description: String, date: DateTime, time: [DateTime], place: String, signUp: String, isStammtisch: Boolean): Boolean
+    addSignUp(id: Int): Boolean
+    removeSignUp(id: Int): Boolean
+  }
+`;
+
diff --git a/guides/bashguide.html b/guides/bashguide.html
new file mode 100644
index 0000000000000000000000000000000000000000..0bc69ed34b6842cb64378fb5d66122b604a0494f
--- /dev/null
+++ b/guides/bashguide.html
@@ -0,0 +1,681 @@
+<!-- start pandoc -->
+
+<h1 data-number="1" id="bash-quick-guide"><span class="header-section-number">1</span> Bash Quick Guide</h1>
+<p>Bash is an acronym for Bourne Again Shell. It is based on the Bourne shell and is mostly compatible with its features.</p>
+<p>Shells are command interpreters. They are applications that provide users with the ability to give commands to their operating system interactively, or to execute batches of commands quickly. In no way are they required for the execution of programs; they are merely a layer between system function calls and the user.</p>
+<p>Think of a shell as a way for you to speak to your system. Your system doesn’t need it for most of its work, but it is an excellent interface between you and what your system can offer. It allows you to perform basic math, run basic tests and execute applications. More importantly, it allows you to combine these operations and connect applications to each other to perform complex and automated tasks.</p>
+<p>Bash is not your operating system. It is not your window manager. It is not your terminal (but it often runs inside your terminal). It does not control your mouse or keyboard. It does not configure your system, activate your screen-saver, or open your files. It’s important to understand that bash is only an interface for you to execute statements (using bash syntax), either at the interactive bash prompt or via bash scripts. The things that <em>actually happen</em> are usually caused by other programs.</p>
+<p>This guide is based on <a href="http://mywiki.wooledge.org/BashGuide">the bash guide in GreyCat’s wiki</a> and aims to be more concise, while still being accurate. It was produced specifically for the Bash Workshop by <a href="www.thealternative.ch">TheAlternative.ch</a>.</p>
+<p>It is published under the <a href="http://creativecommons.org/licenses/by-nc-sa/4.0/">CC by-nc-sa 4.0 license</a>.</p>
+<h1 data-number="2" id="commands-and-arguments"><span class="header-section-number">2</span> Commands and Arguments</h1>
+<p>Bash reads commands from its input, which can be either a file or your terminal. In general, each line is interpreted as a command followed by its arguments.</p>
+<pre><code>ls
+touch file1 file2 file3
+ls -l
+rm file1 file2 file3</code></pre>
+<p>The first word is always the command that is executed. All subsequent words are given to that command as argument.</p>
+<p>Note that <em>options</em>, such as the <code>-l</code> option in the example above, are not treated specially by bash. They are arguments like any other. It is up to the program (<code>ls</code> in the above case) to treat it as an option.</p>
+<p>Words are delimited by whitespace (spaces or tabs). It does not matter how many spaces there are between two words. For example, try</p>
+<pre><code>echo Hello            World</code></pre>
+<p>The process of splitting a line of text into words is called <em>word splitting</em>. It is vital to be aware of it, especially when you come across expansions later on.</p>
+<h2 data-number="2.1" id="preventing-word-splitting"><span class="header-section-number">2.1</span> Preventing Word Splitting</h2>
+<p>Sometimes, you will want to pass arguments to commands that contain whitespace. To do so, you can use quotes:</p>
+<pre><code>touch &quot;Filename with spaces&quot;</code></pre>
+<p>This command creates a single file named <em>Filename with spaces</em>. The text within double quotes is protected from word splitting and hence treated as a single word.</p>
+<p>Note that you can also use single quotes:</p>
+<pre><code>touch &#39;Another filename with spaces&#39;</code></pre>
+<p>There is, however, an important difference between the two:</p>
+<ul>
+<li>Double quotes prevent <strong>word splitting</strong></li>
+<li>Single quotes prevent <strong>word splitting and expansion</strong></li>
+</ul>
+<p>When you use single quotes, the quoted text will never be changed by bash. With double quotes, expansion will still happen. This doesn’t make a difference in the above example, but as soon as you e.g. use variables, it becomes important.</p>
+<p>In general, it is considered good practice to use single quotes whenever possible, and double quotes only when expansion is desired. In that sense, the last example above can be considered “more correct”.</p>
+<h2 data-number="2.2" id="the-importance-of-spaces"><span class="header-section-number">2.2</span> The Importance of Spaces</h2>
+<p>Bash contains various keywords and built-ins that aren’t immediately recognizable as commands, such as the new test command:</p>
+<pre><code>[[ -f file ]]</code></pre>
+<p>The above code tests whether a file named “file” exists in the current directory. Just like every line of bash code, it consists of a command followed by its arguments. Here, the command is <code>[[</code>, while the arguments are <code>-f</code>, <code>file</code> and <code>]]</code>.</p>
+<p>Many programmers of other languages would write the above command like so:</p>
+<pre><code>[[-f file]]</code></pre>
+<p>This, though, is wrong: Bash will look for a command named <code>[[-f</code>, which doesn’t exist, and issue an error message. This kind of mistake is very common for beginners. It is advisable to always use spaces after any kind of brackets in bash, even though there are cases where they are not necessary.</p>
+<h2 data-number="2.3" id="scripts"><span class="header-section-number">2.3</span> Scripts</h2>
+<p>You have probably interacted with bash through a terminal before. You would see a bash prompt, and you would issue one command after another.</p>
+<p>Bash scripts are basically a sequence of commands stored in a file. They are read and processed in order, one after the other.</p>
+<p>Making a script is easy. Begin by making a new file, and put this on the first line:</p>
+<pre><code>#!/bin/bash</code></pre>
+<p>This line is called an <em>interpreter directive</em>, or more commonly, a <em>hashbang</em> or <em>shebang</em>. Your operating system uses it to determine how this file can be run. In this case, the file is to be run using <code>bash</code>, which is stored in the <code>/bin/</code> directory.</p>
+<p>After the shebang, you can add any command that you could also use in your terminal. For example, you could add</p>
+<pre><code>echo &#39;Hello World&#39;</code></pre>
+<p>and then save the file as “myscript”</p>
+<p>You can now run the file from the terminal by typing</p>
+<pre><code>bash myscript</code></pre>
+<p>Here, you explicitly called bash and made it execute the script. <code>bash</code> is used as the command, while <code>myscript</code> is an argument. However, it’s also possible to use <code>myscript</code> as a command directly.</p>
+<p>To do so, you must first make it executable:</p>
+<pre><code>chmod +x myscript</code></pre>
+<p>Now that you have permission to execute this script directly, you can type</p>
+<pre><code>./myscript</code></pre>
+<p>to run it.</p>
+<p>The <code>./</code> is required to tell bash that the executable is located in the current directory, rather than the system directory. We will come back to this in the chapter on Variables.</p>
+<h1 data-number="3" id="variables-and-parameters"><span class="header-section-number">3</span> Variables and Parameters</h1>
+<p>Variables and parameters can be used to store strings and retrieve them later. <em>Variables</em> are the ones you create yourself, while <em>special parameters</em> are pre-set by bash. <em>Parameters</em> actually refers to both, but is often used synonymously to special parameters.</p>
+<p>To store a string in a variable, we use the <em>assignment syntax</em>:</p>
+<pre><code>varname=vardata</code></pre>
+<p>This sets the variable <code>varname</code> to contain the string <code>vardata</code>.</p>
+<p>Note that you cannot use spaces around the <code>=</code> sign. With the spaces, bash would assume <code>varname</code> to be a command and then pass <code>=</code> and <code>vardata</code> as arguments.</p>
+<p>To access the string that is now stored in the variable <code>varname</code>, we have to use <em>parameter expansion</em>. This is the most common kind of expansion: A variable is replaced with its content.</p>
+<p>If you want to print the variable’s value, you can type</p>
+<pre><code>echo $varname</code></pre>
+<p>The <code>$</code> indicates that you want to use expansion on <code>varname</code>, meaning it is replaced by its content. Note that expansion happens before the command is run. Here’s what happens step-by-step:</p>
+<ul>
+<li>Bash uses variable expansion, changing <code>echo $varname</code> to <code>echo vardata</code></li>
+<li>Then, bash runs <code>echo</code> with <code>vardata</code> as its parameter.</li>
+</ul>
+<p>The most important thing here is that <strong>variable expansion happens before wordsplitting</strong>. That means, if you have defined a variable like this:</p>
+<pre><code>myfile=&#39;bad song.mp3&#39;</code></pre>
+<p>and then run the command</p>
+<pre><code>rm $myfile</code></pre>
+<p>bash will expand this to</p>
+<pre><code>rm bad song.mp3</code></pre>
+<p>Only now, word splitting occurs, and bash will call <code>rm</code> with two arguments: <code>bad</code> and <code>song.mp3</code>. If you now had a file called <code>song.mp3</code> in your current directory, that one would be deleted instead.</p>
+<p>To prevent this from happening, you can use double quotes:</p>
+<pre><code>rm &quot;$myfile&quot;</code></pre>
+<p>This will be expanded to</p>
+<pre><code>rm &quot;bad song.mp3&quot;</code></pre>
+<p>which is what we want. In this case, you have to use double quotes, as single quotes would prevent expansion from happening altogether.</p>
+<p>Not quoting variable and parameter expansions is a very common mistake even among advanced bash programmers. It can cause bugs that are hard to find and can be very dangerous. <strong>Always quote your variable expansions.</strong></p>
+<p>You can also use variable expansions inside the variable assignment itself. Consider this example:</p>
+<pre><code>myvariable=&#39;blah&#39;
+myvariable=&quot;$myvariable blah&quot;
+echo &quot;$myvariable&quot;</code></pre>
+<p>What will the output of this script be?</p>
+<p>First, the variable <code>myvariable</code> will get the value <code>blah</code>. Then, <code>myvariable</code> is assigned to again, which overwrites its former content. The assignment contains a variable expansion, <code>"$myvariable blah"</code>. This is expanded to <code>"blah blah"</code>, and that is going to be the new value of <code>myvariable</code>. So the last command is expanded to <code>echo "blah blah"</code>, and the output of the script is <code>blah blah</code>.</p>
+<h2 data-number="3.1" id="special-parameters"><span class="header-section-number">3.1</span> Special Parameters</h2>
+<p><em>Special parameters</em> are variables that are set by bash itself. Most of those variables can’t be written to and they contain useful information.</p>
+<table>
+<colgroup>
+<col style="width: 12%" />
+<col style="width: 12%" />
+<col style="width: 75%" />
+</colgroup>
+<thead>
+<tr class="header">
+<th>Parameter Name</th>
+<th>Usage</th>
+<th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr class="odd">
+<td><code>0</code></td>
+<td><code>"$0"</code></td>
+<td>Contains the name of the current script</td>
+</tr>
+<tr class="even">
+<td><code>1</code> <code>2</code> <code>3</code> etc.</td>
+<td><code>"$1"</code> etc.</td>
+<td>Contains the arguments that were passed to the current script. The number indicates the position of that argument (first, second…). These parameters are also called positional parameters.</td>
+</tr>
+<tr class="odd">
+<td><code>*</code></td>
+<td><code>"$*"</code></td>
+<td>Contains all the positional parameters. Double quoted, it expands to a single word containing them all.</td>
+</tr>
+<tr class="even">
+<td><code>@</code></td>
+<td><code>"$@"</code></td>
+<td>Contains all the positional parameters. Double quoted, it expands to <strong>several words, where each word is one parameter</strong>. This is special syntax, it behaves differently from “normal” expansion in quotes. It retains the arguments exactly as they were passed to the script.</td>
+</tr>
+<tr class="odd">
+<td><code>#</code></td>
+<td><code>"$#"</code></td>
+<td>Contains the number of parameters that were passed to the script</td>
+</tr>
+<tr class="even">
+<td><code>?</code></td>
+<td><code>"$?"</code></td>
+<td>Contains the exit code of the last executed command</td>
+</tr>
+</tbody>
+</table>
+<h2 data-number="3.2" id="environment-variables"><span class="header-section-number">3.2</span> Environment Variables</h2>
+<p><em>Environment variables</em> are special variables that are already set when you start bash. In fact, these variables aren’t specific to bash - they are available in every program that runs on your system and they can affect your system’s behaviour.</p>
+<p>You can use the command <code>printenv</code> in your terminal to display all the environment variables you have currently set. Most of them contain some system configuration, like the variable <code>LANG</code>, which designates your preferred language. Some variables, like <code>TERM</code>, <code>BROWSER</code> or <code>SHELL</code>, designate your preferred default programs (terminal, web browser and shell, respectively. These may not be set on all systems).</p>
+<p>Some of these variables can be useful in your scripts. For example, the variable <code>RANDOM</code> gives you a different random number every time you read it.</p>
+<p>Another important environment variable is <code>PATH</code>. It contains a bunch of file paths, separated by colons. These paths designate where your system will look for executables when you type a command. For example, if you type <code>grep</code> in your terminal, your system will search for an executable called <code>grep</code> in the directories designated in your <code>PATH</code> variable. As soon as it finds one, it will execute that. If it doesn’t find it, you will get a “command not found” error message.</p>
+<p>You can modify your environment variables, if you want. The guideline here is to only mess with those variables of which you know what they do, otherwise you might break something.</p>
+<p>The place to modify these variables is your <code>~/.bash_profile</code> file. This file contains some bash code that is executed whenever you log in. For example, you could add the following line:</p>
+<pre><code>export BROWSER=&quot;firefox&quot;</code></pre>
+<p>This would set your default browser to firefox. Note that on some systems, there are other settings–for example in your Desktop Environment–which can override these environment variables. You’ll have to test whether this works.</p>
+<p>Note the <code>export</code> keyword. This is a bash builtin that takes a variable definition as its argument and puts it in your <em>environment</em>. If you omit this, your new variable will just be an ordinary variable, rather than an environment variable.</p>
+<h2 data-number="3.3" id="ambiguous-names"><span class="header-section-number">3.3</span> Ambiguous Names</h2>
+<p>Say you have a variable called <code>name</code> that is declared as follows:</p>
+<pre><code>name=&#39;bat&#39;</code></pre>
+<p>Now, you want to use this variable in order to print <em>batman</em>:</p>
+<pre><code>echo &quot;$nameman&quot;</code></pre>
+<p>If you try this, you will notice that it doesn’t work–that is because bash will now look for a variable called <code>nameman</code>, which doesn’t exist. Here’s what you can do instead:</p>
+<pre><code>echo &quot;${name}man&quot;</code></pre>
+<p>The curly braces tell bash where the variable name ends. This allows you to add more characters at the end of a variable’s content.</p>
+<h1 data-number="4" id="globbing"><span class="header-section-number">4</span> Globbing</h1>
+<p><em>Globs</em> are an important bash concept–mostly for their incredible convenience. They are patterns that can be used to match filenames or other strings.</p>
+<p>Globs are composed of normal characters and metacharacters. Metacharacters are characters that have a special meaning. These are the metacharacters that can be used in globs:</p>
+<ul>
+<li><code>*</code>: Matches any string, including the empty string (i.e. nothing)</li>
+<li><code>?</code>: Matches any single character</li>
+<li><code>[...]</code>: Matches any one of the characters enclosed in the brackets</li>
+</ul>
+<p>Bash sees the glob, for example <code>a*</code>. It expands this glob, by looking in the current directory and matching it against all files there. Any filenames that match the glob are gathered up and sorted, and then the list of filenames is used in place of the glob. So if you have three files <code>a</code>, <code>b</code> and <code>albert</code> in the current directory, the glob is expanded to <code>a albert</code>.</p>
+<p>A glob always has to match the entire filename. That means <code>a*</code> will match <code>at</code> but not <code>bat</code>.</p>
+<p>Note that globbing is special in that it happens <em>after word splitting</em>. This means you never need to worry about spaces in filenames when you use globbing, and quoting globs is not necessary. In fact, quotes will prevent globbing from happening.</p>
+<h1 data-number="5" id="expansion"><span class="header-section-number">5</span> Expansion</h1>
+<p>We’ve already seen <em>parameter and variable expansion</em>, but that’s not the only kind of expansion that happens in bash. In this chapter, we’ll look at all kinds of expansion that aren’t covered elsewhere.</p>
+<h2 data-number="5.1" id="expansions-and-quotes"><span class="header-section-number">5.1</span> Expansions and Quotes</h2>
+<p>You already know that it is important to quote parameter and variable expansions, but we also told you that quoting globs–which are, in fact, just another form of expansion–is not necessary. So, which expansions need to be quoted?</p>
+<p>The rule of thumb here is as follows:</p>
+<ul>
+<li>Always quote <strong>paramater expansion</strong>, <strong>command substitution</strong> and <strong>arithmetic expansion</strong></li>
+<li>Never quote <strong>brace expansion</strong>, <strong>tilde expansion</strong> and <strong>globs</strong></li>
+</ul>
+<p>The handy thing here is: All the expansions that require quoting have a <code>$</code> in their syntax. Parameter expansion is simply a <code>$</code> followed by a parameter name. Command substitution starts with a <code>$(</code>, and arithmetic expansion starts with <code>$((</code>.</p>
+<p>So, the rule of thumb breaks down to the following: <strong>If there’s a dollar, you probably need quotes.</strong></p>
+<p>Now, what if you want to use two kinds of expansion in the same line, but one requires quotes and the other doesn’t? Consider the following script:</p>
+<pre><code>prefix=&#39;my picture&#39;
+rm ~/pictures/$prefix*</code></pre>
+<p>Here, we use tilde expansion, parameter expansion and globbing in order to remove all files that start with <code>my picture</code> in the folder <code>/home/username/pictures/</code>. But because quotes prevent tilde expansion and globbing, we cannot quote the entire expression. This means that the parameter expansion, too, goes unquoted–and this is fatal, because our variable contains a space. So what should we do?</p>
+<p>The important thing to realize here is that quoting simply prevents word splitting, but it does not actually designate something as a single string. So we can do the following:</p>
+<pre><code>prefix=&#39;my picture&#39;
+rm ~/pictures/&quot;$prefix&quot;*</code></pre>
+<p>Only the parameter expansion is quoted, so it is protected from word splitting. But that does not automatically separate it from the rest of the string. Note that there are no spaces between <code>"$prefix"</code> and <code>~/pictures/</code>. Since word splitting only happens when there are spaces, the entire thing will not be split. Here’s what happens, in order:</p>
+<p>First, tilde expansion occurs:</p>
+<pre><code>rm /home/username/pictures/&quot;$prefix&quot;/*</code></pre>
+<p>Next, parameter expansion:</p>
+<pre><code>rm /home/username/pictures/&quot;my picture&quot;*</code></pre>
+<p>At this point, word splitting happens. But since the only space in our argument is in quotes, the argument remains intact.</p>
+<p>And last, globbing:</p>
+<pre><code>rm /home/username/pictures/&quot;my picture&quot;001.jpg /home/username/pictures/&quot;my picture&quot;002.jpg</code></pre>
+<p>Now, there’s one last step that happens which we didn’t mention before. It’s called <em>quote removal</em>. All the quotes that were needed to prevent word splitting are now ignored, which means that the arguments that are finally given to <code>rm</code> are:</p>
+<ul>
+<li><code>/home/username/pictures/my picture001.jpg</code></li>
+<li><code>/home/username/pictures/my picture002.jpg</code></li>
+</ul>
+<p>and this is exactly what we wanted.</p>
+<p>So, remember: Quotes don’t need to be at the beginning or end of an argument, and if you use several kinds of expansion together, you can add quotes in the middle as required.</p>
+<h2 data-number="5.2" id="expansion-order"><span class="header-section-number">5.2</span> Expansion Order</h2>
+<p>All the kinds of expansion happen in a certain order. The order is as follows:</p>
+<ul>
+<li>Brace expansion</li>
+<li>Tilde expansion</li>
+<li>Parameter and variable expansion</li>
+<li>Command substitution</li>
+<li>Arithmetic expansion</li>
+<li>Word splitting</li>
+<li>Globbing</li>
+</ul>
+<h2 data-number="5.3" id="brace-expansion"><span class="header-section-number">5.3</span> Brace Expansion</h2>
+<p><em>Brace expansions</em> are often used in conjunction with globs, but they also have other uses. They always expand to all possible permutations of their contents. Here’s an example:</p>
+<pre><code>$ echo th{e,a}n
+then than
+$ echo {1..9}
+1 2 3 4 5 6 7 8 9
+$ echo {0,1}{0..9}
+00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19</code></pre>
+<p>Brace expansions are replaced by a list of words. They are often used in conjunction with globs to match specific files but not others. For example, if you want to delete pictures from your pictures folder with filenames IMG020.jpg through IMG039.jpg, you could use the following pattern:</p>
+<pre><code>rm IMG0{2,3}*.jpg</code></pre>
+<p>Note that we don’t use quotes here. Quotes prevent brace expansion.</p>
+<p>Brace expansion happens before globbing, so in the above example, the braces are expanded to</p>
+<pre><code>rm IMG02*.jpg IMG03*.jpg</code></pre>
+<p>We end up with two glob patterns, the first matches IMG020.jpg through IMG029.jpg, and the second matches IMG030.jpg through IMG039.jpg.</p>
+<h2 data-number="5.4" id="tilde-expansion"><span class="header-section-number">5.4</span> Tilde Expansion</h2>
+<p>You have probably already seen and used the tilde in the terminal. It is a shortcut to your home directory:</p>
+<pre><code>cd ~/files</code></pre>
+<p>This will be expanded to <code>cd /home/username/files</code>. Note that tilde expansion only happens outside of quotes, so the following won’t work:</p>
+<pre><code>cd &quot;~/files&quot;</code></pre>
+<h2 data-number="5.5" id="parameter-and-variable-expansion"><span class="header-section-number">5.5</span> Parameter and Variable Expansion</h2>
+<p><em>Parameter and variable expansion</em> is explained in the chapter on Variables and Parameters.</p>
+<p>An important sidenote here is that Parameter expansion and Variable expansion often refer to the same thing. The official name as per the bash manual is <em>Parameter expansion</em>, but <em>Variable expansion</em> is often used instead as it is less misleading.</p>
+<h2 data-number="5.6" id="command-substitution"><span class="header-section-number">5.6</span> Command Substitution</h2>
+<p><em>Command substitution</em> is a way of using a command’s output inside your script. For example, let’s say you want to find out where your script is executed, and then move a file to that location.</p>
+<pre><code>echo &#39;I am at&#39;
+pwd</code></pre>
+<p>This script will simply print the directory it is called from. But you want to move a file to that directory, which means you need to use it as an argument to the <code>mv</code> command. For that, you need command substitution:</p>
+<pre><code>mv ~/myfile &quot;$( pwd )&quot;</code></pre>
+<p>The <code>$(</code> introduces a command substitution. It works similarly to variable expansion, but instead of putting a variable’s content, it puts a command’s output in that place. In this example, <code>pwd</code> is run, and the output is (for example) <code>/home/username/scripts/</code>. Then, the entire command is expanded to</p>
+<pre><code>mv ~/myfile &quot;/home/username/scripts/&quot;</code></pre>
+<p>Note that with this kind of expansion, quotes are important. The path returned by <code>pwd</code> might have contained a space, in which case we need the argument to be properly quoted.</p>
+<h2 data-number="5.7" id="arithmetic-expansion"><span class="header-section-number">5.7</span> Arithmetic Expansion</h2>
+<p><em>Arithmetic expansion</em> is explained in the chapter on arithmetic evaluation.</p>
+<h2 data-number="5.8" id="globbing-1"><span class="header-section-number">5.8</span> Globbing</h2>
+<p><em>Globbing</em> is so important, it has a chapter of its own.</p>
+<h1 data-number="6" id="tests-and-conditionals"><span class="header-section-number">6</span> Tests and Conditionals</h1>
+<p>Every command you run in your terminal or shell script has a return value. That value is a number, and by convention, a return value of 0 means <em>success</em>, while any other number indicates an error.</p>
+<p>You usually don’t see the return value after running a command. What you do see is the command’s <em>output</em>. If you want to know a command’s return value, you can read it by issuing</p>
+<pre><code>echo &quot;$?&quot;</code></pre>
+<p>immediately after running that command.</p>
+<p>While you often don’t need to know a command’s return value, it can be useful to construct conditionals and thereby achieve advanced logic.</p>
+<h2 data-number="6.1" id="control-operators-and"><span class="header-section-number">6.1</span> Control Operators (&amp;&amp; and ||)</h2>
+<p>Control operators can be used to make a command’s execution depend on another command’s success. This concept is called <em>conditional execution</em>:</p>
+<pre><code>mkdir folder &amp;&amp; cd folder</code></pre>
+<p>In the above example, the <code>&amp;&amp;</code> operator is used to connect two commands <code>mkdir folder</code> and <code>cd folder</code>. Using this connection, bash will first execute <code>mkdir folder</code>, and then execute <code>cd folder</code> <em>only if the first command was successful</em>.</p>
+<pre><code>mkdir folder || echo &#39;Error: could not create folder&#39;</code></pre>
+<p>In this example, the <code>||</code> operator is used to connect the commands. Here, the second command is executed <em>only if the first command failed</em>.</p>
+<p>It is good practice to make your own scripts return an error (i.e. something other than 0) whenever something goes wrong. To do that, you can use this construct:</p>
+<pre><code>mkdir folder || exit 1</code></pre>
+<p>The <code>exit</code> command immediately stops the execution of your script and makes it return the number you specified as an argument. In this example, your script will attempt to create a folder. If that goes wrong, it will immediately stop and return 1.</p>
+<p>Control operators can be written more legibly by spreading them across multiple lines:</p>
+<pre><code>mkdir folder \
+    || exit 1</code></pre>
+<p>The backslash at the end of the first line makes bash ignore that line break and treat both lines as a single command plus arguments.</p>
+<h2 data-number="6.2" id="grouping-commands"><span class="header-section-number">6.2</span> Grouping Commands</h2>
+<p>Now, what if you want to execute multiple commands if the first one fails? Going from the example above, when <code>mkdir folder</code> fails, you might want to print an error message <em>and</em> return 1.</p>
+<p>This can be done by enclosing these two commands in single curly braces:</p>
+<pre><code>mkdir folder || { echo &#39;Could not create folder&#39;; exit 1; }</code></pre>
+<p>The two commands in curly braces are treated as an unit, and if the first command fails, both will be executed.</p>
+<p>Note that you need to include spaces between the curly braces and the commands. If there were no spaces, bash would look for a command named <code>{echo</code> and fail to find it.</p>
+<p>There’s a semicolon separating the two commands. The semicolon has the same function as a line break: it makes bash consider both parts as individual commands-plus-arguments.</p>
+<p>The example above could be rewritten as follows:</p>
+<pre><code>mkdir folder || {
+    echo &#39;Could not create folder&#39;
+    exit 1
+}</code></pre>
+<p>Here, no semicolon is required, because there is a line break between the two statements. Line breaks and semicolons can be used interchangeably.</p>
+<h2 data-number="6.3" id="conditional-blocks-if-and"><span class="header-section-number">6.3</span> Conditional Blocks (if and [[)</h2>
+<p><code>if</code> is a shell keyword. It first executes a command and looks at its return value. If it was 0 (success), it executes one list of commands, and if it was something else (failure), it executes another.</p>
+<p>It looks like this:</p>
+<pre><code>if true
+then 
+    echo &#39;It was true&#39;
+else 
+    echo &#39;It was false&#39;
+fi</code></pre>
+<p><code>true</code> is a bash builtin command that does nothing and returns 0. <code>if</code> will run that command, see that it returned 0, and then execute the commands between the <code>then</code> and the <code>else</code>.</p>
+<p>In many programming languages, operators such as <code>&gt;</code>, <code>&lt;</code> or <code>==</code> exist and can be used to compare values. In bash, operators don’t exist. But since comparing values is so common, there’s a special command that can do it:</p>
+<pre><code>[[ a = b ]]</code></pre>
+<p><code>[[</code> is a command that takes as its arguments a comparison. The last argument has to be a <code>]]</code>. It is made to look like a comparison in double brackets, but it is, in fact, a command like any other. It is also called the <em>new test command</em>. (The <em>old test command</em>, often simply called <em>test</em>, exists as well, so be careful not to confuse them).</p>
+<p>For that reason, the spaces are absolutely needed. You cannot write this:</p>
+<pre><code>[[a=b]]</code></pre>
+<p>This will make bash look for a command called <code>[[a=b]]</code>, which doesn’t exist.</p>
+<p><code>[[</code> does not only support comparing strings. For example, <code>[[ -f file ]]</code> will test whether a file named “file” exists. Here’s a list of the most common tests you can use with <code>[[</code>:</p>
+<ul>
+<li><code>-e FILE:</code> True if file exists.</li>
+<li><code>-f FILE:</code> True if file is a regular file.</li>
+<li><code>-d FILE:</code> True if file is a directory.</li>
+<li>String operators: * <code>-z STRING:</code> True if the string is empty (its length is zero). * <code>-n STRING:</code> True if the string is not empty (its length is not zero). * <code>STRING = STRING</code>: True if the string matches the glob pattern (if you quote the glob pattern, the strings have to match exactly). * <code>STRING != STRING</code>: True if the string does not match the glob pattern (if you quote the glob pattern, the strings just have to be different). * <code>STRING &lt; STRING</code>: True if the first string sorts before the second. * <code>STRING &gt; STRING</code>: True if the first string sorts after the second.</li>
+<li><code>EXPR -a EXPR</code>: True if both expressions are true (logical AND).</li>
+<li><code>EXPR -o EXPR</code>: True if either expression is true (logical OR).</li>
+<li><code>! EXPR</code>: Inverts the result of the expression (logical NOT).</li>
+<li><code>EXPR &amp;&amp; EXPR</code>: Much like the ‘-a’ operator of test, but does not evaluate the second expression if the first already turns out to be false.</li>
+<li><code>EXPR || EXPR</code>: Much like the ‘-o’ operator of test, but does not evaluate the second expression if the first already turns out to be true.</li>
+<li>Numeric operators:
+<ul>
+<li><code>INT -eq INT</code>: True if both integers are equal.</li>
+<li><code>INT -ne INT</code>: True if the integers are not equal.</li>
+<li><code>INT -lt INT</code>: True if the first integer is less than the second.</li>
+<li><code>INT -gt INT</code>: True if the first integer is greater than the second.</li>
+<li><code>INT -le INT</code>: True if the first integer is less than or equal to the second.</li>
+<li><code>INT -ge INT</code>: True if the first integer is greater than or equal to the second.</li>
+</ul></li>
+</ul>
+<p>You might occasionally come across something like this:</p>
+<pre><code>[ a = b ]</code></pre>
+<p>Here, we use single brackets instead of double brackets. This is, in fact, an entirely different command, the <code>[</code> command or <em>old test command</em>. It has the same purpose–comparing things–but the <code>[[</code> command is newer, has more features, and is easier to use. We strongly recommend using <code>[[</code> over <code>[</code>.</p>
+<h2 data-number="6.4" id="conditional-loops-while-until-and-for"><span class="header-section-number">6.4</span> Conditional Loops (while, until and for)</h2>
+<p>Loops can be used to repeat a list of commands multiple times. In bash, there are <code>while</code> loops and <code>for</code> loops.</p>
+<p>While loops look like this:</p>
+<pre><code>while true
+do
+    echo &#39;Infinite loop&#39;
+done</code></pre>
+<p>The <code>while</code> keyword will execute the <code>true</code> command, and if that returns 0, it executes all commands between the <code>do</code> and <code>done</code>. After that, it starts over, until the <code>true</code> command returns 1 (which it never does, which is why this loop will run indefinitely).</p>
+<p>The above example might not be immediately useful, but you could also do something like this:</p>
+<pre><code>while ping -c 1 -W 1 www.google.com
+do
+    echo &#39;Google still works!&#39;
+done</code></pre>
+<p>There’s also a variation of the <code>while</code> loop, called <code>until</code>. It works similarly, except it only runs its command list when the first command <em>fails</em>:</p>
+<pre><code>until ping -c 1 -W 1 www.google.com
+do
+    echo &#39;Google isn&#39;\&#39;&#39;t working!&#39;
+done</code></pre>
+<p><code>for</code> loops can be used to iterate over a list of strings:</p>
+<pre><code>for var in 1 2 3
+do
+    echo &quot;$var&quot;
+done</code></pre>
+<p>After the <code>for</code>, you specify a variable name. After the <code>in</code>, you list all the strings you want to iterate over.</p>
+<p>The loop works by setting the variable you specified to all the values from the list in turn, and then executing the command list for each of them.</p>
+<p>This is especially useful in combination with globs or brace expansions:</p>
+<pre><code>echo &#39;This is a list of all my files starting with f:&#39;
+for var in f*
+do
+    echo &quot;$var&quot;
+done
+
+echo &#39;And now I will count from 1 to 100:&#39;
+for var in {1..100}
+do
+    echo &quot;$var&quot;
+done</code></pre>
+<h2 data-number="6.5" id="choices-case-and-select"><span class="header-section-number">6.5</span> Choices (case and select)</h2>
+<p>Sometimes, you want your script to behave differently depending on the content of a variable. This could be implemented by taking a different branch of an if statement for each state:</p>
+<pre><code>if [[ &quot;$LANG&quot; = &#39;en&#39; ]]
+then
+    echo &#39;Hello!&#39;
+elif [[ &quot;$LANG&quot; = &#39;de&#39; ]]
+then
+    echo &#39;Guten Tag!&#39;
+elif [[ &quot;$LANG&quot; = &#39;it&#39; ]]
+then
+    echo &#39;Ciao!&#39;
+else
+    echo &#39;I do not speak your language.&#39;
+fi</code></pre>
+<p>This is quite cumbersome to write. At the same time, constructs like this are very common. For that reason, bash provides a keyword to simplify it:</p>
+<pre><code>case &quot;$LANG&quot; in
+    en)
+        echo &#39;Hello!&#39;
+        ;;
+    de) 
+        echo &#39;Guten Tag!&#39;
+        ;;
+    it)
+        echo &#39;Ciao!&#39;
+        ;;
+    *)
+        echo &#39;I do not speak your language.&#39;
+        ;;
+esac</code></pre>
+<p>Each choice of the case statement consists of a string or glob pattern, a <code>)</code>, a list of commands that is to be executed if the string matches the pattern, and two semicolons to denote the end of a list of commands.</p>
+<p>The string after the keyword <code>case</code> is matched against each glob pattern in order. The list of commands after the first match is executed. After that, execution continues after the <code>esac</code>.</p>
+<p>Since the string is matched against glob patterns, we can use <code>*</code> in the end to catch anything that didn’t match before.</p>
+<p>Another construct of choice is the <code>select</code> construct. It looks and works similarly to a loop, but it also presents the user with a predefined choice. You are encouraged to try running this example yourself:</p>
+<pre><code>echo &#39;Which one of these does not belong in the group?&#39;
+select choice in Apples Pears Crisps Lemons Kiwis
+do
+    if [[ &quot;$choice&quot; = Crisps ]]
+    then
+        echo &#39;Correct! Crisps are not fruit.&#39;
+        break
+    fi
+    echo &#39;Wrong answer. Try again.&#39;
+done</code></pre>
+<p>The syntax of the <code>select</code> construct is very similar to <code>for</code> loops. The difference is that instead of setting the variable (<code>choice</code> in this example) to each value in turn, the <code>select</code> construct lets the user choose which value is used next. This also means that a <code>select</code> construct can run indefinitely, because the user can keep selecting new choices. To avoid being trapped in it, we have to explicitly use <code>break</code>. <code>break</code> is a builtin command that makes bash jump out of the current <code>do</code> block. Execution will continue after the <code>done</code>. <code>break</code> also works in <code>for</code> and <code>while</code> loops.</p>
+<p>As you can see in the example above, we used an <code>if</code> command inside a <code>select</code> command. All of these conditional constructs (<code>if</code>, <code>for</code>, <code>while</code>, <code>case</code> and <code>select</code>) can be nested indefinitely.</p>
+<h1 data-number="7" id="input-and-output"><span class="header-section-number">7</span> Input and Output</h1>
+<p>Input and output in bash is very flexible and, consequentially, complex. We will only look at the most widely used components.</p>
+<h2 data-number="7.1" id="command-line-arguments"><span class="header-section-number">7.1</span> Command-line Arguments</h2>
+<p>For many bash scripts, the first input we care about are the arguments given to it via the command line. As we saw in the chapter on Parameters, these arguments are contained in some <em>special parameters</em>. These are called <em>positional parameters</em>. The first parameter is referred to with <code>$1</code>, the second with <code>$2</code>, and so on. After number 9, you have to enclose the numbers in curly braces: <code>${10}</code>, <code>${11}</code> and so on.</p>
+<p>In addition to referring to them one at a time, you may also refer to the entire set of positional parameters with the <code>"$@"</code> substitution. The double quotes here are <strong>extremely important</strong>. If you don’t use the double quotes, each one of the positional parameters will undergo word splitting and globbing. You don’t want that. By using the quotes, you tell Bash that you want to preserve each parameter as a separate word.</p>
+<p>There are even more ways to deal with parameters. For example, it is very common for commands to accept <em>options</em>, which are single letters starting with a <code>-</code>. For example, <code>ls -l</code> calls the <code>ls</code> program with the <code>-l</code> option, which makes it output more information. Usually, multiple options can be combined, as in <code>ls -la</code>, which is equivalent to <code>ls -l -a</code>.</p>
+<p>You might want to create your own scripts that accept some options. Bash has the so called <code>getopts</code> builtin command to parse passed options.</p>
+<pre><code>while getopts &#39;hlf:&#39; opt
+do 
+    case &quot;$opt&quot; in
+    h|\?)
+        echo &#39;available options: -h -l -f [filename]&#39;
+        ;;
+    f)
+        file=&quot;$OPTARG&quot;
+        ;;
+    l)
+        list=true
+        ;;
+    esac
+done
+
+shift &quot;$(( OPTIND - 1 ))&quot;</code></pre>
+<p>As you can see, we use <code>getopts</code> within a while loop. <code>getopts</code> will return 0 as long as there are more options remaining and something else if there are no more options. That makes it perfectly suitable for a loop.</p>
+<p><code>getopts</code> takes two arguments, the <em>optstring</em> and the <em>variable name</em>. The optstring contains all the letters that are valid options. In our example, these are <code>h</code>, <code>l</code> and <code>f</code>.</p>
+<p>The <code>f</code> is followed by a colon. This indicates that the f option requires an argument. The script could for example be called like so:</p>
+<pre><code>myscript -f file.txt</code></pre>
+<p><code>getopts</code> will set the variable that you specified as its second argument to the letter of the option it found first. If the option required an argument, the variable <code>OPTARG</code> is set to whatever the argument was. In the example above, a case statement is used to react to the different options.</p>
+<p>There’s also a special option <code>?</code>. Whenever <code>getopts</code> finds an option that is not present in the optstring, it sets the shell variable (<code>opt</code> in the example) to <code>?</code>. In the case statement above, that triggers the help message.</p>
+<p>After all options are parsed, the remaining arguments are “moved” such that they are now in <code>$1</code>, <code>$2</code>… even though previously, these positional parameters were occupied by the options.</p>
+<p>Also note the line <code>shift "$(( OPTIND - 1 ))"</code> at the end. The <code>shift</code> builtin can be used to discard command-line arguments. Its argument is a number and designates how many arguments we want to discard.</p>
+<p>This is needed because we don’t know how many options the user will pass to our script. If there are more positional parameters after all the options, we have no way of knowing at which number they start. Fortunately, <code>getopts</code> also sets the shell variable <code>OPTIND</code>, in which it stores the index of the option it’s going to parse next.</p>
+<p>So after parsing all the option, we just discard the first <code>OPTIND - 1</code> options, and the remaining arguments now start from <code>$1</code> onwards.</p>
+<h2 data-number="7.2" id="file-descriptors"><span class="header-section-number">7.2</span> File Descriptors</h2>
+<p><em>File descriptors</em> are the way programs refer to files, or other things that work like files (such as pipes, devices, or terminals). You can think of them as pointers that point to data locations. Through these pointers, programs can write to or read from these locations.</p>
+<p>By default, every program has three file descriptors:</p>
+<ul>
+<li>Standard Input (stdin): File Descriptor 0</li>
+<li>Standard Output (stdout): File Descriptor 1</li>
+<li>Standard Error (stderr): File Descriptor 2</li>
+</ul>
+<p>When you run a script in the terminal, then stdin contains everything you type in that terminal. stdout and stderr both point to the terminal, and everything that is written to these two is displayed as text in the terminal. stdout is where programs send their normal information, and stderr is where they send their error messages.</p>
+<p>Let’s make these definitions a little more concrete. Consider this example:</p>
+<pre><code>echo &#39;What is your name?&#39;
+read name
+echo &quot;Good day, $name. Would you like some tea?&quot;</code></pre>
+<p>You already know <code>echo</code>. It simply prints its argument to <em>stdout</em>. Since stdout is connected to your terminal, you will see that message there.</p>
+<p><code>read</code> is a command that reads one line of text from <em>stdin</em> and stores it in a variable, which we specified to be <code>name</code>. Because stdin is connected to what you type in your terminal, it will let you type a line of text, and as soon as you press enter, that line will be stored in the variable.</p>
+<p>So what about stderr? Consider this example:</p>
+<pre><code>ehco &#39;Hello!&#39;</code></pre>
+<p>The command <code>ehco</code> does not exist. If you run this, bash will print an error message to <em>stderr</em>. Because stderr is connected to your terminal, you will see that message there.</p>
+<h2 data-number="7.3" id="redirection"><span class="header-section-number">7.3</span> Redirection</h2>
+<p><em>Redirection</em> is the most basic form of input/output manipulation in bash. It is used to change the source or destination of <em>File descriptors</em>, i.e. connect them to something other than your terminal. For example, you can send a command’s output to a file instead.</p>
+<pre><code>echo &#39;It was a dark and stormy night. Too dark to write.&#39; &gt; story</code></pre>
+<p>The <code>&gt;</code> operator begins an <em>output redirection</em>. It redirects the <em>stdout</em> file descriptor of the command to the left, and connects it to a file called “story”. That means if you run this, you will not see the output of <code>echo</code>—after all, stdout no longer points to your terminal.</p>
+<p>Note that <code>&gt;</code> will just open the file you specify without checking whether it already exists first. If the file already exists, its contents will be overwritten and you will lose whatever was stored in there before. <strong>Be careful.</strong></p>
+<p>If you don’t want to overwrite the existing content of a file, but rather append your output to the end of that file, you can use <code>&gt;&gt;</code> instead of <code>&gt;</code>.</p>
+<p>Now, let’s look at <em>input redirection</em>. For that, we first introduce a command named <code>cat</code>. <code>cat</code> is often used to display the contents of a file, like so:</p>
+<pre><code>cat myfile</code></pre>
+<p>If <code>cat</code> is called without an argument, however, it will simply read from <em>stdin</em> and print that directly to <em>stdout</em>.</p>
+<p>Try the following: Run <code>cat</code>, without arguments, in your terminal. Then type some characters and hit enter. Can you figure out what is happening?</p>
+<p><em>Input redirection</em> uses the <code>&lt;</code> operator. It works as follows:</p>
+<pre><code>cat &lt; story</code></pre>
+<p>The <code>&lt;</code> operator will take a command’s <em>stdin</em> file descriptor and point it to a file, “story” in this example. This means <code>cat</code> now ignores your terminal and reads from “story” instead. Note that this has the same effect as typing <code>cat story</code>.</p>
+<p>If you want to redirect <em>stderr</em> instead of <em>stdout</em>, you can do as follows:</p>
+<pre><code>ehco &#39;Hello!&#39; 2&gt; errors</code></pre>
+<p>If you run this, you won’t see any error message, even though the command <code>ehco</code> doesn’t exist. That’s because <em>stderr</em> is no longer connected to your terminal, but to a file called “errors” instead.</p>
+<p>Now that you know about redirection, there is one subtlety that you have to be aware of: You can’t have two file descriptors point to the same file.</p>
+<p>If you wanted to log a command’s complete output–stdout <em>and</em> stderr–you might be tempted to do something like this:</p>
+<pre><code>mycommand &gt; logfile 2&gt; logfile</code></pre>
+<p>However, this is a <strong>bad</strong> idea. The two file descriptors will now both point to the same file <em>independently</em>, which causes them to constantly overwrite each other’s text.</p>
+<p>If you still want to point both stdout and stderr to the same file, you can do it like this:</p>
+<pre><code>mycommand &gt; logfile 2&gt;&amp;1</code></pre>
+<p>Here, we use the <code>&gt;&amp;</code> syntax to duplicate file descriptor 1. In this scenario, we no longer have two file descriptors pointing to one file. Instead, we have only one file descriptor that acts as both stdout and stderr at the same time.</p>
+<p>To help remember the syntax, you can think of <code>&amp;1</code> as “where 1 is”, and of the <code>2&gt;</code> as “point 2 to”. The whole thing, <code>2&gt;&amp;1</code>, then becomes “point 2 to wherever 1 is”. This also makes it clear that <code>&gt; logfile</code> has to come <em>before</em> <code>2&gt;&amp;1</code>: First you point 1 to “logfile”, and only then you can point 2 to where 1 is.</p>
+<p>There’s also a quick way to completely get rid of a command’s output using redirections. Consider this:</p>
+<pre><code>mycommand &gt; /dev/null 2&gt;&amp;1</code></pre>
+<p><code>/dev/null</code> is a special file in your file system that you can write to, but the things you write to it are not stored. So, <code>mycommand</code>’s output is written somewhere where it’s not stored or processed in any way. It is discarded completely.</p>
+<p>You could also leave out the <code>2&gt;&amp;1</code>. Then, you’d still see error messages, but discard the normal output.</p>
+<h2 data-number="7.4" id="pipes"><span class="header-section-number">7.4</span> Pipes</h2>
+<p>Now that you know how to manipulate <em>file descriptors</em> to direct output to files, it’s time to learn another type of I/O redirection.</p>
+<p>The <code>|</code> operator can be used to connect one command’s <em>stdout</em> to another command’s <em>stdin</em>. Have a look at this:</p>
+<pre><code>echo &#39;This is a beautiful day!&#39; | sed &#39;s/beauti/wonder&#39;</code></pre>
+<p>The <code>sed</code> command (“sed” is short for “stream editor”) is a utility that can be used to manipulate text “on the fly”. It reads text from stdin, edits it according to some commands, and then prints the result to stdout. It is very powerful. Here, we use it to replace “beauti” with “wonder”.</p>
+<p>First, the <code>echo</code> command writes some text to it’s stdout. The <code>|</code> operator connected <code>echo</code>’s stout to <code>sed</code>’s stdin, so everything <code>echo</code> sends there is immediately picked up by <code>sed</code>. <code>sed</code> will then edit the text and print the result to its own stdout. <code>sed</code>’s stdout is still connected to your terminal, so this is what you see.</p>
+<h1 data-number="8" id="compound-commands"><span class="header-section-number">8</span> Compound Commands</h1>
+<p><em>Compound commands</em> is a catch-all phrase covering several different concepts. We’ve already seen <code>if</code>, <code>for</code>, <code>while</code>, <code>case</code>, <code>select</code> and the <code>[[</code> keyword, which all fall into this category. Now we’ll look at a few more.</p>
+<h2 data-number="8.1" id="subshells"><span class="header-section-number">8.1</span> Subshells</h2>
+<p><em>Subshells</em> can be used to encapsulate a command’s effect. If a command has undesired side effects, you can execute it in a subshell. Once the subshell command ends, all side effects will be gone.</p>
+<p>To execute a command (or several commands) in a subshell, enclose them in parenthesis:</p>
+<pre><code>( 
+    cd /tmp 
+    pwd
+)
+pwd</code></pre>
+<p>The <code>cd</code> and the first <code>pwd</code> commands are executed in a subshell. All side effects in that subshell won’t affect the second <code>pwd</code> command. Changing the current directory is such a side effect–even though we use <code>cd</code> to go to the <code>/tmp</code> folder, we jump back to our original folder as soon as the subshell ends.</p>
+<h2 data-number="8.2" id="command-grouping"><span class="header-section-number">8.2</span> Command Grouping</h2>
+<p>You can group several commands together by enclosing them in curly braces. This makes bash consider them as a unit with regard to pipes, redirections and control flow:</p>
+<pre><code>{
+    echo &#39;Logfile of my backup&#39;
+    rsync -av . /backup
+    echo &quot;Backup finished with exit code $#&quot;
+} &gt; backup.log 2&gt;&amp;1</code></pre>
+<p>This redirects stdout and stderr of <em>all three commands</em> to a file called backup.log. Note that while this looks similar to subshells, it is not the same. Side effects that happen within the curly braces will still be present outside of them.</p>
+<h2 data-number="8.3" id="arithmetic-evaluation"><span class="header-section-number">8.3</span> Arithmetic Evaluation</h2>
+<p>So far, we’ve only been manipulating strings in bash. Sometimes, though, it is also necessary to manipulate numbers. This is done through arithmetic evaluation.</p>
+<p>Say you want to add the numbers 5 and 4. You might do something like this:</p>
+<pre><code>a=5+4</code></pre>
+<p>However, this will result in the variable <code>a</code> containing the string <code>5+4</code>, rather than the number <code>9</code>. Instead, you should do this:</p>
+<pre><code>(( a=5+4 ))</code></pre>
+<p>The double parenthesis indicate that something arithmetic is happening. In fact, <code>((</code> is a bash keyword, much like <code>[[</code>.</p>
+<p><code>((</code> can also be used to do arithmetic comparison:</p>
+<pre><code>if (( 5 &gt; 9 ))
+then
+    echo &#39;5 is greater than 9&#39;
+else 
+    echo &#39;5 is not greater than 9&#39;
+fi</code></pre>
+<p>It is important not to confuse <code>((</code> and <code>[[</code>. <code>[[</code> is for comparing strings (among other things), while <code>((</code> is only for comparing numbers.</p>
+<p>There’s also <em>arithmetic substitution</em>, which works similarly to <em>command substitution</em>:</p>
+<pre><code>echo &quot;There are $(( 60 * 60 * 24 )) seconds in a day.&quot;</code></pre>
+<h1 data-number="9" id="functions"><span class="header-section-number">9</span> Functions</h1>
+<p>Inside a bash script, functions are very handy. They are lists of commands–much like a normal script–except they don’t reside in their own file. They do however take arguments, just like scripts.</p>
+<p>Functions can be defined like this:</p>
+<pre><code>sum() {
+    echo &quot;$1 + $2 = $(( $1 + $2 ))&quot;
+}</code></pre>
+<p>If you put this in a script file and run it, absolutely nothing will happen. The function <code>sum</code> has been defined, but it is never used.</p>
+<p>You can use your function like any other command, but you have to define it <em>before</em> you use it:</p>
+<pre><code>sum() {
+    echo &quot;$1 + $2 = $(( $1 + $2 ))&quot;
+}
+sum 1 2
+sum 3 9
+sum 6283 3141</code></pre>
+<p>As you can see, you can use the function <code>sum</code> multiple times, but you only need to define it once. This is useful in larger scripts, where a certain task has to be performed multiple times. Whenever you catch yourself writing the same or very similar code twice in the same script, you should consider using a function.</p>
+<h1 data-number="10" id="useful-commands"><span class="header-section-number">10</span> Useful Commands</h1>
+<p>This chapter provides an overview of useful commands that you can use in your scripts. It is nowhere near complete, and serves only to provide a brief overview. If you want to know more about a specific command, you should read its manpage.</p>
+<p><strong>grep</strong></p>
+<p><code>grep</code> can be used to search for a string within a file, or within the output of a command.</p>
+<pre><code># searches logfile.txt for lines containing the word error
+grep &#39;error&#39; logfile.txt  
+
+# searches the directory &#39;folder&#39; for files 
+# containing the word &#39;analysis&#39;
+grep &#39;analysis&#39; folder/   
+
+# searches the output of &#39;xrandr&#39; for lines that say &#39;connected&#39;. 
+# only matches whole words, so &#39;disconnected&#39; will not match.
+xrandr | grep -w &#39;connected&#39; </code></pre>
+<p><code>grep</code> returns 0 if it finds something, and returns an error if it doesn’t. This makes it useful for conditionals.</p>
+<p><strong>sed</strong></p>
+<p><code>sed</code> can be used to edit text “on the fly”. It uses its own scripting language to describe modifications to be made to the text, which makes it extremely powerful. Here, we provide examples for the most common usages of sed:</p>
+<pre><code># replaces the first occurrence of &#39;find&#39; in every line by &#39;replace&#39;
+sed &#39;s/find/replace&#39; inputfile 
+
+# replaces every occurrence of &#39;find&#39; in every line by &#39;replace&#39;
+sed &#39;s/find/replace/g&#39; inputfile 
+
+# deletes the first occurrence of &#39;find&#39; in every line
+sed &#39;s/find//&#39; inputfile 
+
+# deletes every occurrence of &#39;find&#39; in every line
+sed &#39;s/find//g&#39; inputfile 
+
+# displays only the 12th line
+sed &#39;12q;d&#39; inputfile </code></pre>
+<p><code>sed</code> is often used in combination with pipes to format the output or get rid of unwanted characters.</p>
+<p><strong>curl and wget</strong></p>
+<p><code>curl</code> and <code>wget</code> are two commands that can be used to access websites or other content from the web. The difference is that <code>wget</code> will simply download the content to a file, while <code>curl</code> will output it to the console.</p>
+<pre><code>curl http://www.thealternative.ch
+wget http://files.project21.ch/LinuxDays-Public/16FS-install-guide.pdf</code></pre>
+<p><strong>xrandr</strong></p>
+<p><code>xrandr</code> can be used to manipulate your video outputs, i.e. enabling and disabling monitors or setting their screen resolution and orientation.</p>
+<pre><code># list all available outputs and their status info
+xrandr  
+
+# enables output HDMI-1
+xrandr --output HDMI-1 --auto 
+
+# puts output HDMI-1 to the left of output LVDS-1
+xrandr --output HDMI-1 --left-of LVDS-1 
+
+# disables output LVDS-1
+xrandr --output LVDS-1 --off </code></pre>
+<p><strong>ImageMagick (convert)</strong></p>
+<p>The <code>convert</code> command makes it possible to do image processing from the commandline.</p>
+<pre><code># scale fullHDWallpaper.jpg to specified resolution
+convert fullHDWallpaper.jpg -scale 3200x1800 evenBiggerWallpaper.jpg 
+
+# &quot;automagically&quot; adjusts the gamma level of somePicture.jpg
+convert somePicture.jpg -auto-gamma someOtherPicture.jpg 
+
+# transform image to black and white
+convert colorfulPicture.jpg -monochrome blackWhitePicture.jpg </code></pre>
+<p>It is extremely powerful and has lots of options. A good resource is the <a href="http://www.imagemagick.org">official website</a>. It also provides examples for most options.</p>
+<p><strong>notify-send</strong></p>
+<p><code>notify-send</code> can be used to display a desktop notification with some custom text:</p>
+<pre><code>notify-send &#39;Battery warning&#39; &#39;Your battery level is below 10%&#39;</code></pre>
+<p>The first argument is the notification’s title, the second is its description.</p>
+<p><code>notify-send</code> requires a <em>notification daemon</em> to be running, else it won’t work. Most desktop environments come with a notification daemon set up and running. If you can’t see your notifications, it might be that you don’t have such a daemon.</p>
+<p><strong>find</strong></p>
+<p><code>find</code> can be used to find files in a directory structure.</p>
+<pre><code># finds all files in the current directory and all subdirectories that end
+# in .png
+find -name &#39;*.png&#39; 
+
+# finds all files ending in .tmp and removes them. {} is replaced by the
+# file&#39;s name when executing the command.
+# Note that we don&#39;t use globbing here, but instead pass the * to find.
+# find will then interpret the * as a wildcard.
+find -name &#39;*.tmp&#39; -exec rm &#39;{}&#39;
+
+# finds all files in the directory &#39;files&#39; and prints their size and path
+find &#39;files/&#39; -printf &#39;%s %p\n&#39; </code></pre>
+<p><code>find</code> has many options that allow you to perform arbitrary actions on the files it found or pretty-print the output.</p>
+<p><strong>sort</strong></p>
+<p><code>sort</code> sorts lines of text files, or lines it reads from <em>stdin</em>.</p>
+<pre><code>sort listOfNames.txt # sorts all lines in listOfNames.txt alphabetically</code></pre>
+<p><strong>head and tail</strong></p>
+<p><code>head</code> and <code>tail</code> can be used to show the beginning or the end of a long stream of text, respectively.</p>
+<pre><code># display the last few lines of the dmesg log
+dmesg | tail 
+
+# display only the first few lines of a very long text file
+head verylongtext.txt </code></pre>
+<p><strong>jshon</strong></p>
+<p><code>jshon</code> is a very simple command-line json parser. It can read data in json format and return specific values.</p>
+<p>Its most important options are <code>-e</code> and <code>-a</code>. <code>-e</code> extracts the value of a given key from a json array or object:</p>
+<pre><code># Find the object with key &quot;title&quot; from a json object stored in the file &quot;json&quot;
+jshon -e &#39;title&#39; &lt; &#39;json&#39;</code></pre>
+<p>The <code>-a</code> option maps all remaining options across the currently selected element. It has to be combined with other options, for example the <code>-e</code> option.</p>
+<pre><code># Find the names of all elements stored in the json object in file &quot;json&quot;
+jshon -a -e &#39;name&#39; &lt; &#39;json&#39;</code></pre>
+<p><strong>shuf</strong></p>
+<p><code>shuf</code> randomly permutates the lines of its input, effectively <em>shuffling</em> them.</p>
+<pre><code># Shuffle the lines of file &quot;playlist&quot;
+shuf &#39;playlist&#39;
+
+# Get a random line from file &quot;quotes&quot;
+shuf -n 1 &#39;quotes&#39;</code></pre>
+<p><strong>tee</strong></p>
+<p><code>tee</code> takes input from <em>stdin</em> and writes it to a file:</p>
+<pre><code>sudo zypper up | tee &#39;updatelog&#39;</code></pre>
+<p>Note that this is equivalent to</p>
+<pre><code>sudo zypper up &gt; &#39;updatelog&#39;</code></pre>
+<p><code>tee</code> is useful when you want to write to a file that requires root access. Then you can do the following:</p>
+<pre><code>echo &#39;some configuration&#39; | sudo tee &#39;/etc/systemconfig&#39;</code></pre>
+<p>A normal redirection wouldn’t work in this case, as that would open the file as a normal user instead of root. <strong>Please be careful when modifying system files.</strong></p>
+<p><strong>sleep</strong></p>
+<p><code>sleep</code> pauses the execution of your script for a number of seconds. It basically takes a number as an argument, then does nothing for that number of seconds, and then returns. It can be useful if you want to make your script do something in a loop, but want to throttle the speed a little.</p>
+<pre><code># prints &quot;Get back to work&quot; once per second. 
+# Note that &#39;true&#39; is a command that always returns 0.
+while true
+do
+    echo &#39;Get back to work!&#39;
+    sleep 1
+done</code></pre>
+<p><strong>mplayer or mpv</strong></p>
+<p><code>mplayer</code> and <code>mpv</code> are media players that can be used from the console. <code>mpv</code> is based on <code>mplayer</code> and a lot more modern, but they can do essentially the same.</p>
+<pre><code># play file &quot;music.mp3&quot;
+mplayer &#39;music.mp3&#39;
+mpv &#39;music.mp3&#39;
+
+# play file &quot;alarm.mp3&quot; in an infinite loop
+mplayer -loop 0 &#39;alarm.mp3&#39;
+mplayer --loop=inf &#39;alarm.mp3&#39;
+
+# play a youtube video
+# this only works with mpv and requires youtube-dl to be installed
+mpv &#39;https://www.youtube.com/watch?v=lAIGb1lfpBw&#39;</code></pre>
+<p><strong>xdotool</strong></p>
+<p><code>xdotool</code> can simulate keypresses. With this command, you can write macros that perform actions for you. It allows you to write scripts that interact with GUI programs.</p>
+<pre><code># press ctrl+s (in order to save a document)
+xdotool key &#39;Control+s&#39;
+
+# type &quot;hello&quot;
+xdotool type &#39;hello&#39;</code></pre>
+
+<!-- end pandoc -->
diff --git a/guides/installguide.html b/guides/installguide.html
new file mode 100644
index 0000000000000000000000000000000000000000..64a1ce6d8d5a16a9377c96133c192f99b10efb8b
--- /dev/null
+++ b/guides/installguide.html
@@ -0,0 +1,623 @@
+<h1 data-number="1" id="introduction"><span class="header-section-number">1</span> Introduction</h1>
+<p>This is a concise guide to install Linux. It can be used as a standalone guide, although we recommend that you attend our Install Events during the LinuxDays so that experienced users can help you with your installation.</p>
+<p>The guide help you to create an install stick, prepare your existing operating system and finally install Linux. We also included some links to distribution-specific installation resources, for the most up-to-date instructions.</p>
+<p>At the end of the guide, we include some software recommendations.</p>
+<h2 data-number="1.1" id="overview"><span class="header-section-number">1.1</span> Overview</h2>
+<p>Installing Linux is done in three steps:</p>
+<ul>
+<li>Flash an USB Stick with the Linux installer</li>
+<li>Prepare your existing operating system</li>
+<li>Install Linux</li>
+</ul>
+<p>We will help you at each step. If you encounter problems or have suggestions how to improve this guide feel free to reach out!</p>
+<h2 data-number="1.2" id="linuxdays-install-event"><span class="header-section-number">1.2</span> LinuxDays Install Event</h2>
+<p><em>You can skip this part if you do not physically attend the install events</em></p>
+<p>Welcome to the LinuxDays Install Event! We are happy you could make it.</p>
+<h3 data-number="1.2.1" id="staff"><span class="header-section-number">1.2.1</span> Staff</h3>
+<p>Our staff is easily recognizable by their blue T-Shirts. Feel free to ask them about Linux, TheAlternative, Free Software or anything else.</p>
+<p>We will help you if you are unable to proceed with the install guide or have any other questions. If we do not have an immediate answer, we know who to ask or where to look it up.</p>
+<p>Also, feel free to stay and just chat :)</p>
+<h3 data-number="1.2.2" id="demolaptops"><span class="header-section-number">1.2.2</span> Demolaptops</h3>
+<p>We have prepared some laptops with different distribution and desktop environments. You can try them out, and decide what you like best.</p>
+<p>If you do not really care or can not decide, we will try to recommend something based on what you want to use Linux for.</p>
+<h3 data-number="1.2.3" id="usb-install-sticks-install-guide-copies"><span class="header-section-number">1.2.3</span> USB Install Sticks &amp; Install Guide Copies</h3>
+<p>We have prepared USB Install Sticks so you can get started right away with installing Linux.</p>
+<p>Further, we have printed copies of the Install Guide if you rather have a printed version than look at it on you phone.</p>
+<h3 data-number="1.2.4" id="anything-else"><span class="header-section-number">1.2.4</span> Anything else?</h3>
+<p>We have adapters (like USB to LAN), hubs, mouse and keyboards, …</p>
+<h1 data-number="2" id="flash-stick"><span class="header-section-number">2</span> Flash Stick</h1>
+<p>You will prepare a stick from which you can install Linux from.</p>
+<p><em>If you are at one of our Install Events, we already prepared USB sticks. Choose a distribution (read on) then come to the welcome desk to get your stick.</em></p>
+<h2 data-number="2.1" id="choosing-a-distribution"><span class="header-section-number">2.1</span> Choosing a distribution</h2>
+<p>In the words of Richard Stallman:</p>
+<blockquote>
+<p>What you’re referring to as Linux, is in fact, GNU/Linux, or as I’ve recently taken to calling it, GNU plus Linux. Linux is not an operating system unto itself, but rather another free component of a fully functioning GNU system &gt; made useful by the GNU corelibs, shell utilities and vital system components comprising a full OS as defined by POSIX."</p>
+</blockquote>
+<p>In simpler terms: Linux by itself is not a full operating system (rather than a vital technical part of it). You need to choose a distribution (a “wrapper” around Linux) which will define to a large extend how you as a user will interact with the operating system (like installing new programs, how the desktop looks by default, …).</p>
+<p>As choosing a distribution is heavily opiniated, we describe it here very short. Feel free to reach out to us for a personal recommendation based on your specific needs.</p>
+<p>If you “just want Linux”, we recommend you go with <a href="https://ubuntu.com/">Ubuntu</a>. As a more open but also very stable alternative we recommend <a href="https://getfedora.org/">Fedora</a>. Truly Free (as in Freedom!) is <a href="https://www.freebsd.org/">FreeBSD</a>.</p>
+<p>For each of these distributions we give you starting points for a successful installation. If you want to install other distributions feel free to do so; and we will do our best to help you. If you are an enthusiast and want to try to install something more advanced (like <a href="https://www.archlinux.org/">Arch Linux</a>) come join us :).</p>
+<h2 data-number="2.2" id="download-iso"><span class="header-section-number">2.2</span> Download ISO</h2>
+<p>You need to download an image containing the operating system installer. Visit the webpage of your favourite distribution and download it.</p>
+<p>If you have to choose from multiple versions, here some guidance of commonly used terms:</p>
+<ul>
+<li><code>amd64</code>, <code>i386</code>, … refers to the architecture of your device. If you have a laptop / PC, it is very likely that you need <code>amd64</code> (else you’d probably know it).</li>
+<li><code>LTS</code> stands for long term support; meaning this specific version of the distribution will receive security updates for much longer than other versions.</li>
+</ul>
+<h2 data-number="2.3" id="create-install-usb-stick"><span class="header-section-number">2.3</span> Create install USB Stick</h2>
+<p>Get a USB stick of at least 8 Gb (make sure you do not need the data on it anymore!). Flash (=“Put”) the .iso file you have just downloaded on the USB stick.</p>
+<p>On windows, you can use <a href="https://rufus.ie/">rufus</a>. On macOS, you can use <a href="https://www.balena.io/etcher/">etcher</a>.</p>
+<h1 data-number="3" id="prepare-windows-mac"><span class="header-section-number">3</span> Prepare Windows / Mac</h1>
+<p>If you want to keep your existing operating system (Windows or macOS) you need to prepare it. This will allow you to “double-boot”, hence choose at startup which operating system to run.</p>
+<p>If you do not want to keep your existing operating system, you can skip this section.</p>
+<h2 data-number="3.1" id="about-partitioning"><span class="header-section-number">3.1</span> About Partitioning</h2>
+<p>Disk partitioning is the separation of different regions on a hard drive or an SSD. This separation is used to install two different operating systems on a computer or simply to have different regions for different purposes (like a partition for your data and one for the programs).</p>
+<p>We recommend to have at least 40GB of space partitioned for Linux. If you know you need programs for your studies (e.g. Matlab, which is around 30GB), please have enough free disk space to install the desired programs and probably some extra, just in case.</p>
+<p>Be aware that repartitioning later is practically impossible, so try to be on the safe side. If you do not have space constraints, with 100Gb all you wildest wishes should be fulfillable.</p>
+<h2 data-number="3.2" id="windows-10"><span class="header-section-number">3.2</span> Windows 10</h2>
+<p>If you have Windows (and want to keep it) follow on.</p>
+<h3 data-number="3.2.1" id="making-space-for-linux"><span class="header-section-number">3.2.1</span> Making Space for Linux</h3>
+<p>Shrink Windows partition:</p>
+<ul>
+<li>Open <code>create and format hard disk partitions</code> or <code>diskmgmt.msc</code>.</li>
+<li>Look for the large Windows partition at the bottom.</li>
+<li>Right-click on it and select <code>Shrink Volume...</code></li>
+<li>Shrink it so you have enough space available.</li>
+</ul>
+<p>If you are unable to shrink the partition, use a tool like <code>EaseUS Partition Master</code> or try it in the Linux installer. Ask a helper for assistance.</p>
+<p>If you do not have enough space, you can free up disk space with these tips:</p>
+<ul>
+<li>Open <code>Disk Cleanup</code> and click on <code>Clean up system files</code>. Select all that apply.</li>
+<li>Open <code>Add or Remove Programs</code> and remove unneeded programs</li>
+<li>Download <code>WinDirStat</code> from https://windirstat.net/ and find where the large files are hiding</li>
+</ul>
+<h3 data-number="3.2.2" id="disable-bitlocker"><span class="header-section-number">3.2.2</span> Disable Bitlocker</h3>
+<p>Bitlocker encrypts your disk, but unfortunately it is not compatible with Linux boot loaders.</p>
+<p>Disable Bitlocker:</p>
+<ul>
+<li>Open <code>cmd</code> as administrator: Press Windows Key, type <code>cmd</code>, then right click on <code>Command Prompt</code> and select <code>Run as administrator</code>)</li>
+<li>Type <code>manage-bde -status</code> and look for <code>Conversion Status: Fully Decrypted</code></li>
+<li>For any drive which is not <code>Fully Decrypted</code>, type <code>manage-bde -unlock C:</code> (replace <code>C:</code> with the drive you need to decrypt), and press Enter.</li>
+<li>Wait for decryption to end (execute <code>manage-bde -status</code> for status updates)</li>
+</ul>
+<p>You can also try to disable Bitlocker over the UI (look for <code>Manage Bitlocker</code>) but it has been confusing to do so in the last few years.</p>
+<h3 data-number="3.2.3" id="fast-boot"><span class="header-section-number">3.2.3</span> Fast Boot</h3>
+<p><code>Fast boot</code> allows Windows to boot faster, but when it is active, the windows file system will be inaccessible to other OSes (like Linux).</p>
+<p>You can avoid the <code>Fast boot</code> mode by explicitly choosing to <code>Restart</code> (rather than <code>Shut down</code>) in windows.</p>
+<p>Alternatively, you can simply disable fast boot:</p>
+<ul>
+<li>Find the battery icon in the task bar</li>
+<li>Right-click and select <code>Power Options</code></li>
+<li>Select <code>Choose what the power buttons do</code></li>
+<li>Select <code>Change settings that are currently unavailable</code></li>
+<li>Remove the check mark at <code>Turn on fast startup</code></li>
+</ul>
+<h3 data-number="3.2.4" id="booting-the-installer"><span class="header-section-number">3.2.4</span> Booting the installer</h3>
+<p>Make sure your Linux install stick is plugged into your PC.</p>
+<p>Click <code>Restart</code> in the Windows start menu, while holding down the <code>Shift</code> key. A <code>Please wait</code>-text appears, after which Windows should enter the troubleshooting menu.</p>
+<p>From this menu you can choose a startup device, or enter the UEFI settings.</p>
+<ul>
+<li>To choose the startup device, select <code>Use a device</code>. As we want to boot from the Linux USB stick choose <code>USB FDD</code> or similar.</li>
+<li>To enter the UEFI settings, select <code>Troubleshoot</code>, <code>Advanced Options</code> and then <code>UEFI   Firmware Settings</code>.</li>
+</ul>
+<p>If none of this works, you can try to change the startup device immediately after booting. This guide will explain how in the next chapter.</p>
+<h2 data-number="3.3" id="macos"><span class="header-section-number">3.3</span> macOS</h2>
+<p><span style="color:red"> <em>Note that on modern Apple computers it is generally not advisable to install Linux (MacBooks after 2016 simply are not very compatible with Linux.)</em> </span></p>
+<p>Up-to-date information on the status of Linux support on MacBooks can be found <a href="https://github.com/Dunedan/mbp-2016-linux">here</a>.</p>
+<h3 data-number="3.3.1" id="shrink-your-os-x-partition"><span class="header-section-number">3.3.1</span> Shrink your OS X partition</h3>
+<p>On OS X, we will resize your existing partition to make space for your new Linux system.</p>
+<ul>
+<li>Go to <code>/Applications/Utilities</code> and open the <code>Disk Utility</code>.</li>
+<li>Select your main disk in the list to the left (usually the first or the largest).</li>
+<li>Select the tab <code>Partition</code>.</li>
+<li>On the left side there is a white rectangle with some blue threshold indicating the space consumed by Mac OS X.</li>
+<li>Click and hold the lower right corner of that rectangle and draw the cursor upwards, to shrink the volume.</li>
+<li>The text on the right will give you information about the freed memory.</li>
+<li>Once you are satisfied, click <code>Apply</code> to confirm the shrinking operation.</li>
+</ul>
+<h3 data-number="3.3.2" id="install-refind"><span class="header-section-number">3.3.2</span> Install rEFInd</h3>
+<p>We will install the bootloader on OS X before the Linux installation. <em>rEFInd</em> will boot your USB Install Medium as well as your operating system later on.</p>
+<ul>
+<li>Browse the web for <a href="http://www.rodsbooks.com/refind/getting.html">http://www.rodsbooks.com/refind/getting.html</a> and scroll down a bit to click the link <em>A binary zip file</em>.</li>
+<li>Once the download has completed, go to the <em>Download folder</em> and extract the file.</li>
+<li>Open a Mac terminal by going to <code>Application/Utilities</code> and opening <code>Terminal</code>.</li>
+<li>Type <code>cd</code> (with a space afterwards, but do <strong>not</strong> press <em>Enter</em> yet) and drag the extracted folder into the terminal.</li>
+<li>Now, hit <em>Enter</em> and then type <code>./refind-install</code>.</li>
+<li>When prompted for your password, enter it. (You won’t see what you enter at the password prompt at all. You have to enter your password blindly.)</li>
+</ul>
+<h3 data-number="3.3.3" id="troubleshoot"><span class="header-section-number">3.3.3</span> Troubleshoot</h3>
+<p>In case you get an error message saying <em>ALERT: SIP ENABLED</em>, you need to do the following:</p>
+<ul>
+<li>Turn off your Mac and start it again, pressing <code>Cmd + R</code> immediately after turning it on again (you might want to hold it for a while).</li>
+<li>Your Mac should boot in <code>recovery mode</code>. Go to <code>Utilities</code> and open up a terminal.</li>
+<li>Now type: <code>csrutil disable</code>.</li>
+<li>Then reboot back into your normal system and try to install <em>rEFInd</em> again.</li>
+<li>After installation, feel free to go once more into recovery and type <code>csrutil enable</code>.</li>
+</ul>
+<h3 data-number="3.3.4" id="booting-the-installer-1"><span class="header-section-number">3.3.4</span> Booting the installer</h3>
+<p>We will now boot from your USB Install Medium.</p>
+<ul>
+<li>Plug your USB Install Medium into your laptop.</li>
+<li>Reboot your machine and <em>rEFInd</em> should see the USB key.</li>
+<li>Your USB installer may have several ways to boot. They all will show up and have a little USB icon to the bottom right.</li>
+<li>Usually the first USB installer is correct. If it doesn’t work, reboot and try the others.</li>
+<li>If your USB installer doesn’t show up, hit <code>Escape</code> to refresh the list. It should show up now.</li>
+<li>If you see multiple USB keys, try each of them until you find the Linux installer.</li>
+</ul>
+<h1 data-number="4" id="install"><span class="header-section-number">4</span> Install</h1>
+<p>You are all set to install Linux on your device.</p>
+<p>If you have not yet done so; ensure you have backed up all your data! In the (unlikely) case something goes terribly wrong, you can recover your data.</p>
+<h2 data-number="4.1" id="boot-from-stick"><span class="header-section-number">4.1</span> Boot from Stick</h2>
+<p>You now want to boot from the USB stick (if you have not already done so, depending on your existing operating system).</p>
+<p>This step can be tricky, as the way to accomplish this is different over different devices and brands. Generally you need to look for something like “BIOS” or “startup device”. You then need to choose the USB stick as the startup device.</p>
+<p>You can enter the BIOS or change the startup device usually with the function keys (such as F1, F8, F10, F12) or with other keys like ESC or Enter.</p>
+<p>The most common keys by brand: - Lenovo: Enter - HP: Esc</p>
+<h2 data-number="4.2" id="partitioning"><span class="header-section-number">4.2</span> Partitioning</h2>
+<p>This can either be done automatically by the Linux distributions installer, or manually if you want more control over your setup. If you are unsure about what setup you want, it might be best to follow the automatic setup.</p>
+<figure>
+<img src="images/partitions.png" alt="Example partitions for a system with Linux only" /><figcaption aria-hidden="true">Example partitions for a system with Linux only</figcaption>
+</figure>
+<figure>
+<img src="images/partitions2.jpg" alt="Example partitions for a dual boot system" /><figcaption aria-hidden="true">Example partitions for a dual boot system</figcaption>
+</figure>
+<h3 data-number="4.2.1" id="automatic-setup"><span class="header-section-number">4.2.1</span> Automatic setup</h3>
+<p>The various installers usually offer an option to either install alongside an existing operating system (Windows/Mac), or to use the entire disk and erase previously installed systems. If you choose to install alongside something else, there is usually an option to choose how much space you want to allocate for the new system. Note that the partition for the old system will also have to shrink by this amount.</p>
+<h3 data-number="4.2.2" id="manual-setup"><span class="header-section-number">4.2.2</span> Manual setup</h3>
+<p>If you want a manual setup these are some partitions you might consider:</p>
+<ul>
+<li><code>/boot</code>: This is the boot partition for EFI. This already exists and will be reused when installing your new operating system.</li>
+<li><code>/</code> (root). A root partition is required for all installations. This is where all the operating system files live.</li>
+<li><code>/home</code>: Some users like to their home directory on a different partition. This can make re-installation of a distribution easier. However, this is entirely optional.</li>
+<li><code>/swap</code>: A swap partition is used as an extension for your machines memory, if it ever fills up. Nowadays, a lot of people omit this on personal computers.</li>
+</ul>
+<p>You will also be able to choose a file system for <code>/</code> and <code>/home</code>. Almost always the <code>ext4</code> filesystem should be used. If you know what you are doing, you can of course also choose something else.</p>
+<h2 data-number="4.3" id="ubuntu"><span class="header-section-number">4.3</span> Ubuntu</h2>
+<p>We recommend to follow the <a href="https://ubuntu.com/tutorials/tutorial-install-ubuntu-desktop">official install-guide</a> for installing Ubuntu.</p>
+<p>As further resources, we recommend the <a href="https://wiki.ubuntu.com/">Ubuntu Wiki</a> and the <a href="https://askubuntu.com/">askubuntu StackExchange</a>.</p>
+<h2 data-number="4.4" id="fedora"><span class="header-section-number">4.4</span> Fedora</h2>
+<p>The top-level documentation for Fedora can be found on the official <a href="https://docs.fedoraproject.org/en-US/docs/">Fedora docs website</a>.</p>
+<p>The following links are a good starting point:</p>
+<ul>
+<li>The Fedora <a href="https://docs.fedoraproject.org/en-US/fedora/f31/install-guide/Introduction/">install guide</a></li>
+<li>The <a href="https://docs.fedoraproject.org/en-US/quick-docs/">usage and customization guide</a></li>
+<li>The guide for upgrading to a new <a href="https://docs.fedoraproject.org/en-US/quick-docs/dnf-system-upgrade/">release</a></li>
+</ul>
+<h2 data-number="4.5" id="open-suse"><span class="header-section-number">4.5</span> Open SUSE</h2>
+<p>For getting started with OpenSuse we recommend going through <a href="https://www.opensuse-guide.org">Unofficial openSUSE Guide</a>, since it gives a good overview and can save you some time.</p>
+<p>Also check out the <a href="https://doc.opensuse.org/documentation/leap/startup/single-html/book.opensuse.startup/index.html">Start-Up Guide</a> from their website and the <a href="https://en.opensuse.org/Portal:Documentation">documentation</a> if you have further questions or want to work with the official material.</p>
+<h1 data-number="5" id="software"><span class="header-section-number">5</span> Software</h1>
+<p>These are software recommendations for Linux. Most of these are graphical programs, but there are some programs that run in the terminal only. Note that these programs have various licenses, some might not even be “libre” software (due to them becoming closed source at a later point, or this list having errors)!</p>
+<p>Some programs are annotated if they are best used on GNOME or KDE. This does not mean they cannot be used on the other environment, but the visual integration might be lacking in these cases.</p>
+<h2 data-number="5.1" id="office"><span class="header-section-number">5.1</span> Office</h2>
+<table>
+<colgroup>
+<col style="width: 33%" />
+<col style="width: 33%" />
+<col style="width: 33%" />
+</colgroup>
+<thead>
+<tr class="header">
+<th style="text-align: left;">Use case</th>
+<th style="text-align: left;">Application</th>
+<th style="text-align: left;">Comment</th>
+</tr>
+</thead>
+<tbody>
+<tr class="odd">
+<td style="text-align: left;">Office suite</td>
+<td style="text-align: left;">LibreOffice</td>
+<td style="text-align: left;"></td>
+</tr>
+<tr class="even">
+<td style="text-align: left;">Office suite</td>
+<td style="text-align: left;">OnlyOffice</td>
+<td style="text-align: left;">Looks much nicer than LibreOffice</td>
+</tr>
+<tr class="odd">
+<td style="text-align: left;">PDF viewer</td>
+<td style="text-align: left;">Zathura</td>
+<td style="text-align: left;">All desktop environments include a PDF viewer. Zathura is another, more simple option.</td>
+</tr>
+<tr class="even">
+<td style="text-align: left;">Note taking, PDF annotation</td>
+<td style="text-align: left;">Xournal</td>
+<td style="text-align: left;"></td>
+</tr>
+<tr class="odd">
+<td style="text-align: left;">LaTeX editor</td>
+<td style="text-align: left;">Texstudio, Texmaker, GNOME LaTeX</td>
+<td style="text-align: left;">Texstudio/Texmaker are “what you see is what you get”, GNOME LaTeX uses a “write, then compile” workflow.</td>
+</tr>
+<tr class="even">
+<td style="text-align: left;">Mindmapping</td>
+<td style="text-align: left;">vym</td>
+<td style="text-align: left;"></td>
+</tr>
+<tr class="odd">
+<td style="text-align: left;">Design/Publishing</td>
+<td style="text-align: left;">Scribus</td>
+<td style="text-align: left;"></td>
+</tr>
+<tr class="even">
+<td style="text-align: left;">Simple Text Editor</td>
+<td style="text-align: left;">Gedit/Geany (GNOME), Kwrite/Kate (KDE)</td>
+<td style="text-align: left;"></td>
+</tr>
+<tr class="odd">
+<td style="text-align: left;">Advanced Text Editor</td>
+<td style="text-align: left;">vim, emacs</td>
+<td style="text-align: left;">These are a bit more difficult to learn, but are very popular with power users.</td>
+</tr>
+<tr class="even">
+<td style="text-align: left;">File manager</td>
+<td style="text-align: left;">PCManFM, ranger/nnn (Terminal)</td>
+<td style="text-align: left;">All desktop environments include a file manager, these are other more advanced options.</td>
+</tr>
+<tr class="odd">
+<td style="text-align: left;">CAD</td>
+<td style="text-align: left;">FreeCAD</td>
+<td style="text-align: left;"></td>
+</tr>
+</tbody>
+</table>
+<h2 data-number="5.2" id="graphics"><span class="header-section-number">5.2</span> Graphics</h2>
+<table>
+<colgroup>
+<col style="width: 33%" />
+<col style="width: 33%" />
+<col style="width: 33%" />
+</colgroup>
+<thead>
+<tr class="header">
+<th style="text-align: left;">Use case</th>
+<th style="text-align: left;">Application</th>
+<th style="text-align: left;">Comment</th>
+</tr>
+</thead>
+<tbody>
+<tr class="odd">
+<td style="text-align: left;">Image editing</td>
+<td style="text-align: left;">GIMP, Pinta</td>
+<td style="text-align: left;">GIMP is a more fully featured editor, similar to Photoshop. Pinta is inspired by Paint.NET.</td>
+</tr>
+<tr class="even">
+<td style="text-align: left;">Painting</td>
+<td style="text-align: left;">Krita</td>
+<td style="text-align: left;"></td>
+</tr>
+<tr class="odd">
+<td style="text-align: left;">3D Animation</td>
+<td style="text-align: left;">Blender</td>
+<td style="text-align: left;"></td>
+</tr>
+<tr class="even">
+<td style="text-align: left;">Photo management</td>
+<td style="text-align: left;">Darktable, Digikam</td>
+<td style="text-align: left;"></td>
+</tr>
+<tr class="odd">
+<td style="text-align: left;">Scanning</td>
+<td style="text-align: left;">Skanlite (KDE), SimpleScan (GNOME)</td>
+<td style="text-align: left;"></td>
+</tr>
+<tr class="even">
+<td style="text-align: left;">OCR (Text Recognition)</td>
+<td style="text-align: left;">OCRGui, OCRmyPDF (Terminal)</td>
+<td style="text-align: left;"></td>
+</tr>
+</tbody>
+</table>
+<h2 data-number="5.3" id="multimedia"><span class="header-section-number">5.3</span> Multimedia</h2>
+<table>
+<colgroup>
+<col style="width: 33%" />
+<col style="width: 33%" />
+<col style="width: 33%" />
+</colgroup>
+<thead>
+<tr class="header">
+<th style="text-align: left;">Use case</th>
+<th style="text-align: left;">Application</th>
+<th style="text-align: left;">Comment</th>
+</tr>
+</thead>
+<tbody>
+<tr class="odd">
+<td style="text-align: left;">Video Player</td>
+<td style="text-align: left;">mpv, VLC, Totem (GNOME)</td>
+<td style="text-align: left;">Desktop environments have a default video player, but mpv/VLC are usually more powerful.</td>
+</tr>
+<tr class="even">
+<td style="text-align: left;">Audio editing</td>
+<td style="text-align: left;">Audacity</td>
+<td style="text-align: left;"></td>
+</tr>
+<tr class="odd">
+<td style="text-align: left;">MP3 tagging</td>
+<td style="text-align: left;">Picard</td>
+<td style="text-align: left;"></td>
+</tr>
+<tr class="even">
+<td style="text-align: left;">Digital Audio Workstation (DAW)</td>
+<td style="text-align: left;">Ardour</td>
+<td style="text-align: left;"></td>
+</tr>
+<tr class="odd">
+<td style="text-align: left;">YouTube downloader</td>
+<td style="text-align: left;">youtube-dl (Terminal)</td>
+<td style="text-align: left;">Requires regular updates, because YouTube changes their website rather often</td>
+</tr>
+<tr class="even">
+<td style="text-align: left;">Screen recording</td>
+<td style="text-align: left;">OBS, SimpleScreenRecorder</td>
+<td style="text-align: left;">OBS is very powerful, SimpleScreenRecorder is more simple option.</td>
+</tr>
+</tbody>
+</table>
+<h2 data-number="5.4" id="scientific"><span class="header-section-number">5.4</span> Scientific</h2>
+<table>
+<colgroup>
+<col style="width: 33%" />
+<col style="width: 33%" />
+<col style="width: 33%" />
+</colgroup>
+<thead>
+<tr class="header">
+<th style="text-align: left;">Use case</th>
+<th style="text-align: left;">Application</th>
+<th style="text-align: left;">Comment</th>
+</tr>
+</thead>
+<tbody>
+<tr class="odd">
+<td style="text-align: left;">Matlab</td>
+<td style="text-align: left;">Python+Numpy, Octave</td>
+<td style="text-align: left;">Octave tries to be similar to Matlab, while Python+Numpy is rather different.</td>
+</tr>
+<tr class="even">
+<td style="text-align: left;">Statistics</td>
+<td style="text-align: left;">R, PSPP</td>
+<td style="text-align: left;"></td>
+</tr>
+<tr class="odd">
+<td style="text-align: left;">ArcGIS</td>
+<td style="text-align: left;">QGIS, GRASS GIS</td>
+<td style="text-align: left;"></td>
+</tr>
+</tbody>
+</table>
+<h2 data-number="5.5" id="internet"><span class="header-section-number">5.5</span> Internet</h2>
+<table>
+<colgroup>
+<col style="width: 33%" />
+<col style="width: 33%" />
+<col style="width: 33%" />
+</colgroup>
+<thead>
+<tr class="header">
+<th style="text-align: left;">Use case</th>
+<th style="text-align: left;">Application</th>
+<th style="text-align: left;">Comment</th>
+</tr>
+</thead>
+<tbody>
+<tr class="odd">
+<td style="text-align: left;">Web Browser</td>
+<td style="text-align: left;">Firefox, Chromium, qutebrowser</td>
+<td style="text-align: left;">We recommend using Chromium instead of Google Chrome on Linux</td>
+</tr>
+<tr class="even">
+<td style="text-align: left;">Mail</td>
+<td style="text-align: left;">Thunderbird, KMail (KDE), Evolution (GNOME), mutt (Terminal)</td>
+<td style="text-align: left;"></td>
+</tr>
+<tr class="odd">
+<td style="text-align: left;">Instant Messaging</td>
+<td style="text-align: left;">Telegram, Pidgin, Empathy (GNOME)</td>
+<td style="text-align: left;"></td>
+</tr>
+<tr class="even">
+<td style="text-align: left;">Torrent client</td>
+<td style="text-align: left;">Transmission (GNOME), Ktorrent (KDE), Deluge, rtorrent (Terminal)</td>
+<td style="text-align: left;"></td>
+</tr>
+<tr class="odd">
+<td style="text-align: left;">Voice chat</td>
+<td style="text-align: left;">Mumble, Empathy (GNOME)</td>
+<td style="text-align: left;"></td>
+</tr>
+<tr class="even">
+<td style="text-align: left;">File synchronization</td>
+<td style="text-align: left;">Syncthing, Nextcloud, OwnCloud, Seafile</td>
+<td style="text-align: left;"></td>
+</tr>
+</tbody>
+</table>
+<h2 data-number="5.6" id="system"><span class="header-section-number">5.6</span> System</h2>
+<table>
+<colgroup>
+<col style="width: 33%" />
+<col style="width: 33%" />
+<col style="width: 33%" />
+</colgroup>
+<thead>
+<tr class="header">
+<th style="text-align: left;">Use case</th>
+<th style="text-align: left;">Application</th>
+<th style="text-align: left;">Comment</th>
+</tr>
+</thead>
+<tbody>
+<tr class="odd">
+<td style="text-align: left;">Disk usage</td>
+<td style="text-align: left;">Baobab (GNOME), Filelight (KDE), ncdu (Terminal)</td>
+<td style="text-align: left;"></td>
+</tr>
+<tr class="even">
+<td style="text-align: left;">Virtualization</td>
+<td style="text-align: left;">virt-manager, VirtualBox, GNOME Boxes</td>
+<td style="text-align: left;"></td>
+</tr>
+<tr class="odd">
+<td style="text-align: left;">Backup</td>
+<td style="text-align: left;">borg backup, Déjà Dup</td>
+<td style="text-align: left;"></td>
+</tr>
+<tr class="even">
+<td style="text-align: left;">System monitor</td>
+<td style="text-align: left;">htop (Terminal)</td>
+<td style="text-align: left;">The desktop environment have their own system monitor included.</td>
+</tr>
+</tbody>
+</table>
+<h2 data-number="5.7" id="development"><span class="header-section-number">5.7</span> Development</h2>
+<table>
+<colgroup>
+<col style="width: 33%" />
+<col style="width: 33%" />
+<col style="width: 33%" />
+</colgroup>
+<thead>
+<tr class="header">
+<th style="text-align: left;">Use case</th>
+<th style="text-align: left;">Application</th>
+<th style="text-align: left;">Comment</th>
+</tr>
+</thead>
+<tbody>
+<tr class="odd">
+<td style="text-align: left;">IDE</td>
+<td style="text-align: left;">IntelliJ, Eclipse, Code::Blocks, Android Studio, Geany, Qt Creator, Gnome Builder</td>
+<td style="text-align: left;">Some of these might not be Free and Open Source!</td>
+</tr>
+</tbody>
+</table>
+<h2 data-number="5.8" id="other"><span class="header-section-number">5.8</span> Other</h2>
+<table>
+<colgroup>
+<col style="width: 33%" />
+<col style="width: 33%" />
+<col style="width: 33%" />
+</colgroup>
+<thead>
+<tr class="header">
+<th style="text-align: left;">Use case</th>
+<th style="text-align: left;">Application</th>
+<th style="text-align: left;">Comment</th>
+</tr>
+</thead>
+<tbody>
+<tr class="odd">
+<td style="text-align: left;">Dropdown terminal</td>
+<td style="text-align: left;">Guake (GNOME), Yakuake (KDE)</td>
+<td style="text-align: left;"></td>
+</tr>
+<tr class="even">
+<td style="text-align: left;">Clipboard manager</td>
+<td style="text-align: left;">Glipper (GNOME), Clipman (XFCE)</td>
+<td style="text-align: left;">The desktop environment each have their own clipboard manager.</td>
+</tr>
+</tbody>
+</table>
+<h1 data-number="6" id="troubleshooting"><span class="header-section-number">6</span> Troubleshooting</h1>
+<p>A chapter for some advanced troubleshooting. If you need something contained in this chapter, better ask some advanced user for help (or one of our helpers if you are at our Install Event).</p>
+<h2 data-number="6.1" id="microsoft-surface"><span class="header-section-number">6.1</span> Microsoft Surface</h2>
+<h3 data-number="6.1.1" id="something-doesnt-work"><span class="header-section-number">6.1.1</span> Something doesn’t work</h3>
+<p>Microsoft Surface devices usually require a patched kernel. <a href="https://github.com/linux-surface/linux-surface">See this project</a> to install such a kernel.</p>
+<h2 data-number="6.2" id="wireless"><span class="header-section-number">6.2</span> Wireless</h2>
+<h3 data-number="6.2.1" id="broadcom-on-ubuntu-doesnt-work"><span class="header-section-number">6.2.1</span> Broadcom on Ubuntu doesn’t work</h3>
+<p><a href="https://help.ubuntu.com/community/WifiDocs/Driver/bcm43xx">See this.</a></p>
+<h3 data-number="6.2.2" id="installing-broadcom-firmware"><span class="header-section-number">6.2.2</span> Installing Broadcom Firmware</h3>
+<p><em>openSUSE:</em></p>
+<p><code>sudo zypper install b43-fwcutter</code> <code>sudo /usr/sbin/install_bcm43xx_firmware</code></p>
+<p><a href="https://www.opensuse-guide.org/wlan.php">See also this site.</a></p>
+<p><em>Ubuntu:</em></p>
+<p><code>sudo apt install firmware-b43-installer</code></p>
+<p><a href="http://linuxwireless.org/en/users/Drivers/b43/">See also this site.</a></p>
+<h2 data-number="6.3" id="opensuse"><span class="header-section-number">6.3</span> OpenSUSE</h2>
+<h3 data-number="6.3.1" id="installing-broadcom-wireless-drivers-broadcom-wl"><span class="header-section-number">6.3.1</span> Installing Broadcom Wireless Drivers (broadcom-wl)</h3>
+<ul>
+<li>Add the packman repo: YaST -&gt; Software repos -&gt; Add -&gt; Select community -&gt; repos -&gt; Next -&gt; Select packman -&gt; Finish</li>
+<li><code>zypper ref</code></li>
+<li><code>zypper install broadcom-wl</code></li>
+</ul>
+<h2 data-number="6.4" id="graphics-drivers"><span class="header-section-number">6.4</span> Graphics drivers</h2>
+<h2 data-number="6.5" id="system-hangs-at-boot-nvidia-present"><span class="header-section-number">6.5</span> System hangs at boot (NVIDIA present)</h2>
+<p>Boot with <code>nomodeset</code> kernel parameter, then either install proprietary NVIDIA drivers or disable the NVIDIA graphics entirely.</p>
+<h2 data-number="6.6" id="i-want-to-disable-the-nouveau-driver"><span class="header-section-number">6.6</span> I want to disable the Nouveau driver</h2>
+<p><code>echo 'blacklist nouveau' | tee /etc/modprobe.d/blacklist.conf</code></p>
+<h2 data-number="6.7" id="acer"><span class="header-section-number">6.7</span> Acer</h2>
+<p>Some types of newer Acer notebooks need special settings for Secure Boot in order to boot an installed GNU/Linux system at all. If you installed eg. Ubuntu but it directly boots Windows without giving you a GRUB selection screen, try the following guide: https://askubuntu.com/questions/771455/dual-boot-ubuntu-with-windows-on-acer-aspire/771749#771749</p>
+<h2 data-number="6.8" id="system-1"><span class="header-section-number">6.8</span> System</h2>
+<h3 data-number="6.8.1" id="chroot-into-an-installed-system"><span class="header-section-number">6.8.1</span> chroot into an installed system</h3>
+<p>To chroot into an installed system from a live iso, do the following:</p>
+<ul>
+<li><code>sudo su</code></li>
+<li><code>mount /dev/sdaX /mnt</code>, where <code>sdaX</code> is your root partition</li>
+<li>If you have EFI: <code>mount /dev/sda1 /mnt/boot/efi</code> (assuming <code>sda1</code> is your EFI partition)</li>
+<li><code>mount -t proc proc /mnt/proc/</code></li>
+<li><code>mount -t sysfs sys /mnt/sys/</code></li>
+<li><code>mount -o bind /dev /mnt/dev/</code></li>
+<li><code>chroot /mnt /bin/bash</code></li>
+</ul>
+<h3 data-number="6.8.2" id="cleaning-up-boot-entries"><span class="header-section-number">6.8.2</span> Cleaning up boot entries</h3>
+<ul>
+<li><code>efibootmgr</code> prints all boot entries.</li>
+<li><code>efibootmgr -o XXXX,YYYY,ZZZZ</code> sets the boot order.</li>
+<li><code>efibootmgr -b &lt;number&gt; -B</code> deletes an EFI boot entry.</li>
+</ul>
+<h3 data-number="6.8.3" id="drives-are-not-found-in-the-installer"><span class="header-section-number">6.8.3</span> Drives are not found in the installer</h3>
+<p>Especially newer laptops (2018+) have options to switch between RAID and AHCI boot mode.</p>
+<p>If the laptop is running in RAID mode and Linux does not recognize its drives, it will have to be switched to AHCI. Unfortunately, this also means Windows needs to be reconfigured, otherwise it won’t boot anymore.</p>
+<ol type="1">
+<li>Click the Start Button and type <code>cmd</code></li>
+<li>Right-click the result and select <em>Run as administrator</em></li>
+<li>Type this command and press <em>ENTER:</em> <code>bcdedit /set {current} safeboot minimal</code> (ALT: <code>bcdedit /set safeboot minimal</code>)</li>
+<li>Restart the computer and enter BIOS Setup</li>
+<li>Change the SATA Operation mode to AHCI from either IDE or RAID</li>
+<li>Save changes and exit Setup and Windows will automatically boot to Safe Mode.</li>
+<li>Right-click the Windows Start Menu once more. Choose Command Prompt (Admin).</li>
+<li>Type this command and press ENTER: <code>bcdedit /deletevalue {current} safeboot</code> (ALT: bcdedit /deletevalue safeboot)</li>
+<li>Reboot once more and Windows will automatically start with AHCI drivers enabled.</li>
+</ol>
+<h3 data-number="6.8.4" id="bit-efi-is-used"><span class="header-section-number">6.8.4</span> 32-bit EFI is used</h3>
+<ul>
+<li>No provided install image will boot.</li>
+<li>Windows is installed in 32-bit mode.</li>
+<li>Some older Macbooks have this configuration.</li>
+<li>To install 64-bit Linux (we never encountered an actual 32-bit CPU with this problem!), manually replace the bootloader with a grub standalone. <a href="https://wiki.archlinux.org/index.php/Unified_Extensible_Firmware_Interface#Booting_64-bit_kernel_on_32-bit_UEFI">See the Arch Wiki.</a></li>
+</ul>
+<h3 data-number="6.8.5" id="i-need-to-turn-off-bitlocker"><span class="header-section-number">6.8.5</span> I need to turn off Bitlocker</h3>
+<p><strong>Do not change any BIOS/UEFI settings before disabling BitLocker!</strong> You will have to provide the decryption key otherwise, which the user typically has no access to.</p>
+<ul>
+<li>Launch a command prompt with administrator rights and use <code>manage-bde -off   C:</code>, where <code>C:</code> is the drive you want to decrypt.</li>
+<li>Use the command <code>manage-bde -status</code> to query the decryption status.</li>
+<li>You will need to wait until decryption is complete, which can take a long time.</li>
+</ul>
+<h3 data-number="6.8.6" id="unlock-bitlocker-encrypted-devices"><span class="header-section-number">6.8.6</span> Unlock BitLocker Encrypted Devices</h3>
+<p>If you change any UEFI settings on a BitLocker encrypted device (typically Surface devices), you will be prompted for the BitLocker key on next boot.</p>
+<p>Since Surface devices come encrypted out of the box, the user does typically not have that key and Windows will refuse to boot. If this happens, resetting the UEFI settings to factory settings should fix the issue.</p>
+<p>Alternatively, you can just enter the correct Bitlocker key. This works only if the user has a Microsoft account linked to the device. You can get the BitLocker key as follows:</p>
+<ul>
+<li>On another device, google for “BitLocker Recovery Key”. You should find several Microsoft Support or FAQ pages on how to recover the key.</li>
+<li>Search for a link saying “To get your recovery key, go to BitLocker Recovery Keys” or similar. Go there.</li>
+<li>Ask the user to sign in using their Microsoft account. The website will then display their recovery key, which can be used to unlock the device.</li>
+</ul>
+<h3 data-number="6.8.7" id="system-will-not-boot-under-any-circumstance"><span class="header-section-number">6.8.7</span> System will not boot under any circumstance</h3>
+<p>Some very bad firmwares just refuse to boot GRUB, however you configure it. This “bootloader hack” can be applied in these cases.</p>
+<ul>
+<li>Try to boot the actual distro that has been installed by “using a device” to boot. Do so by holding shift while clicking on “reboot” in Windows.</li>
+<li>If that doesn’t work, boot a live system and chroot into the installed system.</li>
+<li>Once booted or chrooted into the Linux system, become root (sudo su) and go to <code>/boot/efi/EFI/Microsoft/Boot</code> and locate a file named <code>bootmgfw.efi</code>. Rename it to <code>bootmgfw-original.efi</code>.</li>
+<li>Go to <code>/boot/efi/EFI/grub2</code> (sometimes also just <code>grub</code>) and locate the file <code>grubx64.efi</code>. Copy it over to <code>/boot/efi/EFI/Microsoft/Boot/</code>. If a file called <code>shimx64.efi</code> exists, copy that one over as well.</li>
+<li>Find the file <code>grub.cfg</code> in <code>/boot/efi/EFI/grub2</code> and copy it over to <code>/boot/efi/EFI/Microsoft/Boot/</code>.</li>
+<li>Go back to <code>/boot/efi/EFI/Microsoft/Boot/</code>. If <code>shimx64.efi</code> exists, rename it to <code>bootmgfw.efi</code>. If it does not exist, rename <code>grubx64.efi</code> to <code>bootmgfw.efi</code>.</li>
+<li>Now go to <code>/boot/grub/</code>, or <code>/boot/opensuse/</code> (the exact folder path may vary). Find the file <code>grub.cfg</code> and open it. Find the <code>menuentry</code> block for Windows (usually called “Windows Bootloader (on /dev/sdx)” or similar). Copy the entire block.</li>
+<li>Uninstall the package <code>os-prober</code>.</li>
+<li>Now go to /etc/grub.d. If a file with <code>os-prober</code> in its name exists, delete it.</li>
+<li>Find the file <code>40-custom.cfg</code>. If it doesn’t exist, create it. Paste the menuentry block you copied earlier in this file.</li>
+<li>In the text you just pasted, look for <code>bootmgfw.efi</code> and change it to <code>bootmgfw-original.efi</code>.</li>
+<li>Save the file.</li>
+<li>Run <code>grub-mkconfig -o /boot/grub/grub.cfg</code>. Make sure the file path matches the path where you originally found the <code>grub.cfg</code> you copied the menuentry from.</li>
+<li>Reboot and verify that grub now loads properly. Also test whether Windows boots!</li>
+</ul>
diff --git a/package-lock.json b/package-lock.json
index b9c767737eda12c9f7b1456cc01c1a3e6ff29a0e..05a6fec1f8d0ee511fd256d98f6f60064b48f6a4 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,14 +9,27 @@
       "version": "0.1.0",
       "dependencies": {
         "@apollo/client": "^3.8.1",
+        "@mantine/dates": "^5.10.5",
+        "@mantine/form": "^6.0.20",
         "@mantine/notifications": "^5.10.5",
+        "@mantine/tiptap": "^5.10.5",
+        "@prisma/client": "^5.3.1",
+        "@tiptap/extension-underline": "^2.1.10",
+        "@tiptap/react": "^2.1.10",
+        "@tiptap/starter-kit": "^2.1.10",
+        "adblock-hunter": "^1.0.1",
+        "axios": "^1.5.0",
         "eslint": "8.48.0",
         "eslint-config-next": "13.4.19",
+        "graphql-scalars": "^1.22.2",
+        "graphql-yoga": "^4.0.4",
         "html-react-parser": "^4.2.1",
         "jsonwebtoken": "^9.0.1",
         "next": "13.4.19",
         "next-auth": "^4.23.1",
         "next-i18next": "^14.0.0",
+        "nodemailer": "^6.9.4",
+        "ol": "^8.0.0",
         "react": "18.2.0",
         "react-dom": "18.2.0",
         "sharp": "^0.32.5",
@@ -2243,6 +2256,29 @@
       "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz",
       "integrity": "sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww=="
     },
+    "node_modules/@envelop/core": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/@envelop/core/-/core-4.0.1.tgz",
+      "integrity": "sha512-uBLI7ql3hZopz7vMi9UDAb9HWzKw4STKiqg4QT+lb+tu5ZNaeuJ4fom2rrmgITz38B85QZOhZrGyVrlJXxfDzw==",
+      "dependencies": {
+        "@envelop/types": "4.0.1",
+        "tslib": "^2.5.0"
+      },
+      "engines": {
+        "node": ">=16.0.0"
+      }
+    },
+    "node_modules/@envelop/types": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/@envelop/types/-/types-4.0.1.tgz",
+      "integrity": "sha512-ULo27/doEsP7uUhm2iTnElx13qTO6I5FKvmLoX41cpfuw8x6e0NUFknoqhEsLzAbgz8xVS5mjwcxGCXh4lDYzg==",
+      "dependencies": {
+        "tslib": "^2.5.0"
+      },
+      "engines": {
+        "node": ">=16.0.0"
+      }
+    },
     "node_modules/@eslint-community/eslint-utils": {
       "version": "4.4.0",
       "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz",
@@ -2343,6 +2379,72 @@
       "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.1.1.tgz",
       "integrity": "sha512-m0G6wlnhm/AX0H12IOWtK8gASEMffnX08RtKkCgTdHb9JpHKGloI7icFfLg9ZmQeavcvR0PKmzxClyuFPSjKWw=="
     },
+    "node_modules/@graphql-tools/executor": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/@graphql-tools/executor/-/executor-1.2.0.tgz",
+      "integrity": "sha512-SKlIcMA71Dha5JnEWlw4XxcaJ+YupuXg0QCZgl2TOLFz4SkGCwU/geAsJvUJFwK2RbVLpQv/UMq67lOaBuwDtg==",
+      "dependencies": {
+        "@graphql-tools/utils": "^10.0.0",
+        "@graphql-typed-document-node/core": "3.2.0",
+        "@repeaterjs/repeater": "^3.0.4",
+        "tslib": "^2.4.0",
+        "value-or-promise": "^1.0.12"
+      },
+      "engines": {
+        "node": ">=16.0.0"
+      },
+      "peerDependencies": {
+        "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0"
+      }
+    },
+    "node_modules/@graphql-tools/merge": {
+      "version": "9.0.0",
+      "resolved": "https://registry.npmjs.org/@graphql-tools/merge/-/merge-9.0.0.tgz",
+      "integrity": "sha512-J7/xqjkGTTwOJmaJQJ2C+VDBDOWJL3lKrHJN4yMaRLAJH3PosB7GiPRaSDZdErs0+F77sH2MKs2haMMkywzx7Q==",
+      "dependencies": {
+        "@graphql-tools/utils": "^10.0.0",
+        "tslib": "^2.4.0"
+      },
+      "engines": {
+        "node": ">=16.0.0"
+      },
+      "peerDependencies": {
+        "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0"
+      }
+    },
+    "node_modules/@graphql-tools/schema": {
+      "version": "10.0.0",
+      "resolved": "https://registry.npmjs.org/@graphql-tools/schema/-/schema-10.0.0.tgz",
+      "integrity": "sha512-kf3qOXMFcMs2f/S8Y3A8fm/2w+GaHAkfr3Gnhh2LOug/JgpY/ywgFVxO3jOeSpSEdoYcDKLcXVjMigNbY4AdQg==",
+      "dependencies": {
+        "@graphql-tools/merge": "^9.0.0",
+        "@graphql-tools/utils": "^10.0.0",
+        "tslib": "^2.4.0",
+        "value-or-promise": "^1.0.12"
+      },
+      "engines": {
+        "node": ">=16.0.0"
+      },
+      "peerDependencies": {
+        "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0"
+      }
+    },
+    "node_modules/@graphql-tools/utils": {
+      "version": "10.0.6",
+      "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-10.0.6.tgz",
+      "integrity": "sha512-hZMjl/BbX10iagovakgf3IiqArx8TPsotq5pwBld37uIX1JiZoSbgbCIFol7u55bh32o6cfDEiiJgfAD5fbeyQ==",
+      "dependencies": {
+        "@graphql-typed-document-node/core": "^3.1.1",
+        "dset": "^3.1.2",
+        "tslib": "^2.4.0"
+      },
+      "engines": {
+        "node": ">=16.0.0"
+      },
+      "peerDependencies": {
+        "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0"
+      }
+    },
     "node_modules/@graphql-typed-document-node/core": {
       "version": "3.2.0",
       "resolved": "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.2.0.tgz",
@@ -2351,6 +2453,43 @@
         "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0"
       }
     },
+    "node_modules/@graphql-yoga/logger": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/@graphql-yoga/logger/-/logger-1.0.0.tgz",
+      "integrity": "sha512-JYoxwnPggH2BfO+dWlWZkDeFhyFZqaTRGLvFhy+Pjp2UxitEW6nDrw+pEDw/K9tJwMjIFMmTT9VfTqrnESmBHg==",
+      "dependencies": {
+        "tslib": "^2.5.2"
+      },
+      "engines": {
+        "node": ">=16.0.0"
+      }
+    },
+    "node_modules/@graphql-yoga/subscription": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/@graphql-yoga/subscription/-/subscription-4.0.0.tgz",
+      "integrity": "sha512-0qsN/BPPZNMoC2CZ8i+P6PgiJyHh1H35aKDt37qARBDaIOKDQuvEOq7+4txUKElcmXi7DYFo109FkhSQoEajrg==",
+      "dependencies": {
+        "@graphql-yoga/typed-event-target": "^2.0.0",
+        "@repeaterjs/repeater": "^3.0.4",
+        "@whatwg-node/events": "^0.1.0",
+        "tslib": "^2.5.2"
+      },
+      "engines": {
+        "node": ">=16.0.0"
+      }
+    },
+    "node_modules/@graphql-yoga/typed-event-target": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/@graphql-yoga/typed-event-target/-/typed-event-target-2.0.0.tgz",
+      "integrity": "sha512-oA/VGxGmaSDym1glOHrltw43qZsFwLLjBwvh57B79UKX/vo3+UQcRgOyE44c5RP7DCYjkrC2tuArZmb6jCzysw==",
+      "dependencies": {
+        "@repeaterjs/repeater": "^3.0.4",
+        "tslib": "^2.5.2"
+      },
+      "engines": {
+        "node": ">=16.0.0"
+      }
+    },
     "node_modules/@humanwhocodes/config-array": {
       "version": "0.11.10",
       "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz",
@@ -2598,6 +2737,32 @@
         "react-dom": ">=16.8.0"
       }
     },
+    "node_modules/@mantine/dates": {
+      "version": "5.10.5",
+      "resolved": "https://registry.npmjs.org/@mantine/dates/-/dates-5.10.5.tgz",
+      "integrity": "sha512-l7lSgDKEV+phTgUAHIkc/22Qgq+WBg0P7JS2WpeZeERX8eyD4BGlsY3ZWqHigYxhBq/Ycd2tHZFmwl2p+694Zw==",
+      "dependencies": {
+        "@mantine/utils": "5.10.5"
+      },
+      "peerDependencies": {
+        "@mantine/core": "5.10.5",
+        "@mantine/hooks": "5.10.5",
+        "dayjs": ">=1.0.0",
+        "react": ">=16.8.0"
+      }
+    },
+    "node_modules/@mantine/form": {
+      "version": "6.0.20",
+      "resolved": "https://registry.npmjs.org/@mantine/form/-/form-6.0.20.tgz",
+      "integrity": "sha512-htwFVfo60nYEMNwuBiYyJpqArwNnXIU7H70l8lZ+ie9QWERZCHgS7JVUBwFpS3n3iYArKbFBG13PnQAzPHMg2w==",
+      "dependencies": {
+        "fast-deep-equal": "^3.1.3",
+        "klona": "^2.0.5"
+      },
+      "peerDependencies": {
+        "react": ">=16.8.0"
+      }
+    },
     "node_modules/@mantine/hooks": {
       "version": "5.10.5",
       "resolved": "https://registry.npmjs.org/@mantine/hooks/-/hooks-5.10.5.tgz",
@@ -2640,6 +2805,22 @@
       "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.9.tgz",
       "integrity": "sha512-rpw6JPxK6Rfg1zLOYCSwle2GFOOsnjmDYDaBwEcwoOg4qlsIVCN789VkBZDJAGi4T07gI4YSutR43t9Zz4Lzuw=="
     },
+    "node_modules/@mantine/tiptap": {
+      "version": "5.10.5",
+      "resolved": "https://registry.npmjs.org/@mantine/tiptap/-/tiptap-5.10.5.tgz",
+      "integrity": "sha512-ia8Oji18LfFO7x3sBBFR3FFMbWTHstTHnuZQvOS4Kkwi9KJLFDY5m+az0EVP548fthTK6yBHM1v/Hq1md1+D9w==",
+      "dependencies": {
+        "@mantine/utils": "5.10.5"
+      },
+      "peerDependencies": {
+        "@mantine/core": "5.10.5",
+        "@mantine/hooks": "5.10.5",
+        "@tabler/icons": "^1.119.0",
+        "@tiptap/extension-link": "^2.0.0-beta.202",
+        "@tiptap/react": "^2.0.0-beta.202",
+        "react": ">=16.8.0"
+      }
+    },
     "node_modules/@mantine/utils": {
       "version": "5.10.5",
       "resolved": "https://registry.npmjs.org/@mantine/utils/-/utils-5.10.5.tgz",
@@ -2935,6 +3116,45 @@
         "url": "https://github.com/sponsors/panva"
       }
     },
+    "node_modules/@petamoriken/float16": {
+      "version": "3.8.3",
+      "resolved": "https://registry.npmjs.org/@petamoriken/float16/-/float16-3.8.3.tgz",
+      "integrity": "sha512-an2OZ7/6er9Jja8EDUvU/tmtGIutdlb6LwXOwgjzoCjDRAsUd8sRZMBjoPEy78Xa9iOp+Kglk2CHgVwZuZbWbw=="
+    },
+    "node_modules/@popperjs/core": {
+      "version": "2.11.8",
+      "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
+      "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/popperjs"
+      }
+    },
+    "node_modules/@prisma/client": {
+      "version": "5.3.1",
+      "resolved": "https://registry.npmjs.org/@prisma/client/-/client-5.3.1.tgz",
+      "integrity": "sha512-ArOKjHwdFZIe1cGU56oIfy7wRuTn0FfZjGuU/AjgEBOQh+4rDkB6nF+AGHP8KaVpkBIiHGPQh3IpwQ3xDMdO0Q==",
+      "hasInstallScript": true,
+      "dependencies": {
+        "@prisma/engines-version": "5.3.1-2.61e140623197a131c2a6189271ffee05a7aa9a59"
+      },
+      "engines": {
+        "node": ">=16.13"
+      },
+      "peerDependencies": {
+        "prisma": "*"
+      },
+      "peerDependenciesMeta": {
+        "prisma": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@prisma/engines-version": {
+      "version": "5.3.1-2.61e140623197a131c2a6189271ffee05a7aa9a59",
+      "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-5.3.1-2.61e140623197a131c2a6189271ffee05a7aa9a59.tgz",
+      "integrity": "sha512-y5qbUi3ql2Xg7XraqcXEdMHh0MocBfnBzDn5GbV1xk23S3Mq8MGs+VjacTNiBh3dtEdUERCrUUG7Z3QaJ+h79w=="
+    },
     "node_modules/@radix-ui/number": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.0.0.tgz",
@@ -3066,6 +3286,59 @@
         "react": "^16.8 || ^17.0 || ^18.0"
       }
     },
+    "node_modules/@remirror/core-constants": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/@remirror/core-constants/-/core-constants-2.0.2.tgz",
+      "integrity": "sha512-dyHY+sMF0ihPus3O27ODd4+agdHMEmuRdyiZJ2CCWjPV5UFmn17ZbElvk6WOGVE4rdCJKZQCrPV2BcikOMLUGQ==",
+      "peer": true
+    },
+    "node_modules/@remirror/core-helpers": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/@remirror/core-helpers/-/core-helpers-3.0.0.tgz",
+      "integrity": "sha512-tusEgQJIqg4qKj6HSBUFcyRnWnziw3neh4T9wOmsPGHFC3w9kl5KSrDb9UAgE8uX6y32FnS7vJ955mWOl3n50A==",
+      "peer": true,
+      "dependencies": {
+        "@remirror/core-constants": "^2.0.2",
+        "@remirror/types": "^1.0.1",
+        "@types/object.omit": "^3.0.0",
+        "@types/object.pick": "^1.3.2",
+        "@types/throttle-debounce": "^2.1.0",
+        "case-anything": "^2.1.13",
+        "dash-get": "^1.0.2",
+        "deepmerge": "^4.3.1",
+        "fast-deep-equal": "^3.1.3",
+        "make-error": "^1.3.6",
+        "object.omit": "^3.0.0",
+        "object.pick": "^1.3.0",
+        "throttle-debounce": "^3.0.1"
+      }
+    },
+    "node_modules/@remirror/types": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/@remirror/types/-/types-1.0.1.tgz",
+      "integrity": "sha512-VlZQxwGnt1jtQ18D6JqdIF+uFZo525WEqrfp9BOc3COPpK4+AWCgdnAWL+ho6imWcoINlGjR/+3b6y5C1vBVEA==",
+      "peer": true,
+      "dependencies": {
+        "type-fest": "^2.19.0"
+      }
+    },
+    "node_modules/@remirror/types/node_modules/type-fest": {
+      "version": "2.19.0",
+      "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz",
+      "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==",
+      "peer": true,
+      "engines": {
+        "node": ">=12.20"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/@repeaterjs/repeater": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/@repeaterjs/repeater/-/repeater-3.0.4.tgz",
+      "integrity": "sha512-AW8PKd6iX3vAZ0vA43nOUOnbq/X5ihgU+mSXXqunMkeQADGiqw/PY0JNeYtD5sr0PAy51YPgAPbDoeapv9r8WA=="
+    },
     "node_modules/@rushstack/eslint-patch": {
       "version": "1.3.3",
       "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.3.3.tgz",
@@ -4252,6 +4525,401 @@
         "tslib": "^2.4.0"
       }
     },
+    "node_modules/@tabler/icons": {
+      "version": "1.119.0",
+      "resolved": "https://registry.npmjs.org/@tabler/icons/-/icons-1.119.0.tgz",
+      "integrity": "sha512-Fk3Qq4w2SXcTjc/n1cuL5bccPkylrOMo7cYpQIf/yw6zP76LQV9dtLcHQUjFiUnaYuswR645CnURIhlafyAh9g==",
+      "peer": true,
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/codecalm"
+      },
+      "peerDependencies": {
+        "react": "^16.x || 17.x || 18.x",
+        "react-dom": "^16.x || 17.x || 18.x"
+      },
+      "peerDependenciesMeta": {
+        "react": {
+          "optional": true
+        },
+        "react-dom": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@tiptap/core": {
+      "version": "2.1.10",
+      "resolved": "https://registry.npmjs.org/@tiptap/core/-/core-2.1.10.tgz",
+      "integrity": "sha512-yhUKsac6nlqbPQfwQnp+4Jb110EqmzocXKoZacLwzHpM7JVsr2+LXMDu9kahtrvHNJErJljhnQvDHRsrrYeJkQ==",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/pm": "^2.0.0"
+      }
+    },
+    "node_modules/@tiptap/extension-blockquote": {
+      "version": "2.1.10",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-blockquote/-/extension-blockquote-2.1.10.tgz",
+      "integrity": "sha512-lpBF/a+qgv4Bdf7HYisTkMFdFdGfn2SqspsydvG8UI7N9B/PfnCCrtoMaC3bqTaT6u8ZVxyM3Y3vnq2AxXJvBw==",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.0.0"
+      }
+    },
+    "node_modules/@tiptap/extension-bold": {
+      "version": "2.1.10",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-bold/-/extension-bold-2.1.10.tgz",
+      "integrity": "sha512-I43WCwc7pyz5vtKGj24Rjv7HN0EK5S4PlADQPBuhC1qQvfCTFvjrBB6ZmsekUMGmllW0qMOFVLSjtffpckqshA==",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.0.0"
+      }
+    },
+    "node_modules/@tiptap/extension-bubble-menu": {
+      "version": "2.1.10",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-bubble-menu/-/extension-bubble-menu-2.1.10.tgz",
+      "integrity": "sha512-XxgJajXkfAj/fChXkIwKBs7/3pd7OxV1uGc6Opx1qW/nSRYx/rr97654Sx/sg6auwIlbpRoqTmyqjbykGX1/yA==",
+      "dependencies": {
+        "tippy.js": "^6.3.7"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.0.0",
+        "@tiptap/pm": "^2.0.0"
+      }
+    },
+    "node_modules/@tiptap/extension-bullet-list": {
+      "version": "2.1.10",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-bullet-list/-/extension-bullet-list-2.1.10.tgz",
+      "integrity": "sha512-e6aFr29OSOmXsjFZB2zt3p8aeCWOx0C9Ayrpdf4QBUCOUJtt6FQPxxiYc+XZcdrYbLGLznA7QJlulCK9SGv2Fw==",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.0.0"
+      }
+    },
+    "node_modules/@tiptap/extension-code": {
+      "version": "2.1.10",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-code/-/extension-code-2.1.10.tgz",
+      "integrity": "sha512-1yy/kR0FAeMkDdAt1LW/FH6vlyZLqLZqY6BM+wBCiGrr+XeA5FTXih9iT/4gbTRuIzG0EPqx18nvroG7hUsWBg==",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.0.0"
+      }
+    },
+    "node_modules/@tiptap/extension-code-block": {
+      "version": "2.1.10",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-code-block/-/extension-code-block-2.1.10.tgz",
+      "integrity": "sha512-M+s89V9mP3tOoS6p/X2Dzw/Z7Fcg9EF0ZXlsMNifdlpwJlhAIYxI7vjPBmkMAFXTDB5eMZblXyNQaZ7v6V2Yeg==",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.0.0",
+        "@tiptap/pm": "^2.0.0"
+      }
+    },
+    "node_modules/@tiptap/extension-document": {
+      "version": "2.1.10",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-document/-/extension-document-2.1.10.tgz",
+      "integrity": "sha512-jNlNGQIGg471DvzhADaEoRINa3LNghowrBbKK9d5wGVnbKRykNEPwjCf8zNl+m5NBmCZl3lsdznlwBk5zyh5Bg==",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.0.0"
+      }
+    },
+    "node_modules/@tiptap/extension-dropcursor": {
+      "version": "2.1.10",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-dropcursor/-/extension-dropcursor-2.1.10.tgz",
+      "integrity": "sha512-GhsWsCq6wLb8HJ32BeAm7ndv4lPyu1F7FFwmnARzEF5q54FV20kWSv2zC+Dv0dTvynXR3quXybdUM92xeNDovw==",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.0.0",
+        "@tiptap/pm": "^2.0.0"
+      }
+    },
+    "node_modules/@tiptap/extension-floating-menu": {
+      "version": "2.1.10",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-floating-menu/-/extension-floating-menu-2.1.10.tgz",
+      "integrity": "sha512-uChrDrY3usnF9wSegqq+YGaqd229p9gmaB5xyOyMERDs972hKj4Ul95rXzBBiMKAWUMw9eM09i7+ijTzz4KDUw==",
+      "dependencies": {
+        "tippy.js": "^6.3.7"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.0.0",
+        "@tiptap/pm": "^2.0.0"
+      }
+    },
+    "node_modules/@tiptap/extension-gapcursor": {
+      "version": "2.1.10",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-gapcursor/-/extension-gapcursor-2.1.10.tgz",
+      "integrity": "sha512-WSBT9X7dzg0HyMoMP/Yyxl28QwIJO90YzobI9z5mav86BQv7C5wU0fQSpbpAbsN3s7lxKhPwNrXkwkpnXT4ZCA==",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.0.0",
+        "@tiptap/pm": "^2.0.0"
+      }
+    },
+    "node_modules/@tiptap/extension-hard-break": {
+      "version": "2.1.10",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-hard-break/-/extension-hard-break-2.1.10.tgz",
+      "integrity": "sha512-sYrzpPoV5jQri+duGb50nDTs+hOBQDxXTKlJuZNFfZMwgx6epwxb8xICcGAUJFShuuW8UAWCNcB4jG9tMqgvyw==",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.0.0"
+      }
+    },
+    "node_modules/@tiptap/extension-heading": {
+      "version": "2.1.10",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-heading/-/extension-heading-2.1.10.tgz",
+      "integrity": "sha512-1OgmrRPMcY52WI7I4799xd4eIsEX/bI813B8mZvNYXLzZI75pLW1hmz1mUvBYyMwlcek74zVTGYgPy11o+2JEg==",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.0.0"
+      }
+    },
+    "node_modules/@tiptap/extension-history": {
+      "version": "2.1.10",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-history/-/extension-history-2.1.10.tgz",
+      "integrity": "sha512-tApuN8MIJMzc0dxvkYJPt3t5cea9NuZBGNiuVedJwMMUF6hbFpMZAt20GW2qwjBaZ76rQwbLp1s3KnImFsPe5A==",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.0.0",
+        "@tiptap/pm": "^2.0.0"
+      }
+    },
+    "node_modules/@tiptap/extension-horizontal-rule": {
+      "version": "2.1.10",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-2.1.10.tgz",
+      "integrity": "sha512-91lGpK2d6WMPhrMDPBURS8z8pEg1CUBYy7GmBenKvvgh+JzVhG+U6MtykfWNfm2R4iRXOl1xLbyUOCiOSUXodQ==",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.0.0",
+        "@tiptap/pm": "^2.0.0"
+      }
+    },
+    "node_modules/@tiptap/extension-italic": {
+      "version": "2.1.10",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-italic/-/extension-italic-2.1.10.tgz",
+      "integrity": "sha512-ebw5m+rWx6K5UoBVXSkz3fpvDJh/wScfYmwl6pkbjc2jNbZiln2LSiLHYc2eIYJ2aTsVxcw/n0Azfk5Lb19InA==",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.0.0"
+      }
+    },
+    "node_modules/@tiptap/extension-link": {
+      "version": "2.1.10",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-link/-/extension-link-2.1.10.tgz",
+      "integrity": "sha512-dXxPTWzJzpbDRAewM4P8jN/n9h8uUH83lOLwweuODYCqHRdjQL/uGkQworFFrgqmRHs+9JjHZ4DETILZVawJ+Q==",
+      "peer": true,
+      "dependencies": {
+        "linkifyjs": "^4.1.0"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.0.0",
+        "@tiptap/pm": "^2.0.0"
+      }
+    },
+    "node_modules/@tiptap/extension-list-item": {
+      "version": "2.1.10",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-list-item/-/extension-list-item-2.1.10.tgz",
+      "integrity": "sha512-rRRyB14vOcSjTMAh8Y+50TRC/jO469CelGwFjOLrK1ZSEag5wmLDaqpWOOb52BFYnvCHuIm1HqZtdL5bTI/J1w==",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.0.0"
+      }
+    },
+    "node_modules/@tiptap/extension-ordered-list": {
+      "version": "2.1.10",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-ordered-list/-/extension-ordered-list-2.1.10.tgz",
+      "integrity": "sha512-jouo3RHUMxU4dPzZcfZdUzmsLVp1KHrLIAD2YAxBuqArACrBNfJpIhtkTKuGLlaFhKqGr+EmNdNQnK8JOBhLtQ==",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.0.0"
+      }
+    },
+    "node_modules/@tiptap/extension-paragraph": {
+      "version": "2.1.10",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-paragraph/-/extension-paragraph-2.1.10.tgz",
+      "integrity": "sha512-kzuHbrxcxpWkha5P+JFzCKT54pNqb4IBKMU5qT9YGhZSdNTtU63ncdCHM+Ad1ukLuvXAv95zh1IQC5j+Z1Qk4A==",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.0.0"
+      }
+    },
+    "node_modules/@tiptap/extension-strike": {
+      "version": "2.1.10",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-strike/-/extension-strike-2.1.10.tgz",
+      "integrity": "sha512-KW63lZLPFIir5AIeh2I7UK6Tx1O3jetD7JIPUzEqp1I1BfJlHGHVQxV8VXAmJl0hTOzjQBsHW42PmBxSC97NUg==",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.0.0"
+      }
+    },
+    "node_modules/@tiptap/extension-text": {
+      "version": "2.1.10",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-text/-/extension-text-2.1.10.tgz",
+      "integrity": "sha512-ubU/WQwNB0MVKyMAHr8ka3Nu3jCR03HARGKUwNRzppZYtRXWyXHNlAaJdplNb1NMGb8hd0ElBJmwFlVqmh8haQ==",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.0.0"
+      }
+    },
+    "node_modules/@tiptap/extension-underline": {
+      "version": "2.1.10",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-underline/-/extension-underline-2.1.10.tgz",
+      "integrity": "sha512-f+rJKviGNqORGv4/1pTLZuVTb9VsKMZMLucL8423M6s8TdrH//sBB8QeU92JSnO9PjAGwxWjS1f23/KtufxP8g==",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.0.0"
+      }
+    },
+    "node_modules/@tiptap/pm": {
+      "version": "2.1.10",
+      "resolved": "https://registry.npmjs.org/@tiptap/pm/-/pm-2.1.10.tgz",
+      "integrity": "sha512-Y+AqizKnjQpx4pSaA6m/cCD5QHQRPtALhO4ZO4YFZV1idYmsJA3/S5lgJI3ZL5eAHKHcGk6Vv3/8Y+eej5YIPw==",
+      "peer": true,
+      "dependencies": {
+        "prosemirror-changeset": "^2.2.0",
+        "prosemirror-collab": "^1.3.0",
+        "prosemirror-commands": "^1.3.1",
+        "prosemirror-dropcursor": "^1.5.0",
+        "prosemirror-gapcursor": "^1.3.1",
+        "prosemirror-history": "^1.3.0",
+        "prosemirror-inputrules": "^1.2.0",
+        "prosemirror-keymap": "^1.2.0",
+        "prosemirror-markdown": "^1.10.1",
+        "prosemirror-menu": "^1.2.1",
+        "prosemirror-model": "^1.18.1",
+        "prosemirror-schema-basic": "^1.2.0",
+        "prosemirror-schema-list": "^1.2.2",
+        "prosemirror-state": "^1.4.1",
+        "prosemirror-tables": "^1.3.0",
+        "prosemirror-trailing-node": "^2.0.2",
+        "prosemirror-transform": "^1.7.0",
+        "prosemirror-view": "^1.28.2"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      }
+    },
+    "node_modules/@tiptap/react": {
+      "version": "2.1.10",
+      "resolved": "https://registry.npmjs.org/@tiptap/react/-/react-2.1.10.tgz",
+      "integrity": "sha512-kzCWzbV2dnD5NmHjN8GiS+k0GOmoEhKnMuMzuuU6FjtOALhJzPTrIXITzWDpU3jL+r/4eeXYhAt64Wp7PVwscg==",
+      "dependencies": {
+        "@tiptap/extension-bubble-menu": "^2.1.10",
+        "@tiptap/extension-floating-menu": "^2.1.10"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      },
+      "peerDependencies": {
+        "@tiptap/core": "^2.0.0",
+        "@tiptap/pm": "^2.0.0",
+        "react": "^17.0.0 || ^18.0.0",
+        "react-dom": "^17.0.0 || ^18.0.0"
+      }
+    },
+    "node_modules/@tiptap/starter-kit": {
+      "version": "2.1.10",
+      "resolved": "https://registry.npmjs.org/@tiptap/starter-kit/-/starter-kit-2.1.10.tgz",
+      "integrity": "sha512-h5mH1qv7SDFXWZPbOWC8zpGZ62EnDizRNtM45Gani0HYWJXcbPFpgN1qJmESP/jP+v+0hxtnVEkgfpiy3LRm6A==",
+      "dependencies": {
+        "@tiptap/core": "^2.1.10",
+        "@tiptap/extension-blockquote": "^2.1.10",
+        "@tiptap/extension-bold": "^2.1.10",
+        "@tiptap/extension-bullet-list": "^2.1.10",
+        "@tiptap/extension-code": "^2.1.10",
+        "@tiptap/extension-code-block": "^2.1.10",
+        "@tiptap/extension-document": "^2.1.10",
+        "@tiptap/extension-dropcursor": "^2.1.10",
+        "@tiptap/extension-gapcursor": "^2.1.10",
+        "@tiptap/extension-hard-break": "^2.1.10",
+        "@tiptap/extension-heading": "^2.1.10",
+        "@tiptap/extension-history": "^2.1.10",
+        "@tiptap/extension-horizontal-rule": "^2.1.10",
+        "@tiptap/extension-italic": "^2.1.10",
+        "@tiptap/extension-list-item": "^2.1.10",
+        "@tiptap/extension-ordered-list": "^2.1.10",
+        "@tiptap/extension-paragraph": "^2.1.10",
+        "@tiptap/extension-strike": "^2.1.10",
+        "@tiptap/extension-text": "^2.1.10"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/ueberdosis"
+      }
+    },
     "node_modules/@types/eslint": {
       "version": "8.44.2",
       "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.44.2.tgz",
@@ -4362,6 +5030,18 @@
       "resolved": "https://registry.npmjs.org/@types/npmlog/-/npmlog-4.1.4.tgz",
       "integrity": "sha512-WKG4gTr8przEZBiJ5r3s8ZIAoMXNbOgQ+j/d5O4X3x6kZJRLNvyUJuUK/KoG3+8BaOHPhp2m7WC6JKKeovDSzQ=="
     },
+    "node_modules/@types/object.omit": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/@types/object.omit/-/object.omit-3.0.1.tgz",
+      "integrity": "sha512-24XD34UeRWw505TsMNBrQ4bES2s8IxiFC59mmNUFhTz9IX2hAtA7gQ8wVww1i17QmhBYILg5iqYP2y7aqA3pwQ==",
+      "peer": true
+    },
+    "node_modules/@types/object.pick": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/@types/object.pick/-/object.pick-1.3.2.tgz",
+      "integrity": "sha512-sn7L+qQ6RLPdXRoiaE7bZ/Ek+o4uICma/lBFPyJEKDTPTBP1W8u0c4baj3EiS4DiqLs+Hk+KUGvMVJtAw3ePJg==",
+      "peer": true
+    },
     "node_modules/@types/parse-json": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz",
@@ -4397,6 +5077,12 @@
       "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz",
       "integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ=="
     },
+    "node_modules/@types/throttle-debounce": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/@types/throttle-debounce/-/throttle-debounce-2.1.0.tgz",
+      "integrity": "sha512-5eQEtSCoESnh2FsiLTxE121IiE60hnMqcb435fShf4bpLRjEu1Eoekht23y6zXS9Ts3l+Szu3TARnTsA0GkOkQ==",
+      "peer": true
+    },
     "node_modules/@types/unist": {
       "version": "2.0.7",
       "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.7.tgz",
@@ -4762,6 +5448,53 @@
         "@xtuc/long": "4.2.2"
       }
     },
+    "node_modules/@whatwg-node/events": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/@whatwg-node/events/-/events-0.1.1.tgz",
+      "integrity": "sha512-AyQEn5hIPV7Ze+xFoXVU3QTHXVbWPrzaOkxtENMPMuNL6VVHrp4hHfDt9nrQpjO7BgvuM95dMtkycX5M/DZR3w==",
+      "engines": {
+        "node": ">=16.0.0"
+      }
+    },
+    "node_modules/@whatwg-node/fetch": {
+      "version": "0.9.13",
+      "resolved": "https://registry.npmjs.org/@whatwg-node/fetch/-/fetch-0.9.13.tgz",
+      "integrity": "sha512-PPtMwhjtS96XROnSpowCQM85gCUG2m7AXZFw0PZlGbhzx2GK7f2iOXilfgIJ0uSlCuuGbOIzfouISkA7C4FJOw==",
+      "dependencies": {
+        "@whatwg-node/node-fetch": "^0.4.17",
+        "urlpattern-polyfill": "^9.0.0"
+      },
+      "engines": {
+        "node": ">=16.0.0"
+      }
+    },
+    "node_modules/@whatwg-node/node-fetch": {
+      "version": "0.4.18",
+      "resolved": "https://registry.npmjs.org/@whatwg-node/node-fetch/-/node-fetch-0.4.18.tgz",
+      "integrity": "sha512-zdey6buMKCqDVDq+tMqcjopO75Fb6iLqWo+g6cWwN5kiwctEHtVcbws2lJUFhCbo+TLZeH6bMDRUXEo5bkPtcQ==",
+      "dependencies": {
+        "@whatwg-node/events": "^0.1.0",
+        "busboy": "^1.6.0",
+        "fast-querystring": "^1.1.1",
+        "fast-url-parser": "^1.1.3",
+        "tslib": "^2.3.1"
+      },
+      "engines": {
+        "node": ">=16.0.0"
+      }
+    },
+    "node_modules/@whatwg-node/server": {
+      "version": "0.9.14",
+      "resolved": "https://registry.npmjs.org/@whatwg-node/server/-/server-0.9.14.tgz",
+      "integrity": "sha512-I8TT0NoCP+xThLBuGlU6dgq5wpExkphNMo2geZwQW0vAmEPtc3MNMZMIYqg5GyNmpv5Nf7fnxb8tVOIHbDvuDA==",
+      "dependencies": {
+        "@whatwg-node/fetch": "^0.9.10",
+        "tslib": "^2.3.1"
+      },
+      "engines": {
+        "node": ">=16.0.0"
+      }
+    },
     "node_modules/@wry/context": {
       "version": "0.7.3",
       "resolved": "https://registry.npmjs.org/@wry/context/-/context-0.7.3.tgz",
@@ -4845,6 +5578,15 @@
         "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
       }
     },
+    "node_modules/adblock-hunter": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/adblock-hunter/-/adblock-hunter-1.0.1.tgz",
+      "integrity": "sha512-BEhm3l2rYGs6WCZB+T7D+Je5rqp7WKOAqN8UMOmQZJSqR93IcU1aHaJ4vn6RMwLiRmc4fVkKc+clisPGcOQurA==",
+      "funding": {
+        "type": "individual",
+        "url": "https://ko-fi.com/andriir"
+      }
+    },
     "node_modules/ajv": {
       "version": "6.12.6",
       "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
@@ -5199,6 +5941,11 @@
         "has-symbols": "^1.0.3"
       }
     },
+    "node_modules/asynckit": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+      "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
+    },
     "node_modules/at-least-node": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz",
@@ -5237,6 +5984,16 @@
         "node": ">=4"
       }
     },
+    "node_modules/axios": {
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/axios/-/axios-1.5.0.tgz",
+      "integrity": "sha512-D4DdjDo5CY50Qms0qGQTTw6Q44jl7zRwY7bthds06pUGfChBCTcQs+N743eFWGEd6pRTMd6A+I87aWyFV5wiZQ==",
+      "dependencies": {
+        "follow-redirects": "^1.15.0",
+        "form-data": "^4.0.0",
+        "proxy-from-env": "^1.1.0"
+      }
+    },
     "node_modules/axobject-query": {
       "version": "3.2.1",
       "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.2.1.tgz",
@@ -5971,6 +6728,18 @@
         "node": "6.* || 8.* || >= 10.*"
       }
     },
+    "node_modules/case-anything": {
+      "version": "2.1.13",
+      "resolved": "https://registry.npmjs.org/case-anything/-/case-anything-2.1.13.tgz",
+      "integrity": "sha512-zlOQ80VrQ2Ue+ymH5OuM/DlDq64mEm+B9UTdHULv5osUMD6HalNTblf2b1u/m6QecjsnOkBpqVZ+XPwIVsy7Ng==",
+      "peer": true,
+      "engines": {
+        "node": ">=12.13"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/mesqueeb"
+      }
+    },
     "node_modules/ccount": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/ccount/-/ccount-1.1.0.tgz",
@@ -6273,6 +7042,17 @@
         "color-support": "bin.js"
       }
     },
+    "node_modules/combined-stream": {
+      "version": "1.0.8",
+      "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
+      "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+      "dependencies": {
+        "delayed-stream": "~1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
     "node_modules/comma-separated-tokens": {
       "version": "1.0.8",
       "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz",
@@ -6518,6 +7298,12 @@
         "sha.js": "^2.4.8"
       }
     },
+    "node_modules/crelt": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz",
+      "integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==",
+      "peer": true
+    },
     "node_modules/cross-spawn": {
       "version": "7.0.3",
       "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
@@ -6567,6 +7353,18 @@
       "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz",
       "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA=="
     },
+    "node_modules/dash-get": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/dash-get/-/dash-get-1.0.2.tgz",
+      "integrity": "sha512-4FbVrHDwfOASx7uQVxeiCTo7ggSdYZbqs8lH+WU6ViypPlDbe9y6IP5VVUDQBv9DcnyaiPT5XT0UWHgJ64zLeQ==",
+      "peer": true
+    },
+    "node_modules/dayjs": {
+      "version": "1.11.9",
+      "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.9.tgz",
+      "integrity": "sha512-QvzAURSbQ0pKdIye2txOzNaHmxtUBXerpY0FJsFXUMKbIZeFm5ht1LS/jFsrncjnmtv8HsG0W2g6c0zUjZWmpA==",
+      "peer": true
+    },
     "node_modules/debug": {
       "version": "4.3.4",
       "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
@@ -6653,6 +7451,14 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/delayed-stream": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+      "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
     "node_modules/delegates": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
@@ -6847,6 +7653,14 @@
       "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz",
       "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA=="
     },
+    "node_modules/dset": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/dset/-/dset-3.1.2.tgz",
+      "integrity": "sha512-g/M9sqy3oHe477Ar4voQxWtaPIFw1jTdKZuomOjhCcBx9nHUNn0pu6NopuFFrTh/TRZIKEj+76vLWFu9BNKk+Q==",
+      "engines": {
+        "node": ">=4"
+      }
+    },
     "node_modules/duplexify": {
       "version": "3.7.1",
       "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz",
@@ -6890,6 +7704,11 @@
         "safe-buffer": "~5.1.0"
       }
     },
+    "node_modules/earcut": {
+      "version": "2.2.4",
+      "resolved": "https://registry.npmjs.org/earcut/-/earcut-2.2.4.tgz",
+      "integrity": "sha512-/pjZsA1b4RPHbeWZQn66SWS8nZZWLQQ23oE3Eam7aroEFGEvwKAsJfZ9ytiEMycfzXWpca4FA9QIOehf7PocBQ=="
+    },
     "node_modules/ecdsa-sig-formatter": {
       "version": "1.0.11",
       "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
@@ -7919,6 +8738,11 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/fast-decode-uri-component": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/fast-decode-uri-component/-/fast-decode-uri-component-1.0.1.tgz",
+      "integrity": "sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg=="
+    },
     "node_modules/fast-deep-equal": {
       "version": "3.1.3",
       "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
@@ -7960,10 +8784,31 @@
       "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
       "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="
     },
-    "node_modules/fast-levenshtein": {
-      "version": "2.0.6",
-      "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
-      "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="
+    "node_modules/fast-levenshtein": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+      "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="
+    },
+    "node_modules/fast-querystring": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/fast-querystring/-/fast-querystring-1.1.2.tgz",
+      "integrity": "sha512-g6KuKWmFXc0fID8WWH0jit4g0AGBoJhCkJMb1RmbsSEUNvQ+ZC8D6CUZ+GtF8nMzSPXnhiePyyqqipzNNEnHjg==",
+      "dependencies": {
+        "fast-decode-uri-component": "^1.0.1"
+      }
+    },
+    "node_modules/fast-url-parser": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/fast-url-parser/-/fast-url-parser-1.1.3.tgz",
+      "integrity": "sha512-5jOCVXADYNuRkKFzNJ0dCCewsZiYo0dz8QNYljkOpFC6r2U4OBmKtvm/Tsuh4w1YYdDqDb31a8TVhBJ2OJKdqQ==",
+      "dependencies": {
+        "punycode": "^1.3.2"
+      }
+    },
+    "node_modules/fast-url-parser/node_modules/punycode": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
+      "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ=="
     },
     "node_modules/fastq": {
       "version": "1.15.0",
@@ -8225,6 +9070,25 @@
         "safe-buffer": "~5.1.0"
       }
     },
+    "node_modules/follow-redirects": {
+      "version": "1.15.2",
+      "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
+      "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://github.com/sponsors/RubenVerborgh"
+        }
+      ],
+      "engines": {
+        "node": ">=4.0"
+      },
+      "peerDependenciesMeta": {
+        "debug": {
+          "optional": true
+        }
+      }
+    },
     "node_modules/for-each": {
       "version": "0.3.3",
       "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
@@ -8319,6 +9183,19 @@
         "node": ">=6"
       }
     },
+    "node_modules/form-data": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
+      "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
+      "dependencies": {
+        "asynckit": "^0.4.0",
+        "combined-stream": "^1.0.8",
+        "mime-types": "^2.1.12"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
     "node_modules/forwarded": {
       "version": "0.2.0",
       "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
@@ -8529,6 +9406,28 @@
         "node": ">=6.9.0"
       }
     },
+    "node_modules/geotiff": {
+      "version": "2.0.7",
+      "resolved": "https://registry.npmjs.org/geotiff/-/geotiff-2.0.7.tgz",
+      "integrity": "sha512-FKvFTNowMU5K6lHYY2f83d4lS2rsCNdpUC28AX61x9ZzzqPNaWFElWv93xj0eJFaNyOYA63ic5OzJ88dHpoA5Q==",
+      "dependencies": {
+        "@petamoriken/float16": "^3.4.7",
+        "lerc": "^3.0.0",
+        "pako": "^2.0.4",
+        "parse-headers": "^2.0.2",
+        "quick-lru": "^6.1.1",
+        "web-worker": "^1.2.0",
+        "xml-utils": "^1.0.2"
+      },
+      "engines": {
+        "node": ">=10.19"
+      }
+    },
+    "node_modules/geotiff/node_modules/pako": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz",
+      "integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug=="
+    },
     "node_modules/get-intrinsic": {
       "version": "1.2.1",
       "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz",
@@ -8727,6 +9626,20 @@
         "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0"
       }
     },
+    "node_modules/graphql-scalars": {
+      "version": "1.22.2",
+      "resolved": "https://registry.npmjs.org/graphql-scalars/-/graphql-scalars-1.22.2.tgz",
+      "integrity": "sha512-my9FB4GtghqXqi/lWSVAOPiTzTnnEzdOXCsAC2bb5V7EFNQjVjwy3cSSbUvgYOtDuDibd+ZsCDhz+4eykYOlhQ==",
+      "dependencies": {
+        "tslib": "^2.5.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "peerDependencies": {
+        "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0"
+      }
+    },
     "node_modules/graphql-tag": {
       "version": "2.12.6",
       "resolved": "https://registry.npmjs.org/graphql-tag/-/graphql-tag-2.12.6.tgz",
@@ -8741,6 +9654,38 @@
         "graphql": "^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0"
       }
     },
+    "node_modules/graphql-yoga": {
+      "version": "4.0.4",
+      "resolved": "https://registry.npmjs.org/graphql-yoga/-/graphql-yoga-4.0.4.tgz",
+      "integrity": "sha512-MvCLhFecYNIKuxAZisPjpIL9lxRYbpgPSNKENDO/8CV3oiFlsLJHZb5dp2sVAeLafXHeZ9TgkijLthUBc1+Jag==",
+      "dependencies": {
+        "@envelop/core": "^4.0.0",
+        "@graphql-tools/executor": "^1.0.0",
+        "@graphql-tools/schema": "^10.0.0",
+        "@graphql-tools/utils": "^10.0.0",
+        "@graphql-yoga/logger": "^1.0.0",
+        "@graphql-yoga/subscription": "^4.0.0",
+        "@whatwg-node/fetch": "^0.9.7",
+        "@whatwg-node/server": "^0.9.1",
+        "dset": "^3.1.1",
+        "lru-cache": "^10.0.0",
+        "tslib": "^2.5.2"
+      },
+      "engines": {
+        "node": ">=16.0.0"
+      },
+      "peerDependencies": {
+        "graphql": "^15.2.0 || ^16.0.0"
+      }
+    },
+    "node_modules/graphql-yoga/node_modules/lru-cache": {
+      "version": "10.0.1",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.0.1.tgz",
+      "integrity": "sha512-IJ4uwUTi2qCccrioU6g9g/5rvvVl13bsdczUUcqbciD9iLr095yj8DQKdObriEvuNSx325N1rV1O0sJFszx75g==",
+      "engines": {
+        "node": "14 || >=16.14"
+      }
+    },
     "node_modules/handlebars": {
       "version": "4.7.8",
       "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz",
@@ -10091,6 +11036,14 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/klona": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz",
+      "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==",
+      "engines": {
+        "node": ">= 8"
+      }
+    },
     "node_modules/language-subtag-registry": {
       "version": "0.3.22",
       "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz",
@@ -10121,6 +11074,11 @@
         "yarn": ">=1.0.0"
       }
     },
+    "node_modules/lerc": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/lerc/-/lerc-3.0.0.tgz",
+      "integrity": "sha512-Rm4J/WaHhRa93nCN2mwWDZFoRVF18G1f47C+kvQWyHGEZxFpTUi73p7lMVSAndyxGt6lJ2/CFbOcf9ra5p8aww=="
+    },
     "node_modules/levn": {
       "version": "0.4.1",
       "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
@@ -10138,6 +11096,21 @@
       "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
       "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="
     },
+    "node_modules/linkify-it": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-4.0.1.tgz",
+      "integrity": "sha512-C7bfi1UZmoj8+PQx22XyeXCuBlokoyWQL5pWSP+EI6nzRylyThouddufc2c1NDIcP9k5agmN9fLpA7VNJfIiqw==",
+      "peer": true,
+      "dependencies": {
+        "uc.micro": "^1.0.1"
+      }
+    },
+    "node_modules/linkifyjs": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/linkifyjs/-/linkifyjs-4.1.1.tgz",
+      "integrity": "sha512-zFN/CTVmbcVef+WaDXT63dNzzkfRBKT1j464NJQkV7iSgJU0sLBus9W0HBwnXK13/hf168pbrx/V/bjEHOXNHA==",
+      "peer": true
+    },
     "node_modules/loader-runner": {
       "version": "4.3.0",
       "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz",
@@ -10247,6 +11220,12 @@
         "semver": "bin/semver"
       }
     },
+    "node_modules/make-error": {
+      "version": "1.3.6",
+      "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
+      "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
+      "peer": true
+    },
     "node_modules/makeerror": {
       "version": "1.0.12",
       "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz",
@@ -10288,6 +11267,34 @@
         "url": "https://github.com/sponsors/wooorm"
       }
     },
+    "node_modules/markdown-it": {
+      "version": "13.0.1",
+      "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-13.0.1.tgz",
+      "integrity": "sha512-lTlxriVoy2criHP0JKRhO2VDG9c2ypWCsT237eDiLqi09rmbKoUetyGHq2uOIRoRS//kfoJckS0eUzzkDR+k2Q==",
+      "peer": true,
+      "dependencies": {
+        "argparse": "^2.0.1",
+        "entities": "~3.0.1",
+        "linkify-it": "^4.0.1",
+        "mdurl": "^1.0.1",
+        "uc.micro": "^1.0.5"
+      },
+      "bin": {
+        "markdown-it": "bin/markdown-it.js"
+      }
+    },
+    "node_modules/markdown-it/node_modules/entities": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz",
+      "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==",
+      "peer": true,
+      "engines": {
+        "node": ">=0.12"
+      },
+      "funding": {
+        "url": "https://github.com/fb55/entities?sponsor=1"
+      }
+    },
     "node_modules/md5.js": {
       "version": "1.3.5",
       "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
@@ -10911,6 +11918,14 @@
       "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz",
       "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ=="
     },
+    "node_modules/nodemailer": {
+      "version": "6.9.4",
+      "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.4.tgz",
+      "integrity": "sha512-CXjQvrQZV4+6X5wP6ZIgdehJamI63MFoYFGGPtHudWym9qaEHDNdPzaj5bfMCvxG1vhAileSWW90q7nL0N36mA==",
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
     "node_modules/normalize-path": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
@@ -11149,6 +12164,18 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/object.omit": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-3.0.0.tgz",
+      "integrity": "sha512-EO+BCv6LJfu+gBIF3ggLicFebFLN5zqzz/WWJlMFfkMyGth+oBkhxzDl0wx2W4GkLzuQs/FsSkXZb2IMWQqmBQ==",
+      "peer": true,
+      "dependencies": {
+        "is-extendable": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
     "node_modules/object.pick": {
       "version": "1.3.0",
       "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz",
@@ -11184,6 +12211,21 @@
         "node": "^10.13.0 || >=12.0.0"
       }
     },
+    "node_modules/ol": {
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/ol/-/ol-8.0.0.tgz",
+      "integrity": "sha512-tWDVFlt4ylZJeByD/Q5vSWPxEMoHy1tyyWT+LFDlGmGl6p9kmxtCfGAIupwUGrc5ifWsy+gDbg6QGd1Qw0y3HA==",
+      "dependencies": {
+        "earcut": "^2.2.3",
+        "geotiff": "^2.0.7",
+        "pbf": "3.2.1",
+        "rbush": "^3.0.1"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/openlayers"
+      }
+    },
     "node_modules/on-finished": {
       "version": "2.4.1",
       "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
@@ -11243,6 +12285,12 @@
         "node": ">= 0.8.0"
       }
     },
+    "node_modules/orderedmap": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/orderedmap/-/orderedmap-2.1.1.tgz",
+      "integrity": "sha512-TvAWxi0nDe1j/rtMcWcIj94+Ffe6n7zhow33h40SKxmsmozs6dz/e+EajymfoFcHd7sxNn8yHM8839uixMOV6g==",
+      "peer": true
+    },
     "node_modules/os-browserify": {
       "version": "0.3.0",
       "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz",
@@ -11379,6 +12427,11 @@
         "url": "https://github.com/sponsors/wooorm"
       }
     },
+    "node_modules/parse-headers": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.5.tgz",
+      "integrity": "sha512-ft3iAoLOB/MlwbNXgzy43SWGP6sQki2jQvAyBg/zDFAgr9bfNWZIUj42Kw2eJIl8kEi4PbgE6U1Zau/HwI75HA=="
+    },
     "node_modules/parse-json": {
       "version": "5.2.0",
       "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
@@ -11470,6 +12523,18 @@
         "node": ">=8"
       }
     },
+    "node_modules/pbf": {
+      "version": "3.2.1",
+      "resolved": "https://registry.npmjs.org/pbf/-/pbf-3.2.1.tgz",
+      "integrity": "sha512-ClrV7pNOn7rtmoQVF4TS1vyU0WhYRnP92fzbfF75jAIwpnzdJXf8iTd4CMEqO4yUenH6NDqLiwjqlh6QgZzgLQ==",
+      "dependencies": {
+        "ieee754": "^1.1.12",
+        "resolve-protobuf-schema": "^2.1.0"
+      },
+      "bin": {
+        "pbf": "bin/pbf"
+      }
+    },
     "node_modules/pbkdf2": {
       "version": "3.1.2",
       "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz",
@@ -11702,6 +12767,206 @@
         "url": "https://github.com/sponsors/wooorm"
       }
     },
+    "node_modules/prosemirror-changeset": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/prosemirror-changeset/-/prosemirror-changeset-2.2.1.tgz",
+      "integrity": "sha512-J7msc6wbxB4ekDFj+n9gTW/jav/p53kdlivvuppHsrZXCaQdVgRghoZbSS3kwrRyAstRVQ4/+u5k7YfLgkkQvQ==",
+      "peer": true,
+      "dependencies": {
+        "prosemirror-transform": "^1.0.0"
+      }
+    },
+    "node_modules/prosemirror-collab": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/prosemirror-collab/-/prosemirror-collab-1.3.1.tgz",
+      "integrity": "sha512-4SnynYR9TTYaQVXd/ieUvsVV4PDMBzrq2xPUWutHivDuOshZXqQ5rGbZM84HEaXKbLdItse7weMGOUdDVcLKEQ==",
+      "peer": true,
+      "dependencies": {
+        "prosemirror-state": "^1.0.0"
+      }
+    },
+    "node_modules/prosemirror-commands": {
+      "version": "1.5.2",
+      "resolved": "https://registry.npmjs.org/prosemirror-commands/-/prosemirror-commands-1.5.2.tgz",
+      "integrity": "sha512-hgLcPaakxH8tu6YvVAaILV2tXYsW3rAdDR8WNkeKGcgeMVQg3/TMhPdVoh7iAmfgVjZGtcOSjKiQaoeKjzd2mQ==",
+      "peer": true,
+      "dependencies": {
+        "prosemirror-model": "^1.0.0",
+        "prosemirror-state": "^1.0.0",
+        "prosemirror-transform": "^1.0.0"
+      }
+    },
+    "node_modules/prosemirror-dropcursor": {
+      "version": "1.8.1",
+      "resolved": "https://registry.npmjs.org/prosemirror-dropcursor/-/prosemirror-dropcursor-1.8.1.tgz",
+      "integrity": "sha512-M30WJdJZLyXHi3N8vxN6Zh5O8ZBbQCz0gURTfPmTIBNQ5pxrdU7A58QkNqfa98YEjSAL1HUyyU34f6Pm5xBSGw==",
+      "peer": true,
+      "dependencies": {
+        "prosemirror-state": "^1.0.0",
+        "prosemirror-transform": "^1.1.0",
+        "prosemirror-view": "^1.1.0"
+      }
+    },
+    "node_modules/prosemirror-gapcursor": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/prosemirror-gapcursor/-/prosemirror-gapcursor-1.3.2.tgz",
+      "integrity": "sha512-wtjswVBd2vaQRrnYZaBCbyDqr232Ed4p2QPtRIUK5FuqHYKGWkEwl08oQM4Tw7DOR0FsasARV5uJFvMZWxdNxQ==",
+      "peer": true,
+      "dependencies": {
+        "prosemirror-keymap": "^1.0.0",
+        "prosemirror-model": "^1.0.0",
+        "prosemirror-state": "^1.0.0",
+        "prosemirror-view": "^1.0.0"
+      }
+    },
+    "node_modules/prosemirror-history": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/prosemirror-history/-/prosemirror-history-1.3.2.tgz",
+      "integrity": "sha512-/zm0XoU/N/+u7i5zepjmZAEnpvjDtzoPWW6VmKptcAnPadN/SStsBjMImdCEbb3seiNTpveziPTIrXQbHLtU1g==",
+      "peer": true,
+      "dependencies": {
+        "prosemirror-state": "^1.2.2",
+        "prosemirror-transform": "^1.0.0",
+        "prosemirror-view": "^1.31.0",
+        "rope-sequence": "^1.3.0"
+      }
+    },
+    "node_modules/prosemirror-inputrules": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/prosemirror-inputrules/-/prosemirror-inputrules-1.2.1.tgz",
+      "integrity": "sha512-3LrWJX1+ULRh5SZvbIQlwZafOXqp1XuV21MGBu/i5xsztd+9VD15x6OtN6mdqSFI7/8Y77gYUbQ6vwwJ4mr6QQ==",
+      "peer": true,
+      "dependencies": {
+        "prosemirror-state": "^1.0.0",
+        "prosemirror-transform": "^1.0.0"
+      }
+    },
+    "node_modules/prosemirror-keymap": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/prosemirror-keymap/-/prosemirror-keymap-1.2.2.tgz",
+      "integrity": "sha512-EAlXoksqC6Vbocqc0GtzCruZEzYgrn+iiGnNjsJsH4mrnIGex4qbLdWWNza3AW5W36ZRrlBID0eM6bdKH4OStQ==",
+      "peer": true,
+      "dependencies": {
+        "prosemirror-state": "^1.0.0",
+        "w3c-keyname": "^2.2.0"
+      }
+    },
+    "node_modules/prosemirror-markdown": {
+      "version": "1.11.2",
+      "resolved": "https://registry.npmjs.org/prosemirror-markdown/-/prosemirror-markdown-1.11.2.tgz",
+      "integrity": "sha512-Eu5g4WPiCdqDTGhdSsG9N6ZjACQRYrsAkrF9KYfdMaCmjIApH75aVncsWYOJvEk2i1B3i8jZppv3J/tnuHGiUQ==",
+      "peer": true,
+      "dependencies": {
+        "markdown-it": "^13.0.1",
+        "prosemirror-model": "^1.0.0"
+      }
+    },
+    "node_modules/prosemirror-menu": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/prosemirror-menu/-/prosemirror-menu-1.2.4.tgz",
+      "integrity": "sha512-S/bXlc0ODQup6aiBbWVsX/eM+xJgCTAfMq/nLqaO5ID/am4wS0tTCIkzwytmao7ypEtjj39i7YbJjAgO20mIqA==",
+      "peer": true,
+      "dependencies": {
+        "crelt": "^1.0.0",
+        "prosemirror-commands": "^1.0.0",
+        "prosemirror-history": "^1.0.0",
+        "prosemirror-state": "^1.0.0"
+      }
+    },
+    "node_modules/prosemirror-model": {
+      "version": "1.19.3",
+      "resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.19.3.tgz",
+      "integrity": "sha512-tgSnwN7BS7/UM0sSARcW+IQryx2vODKX4MI7xpqY2X+iaepJdKBPc7I4aACIsDV/LTaTjt12Z56MhDr9LsyuZQ==",
+      "peer": true,
+      "dependencies": {
+        "orderedmap": "^2.0.0"
+      }
+    },
+    "node_modules/prosemirror-schema-basic": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/prosemirror-schema-basic/-/prosemirror-schema-basic-1.2.2.tgz",
+      "integrity": "sha512-/dT4JFEGyO7QnNTe9UaKUhjDXbTNkiWTq/N4VpKaF79bBjSExVV2NXmJpcM7z/gD7mbqNjxbmWW5nf1iNSSGnw==",
+      "peer": true,
+      "dependencies": {
+        "prosemirror-model": "^1.19.0"
+      }
+    },
+    "node_modules/prosemirror-schema-list": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/prosemirror-schema-list/-/prosemirror-schema-list-1.3.0.tgz",
+      "integrity": "sha512-Hz/7gM4skaaYfRPNgr421CU4GSwotmEwBVvJh5ltGiffUJwm7C8GfN/Bc6DR1EKEp5pDKhODmdXXyi9uIsZl5A==",
+      "peer": true,
+      "dependencies": {
+        "prosemirror-model": "^1.0.0",
+        "prosemirror-state": "^1.0.0",
+        "prosemirror-transform": "^1.7.3"
+      }
+    },
+    "node_modules/prosemirror-state": {
+      "version": "1.4.3",
+      "resolved": "https://registry.npmjs.org/prosemirror-state/-/prosemirror-state-1.4.3.tgz",
+      "integrity": "sha512-goFKORVbvPuAQaXhpbemJFRKJ2aixr+AZMGiquiqKxaucC6hlpHNZHWgz5R7dS4roHiwq9vDctE//CZ++o0W1Q==",
+      "peer": true,
+      "dependencies": {
+        "prosemirror-model": "^1.0.0",
+        "prosemirror-transform": "^1.0.0",
+        "prosemirror-view": "^1.27.0"
+      }
+    },
+    "node_modules/prosemirror-tables": {
+      "version": "1.3.4",
+      "resolved": "https://registry.npmjs.org/prosemirror-tables/-/prosemirror-tables-1.3.4.tgz",
+      "integrity": "sha512-z6uLSQ1BLC3rgbGwZmpfb+xkdvD7W/UOsURDfognZFYaTtc0gsk7u/t71Yijp2eLflVpffMk6X0u0+u+MMDvIw==",
+      "peer": true,
+      "dependencies": {
+        "prosemirror-keymap": "^1.1.2",
+        "prosemirror-model": "^1.8.1",
+        "prosemirror-state": "^1.3.1",
+        "prosemirror-transform": "^1.2.1",
+        "prosemirror-view": "^1.13.3"
+      }
+    },
+    "node_modules/prosemirror-trailing-node": {
+      "version": "2.0.7",
+      "resolved": "https://registry.npmjs.org/prosemirror-trailing-node/-/prosemirror-trailing-node-2.0.7.tgz",
+      "integrity": "sha512-8zcZORYj/8WEwsGo6yVCRXFMOfBo0Ub3hCUvmoWIZYfMP26WqENU0mpEP27w7mt8buZWuGrydBewr0tOArPb1Q==",
+      "peer": true,
+      "dependencies": {
+        "@remirror/core-constants": "^2.0.2",
+        "@remirror/core-helpers": "^3.0.0",
+        "escape-string-regexp": "^4.0.0"
+      },
+      "peerDependencies": {
+        "prosemirror-model": "^1.19.0",
+        "prosemirror-state": "^1.4.2",
+        "prosemirror-view": "^1.31.2"
+      }
+    },
+    "node_modules/prosemirror-transform": {
+      "version": "1.7.5",
+      "resolved": "https://registry.npmjs.org/prosemirror-transform/-/prosemirror-transform-1.7.5.tgz",
+      "integrity": "sha512-U/fWB6frEzY7dzwJUo+ir8dU1JEanaI/RwL12Imy9js/527N0v/IRUKewocP1kTq998JNT18IGtThaDLwLOBxQ==",
+      "peer": true,
+      "dependencies": {
+        "prosemirror-model": "^1.0.0"
+      }
+    },
+    "node_modules/prosemirror-view": {
+      "version": "1.31.8",
+      "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.31.8.tgz",
+      "integrity": "sha512-VQrEIdiPJ4YV65Ifj2kWISwaiqocMHy7cpUKVQYt19C/87FepoqnwVW3kMKRpeY/nQzED8L+vyOaYDBn0WqT7w==",
+      "peer": true,
+      "dependencies": {
+        "prosemirror-model": "^1.16.0",
+        "prosemirror-state": "^1.0.0",
+        "prosemirror-transform": "^1.1.0"
+      }
+    },
+    "node_modules/protocol-buffers-schema": {
+      "version": "3.6.0",
+      "resolved": "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.6.0.tgz",
+      "integrity": "sha512-TdDRD+/QNdrCGCE7v8340QyuXd4kIWIgapsE2+n/SaGiSSbomYl4TjHlvIoCWRpE7wFt02EpB35VVA2ImcBVqw=="
+    },
     "node_modules/proxy-addr": {
       "version": "2.0.7",
       "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
@@ -11714,6 +12979,11 @@
         "node": ">= 0.10"
       }
     },
+    "node_modules/proxy-from-env": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
+      "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
+    },
     "node_modules/prr": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz",
@@ -11819,6 +13089,22 @@
       "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz",
       "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag=="
     },
+    "node_modules/quick-lru": {
+      "version": "6.1.2",
+      "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-6.1.2.tgz",
+      "integrity": "sha512-AAFUA5O1d83pIHEhJwWCq/RQcRukCkn/NSm2QsTEMle5f2hP0ChI2+3Xb051PZCkLryI/Ir1MVKviT2FIloaTQ==",
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/quickselect": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-2.0.0.tgz",
+      "integrity": "sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw=="
+    },
     "node_modules/ramda": {
       "version": "0.28.0",
       "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.28.0.tgz",
@@ -11867,6 +13153,14 @@
         "node": ">= 0.8"
       }
     },
+    "node_modules/rbush": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/rbush/-/rbush-3.0.1.tgz",
+      "integrity": "sha512-XRaVO0YecOpEuIvbhbpTrZgoiI6xBlz6hnlr6EHhd+0x9ase6EmeN+hdwwUaJvLcsFFQ8iWVF1GAK1yB0BWi0w==",
+      "dependencies": {
+        "quickselect": "^2.0.0"
+      }
+    },
     "node_modules/rc": {
       "version": "1.2.8",
       "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
@@ -12338,6 +13632,14 @@
         "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1"
       }
     },
+    "node_modules/resolve-protobuf-schema": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/resolve-protobuf-schema/-/resolve-protobuf-schema-2.1.0.tgz",
+      "integrity": "sha512-kI5ffTiZWmJaS/huM8wZfEMer1eRd7oJQhDuxeCLe3t7N7mX3z94CN0xPxBQxFYQTSNz9T0i+v6inKqSdK8xrQ==",
+      "dependencies": {
+        "protocol-buffers-schema": "^3.3.1"
+      }
+    },
     "node_modules/resolve-url": {
       "version": "0.2.1",
       "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
@@ -12392,6 +13694,12 @@
         "inherits": "^2.0.1"
       }
     },
+    "node_modules/rope-sequence": {
+      "version": "1.3.4",
+      "resolved": "https://registry.npmjs.org/rope-sequence/-/rope-sequence-1.3.4.tgz",
+      "integrity": "sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ==",
+      "peer": true
+    },
     "node_modules/rsvp": {
       "version": "4.8.5",
       "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz",
@@ -13863,6 +15171,15 @@
       "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
       "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw=="
     },
+    "node_modules/throttle-debounce": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/throttle-debounce/-/throttle-debounce-3.0.1.tgz",
+      "integrity": "sha512-dTEWWNu6JmeVXY0ZYoPuH5cRIwc0MeGbJwah9KUNYSJwommQpCzTySTpEe8Gs1J23aeWEuAobe4Ag7EHVt/LOg==",
+      "peer": true,
+      "engines": {
+        "node": ">=10"
+      }
+    },
     "node_modules/through2": {
       "version": "2.0.5",
       "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz",
@@ -13920,6 +15237,14 @@
       "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.6.0.tgz",
       "integrity": "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw=="
     },
+    "node_modules/tippy.js": {
+      "version": "6.3.7",
+      "resolved": "https://registry.npmjs.org/tippy.js/-/tippy.js-6.3.7.tgz",
+      "integrity": "sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ==",
+      "dependencies": {
+        "@popperjs/core": "^2.9.0"
+      }
+    },
     "node_modules/tmpl": {
       "version": "1.0.5",
       "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz",
@@ -14205,6 +15530,12 @@
         "node": ">=14.17"
       }
     },
+    "node_modules/uc.micro": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz",
+      "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==",
+      "peer": true
+    },
     "node_modules/uglify-js": {
       "version": "3.17.4",
       "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz",
@@ -14571,6 +15902,11 @@
       "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
       "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ=="
     },
+    "node_modules/urlpattern-polyfill": {
+      "version": "9.0.0",
+      "resolved": "https://registry.npmjs.org/urlpattern-polyfill/-/urlpattern-polyfill-9.0.0.tgz",
+      "integrity": "sha512-WHN8KDQblxd32odxeIgo83rdVDE2bvdkb86it7bMhYZwWKJz0+O0RK/eZiHYnM+zgt/U7hAHOlCQGfjjvSkw2g=="
+    },
     "node_modules/use": {
       "version": "3.1.1",
       "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
@@ -14650,6 +15986,14 @@
         "uuid": "dist/bin/uuid"
       }
     },
+    "node_modules/value-or-promise": {
+      "version": "1.0.12",
+      "resolved": "https://registry.npmjs.org/value-or-promise/-/value-or-promise-1.0.12.tgz",
+      "integrity": "sha512-Z6Uz+TYwEqE7ZN50gwn+1LCVo9ZVrpxRPOhOLnncYkY1ZzOYtrX8Fwf/rFktZ8R5mJms6EZf5TqNOMeZmnPq9Q==",
+      "engines": {
+        "node": ">=12"
+      }
+    },
     "node_modules/vary": {
       "version": "1.1.2",
       "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
@@ -14726,6 +16070,12 @@
         "react-dom": "^18.0.0"
       }
     },
+    "node_modules/w3c-keyname": {
+      "version": "2.2.8",
+      "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz",
+      "integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==",
+      "peer": true
+    },
     "node_modules/walker": {
       "version": "1.0.8",
       "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz",
@@ -15056,6 +16406,11 @@
         "url": "https://github.com/sponsors/wooorm"
       }
     },
+    "node_modules/web-worker": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/web-worker/-/web-worker-1.2.0.tgz",
+      "integrity": "sha512-PgF341avzqyx60neE9DD+XS26MMNMoUQRz9NOZwW32nPQrF6p77f1htcnjBSEV8BGMKZ16choqUG4hyI0Hx7mA=="
+    },
     "node_modules/webpack": {
       "version": "5.88.2",
       "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.88.2.tgz",
@@ -15275,6 +16630,11 @@
         "typedarray-to-buffer": "^3.1.5"
       }
     },
+    "node_modules/xml-utils": {
+      "version": "1.7.0",
+      "resolved": "https://registry.npmjs.org/xml-utils/-/xml-utils-1.7.0.tgz",
+      "integrity": "sha512-bWB489+RQQclC7A9OW8e5BzbT8Tu//jtAOvkYwewFr+Q9T9KDGvfzC1lp0pYPEQPEoPQLDkmxkepSC/2gIAZGw=="
+    },
     "node_modules/xtend": {
       "version": "4.0.2",
       "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
diff --git a/package.json b/package.json
index e6904f8115f017c2637536f9453b00fe49bc983f..33c4567f45fe2d0a14ddaaba5456ac824166a33d 100644
--- a/package.json
+++ b/package.json
@@ -10,14 +10,27 @@
   },
   "dependencies": {
     "@apollo/client": "^3.8.1",
+    "@mantine/dates": "^5.10.5",
+    "@mantine/form": "^6.0.20",
     "@mantine/notifications": "^5.10.5",
+    "@mantine/tiptap": "^5.10.5",
+    "@prisma/client": "^5.3.1",
+    "@tiptap/extension-underline": "^2.1.10",
+    "@tiptap/react": "^2.1.10",
+    "@tiptap/starter-kit": "^2.1.10",
+    "adblock-hunter": "^1.0.1",
+    "axios": "^1.5.0",
     "eslint": "8.48.0",
     "eslint-config-next": "13.4.19",
+    "graphql-scalars": "^1.22.2",
+    "graphql-yoga": "^4.0.4",
     "html-react-parser": "^4.2.1",
     "jsonwebtoken": "^9.0.1",
     "next": "13.4.19",
     "next-auth": "^4.23.1",
     "next-i18next": "^14.0.0",
+    "nodemailer": "^6.9.4",
+    "ol": "^8.0.0",
     "react": "18.2.0",
     "react-dom": "18.2.0",
     "sharp": "^0.32.5",
diff --git a/pages/_app.js b/pages/_app.js
index 52940f585c3f86cf191bf0baa27c05bc1affe734..2ec76be163fea807b1be6f1db2a0984396ffb053 100644
--- a/pages/_app.js
+++ b/pages/_app.js
@@ -17,7 +17,9 @@ function App({ Component, pageProps: { session, ...pageProps } }) {
         <meta name="viewport" content="width=device-width, initial-scale=1" />
         <link
           rel="icon"
-          href={"https://static.vseth.ethz.ch/assets/vseth-0522-thealt/favicon.ico"}
+          href={
+            "https://static.vseth.ethz.ch/assets/vseth-0522-thealt/favicon.ico"
+          }
         />
         <title>TheAlternative</title>
       </Head>
diff --git a/pages/api/contact.js b/pages/api/contact.js
new file mode 100644
index 0000000000000000000000000000000000000000..2a7b257332b83f6a4ff44e978a6333fadf68e555
--- /dev/null
+++ b/pages/api/contact.js
@@ -0,0 +1,42 @@
+import nodemailer from "nodemailer";
+
+import config from "../../thealternative.config";
+
+export default async function handler(req, res) {
+  if (req.method == "POST") {
+    const { name, mail, message, human, robot } = req.body;
+
+    if (
+      human == true &&
+      robot == false &&
+      name != "" &&
+      mail != "" &&
+      message != ""
+    ) {
+      const transporter = nodemailer.createTransport({
+        host: process.env.MAILER_HOST,
+        port: 587,
+        secure: false, // true for 465, false for other ports
+        auth: {
+          user: process.env.MAILER_USERNAME,
+          pass: process.env.MAILER_PASSWORD,
+        },
+      });
+
+      await transporter.sendMail({
+        from: process.env.MAILER_NAME,
+        to: config.address,
+        replyTo: mail,
+        subject: (config.subject || "").replace("NAME", name),
+        html: message,
+      });
+
+      res.status(200).json({ message: "mailSuccess" });
+    } else {
+      res.status(200).json({ message: "mailFailure" });
+    }
+  } else {
+    res.setHeader("Allow", ["POST"]);
+    res.status(405).end(`Method ${req.method} Not Allowed`);
+  }
+}
diff --git a/pages/api/graphql.js b/pages/api/graphql.js
new file mode 100644
index 0000000000000000000000000000000000000000..547f4860a155ca71d9e6be11aab4b7de01d241ba
--- /dev/null
+++ b/pages/api/graphql.js
@@ -0,0 +1,33 @@
+import { createSchema, createYoga } from "graphql-yoga";
+import { typeDefs } from "../../graphql/schema";
+import { resolvers } from "../../graphql/resolvers";
+import { createContext } from "../../graphql/context";
+
+import { getServerSession } from "next-auth/next";
+import { authOptions } from "./auth/[...nextauth]";
+
+export default createYoga({
+  schema: createSchema({
+    typeDefs,
+    resolvers,
+    context: createContext,
+  }),
+  context: async (context) => {
+    const session = await getServerSession(
+      context.req,
+      context.res,
+      authOptions
+    );
+
+    return {
+      session,
+    };
+  },
+  graphqlEndpoint: "/api/graphql",
+});
+
+export const config = {
+  api: {
+    bodyParser: false,
+  },
+};
diff --git a/pages/api/hello.js b/pages/api/hello.js
index df63de88fa67cb006e692cc789caea580ba3697e..aee21e9afabdf82f7bab84f49cedc076f49f1504 100644
--- a/pages/api/hello.js
+++ b/pages/api/hello.js
@@ -1,5 +1,5 @@
 // Next.js API route support: https://nextjs.org/docs/api-routes/introduction
 
 export default function handler(req, res) {
-  res.status(200).json({ name: 'John Doe' })
+  res.status(200).json({ name: "John Doe" });
 }
diff --git a/pages/bash.jsx b/pages/bash.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..b00ac4d5c7ac03fc9aa677bd82073376d1579735
--- /dev/null
+++ b/pages/bash.jsx
@@ -0,0 +1,49 @@
+import dynamic from "next/dynamic";
+import { useRouter } from "next/router";
+import { useState, useEffect } from "react";
+
+import { serverSideTranslations } from "next-i18next/serverSideTranslations";
+
+import { Alert, Container, Grid, MediaQuery } from "@mantine/core";
+
+import { Icon, ICONS } from "vseth-canine-ui";
+
+import BashGuide from "../components/bashguide";
+const TOC = dynamic(() => import("../components/toc"), {
+  ssr: false,
+});
+
+export default function Bash() {
+  const { locale } = useRouter();
+
+  return (
+    <>
+      <Container size="xl">
+        <Grid>
+          <MediaQuery smallerThan="md" styles={{ display: "none" }}>
+            <Grid.Col md={4}>
+              <TOC />
+            </Grid.Col>
+          </MediaQuery>
+          <Grid.Col md={8} sm={12} className="bash-guide">
+            {locale === "de" && (
+              <Alert icon={<Icon icon={ICONS.INFO} />} title="Bemerkung">
+                Leider ist dieser Guide nur auf Englisch verfügbar.
+              </Alert>
+            )}
+            <BashGuide />
+          </Grid.Col>
+        </Grid>
+      </Container>
+    </>
+  );
+}
+
+export async function getStaticProps({ locale }) {
+  return {
+    props: {
+      ...(await serverSideTranslations(locale, ["common"])),
+      protected: false,
+    },
+  };
+}
diff --git a/pages/index.jsx b/pages/index.jsx
index a8d08c6c0e6bf8f025ed3bc73484be3a2a6b1ef0..7de83e4706e151b0b27f6d82d124dc2f9543ff40 100644
--- a/pages/index.jsx
+++ b/pages/index.jsx
@@ -1,48 +1,44 @@
-import { useRouter } from 'next/router';
-import Image from 'next/image';
+import { Container } from "@mantine/core";
 
-import parse from "html-react-parser";
+import { serverSideTranslations } from "next-i18next/serverSideTranslations";
 
-import {
-  Container,
-  Grid,
-  MediaQuery,
-} from '@mantine/core';
-
-import content from '../content/texts.json';
-import tux from '../content/images/tux.png';
+import Header from "../components/header";
+import Events from "../components/events";
+import About from "../components/about";
+import Philosophy from "../components/philosophy";
 
 export default function Home() {
-  const { locale } = useRouter();
-
   return (
     <>
-      <section className='light'>
+      <section className="light" style={{ paddingTop: 0 }}>
         <Container size="xl">
-          <Grid style={{ display: 'flex', alignItems: 'center' }}>
-            <Grid.Col xs={12} md={6}>
-              <div>
-                <h1>TheAlternative</h1>
-                {content.topSection.map((entry, i) => (
-                  <p key={i}>{parse(entry[locale || 'en'])}</p>
-                ))}
-              </div>
-            </Grid.Col>
-            <MediaQuery smallerThan="md" styles={{ display: "none" }}>
-              <Grid.Col md={6}>
-                <Image
-                  src={tux}
-                  width={0}
-                  height={0}
-                  sizes="100vw"
-                  style={{ width: "100%", height: "auto" }}
-                  alt="Tux, the Linux Mascot"
-                />
-              </Grid.Col>
-            </MediaQuery>
-          </Grid>
+          <Header />
+        </Container>
+      </section>
+      <section className="dark" id="events">
+        <Container size="xl">
+          <Events />
+        </Container>
+      </section>
+      <section className="light" id="about">
+        <Container size="xl">
+          <About />
+        </Container>
+      </section>
+      <section className="dark" id="philosophy">
+        <Container size="xl">
+          <Philosophy />
         </Container>
       </section>
     </>
-  )
+  );
+}
+
+export async function getStaticProps({ locale }) {
+  return {
+    props: {
+      ...(await serverSideTranslations(locale, ["common"])),
+      protected: false,
+    },
+  };
 }
diff --git a/pages/install.jsx b/pages/install.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..293a70c139c1adcbd9d31d8ae64815a585a6bc62
--- /dev/null
+++ b/pages/install.jsx
@@ -0,0 +1,49 @@
+import dynamic from "next/dynamic";
+import { useRouter } from "next/router";
+import { useState, useEffect } from "react";
+
+import { serverSideTranslations } from "next-i18next/serverSideTranslations";
+
+import { Alert, Container, Grid, MediaQuery } from "@mantine/core";
+
+import { Icon, ICONS } from "vseth-canine-ui";
+
+import InstallGuide from "../components/installguide";
+const TOC = dynamic(() => import("../components/toc"), {
+  ssr: false,
+});
+
+export default function Install() {
+  const { locale } = useRouter();
+
+  return (
+    <>
+      <Container size="xl">
+        <Grid>
+          <MediaQuery smallerThan="md" styles={{ display: "none" }}>
+            <Grid.Col md={4}>
+              <TOC />
+            </Grid.Col>
+          </MediaQuery>
+          <Grid.Col md={8} sm={12} className="bash-guide">
+            {locale === "de" && (
+              <Alert icon={<Icon icon={ICONS.INFO} />} title="Bemerkung">
+                Leider ist dieser Guide nur auf Englisch verfügbar.
+              </Alert>
+            )}
+            <InstallGuide />
+          </Grid.Col>
+        </Grid>
+      </Container>
+    </>
+  );
+}
+
+export async function getStaticProps({ locale }) {
+  return {
+    props: {
+      ...(await serverSideTranslations(locale, ["common"])),
+      protected: false,
+    },
+  };
+}
diff --git a/prisma.sh b/prisma.sh
index 545b9da75c8fd4d2f7a8013deb602bee0e79f91f..f2964eaae2f5e06cf762ed3e8602cd4d03550e75 100755
--- a/prisma.sh
+++ b/prisma.sh
@@ -3,4 +3,4 @@
 echo "DATABASE_URL=mysql://$SIP_MYSQL_ALT_USER:$SIP_MYSQL_ALT_PW@$SIP_MYSQL_ALT_SERVER:$SIP_MYSQL_ALT_PORT/$SIP_MYSQL_ALT_NAME?schema=public" > .env
 
 npx prisma generate
-npx prisma migrate deploy
+npx prisma migrate deploy
\ No newline at end of file
diff --git a/prisma/migrations/20230915103134_initial_migration/migration.sql b/prisma/migrations/20230915103134_initial_migration/migration.sql
new file mode 100644
index 0000000000000000000000000000000000000000..2668ce14f452975c8a0a36bdee53d885e14a777a
--- /dev/null
+++ b/prisma/migrations/20230915103134_initial_migration/migration.sql
@@ -0,0 +1,15 @@
+-- CreateTable
+CREATE TABLE `Event` (
+    `id` INTEGER NOT NULL AUTO_INCREMENT,
+    `title` VARCHAR(191) NOT NULL,
+    `speaker` VARCHAR(191) NOT NULL,
+    `description` VARCHAR(191) NOT NULL,
+    `date` DATETIME(3) NOT NULL,
+    `startTime` DATETIME(3) NOT NULL,
+    `endTime` DATETIME(3) NOT NULL,
+    `place` VARCHAR(191) NOT NULL,
+    `signUp` VARCHAR(191) NOT NULL,
+    `isStammtisch` BOOLEAN NOT NULL DEFAULT false,
+
+    PRIMARY KEY (`id`)
+) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
diff --git a/prisma/migrations/20230915104240_store_dates_as_string/migration.sql b/prisma/migrations/20230915104240_store_dates_as_string/migration.sql
new file mode 100644
index 0000000000000000000000000000000000000000..22ca17c055a1e774ebab6c8d4981ca2f2dfb7218
--- /dev/null
+++ b/prisma/migrations/20230915104240_store_dates_as_string/migration.sql
@@ -0,0 +1,4 @@
+-- AlterTable
+ALTER TABLE `Event` MODIFY `date` VARCHAR(191) NOT NULL,
+    MODIFY `startTime` VARCHAR(191) NOT NULL,
+    MODIFY `endTime` VARCHAR(191) NOT NULL;
diff --git a/prisma/migrations/20230915121556_description_is_now_text/migration.sql b/prisma/migrations/20230915121556_description_is_now_text/migration.sql
new file mode 100644
index 0000000000000000000000000000000000000000..c4bf21425789fa9653f62a07fae68e87e2ee9fea
--- /dev/null
+++ b/prisma/migrations/20230915121556_description_is_now_text/migration.sql
@@ -0,0 +1,2 @@
+-- AlterTable
+ALTER TABLE `Event` MODIFY `description` TEXT NOT NULL;
diff --git a/prisma/migrations/20230915132050_add_sign_up/migration.sql b/prisma/migrations/20230915132050_add_sign_up/migration.sql
new file mode 100644
index 0000000000000000000000000000000000000000..1bf9d8ebbafa19a4586c0a3a610a115af757dd30
--- /dev/null
+++ b/prisma/migrations/20230915132050_add_sign_up/migration.sql
@@ -0,0 +1,11 @@
+-- CreateTable
+CREATE TABLE `SignUp` (
+    `id` INTEGER NOT NULL AUTO_INCREMENT,
+    `sub` VARCHAR(191) NOT NULL,
+    `eventId` INTEGER NOT NULL,
+
+    PRIMARY KEY (`id`)
+) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
+
+-- AddForeignKey
+ALTER TABLE `SignUp` ADD CONSTRAINT `SignUp_eventId_fkey` FOREIGN KEY (`eventId`) REFERENCES `Event`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
diff --git a/prisma/migrations/20230915135047_add_name_and_email_to_sign_up/migration.sql b/prisma/migrations/20230915135047_add_name_and_email_to_sign_up/migration.sql
new file mode 100644
index 0000000000000000000000000000000000000000..143b68226b466af0743b59c5ba5b36b22f3880d5
--- /dev/null
+++ b/prisma/migrations/20230915135047_add_name_and_email_to_sign_up/migration.sql
@@ -0,0 +1,12 @@
+/*
+  Warnings:
+
+  - Added the required column `email` to the `SignUp` table without a default value. This is not possible if the table is not empty.
+  - Added the required column `firstName` to the `SignUp` table without a default value. This is not possible if the table is not empty.
+  - Added the required column `lastName` to the `SignUp` table without a default value. This is not possible if the table is not empty.
+
+*/
+-- AlterTable
+ALTER TABLE `SignUp` ADD COLUMN `email` VARCHAR(191) NOT NULL,
+    ADD COLUMN `firstName` VARCHAR(191) NOT NULL,
+    ADD COLUMN `lastName` VARCHAR(191) NOT NULL;
diff --git a/prisma/migrations/migration_lock.toml b/prisma/migrations/migration_lock.toml
new file mode 100644
index 0000000000000000000000000000000000000000..e5a788a7af8fecc0478ef418b8e95c2cf2bbffdf
--- /dev/null
+++ b/prisma/migrations/migration_lock.toml
@@ -0,0 +1,3 @@
+# Please do not edit this file manually
+# It should be added in your version-control system (i.e. Git)
+provider = "mysql"
\ No newline at end of file
diff --git a/prisma/schema.prisma b/prisma/schema.prisma
new file mode 100644
index 0000000000000000000000000000000000000000..48d318d695a6a4c00c757c110754f9aeb76cedf4
--- /dev/null
+++ b/prisma/schema.prisma
@@ -0,0 +1,35 @@
+// This is your Prisma schema file,
+// learn more about it in the docs: https://pris.ly/d/prisma-schema
+
+generator client {
+  provider = "prisma-client-js"
+}
+
+datasource db {
+  provider = "mysql"
+  url      = env("DATABASE_URL")
+}
+
+model Event {
+  id           Int     @id @default(autoincrement())
+  title        String
+  speaker      String
+  description  String  @db.Text
+  date         String
+  startTime    String
+  endTime      String
+  place        String
+  signUp       String
+  isStammtisch Boolean @default(false)
+  signUps      SignUp[]
+}
+
+model SignUp {
+  id        Int    @id @default(autoincrement())
+  sub       String
+  firstName String
+  lastName  String
+  email     String
+  event     Event  @relation(fields: [eventId], references: [id], onDelete: Cascade)
+  eventId   Int
+}
diff --git a/public/images/board/alex.png b/public/images/board/alex.png
new file mode 100644
index 0000000000000000000000000000000000000000..121c1f931456d2aa2a895669f4d34efd800b0eb1
Binary files /dev/null and b/public/images/board/alex.png differ
diff --git a/public/images/board/fadri.jpg b/public/images/board/fadri.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..2047705569646c434b5e4d783b67c943cd2593e2
Binary files /dev/null and b/public/images/board/fadri.jpg differ
diff --git a/public/images/board/jeanclaude.jpg b/public/images/board/jeanclaude.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..5d7bc0d20208568e3e85e20e5f4fa2dd9be08b90
Binary files /dev/null and b/public/images/board/jeanclaude.jpg differ
diff --git a/public/images/board/jindra.png b/public/images/board/jindra.png
new file mode 100644
index 0000000000000000000000000000000000000000..ab33c090480d96b919c0b737f8daf2892abd938c
Binary files /dev/null and b/public/images/board/jindra.png differ
diff --git a/public/images/board/nicolas.jpg b/public/images/board/nicolas.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..084b440a18844ba82e129ff52d8c09ecf6428ae6
Binary files /dev/null and b/public/images/board/nicolas.jpg differ
diff --git a/public/images/board/placeholder.png b/public/images/board/placeholder.png
new file mode 100644
index 0000000000000000000000000000000000000000..1aa55e6838eb027ae34020aa91a25e8932b44a9c
Binary files /dev/null and b/public/images/board/placeholder.png differ
diff --git a/public/images/board/placeholder_girl.png b/public/images/board/placeholder_girl.png
new file mode 100644
index 0000000000000000000000000000000000000000..3d905c6bd29cfbe53281471beda2378d5cfe0f90
Binary files /dev/null and b/public/images/board/placeholder_girl.png differ
diff --git a/public/images/board/sophie.png b/public/images/board/sophie.png
new file mode 100644
index 0000000000000000000000000000000000000000..6b7f34290d79ed55fdcfd9728082c3067c7d57e4
Binary files /dev/null and b/public/images/board/sophie.png differ
diff --git a/public/images/logo.svg b/public/images/logo.svg
new file mode 100644
index 0000000000000000000000000000000000000000..16eca6c46515375cbb9af4a9205878f2bcdd8439
--- /dev/null
+++ b/public/images/logo.svg
@@ -0,0 +1,327 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   width="125.61094mm"
+   height="17.76333mm"
+   viewBox="0 0 125.61094 17.76333"
+   version="1.1"
+   id="svg1"
+   inkscape:version="1.3 (0e150ed6c4, 2023-07-21)"
+   sodipodi:docname="logo.svg"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:svg="http://www.w3.org/2000/svg">
+  <sodipodi:namedview
+     id="namedview1"
+     pagecolor="#ffffff"
+     bordercolor="#000000"
+     borderopacity="0.25"
+     inkscape:showpageshadow="2"
+     inkscape:pageopacity="0.0"
+     inkscape:pagecheckerboard="true"
+     inkscape:deskcolor="#d1d1d1"
+     inkscape:document-units="mm"
+     inkscape:zoom="1.8469494"
+     inkscape:cx="230.65061"
+     inkscape:cy="-38.171051"
+     inkscape:window-width="1680"
+     inkscape:window-height="981"
+     inkscape:window-x="0"
+     inkscape:window-y="0"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="g19" />
+  <defs
+     id="defs1" />
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(-42.06875,-139.7)">
+    <g
+       id="g50"
+       transform="matrix(0.26458333,0,0,0.26458333,25.186481,122.92859)">
+      <g
+         id="g19">
+        <g
+           id="g2"
+           style="fill:#244471;fill-opacity:1">
+          <path
+             fill="#ffffff"
+             d="m 166.616,63.389 v 5.929 h -10.568 v 30.934 h -6.831 V 69.318 h -10.568 v -5.929 z"
+             id="path1"
+             style="fill:#244471;fill-opacity:1" />
+        </g>
+        <g
+           id="g3"
+           style="fill:#244471;fill-opacity:1">
+          <path
+             fill="#ffffff"
+             d="M 170.874,100.25 V 63.389 h 6.831 v 13.25 c 2.131,-2.302 4.854,-3.454 8.171,-3.454 6.41,0 9.615,3.334 9.615,10.002 v 17.064 H 188.66 V 83.186 c 0,-2.99 -1.487,-4.484 -4.459,-4.484 -2.217,0 -4.382,0.885 -6.496,2.654 v 18.896 z"
+             id="path2"
+             style="fill:#244471;fill-opacity:1" />
+        </g>
+        <g
+           id="g4"
+           style="fill:#244471;fill-opacity:1">
+          <path
+             fill="#ffffff"
+             d="m 214.415,73.184 c 8.214,0 12.322,4.193 12.322,12.58 0,1.117 -0.078,2.234 -0.232,3.351 h -17.967 c 0,3.815 2.801,5.724 8.404,5.724 2.731,0 5.464,-0.258 8.197,-0.773 v 5.413 c -2.39,0.517 -5.293,0.773 -8.712,0.773 -9.813,0 -14.72,-4.614 -14.72,-13.842 -0.001,-8.818 4.235,-13.226 12.708,-13.226 z m -5.878,11.188 h 11.548 v -0.206 c 0,-3.746 -1.891,-5.62 -5.671,-5.62 -3.608,0 -5.567,1.942 -5.877,5.826 z"
+             id="path3"
+             style="fill:#244471;fill-opacity:1" />
+        </g>
+        <g
+           id="g14"
+           style="fill:#f28a20;fill-opacity:1">
+          <path
+             fill="#f18a21"
+             d="m 236.713,100.316 h -7.011 l 15.647,-36.861 h 7.346 l 15.982,36.861 h -7.347 l -4.202,-10.053 h -12.245 l 2.347,-5.929 h 7.424 l -5.8,-13.842 z"
+             id="path4"
+             style="fill:#f28a20;fill-opacity:1" />
+          <path
+             fill="#f18a21"
+             d="m 280.378,63.455 v 36.861 h -6.831 V 63.455 Z"
+             id="path5"
+             style="fill:#f28a20;fill-opacity:1" />
+          <path
+             fill="#f18a21"
+             d="m 287.439,68.868 h 5.052 l 1.031,4.382 h 6.805 v 5.414 h -6.058 v 12.449 c 0,2.526 1.091,3.79 3.273,3.79 h 2.784 v 5.413 h -6.083 c -4.537,0 -6.805,-2.432 -6.805,-7.295 V 68.868 Z"
+             id="path6"
+             style="fill:#f28a20;fill-opacity:1" />
+          <path
+             fill="#f18a21"
+             d="m 317.391,73.25 c 8.213,0 12.32,4.192 12.32,12.58 0,1.116 -0.076,2.233 -0.23,3.351 h -17.967 c 0,3.815 2.801,5.723 8.401,5.723 2.732,0 5.466,-0.258 8.197,-0.772 v 5.413 c -2.389,0.516 -5.293,0.772 -8.713,0.772 -9.813,0 -14.718,-4.613 -14.718,-13.842 0.001,-8.817 4.238,-13.225 12.71,-13.225 z m -5.877,11.188 h 11.547 v -0.206 c 0,-3.746 -1.891,-5.62 -5.67,-5.62 -3.61,0 -5.569,1.942 -5.877,5.826 z"
+             id="path7"
+             style="fill:#f28a20;fill-opacity:1" />
+          <path
+             fill="#f18a21"
+             d="M 335.844,100.316 V 73.25 h 5.285 l 0.85,3.454 c 2.371,-2.303 4.881,-3.454 7.527,-3.454 v 5.517 c -2.543,0 -4.82,1.057 -6.832,3.17 v 18.379 z"
+             id="path8"
+             style="fill:#f28a20;fill-opacity:1" />
+          <path
+             fill="#f18a21"
+             d="M 354.378,100.316 V 73.25 h 5.282 l 0.853,3.97 c 2.594,-2.646 5.551,-3.97 8.867,-3.97 6.409,0 9.614,3.334 9.614,10.002 v 17.063 h -6.832 V 83.252 c 0,-2.99 -1.485,-4.485 -4.459,-4.485 -2.217,0 -4.383,0.885 -6.496,2.655 v 18.895 z"
+             id="path9"
+             style="fill:#f28a20;fill-opacity:1" />
+          <path
+             fill="#f18a21"
+             d="m 385.152,91.887 c 0,-5.378 3.918,-8.068 11.754,-8.068 1.838,0 3.679,0.172 5.517,0.517 v -2.037 c 0,-2.423 -1.744,-3.634 -5.232,-3.634 -2.955,0 -6.238,0.43 -9.848,1.289 V 74.54 c 3.608,-0.859 6.893,-1.289 9.848,-1.289 8.043,0 12.064,2.974 12.064,8.919 v 18.146 h -3.972 l -2.422,-2.423 c -2.354,1.615 -4.949,2.423 -7.785,2.423 -6.616,0 -9.924,-2.809 -9.924,-8.429 z m 11.754,-3.428 c -3.283,0 -4.924,1.117 -4.924,3.351 0,2.406 1.375,3.609 4.125,3.609 2.268,0 4.373,-0.705 6.314,-2.114 v -4.331 c -1.718,-0.343 -3.556,-0.515 -5.515,-0.515 z"
+             id="path10"
+             style="fill:#f28a20;fill-opacity:1" />
+          <path
+             fill="#f18a21"
+             d="m 416.314,68.868 h 5.053 l 1.031,4.382 h 6.805 v 5.414 h -6.057 v 12.449 c 0,2.526 1.09,3.79 3.273,3.79 h 2.782 v 5.413 h -6.084 c -4.537,0 -6.805,-2.432 -6.805,-7.295 z"
+             id="path11"
+             style="fill:#f28a20;fill-opacity:1" />
+          <path
+             fill="#f18a21"
+             d="m 441.677,63.455 v 5.414 h -6.83 v -5.414 z m 0,9.795 v 27.065 h -6.83 V 73.25 Z"
+             id="path12"
+             style="fill:#f28a20;fill-opacity:1" />
+          <path
+             fill="#f18a21"
+             d="m 445.902,73.25 h 7.217 l 6.574,18.921 6.83,-18.921 h 7.219 l -11.008,27.065 h -6.496 z"
+             id="path13"
+             style="fill:#f28a20;fill-opacity:1" />
+          <path
+             fill="#f18a21"
+             d="m 489.387,73.25 c 8.213,0 12.319,4.192 12.319,12.58 0,1.116 -0.075,2.233 -0.229,3.351 H 483.51 c 0,3.815 2.801,5.723 8.401,5.723 2.732,0 5.466,-0.258 8.197,-0.772 v 5.413 c -2.389,0.516 -5.293,0.772 -8.713,0.772 -9.813,0 -14.719,-4.613 -14.719,-13.842 0.002,-8.817 4.238,-13.225 12.711,-13.225 z m -5.877,11.188 h 11.547 v -0.206 c 0,-3.746 -1.892,-5.62 -5.67,-5.62 -3.61,0 -5.569,1.942 -5.877,5.826 z"
+             id="path14"
+             style="fill:#f28a20;fill-opacity:1" />
+        </g>
+        <g
+           transform="matrix(0.4050561,0,0,0.4050561,513.72016,151.02668)"
+           id="g18"
+           style="fill:#244471;fill-opacity:1">
+          <g
+             id="g17"
+             style="fill:#244471;fill-opacity:1">
+            <path
+               fill="#ffffff"
+               d="m -12.003,-133.014 v 7.821 h -8.46 v -7.821 z"
+               id="path15"
+               style="fill:#244471;fill-opacity:1" />
+            <path
+               fill="#ffffff"
+               d="m 22.471,-126.15 c -2.768,0.636 -5.639,0.957 -8.619,0.957 -11.922,0 -17.877,-5.798 -17.877,-17.4 0,-10.748 5.955,-16.122 17.877,-16.122 2.98,0 5.854,0.321 8.619,0.96 v 6.702 c -2.768,-0.639 -5.427,-0.955 -7.98,-0.955 -6.705,0 -10.056,3.139 -10.056,9.415 0,7.132 3.351,10.697 10.056,10.697 2.553,0 5.213,-0.321 7.98,-0.96 z"
+               id="path16"
+               style="fill:#244471;fill-opacity:1" />
+            <path
+               fill="#ffffff"
+               d="m 30.608,-125.193 v -45.651 h 8.46 v 16.409 c 2.64,-2.852 6.013,-4.279 10.121,-4.279 7.937,0 11.905,4.13 11.905,12.387 v 21.134 h -8.458 v -21.134 c 0,-3.703 -1.842,-5.555 -5.526,-5.555 -2.744,0 -5.425,1.097 -8.043,3.289 v 23.401 h -8.459 z"
+               id="path17"
+               style="fill:#244471;fill-opacity:1" />
+          </g>
+        </g>
+      </g>
+      <g
+         id="g23"
+         style="fill:#244471;fill-opacity:1">
+        <path
+           fill="#ffffff"
+           d="m 75.358,63.389 c -6.399,0 -11.551,5.152 -11.551,11.551 v 40.288 c 0,6.398 5.151,11.55 11.551,11.55 h 40.287 c 6.398,0 11.55,-5.151 11.55,-11.55 V 74.939 c 0,-6.398 -5.151,-11.551 -11.55,-11.551 z m 1.182,3.823 h 36.325 c 5.821,0 10.507,4.686 10.507,10.507 v 36.325 c 0,5.82 -4.686,10.507 -10.507,10.507 H 76.54 c -5.822,0 -10.507,-4.687 -10.507,-10.507 V 77.72 c 0,-5.822 4.685,-10.508 10.507,-10.508 z"
+           id="path19"
+           style="fill:#244471;fill-opacity:1" />
+        <g
+           id="g22"
+           style="fill:#244471;fill-opacity:1">
+          <path
+             fill="#ffffff"
+             d="m 85.647,96.678 h -3.663 l 8.174,-19.256 h 3.837 l 8.35,19.256 h -3.838 l -2.194,-5.251 h -6.396 l 1.226,-3.097 h 3.878 l -3.03,-7.231 z"
+             id="path20"
+             style="fill:#244471;fill-opacity:1" />
+          <path
+             fill="#ffffff"
+             d="m 107.933,77.422 v 19.256 h -3.568 V 77.422 Z"
+             id="path21"
+             style="fill:#244471;fill-opacity:1" />
+          <path
+             fill="#ffffff"
+             d="m 111.097,80.251 h 2.639 l 0.539,2.289 h 3.555 v 2.828 h -3.164 v 6.504 c 0,1.318 0.57,1.979 1.71,1.979 h 1.454 v 2.828 h -3.178 c -2.37,0 -3.555,-1.27 -3.555,-3.811 z"
+             id="path22"
+             style="fill:#244471;fill-opacity:1" />
+        </g>
+      </g>
+      <g
+         id="g49"
+         style="fill:#244471;fill-opacity:1">
+        <path
+           fill="#ffffff"
+           d="m 148.923,126.816 v -10.747 c 0,-2.479 1.405,-3.719 4.218,-3.719 0.773,0 1.503,0.13 2.187,0.391 v 1.465 c -0.644,-0.261 -1.376,-0.391 -2.196,-0.391 -1.601,0 -2.4,0.727 -2.4,2.178 v 0.575 h 3.172 v 1.464 h -3.172 v 8.785 z"
+           id="path23"
+           style="fill:#244471;fill-opacity:1" />
+        <path
+           fill="#ffffff"
+           d="m 159.553,121.692 c 0,-3.417 1.627,-5.125 4.881,-5.125 3.253,0 4.88,1.708 4.88,5.125 0,3.41 -1.627,5.115 -4.88,5.115 -3.241,0 -4.868,-1.705 -4.881,-5.115 z m 4.881,3.66 c 2.05,0 3.074,-1.232 3.074,-3.699 0,-2.415 -1.024,-3.622 -3.074,-3.622 -2.051,0 -3.075,1.207 -3.075,3.622 0,2.466 1.025,3.699 3.075,3.699 z"
+           id="path24"
+           style="fill:#244471;fill-opacity:1" />
+        <path
+           fill="#ffffff"
+           d="m 175.933,126.816 v -10.25 h 1.22 l 0.322,1.309 c 0.897,-0.872 1.979,-1.309 3.24,-1.309 v 1.503 c -1.223,0 -2.216,0.434 -2.977,1.299 v 7.447 z"
+           id="path25"
+           style="fill:#244471;fill-opacity:1" />
+        <path
+           fill="#ffffff"
+           d="m 195.271,123.722 c 0,-2.102 1.386,-3.153 4.158,-3.153 0.892,0 1.782,0.065 2.675,0.195 v -0.966 c 0,-1.178 -0.921,-1.768 -2.764,-1.768 -1.054,0 -2.134,0.163 -3.24,0.488 v -1.464 c 1.105,-0.326 2.187,-0.488 3.24,-0.488 3.047,0 4.568,1.062 4.568,3.183 v 7.066 h -1.015 l -0.625,-1.015 c -1.022,0.677 -2.136,1.015 -3.338,1.015 -2.439,0.001 -3.659,-1.03 -3.659,-3.093 z m 4.158,-1.689 c -1.568,0 -2.353,0.553 -2.353,1.659 0,1.107 0.618,1.659 1.854,1.659 1.25,0 2.307,-0.332 3.172,-0.996 v -2.128 c -0.89,-0.128 -1.781,-0.194 -2.673,-0.194 z"
+           id="path26"
+           style="fill:#244471;fill-opacity:1" />
+        <path
+           fill="#ffffff"
+           d="m 219.978,126.328 v -1.563 c 1.204,0.39 2.421,0.585 3.65,0.585 1.634,0 2.45,-0.488 2.45,-1.464 0,-0.911 -0.569,-1.367 -1.708,-1.367 h -1.464 c -2.212,0 -3.319,-1.009 -3.319,-3.025 0,-1.953 1.422,-2.93 4.267,-2.93 1.224,0 2.437,0.163 3.641,0.488 v 1.562 c -1.204,-0.39 -2.417,-0.585 -3.641,-0.585 -1.705,0 -2.558,0.488 -2.558,1.465 0,0.91 0.537,1.365 1.61,1.365 h 1.464 c 2.343,0 3.515,1.01 3.515,3.026 0,1.952 -1.42,2.928 -4.257,2.928 -1.23,0.003 -2.447,-0.159 -3.65,-0.485 z"
+           id="path27"
+           style="fill:#244471;fill-opacity:1" />
+        <path
+           fill="#ffffff"
+           d="m 243.337,116.567 v 10.25 h -1.239 l -0.313,-1.308 c -1.243,0.872 -2.492,1.308 -3.748,1.308 -2.355,0 -3.534,-1.271 -3.534,-3.816 v -6.434 h 1.807 v 6.462 c 0,1.523 0.755,2.284 2.265,2.284 1.035,0 2.021,-0.433 2.958,-1.298 v -7.448 z"
+           id="path28"
+           style="fill:#244471;fill-opacity:1" />
+        <path
+           fill="#ffffff"
+           d="m 250.346,126.328 v -1.563 c 1.203,0.39 2.421,0.585 3.65,0.585 1.633,0 2.45,-0.488 2.45,-1.464 0,-0.911 -0.569,-1.367 -1.708,-1.367 h -1.464 c -2.212,0 -3.319,-1.009 -3.319,-3.025 0,-1.953 1.422,-2.93 4.267,-2.93 1.224,0 2.437,0.163 3.641,0.488 v 1.562 c -1.204,-0.39 -2.417,-0.585 -3.641,-0.585 -1.705,0 -2.558,0.488 -2.558,1.465 0,0.91 0.537,1.365 1.61,1.365 h 1.464 c 2.343,0 3.514,1.01 3.514,3.026 0,1.952 -1.419,2.928 -4.256,2.928 -1.229,0.003 -2.447,-0.159 -3.65,-0.485 z"
+           id="path29"
+           style="fill:#244471;fill-opacity:1" />
+        <path
+           fill="#ffffff"
+           d="m 264.871,114.908 h 1.132 l 0.391,1.658 h 2.771 v 1.464 h -2.489 v 5.887 c 0,0.957 0.413,1.435 1.24,1.435 h 1.25 v 1.464 h -1.718 c -1.718,0 -2.577,-0.921 -2.577,-2.763 z"
+           id="path30"
+           style="fill:#244471;fill-opacity:1" />
+        <path
+           fill="#ffffff"
+           d="m 275.15,123.722 c 0,-2.102 1.386,-3.153 4.158,-3.153 0.892,0 1.782,0.065 2.675,0.195 v -0.966 c 0,-1.178 -0.921,-1.768 -2.763,-1.768 -1.055,0 -2.135,0.163 -3.241,0.488 v -1.464 c 1.105,-0.326 2.187,-0.488 3.241,-0.488 3.046,0 4.567,1.062 4.567,3.183 v 7.066 h -1.015 l -0.625,-1.015 c -1.022,0.677 -2.135,1.015 -3.338,1.015 -2.439,0.001 -3.659,-1.03 -3.659,-3.093 z m 4.158,-1.689 c -1.568,0 -2.353,0.553 -2.353,1.659 0,1.107 0.618,1.659 1.854,1.659 1.25,0 2.307,-0.332 3.172,-0.996 v -2.128 c -0.89,-0.128 -1.781,-0.194 -2.673,-0.194 z"
+           id="path31"
+           style="fill:#244471;fill-opacity:1" />
+        <path
+           fill="#ffffff"
+           d="m 292.896,112.857 v 1.708 h -1.807 v -1.708 z m 0,3.71 v 10.25 h -1.807 v -10.25 z"
+           id="path32"
+           style="fill:#244471;fill-opacity:1" />
+        <path
+           fill="#ffffff"
+           d="m 300.198,126.816 v -10.25 h 1.222 l 0.321,1.309 c 1.047,-0.872 2.199,-1.309 3.455,-1.309 2.559,0 3.835,1.272 3.835,3.817 v 6.433 h -1.805 v -6.462 c 0,-1.522 -0.758,-2.284 -2.275,-2.284 -1.033,0 -2.018,0.434 -2.946,1.299 v 7.447 z"
+           id="path33"
+           style="fill:#244471;fill-opacity:1" />
+        <path
+           fill="#ffffff"
+           d="m 315.65,123.722 c 0,-2.102 1.387,-3.153 4.158,-3.153 0.893,0 1.783,0.065 2.676,0.195 v -0.966 c 0,-1.178 -0.922,-1.768 -2.764,-1.768 -1.056,0 -2.135,0.163 -3.24,0.488 v -1.464 c 1.105,-0.326 2.186,-0.488 3.24,-0.488 3.045,0 4.567,1.062 4.567,3.183 v 7.066 h -1.016 l -0.625,-1.015 c -1.021,0.677 -2.133,1.015 -3.338,1.015 -2.437,0.001 -3.658,-1.03 -3.658,-3.093 z m 4.159,-1.689 c -1.568,0 -2.353,0.553 -2.353,1.659 0,1.107 0.617,1.659 1.854,1.659 1.25,0 2.307,-0.332 3.174,-0.996 v -2.128 c -0.891,-0.128 -1.783,-0.194 -2.675,-0.194 z"
+           id="path34"
+           style="fill:#244471;fill-opacity:1" />
+        <path
+           fill="#ffffff"
+           d="m 331.396,112.857 h 1.807 v 4.198 c 0.773,-0.326 1.604,-0.488 2.488,-0.488 3.24,0 4.861,1.641 4.861,4.92 0,3.554 -1.701,5.33 -5.105,5.33 -1.471,0 -2.819,-0.14 -4.051,-0.42 z m 1.807,12.173 c 0.593,0.188 1.312,0.283 2.156,0.283 2.277,0 3.416,-1.298 3.416,-3.895 0,-2.193 -1.031,-3.29 -3.094,-3.29 -0.938,0 -1.764,0.176 -2.479,0.526 z"
+           id="path35"
+           style="fill:#244471;fill-opacity:1" />
+        <path
+           fill="#ffffff"
+           d="m 349.074,112.857 v 13.959 h -1.807 v -13.959 z"
+           id="path36"
+           style="fill:#244471;fill-opacity:1" />
+        <path
+           fill="#ffffff"
+           d="m 360.505,116.567 c 2.916,0 4.375,1.441 4.375,4.324 0,0.41 -0.029,0.85 -0.089,1.318 h -7.194 c 0,2.096 1.223,3.143 3.67,3.143 1.166,0 2.199,-0.13 3.104,-0.39 v 1.464 c -0.905,0.261 -2.006,0.391 -3.301,0.391 -3.52,0 -5.279,-1.747 -5.279,-5.241 0,-3.34 1.57,-5.009 4.714,-5.009 z m -2.909,4.139 h 5.545 c -0.039,-1.796 -0.918,-2.694 -2.637,-2.694 -1.82,0 -2.79,0.898 -2.908,2.694 z"
+           id="path37"
+           style="fill:#244471;fill-opacity:1" />
+        <path
+           fill="#ffffff"
+           d="m 389.232,126.202 c -1.242,0.409 -2.775,0.614 -4.596,0.614 -3.054,0 -4.578,-1.775 -4.578,-5.33 0,-3.279 1.619,-4.92 4.859,-4.92 0.887,0 1.723,0.163 2.51,0.488 v -4.198 h 1.805 z m -1.804,-7.546 c -0.729,-0.351 -1.563,-0.526 -2.5,-0.526 -2.063,0 -3.094,1.097 -3.094,3.29 0,2.597 1.03,3.895 3.094,3.895 0.938,0 1.771,-0.127 2.5,-0.38 z"
+           id="path38"
+           style="fill:#244471;fill-opacity:1" />
+        <path
+           fill="#ffffff"
+           d="m 398.341,112.857 v 1.708 h -1.806 v -1.708 z m 0,3.71 v 10.25 h -1.806 v -10.25 z"
+           id="path39"
+           style="fill:#244471;fill-opacity:1" />
+        <path
+           fill="#ffffff"
+           d="m 414.302,126.816 c 0,2.474 -1.57,3.709 -4.713,3.709 -1.265,0 -2.384,-0.163 -3.359,-0.487 v -1.465 c 0.996,0.326 2.121,0.488 3.379,0.488 1.926,0 2.889,-0.749 2.889,-2.245 v -0.487 c -0.768,0.325 -1.594,0.487 -2.479,0.487 -3.24,0 -4.859,-1.728 -4.859,-5.183 0,-3.377 1.707,-5.066 5.123,-5.066 1.387,0 2.728,0.141 4.021,0.42 z m -1.806,-8.511 c -0.618,-0.156 -1.383,-0.234 -2.295,-0.234 -2.18,0 -3.27,1.182 -3.27,3.543 0,2.428 1.031,3.642 3.094,3.642 0.938,0 1.762,-0.175 2.471,-0.527 z"
+           id="path40"
+           style="fill:#244471;fill-opacity:1" />
+        <path
+           fill="#ffffff"
+           d="m 423.408,112.857 v 1.708 h -1.805 v -1.708 z m 0,3.71 v 10.25 h -1.805 v -10.25 z"
+           id="path41"
+           style="fill:#244471;fill-opacity:1" />
+        <path
+           fill="#ffffff"
+           d="m 430.712,114.908 h 1.133 l 0.391,1.658 h 2.771 v 1.464 h -2.488 v 5.887 c 0,0.957 0.412,1.435 1.238,1.435 h 1.25 v 1.464 h -1.72 c -1.717,0 -2.575,-0.921 -2.575,-2.763 z"
+           id="path42"
+           style="fill:#244471;fill-opacity:1" />
+        <path
+           fill="#ffffff"
+           d="m 440.99,123.722 c 0,-2.102 1.388,-3.153 4.158,-3.153 0.893,0 1.783,0.065 2.676,0.195 v -0.966 c 0,-1.178 -0.922,-1.768 -2.764,-1.768 -1.055,0 -2.135,0.163 -3.24,0.488 v -1.464 c 1.105,-0.326 2.187,-0.488 3.24,-0.488 3.045,0 4.568,1.062 4.568,3.183 v 7.066 h -1.017 l -0.625,-1.015 c -1.021,0.677 -2.133,1.015 -3.338,1.015 -2.436,0.001 -3.658,-1.03 -3.658,-3.093 z m 4.158,-1.689 c -1.568,0 -2.352,0.553 -2.352,1.659 0,1.107 0.616,1.659 1.854,1.659 1.25,0 2.307,-0.332 3.174,-0.996 v -2.128 c -0.892,-0.128 -1.783,-0.194 -2.676,-0.194 z"
+           id="path43"
+           style="fill:#244471;fill-opacity:1" />
+        <path
+           fill="#ffffff"
+           d="m 458.639,112.857 v 13.959 h -1.808 v -13.959 z"
+           id="path44"
+           style="fill:#244471;fill-opacity:1" />
+        <path
+           fill="#ffffff"
+           d="m 473.779,116.567 h 1.826 l 1.814,8.034 2.666,-8.034 h 1.629 l 2.852,8.034 1.639,-8.034 h 1.914 l -2.674,10.25 h -1.649 l -2.938,-7.663 -2.793,7.663 h -1.688 z"
+           id="path45"
+           style="fill:#244471;fill-opacity:1" />
+        <path
+           fill="#ffffff"
+           d="m 493.615,121.692 c 0,-3.417 1.625,-5.125 4.879,-5.125 3.254,0 4.881,1.708 4.881,5.125 0,3.41 -1.627,5.115 -4.881,5.115 -3.239,0 -4.866,-1.705 -4.879,-5.115 z m 4.879,3.66 c 2.052,0 3.076,-1.232 3.076,-3.699 0,-2.415 -1.024,-3.622 -3.076,-3.622 -2.049,0 -3.073,1.207 -3.073,3.622 0,2.466 1.024,3.699 3.073,3.699 z"
+           id="path46"
+           style="fill:#244471;fill-opacity:1" />
+        <path
+           fill="#ffffff"
+           d="m 509.994,126.816 v -10.25 h 1.222 l 0.321,1.309 c 0.898,-0.872 1.979,-1.309 3.24,-1.309 v 1.503 c -1.223,0 -2.215,0.434 -2.977,1.299 v 7.447 z"
+           id="path47"
+           style="fill:#244471;fill-opacity:1" />
+        <path
+           fill="#ffffff"
+           d="m 522.664,112.857 v 13.959 h -1.805 v -13.959 z"
+           id="path48"
+           style="fill:#244471;fill-opacity:1" />
+        <path
+           fill="#ffffff"
+           d="m 538.557,126.202 c -1.242,0.409 -2.775,0.614 -4.599,0.614 -3.053,0 -4.577,-1.775 -4.577,-5.33 0,-3.279 1.62,-4.92 4.86,-4.92 0.886,0 1.722,0.163 2.508,0.488 v -4.198 h 1.808 z m -1.807,-7.546 c -0.729,-0.351 -1.561,-0.526 -2.497,-0.526 -2.063,0 -3.095,1.097 -3.095,3.29 0,2.597 1.031,3.895 3.095,3.895 0.938,0 1.77,-0.127 2.497,-0.38 z"
+           id="path49"
+           style="fill:#244471;fill-opacity:1" />
+      </g>
+    </g>
+  </g>
+</svg>
diff --git a/public/tux.png b/public/images/tux.png
similarity index 100%
rename from public/tux.png
rename to public/images/tux.png
diff --git a/public/images/vseth-inv.svg b/public/images/vseth-inv.svg
new file mode 100755
index 0000000000000000000000000000000000000000..a0f302df6c2e77c18f75fe833434d20f11ff2d5e
--- /dev/null
+++ b/public/images/vseth-inv.svg
@@ -0,0 +1,140 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   width="344.50601"
+   height="64.655998"
+   viewBox="0 0 344.50601 64.655998"
+   version="1.1"
+   xml:space="preserve"
+   style="clip-rule:evenodd;fill-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421"
+   id="svg45"
+   sodipodi:docname="vseth-inv.svg"
+   inkscape:version="1.3 (0e150ed6c4, 2023-07-21)"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:svg="http://www.w3.org/2000/svg"><defs
+     id="defs45" /><sodipodi:namedview
+     id="namedview45"
+     pagecolor="#ffffff"
+     bordercolor="#000000"
+     borderopacity="0.25"
+     inkscape:showpageshadow="2"
+     inkscape:pageopacity="0.0"
+     inkscape:pagecheckerboard="0"
+     inkscape:deskcolor="#d1d1d1"
+     inkscape:zoom="1.4931818"
+     inkscape:cx="173.12025"
+     inkscape:cy="37.838661"
+     inkscape:window-width="1920"
+     inkscape:window-height="1011"
+     inkscape:window-x="0"
+     inkscape:window-y="0"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="g45" /><g
+     id="g45"
+     transform="translate(-46.646,-40.293)"><path
+       d="m 175.77,70.484 c -1.219,-2.697 -3.741,-4.697 -7.571,-4.697 -3.828,0 -6.349,2 -7.568,4.697 -0.695,1.654 -0.957,2.871 -1.045,4.873 h 17.228 c -0.087,-2.002 -0.349,-3.219 -1.044,-4.873 z m -16.184,12.615 c 0,5.83 3.568,10.094 9.92,10.094 4.959,0 7.394,-1.393 10.265,-4.264 l 6.874,6.7 c -4.612,4.611 -9.047,7.134 -17.227,7.134 -10.701,0 -20.969,-4.873 -20.969,-23.23 0,-14.791 8.006,-23.143 19.75,-23.143 12.617,0 19.75,9.223 19.75,21.664 v 5.045 z"
+       style="fill:#ffffff;fill-rule:nonzero"
+       id="path1" /><path
+       d="m 212.568,102.242 c -9.222,0 -13.138,-6.525 -13.138,-12.965 V 66.83 h -4.785 v -8.613 h 4.785 V 44.818 h 11.31 v 13.399 h 8.006 v 8.613 h -8.006 v 21.752 c 0,2.609 1.219,4.09 3.916,4.09 h 4.09 v 9.57 z"
+       style="fill:#ffffff;fill-rule:nonzero"
+       id="path2" /><path
+       d="M 255.023,102.242 V 74.574 c 0,-6.004 -3.828,-8.004 -7.394,-8.004 -3.569,0 -7.309,2.088 -7.309,8.004 v 27.668 H 229.01 V 40.293 h 11.31 v 20.795 c 3.045,-3.133 6.873,-4.698 10.875,-4.698 9.918,0 15.139,6.959 15.139,16.53 v 29.322 z"
+       style="fill:#ffffff;fill-rule:nonzero"
+       id="path3" /><path
+       d="M 71.929,100.839 H 63.156 L 46.646,56.035 h 11.781 l 9.115,27.691 9.03,-27.691 h 11.782 z"
+       style="fill:#ffffff;fill-rule:nonzero"
+       id="path4" /><path
+       d="m 115.763,51.367 c -14.774,0 -26.794,12.11 -26.794,26.996 0,12.459 8.422,22.968 19.831,26.066 v -0.047 c 1.611,0.391 3.347,0.567 5.068,0.567 3.65,0 7.234,-0.791 9.4,-1.999 3.405,-1.9 5.704,-4.468 6.832,-7.635 1.208,-3.393 1.083,-6.737 -0.376,-9.937 -0.764,-1.668 -1.971,-3.376 -3.594,-5.079 l -3.399,-3.557 c -3.402,-3.553 -4.615,-5.223 -5.048,-6.022 -0.497,-0.88 -0.991,-2.206 -0.526,-3.513 0.26,-0.732 1.045,-2.111 3.381,-3.139 1.365,-0.6 2.113,-0.723 2.414,-0.745 l 0.754,-2.944 c -4.119,-1.227 -12.647,-1.104 -16.506,7.928 -1.139,2.659 -1.191,5.556 -0.156,8.377 0.912,2.49 2.851,5.272 5.93,8.503 l 2.931,3.084 c 2.131,2.227 2.916,3.363 3.195,3.917 0.538,1.081 0.575,2.234 0.116,3.527 -0.426,1.193 -1.045,1.937 -2.209,2.652 -0.647,0.396 -4.106,2.304 -8.848,0.935 v 10e-4 C 99.385,96.175 93.098,87.815 93.098,77.968 c 0,-12.517 10.147,-22.664 22.665,-22.664 12.517,0 22.664,10.147 22.664,22.664 0,4.342 -1.223,8.397 -3.34,11.844 l 3.107,3.291 c 2.755,-4.242 4.364,-9.303 4.364,-14.74 0,-14.886 -12.021,-26.996 -26.795,-26.996 z"
+       style="fill:#009fe3;fill-rule:nonzero"
+       id="path5" /><path
+       d="m 295.412,57.294 h -1.881 l -2.706,8.547 -2.706,-8.547 h -1.848 l 3.861,11.748 h 1.386 z"
+       style="fill:#009fe3;fill-rule:nonzero"
+       id="path16" /><path
+       d="m 303.609,65.346 v -0.743 c 0,-2.376 -1.303,-4.026 -3.547,-4.026 -2.145,0 -3.548,1.568 -3.548,4.274 0,3.184 1.667,4.29 3.762,4.29 1.469,0 2.277,-0.446 3.135,-1.304 l -1.072,-1.006 c -0.594,0.594 -1.089,0.858 -2.03,0.858 -1.369,0 -2.128,-0.908 -2.128,-2.343 z m -1.666,-1.172 h -3.762 c 0.016,-0.511 0.049,-0.759 0.214,-1.138 0.264,-0.627 0.875,-1.056 1.667,-1.056 0.792,0 1.386,0.429 1.65,1.056 0.165,0.379 0.214,0.627 0.231,1.138 z"
+       style="fill:#009fe3;fill-rule:nonzero"
+       id="path17" /><path
+       d="m 312.28,61.369 c -0.578,-0.577 -1.188,-0.792 -1.997,-0.792 -0.94,0 -1.798,0.413 -2.227,1.007 v -0.908 h -1.65 v 8.366 h 1.683 V 63.96 c 0,-1.155 0.759,-1.881 1.666,-1.881 0.578,0 0.875,0.181 1.254,0.561 z"
+       style="fill:#009fe3;fill-rule:nonzero"
+       id="path18" /><path
+       d="m 321.385,64.851 c 0,-1.271 -0.099,-2.69 -0.941,-3.531 -0.462,-0.462 -1.188,-0.743 -2.029,-0.743 -0.891,0 -1.584,0.215 -2.195,0.941 v -4.224 h -1.683 v 11.748 h 1.65 v -0.891 c 0.627,0.759 1.304,0.99 2.211,0.99 0.842,0 1.584,-0.281 2.046,-0.743 0.842,-0.841 0.941,-2.277 0.941,-3.547 z m -1.683,0 c 0,1.485 -0.215,2.788 -1.733,2.788 -1.518,0 -1.749,-1.303 -1.749,-2.788 0,-1.485 0.231,-2.772 1.749,-2.772 1.518,0 1.733,1.287 1.733,2.772 z"
+       style="fill:#009fe3;fill-rule:nonzero"
+       id="path19" /><path
+       d="m 330.537,69.042 v -5.594 c 0,-1.897 -1.155,-2.871 -3.449,-2.871 -1.386,0 -2.211,0.281 -3.003,1.205 l 1.106,1.039 c 0.462,-0.594 0.907,-0.808 1.831,-0.808 1.304,0 1.832,0.511 1.832,1.567 v 0.594 h -2.211 c -1.914,0 -2.888,1.007 -2.888,2.409 0,0.71 0.231,1.353 0.66,1.799 0.512,0.511 1.205,0.759 2.244,0.759 1.04,0 1.617,-0.248 2.228,-0.858 v 0.759 z m -1.683,-3.02 c 0,0.594 -0.116,0.99 -0.363,1.238 -0.446,0.429 -0.924,0.478 -1.568,0.478 -1.056,0 -1.534,-0.429 -1.534,-1.188 0,-0.759 0.511,-1.204 1.501,-1.204 h 1.964 z"
+       style="fill:#009fe3;fill-rule:nonzero"
+       id="path20" /><path
+       d="m 340.469,69.042 v -5.346 c 0,-0.941 -0.198,-1.733 -0.842,-2.36 -0.495,-0.478 -1.204,-0.759 -2.062,-0.759 -0.842,0 -1.65,0.314 -2.228,0.941 v -0.842 h -1.65 v 8.366 h 1.683 v -5.099 c 0,-1.287 0.792,-1.864 1.733,-1.864 0.94,0 1.683,0.561 1.683,1.864 v 5.099 z"
+       style="fill:#009fe3;fill-rule:nonzero"
+       id="path21" /><path
+       d="M 350.143,69.042 V 57.294 h -1.683 v 4.224 c -0.611,-0.726 -1.304,-0.941 -2.195,-0.941 -0.841,0 -1.567,0.281 -2.029,0.743 -0.842,0.841 -0.941,2.26 -0.941,3.531 0,1.27 0.099,2.706 0.941,3.547 0.462,0.462 1.204,0.743 2.046,0.743 0.907,0 1.584,-0.231 2.211,-0.99 v 0.891 z m -1.683,-4.191 c 0,1.485 -0.215,2.788 -1.733,2.788 -1.518,0 -1.749,-1.303 -1.749,-2.788 0,-1.485 0.231,-2.772 1.749,-2.772 1.518,0 1.733,1.287 1.733,2.772 z"
+       style="fill:#009fe3;fill-rule:nonzero"
+       id="path22" /><path
+       d="M 364.547,69.042 V 57.294 h -1.683 v 4.224 c -0.611,-0.726 -1.304,-0.941 -2.195,-0.941 -0.841,0 -1.567,0.281 -2.029,0.743 -0.842,0.841 -0.941,2.26 -0.941,3.531 0,1.27 0.099,2.706 0.941,3.547 0.462,0.462 1.204,0.743 2.046,0.743 0.907,0 1.584,-0.231 2.211,-0.99 v 0.891 z m -1.683,-4.191 c 0,1.485 -0.215,2.788 -1.733,2.788 -1.518,0 -1.749,-1.303 -1.749,-2.788 0,-1.485 0.231,-2.772 1.749,-2.772 1.518,0 1.733,1.287 1.733,2.772 z"
+       style="fill:#009fe3;fill-rule:nonzero"
+       id="path23" /><path
+       d="m 374.47,65.346 v -0.743 c 0,-2.376 -1.303,-4.026 -3.547,-4.026 -2.145,0 -3.548,1.568 -3.548,4.274 0,3.184 1.667,4.29 3.762,4.29 1.469,0 2.277,-0.446 3.135,-1.304 L 373.2,66.831 c -0.594,0.594 -1.089,0.858 -2.03,0.858 -1.369,0 -2.128,-0.908 -2.128,-2.343 z m -1.666,-1.172 h -3.762 c 0.016,-0.511 0.049,-0.759 0.214,-1.138 0.264,-0.627 0.875,-1.056 1.667,-1.056 0.792,0 1.386,0.429 1.65,1.056 0.165,0.379 0.214,0.627 0.231,1.138 z"
+       style="fill:#009fe3;fill-rule:nonzero"
+       id="path24" /><path
+       d="m 383.141,61.369 c -0.578,-0.577 -1.188,-0.792 -1.997,-0.792 -0.94,0 -1.798,0.413 -2.227,1.007 v -0.908 h -1.65 v 8.366 h 1.683 V 63.96 c 0,-1.155 0.759,-1.881 1.666,-1.881 0.578,0 0.875,0.181 1.254,0.561 z"
+       style="fill:#009fe3;fill-rule:nonzero"
+       id="path25" /><path
+       d="m 295.066,82.692 c 0,-1.006 -0.314,-1.848 -0.957,-2.409 -0.495,-0.445 -1.106,-0.709 -2.195,-0.874 l -1.336,-0.198 c -0.545,-0.083 -1.023,-0.281 -1.32,-0.545 -0.314,-0.28 -0.446,-0.66 -0.446,-1.089 0,-1.039 0.759,-1.831 2.145,-1.831 0.99,0 1.832,0.214 2.558,0.907 l 1.138,-1.122 c -1.006,-0.94 -2.095,-1.336 -3.646,-1.336 -2.442,0 -3.927,1.402 -3.927,3.448 0,0.957 0.28,1.7 0.858,2.244 0.511,0.479 1.27,0.809 2.227,0.941 l 1.386,0.198 c 0.693,0.099 0.99,0.214 1.287,0.495 0.314,0.28 0.462,0.709 0.462,1.221 0,1.138 -0.891,1.798 -2.425,1.798 -1.205,0 -2.145,-0.264 -3.003,-1.122 l -1.188,1.172 c 1.122,1.138 2.392,1.551 4.158,1.551 2.458,0 4.224,-1.287 4.224,-3.449 z"
+       style="fill:#009fe3;fill-rule:nonzero"
+       id="path26" /><path
+       d="m 301.195,86.042 v -1.436 h -0.693 c -0.627,0 -0.924,-0.363 -0.924,-0.973 v -4.521 h 1.617 v -1.287 h -1.617 v -2.541 h -1.683 v 2.541 h -0.957 v 1.287 h 0.957 v 4.603 c 0,1.205 0.726,2.327 2.293,2.327 z"
+       style="fill:#009fe3;fill-rule:nonzero"
+       id="path27" /><path
+       d="m 310.569,86.042 v -8.366 h -1.683 v 5.099 c 0,1.287 -0.792,1.864 -1.733,1.864 -0.94,0 -1.683,-0.561 -1.683,-1.864 v -5.099 h -1.683 v 5.346 c 0,0.941 0.198,1.733 0.842,2.36 0.495,0.478 1.204,0.759 2.062,0.759 0.842,0 1.65,-0.314 2.228,-0.941 v 0.842 z"
+       style="fill:#009fe3;fill-rule:nonzero"
+       id="path28" /><path
+       d="M 320.324,86.042 V 74.294 h -1.683 v 4.224 c -0.611,-0.726 -1.304,-0.941 -2.195,-0.941 -0.841,0 -1.567,0.281 -2.029,0.743 -0.842,0.841 -0.941,2.26 -0.941,3.531 0,1.27 0.099,2.706 0.941,3.547 0.462,0.462 1.204,0.743 2.046,0.743 0.907,0 1.584,-0.231 2.211,-0.99 v 0.891 z m -1.683,-4.191 c 0,1.485 -0.215,2.788 -1.733,2.788 -1.518,0 -1.749,-1.303 -1.749,-2.788 0,-1.485 0.231,-2.772 1.749,-2.772 1.518,0 1.733,1.287 1.733,2.772 z"
+       style="fill:#009fe3;fill-rule:nonzero"
+       id="path29" /><path
+       d="m 325.214,86.042 v -8.366 h -1.683 v 8.366 z m 0.05,-10.016 v -1.782 h -1.782 v 1.782 z"
+       style="fill:#009fe3;fill-rule:nonzero"
+       id="path30" /><path
+       d="m 335.096,82.346 v -0.743 c 0,-2.376 -1.303,-4.026 -3.547,-4.026 -2.145,0 -3.548,1.568 -3.548,4.274 0,3.184 1.667,4.29 3.762,4.29 1.469,0 2.277,-0.446 3.135,-1.304 l -1.072,-1.006 c -0.594,0.594 -1.089,0.858 -2.03,0.858 -1.369,0 -2.128,-0.908 -2.128,-2.343 z m -1.666,-1.172 h -3.762 c 0.016,-0.511 0.049,-0.759 0.214,-1.138 0.264,-0.627 0.875,-1.056 1.667,-1.056 0.792,0 1.386,0.429 1.65,1.056 0.165,0.379 0.214,0.627 0.231,1.138 z"
+       style="fill:#009fe3;fill-rule:nonzero"
+       id="path31" /><path
+       d="m 343.767,78.369 c -0.578,-0.577 -1.188,-0.792 -1.997,-0.792 -0.94,0 -1.798,0.413 -2.227,1.007 v -0.908 h -1.65 v 8.366 h 1.683 V 80.96 c 0,-1.155 0.759,-1.881 1.666,-1.881 0.578,0 0.875,0.181 1.254,0.561 z"
+       style="fill:#009fe3;fill-rule:nonzero"
+       id="path32" /><path
+       d="m 352.4,82.346 v -0.743 c 0,-2.376 -1.304,-4.026 -3.548,-4.026 -2.145,0 -3.547,1.568 -3.547,4.274 0,3.184 1.666,4.29 3.762,4.29 1.468,0 2.277,-0.446 3.135,-1.304 l -1.073,-1.006 c -0.594,0.594 -1.089,0.858 -2.029,0.858 -1.37,0 -2.129,-0.908 -2.129,-2.343 z m -1.667,-1.172 h -3.762 c 0.017,-0.511 0.05,-0.759 0.215,-1.138 0.264,-0.627 0.874,-1.056 1.666,-1.056 0.792,0 1.386,0.429 1.65,1.056 0.165,0.379 0.215,0.627 0.231,1.138 z"
+       style="fill:#009fe3;fill-rule:nonzero"
+       id="path33" /><path
+       d="m 361.978,86.042 v -5.346 c 0,-0.941 -0.198,-1.733 -0.842,-2.36 -0.495,-0.478 -1.204,-0.759 -2.062,-0.759 -0.842,0 -1.65,0.314 -2.228,0.941 v -0.842 h -1.65 v 8.366 h 1.683 v -5.099 c 0,-1.287 0.792,-1.864 1.733,-1.864 0.94,0 1.683,0.561 1.683,1.864 v 5.099 z"
+       style="fill:#009fe3;fill-rule:nonzero"
+       id="path34" /><path
+       d="M 371.651,86.042 V 74.294 h -1.683 v 4.224 c -0.61,-0.726 -1.303,-0.941 -2.194,-0.941 -0.842,0 -1.568,0.281 -2.03,0.743 -0.841,0.841 -0.94,2.26 -0.94,3.531 0,1.27 0.099,2.706 0.94,3.547 0.462,0.462 1.205,0.743 2.046,0.743 0.908,0 1.584,-0.231 2.211,-0.99 v 0.891 z m -1.683,-4.191 c 0,1.485 -0.214,2.788 -1.732,2.788 -1.518,0 -1.749,-1.303 -1.749,-2.788 0,-1.485 0.231,-2.772 1.749,-2.772 1.518,0 1.732,1.287 1.732,2.772 z"
+       style="fill:#009fe3;fill-rule:nonzero"
+       id="path35" /><path
+       d="m 381.574,82.346 v -0.743 c 0,-2.376 -1.303,-4.026 -3.547,-4.026 -2.145,0 -3.548,1.568 -3.548,4.274 0,3.184 1.667,4.29 3.762,4.29 1.469,0 2.277,-0.446 3.135,-1.304 l -1.072,-1.006 c -0.594,0.594 -1.089,0.858 -2.03,0.858 -1.369,0 -2.128,-0.908 -2.128,-2.343 z m -1.666,-1.172 h -3.762 c 0.016,-0.511 0.049,-0.759 0.214,-1.138 0.264,-0.627 0.875,-1.056 1.667,-1.056 0.792,0 1.386,0.429 1.65,1.056 0.165,0.379 0.214,0.627 0.231,1.138 z"
+       style="fill:#009fe3;fill-rule:nonzero"
+       id="path36" /><path
+       d="m 391.152,86.042 v -5.346 c 0,-0.941 -0.198,-1.733 -0.841,-2.36 -0.495,-0.478 -1.205,-0.759 -2.063,-0.759 -0.841,0 -1.65,0.314 -2.227,0.941 v -0.842 h -1.65 v 8.366 h 1.683 v -5.099 c 0,-1.287 0.792,-1.864 1.732,-1.864 0.941,0 1.683,0.561 1.683,1.864 v 5.099 z"
+       style="fill:#009fe3;fill-rule:nonzero"
+       id="path37" /><path
+       d="m 293.68,102.041 v -5.593 c 0,-1.898 -1.155,-2.871 -3.449,-2.871 -1.386,0 -2.211,0.28 -3.003,1.204 l 1.106,1.04 c 0.462,-0.594 0.907,-0.809 1.831,-0.809 1.304,0 1.832,0.512 1.832,1.568 v 0.594 h -2.211 c -1.914,0 -2.888,1.006 -2.888,2.409 0,0.709 0.231,1.353 0.66,1.798 0.512,0.512 1.205,0.759 2.244,0.759 1.04,0 1.617,-0.247 2.228,-0.858 v 0.759 z m -1.683,-3.019 c 0,0.594 -0.116,0.99 -0.363,1.237 -0.446,0.429 -0.924,0.479 -1.568,0.479 -1.056,0 -1.534,-0.429 -1.534,-1.188 0,-0.759 0.511,-1.205 1.501,-1.205 h 1.964 z"
+       style="fill:#009fe3;fill-rule:nonzero"
+       id="path38" /><path
+       d="m 303.611,102.042 v -5.346 c 0,-0.941 -0.198,-1.733 -0.841,-2.36 -0.495,-0.478 -1.205,-0.759 -2.063,-0.759 -0.841,0 -1.65,0.314 -2.227,0.941 v -0.842 h -1.65 v 8.366 h 1.683 v -5.099 c 0,-1.287 0.792,-1.864 1.732,-1.864 0.941,0 1.683,0.561 1.683,1.864 v 5.099 z"
+       style="fill:#009fe3;fill-rule:nonzero"
+       id="path39" /><path
+       d="M 317.933,102.042 V 90.294 h -1.683 v 4.224 c -0.61,-0.726 -1.303,-0.941 -2.194,-0.941 -0.842,0 -1.568,0.281 -2.03,0.743 -0.841,0.841 -0.94,2.26 -0.94,3.531 0,1.27 0.099,2.706 0.94,3.547 0.462,0.462 1.205,0.743 2.046,0.743 0.908,0 1.584,-0.231 2.211,-0.99 v 0.891 z m -1.683,-4.191 c 0,1.485 -0.214,2.788 -1.732,2.788 -1.518,0 -1.749,-1.303 -1.749,-2.788 0,-1.485 0.231,-2.772 1.749,-2.772 1.518,0 1.732,1.287 1.732,2.772 z"
+       style="fill:#009fe3;fill-rule:nonzero"
+       id="path40" /><path
+       d="m 327.856,98.346 v -0.743 c 0,-2.376 -1.303,-4.026 -3.547,-4.026 -2.145,0 -3.548,1.568 -3.548,4.274 0,3.184 1.667,4.29 3.762,4.29 1.469,0 2.277,-0.446 3.135,-1.304 l -1.072,-1.006 c -0.594,0.594 -1.089,0.858 -2.03,0.858 -1.369,0 -2.128,-0.908 -2.128,-2.343 z m -1.666,-1.172 h -3.762 c 0.016,-0.511 0.049,-0.759 0.214,-1.138 0.264,-0.627 0.875,-1.056 1.667,-1.056 0.792,0 1.386,0.429 1.65,1.056 0.165,0.379 0.214,0.627 0.231,1.138 z"
+       style="fill:#009fe3;fill-rule:nonzero"
+       id="path41" /><path
+       d="m 336.526,94.369 c -0.577,-0.577 -1.188,-0.792 -1.996,-0.792 -0.941,0 -1.799,0.413 -2.228,1.007 v -0.908 h -1.65 v 8.366 h 1.683 V 96.96 c 0,-1.155 0.759,-1.881 1.667,-1.881 0.577,0 0.874,0.181 1.254,0.561 z"
+       style="fill:#009fe3;fill-rule:nonzero"
+       id="path42" /><path
+       d="m 350.881,102.042 v -1.601 h -5.725 V 96.91 h 4.884 v -1.584 h -4.884 v -3.432 h 5.725 v -1.6 h -7.507 v 11.748 z"
+       style="fill:#009fe3;fill-rule:nonzero"
+       id="path43" /><path
+       d="m 361.537,91.894 v -1.6 h -8.25 v 1.6 h 3.234 v 10.148 h 1.782 V 91.894 Z"
+       style="fill:#009fe3;fill-rule:nonzero"
+       id="path44" /><path
+       d="M 372.585,102.042 V 90.294 h -1.782 v 5.016 h -4.768 v -5.016 h -1.782 v 11.748 h 1.782 V 96.91 h 4.768 v 5.132 z"
+       style="fill:#009fe3;fill-rule:nonzero"
+       id="path45" /></g></svg>
diff --git a/public/locales/de/common.json b/public/locales/de/common.json
new file mode 100644
index 0000000000000000000000000000000000000000..48d63715de96de6339f164eb5a1b3f0733bfdaba
--- /dev/null
+++ b/public/locales/de/common.json
@@ -0,0 +1,44 @@
+{
+  "main": "Main",
+  "bashGuide": "Bash Guide",
+  "installGuide": "Install Guide",
+  "courses": "Kursmaterialien",
+  "events": "Events",
+  "about": "Wer wir Sind",
+  "aboutUs": "Ãœber Uns",
+  "contact": "Kontakt",
+  "name": "Name",
+  "mail": "Mail",
+  "message": "Nachricht",
+  "human": "Ich bin ein Mensch",
+  "robot": "Ich bin ein Roboter",
+  "submit": "Absenden",
+  "formIncomplete": "Formular Unvollständig",
+  "formIncompleteText": "Bitte fülle das gesamte Formular aus.",
+  "mailSuccess": "Formular Versandt",
+  "mailSuccessText": "Das Formular wurde erfolgreich versandt.",
+  "mailFailure": "Fehler",
+  "mailFailureText": "Etwas ist beim Versand des Formulars schiefgelaufen.",
+  "addEvent": "Event Hinzufügen",
+  "editEvent": "Event Bearbeiten",
+  "ENotEmpty": "Dieses Feld bitte ausfüllen",
+  "noAdblockTitle": "Kein Adblocker Installiert!",
+  "noAdblockText": "Du hast deinen Adblocker ausgeschaltet oder keinen installiert! Installiere jetzt einen für <a target='_blank' href='https://addons.mozilla.org/de/firefox/addon/ublock-origin/'>Firefox</a> oder <a target='_blank' href='https://chrome.google.com/webstore/detail/ublock-origin/cjpalhdlnbpafiamejdnhcphjbkeiagm?hl=de'>Chrome</a>. Weil <a href='#philosophy'>Datenschutz</a> ein Menschenrecht ist.",
+  "stammtisch": "Stammtisch",
+  "date": "Datum",
+  "time": "Zeit",
+  "title": "Titel",
+  "speaker": "Sprecher*in",
+  "description": "Beschreibung",
+  "place": "Ort",
+  "signUpLink": "Anmdeldelink (falls extern)",
+  "signUp": "Anmelden",
+  "externalSignUp": "Anmelden (extern)",
+  "signedUpTitle": "Angemeldet",
+  "signedUpText": "Du bist für dieses Event angemeldet.",
+  "signOff": "Abmelden",
+  "viewParticipants": "Teilnehmendenliste",
+  "participants": "Teilnehmendenliste",
+  "copyMailAddresses": "Mailadressen Kopieren",
+  "loadTemplate": "Template Laden"
+}
\ No newline at end of file
diff --git a/public/locales/en/common.json b/public/locales/en/common.json
new file mode 100644
index 0000000000000000000000000000000000000000..653fc69799f74accb3875e4ab6ca68f4245a7a18
--- /dev/null
+++ b/public/locales/en/common.json
@@ -0,0 +1,44 @@
+{
+  "main": "Main",
+  "bashGuide": "Bash Guide",
+  "installGuide": "Install Guide",
+  "courses": "Courses",
+  "events": "Events",
+  "about": "Who we Are",
+  "aboutUs": "About Us",
+  "contact": "Contact",
+  "name": "Name",
+  "mail": "Mail",
+  "message": "Message",
+  "human": "I am a human",
+  "robot": "I am a robot",
+  "submit": "Submit",
+  "formIncomplete": "Form Incomplete",
+  "formIncompleteText": "Please fill out the entire form",
+  "mailSuccess": "Form Sent",
+  "mailSuccessText": "The form was successfully sent",
+  "mailFailure": "Error",
+  "mailFailureText": "Something went wrong when sending the form",
+  "addEvent": "Add Event",
+  "editEvent": "Edit Event",
+  "ENotEmpty": "Please fill out this field",
+  "noAdblockTitle": "No Adblocker Installed",
+  "noAdblockText": "You have turned off or did not install an Adblocker! Install it now for <a target='_blank' href='https://addons.mozilla.org/de/firefox/addon/ublock-origin/'>Firefox</a> or <a target='_blank' href='https://chrome.google.com/webstore/detail/ublock-origin/cjpalhdlnbpafiamejdnhcphjbkeiagm?hl=de'>Chrome</a>. Because <a href='#philosophy'>privacy</a> is a human right.",
+  "stammtisch": "Stammtisch",
+  "date": "Date",
+  "time": "Time",
+  "title": "Title",
+  "speaker": "Speaker",
+  "description": "Description",
+  "place": "Place",
+  "signUpLink": "Sign Up Link (if external)",
+  "signUp": "Sign Up",
+  "externalSignUp": "Sign Up (external)",
+  "signedUpTitle": "Signed Up",
+  "signedUpText": "You are signed up to this event",
+  "signOff": "Sign Off",
+  "viewParticipants": "View Participants",
+  "participants": "Participants",
+  "copyMailAddresses": "Copy Mail Addresses",
+  "loadTemplate": "Load Template"
+}
\ No newline at end of file
diff --git a/sip.yml b/sip.yml
index 2777d57e2830a3bfceafa1aee70b5077988766f0..7bb02e93279d4eab6938fc31bed2534890d05b9f 100644
--- a/sip.yml
+++ b/sip.yml
@@ -14,7 +14,7 @@ auth:
   accessType: confidential
   clientProtocol: openid-connect
   validRedirectURIs:
-   - https://website.alt.staging-sip.ethz.ch/*
+   - https://www.thealt.staging-sip.ethz.ch/*
    - https://thealternative.ethz.ch/*
    - http://localhost/*
   scopes:
@@ -39,5 +39,21 @@ env:
   secret:
     key: nextauthSecret
     create: provided
+- name: MAILER_USERNAME
+  secret:
+    key: mailerUsername
+    create: provided
+- name: MAILER_PASSWORD
+  secret:
+    key: mailerPassword
+    create: provided
+- name: MAILER_HOST
+  secret:
+    key: mailerHost
+    create: provided
+- name: MAILER_NAME
+  secret:
+    key: mailerName
+    create: provided
 
 replicas: 1
diff --git a/styles/globals.css b/styles/globals.css
index 0e503cc1442085a3548f00c1938b4a0ab3a28d53..913d8e331cfa11c90ce13b4dc1df4763255c9188 100644
--- a/styles/globals.css
+++ b/styles/globals.css
@@ -14,13 +14,21 @@ h3 {
   margin: 0;
 }
 
+.mantine-AppShell-main {
+  padding-bottom: 0;
+}
+
 .light {
   padding-top: 50px;
   padding-bottom: 50px;
 }
 
+a {
+  color: #f28a20;
+}
+
 .light a {
-  color: #244471;
+  color: #f28a20;
 }
 
 .dark {
@@ -31,6 +39,10 @@ h3 {
 }
 
 .dark a {
+  color: #f28a20;
+}
+
+.dark blockquote {
   color: white;
 }
 
@@ -38,6 +50,10 @@ body {
   margin: 0;
 }
 
+p {
+  margin-bottom: .5em;
+}
+
 .mantine-Select-label {
   font-family: "Source Sans Pro";
 }
@@ -95,3 +111,53 @@ body {
 .blogPost p {
   margin-top: 0.5rem;
 }
+
+.ol-rotate {
+  display: none;
+}
+
+.ol-attribution button {
+  display: none;
+}
+
+.ol-overlaycontainer-stopevent {
+  display: flex;
+  flex-direction: column;
+  justify-content: space-between;
+}
+
+.ol-attribution {
+  background-color: white;
+  opacity: 0.8;
+  color: black;
+}
+
+.header-section-number {
+  color: #767676;
+  font-size: 0.6em;
+}
+
+.bash-guide p {
+  margin-top: 10px;
+}
+
+.bash-guide pre {
+  background-color: #eeeeee;
+  padding: 0.5rem;
+}
+
+.bash-guide p>code {
+  color: #888888;
+}
+
+.vseth-footer-dark {
+  background-color: #1A1B1E !important;
+}
+
+.vseth-logo-dark {
+  content: url("/images/vseth-inv.svg");
+}
+
+.mantine-wvcbqp {
+  color: inherit !important;
+}
diff --git a/thealternative.config.js b/thealternative.config.js
new file mode 100644
index 0000000000000000000000000000000000000000..8e8fc8fc9dc05e23dd39a1fafad7306bb24a0e43
--- /dev/null
+++ b/thealternative.config.js
@@ -0,0 +1,6 @@
+const config = {
+  subject: "TheAlternative Contact Request by NAME",
+  address: "board@thealternative.ch"
+};
+
+export default config;
diff --git a/utilities/colors.js b/utilities/colors.js
new file mode 100644
index 0000000000000000000000000000000000000000..0a08ce9cc9177dbf1c737155584dd666ef6b0323
--- /dev/null
+++ b/utilities/colors.js
@@ -0,0 +1,3 @@
+export function getAccentColor(theme) {
+  return theme.colorScheme === "dark" ? "white" : "#244471";
+}
diff --git a/utilities/dates.js b/utilities/dates.js
new file mode 100644
index 0000000000000000000000000000000000000000..36d8bc7f80f2714445471528364221405e01d82d
--- /dev/null
+++ b/utilities/dates.js
@@ -0,0 +1,24 @@
+import dayjs from "dayjs";
+
+const customParseFormat = require("dayjs/plugin/customParseFormat");
+dayjs.extend(customParseFormat);
+
+require("dayjs/locale/en");
+require("dayjs/locale/de");
+
+export function formatDateFromDB(date, locale) {
+  dayjs.locale(locale);
+  const d = dayjs(date);
+  return locale == "de" ? d.format("dd, DD.MM.YY") : d.format("ddd, DD.MM.YY");
+}
+
+export function formatTimeFromDB(startTime, endTime) {
+  const s = dayjs(startTime);
+  const e = dayjs(endTime);
+  return s.format("HH:mm") + " — " + e.format("HH:mm");
+}
+
+export function isInFuture(event) {
+  // TODO: implement logic
+  return true;
+}
diff --git a/utilities/hasAccess.js b/utilities/hasAccess.js
index ed8851d73a90af1a366962244c8d9e5c411aa6b9..3437edcfde839bfebf7991ec0107bbcdedd43026 100644
--- a/utilities/hasAccess.js
+++ b/utilities/hasAccess.js
@@ -1,8 +1,9 @@
 export default function hasAccess(session, admin) {
-  const stag_role = "pub_staging_papperlaweb_papperlaweb";
-  const prod_role = "pub_prod_papperlaweb_papperlaweb";
+  const stag_role = "thealt_staging_website_website";
+  const prod_role = "thealt_prod_website_website";
 
   // this is just for development purposes
+  return true;
   return session ? true : false;
 
   if (process.env.NODE_ENV && process.env.NODE_ENV === "development")
diff --git a/utilities/signUp.js b/utilities/signUp.js
new file mode 100644
index 0000000000000000000000000000000000000000..987759476d786eec97df45b1844c18635c47ba1f
--- /dev/null
+++ b/utilities/signUp.js
@@ -0,0 +1,8 @@
+export function isRegistered(session, event) {
+  if (!session) return false;
+  const matches = event.signUps.filter(
+    (signUp) => signUp.sub === session.info.payload.sub
+  );
+  if (matches.length > 0) return true;
+  return false;
+}