diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index d46b1ce3f57dfd37544ba1f8f67745c61b3f3d1e..410d408a7856af6a913a558e1e9f2d8462e465a9 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -9,6 +9,11 @@ and this project adheres to `Semantic Versioning`_.
 Unreleased
 ----------
 
+Changed
+~~~~~~~
+
+* Optimize view for one register object ("lesson view") for mobile and tablet devices.
+
 Fixed
 ~~~~~
 
diff --git a/aleksis/apps/alsijil/static/css/alsijil/lesson.css b/aleksis/apps/alsijil/static/css/alsijil/lesson.css
index d402156fc7bc1f750e88a5a9c04bf46fa2fd0d5b..f61bde7667661caf578f3178518bd48be6fc75da 100644
--- a/aleksis/apps/alsijil/static/css/alsijil/lesson.css
+++ b/aleksis/apps/alsijil/static/css/alsijil/lesson.css
@@ -23,6 +23,55 @@
       height: 109px;}
 }
 
-.alsijil-top-button {
-    margin-top: -20px;
+.alsijil-time-head, .alsijil-object-head {
+    display: block;
 }
+
+.alsijil-time-head {
+    font-size: 2rem;
+    line-height: 1.1;
+}
+
+.alsijil-object-head {
+    font-size: 3rem;
+}
+
+@media only screen and (max-width: 600px) {
+    .alsijil-time-head {
+        font-size: 1.5rem;
+    }
+
+    .alsijil-object-head {
+        font-size: 2.2rem;
+        line-height: 1.4;
+    }
+}
+
+.alsijil-nav {
+    line-height: 36px;
+}
+
+.alsijil-header-nav-button {
+    height: 66px;
+    padding: 0;
+}
+
+.alsijil-header-nav-button.left {
+    margin-right: 5px;
+}
+
+.alsijil-header-nav-button.right {
+    margin-left: 5px;
+}
+
+.alsijil-header-nav-button i.material-icons {
+    line-height: 60px;
+    height: 60px;
+    font-size: 40px;
+}
+
+.alsijil-nav-header {
+    width: calc(100% + 40px);
+    padding: 10px 20px;
+    margin: -10px -20px 0;
+}
\ No newline at end of file
diff --git a/aleksis/apps/alsijil/tables.py b/aleksis/apps/alsijil/tables.py
index f4f064450fba28100e1ee9c775c12cd2db03776c..1aaabe732c8fab0b6d13a7a530a46d44c26e9a52 100644
--- a/aleksis/apps/alsijil/tables.py
+++ b/aleksis/apps/alsijil/tables.py
@@ -192,15 +192,15 @@ class RegisterObjectTable(tables.Table):
     group_note = tables.Column(linkify=_get_link)
 
     def render_status(self, value, record):
-        return render_to_string(
-            "alsijil/partials/lesson_status_icon.html",
-            dict(
-                week=record.get("week"),
-                has_documentation=record.get("has_documentation", False),
-                substitution=record.get("substitution"),
-                register_object=value,
-            ),
-        )
+        context = {
+            "has_documentation": record.get("has_documentation", False),
+            "register_object": value,
+        }
+        if record.get("week"):
+            context["week"] = record["week"]
+        if record.get("substitution"):
+            context["substitution"] = record["substitution"]
+        return render_to_string("alsijil/partials/lesson_status.html", context)
 
 
 class RegisterObjectSelectTable(RegisterObjectTable):
diff --git a/aleksis/apps/alsijil/templates/alsijil/class_register/lesson.html b/aleksis/apps/alsijil/templates/alsijil/class_register/lesson.html
index 7c27f555b113da2e420ad9455ec0b9bfe6e9acf6..9a55603ef3f7857b9fc8e5b85c4059518dedc46e 100644
--- a/aleksis/apps/alsijil/templates/alsijil/class_register/lesson.html
+++ b/aleksis/apps/alsijil/templates/alsijil/class_register/lesson.html
@@ -3,434 +3,152 @@
 {% load week_helpers material_form_internal material_form i18n static rules time_helpers %}
 
 {% block browser_title %}{% blocktrans %}Lesson{% endblocktrans %}{% endblock %}
-
+{% block no_page_title %}{% endblock %}
 {% block extra_head %}
   {{ block.super }}
   <link rel="stylesheet" href="{% static 'css/alsijil/lesson.css' %}"/>
 {% endblock %}
 
-{% block content %}
-  <h1>
-    {% if next_lesson_person or prev_lesson_person or lesson_documentation %}
-      <div class="row no-margin">
-        <div class="col s12 no-padding">
-          {# Back to week view #}
-          {% if back_to_week_url %}
-            <a href="{{ back_to_week_url }}"
-               class="btn primary-color waves-light waves-effect alsijil-top-button">
-              <i class="material-icons left">chevron_left</i> {% trans "Back to week view" %}
-            </a>
-          {% endif %}
-
-          {# Next lesson #}
-          {% if prev_lesson_person %}
-            <a class="btn primary waves-effect waves-light alsijil-top-button"
-               href="{% url "lesson_period" prev_lesson_person.week.year prev_lesson_person.week.week prev_lesson_person.id %}">
-            <i class="material-icons left">arrow_back</i>
-            {% trans "My previous lesson" %}
-            </a>
-          {% endif %}
-
-          {# Previous lesson #}
-          {% if next_lesson_person %}
-            <a class="btn primary right waves-effect waves-light alsijil-top-button"
-               href="{% url "lesson_period" next_lesson_person.week.year next_lesson_person.week.week next_lesson_person.id %}">
-            <i class="material-icons right">arrow_forward</i>
-            {% trans "My next lesson" %}
-            </a>
-          {% endif %}
-        </div>
-      </div>
+{% block nav_content %}
+  <ul class="tabs tabs-transparent tabs-icons tabs-fixed-width">
+    <li class="tab">
+      <a href="#lesson-documentation">
+        <i class="material-icons">speaker_notes</i>
+        {% trans "Period" %}
+      </a>
+    </li>
+    {% if register_object.label_ != "lesson_period" or not register_object.get_substitution.cancelled or not request.site.preferences.alsijil__block_personal_notes_for_cancelled %}
+      <li class="tab">
+        <a href="#personal-notes">
+          <i class="material-icons">people</i>
+          {% trans "Persons" %}
+        </a>
+      </li>
     {% endif %}
-
-
-    {% if register_object.label_ == "event" %}
-      {{ register_object.date_start }} {{ register_object.period_from.period }}.–{{ register_object.date_end }}
-      {{ register_object.period_to.period }}.,
-    {% else %}
-      {{ day }}, {% blocktrans with period=register_object.period.period %}{{ period }}. period{% endblocktrans %} –
+    {% if prev_lesson %}
+      {% has_perm "alsijil.view_lessondocumentation_rule" user prev_lesson as can_view_prev_lesson_documentation %}
+      {% if prev_lesson.get_lesson_documentation and can_view_prev_lesson_documentation %}
+        <li class="tab">
+          <a href="#previous-lesson">
+            <i class="material-icons">history</i>
+            {% trans "Previous" %}
+          </a>
+        </li>
+      {% endif %}
     {% endif %}
+    <li class="tab">
+      <a href="#more">
+        <i class="material-icons">more_horiz</i>
+        {% trans "More" %}
+      </a>
+    </li>
+  </ul>
+{% endblock %}
 
-    {{ register_object.group_names }},
-
-    {% if register_object.label_ == "event" %}
-      {% trans "Event" %} ({{ register_object.title }})
-    {% else %}
-      {{ register_object.get_subject.name }}
-    {% endif %},
-
-    {{ register_object.teacher_short_names }}
-
-    <span class="right">
-      {% include "alsijil/partials/lesson_status_icon.html" with register_object=register_object css_class="medium" %}
-    </span>
-  </h1>
-  <br/>
-
+{% block content %}
   {% has_perm "alsijil.view_lessondocumentation_rule" user register_object as can_view_lesson_documentation %}
   {% has_perm "alsijil.edit_lessondocumentation_rule" user register_object as can_edit_lesson_documentation %}
   {% has_perm "alsijil.edit_register_object_personalnote_rule" user register_object as can_edit_register_object_personalnote %}
 
-  <form method="post" class="row">
-    <p>
-      {% if not blocked_because_holidays %}
-        {% if can_edit_lesson_documentation or can_edit_register_object_personalnote %}
-          {% include "core/partials/save_button.html" %}
+  {% if next_lesson_person or prev_lesson_person or lesson_documentation %}
+    <div class="row margin-bottom z-depth-1 alsijil-nav-header">
+      <div class="col s12 no-padding">
+        {# Back to week view #}
+        {% if back_to_week_url %}
+          <a href="{{ back_to_week_url }}"
+             class="btn secondary-color waves-light waves-effect margin-bottom {% if prev_lesson_person or next_lesson_person %}hide-on-extra-large-only{% endif %}">
+            <i class="material-icons left">chevron_left</i> {% trans "Week view" %}
+          </a>
         {% endif %}
-      {% endif %}
 
-      {% if prev_lesson %}
-        <a class="btn waves-effect waves-light primary"
-           href="{% url "lesson_period" prev_lesson.week.year prev_lesson.week.week prev_lesson.id %}">
-          <i class="material-icons left">arrow_back</i>
-          {% blocktrans with subject=register_object.get_subject.name %}
-            Previous {{ subject }} lesson
-          {% endblocktrans %}
-        </a>
-      {% endif %}
+        {% if prev_lesson_person or next_lesson_person %}
+          <div class="col s12 no-padding center alsijil-nav">
+            {% if back_to_week_url %}
+              <a href="{{ back_to_week_url }}"
+                 class="btn-flat secondary-color-text waves-light waves-effect left hide-on-med-and-down hide-on-large-only show-on-extra-large">
+                <i class="material-icons left">chevron_left</i> {% trans "Week view" %}
+              </a>
+            {% endif %}
 
-      {% if next_lesson %}
-        <a class="btn right waves-effect waves-light primary"
-           href="{% url "lesson_period" next_lesson.week.year next_lesson.week.week next_lesson.id %}">
-          <i class="material-icons right">arrow_forward</i>
-          {% blocktrans with subject=register_object.get_subject.name %}
-            Next {{ subject }} lesson
-          {% endblocktrans %}
-        </a>
-      {% endif %}
-    </p>
+            {# Previous lesson #}
+            <a class="btn-flat waves-effect waves-light left primary-color-text {% if not prev_lesson_person %}disabled{% endif %}"
+               title="{% trans "My previous lesson" %}"
+                {% if prev_lesson_person %}
+               href="{% url "lesson_period" prev_lesson_person.week.year prev_lesson_person.week.week prev_lesson_person.id %}"
+                {% endif %}
+            >
+              <i class="material-icons left">navigate_before</i>
+              <span class="hide-on-small-only">{% trans "My previous lesson" %}</span>
+              <span class="hide-on-med-and-up">{% trans "Previous" %}</span>
+            </a>
+            {# Next lesson #}
+            <a class="btn-flat waves-effect waves-light right primary-color-text {% if not next_lesson_person %}disabled{% endif %}"
+               title="{% trans "My next lesson" %}"
+                {% if next_lesson_person %}
+               href="{% url "lesson_period" next_lesson_person.week.year next_lesson_person.week.week next_lesson_person.id %}"
+                {% endif %}
+            >
+              <i class="material-icons right">navigate_next</i>
+              <span class="hide-on-small-only">{% trans "My next lesson" %}</span>
+              <span class="hide-on-med-and-up">{% trans "Next" %}</span>
+            </a>
+            <span class="truncate">{{ request.user.person }}</span>
+          </div>
+        {% endif %}
+      </div>
+    </div>
+  {% endif %}
 
+  <form method="post" class="row">
     {% csrf_token %}
 
     {% if not blocked_because_holidays %}
-
       <div class="row">
-        <div class="col s12">
-          <ul class="tabs">
-            <li class="tab">
-              <a href="#lesson-documentation">{% trans "Lesson documentation" %}</a>
-            </li>
-            {% if register_object.label_ != "lesson_period" or not register_object.get_substitution.cancelled or not request.site.preferences.alsijil__block_personal_notes_for_cancelled %}
-              <li class="tab">
-                <a href="#personal-notes">{% trans "Personal notes" %}</a>
-              </li>
-            {% endif %}
-            {% if prev_lesson %}
-              {% has_perm "alsijil.view_lessondocumentation_rule" user prev_lesson as can_view_prev_lesson_documentation %}
-              {% if prev_lesson.get_lesson_documentation and can_view_prev_lesson_documentation %}
-                <li class="tab">
-                  <a href="#previous-lesson">{% trans "Previous lesson" %}</a>
-                </li>
-              {% endif %}
-            {% endif %}
-            {% if group_roles %}
-              <li class="tab">
-                <a href="#group-roles">{% trans "Group roles" %}</a>
-              </li>
-            {% endif %}
-            <li class="tab">
-              <a href="#version-history">{% trans "Change history" %}</a>
-            </li>
-          </ul>
-        </div>
-
-        <div class="col s12" id="lesson-documentation">
-          <div class="card">
-            <div class="card-content">
-              <span class="card-title">
-                {% blocktrans %}Lesson documentation{% endblocktrans %}
-              </span>
-
-              {% if can_edit_lesson_documentation %}
-                {% form form=lesson_documentation_form %}{% endform %}
-              {% elif can_view_lesson_documentation %}
-                <table>
-                  <tr>
-                    <th>
-                      {% trans "Lesson topic" %}
-                    </th>
-                    <td>
-                      {{ lesson_documentation.topic }}
-                    </td>
-                  </tr>
-                  <tr>
-                    <th>
-                      {% trans "Homework" %}
-                    </th>
-                    <td>
-                      {{ lesson_documentation.homework }}
-                    </td>
-                  </tr>
-                  <tr>
-                    <th>
-                      {% trans "Group note" %}
-                    </th>
-                    <td>
-                      {{ lesson_documentation.group_note }}
-                    </td>
-                  </tr>
-                </table>
-              {% endif %}
-            </div>
-          </div>
+        <div class="col s12 no-padding" id="lesson-documentation">
+          {% include "alsijil/partials/lesson/tabs/documentation.html" %}
         </div>
 
         {% with prev_doc=prev_lesson.get_lesson_documentation %}
           {% with absences=prev_lesson.get_absences tardinesses=prev_lesson.get_tardinesses extra_marks=prev_lesson.get_extra_marks %}
             {% has_perm "alsijil.view_lessondocumentation_rule" user prev_lesson as can_view_prev_lesson_documentation %}
             {% if prev_doc and can_view_prev_lesson_documentation %}
-              <div class="col s12" id="previous-lesson">
-                <div class="card">
-                  <div class="card-content">
-                    <span class="card-title">
-                      {% blocktrans %}Overview: Previous lesson{% endblocktrans %} ({{ prev_doc.date_formatted }},
-                      {% blocktrans with period=prev_lesson.period.period %}{{ period }}. period{% endblocktrans %})
-                    </span>
-
-                    <table>
-                      {% if prev_doc.topic %}
-                        <tr>
-                          <th class="collection-item">{% trans "Lesson topic of previous lesson:" %}</th>
-                          <td>{{ prev_doc.topic }}</td>
-                        </tr>
-                      {% endif %}
-
-                      {% if prev_doc.homework %}
-                        <tr>
-                          <th class="collection-item">{% trans "Homework for this lesson:" %}</th>
-                          <td>{{ prev_doc.homework }}</td>
-                        </tr>
-                      {% endif %}
-
-                      {% if prev_doc.group_note %}
-                        <tr>
-                          <th class="collection-item">{% trans "Group notes for previous lesson:" %}</th>
-                          <td>{{ prev_doc.group_note }}</td>
-                        </tr>
-                      {% endif %}
-
-                      {% if absences %}
-                        <tr>
-                          <th>{% trans "Absent persons:" %}</th>
-                          <td>{% include "alsijil/partials/absences.html" with notes=absences %}</td>
-                        </tr>
-                      {% endif %}
-
-                      {% if tardinesses %}
-                        <tr>
-                          <th>{% trans "Late persons:" %}</th>
-                          <td>{% include "alsijil/partials/tardinesses.html" with notes=tardinesses %}</td>
-                        </tr>
-                      {% endif %}
-
-                      {% for extra_mark, notes in extra_marks.items %}
-                        <tr>
-                          <th>{{ extra_mark.name }}</th>
-                          <td>
-                            {% for note in notes %}
-                              {% has_perm "alsijil.view_personalnote_rule" user note as can_view_personalnote %}
-                              {% if can_view_personalnote %}
-                                <span>{{ note.person }}{% if not forloop.last %},{% endif %}</span>
-                              {% endif %}
-                            {% endfor %}
-                          </td>
-                        </tr>
-                      {% endfor %}
-
-                    </table>
-                  </div>
-                </div>
+              <div class="col s12 no-padding" id="previous-lesson">
+                {% include "alsijil/partials/lesson/tabs/previous_lesson.html" %}
               </div>
             {% endif %}
           {% endwith %}
         {% endwith %}
 
         {% if register_object.label_ != "lesson_period" or not register_object.get_substitution.cancelled or not request.site.preferences.alsijil__block_personal_notes_for_cancelled %}
-          <div class="col s12" id="personal-notes">
-            <div class="card">
-              <div class="card-content">
-                <span class="card-title">
-                  {% blocktrans %}Personal notes{% endblocktrans %}
-                </span>
-                {% if can_edit_register_object_personalnote %}
-                  {% form form=personal_note_formset.management_form %}{% endform %}
-                {% endif %}
-
-                <table class="striped responsive-table alsijil-table">
-                  <thead>
-                  <tr>
-                    <th>{% blocktrans %}Person{% endblocktrans %}</th>
-                    <th>{% blocktrans %}Absent{% endblocktrans %}</th>
-                    <th>{% blocktrans %}Tardiness{% endblocktrans %}</th>
-                    <th>{% blocktrans %}Excused{% endblocktrans %}</th>
-                    <th>{% blocktrans %}Excuse type{% endblocktrans %}</th>
-                    <th>{% blocktrans %}Extra marks{% endblocktrans %}</th>
-                    <th>{% blocktrans %}Remarks{% endblocktrans %}</th>
-                  </tr>
-                  </thead>
-                  <tbody>
-                  {% for form in personal_note_formset %}
-                    {% if can_edit_register_object_personalnote %}
-                      <tr>
-                        {{ form.id }}
-                        <td>{{ form.person_name }}{{ form.person_name.value }}
-                          <p>
-                            {% for assignment in form.instance.person.group_roles.all %}
-                              {% include "alsijil/group_role/chip.html" with role=assignment.role %}
-                            {% endfor %}
-                          </p>
-                        </td>
-                        <td class="center-align">
-                          <label>
-                            {{ form.absent }}
-                            <span></span>
-                          </label>
-                        </td>
-                        <td>
-                          <div class="input-field">
-                            {{ form.late }}
-                            <label for="{{ form.absent.id_for_label }}">
-                              {% trans "Tardiness (in m)" %}
-                            </label>
-                          </div>
-                        </td>
-                        <td class="center-align">
-                          <label>
-                            {{ form.excused }}
-                            <span></span>
-                          </label>
-                        </td>
-                        <td>
-                          <div class="input-field">
-                            {{ form.excuse_type }}
-                            <label for="{{ form.excuse_type.id_for_label }}">
-                              {% trans "Excuse type" %}
-                            </label>
-                          </div>
-                        </td>
-                        <td>
-                          {% for group, items in form.extra_marks|select_options %}
-                            {% for choice, value, selected in items %}
-                              <label class="{% if selected %} active{% endif %} alsijil-check-box">
-                                <input type="checkbox"
-                                       {% if value == None or value == '' %}disabled{% else %}value="{{ value }}"{% endif %}
-                                    {% if selected %} checked="checked"{% endif %}
-                                       name="{{ form.extra_marks.html_name }}">
-                                <span>{{ choice }}</span>
-                              </label>
-                            {% endfor %}
-                          {% endfor %}
-                        </td>
-                        <td>
-                          <div class="input-field">
-                            {{ form.remarks }}
-                            <label for="{{ form.remarks.id_for_label }}">
-                              {% trans "Remarks" %}
-                            </label>
-                          </div>
-                        </td>
-                      </tr>
-                    {% else %}
-                      <tr>
-                        <td>{{ form.person_name.value }}
-                          <p>
-                            {% for assignment in form.instance.person.group_roles.all %}
-                              {% include "alsijil/group_role/chip.html" with role=assignment.role %}
-                            {% endfor %}
-                          </p>
-                        </td>
-                        <td><i class="material-icons center">{{ form.absent.value|yesno:"check,clear" }}</i></td>
-                        <td>
-                          <i class="material-icons center">{{ form.late.value|yesno:"check,clear" }}</i>
-                          <span class="alsijil-tardiness-text">
-                            {% if form.late.value %}{{ form.late.value|to_time|time:"i\m" }}{% endif %}
-                          </span>
-                        </td>
-                        <td><i class="material-icons center">{{ form.excused.value|yesno:"check,clear" }}</i></td>
-                        <td>{% firstof form.excuse_type.value "–" %}</td>
-                        <td>
-                          {% for extra_mark in form.extra_marks.value %}
-                            {{ extra_mark }}{% if not forloop.last %},{% endif %}
-                            {% empty %}
-                            –
-                          {% endfor %}
-                        </td>
-                        <td>{% firstof form.remarks.value "–" %}</td>
-                      </tr>
-                    {% endif %}
-                  {% endfor %}
-                  </tbody>
-                </table>
-              </div>
-            </div>
+          <div class="col s12 no-padding" id="personal-notes">
+            {% include "alsijil/partials/lesson/tabs/notes.html" %}
           </div>
         {% endif %}
 
-        {% if group_roles %}
-          <div class="col s12" id="group-roles">
-            {% include "alsijil/group_role/partials/assigned_roles.html" with roles=group_roles group=register_object.get_groups.first back_url=back_url %}
-          </div>
-        {% endif %}
-
-        {% if can_view_lesson_documentation %}
-          <div class="col s12" id="version-history">
-            <div class="card">
-              <div class="card-content">
-                <span class="card-title">
-                  {% blocktrans %}Change history{% endblocktrans %}
-                </span>
-                {% include 'core/partials/crud_events.html' with obj=lesson_documentation %}
-              </div>
-            </div>
-          </div>
-        {% endif %}
+        <div class="col s12 no-padding" id="more">
+          {% include "alsijil/partials/lesson/tabs/more.html" %}
+        </div>
       </div>
-
-
-      <p>
-        {% if can_edit_lesson_documentation or can_edit_register_object_personalnote %}
-          {% include "core/partials/save_button.html" %}
-        {% endif %}
-
-        {% if prev_lesson %}
-          <a class="btn primary waves-effect waves-light"
-             href="{% url "lesson_period" prev_lesson.week.year prev_lesson.week.week prev_lesson.id %}">
-            <i class="material-icons left">arrow_back</i>
-            {% blocktrans with subject=register_object.get_subject.name %}
-              Previous {{ subject }} lesson
-            {% endblocktrans %}
-          </a>
-        {% endif %}
-
-        {% if next_lesson %}
-          <a class="btn primary right waves-effect waves-light"
-             href="{% url "lesson_period" next_lesson.week.year next_lesson.week.week next_lesson.id %}">
-            <i class="material-icons right">arrow_forward</i>
-            {% blocktrans with subject=register_object.get_subject.name %}
-              Next {{ subject }} lesson
-            {% endblocktrans %}
-          </a>
-        {% endif %}
-      </p>
-
     {% else %}
+      {% include "alsijil/partials/lesson/heading.html" %}
+
       <div class="row no-margin">
-      <div class="container">
-        <div class="card">
-          <div class="card-content center-align">
-            <p>
-              <i class="material-icons medium orange-text">warning</i>
-            </p>
-            <p class="card-title">
-              {% blocktrans %}
-                This lesson overlaps with holidays and can't be edited.
-              {% endblocktrans %}
-            </p>
-            <span class="badge new blue no-float no-margin">{{ holiday }}</span>
+        <div class="container">
+          <div class="card">
+            <div class="card-content center-align">
+              <p>
+                <i class="material-icons medium orange-text">warning</i>
+              </p>
+              <p class="card-title">
+                {% blocktrans %}
+                  This lesson overlaps with holidays and can't be edited.
+                {% endblocktrans %}
+              </p>
+              <span class="badge new blue no-float no-margin">{{ holiday }}</span>
+            </div>
           </div>
         </div>
       </div>
-      </div>
     {% endif %}
   </form>
 {% endblock %}
diff --git a/aleksis/apps/alsijil/templates/alsijil/class_register/week_view.html b/aleksis/apps/alsijil/templates/alsijil/class_register/week_view.html
index 1cdab7ff87800a30797da5c8d8c346c919ffecd9..435f4e1ed275abdd35f8ebb86d002d8600f613c6 100644
--- a/aleksis/apps/alsijil/templates/alsijil/class_register/week_view.html
+++ b/aleksis/apps/alsijil/templates/alsijil/class_register/week_view.html
@@ -116,7 +116,7 @@
                       {% if can_view_lesson_documentation %}
                         <tr>
                           <td class="center-align">
-                            {% include "alsijil/partials/lesson_status_icon.html" with register_object=register_object %}
+                            {% include "alsijil/partials/lesson_status.html" with register_object=register_object %}
                           </td>
                           <td class="tr-link">
                             <a class="tr-link"
@@ -196,7 +196,7 @@
                         {% if can_view_lesson_documentation %}
                           <a class="collection-item avatar"
                              href="{{ register_object.alsijil_url }}?back={{ back_url }}">
-                            {% include "alsijil/partials/lesson_status_icon.html" with register_object=register_object css_class="materialize-circle" color_suffix=" " %}
+                            {% include "alsijil/partials/lesson_status.html" with register_object=register_object css_class="materialize-circle" color_suffix=" " %}
                             <table class="hide-on-med-and-down">
                               <tr>
                                 <th>{% trans "Subject" %}</th>
diff --git a/aleksis/apps/alsijil/templates/alsijil/partials/lesson/heading.html b/aleksis/apps/alsijil/templates/alsijil/partials/lesson/heading.html
new file mode 100644
index 0000000000000000000000000000000000000000..07c14a649a96892987b984aa315e955df856cbf7
--- /dev/null
+++ b/aleksis/apps/alsijil/templates/alsijil/partials/lesson/heading.html
@@ -0,0 +1,61 @@
+{% load i18n %}
+
+<h1>
+  <span class="right hide-on-small-only">
+    {% include "alsijil/partials/lesson_status.html" with register_object=register_object css_class="medium" %}
+  </span>
+
+  <a class="btn-flat waves-effect waves-light primary-color-text left alsijil-header-nav-button hide-on-med-and-up {% if not prev_lesson %}disabled{% endif %}"
+      {% if prev_lesson %}
+     href="{% url "lesson_period" prev_lesson.week.year prev_lesson.week.week prev_lesson.id %}"
+      {% endif %}
+  >
+    <i class="material-icons center">navigate_before</i>
+  </a>
+  <a class="btn-flat waves-effect waves-light primary-color-text right alsijil-header-nav-button hide-on-med-and-up {% if not next_lesson %}disabled{% endif %}"
+      {% if next_lesson %}
+     href="{% url "lesson_period" next_lesson.week.year next_lesson.week.week next_lesson.id %}"
+      {% endif %}
+  >
+    <i class="material-icons center">navigate_next</i>
+  </a>
+
+  <span class="alsijil-time-head">
+    {% if register_object.label_ == "event" %}
+      {% if register_object.date_start == register_object.date_end %}
+        {% if register_object.period_from.period == register_object.period_to.period %}
+          {{ register_object.date_start|date:"SHORT_DATE_FORMAT" }},
+          {% blocktrans with period=register_object.period_from.period %}{{ period }}. period{% endblocktrans %}
+        {% else %}
+          {{ register_object.date_start|date:"SHORT_DATE_FORMAT" }},
+          {% blocktrans with period_from=register_object.period_from.period  period_to=register_object.period_to.period %}
+            {{ period_from }}.–{{ period_to }}.  period
+          {% endblocktrans %}
+        {% endif %}
+      {% else %}
+        {{ register_object.date_start|date:"SHORT_DATE_FORMAT" }},
+        {{ register_object.period_from.period }}.–{{ register_object.date_end|date:"SHORT_DATE_FORMAT" }},
+        {{ register_object.period_to.period }}.
+      {% endif %}
+    {% else %}
+      {{ day|date:"SHORT_DATE_FORMAT" }},
+      {% blocktrans with period=register_object.period.period %}{{ period }}. period{% endblocktrans %}
+    {% endif %}
+  </span>
+
+  <span class="alsijil-object-head">
+    {{ register_object.group_names }},
+
+    {% if register_object.label_ == "event" %}
+      {% trans "Event" %} ({{ register_object.title }}),
+    {% else %}
+      {{ register_object.get_subject.short_name }},
+    {% endif %}
+
+    {{ register_object.teacher_short_names }}
+  </span>
+</h1>
+
+<div class="hide-on-med-and-up margin-bottom">
+  {% include "alsijil/partials/lesson_status.html" with register_object=register_object chip=1 css_class="hundred-percent center" %}
+</div>
diff --git a/aleksis/apps/alsijil/templates/alsijil/partials/lesson/prev_next.html b/aleksis/apps/alsijil/templates/alsijil/partials/lesson/prev_next.html
new file mode 100644
index 0000000000000000000000000000000000000000..dcddcfcc13a6437bf1982f9e3ce20930e9aaf774
--- /dev/null
+++ b/aleksis/apps/alsijil/templates/alsijil/partials/lesson/prev_next.html
@@ -0,0 +1,37 @@
+{% load i18n %}
+
+<div class="row no-margin hide-on-small-only">
+  <div class="col s12 no-padding">
+    {% if not blocked_because_holidays and with_save %}
+      {% if can_edit_lesson_documentation or can_edit_register_object_personalnote %}
+        <button type="submit" class="btn waves-effect waves-light green margin-bottom">
+          <i class="material-icons left">save</i> {% trans "Save" %}
+        </button>
+      {% endif %}
+    {% endif %}
+
+    <a class="btn waves-effect waves-light primary margin-bottom {% if not prev_lesson %}disabled{% endif %}"
+        {% if prev_lesson %}
+       href="{% url "lesson_period" prev_lesson.week.year prev_lesson.week.week prev_lesson.id %}"
+        {% endif %}
+    >
+      <i class="material-icons left">arrow_back</i>
+      {% blocktrans with subject=register_object.get_subject.short_name %}
+        Previous {{ subject }} lesson
+      {% endblocktrans %}
+    </a>
+
+    <a class="btn right waves-effect waves-light primary margin-bottom {% if not next_lesson %}disabled{% endif %}"
+        {% if next_lesson %}
+       href="{% url "lesson_period" next_lesson.week.year next_lesson.week.week next_lesson.id %}"
+        {% endif %}
+    >
+      <i class="material-icons right">arrow_forward</i>
+      {% blocktrans with subject=register_object.get_subject.short_name %}
+        Next {{ subject }} lesson
+      {% endblocktrans %}
+    </a>
+  </div>
+</div>
+
+
diff --git a/aleksis/apps/alsijil/templates/alsijil/partials/lesson/tabs/documentation.html b/aleksis/apps/alsijil/templates/alsijil/partials/lesson/tabs/documentation.html
new file mode 100644
index 0000000000000000000000000000000000000000..ef0f42048bf1df524924ec1f380f8d88dd7fab3e
--- /dev/null
+++ b/aleksis/apps/alsijil/templates/alsijil/partials/lesson/tabs/documentation.html
@@ -0,0 +1,66 @@
+{% load i18n material_form_internal material_form %}
+
+{% include "alsijil/partials/lesson/heading.html" %}
+{% include "alsijil/partials/lesson/prev_next.html" with with_save=0 %}
+
+<div class="hide-on-med-and-up margin-bottom">
+  {% if not blocked_because_holidays %}
+    {% if can_edit_lesson_documentation or can_edit_register_object_personalnote %}
+      {% include "core/partials/save_button.html" %}
+    {% endif %}
+  {% endif %}
+</div>
+
+<div class="card">
+  <div class="card-content">
+    <span class="card-title">
+      {% blocktrans %}Lesson documentation{% endblocktrans %}
+    </span>
+
+    {% if can_edit_lesson_documentation %}
+      {% form form=lesson_documentation_form %}{% endform %}
+    {% elif can_view_lesson_documentation %}
+      <table>
+        <tr>
+          <th>
+            {% trans "Lesson topic" %}
+          </th>
+          <td>
+            {{ lesson_documentation.topic }}
+          </td>
+        </tr>
+        <tr>
+          <th>
+            {% trans "Homework" %}
+          </th>
+          <td>
+            {{ lesson_documentation.homework }}
+          </td>
+        </tr>
+        <tr>
+          <th>
+            {% trans "Group note" %}
+          </th>
+          <td>
+            {{ lesson_documentation.group_note }}
+          </td>
+        </tr>
+      </table>
+    {% endif %}
+  </div>
+  <div class="card-action-light hide-on-small-only">
+    {% if not blocked_because_holidays %}
+      {% if can_edit_lesson_documentation or can_edit_register_object_personalnote %}
+        {% include "core/partials/save_button.html" %}
+      {% endif %}
+    {% endif %}
+  </div>
+</div>
+
+<div class="hide-on-med-and-up">
+  {% if not blocked_because_holidays %}
+    {% if can_edit_lesson_documentation or can_edit_register_object_personalnote %}
+      {% include "core/partials/save_button.html" %}
+    {% endif %}
+  {% endif %}
+</div>
\ No newline at end of file
diff --git a/aleksis/apps/alsijil/templates/alsijil/partials/lesson/tabs/more.html b/aleksis/apps/alsijil/templates/alsijil/partials/lesson/tabs/more.html
new file mode 100644
index 0000000000000000000000000000000000000000..b7e010125077dd003e529bb85432dfc64adad7ab
--- /dev/null
+++ b/aleksis/apps/alsijil/templates/alsijil/partials/lesson/tabs/more.html
@@ -0,0 +1,18 @@
+{% load i18n %}
+
+{% include "alsijil/partials/lesson/heading.html" %}
+
+{% if group_roles %}
+  {% include "alsijil/group_role/partials/assigned_roles.html" with roles=group_roles group=register_object.get_groups.first back_url=back_url %}
+{% endif %}
+
+{% if can_view_lesson_documentation %}
+  <div class="card">
+    <div class="card-content">
+      <span class="card-title">
+        {% blocktrans %}Change history{% endblocktrans %}
+      </span>
+      {% include 'core/partials/crud_events.html' with obj=lesson_documentation %}
+    </div>
+  </div>
+{% endif %}
\ No newline at end of file
diff --git a/aleksis/apps/alsijil/templates/alsijil/partials/lesson/tabs/notes.html b/aleksis/apps/alsijil/templates/alsijil/partials/lesson/tabs/notes.html
new file mode 100644
index 0000000000000000000000000000000000000000..7d011050f6aec7ba07ccc7bc9199e149c99f016d
--- /dev/null
+++ b/aleksis/apps/alsijil/templates/alsijil/partials/lesson/tabs/notes.html
@@ -0,0 +1,138 @@
+{% load i18n material_form_internal material_form time_helpers %}
+
+{% include "alsijil/partials/lesson/heading.html" %}
+{% include "alsijil/partials/lesson/prev_next.html" with with_save=1 %}
+
+{% if not blocked_because_holidays %}
+  {% if can_edit_lesson_documentation or can_edit_register_object_personalnote %}
+    <button type="submit"
+            class="btn waves-effect waves-light green margin-bottom hundred-percent hide-on-med-and-up">
+      <i class="material-icons left">save</i> {% trans "Save" %}
+    </button>
+  {% endif %}
+{% endif %}
+
+<div class="card">
+  <div class="card-content">
+    <span class="card-title">
+      {% blocktrans %}Personal notes{% endblocktrans %}
+    </span>
+    {% if can_edit_register_object_personalnote %}
+      {% form form=personal_note_formset.management_form %}{% endform %}
+    {% endif %}
+
+    <table class="striped responsive-table alsijil-table">
+      <thead>
+      <tr>
+        <th>{% blocktrans %}Person{% endblocktrans %}</th>
+        <th>{% blocktrans %}Absent{% endblocktrans %}</th>
+        <th>{% blocktrans %}Tardiness{% endblocktrans %}</th>
+        <th>{% blocktrans %}Excused{% endblocktrans %}</th>
+        <th>{% blocktrans %}Excuse type{% endblocktrans %}</th>
+        <th>{% blocktrans %}Extra marks{% endblocktrans %}</th>
+        <th>{% blocktrans %}Remarks{% endblocktrans %}</th>
+      </tr>
+      </thead>
+      <tbody>
+      {% for form in personal_note_formset %}
+        {% if can_edit_register_object_personalnote %}
+          <tr>
+            {{ form.id }}
+            <td>{{ form.person_name }}{{ form.person_name.value }}
+              <p>
+                {% for assignment in form.instance.person.group_roles.all %}
+                  {% include "alsijil/group_role/chip.html" with role=assignment.role %}
+                {% endfor %}
+              </p>
+            </td>
+            <td class="center-align">
+              <label>
+                {{ form.absent }}
+                <span></span>
+              </label>
+            </td>
+            <td>
+              <div class="input-field">
+                {{ form.late }}
+                <label for="{{ form.absent.id_for_label }}">
+                  {% trans "Tardiness (in m)" %}
+                </label>
+              </div>
+            </td>
+            <td class="center-align">
+              <label>
+                {{ form.excused }}
+                <span></span>
+              </label>
+            </td>
+            <td>
+              <div class="input-field">
+                {{ form.excuse_type }}
+                <label for="{{ form.excuse_type.id_for_label }}">
+                  {% trans "Excuse type" %}
+                </label>
+              </div>
+            </td>
+            <td>
+              {% for group, items in form.extra_marks|select_options %}
+                {% for choice, value, selected in items %}
+                  <label class="{% if selected %} active{% endif %} alsijil-check-box">
+                    <input type="checkbox"
+                           {% if value == None or value == '' %}disabled{% else %}value="{{ value }}"{% endif %}
+                        {% if selected %} checked="checked"{% endif %}
+                           name="{{ form.extra_marks.html_name }}">
+                    <span>{{ choice }}</span>
+                  </label>
+                {% endfor %}
+              {% endfor %}
+            </td>
+            <td>
+              <div class="input-field">
+                {{ form.remarks }}
+                <label for="{{ form.remarks.id_for_label }}">
+                  {% trans "Remarks" %}
+                </label>
+              </div>
+            </td>
+          </tr>
+        {% else %}
+          <tr>
+            <td>{{ form.person_name.value }}
+              <p>
+                {% for assignment in form.instance.person.group_roles.all %}
+                  {% include "alsijil/group_role/chip.html" with role=assignment.role %}
+                {% endfor %}
+              </p>
+            </td>
+            <td><i class="material-icons center">{{ form.absent.value|yesno:"check,clear" }}</i></td>
+            <td>
+              <i class="material-icons center">{{ form.late.value|yesno:"check,clear" }}</i>
+              <span class="alsijil-tardiness-text">
+                {% if form.late.value %}{{ form.late.value|to_time|time:"i\m" }}{% endif %}
+              </span>
+            </td>
+            <td><i class="material-icons center">{{ form.excused.value|yesno:"check,clear" }}</i></td>
+            <td>{% firstof form.excuse_type.value "–" %}</td>
+            <td>
+              {% for extra_mark in form.extra_marks.value %}
+                {{ extra_mark }}{% if not forloop.last %},{% endif %}
+              {% empty %}
+                –
+              {% endfor %}
+            </td>
+            <td>{% firstof form.remarks.value "–" %}</td>
+          </tr>
+        {% endif %}
+      {% endfor %}
+      </tbody>
+    </table>
+  </div>
+</div>
+{% if not blocked_because_holidays %}
+  {% if can_edit_lesson_documentation or can_edit_register_object_personalnote %}
+    <button type="submit"
+            class="btn waves-effect waves-light green margin-bottom hundred-percent hide-on-med-and-up">
+      <i class="material-icons left">save</i> {% trans "Save" %}
+    </button>
+  {% endif %}
+{% endif %}
\ No newline at end of file
diff --git a/aleksis/apps/alsijil/templates/alsijil/partials/lesson/tabs/previous_lesson.html b/aleksis/apps/alsijil/templates/alsijil/partials/lesson/tabs/previous_lesson.html
new file mode 100644
index 0000000000000000000000000000000000000000..8457576b786f579032d5c02052c3ea02a940b6ce
--- /dev/null
+++ b/aleksis/apps/alsijil/templates/alsijil/partials/lesson/tabs/previous_lesson.html
@@ -0,0 +1,62 @@
+{% load i18n rules %}
+
+<div class="card">
+  <div class="card-content">
+    <span class="card-title">
+      {% blocktrans %}Overview: Previous lesson{% endblocktrans %} ({{ prev_doc.date_formatted }},
+      {% blocktrans with period=prev_lesson.period.period %}{{ period }}. period{% endblocktrans %})
+    </span>
+
+    <table>
+      {% if prev_doc.topic %}
+        <tr>
+          <th class="collection-item">{% trans "Lesson topic of previous lesson:" %}</th>
+          <td>{{ prev_doc.topic }}</td>
+        </tr>
+      {% endif %}
+
+      {% if prev_doc.homework %}
+        <tr>
+          <th class="collection-item">{% trans "Homework for this lesson:" %}</th>
+          <td>{{ prev_doc.homework }}</td>
+        </tr>
+      {% endif %}
+
+      {% if prev_doc.group_note %}
+        <tr>
+          <th class="collection-item">{% trans "Group notes for previous lesson:" %}</th>
+          <td>{{ prev_doc.group_note }}</td>
+        </tr>
+      {% endif %}
+
+      {% if absences %}
+        <tr>
+          <th>{% trans "Absent persons:" %}</th>
+          <td>{% include "alsijil/partials/absences.html" with notes=absences %}</td>
+        </tr>
+      {% endif %}
+
+      {% if tardinesses %}
+        <tr>
+          <th>{% trans "Late persons:" %}</th>
+          <td>{% include "alsijil/partials/tardinesses.html" with notes=tardinesses %}</td>
+        </tr>
+      {% endif %}
+
+      {% for extra_mark, notes in extra_marks.items %}
+        <tr>
+          <th>{{ extra_mark.name }}</th>
+          <td>
+            {% for note in notes %}
+              {% has_perm "alsijil.view_personalnote_rule" user note as can_view_personalnote %}
+              {% if can_view_personalnote %}
+                <span>{{ note.person }}{% if not forloop.last %},{% endif %}</span>
+              {% endif %}
+            {% endfor %}
+          </td>
+        </tr>
+      {% endfor %}
+
+    </table>
+  </div>
+</div>
\ No newline at end of file
diff --git a/aleksis/apps/alsijil/templates/alsijil/partials/lesson_status.html b/aleksis/apps/alsijil/templates/alsijil/partials/lesson_status.html
new file mode 100644
index 0000000000000000000000000000000000000000..41c80fd25d208e34f38bbcd9e4137016a0734301
--- /dev/null
+++ b/aleksis/apps/alsijil/templates/alsijil/partials/lesson_status.html
@@ -0,0 +1,36 @@
+{% load i18n week_helpers %}
+
+{% now_datetime as now_dt %}
+
+{% if has_documentation or register_object.has_documentation %}
+  {% include "alsijil/partials/lesson_status_icon.html" with text=_("Data complete") icon="check_circle" color="green" %}
+{% elif not register_object.period %}
+  {% if week %}
+    {% period_to_time_start week register_object.raw_period_from_on_day as time_start %}
+    {% period_to_time_end week register_object.raw_period_to_on_day as time_end %}
+  {% else %}
+    {% period_to_time_start register_object.date_start register_object.period_from as time_start %}
+    {% period_to_time_end register_object.date_end register_object.period_to as time_end %}
+  {% endif %}
+
+  {% if now_dt > time_end %}
+    {% include "alsijil/partials/lesson_status_icon.html" with text=_("Missing data") icon="warning" color="red" %}
+  {% elif now_dt > time_start and now_dt < time_end %}
+    {% include "alsijil/partials/lesson_status_icon.html" with text=_("Pending") icon="more_horiz" color="orange" %}
+  {% else %}
+    {% include "alsijil/partials/lesson_status_icon.html" with text=_("Event") icon="event" color="purple" %}
+  {% endif %}
+{% else %}
+  {% period_to_time_start week register_object.period as time_start %}
+  {% period_to_time_end week register_object.period as time_end %}
+
+  {% if substitution.cancelled or register_object.get_substitution.cancelled %}
+    {% include "alsijil/partials/lesson_status_icon.html" with text=_("Lesson cancelled") icon="cancel" color="red" %}
+  {% elif now_dt > time_end %}
+    {% include "alsijil/partials/lesson_status_icon.html" with text=_("Missing data") icon="warning" color="red" %}
+  {% elif now_dt > time_start and now_dt < time_end %}
+    {% include "alsijil/partials/lesson_status_icon.html" with text=_("Pending") icon="more_horiz" color="orange" %}
+  {% elif substitution or register_object.get_substitution %}
+    {% include "alsijil/partials/lesson_status_icon.html" with text=_("Substitution") icon="update" color="orange" %}
+  {% endif %}
+{% endif %}
diff --git a/aleksis/apps/alsijil/templates/alsijil/partials/lesson_status_icon.html b/aleksis/apps/alsijil/templates/alsijil/partials/lesson_status_icon.html
index 52f55e9723c3b9650bcd09f63725467a75f8993d..046b3ffbdacbbb5f18232668363fae195457faa1 100644
--- a/aleksis/apps/alsijil/templates/alsijil/partials/lesson_status_icon.html
+++ b/aleksis/apps/alsijil/templates/alsijil/partials/lesson_status_icon.html
@@ -1,31 +1,14 @@
-{% load i18n week_helpers %}
-
-{% now_datetime as now_dt %}
-
-{% if has_documentation or register_object.has_documentation %}
-  <i class="material-icons green{% firstof color_suffix "-text"%} tooltipped {{ css_class }}" data-position="bottom" data-tooltip="{% trans "Data complete" %}" title="{% trans "Data complete" %}">check_circle</i>
-{% elif not register_object.period %}
-  {% period_to_time_start week register_object.raw_period_from_on_day as time_start %}
-  {% period_to_time_end week register_object.raw_period_to_on_day as time_end %}
-
-  {% if now_dt > time_end %}
-    <i class="material-icons red{% firstof color_suffix "-text"%} tooltipped {{ css_class }}"  data-position="bottom" data-tooltip="{% trans "Missing data" %}" title="{% trans "Missing data" %}">history</i>
-  {% elif now_dt > time_start and now_dt < time_end %}
-    <i class="material-icons orange{% firstof color_suffix "-text"%} tooltipped {{ css_class }}"  data-position="bottom" data-tooltip="{% trans "Pending" %}" title="{% trans "Pending" %}">more_horiz</i>
-  {% else %}
-    <i class="material-icons purple{% firstof color_suffix "-text"%} tooltipped {{ css_class }}" data-position="bottom" data-tooltip="{% trans "Event" %}" title="{% trans "Event" %}">event</i>
-  {% endif %}
+{% if chip %}
+  <span class="{% if chip %}chip{% endif %} {{ color }} white-text {{ css_class }}">
+    <i class="material-icons left">
+      {{ icon }}
+    </i>
+    {{ text }}
+  </span>
 {% else %}
-  {% period_to_time_start week register_object.period as time_start %}
-  {% period_to_time_end week register_object.period as time_end %}
-
-  {% if substitution.cancelled or register_object.get_substitution.cancelled %}
-    <i class="material-icons red{% firstof color_suffix "-text"%} tooltipped {{ css_class }}"  data-position="bottom" data-tooltip="{% trans "Lesson cancelled" %}" title="{% trans "Lesson cancelled" %}">cancel</i>
-  {% elif now_dt > time_end %}
-    <i class="material-icons red{% firstof color_suffix "-text"%} tooltipped {{ css_class }}"  data-position="bottom" data-tooltip="{% trans "Missing data" %}" title="{% trans "Missing data" %}">history</i>
-  {% elif now_dt > time_start and now_dt < time_end %}
-    <i class="material-icons orange{% firstof color_suffix "-text"%} tooltipped {{ css_class }}"  data-position="bottom" data-tooltip="{% trans "Pending" %}" title="{% trans "Pending" %}">more_horiz</i>
-  {% elif substitution or register_object.get_substitution %}
-    <i class="material-icons orange{% firstof color_suffix "-text"%} tooltipped {{ css_class }}"  data-position="bottom" data-tooltip="{% trans "Substitution" %}" title="{% trans "Substitution" %}">update</i>
-  {% endif %}
+  <i class="material-icons {{ color }}{% firstof color_suffix "-text" %} tooltipped {{ css_class }}"
+     data-position="bottom"
+     data-tooltip="{{ text }}" title="{{ text }}">
+    {{ icon }}
+  </i>
 {% endif %}
diff --git a/poetry.lock b/poetry.lock
index 96879f21465526eb66c7e24f1d7025d48719d460..989505cc3037ec9b6c770009042a1cf2ddda5884 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -8,7 +8,7 @@ python-versions = "*"
 
 [[package]]
 name = "aleksis-app-chronos"
-version = "2.1.dev2"
+version = "2.1.dev3"
 description = "AlekSIS (School Information System) — App Χρόνος (digital timetables)"
 category = "main"
 optional = false
@@ -37,7 +37,7 @@ reference = "gitlab"
 
 [[package]]
 name = "aleksis-builddeps"
-version = "5+20211115090333.5c84baaf"
+version = "5+20211130152626.23302bab"
 description = "AlekSIS (School Information System) — Build/Dev dependencies for apps"
 category = "dev"
 optional = false
@@ -78,7 +78,7 @@ reference = "gitlab"
 
 [[package]]
 name = "aleksis-core"
-version = "2.2.dev0+20211114193927.5ca5f145"
+version = "2.2+20211129202100.032a3cac"
 description = "AlekSIS (School Information System) — Core"
 category = "main"
 optional = false
@@ -92,7 +92,7 @@ celery-haystack-ng = ">=0.20,<0.21"
 celery-progress = ">=0.1.0,<0.2.0"
 colour = ">=0.1.5,<0.2.0"
 Django = ">=3.2.5,<4.0.0"
-django-allauth = ">=0.45.0,<0.46.0"
+django-allauth = ">=0.46.0,<0.47.0"
 django-any-js = ">=1.1,<2.0"
 django-bleach = ">=0.9.0,<0.10.0"
 django-cachalot = ">=2.3.2,<3.0.0"
@@ -145,7 +145,7 @@ license-expression = ">=1.2,<2.0"
 psutil = ">=5.7.0,<6.0.0"
 psycopg2 = ">=2.8,<3.0"
 python-gnupg = ">=0.4.7,<0.5.0"
-rules = ">=3.0,<4.0"
+rules = ">=2.2,<3.0"
 sentry-sdk = ">=1.4.3,<2.0.0"
 spdx-license-list = ">=0.5.0,<0.6.0"
 Whoosh = ">=2.7.4,<3.0.0"
@@ -285,7 +285,7 @@ python-versions = "*"
 
 [[package]]
 name = "black"
-version = "21.11b0"
+version = "21.11b1"
 description = "The uncompromising code formatter."
 category = "dev"
 optional = false
@@ -296,7 +296,7 @@ click = ">=7.1.2"
 mypy-extensions = ">=0.4.3"
 pathspec = ">=0.9.0,<1"
 platformdirs = ">=2"
-regex = ">=2020.1.8"
+regex = ">=2021.4.4"
 tomli = ">=0.2.6,<2.0.0"
 typing-extensions = [
     {version = ">=3.10.0.0", markers = "python_version < \"3.10\""},
@@ -453,7 +453,7 @@ pycparser = "*"
 
 [[package]]
 name = "charset-normalizer"
-version = "2.0.7"
+version = "2.0.8"
 description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
 category = "main"
 optional = false
@@ -543,7 +543,7 @@ six = "*"
 
 [[package]]
 name = "coverage"
-version = "6.1.2"
+version = "6.2"
 description = "Code coverage measurement for Python"
 category = "dev"
 optional = false
@@ -557,7 +557,7 @@ toml = ["tomli"]
 
 [[package]]
 name = "cryptography"
-version = "35.0.0"
+version = "36.0.0"
 description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers."
 category = "main"
 optional = false
@@ -568,7 +568,7 @@ cffi = ">=1.12"
 
 [package.extras]
 docs = ["sphinx (>=1.6.5,!=1.8.0,!=3.1.0,!=3.1.1)", "sphinx-rtd-theme"]
-docstest = ["doc8", "pyenchant (>=1.6.11)", "twine (>=1.12.0)", "sphinxcontrib-spelling (>=4.0.1)"]
+docstest = ["pyenchant (>=1.6.11)", "twine (>=1.12.0)", "sphinxcontrib-spelling (>=4.0.1)"]
 pep8test = ["black", "flake8", "flake8-import-order", "pep8-naming"]
 sdist = ["setuptools_rust (>=0.11.4)"]
 ssh = ["bcrypt (>=3.1.5)"]
@@ -646,7 +646,7 @@ bcrypt = ["bcrypt"]
 
 [[package]]
 name = "django-allauth"
-version = "0.45.0"
+version = "0.46.0"
 description = "Integrated set of Django applications addressing authentication, registration, account management as well as 3rd party (social) account authentication."
 category = "main"
 optional = false
@@ -755,7 +755,7 @@ celery = ">=5.0,<6.0"
 
 [[package]]
 name = "django-ckeditor"
-version = "6.1.0"
+version = "6.2.0"
 description = "Django admin CKEditor integration."
 category = "main"
 optional = false
@@ -1001,7 +1001,7 @@ six = "*"
 
 [[package]]
 name = "django-otp"
-version = "1.1.1"
+version = "1.1.3"
 description = "A pluggable framework for adding two-factor authentication to Django using one-time passwords."
 category = "main"
 optional = false
@@ -1015,7 +1015,7 @@ qrcode = ["qrcode"]
 
 [[package]]
 name = "django-otp-yubikey"
-version = "1.0.0.post1"
+version = "1.0.1"
 description = "A django-otp plugin that verifies YubiKey OTP tokens."
 category = "main"
 optional = false
@@ -1043,7 +1043,7 @@ phonenumberslite = ["phonenumberslite (>=7.0.2)"]
 
 [[package]]
 name = "django-polymorphic"
-version = "3.0.0"
+version = "3.1.0"
 description = "Seamless polymorphic inheritance for Django models"
 category = "main"
 optional = false
@@ -1065,7 +1065,7 @@ prometheus-client = ">=0.7"
 
 [[package]]
 name = "django-redis"
-version = "5.0.0"
+version = "5.1.0"
 description = "Full featured redis cache backend for Django."
 category = "main"
 optional = false
@@ -1073,7 +1073,10 @@ python-versions = ">=3.6"
 
 [package.dependencies]
 Django = ">=2.2"
-redis = ">=3.0.0"
+redis = ">=3,<4"
+
+[package.extras]
+hiredis = ["redis[hiredis] (>=3,<4)"]
 
 [[package]]
 name = "django-render-block"
@@ -1543,7 +1546,7 @@ python-versions = "*"
 
 [[package]]
 name = "ipython"
-version = "7.29.0"
+version = "7.30.0"
 description = "IPython: Productive Interactive Computing"
 category = "main"
 optional = false
@@ -1756,18 +1759,18 @@ attrs = ">=19.2.0"
 
 [[package]]
 name = "packaging"
-version = "21.2"
+version = "21.3"
 description = "Core utilities for Python packages"
 category = "main"
 optional = false
 python-versions = ">=3.6"
 
 [package.dependencies]
-pyparsing = ">=2.0.2,<3"
+pyparsing = ">=2.0.2,<3.0.5 || >3.0.5"
 
 [[package]]
 name = "parso"
-version = "0.8.2"
+version = "0.8.3"
 description = "A Python Parser"
 category = "main"
 optional = false
@@ -1795,7 +1798,7 @@ python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
 
 [[package]]
 name = "pbr"
-version = "5.7.0"
+version = "5.8.0"
 description = "Python Build Reasonableness"
 category = "dev"
 optional = false
@@ -1833,7 +1836,7 @@ scramp = ">=1.4.1"
 
 [[package]]
 name = "phonenumbers"
-version = "8.12.37"
+version = "8.12.38"
 description = "Python version of Google's common library for parsing, formatting, storing and validating international phone numbers."
 category = "main"
 optional = false
@@ -1892,7 +1895,7 @@ twisted = ["twisted"]
 
 [[package]]
 name = "prompt-toolkit"
-version = "3.0.22"
+version = "3.0.23"
 description = "Library for building powerful interactive command lines in Python"
 category = "main"
 optional = false
@@ -2025,11 +2028,14 @@ test = ["flaky", "pretend", "pytest (>=3.0.1)"]
 
 [[package]]
 name = "pyparsing"
-version = "2.4.7"
+version = "3.0.6"
 description = "Python parsing module"
 category = "main"
 optional = false
-python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
+python-versions = ">=3.6"
+
+[package.extras]
+diagrams = ["jinja2", "railroad-diagrams"]
 
 [[package]]
 name = "pytest"
@@ -2069,7 +2075,7 @@ testing = ["fields", "hunter", "process-tests", "six", "pytest-xdist", "virtuale
 
 [[package]]
 name = "pytest-django"
-version = "4.4.0"
+version = "4.5.0"
 description = "A Django plugin for pytest."
 category = "dev"
 optional = false
@@ -2135,7 +2141,7 @@ six = ">=1.5"
 
 [[package]]
 name = "python-gnupg"
-version = "0.4.7"
+version = "0.4.8"
 description = "A wrapper for the Gnu Privacy Guard (GPG or GnuPG)"
 category = "main"
 optional = false
@@ -2278,7 +2284,7 @@ python-versions = ">=3.5"
 
 [[package]]
 name = "rules"
-version = "3.0"
+version = "2.2"
 description = "Awesome Django authorization, without the database"
 category = "main"
 optional = false
@@ -2311,7 +2317,7 @@ asn1crypto = ">=1.4.0"
 
 [[package]]
 name = "selenium"
-version = "4.0.0"
+version = "4.1.0"
 description = ""
 category = "dev"
 optional = false
@@ -2678,7 +2684,7 @@ requests = ">=2.0.0"
 
 [[package]]
 name = "types-pytz"
-version = "2021.3.0"
+version = "2021.3.1"
 description = "Typing stubs for pytz"
 category = "dev"
 optional = false
@@ -2694,7 +2700,7 @@ python-versions = "*"
 
 [[package]]
 name = "typing-extensions"
-version = "4.0.0"
+version = "4.0.1"
 description = "Backported and Experimental Type Hints for Python 3.6+"
 category = "dev"
 optional = false
@@ -2784,7 +2790,7 @@ pycryptodome = "*"
 [metadata]
 lock-version = "1.1"
 python-versions = "^3.9"
-content-hash = "d1e937b590a63fb0c6c57bdf75aef8be499ee5dba2fdb5062fdc18ce5b4ff6d7"
+content-hash = "4a288b88c8dc19e28d5437bdb4d838daf0eb22c05557bcff74e754e6af3a9376"
 
 [metadata.files]
 alabaster = [
@@ -2792,20 +2798,20 @@ alabaster = [
     {file = "alabaster-0.7.12.tar.gz", hash = "sha256:a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02"},
 ]
 aleksis-app-chronos = [
-    {file = "AlekSIS-App-Chronos-2.1.dev2.tar.gz", hash = "sha256:01de027d0dfd80b4b0233763ba82f49bc29438eea81f01a77420196208e58391"},
-    {file = "AlekSIS_App_Chronos-2.1.dev2-py3-none-any.whl", hash = "sha256:57cc969da453938074ef01387004a8f1c52bf1a55f3b0437cb6f4aada07b7157"},
+    {file = "AlekSIS-App-Chronos-2.1.dev3.tar.gz", hash = "sha256:3cae1e9bd29ef3217ce3c9dc60589f8bfe0296b3349aa6f415479c7b9a38ee24"},
+    {file = "AlekSIS_App_Chronos-2.1.dev3-py3-none-any.whl", hash = "sha256:f901144d48722576874fcf6c249b389d6243539e9588d88da0598d1c4f1295fc"},
 ]
 aleksis-app-resint = [
     {file = "AlekSIS-App-Resint-2.0b1+20211107142135.95d735a4.tar.gz", hash = "sha256:9d81c6ebb8ba3c87d46735b100ff550fa6034dac4294fdab2b58b40dbc5452fd"},
     {file = "AlekSIS_App_Resint-2.0b1+20211107142135.95d735a4-py3-none-any.whl", hash = "sha256:d2aa485ae46c7eb4186d1500bdb0ded0214820c04c3ce01e04b2372af2d9dcd0"},
 ]
 aleksis-builddeps = [
-    {file = "AlekSIS-Builddeps-5+20211115090333.5c84baaf.tar.gz", hash = "sha256:c1572008de5b1aa98468c7b332622229838a1aadc8a10154cc678f220aa78c9b"},
-    {file = "AlekSIS_Builddeps-5+20211115090333.5c84baaf-py3-none-any.whl", hash = "sha256:05f91a8a2020927bfd89621377b2f0b04dc910c77aa55db6055b471dca6d2a72"},
+    {file = "AlekSIS-Builddeps-5+20211130152626.23302bab.tar.gz", hash = "sha256:bed0e9a4d00cf45f8cd75fcf059402c4b81525785ba2cb3d89c4cd6df907b58c"},
+    {file = "AlekSIS_Builddeps-5+20211130152626.23302bab-py3-none-any.whl", hash = "sha256:023f594eb06667f747059c8d69a2058e195d4644644a09d747197f152ece9741"},
 ]
 aleksis-core = [
-    {file = "AlekSIS-Core-2.2.dev0+20211114193927.5ca5f145.tar.gz", hash = "sha256:9b75dacd35b1d803906c5506f9bb4918123151093917f3fa75762a96e564904b"},
-    {file = "AlekSIS_Core-2.2.dev0+20211114193927.5ca5f145-py3-none-any.whl", hash = "sha256:60a7eebc04141a43286d52bf637ca50ee137984b2379b10feaa8e70f6bb084a9"},
+    {file = "AlekSIS-Core-2.2+20211129202100.032a3cac.tar.gz", hash = "sha256:e752af44c539ccb287c30bbc135e1d70aca246da5f1755945da468ced03ba8dc"},
+    {file = "AlekSIS_Core-2.2+20211129202100.032a3cac-py3-none-any.whl", hash = "sha256:b380f6797c58a13c3bb62f168b2e871036b6f973208d8da0fa4469d7e02dd487"},
 ]
 amqp = [
     {file = "amqp-5.0.6-py3-none-any.whl", hash = "sha256:493a2ac6788ce270a2f6a765b017299f60c1998f5a8617908ee9be082f7300fb"},
@@ -2856,8 +2862,8 @@ billiard = [
     {file = "billiard-3.6.4.0.tar.gz", hash = "sha256:299de5a8da28a783d51b197d496bef4f1595dd023a93a4f59dde1886ae905547"},
 ]
 black = [
-    {file = "black-21.11b0-py3-none-any.whl", hash = "sha256:0b1f66cbfadcd332ceeaeecf6373d9991d451868d2e2219ad0ac1213fb701117"},
-    {file = "black-21.11b0.tar.gz", hash = "sha256:83f3852301c8dcb229e9c444dd79f573c8d31c7c2dad9bbaaa94c808630e32aa"},
+    {file = "black-21.11b1-py3-none-any.whl", hash = "sha256:802c6c30b637b28645b7fde282ed2569c0cd777dbe493a41b6a03c1d903f99ac"},
+    {file = "black-21.11b1.tar.gz", hash = "sha256:a042adbb18b3262faad5aff4e834ff186bb893f95ba3a8013f09de1e5569def2"},
 ]
 bleach = [
     {file = "bleach-4.1.0-py2.py3-none-any.whl", hash = "sha256:4d2651ab93271d1129ac9cbc679f524565cc8a1b791909c4a51eac4446a15994"},
@@ -2943,8 +2949,8 @@ cffi = [
     {file = "cffi-1.15.0.tar.gz", hash = "sha256:920f0d66a896c2d99f0adbb391f990a84091179542c205fa53ce5787aff87954"},
 ]
 charset-normalizer = [
-    {file = "charset-normalizer-2.0.7.tar.gz", hash = "sha256:e019de665e2bcf9c2b64e2e5aa025fa991da8720daa3c1138cadd2fd1856aed0"},
-    {file = "charset_normalizer-2.0.7-py3-none-any.whl", hash = "sha256:f7af805c321bfa1ce6714c51f254e0d5bb5e5834039bc17db7ebe3a4cec9492b"},
+    {file = "charset-normalizer-2.0.8.tar.gz", hash = "sha256:735e240d9a8506778cd7a453d97e817e536bb1fc29f4f6961ce297b9c7a917b0"},
+    {file = "charset_normalizer-2.0.8-py3-none-any.whl", hash = "sha256:83fcdeb225499d6344c8f7f34684c2981270beacc32ede2e669e94f7fa544405"},
 ]
 click = [
     {file = "click-8.0.3-py3-none-any.whl", hash = "sha256:353f466495adaeb40b6b5f592f9f91cb22372351c84caeb068132442a4518ef3"},
@@ -2974,75 +2980,76 @@ configobj = [
     {file = "configobj-5.0.6.tar.gz", hash = "sha256:a2f5650770e1c87fb335af19a9b7eb73fc05ccf22144eb68db7d00cd2bcb0902"},
 ]
 coverage = [
-    {file = "coverage-6.1.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:675adb3b3380967806b3cbb9c5b00ceb29b1c472692100a338730c1d3e59c8b9"},
-    {file = "coverage-6.1.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:95a58336aa111af54baa451c33266a8774780242cab3704b7698d5e514840758"},
-    {file = "coverage-6.1.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:d0a595a781f8e186580ff8e3352dd4953b1944289bec7705377c80c7e36c4d6c"},
-    {file = "coverage-6.1.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:d3c5f49ce6af61154060640ad3b3281dbc46e2e0ef2fe78414d7f8a324f0b649"},
-    {file = "coverage-6.1.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:310c40bed6b626fd1f463e5a83dba19a61c4eb74e1ac0d07d454ebbdf9047e9d"},
-    {file = "coverage-6.1.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:a4d48e42e17d3de212f9af44f81ab73b9378a4b2b8413fd708d0d9023f2bbde4"},
-    {file = "coverage-6.1.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ffa545230ca2ad921ad066bf8fd627e7be43716b6e0fcf8e32af1b8188ccb0ab"},
-    {file = "coverage-6.1.2-cp310-cp310-win32.whl", hash = "sha256:cd2d11a59afa5001ff28073ceca24ae4c506da4355aba30d1e7dd2bd0d2206dc"},
-    {file = "coverage-6.1.2-cp310-cp310-win_amd64.whl", hash = "sha256:96129e41405887a53a9cc564f960d7f853cc63d178f3a182fdd302e4cab2745b"},
-    {file = "coverage-6.1.2-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:1de9c6f5039ee2b1860b7bad2c7bc3651fbeb9368e4c4d93e98a76358cdcb052"},
-    {file = "coverage-6.1.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:80cb70264e9a1d04b519cdba3cd0dc42847bf8e982a4d55c769b9b0ee7cdce1e"},
-    {file = "coverage-6.1.2-cp311-cp311-win_amd64.whl", hash = "sha256:ba6125d4e55c0b8e913dad27b22722eac7abdcb1f3eab1bd090eee9105660266"},
-    {file = "coverage-6.1.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:8492d37acdc07a6eac6489f6c1954026f2260a85a4c2bb1e343fe3d35f5ee21a"},
-    {file = "coverage-6.1.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:66af99c7f7b64d050d37e795baadf515b4561124f25aae6e1baa482438ecc388"},
-    {file = "coverage-6.1.2-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:ebcc03e1acef4ff44f37f3c61df478d6e469a573aa688e5a162f85d7e4c3860d"},
-    {file = "coverage-6.1.2-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98d44a8136eebbf544ad91fef5bd2b20ef0c9b459c65a833c923d9aa4546b204"},
-    {file = "coverage-6.1.2-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:c18725f3cffe96732ef96f3de1939d81215fd6d7d64900dcc4acfe514ea4fcbf"},
-    {file = "coverage-6.1.2-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:c8e9c4bcaaaa932be581b3d8b88b677489975f845f7714efc8cce77568b6711c"},
-    {file = "coverage-6.1.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:06d009e8a29483cbc0520665bc46035ffe9ae0e7484a49f9782c2a716e37d0a0"},
-    {file = "coverage-6.1.2-cp36-cp36m-win32.whl", hash = "sha256:e5432d9c329b11c27be45ee5f62cf20a33065d482c8dec1941d6670622a6fb8f"},
-    {file = "coverage-6.1.2-cp36-cp36m-win_amd64.whl", hash = "sha256:82fdcb64bf08aa5db881db061d96db102c77397a570fbc112e21c48a4d9cb31b"},
-    {file = "coverage-6.1.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:94f558f8555e79c48c422045f252ef41eb43becdd945e9c775b45ebfc0cbd78f"},
-    {file = "coverage-6.1.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:046647b96969fda1ae0605f61288635209dd69dcd27ba3ec0bf5148bc157f954"},
-    {file = "coverage-6.1.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:cc799916b618ec9fd00135e576424165691fec4f70d7dc12cfaef09268a2478c"},
-    {file = "coverage-6.1.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:62646d98cf0381ffda301a816d6ac6c35fc97aa81b09c4c52d66a15c4bef9d7c"},
-    {file = "coverage-6.1.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:27a3df08a855522dfef8b8635f58bab81341b2fb5f447819bc252da3aa4cf44c"},
-    {file = "coverage-6.1.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:610c0ba11da8de3a753dc4b1f71894f9f9debfdde6559599f303286e70aeb0c2"},
-    {file = "coverage-6.1.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:35b246ae3a2c042dc8f410c94bcb9754b18179cdb81ff9477a9089dbc9ecc186"},
-    {file = "coverage-6.1.2-cp37-cp37m-win32.whl", hash = "sha256:0cde7d9fe2fb55ff68ebe7fb319ef188e9b88e0a3d1c9c5db7dd829cd93d2193"},
-    {file = "coverage-6.1.2-cp37-cp37m-win_amd64.whl", hash = "sha256:958ac66272ff20e63d818627216e3d7412fdf68a2d25787b89a5c6f1eb7fdd93"},
-    {file = "coverage-6.1.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a300b39c3d5905686c75a369d2a66e68fd01472ea42e16b38c948bd02b29e5bd"},
-    {file = "coverage-6.1.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d3855d5d26292539861f5ced2ed042fc2aa33a12f80e487053aed3bcb6ced13"},
-    {file = "coverage-6.1.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:586d38dfc7da4a87f5816b203ff06dd7c1bb5b16211ccaa0e9788a8da2b93696"},
-    {file = "coverage-6.1.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a34fccb45f7b2d890183a263578d60a392a1a218fdc12f5bce1477a6a68d4373"},
-    {file = "coverage-6.1.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:bc1ee1318f703bc6c971da700d74466e9b86e0c443eb85983fb2a1bd20447263"},
-    {file = "coverage-6.1.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:3f546f48d5d80a90a266769aa613bc0719cb3e9c2ef3529d53f463996dd15a9d"},
-    {file = "coverage-6.1.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:fd92ece726055e80d4e3f01fff3b91f54b18c9c357c48fcf6119e87e2461a091"},
-    {file = "coverage-6.1.2-cp38-cp38-win32.whl", hash = "sha256:24ed38ec86754c4d5a706fbd5b52b057c3df87901a8610d7e5642a08ec07087e"},
-    {file = "coverage-6.1.2-cp38-cp38-win_amd64.whl", hash = "sha256:97ef6e9119bd39d60ef7b9cd5deea2b34869c9f0b9777450a7e3759c1ab09b9b"},
-    {file = "coverage-6.1.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6e5a8c947a2a89c56655ecbb789458a3a8e3b0cbf4c04250331df8f647b3de59"},
-    {file = "coverage-6.1.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7a39590d1e6acf6a3c435c5d233f72f5d43b585f5be834cff1f21fec4afda225"},
-    {file = "coverage-6.1.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:9d2c2e3ce7b8cc932a2f918186964bd44de8c84e2f9ef72dc616f5bb8be22e71"},
-    {file = "coverage-6.1.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3348865798c077c695cae00da0924136bb5cc501f236cfd6b6d9f7a3c94e0ec4"},
-    {file = "coverage-6.1.2-cp39-cp39-win32.whl", hash = "sha256:fae3fe111670e51f1ebbc475823899524e3459ea2db2cb88279bbfb2a0b8a3de"},
-    {file = "coverage-6.1.2-cp39-cp39-win_amd64.whl", hash = "sha256:af45eea024c0e3a25462fade161afab4f0d9d9e0d5a5d53e86149f74f0a35ecc"},
-    {file = "coverage-6.1.2-pp36.pp37.pp38-none-any.whl", hash = "sha256:eab14fdd410500dae50fd14ccc332e65543e7b39f6fc076fe90603a0e5d2f929"},
-    {file = "coverage-6.1.2.tar.gz", hash = "sha256:d9a635114b88c0ab462e0355472d00a180a5fbfd8511e7f18e4ac32652e7d972"},
+    {file = "coverage-6.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6dbc1536e105adda7a6312c778f15aaabe583b0e9a0b0a324990334fd458c94b"},
+    {file = "coverage-6.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:174cf9b4bef0db2e8244f82059a5a72bd47e1d40e71c68ab055425172b16b7d0"},
+    {file = "coverage-6.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:92b8c845527eae547a2a6617d336adc56394050c3ed8a6918683646328fbb6da"},
+    {file = "coverage-6.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c7912d1526299cb04c88288e148c6c87c0df600eca76efd99d84396cfe00ef1d"},
+    {file = "coverage-6.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d5d2033d5db1d58ae2d62f095e1aefb6988af65b4b12cb8987af409587cc0739"},
+    {file = "coverage-6.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:3feac4084291642165c3a0d9eaebedf19ffa505016c4d3db15bfe235718d4971"},
+    {file = "coverage-6.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:276651978c94a8c5672ea60a2656e95a3cce2a3f31e9fb2d5ebd4c215d095840"},
+    {file = "coverage-6.2-cp310-cp310-win32.whl", hash = "sha256:f506af4f27def639ba45789fa6fde45f9a217da0be05f8910458e4557eed020c"},
+    {file = "coverage-6.2-cp310-cp310-win_amd64.whl", hash = "sha256:3f7c17209eef285c86f819ff04a6d4cbee9b33ef05cbcaae4c0b4e8e06b3ec8f"},
+    {file = "coverage-6.2-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:13362889b2d46e8d9f97c421539c97c963e34031ab0cb89e8ca83a10cc71ac76"},
+    {file = "coverage-6.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:22e60a3ca5acba37d1d4a2ee66e051f5b0e1b9ac950b5b0cf4aa5366eda41d47"},
+    {file = "coverage-6.2-cp311-cp311-win_amd64.whl", hash = "sha256:b637c57fdb8be84e91fac60d9325a66a5981f8086c954ea2772efe28425eaf64"},
+    {file = "coverage-6.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f467bbb837691ab5a8ca359199d3429a11a01e6dfb3d9dcc676dc035ca93c0a9"},
+    {file = "coverage-6.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2641f803ee9f95b1f387f3e8f3bf28d83d9b69a39e9911e5bfee832bea75240d"},
+    {file = "coverage-6.2-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:1219d760ccfafc03c0822ae2e06e3b1248a8e6d1a70928966bafc6838d3c9e48"},
+    {file = "coverage-6.2-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:9a2b5b52be0a8626fcbffd7e689781bf8c2ac01613e77feda93d96184949a98e"},
+    {file = "coverage-6.2-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:8e2c35a4c1f269704e90888e56f794e2d9c0262fb0c1b1c8c4ee44d9b9e77b5d"},
+    {file = "coverage-6.2-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:5d6b09c972ce9200264c35a1d53d43ca55ef61836d9ec60f0d44273a31aa9f17"},
+    {file = "coverage-6.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:e3db840a4dee542e37e09f30859f1612da90e1c5239a6a2498c473183a50e781"},
+    {file = "coverage-6.2-cp36-cp36m-win32.whl", hash = "sha256:4e547122ca2d244f7c090fe3f4b5a5861255ff66b7ab6d98f44a0222aaf8671a"},
+    {file = "coverage-6.2-cp36-cp36m-win_amd64.whl", hash = "sha256:01774a2c2c729619760320270e42cd9e797427ecfddd32c2a7b639cdc481f3c0"},
+    {file = "coverage-6.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:fb8b8ee99b3fffe4fd86f4c81b35a6bf7e4462cba019997af2fe679365db0c49"},
+    {file = "coverage-6.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:619346d57c7126ae49ac95b11b0dc8e36c1dd49d148477461bb66c8cf13bb521"},
+    {file = "coverage-6.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0a7726f74ff63f41e95ed3a89fef002916c828bb5fcae83b505b49d81a066884"},
+    {file = "coverage-6.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:cfd9386c1d6f13b37e05a91a8583e802f8059bebfccde61a418c5808dea6bbfa"},
+    {file = "coverage-6.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:17e6c11038d4ed6e8af1407d9e89a2904d573be29d51515f14262d7f10ef0a64"},
+    {file = "coverage-6.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c254b03032d5a06de049ce8bca8338a5185f07fb76600afff3c161e053d88617"},
+    {file = "coverage-6.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:dca38a21e4423f3edb821292e97cec7ad38086f84313462098568baedf4331f8"},
+    {file = "coverage-6.2-cp37-cp37m-win32.whl", hash = "sha256:600617008aa82032ddeace2535626d1bc212dfff32b43989539deda63b3f36e4"},
+    {file = "coverage-6.2-cp37-cp37m-win_amd64.whl", hash = "sha256:bf154ba7ee2fd613eb541c2bc03d3d9ac667080a737449d1a3fb342740eb1a74"},
+    {file = "coverage-6.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f9afb5b746781fc2abce26193d1c817b7eb0e11459510fba65d2bd77fe161d9e"},
+    {file = "coverage-6.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:edcada2e24ed68f019175c2b2af2a8b481d3d084798b8c20d15d34f5c733fa58"},
+    {file = "coverage-6.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:a9c8c4283e17690ff1a7427123ffb428ad6a52ed720d550e299e8291e33184dc"},
+    {file = "coverage-6.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f614fc9956d76d8a88a88bb41ddc12709caa755666f580af3a688899721efecd"},
+    {file = "coverage-6.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9365ed5cce5d0cf2c10afc6add145c5037d3148585b8ae0e77cc1efdd6aa2953"},
+    {file = "coverage-6.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8bdfe9ff3a4ea37d17f172ac0dff1e1c383aec17a636b9b35906babc9f0f5475"},
+    {file = "coverage-6.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:63c424e6f5b4ab1cf1e23a43b12f542b0ec2e54f99ec9f11b75382152981df57"},
+    {file = "coverage-6.2-cp38-cp38-win32.whl", hash = "sha256:49dbff64961bc9bdd2289a2bda6a3a5a331964ba5497f694e2cbd540d656dc1c"},
+    {file = "coverage-6.2-cp38-cp38-win_amd64.whl", hash = "sha256:9a29311bd6429be317c1f3fe4bc06c4c5ee45e2fa61b2a19d4d1d6111cb94af2"},
+    {file = "coverage-6.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:03b20e52b7d31be571c9c06b74746746d4eb82fc260e594dc662ed48145e9efd"},
+    {file = "coverage-6.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:215f8afcc02a24c2d9a10d3790b21054b58d71f4b3c6f055d4bb1b15cecce685"},
+    {file = "coverage-6.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:a4bdeb0a52d1d04123b41d90a4390b096f3ef38eee35e11f0b22c2d031222c6c"},
+    {file = "coverage-6.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c332d8f8d448ded473b97fefe4a0983265af21917d8b0cdcb8bb06b2afe632c3"},
+    {file = "coverage-6.2-cp39-cp39-win32.whl", hash = "sha256:6e1394d24d5938e561fbeaa0cd3d356207579c28bd1792f25a068743f2d5b282"},
+    {file = "coverage-6.2-cp39-cp39-win_amd64.whl", hash = "sha256:86f2e78b1eff847609b1ca8050c9e1fa3bd44ce755b2ec30e70f2d3ba3844644"},
+    {file = "coverage-6.2-pp36.pp37.pp38-none-any.whl", hash = "sha256:5829192582c0ec8ca4a2532407bc14c2f338d9878a10442f5d03804a95fac9de"},
+    {file = "coverage-6.2.tar.gz", hash = "sha256:e2cad8093172b7d1595b4ad66f24270808658e11acf43a8f95b41276162eb5b8"},
 ]
 cryptography = [
-    {file = "cryptography-35.0.0-cp36-abi3-macosx_10_10_x86_64.whl", hash = "sha256:d57e0cdc1b44b6cdf8af1d01807db06886f10177469312fbde8f44ccbb284bc9"},
-    {file = "cryptography-35.0.0-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:ced40344e811d6abba00295ced98c01aecf0c2de39481792d87af4fa58b7b4d6"},
-    {file = "cryptography-35.0.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:54b2605e5475944e2213258e0ab8696f4f357a31371e538ef21e8d61c843c28d"},
-    {file = "cryptography-35.0.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:7b7ceeff114c31f285528ba8b390d3e9cfa2da17b56f11d366769a807f17cbaa"},
-    {file = "cryptography-35.0.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d69645f535f4b2c722cfb07a8eab916265545b3475fdb34e0be2f4ee8b0b15e"},
-    {file = "cryptography-35.0.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a2d0e0acc20ede0f06ef7aa58546eee96d2592c00f450c9acb89c5879b61992"},
-    {file = "cryptography-35.0.0-cp36-abi3-manylinux_2_24_x86_64.whl", hash = "sha256:07bb7fbfb5de0980590ddfc7f13081520def06dc9ed214000ad4372fb4e3c7f6"},
-    {file = "cryptography-35.0.0-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:7eba2cebca600a7806b893cb1d541a6e910afa87e97acf2021a22b32da1df52d"},
-    {file = "cryptography-35.0.0-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:18d90f4711bf63e2fb21e8c8e51ed8189438e6b35a6d996201ebd98a26abbbe6"},
-    {file = "cryptography-35.0.0-cp36-abi3-win32.whl", hash = "sha256:c10c797ac89c746e488d2ee92bd4abd593615694ee17b2500578b63cad6b93a8"},
-    {file = "cryptography-35.0.0-cp36-abi3-win_amd64.whl", hash = "sha256:7075b304cd567694dc692ffc9747f3e9cb393cc4aa4fb7b9f3abd6f5c4e43588"},
-    {file = "cryptography-35.0.0-pp36-pypy36_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a688ebcd08250eab5bb5bca318cc05a8c66de5e4171a65ca51db6bd753ff8953"},
-    {file = "cryptography-35.0.0-pp36-pypy36_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d99915d6ab265c22873f1b4d6ea5ef462ef797b4140be4c9d8b179915e0985c6"},
-    {file = "cryptography-35.0.0-pp36-pypy36_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:928185a6d1ccdb816e883f56ebe92e975a262d31cc536429041921f8cb5a62fd"},
-    {file = "cryptography-35.0.0-pp37-pypy37_pp73-macosx_10_10_x86_64.whl", hash = "sha256:ebeddd119f526bcf323a89f853afb12e225902a24d29b55fe18dd6fcb2838a76"},
-    {file = "cryptography-35.0.0-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:22a38e96118a4ce3b97509443feace1d1011d0571fae81fc3ad35f25ba3ea999"},
-    {file = "cryptography-35.0.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb80e8a1f91e4b7ef8b33041591e6d89b2b8e122d787e87eeb2b08da71bb16ad"},
-    {file = "cryptography-35.0.0-pp37-pypy37_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:abb5a361d2585bb95012a19ed9b2c8f412c5d723a9836418fab7aaa0243e67d2"},
-    {file = "cryptography-35.0.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:1ed82abf16df40a60942a8c211251ae72858b25b7421ce2497c2eb7a1cee817c"},
-    {file = "cryptography-35.0.0.tar.gz", hash = "sha256:9933f28f70d0517686bd7de36166dda42094eac49415459d9bdf5e7df3e0086d"},
+    {file = "cryptography-36.0.0-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:9511416e85e449fe1de73f7f99b21b3aa04fba4c4d335d30c486ba3756e3a2a6"},
+    {file = "cryptography-36.0.0-cp36-abi3-macosx_10_10_x86_64.whl", hash = "sha256:97199a13b772e74cdcdb03760c32109c808aff7cd49c29e9cf4b7754bb725d1d"},
+    {file = "cryptography-36.0.0-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:494106e9cd945c2cadfce5374fa44c94cfadf01d4566a3b13bb487d2e6c7959e"},
+    {file = "cryptography-36.0.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6fbbbb8aab4053fa018984bb0e95a16faeb051dd8cca15add2a27e267ba02b58"},
+    {file = "cryptography-36.0.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:684993ff6f67000a56454b41bdc7e015429732d65a52d06385b6e9de6181c71e"},
+    {file = "cryptography-36.0.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4c702855cd3174666ef0d2d13dcc879090aa9c6c38f5578896407a7028f75b9f"},
+    {file = "cryptography-36.0.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d91bc9f535599bed58f6d2e21a2724cb0c3895bf41c6403fe881391d29096f1d"},
+    {file = "cryptography-36.0.0-cp36-abi3-manylinux_2_24_x86_64.whl", hash = "sha256:b17d83b3d1610e571fedac21b2eb36b816654d6f7496004d6a0d32f99d1d8120"},
+    {file = "cryptography-36.0.0-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:8982c19bb90a4fa2aad3d635c6d71814e38b643649b4000a8419f8691f20ac44"},
+    {file = "cryptography-36.0.0-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:24469d9d33217ffd0ce4582dfcf2a76671af115663a95328f63c99ec7ece61a4"},
+    {file = "cryptography-36.0.0-cp36-abi3-win32.whl", hash = "sha256:f6a5a85beb33e57998dc605b9dbe7deaa806385fdf5c4810fb849fcd04640c81"},
+    {file = "cryptography-36.0.0-cp36-abi3-win_amd64.whl", hash = "sha256:2deab5ec05d83ddcf9b0916319674d3dae88b0e7ee18f8962642d3cde0496568"},
+    {file = "cryptography-36.0.0-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2049f8b87f449fc6190350de443ee0c1dd631f2ce4fa99efad2984de81031681"},
+    {file = "cryptography-36.0.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a776bae1629c8d7198396fd93ec0265f8dd2341c553dc32b976168aaf0e6a636"},
+    {file = "cryptography-36.0.0-pp37-pypy37_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:aa94d617a4cd4cdf4af9b5af65100c036bce22280ebb15d8b5262e8273ebc6ba"},
+    {file = "cryptography-36.0.0-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:5c49c9e8fb26a567a2b3fa0343c89f5d325447956cc2fc7231c943b29a973712"},
+    {file = "cryptography-36.0.0-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ef216d13ac8d24d9cd851776662f75f8d29c9f2d05cdcc2d34a18d32463a9b0b"},
+    {file = "cryptography-36.0.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:231c4a69b11f6af79c1495a0e5a85909686ea8db946935224b7825cfb53827ed"},
+    {file = "cryptography-36.0.0-pp38-pypy38_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:f92556f94e476c1b616e6daec5f7ddded2c082efa7cee7f31c7aeda615906ed8"},
+    {file = "cryptography-36.0.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:d73e3a96c38173e0aa5646c31bf8473bc3564837977dd480f5cbeacf1d7ef3a3"},
+    {file = "cryptography-36.0.0.tar.gz", hash = "sha256:52f769ecb4ef39865719aedc67b4b7eae167bafa48dbc2a26dd36fa56460507f"},
 ]
 curlylint = [
     {file = "curlylint-0.13.0-py3-none-any.whl", hash = "sha256:63e5fc98f99c7b0eab0c4e3390356ad569b7bb3eecb6da115e6cb9ee98eb738f"},
@@ -3069,7 +3076,7 @@ django = [
     {file = "Django-3.2.9.tar.gz", hash = "sha256:51284300f1522ffcdb07ccbdf676a307c6678659e1284f0618e5a774127a6a08"},
 ]
 django-allauth = [
-    {file = "django-allauth-0.45.0.tar.gz", hash = "sha256:6d46be0e1480316ccd45476db3aefb39db70e038d2a543112d314b76bb999a4e"},
+    {file = "django-allauth-0.46.0.tar.gz", hash = "sha256:8217b8dc46f85812ff209fc542f4bf378f1751cdbe867008169d4c85685df50d"},
 ]
 django-any-js = [
     {file = "django-any-js-1.1.tar.gz", hash = "sha256:2972946902ba049f73bf8bb87e0a0118f77a8c9dca89438f193598bff758422f"},
@@ -3104,8 +3111,8 @@ django-celery-results = [
     {file = "django_celery_results-2.2.0.tar.gz", hash = "sha256:cc0285090a306f97f1d4b7929ed98af0475bf6db2568976b3387de4fbe812edc"},
 ]
 django-ckeditor = [
-    {file = "django-ckeditor-6.1.0.tar.gz", hash = "sha256:f0d108f67a81a04e26d8de11255fe314f51026eaf8eb0534a807512ae3c21620"},
-    {file = "django_ckeditor-6.1.0-py2.py3-none-any.whl", hash = "sha256:346b26b9d60dc8a88524d0eaaf406f4e91a4b3c22d208ae87aa032bf500b251c"},
+    {file = "django-ckeditor-6.2.0.tar.gz", hash = "sha256:df64dc9e62790ef824f609605d31be847bdbce1cc7aa94e49bd5ca60d7aa79bb"},
+    {file = "django_ckeditor-6.2.0-py2.py3-none-any.whl", hash = "sha256:9f66420907e41f5b4e698fa5671a00a86995776735f2c4696174aed4640fcbd8"},
 ]
 django-cleanup = [
     {file = "django-cleanup-5.2.0.tar.gz", hash = "sha256:909d10ff574f5ce1a40fa63bd5c94c9ed866fd7ae770994c46cdf66c3db3e846"},
@@ -3193,28 +3200,28 @@ django-oauth-toolkit = [
     {file = "django_oauth_toolkit-1.5.0-py3-none-any.whl", hash = "sha256:b2e346a7c1e222774bfb370f21b556b92b408395b4c23914e2d1b241b2e5376a"},
 ]
 django-otp = [
-    {file = "django-otp-1.1.1.tar.gz", hash = "sha256:4c90cdaed683d736b0efafc034a3c6b410e1be2a53c24da287165b1f371d8776"},
-    {file = "django_otp-1.1.1-py3-none-any.whl", hash = "sha256:0c03a471db9e876f3671314bc9a65bd56a5c3c108ee0562c473701310bba4a77"},
+    {file = "django-otp-1.1.3.tar.gz", hash = "sha256:f002c71d4ea7f514590be00492980d3c87397b73dc20542e1c4fc00b66f2dda1"},
+    {file = "django_otp-1.1.3-py3-none-any.whl", hash = "sha256:8637be826c0465d0fd1710e4472efe9fc83883853a2141fefdbace9358d20003"},
 ]
 django-otp-yubikey = [
-    {file = "django-otp-yubikey-1.0.0.post1.tar.gz", hash = "sha256:1da060257611d06e681848b7923fd788d878a79e8c358a373374deab13a085af"},
-    {file = "django_otp_yubikey-1.0.0.post1-py2.py3-none-any.whl", hash = "sha256:613c96be211c1267400a5a78ae63f212c722f82dffb9daef3c8b1df370abb9be"},
+    {file = "django-otp-yubikey-1.0.1.tar.gz", hash = "sha256:5917b9134fa408d12b94bdb4d3cac23e4586ae99c3a42fcb1d2c287c182e6c77"},
+    {file = "django_otp_yubikey-1.0.1-py2.py3-none-any.whl", hash = "sha256:5a1b59be47088a3eccf376ca27d708bdcccfeb30324bb5ca01ed2d669b73756c"},
 ]
 django-phonenumber-field = [
     {file = "django-phonenumber-field-5.2.0.tar.gz", hash = "sha256:52b2e5970133ec5ab701218b802f7ab237229854dc95fd239b7e9e77dc43731d"},
     {file = "django_phonenumber_field-5.2.0-py3-none-any.whl", hash = "sha256:5547fb2b2cc690a306ba77a5038419afc8fa8298a486fb7895008e9067cc7e75"},
 ]
 django-polymorphic = [
-    {file = "django-polymorphic-3.0.0.tar.gz", hash = "sha256:9d886f19f031d26bb1391c055ed9be06fb226a04a4cec1842b372c58873b3caa"},
-    {file = "django_polymorphic-3.0.0-py2.py3-none-any.whl", hash = "sha256:73b75eb44ea302bd32820f8661e469509d245ce7f7ff09cd2ad149e5c42034ff"},
+    {file = "django-polymorphic-3.1.0.tar.gz", hash = "sha256:d6955b5308bf6e41dcb22ba7c96f00b51dfa497a8a5ab1e9c06c7951bf417bf8"},
+    {file = "django_polymorphic-3.1.0-py3-none-any.whl", hash = "sha256:08bc4f4f4a773a19b2deced5a56deddd1ef56ebd15207bf4052e2901c25ef57e"},
 ]
 django-prometheus = [
     {file = "django-prometheus-2.1.0.tar.gz", hash = "sha256:dd3f8da1399140fbef5c00d1526a23d1ade286b144281c325f8e409a781643f2"},
     {file = "django_prometheus-2.1.0-py2.py3-none-any.whl", hash = "sha256:c338d6efde1ca336e90c540b5e87afe9287d7bcc82d651a778f302b0be17a933"},
 ]
 django-redis = [
-    {file = "django-redis-5.0.0.tar.gz", hash = "sha256:048f665bbe27f8ff2edebae6aa9c534ab137f1e8fa7234147ef470df3f3aa9b8"},
-    {file = "django_redis-5.0.0-py3-none-any.whl", hash = "sha256:97739ca9de3f964c51412d1d7d8aecdfd86737bb197fce6e1ff12620c63c97ee"},
+    {file = "django-redis-5.1.0.tar.gz", hash = "sha256:98fb3d31633a1addea1aeb558a647359908bbcf78c0833f99496c5348fe3c1b4"},
+    {file = "django_redis-5.1.0-py3-none-any.whl", hash = "sha256:bf75bce0d6f65c3a6165dd6789506c8d22238f3bfaf7c4ad447e55afbc5b68cb"},
 ]
 django-render-block = [
     {file = "django-render-block-0.8.1.tar.gz", hash = "sha256:edbc5d444cc50f3eb3387cf17f6f1014bf19d6018f680861cdeae9e0306003fa"},
@@ -3366,8 +3373,8 @@ iniconfig = [
     {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"},
 ]
 ipython = [
-    {file = "ipython-7.29.0-py3-none-any.whl", hash = "sha256:a658beaf856ce46bc453366d5dc6b2ddc6c481efd3540cb28aa3943819caac9f"},
-    {file = "ipython-7.29.0.tar.gz", hash = "sha256:4f69d7423a5a1972f6347ff233e38bbf4df6a150ef20fbb00c635442ac3060aa"},
+    {file = "ipython-7.30.0-py3-none-any.whl", hash = "sha256:c8f3e07aefb9cf9e067f39686f035ce09b27a1ee602116a3030b91b6fc138ee4"},
+    {file = "ipython-7.30.0.tar.gz", hash = "sha256:d41f8e80b99690122400f9b2069b12f670246a1b4cc5d332bd6c4e2500e6d6fb"},
 ]
 isort = [
     {file = "isort-5.10.1-py3-none-any.whl", hash = "sha256:6f62d78e2f89b4500b080fe3a81690850cd254227f27f75c3a0c491a1f351ba7"},
@@ -3506,12 +3513,12 @@ outcome = [
     {file = "outcome-1.1.0.tar.gz", hash = "sha256:e862f01d4e626e63e8f92c38d1f8d5546d3f9cce989263c521b2e7990d186967"},
 ]
 packaging = [
-    {file = "packaging-21.2-py3-none-any.whl", hash = "sha256:14317396d1e8cdb122989b916fa2c7e9ca8e2be9e8060a6eff75b6b7b4d8a7e0"},
-    {file = "packaging-21.2.tar.gz", hash = "sha256:096d689d78ca690e4cd8a89568ba06d07ca097e3306a4381635073ca91479966"},
+    {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"},
+    {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"},
 ]
 parso = [
-    {file = "parso-0.8.2-py2.py3-none-any.whl", hash = "sha256:a8c4922db71e4fdb90e0d0bc6e50f9b273d3397925e5e60a717e719201778d22"},
-    {file = "parso-0.8.2.tar.gz", hash = "sha256:12b83492c6239ce32ff5eed6d3639d6a536170723c6f3f1506869f1ace413398"},
+    {file = "parso-0.8.3-py2.py3-none-any.whl", hash = "sha256:c001d4636cd3aecdaf33cbb40aebb59b094be2a74c556778ef5576c175e19e75"},
+    {file = "parso-0.8.3.tar.gz", hash = "sha256:8c07be290bb59f03588915921e29e8a50002acaf2cdc5fa0e0114f91709fafa0"},
 ]
 parsy = [
     {file = "parsy-1.1.0-py3-none-any.whl", hash = "sha256:25bd5cea2954950ebbfdf71f8bdaf7fd45a5df5325fd36a1064be2204d9d4c94"},
@@ -3522,8 +3529,8 @@ pathspec = [
     {file = "pathspec-0.9.0.tar.gz", hash = "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1"},
 ]
 pbr = [
-    {file = "pbr-5.7.0-py2.py3-none-any.whl", hash = "sha256:60002958e459b195e8dbe61bf22bcf344eedf1b4e03a321a5414feb15566100c"},
-    {file = "pbr-5.7.0.tar.gz", hash = "sha256:4651ca1445e80f2781827305de3d76b3ce53195f2227762684eb08f17bc473b7"},
+    {file = "pbr-5.8.0-py2.py3-none-any.whl", hash = "sha256:176e8560eaf61e127817ef93d8a844803abb27a4d4637f0ff3bb783129be2e0a"},
+    {file = "pbr-5.8.0.tar.gz", hash = "sha256:672d8ebee84921862110f23fcec2acea191ef58543d34dfe9ef3d9f13c31cddf"},
 ]
 persisting-theory = [
     {file = "persisting-theory-0.2.1.tar.gz", hash = "sha256:00ff7dcc8f481ff75c770ca5797d968e8725b6df1f77fe0cf7d20fa1e5790c0a"},
@@ -3537,8 +3544,8 @@ pg8000 = [
     {file = "pg8000-1.23.0.tar.gz", hash = "sha256:a413e00141342813a2ca47e8b7b0549ff338cca02bc819076b6d70f12d755c79"},
 ]
 phonenumbers = [
-    {file = "phonenumbers-8.12.37-py2.py3-none-any.whl", hash = "sha256:355956697047bc89efd89909373a0bdc50ac725c5613b2684a478d6b408a4010"},
-    {file = "phonenumbers-8.12.37.tar.gz", hash = "sha256:dbc560992844a059f56c7c0c6a587904e65d956740bbfb7e39589980bc9055b8"},
+    {file = "phonenumbers-8.12.38-py2.py3-none-any.whl", hash = "sha256:95c8a30157323a73a4f9207792e3ed69b626b4c74d8fc44064f25e7fb56cfc94"},
+    {file = "phonenumbers-8.12.38.tar.gz", hash = "sha256:3cda1d1cea9a6801babf825e6c0f6a9776ea6d8a68b81b256178f8e5aa813344"},
 ]
 pickleshare = [
     {file = "pickleshare-0.7.5-py2.py3-none-any.whl", hash = "sha256:9649af414d74d4df115d5d718f82acb59c9d418196b7b4290ed47a12ce62df56"},
@@ -3600,8 +3607,8 @@ prometheus-client = [
     {file = "prometheus_client-0.12.0.tar.gz", hash = "sha256:1b12ba48cee33b9b0b9de64a1047cbd3c5f2d0ab6ebcead7ddda613a750ec3c5"},
 ]
 prompt-toolkit = [
-    {file = "prompt_toolkit-3.0.22-py3-none-any.whl", hash = "sha256:48d85cdca8b6c4f16480c7ce03fd193666b62b0a21667ca56b4bb5ad679d1170"},
-    {file = "prompt_toolkit-3.0.22.tar.gz", hash = "sha256:449f333dd120bd01f5d296a8ce1452114ba3a71fae7288d2f0ae2c918764fa72"},
+    {file = "prompt_toolkit-3.0.23-py3-none-any.whl", hash = "sha256:5f29d62cb7a0ecacfa3d8ceea05a63cd22500543472d64298fc06ddda906b25d"},
+    {file = "prompt_toolkit-3.0.23.tar.gz", hash = "sha256:7053aba00895473cb357819358ef33f11aa97e4ac83d38efb123e5649ceeecaf"},
 ]
 psutil = [
     {file = "psutil-5.8.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:0066a82f7b1b37d334e68697faba68e5ad5e858279fd6351c8ca6024e8d6ba64"},
@@ -3715,8 +3722,8 @@ pyopenssl = [
     {file = "pyOpenSSL-21.0.0.tar.gz", hash = "sha256:5e2d8c5e46d0d865ae933bef5230090bdaf5506281e9eec60fa250ee80600cb3"},
 ]
 pyparsing = [
-    {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"},
-    {file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"},
+    {file = "pyparsing-3.0.6-py3-none-any.whl", hash = "sha256:04ff808a5b90911829c55c4e26f75fa5ca8a2f5f36aa3a51f68e27033341d3e4"},
+    {file = "pyparsing-3.0.6.tar.gz", hash = "sha256:d9bdec0013ef1eb5a84ab39a3b3868911598afa494f5faa038647101504e2b81"},
 ]
 pytest = [
     {file = "pytest-6.2.5-py3-none-any.whl", hash = "sha256:7310f8d27bc79ced999e760ca304d69f6ba6c6649c0b60fb0e04a4a77cacc134"},
@@ -3727,8 +3734,8 @@ pytest-cov = [
     {file = "pytest_cov-3.0.0-py3-none-any.whl", hash = "sha256:578d5d15ac4a25e5f961c938b85a05b09fdaae9deef3bb6de9a6e766622ca7a6"},
 ]
 pytest-django = [
-    {file = "pytest-django-4.4.0.tar.gz", hash = "sha256:b5171e3798bf7e3fc5ea7072fe87324db67a4dd9f1192b037fed4cc3c1b7f455"},
-    {file = "pytest_django-4.4.0-py3-none-any.whl", hash = "sha256:65783e78382456528bd9d79a35843adde9e6a47347b20464eb2c885cb0f1f606"},
+    {file = "pytest-django-4.5.0.tar.gz", hash = "sha256:4b1120c364404cfa9f54e2229b5c39151821bb17819e4bcf357e0f62a3e925a0"},
+    {file = "pytest_django-4.5.0-py3-none-any.whl", hash = "sha256:10cb6e5baacd56ca1f0134ce448b050c31824ba4e480eb7e0fa3832f3a0f8b4c"},
 ]
 pytest-django-testing-postgresql = [
     {file = "pytest-django-testing-postgresql-0.1.post0.tar.gz", hash = "sha256:78b0c58930084cb4393407b2e5a2a3b8734c627b841ecef7d62d39bbfb8e8a45"},
@@ -3745,8 +3752,8 @@ python-dateutil = [
     {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"},
 ]
 python-gnupg = [
-    {file = "python-gnupg-0.4.7.tar.gz", hash = "sha256:2061f56b1942c29b92727bf9aecbd3cea3893acc9cccbdc7eb4604285efe4ac7"},
-    {file = "python_gnupg-0.4.7-py2.py3-none-any.whl", hash = "sha256:3ff5b1bf5e397de6e1fe41a7c0f403dad4e242ac92b345f440eaecfb72a7ebae"},
+    {file = "python-gnupg-0.4.8.tar.gz", hash = "sha256:b64de1ae5cedf872b437201a566fa2c62ce0c95ea2e30177eb53aee1258507d7"},
+    {file = "python_gnupg-0.4.8-py2.py3-none-any.whl", hash = "sha256:93a521501d6c2785d96b190aec7125ba89c1c2fe708b0c98af3fb32b59026ab8"},
 ]
 python3-openid = [
     {file = "python3-openid-3.2.0.tar.gz", hash = "sha256:33fbf6928f401e0b790151ed2b5290b02545e8775f982485205a066f874aaeaf"},
@@ -3890,8 +3897,7 @@ restructuredtext-lint = [
     {file = "ruamel.yaml.clib-0.2.6.tar.gz", hash = "sha256:4ff604ce439abb20794f05613c374759ce10e3595d1867764dd1ae675b85acbd"},
 ]
 rules = [
-    {file = "rules-3.0-py2.py3-none-any.whl", hash = "sha256:8194937b537c8a384eafe21750f1d396e1aecdc833e7d06808a5b805ae42a852"},
-    {file = "rules-3.0.tar.gz", hash = "sha256:9141e2fdb7f300fcb59f2f06619fe4ff52bb846eb112ba8c30444f971d6af05e"},
+    {file = "rules-2.2.tar.gz", hash = "sha256:9bae429f9d4f91a375402990da1541f9e093b0ac077221d57124d06eeeca4405"},
 ]
 safety = [
     {file = "safety-1.10.3-py2.py3-none-any.whl", hash = "sha256:5f802ad5df5614f9622d8d71fedec2757099705c2356f862847c58c6dfe13e84"},
@@ -3902,7 +3908,7 @@ scramp = [
     {file = "scramp-1.4.1.tar.gz", hash = "sha256:f964801077be9be2a1416ffe255d2d78834b3d9d5c8ce5d28f76a856f209f70e"},
 ]
 selenium = [
-    {file = "selenium-4.0.0-py3-none-any.whl", hash = "sha256:c942b166a21ce9c9065ad249b54059e926d39f9000167b5ca0fa4950d2ef9a82"},
+    {file = "selenium-4.1.0-py3-none-any.whl", hash = "sha256:27e7b64df961d609f3d57237caa0df123abbbe22d038f2ec9e332fb90ec1a939"},
 ]
 sentry-sdk = [
     {file = "sentry-sdk-1.5.0.tar.gz", hash = "sha256:789a11a87ca02491896e121efdd64e8fd93327b69e8f2f7d42f03e2569648e88"},
@@ -4023,16 +4029,16 @@ twilio = [
     {file = "twilio-7.3.1.tar.gz", hash = "sha256:b61a1209136e7e3d0b9e50653a821ef6a81b87f3b7c513144e5f0d955dca5bba"},
 ]
 types-pytz = [
-    {file = "types-pytz-2021.3.0.tar.gz", hash = "sha256:86a61967834dceeaaf98b6902ed8357efdd262bb8afcaf4bc8ccecf748592778"},
-    {file = "types_pytz-2021.3.0-py3-none-any.whl", hash = "sha256:b5027e5de50a4c978cd60ca16849d934d44c44ebd7d29cf13ada009efaa9feef"},
+    {file = "types-pytz-2021.3.1.tar.gz", hash = "sha256:dffd77f3efecd3b1555f187a9bf3a638d55fac296700b829c41bd51ec72a6eb7"},
+    {file = "types_pytz-2021.3.1-py3-none-any.whl", hash = "sha256:d58a0688094b768d8e21c044e45861cbcaecba0494fd5b9c5feb3e1739211606"},
 ]
 types-pyyaml = [
     {file = "types-PyYAML-6.0.1.tar.gz", hash = "sha256:2e27b0118ca4248a646101c5c318dc02e4ca2866d6bc42e84045dbb851555a76"},
     {file = "types_PyYAML-6.0.1-py3-none-any.whl", hash = "sha256:d5b318269652e809b5c30a5fe666c50159ab80bfd41cd6bafe655bf20b29fcba"},
 ]
 typing-extensions = [
-    {file = "typing_extensions-4.0.0-py3-none-any.whl", hash = "sha256:829704698b22e13ec9eaf959122315eabb370b0884400e9818334d8b677023d9"},
-    {file = "typing_extensions-4.0.0.tar.gz", hash = "sha256:2cdf80e4e04866a9b3689a51869016d36db0814d84b8d8a568d22781d45d27ed"},
+    {file = "typing_extensions-4.0.1-py3-none-any.whl", hash = "sha256:7f001e5ac290a0c0401508864c7ec868be4e701886d5b573a9528ed3973d9d3b"},
+    {file = "typing_extensions-4.0.1.tar.gz", hash = "sha256:4ca091dea149f945ec56afb48dae714f21e8692ef22a395223bcd328961b6a0e"},
 ]
 urllib3 = [
     {file = "urllib3-1.26.7-py2.py3-none-any.whl", hash = "sha256:c4fdf4019605b6e5423637e01bc9fe4daef873709a7973e195ceba0a62bbc844"},
diff --git a/pyproject.toml b/pyproject.toml
index 9f065b0d664232fc4e5224dcce2b4428a1b4f3ea..d0507242bda33996b8c0ff5e71ff68e34a9c1982 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -41,8 +41,8 @@ secondary = true
 
 [tool.poetry.dependencies]
 python = "^3.9"
-aleksis-core = "^2.0rc"
-aleksis-app-chronos = "^2.0rc"
+aleksis-core = "^2.2"
+aleksis-app-chronos = "^2.0rc3"
 
 [tool.poetry.dev-dependencies]
 aleksis-builddeps = "^5"