diff --git a/aleksis/core/admin.py b/aleksis/core/admin.py
index 0725c0aa5545797317a3bfac955cd854d28f227e..e3258ed33bea0fc4dbcb452c2f2f57573212dbe2 100644
--- a/aleksis/core/admin.py
+++ b/aleksis/core/admin.py
@@ -1,6 +1,15 @@
 from django.contrib import admin
 
-from .models import Group, Person, School, SchoolTerm, Activity, Notification
+from .models import (
+    Group,
+    Person,
+    School,
+    SchoolTerm,
+    Activity,
+    Notification,
+    Announcement,
+    AnnouncementRecipient,
+)
 
 admin.site.register(Person)
 admin.site.register(Group)
@@ -8,3 +17,16 @@ admin.site.register(School)
 admin.site.register(SchoolTerm)
 admin.site.register(Activity)
 admin.site.register(Notification)
+
+
+class AnnouncementRecipientInline(admin.StackedInline):
+    model = AnnouncementRecipient
+
+
+class AnnouncementAdmin(admin.ModelAdmin):
+    inlines = [
+        AnnouncementRecipientInline,
+    ]
+
+
+admin.site.register(Announcement, AnnouncementAdmin)
diff --git a/aleksis/core/checks.py b/aleksis/core/checks.py
index 91c5e6291ad44d468d1f08b855688d1485f80390..e52290eb3a48ae4d7e7efe90fbec61d8f86ed365 100644
--- a/aleksis/core/checks.py
+++ b/aleksis/core/checks.py
@@ -3,13 +3,14 @@ from typing import Optional
 import django.apps
 from django.core.checks import Tags, Warning, register
 
+from .mixins import ExtensibleModel, PureDjangoModel
 from .util.apps import AppConfig
 
 
 @register(Tags.compatibility)
 def check_app_configs_base_class(
     app_configs: Optional[django.apps.registry.Apps] = None, **kwargs
-) -> None:
+) -> list:
     """ Checks whether all apps derive from AlekSIS's base app config """
 
     results = []
@@ -17,11 +18,11 @@ def check_app_configs_base_class(
     if app_configs is None:
         app_configs = django.apps.apps.get_app_configs()
 
-    for app_config in app_configs:
-        if app_config.name.startswith("aleksis.apps.") and not isinstance(app_config, AppConfig):
+    for app_config in filter(lambda c: c.name.startswith("aleksis."), app_configs):
+        if not isinstance(app_config, AppConfig):
             results.append(
                 Warning(
-                    "App config %s does not derive from aleksis.core.util.apps.AppConfig.",
+                    "App config %s does not derive from aleksis.core.util.apps.AppConfig." % app_config.name,
                     hint="Ensure the app uses the correct base class for all registry functionality to work.",
                     obj=app_config,
                     id="aleksis.core.W001",
@@ -29,3 +30,29 @@ def check_app_configs_base_class(
             )
 
     return results
+
+
+@register(Tags.compatibility)
+def check_app_models_base_class(
+    app_configs: Optional[django.apps.registry.Apps] = None, **kwargs
+) -> list:
+    """ Checks whether all app models derive from AlekSIS's base ExtensibleModel """
+
+    results = []
+
+    if app_configs is None:
+        app_configs = django.apps.apps.get_app_configs()
+
+    for app_config in filter(lambda c: c.name.startswith("aleksis."), app_configs):
+        for model in app_config.get_models():
+            if ExtensibleModel not in model.__mro__ and PureDjangoModel not in model.__mro__:
+                results.append(
+                    Warning(
+                        "Model %s in app config %s does not derive from aleksis.core.mixins.ExtensibleModel." % (model._meta.object_name, app_config.name),
+                        hint="Ensure all models in AlekSIS use ExtensibleModel as base. If your deviation is intentional, you can add the PureDjangoModel mixin instead to silence this warning.",
+                        obj=model,
+                        id="aleksis.core.W002",
+                    )
+                )
+
+    return results
diff --git a/aleksis/core/menus.py b/aleksis/core/menus.py
index 65d0a584858322665bbfad34af67aebd539f6b4f..1c41dbb704847658c4ae91e4e060ff54bc1548b0 100644
--- a/aleksis/core/menus.py
+++ b/aleksis/core/menus.py
@@ -9,6 +9,12 @@ MENUS = {
             "icon": "lock_open",
             "validators": ["menu_generator.validators.is_anonymous"],
         },
+        {
+            "name": _("Dashboard"),
+            "url": "index",
+            "icon": "home",
+            "validators": ["menu_generator.validators.is_authenticated"],
+        },
         {
             "name": _("Account"),
             "url": "#",
diff --git a/aleksis/core/migrations/0013_extensible_model_as_default.py b/aleksis/core/migrations/0013_extensible_model_as_default.py
new file mode 100644
index 0000000000000000000000000000000000000000..4e23d86f49c0fcc53d92813b794c4083e475a6e3
--- /dev/null
+++ b/aleksis/core/migrations/0013_extensible_model_as_default.py
@@ -0,0 +1,38 @@
+# Generated by Django 3.0.3 on 2020-02-20 12:24
+
+import aleksis.core.util.core_helpers
+import django.contrib.postgres.fields.jsonb
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('core', '0012_announcement'),
+    ]
+
+    operations = [
+        migrations.RemoveField(
+            model_name='activity',
+            name='created_at',
+        ),
+        migrations.RemoveField(
+            model_name='notification',
+            name='created_at',
+        ),
+        migrations.AddField(
+            model_name='activity',
+            name='extended_data',
+            field=django.contrib.postgres.fields.jsonb.JSONField(default=dict, editable=False),
+        ),
+        migrations.AddField(
+            model_name='announcement',
+            name='extended_data',
+            field=django.contrib.postgres.fields.jsonb.JSONField(default=dict, editable=False),
+        ),
+        migrations.AddField(
+            model_name='notification',
+            name='extended_data',
+            field=django.contrib.postgres.fields.jsonb.JSONField(default=dict, editable=False),
+        ),
+    ]
diff --git a/aleksis/core/migrations/0014_multiple_recipients_announcement.py b/aleksis/core/migrations/0014_multiple_recipients_announcement.py
new file mode 100644
index 0000000000000000000000000000000000000000..ebe1aa81d3791b80b93d5afa2a2309cb0f09ca2c
--- /dev/null
+++ b/aleksis/core/migrations/0014_multiple_recipients_announcement.py
@@ -0,0 +1,51 @@
+# Generated by Django 3.0.3 on 2020-02-19 18:14
+
+import aleksis.core.models
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('contenttypes', '0002_remove_content_type_name'),
+        ('core', '0013_extensible_model_as_default'),
+    ]
+
+    operations = [
+        migrations.AlterModelOptions(
+            name='announcement',
+            options={'verbose_name': 'Announcement', 'verbose_name_plural': 'Announcements'},
+        ),
+        migrations.RemoveField(
+            model_name='announcement',
+            name='content_type',
+        ),
+        migrations.RemoveField(
+            model_name='announcement',
+            name='recipient_id',
+        ),
+        migrations.AlterField(
+            model_name='announcement',
+            name='description',
+            field=models.TextField(blank=True, max_length=500, verbose_name='Description'),
+        ),
+        migrations.AlterField(
+            model_name='announcement',
+            name='valid_until',
+            field=models.DateTimeField(default=aleksis.core.util.core_helpers.now_tomorrow, verbose_name='Date and time until when to show'),
+        ),
+        migrations.CreateModel(
+            name='AnnouncementRecipient',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('recipient_id', models.PositiveIntegerField()),
+                ('announcement', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='recipients', to='core.Announcement')),
+                ('content_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='contenttypes.ContentType')),
+            ],
+        ),
+        migrations.AlterModelOptions(
+            name='announcementrecipient',
+            options={'verbose_name': 'Announcement recipient', 'verbose_name_plural': 'Announcement recipients'},
+        ),
+    ]
diff --git a/aleksis/core/migrations/0015_announcement_recipient_extensible_model.py b/aleksis/core/migrations/0015_announcement_recipient_extensible_model.py
new file mode 100644
index 0000000000000000000000000000000000000000..2faf84a8cef450c44d737942cfebcfc95695267f
--- /dev/null
+++ b/aleksis/core/migrations/0015_announcement_recipient_extensible_model.py
@@ -0,0 +1,19 @@
+# Generated by Django 3.0.3 on 2020-02-25 15:26
+
+import django.contrib.postgres.fields.jsonb
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('core', '0014_multiple_recipients_announcement'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='announcementrecipient',
+            name='extended_data',
+            field=django.contrib.postgres.fields.jsonb.JSONField(default=dict, editable=False),
+        ),
+    ]
diff --git a/aleksis/core/mixins.py b/aleksis/core/mixins.py
index ff79940ea9e5e091b381a99a85b2d1f8a9587d1a..984a412556b69a71c5ce875f927989263ffce228 100644
--- a/aleksis/core/mixins.py
+++ b/aleksis/core/mixins.py
@@ -1,3 +1,4 @@
+from datetime import datetime
 from typing import Any, Callable, Optional
 
 from django.contrib.contenttypes.models import ContentType
@@ -8,9 +9,34 @@ from easyaudit.models import CRUDEvent
 from jsonstore.fields import JSONField, JSONFieldMixin
 
 
-class ExtensibleModel(models.Model):
-    """ Allow injection of fields and code from AlekSIS apps to extend
-    model functionality.
+class CRUDMixin(models.Model):
+    class Meta:
+        abstract = True
+
+    @property
+    def crud_events(self) -> QuerySet:
+        """Get all CRUD events connected to this object from easyaudit."""
+
+        content_type = ContentType.objects.get_for_model(self)
+
+        return CRUDEvent.objects.filter(
+            object_id=self.pk, content_type=content_type
+        ).select_related("user")
+
+
+class ExtensibleModel(CRUDMixin):
+    """ Base model for all objects in AlekSIS apps
+
+    This base model ensures all objects in AlekSIS apps fulfill the
+    following properties:
+
+     * crud_events property to retrieve easyaudit's CRUD event log
+     * created_at and updated_at properties based n CRUD events
+     * Allow injection of fields and code from AlekSIS apps to extend
+       model functionality.
+
+    Injection of fields and code
+    ============================
 
     After all apps have been loaded, the code in the `model_extensions` module
     in every app is executed. All code that shall be injected into a model goes there.
@@ -43,8 +69,48 @@ class ExtensibleModel(models.Model):
         - Dominik George <dominik.george@teckids.org>
     """
 
+    @property
+    def crud_event_create(self) -> Optional[CRUDEvent]:
+        """ Return create event of this object """
+        return self.crud_events.filter(event_type=CRUDEvent.CREATE).latest("datetime")
+
+    @property
+    def crud_event_update(self) -> Optional[CRUDEvent]:
+        """ Return last event of this object """
+        return self.crud_events.latest("datetime")
+
+    @property
+    def created_at(self) -> Optional[datetime]:
+        """ Determine creation timestamp from CRUD log """
+
+        if self.crud_event_create:
+            return self.crud_event_create.datetime
+
+    @property
+    def updated_at(self) -> Optional[datetime]:
+        """ Determine last timestamp from CRUD log """
+
+        if self.crud_event_update:
+            return self.crud_event_update.datetime
+
     extended_data = JSONField(default=dict, editable=False)
-    
+
+    @property
+    def created_by(self) -> Optional[models.Model]:
+        """ Determine user who created this object from CRUD log """
+
+        if self.crud_event_create:
+            return self.crud_event_create.user
+
+    @property
+    def updated_by(self) -> Optional[models.Model]:
+        """ Determine user who last updated this object from CRUD log """
+
+        if self.crud_event_update:
+            return self.crud_event_update.user
+
+    extended_data = JSONField(default=dict, editable=False)
+
     @classmethod
     def _safe_add(cls, obj: Any, name: Optional[str]) -> None:
         # Decide the name for the attribute
@@ -101,17 +167,6 @@ class ExtensibleModel(models.Model):
     class Meta:
         abstract = True
 
-
-class CRUDMixin(models.Model):
-    class Meta:
-        abstract = True
-
-    @property
-    def crud_events(self) -> QuerySet:
-        """Get all CRUD events connected to this object from easyaudit."""
-
-        content_type = ContentType.objects.get_for_model(self)
-
-        return CRUDEvent.objects.filter(
-            object_id=self.pk, content_type=content_type
-        ).select_related("user")
+class PureDjangoModel(object):
+    """ No-op mixin to mark a model as deliberately not using ExtensibleModel """
+    pass
diff --git a/aleksis/core/models.py b/aleksis/core/models.py
index ad40d171e660cd7a666edb7f4322d4de98dbed58..9f001cc714584c9c4694d44b5f53f72971f3f6b9 100644
--- a/aleksis/core/models.py
+++ b/aleksis/core/models.py
@@ -1,5 +1,5 @@
 from datetime import date, datetime
-from typing import Optional, Iterable, Union, Sequence
+from typing import Optional, Iterable, Union, Sequence, List
 
 from django.contrib.auth import get_user_model
 from django.contrib.auth.models import User
@@ -8,12 +8,14 @@ from django.contrib.contenttypes.models import ContentType
 from django.db import models
 from django.db.models import QuerySet
 from django.forms.widgets import Media
+from django.utils import timezone
 from django.utils.translation import ugettext_lazy as _
 from image_cropping import ImageCropField, ImageRatioField
 from phonenumber_field.modelfields import PhoneNumberField
 from polymorphic.models import PolymorphicModel
 
-from .mixins import ExtensibleModel
+from .mixins import ExtensibleModel, PureDjangoModel
+from .util.core_helpers import now_tomorrow
 from .util.notifications import send_notification
 
 from constance import config
@@ -229,13 +231,13 @@ class Group(ExtensibleModel):
 
     @property
     def announcement_recipients(self):
-        return list(self.members) + list(self.owners)
+        return list(self.members.all()) + list(self.owners.all())
 
     def __str__(self) -> str:
         return "%s (%s)" % (self.name, self.short_name)
 
 
-class Activity(models.Model):
+class Activity(ExtensibleModel):
     user = models.ForeignKey("Person", on_delete=models.CASCADE, related_name="activities")
 
     title = models.CharField(max_length=150, verbose_name=_("Title"))
@@ -243,8 +245,6 @@ class Activity(models.Model):
 
     app = models.CharField(max_length=100, verbose_name=_("Application"))
 
-    created_at = models.DateTimeField(auto_now_add=True, verbose_name=_("Created at"))
-
     def __str__(self):
         return self.title
 
@@ -253,7 +253,7 @@ class Activity(models.Model):
         verbose_name_plural = _("Activities")
 
 
-class Notification(models.Model):
+class Notification(ExtensibleModel):
     sender = models.CharField(max_length=100, verbose_name=_("Sender"))
     recipient = models.ForeignKey("Person", on_delete=models.CASCADE, related_name="notifications")
 
@@ -264,8 +264,6 @@ class Notification(models.Model):
     read = models.BooleanField(default=False, verbose_name=_("Read"))
     sent = models.BooleanField(default=False, verbose_name=_("Sent"))
 
-    created_at = models.DateTimeField(auto_now_add=True, verbose_name=_("Created at"))
-
     def __str__(self):
         return self.title
 
@@ -279,17 +277,18 @@ class Notification(models.Model):
         verbose_name_plural = _("Notifications")
 
 
-class Announcement(models.Model):
+class Announcement(ExtensibleModel):
     title = models.CharField(max_length=150, verbose_name=_("Title"))
-    description = models.TextField(max_length=500, verbose_name=_("Description"))
+    description = models.TextField(max_length=500, verbose_name=_("Description"), blank=True)
     link = models.URLField(blank=True, verbose_name=_("Link"))
 
-    valid_from = models.DateTimeField(verbose_name=_("Date and time from when to show"), default=datetime.now)
-    valid_until = models.DateTimeField(verbose_name=_("Date and time until when to show"), null=True, blank=True)
-
-    content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
-    recipient_id = models.PositiveIntegerField()
-    recipient = GenericForeignKey("content_type", "recipient_id")
+    valid_from = models.DateTimeField(
+        verbose_name=_("Date and time from when to show"), default=timezone.datetime.now
+    )
+    valid_until = models.DateTimeField(
+        verbose_name=_("Date and time until when to show"),
+        default=now_tomorrow,
+    )
 
     @classmethod
     def relevant_for(cls, obj: Union[models.Model, models.QuerySet]) -> models.QuerySet:
@@ -304,13 +303,53 @@ class Announcement(models.Model):
             ct = ContentType.objects.get_for_model(obj)
             pks = [obj.pk]
 
-        return cls.objects.filter(content_type=ct, recipient_id__in=pks)
+        return cls.objects.filter(recipients__content_type=ct, recipients__recipient_id__in=pks)
+
+    @classmethod
+    def for_person_at_time(cls, person: Person, when: Optional[datetime] = None) -> List:
+        """ Get all announcements for one person at a certain time """
+        when = when or timezone.datetime.now()
+
+        # Get announcements by time
+        announcements = cls.objects.filter(valid_from__lte=when, valid_until__gte=when)
+
+        # Filter by person
+        announcements_for_person = []
+        for announcement in announcements:
+            if person in announcement.recipient_persons:
+                announcements_for_person.append(announcement)
+
+        return announcements_for_person
+
+    @property
+    def recipient_persons(self) -> Sequence[Person]:
+        """ Return a list of Persons this announcement is relevant for """
+
+        persons = []
+        for recipient in self.recipients.all():
+            persons += recipient.persons
+        return persons
+
+    def __str__(self):
+        return self.title
+
+    class Meta:
+        verbose_name = _("Announcement")
+        verbose_name_plural = _("Announcements")
+
+
+class AnnouncementRecipient(ExtensibleModel):
+    announcement = models.ForeignKey(Announcement, on_delete=models.CASCADE, related_name="recipients")
+
+    content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
+    recipient_id = models.PositiveIntegerField()
+    recipient = GenericForeignKey("content_type", "recipient_id")
 
     @property
-    def recipient_persons(self) -> Union[models.QuerySet, Sequence[models.Model]]:
-        """ Return a list of Persons this announcement is relevant for
+    def persons(self) -> Sequence[Person]:
+        """ Return a list of Persons selected by this recipient object
 
-        If the recipient is a Person, return that object. If not, it returns the QUerySet
+        If the recipient is a Person, return that object. If not, it returns the list
         from the announcement_recipients field on the target model.
         """
 
@@ -319,14 +358,15 @@ class Announcement(models.Model):
         else:
             return getattr(self.recipient, "announcement_recipients", [])
 
-    def save(self, **kwargs):
-        if not self.valid_until:
-            self.valid_until = self.valid_from
+    def __str__(self):
+        return str(self.recipient)
 
-        super().save(**kwargs)
+    class Meta:
+        verbose_name = _("Announcement recipient")
+        verbose_name_plural = _("Announcement recipients")
 
 
-class DashboardWidget(PolymorphicModel):
+class DashboardWidget(PolymorphicModel, PureDjangoModel):
     """ Base class for dashboard widgets on the index page
 
     To implement a widget, add a model that subclasses DashboardWidget, sets the template
diff --git a/aleksis/core/settings.py b/aleksis/core/settings.py
index fa098c1fc62a32f13c55aeaeccd461e1445fde52..f1cee79a5befae2cf9b49ea2c16e6d8a396c320c 100644
--- a/aleksis/core/settings.py
+++ b/aleksis/core/settings.py
@@ -50,6 +50,7 @@ INSTALLED_APPS = [
     "django.contrib.contenttypes",
     "django.contrib.sessions",
     "django.contrib.messages",
+    "django.contrib.sites",
     "django.contrib.staticfiles",
     "django.contrib.humanize",
     "polymorphic",
@@ -458,6 +459,8 @@ PWA_APP_SPLASH_SCREEN = [
 ]
 PWA_SERVICE_WORKER_PATH = os.path.join(STATIC_ROOT, "js", "serviceworker.js")
 
+SITE_ID = 1
+
 CKEDITOR_CONFIGS = {
     'default': {
         'toolbar_Basic': [
diff --git a/aleksis/core/templates/core/announcements.html b/aleksis/core/templates/core/announcements.html
new file mode 100644
index 0000000000000000000000000000000000000000..3e1925536a12bb3824a5b5bb11adb636fcfc9bf2
--- /dev/null
+++ b/aleksis/core/templates/core/announcements.html
@@ -0,0 +1,41 @@
+{% load i18n humanize %}
+
+{% for announcement in announcements %}
+  <div class="alert primary">
+    <div>
+      {% if show_interval %}
+        <em class="right hide-on-small-and-down">
+          {% if announcement.valid_from.date == announcement.valid_until.date %}
+            {% blocktrans with from=announcement.valid_from|naturalday %}
+              Valid for {{ from }}
+            {% endblocktrans %}
+          {% else %}
+            {% blocktrans with from=announcement.valid_from|naturalday until=announcement.valid_until|naturalday %}
+              Valid for {{ from }} – {{ until }}
+            {% endblocktrans %}
+          {% endif %}
+        </em>
+      {% endif %}
+
+      <i class="material-icons left">announcement</i>
+      <p>
+        <strong>{{ announcement.title }}</strong> <br/>
+        {{ announcement.description }}
+      </p>
+
+      {% if show_interval %}
+        <em class="hide-on-med-and-up">
+          {% if announcement.valid_from.date == announcement.valid_until.date %}
+            {% blocktrans with from=announcement.valid_from|naturalday %}
+              Valid for {{ from }}
+            {% endblocktrans %}
+          {% else %}
+            {% blocktrans with from=announcement.valid_from|naturalday until=announcement.valid_until|naturalday %}
+              Valid for {{ from }} – {{ until }}
+            {% endblocktrans %}
+          {% endif %}
+        </em>
+      {% endif %}
+    </div>
+  </div>
+{% endfor %}
diff --git a/aleksis/core/templates/core/index.html b/aleksis/core/templates/core/index.html
index 9e8e19ac71dd20e17ca690c560a81767975e85aa..2ace14e98652ded4e56c840c180b10690b1fb7d6 100644
--- a/aleksis/core/templates/core/index.html
+++ b/aleksis/core/templates/core/index.html
@@ -28,6 +28,8 @@
       </div>
     {% endfor %}
 
+    {% include "core/announcements.html" with announcements=announcements %}
+
     <div class="row" id="live_load">
         {% for widget in widgets %}
           <div class="col s12 m12 l6 xl4">
diff --git a/aleksis/core/util/core_helpers.py b/aleksis/core/util/core_helpers.py
index f273016659cf08bf7d4e924296d2950dc9e20694..9d019103d2e4b45558a5119c05b26a618d24be87 100644
--- a/aleksis/core/util/core_helpers.py
+++ b/aleksis/core/util/core_helpers.py
@@ -1,3 +1,4 @@
+from datetime import datetime, timedelta
 import os
 import pkgutil
 from importlib import import_module
@@ -7,6 +8,7 @@ from uuid import uuid4
 from django.conf import settings
 from django.db.models import Model
 from django.http import HttpRequest
+from django.utils import timezone
 from django.utils.functional import lazy
 
 
@@ -148,3 +150,8 @@ def school_information_processor(request: HttpRequest) -> dict:
     return {
         "SCHOOL": School.get_default,
     }
+
+
+def now_tomorrow() -> datetime:
+    """ Return current time tomorrow """
+    return timezone.datetime.now() + timedelta(days=1)
diff --git a/aleksis/core/views.py b/aleksis/core/views.py
index 2e1946de401b866e0adbc4aa3ee8463b5f1b94af..98db80da4a5d30df58f6bc2a8d3d037f226a0044 100644
--- a/aleksis/core/views.py
+++ b/aleksis/core/views.py
@@ -16,7 +16,7 @@ from .forms import (
     EditTermForm,
     PersonsAccountsFormSet,
 )
-from .models import Activity, Group, Notification, Person, School, DashboardWidget
+from .models import Activity, Group, Notification, Person, School, DashboardWidget, Announcement
 from .tables import GroupsTable, PersonsTable
 from .util import messages
 
@@ -33,6 +33,9 @@ def index(request: HttpRequest) -> HttpResponse:
     context["notifications"] = notifications
     context["unread_notifications"] = unread_notifications
 
+    announcements = Announcement.for_person_at_time(request.user.person)
+    context["announcements"] = announcements
+
     widgets = DashboardWidget.objects.filter(active=True)
     media = DashboardWidget.get_media(widgets)
 
diff --git a/apps/official/AlekSIS-App-Alsijil b/apps/official/AlekSIS-App-Alsijil
index f04cda54c04eba8f5430c6f562e39a954deb41cb..bd516e09a6e651b7171a6d7b31f79c3e4a22892e 160000
--- a/apps/official/AlekSIS-App-Alsijil
+++ b/apps/official/AlekSIS-App-Alsijil
@@ -1 +1 @@
-Subproject commit f04cda54c04eba8f5430c6f562e39a954deb41cb
+Subproject commit bd516e09a6e651b7171a6d7b31f79c3e4a22892e
diff --git a/apps/official/AlekSIS-App-Chronos b/apps/official/AlekSIS-App-Chronos
index 182b37deddc5049fb37c3b0a65ad0516c6147e7b..455c9d1bb74ae0d727b654a54d8f7c0278308a4e 160000
--- a/apps/official/AlekSIS-App-Chronos
+++ b/apps/official/AlekSIS-App-Chronos
@@ -1 +1 @@
-Subproject commit 182b37deddc5049fb37c3b0a65ad0516c6147e7b
+Subproject commit 455c9d1bb74ae0d727b654a54d8f7c0278308a4e
diff --git a/apps/official/AlekSIS-App-DashboardFeeds b/apps/official/AlekSIS-App-DashboardFeeds
index ca29920aabf8ee24bc073bae8f75efe7d90c9aea..b89287de8e16e4f87691457a2569e3c16d728935 160000
--- a/apps/official/AlekSIS-App-DashboardFeeds
+++ b/apps/official/AlekSIS-App-DashboardFeeds
@@ -1 +1 @@
-Subproject commit ca29920aabf8ee24bc073bae8f75efe7d90c9aea
+Subproject commit b89287de8e16e4f87691457a2569e3c16d728935
diff --git a/apps/official/AlekSIS-App-Exlibris b/apps/official/AlekSIS-App-Exlibris
index 0dbf5bb89e27e55e7347cca2405c7495a803a2dd..f1304db3bb4b8905269eb5f5079f3fe4630c4312 160000
--- a/apps/official/AlekSIS-App-Exlibris
+++ b/apps/official/AlekSIS-App-Exlibris
@@ -1 +1 @@
-Subproject commit 0dbf5bb89e27e55e7347cca2405c7495a803a2dd
+Subproject commit f1304db3bb4b8905269eb5f5079f3fe4630c4312
diff --git a/poetry.lock b/poetry.lock
index f450327e896d507b72ca245ee1f5e53be0656188..787b2e8c9c9cffae4371725f98cabb4dcc53b5be 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -106,7 +106,7 @@ description = "Python multiprocessing fork with improvements and bugfixes"
 name = "billiard"
 optional = true
 python-versions = "*"
-version = "3.6.2.0"
+version = "3.6.3.0"
 
 [[package]]
 category = "dev"
@@ -427,7 +427,7 @@ description = "Yet another Django audit log app, hopefully the simplest one."
 name = "django-easy-audit"
 optional = false
 python-versions = "*"
-version = "1.2.2b1"
+version = "1.2.2b2"
 
 [package.dependencies]
 beautifulsoup4 = "*"
@@ -541,7 +541,7 @@ description = "Material design for django forms and admin"
 name = "django-material"
 optional = false
 python-versions = "*"
-version = "1.6.0"
+version = "1.6.3"
 
 [package.dependencies]
 six = "*"
@@ -880,7 +880,7 @@ description = "Faker is a Python package that generates fake data for you."
 name = "faker"
 optional = false
 python-versions = ">=3.4"
-version = "4.0.0"
+version = "4.0.1"
 
 [package.dependencies]
 python-dateutil = ">=2.4"
@@ -1029,13 +1029,13 @@ restructuredtext_lint = "*"
 [[package]]
 category = "dev"
 description = "Git Object Database"
-name = "gitdb2"
+name = "gitdb"
 optional = false
 python-versions = ">=3.4"
-version = "3.0.0"
+version = "4.0.2"
 
 [package.dependencies]
-smmap2 = ">=2.0.0"
+smmap = ">=3.0.1,<4"
 
 [[package]]
 category = "dev"
@@ -1043,10 +1043,10 @@ description = "Python Git Library"
 name = "gitpython"
 optional = false
 python-versions = ">=3.4"
-version = "3.0.7"
+version = "3.1.0"
 
 [package.dependencies]
-gitdb2 = ">=2.0.0"
+gitdb = ">=4.0.1,<5"
 
 [[package]]
 category = "main"
@@ -1062,7 +1062,7 @@ description = "Internationalized Domain Names in Applications (IDNA)"
 name = "idna"
 optional = false
 python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
-version = "2.8"
+version = "2.9"
 
 [[package]]
 category = "dev"
@@ -1326,7 +1326,7 @@ description = "Cryptographic library for Python"
 name = "pycryptodome"
 optional = false
 python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
-version = "3.9.6"
+version = "3.9.7"
 
 [[package]]
 category = "dev"
@@ -1579,7 +1579,7 @@ description = "Alternative regular expression module, to replace re."
 name = "regex"
 optional = false
 python-versions = "*"
-version = "2020.1.8"
+version = "2020.2.20"
 
 [[package]]
 category = "main"
@@ -1587,16 +1587,16 @@ description = "Python HTTP for Humans."
 name = "requests"
 optional = false
 python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
-version = "2.22.0"
+version = "2.23.0"
 
 [package.dependencies]
 certifi = ">=2017.4.17"
-chardet = ">=3.0.2,<3.1.0"
-idna = ">=2.5,<2.9"
+chardet = ">=3.0.2,<4"
+idna = ">=2.5,<3"
 urllib3 = ">=1.21.1,<1.25.0 || >1.25.0,<1.25.1 || >1.25.1,<1.26"
 
 [package.extras]
-security = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)"]
+security = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)"]
 socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7)", "win-inet-pton"]
 
 [[package]]
@@ -1655,10 +1655,10 @@ version = "1.14.0"
 [[package]]
 category = "dev"
 description = "A pure Python implementation of a sliding window memory map manager"
-name = "smmap2"
+name = "smmap"
 optional = false
 python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
-version = "2.0.5"
+version = "3.0.1"
 
 [[package]]
 category = "dev"
@@ -1673,8 +1673,8 @@ category = "main"
 description = "A modern CSS selector implementation for Beautiful Soup."
 name = "soupsieve"
 optional = false
-python-versions = "*"
-version = "1.9.5"
+python-versions = ">=3.5"
+version = "2.0"
 
 [[package]]
 category = "dev"
@@ -1682,7 +1682,7 @@ description = "Python documentation generator"
 name = "sphinx"
 optional = false
 python-versions = ">=3.5"
-version = "2.4.1"
+version = "2.4.3"
 
 [package.dependencies]
 Jinja2 = ">=2.3"
@@ -1754,14 +1754,15 @@ version = "0.5.1"
 
 [[package]]
 category = "dev"
-description = ""
+description = "sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files"
 name = "sphinxcontrib-htmlhelp"
 optional = false
-python-versions = "*"
-version = "1.0.2"
+python-versions = ">=3.5"
+version = "1.0.3"
 
 [package.extras]
-test = ["pytest", "flake8", "mypy", "html5lib"]
+lint = ["flake8", "mypy", "docutils-stubs"]
+test = ["pytest", "html5lib"]
 
 [[package]]
 category = "dev"
@@ -1830,12 +1831,12 @@ description = "A collection of helpers and mock objects for unit tests and doc t
 name = "testfixtures"
 optional = false
 python-versions = "*"
-version = "6.12.0"
+version = "6.14.0"
 
 [package.extras]
 build = ["setuptools-git", "wheel", "twine"]
-docs = ["sphinx"]
-test = ["pytest (>=3.6)", "pytest-cov", "pytest-django", "sybil", "zope.component", "twisted", "mock", "django (<2)", "django"]
+docs = ["sphinx", "zope.component", "sybil", "twisted", "mock", "django (<2)", "django"]
+test = ["pytest (>=3.6)", "pytest-cov", "pytest-django", "zope.component", "sybil", "twisted", "mock", "django (<2)", "django"]
 
 [[package]]
 category = "dev"
@@ -1885,7 +1886,7 @@ description = "Fast, Extensible Progress Meter"
 name = "tqdm"
 optional = false
 python-versions = ">=2.6, !=3.0.*, !=3.1.*"
-version = "4.42.1"
+version = "4.43.0"
 
 [package.extras]
 dev = ["py-make (>=0.1.0)", "twine", "argopt", "pydoc-markdown"]
@@ -1896,7 +1897,7 @@ description = "Twilio API client and TwiML generator"
 name = "twilio"
 optional = false
 python-versions = "*"
-version = "6.35.4"
+version = "6.35.5"
 
 [package.dependencies]
 PyJWT = ">=1.4.2"
@@ -1971,11 +1972,11 @@ marker = "python_version < \"3.8\""
 name = "zipp"
 optional = false
 python-versions = ">=3.6"
-version = "2.2.0"
+version = "3.0.0"
 
 [package.extras]
 docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"]
-testing = ["jaraco.itertools"]
+testing = ["jaraco.itertools", "func-timeout"]
 
 [extras]
 celery = ["Celery", "django-celery-results", "django-celery-beat", "django-celery-email"]
@@ -2024,8 +2025,8 @@ beautifulsoup4 = [
     {file = "beautifulsoup4-4.8.2.tar.gz", hash = "sha256:05fd825eb01c290877657a56df4c6e4c311b3965bda790c613a3d6fb01a5462a"},
 ]
 billiard = [
-    {file = "billiard-3.6.2.0-py3-none-any.whl", hash = "sha256:26fd494dc3251f8ce1f5559744f18aeed427fdaf29a75d7baae26752a5d3816f"},
-    {file = "billiard-3.6.2.0.tar.gz", hash = "sha256:f4e09366653aa3cb3ae8ed16423f9ba1665ff426f087bcdbbed86bf3664fe02c"},
+    {file = "billiard-3.6.3.0-py3-none-any.whl", hash = "sha256:bff575450859a6e0fbc2f9877d9b715b0bbc07c3565bb7ed2280526a0cdf5ede"},
+    {file = "billiard-3.6.3.0.tar.gz", hash = "sha256:d91725ce6425f33a97dfa72fb6bfef0e47d4652acd98a032bd1a7fbf06d5fa6a"},
 ]
 black = [
     {file = "black-19.10b0-py36-none-any.whl", hash = "sha256:1b30e59be925fafc1ee4565e5e08abef6b03fe455102883820fe5ee2e4734e0b"},
@@ -2146,8 +2147,8 @@ django-debug-toolbar = [
     {file = "django_debug_toolbar-2.2-py3-none-any.whl", hash = "sha256:ff94725e7aae74b133d0599b9bf89bd4eb8f5d2c964106e61d11750228c8774c"},
 ]
 django-easy-audit = [
-    {file = "django-easy-audit-1.2.2b1.tar.gz", hash = "sha256:acae5c3ca5cdf9d9e0eaa77d7987e540b7ed4581718ee9c52e67cef27a9c1099"},
-    {file = "django_easy_audit-1.2.2b1-py3-none-any.whl", hash = "sha256:c488dc62b8661602944fd795643a507bfa9da8ed08ad271d6ee820b10a08631c"},
+    {file = "django-easy-audit-1.2.2b2.tar.gz", hash = "sha256:73b19942999803c0303b35cf303863198897ec84dc10edcb7c967363a64a92dd"},
+    {file = "django_easy_audit-1.2.2b2-py3-none-any.whl", hash = "sha256:865af8e2b6f615bcc3ec52a28503aa87d577965d3e1b304d7eb3ed337a319ee9"},
 ]
 django-filter = [
     {file = "django-filter-2.2.0.tar.gz", hash = "sha256:c3deb57f0dd7ff94d7dce52a047516822013e2b441bed472b722a317658cfd14"},
@@ -2186,8 +2187,8 @@ django-maintenance-mode = [
     {file = "django_maintenance_mode-0.14.0-py2-none-any.whl", hash = "sha256:b4cc24a469ed10897826a28f05d64e6166a58d130e4940ac124ce198cd4cc778"},
 ]
 django-material = [
-    {file = "django-material-1.6.0.tar.gz", hash = "sha256:767ab6ad51f906bf773f927e853c2bff6b4ebdd1bd2bf45dbd4ef3e31657c3d5"},
-    {file = "django_material-1.6.0-py2.py3-none-any.whl", hash = "sha256:6a30e42f0ceefef1ff325bda0017fa6f6a7fa534b15b8fcc48eb96de4b6adc8e"},
+    {file = "django-material-1.6.3.tar.gz", hash = "sha256:f8758afe1beabc16a3c54f5437c7fea15946b7d068eedd89c97d57a363793950"},
+    {file = "django_material-1.6.3-py2.py3-none-any.whl", hash = "sha256:502dc88c2f61f190fdc401666e83b47da00cbda98477af6ed8b7d43944ce6407"},
 ]
 django-menu-generator = [
     {file = "django-menu-generator-1.0.4.tar.gz", hash = "sha256:ce71a5055c16933c8aff64fb36c21e5cf8b6d505733aceed1252f8b99369a378"},
@@ -2278,8 +2279,8 @@ entrypoints = [
     {file = "entrypoints-0.3.tar.gz", hash = "sha256:c70dd71abe5a8c85e55e12c19bd91ccfeec11a6e99044204511f9ed547d48451"},
 ]
 faker = [
-    {file = "Faker-4.0.0-py3-none-any.whl", hash = "sha256:047d4d1791bfb3756264da670d99df13d799bb36e7d88774b1585a82d05dbaec"},
-    {file = "Faker-4.0.0.tar.gz", hash = "sha256:1b1a58961683b30c574520d0c739c4443e0ef6a185c04382e8cc888273dbebed"},
+    {file = "Faker-4.0.1-py3-none-any.whl", hash = "sha256:ee24608768549c2c69e593e9d7a3b53c9498ae735534243ec8390cae5d529f8b"},
+    {file = "Faker-4.0.1.tar.gz", hash = "sha256:440d68fe0e46c1658b1975b2497abe0c24a7f772e3892253f31e713ffcc48965"},
 ]
 flake8 = [
     {file = "flake8-3.7.9-py2.py3-none-any.whl", hash = "sha256:49356e766643ad15072a789a20915d3c91dc89fd313ccd71802303fd67e4deca"},
@@ -2321,21 +2322,21 @@ flake8-polyfill = [
 flake8-rst-docstrings = [
     {file = "flake8-rst-docstrings-0.0.13.tar.gz", hash = "sha256:b1b619d81d879b874533973ac04ee5d823fdbe8c9f3701bfe802bb41813997b4"},
 ]
-gitdb2 = [
-    {file = "gitdb2-3.0.0-py2.py3-none-any.whl", hash = "sha256:0a84c85d07166cefaf10fa4b728a8a1b847a7f0d081e2fbe083185462158c126"},
-    {file = "gitdb2-3.0.0.tar.gz", hash = "sha256:51380b9d8b977b42ac9fc3a8e17af90a56ffc573ca9c6b79f99033b04f29f457"},
+gitdb = [
+    {file = "gitdb-4.0.2-py3-none-any.whl", hash = "sha256:284a6a4554f954d6e737cddcff946404393e030b76a282c6640df8efd6b3da5e"},
+    {file = "gitdb-4.0.2.tar.gz", hash = "sha256:598e0096bb3175a0aab3a0b5aedaa18a9a25c6707e0eca0695ba1a0baf1b2150"},
 ]
 gitpython = [
-    {file = "GitPython-3.0.7-py3-none-any.whl", hash = "sha256:99c77677f31f255e130f3fed4c8e0eebb35f1a09df98ff965fff6774f71688cf"},
-    {file = "GitPython-3.0.7.tar.gz", hash = "sha256:99cd0403cecd8a13b95d2e045b9fcaa7837137fcc5ec3105f2c413305d82c143"},
+    {file = "GitPython-3.1.0-py3-none-any.whl", hash = "sha256:43da89427bdf18bf07f1164c6d415750693b4d50e28fc9b68de706245147b9dd"},
+    {file = "GitPython-3.1.0.tar.gz", hash = "sha256:e426c3b587bd58c482f0b7fe6145ff4ac7ae6c82673fc656f489719abca6f4cb"},
 ]
 html2text = [
     {file = "html2text-2020.1.16-py3-none-any.whl", hash = "sha256:c7c629882da0cf377d66f073329ccf34a12ed2adf0169b9285ae4e63ef54c82b"},
     {file = "html2text-2020.1.16.tar.gz", hash = "sha256:e296318e16b059ddb97f7a8a1d6a5c1d7af4544049a01e261731d2d5cc277bbb"},
 ]
 idna = [
-    {file = "idna-2.8-py2.py3-none-any.whl", hash = "sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c"},
-    {file = "idna-2.8.tar.gz", hash = "sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407"},
+    {file = "idna-2.9-py2.py3-none-any.whl", hash = "sha256:a068a21ceac8a4d63dbfd964670474107f541babbd2250d61922f029858365fa"},
+    {file = "idna-2.9.tar.gz", hash = "sha256:7588d1c14ae4c77d74036e8c22ff447b26d0fde8f007354fd48a7814db15b7cb"},
 ]
 imagesize = [
     {file = "imagesize-1.2.0-py2.py3-none-any.whl", hash = "sha256:6965f19a6a2039c7d48bca7dba2473069ff854c36ae6f19d2cde309d998228a1"},
@@ -2535,36 +2536,36 @@ pycodestyle = [
     {file = "pycodestyle-2.5.0.tar.gz", hash = "sha256:e40a936c9a450ad81df37f549d676d127b1b66000a6c500caa2b085bc0ca976c"},
 ]
 pycryptodome = [
-    {file = "pycryptodome-3.9.6-cp27-cp27m-macosx_10_6_intel.whl", hash = "sha256:5029c46b0d41dfb763c3981c0af68eab029f06fe2b94f2299112fc18cf9e8d6d"},
-    {file = "pycryptodome-3.9.6-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:95d324e603c5cec5d89e8595236bbf59ade5fe3a72d100ce61eebb323d598750"},
-    {file = "pycryptodome-3.9.6-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:2a57daef18a2022a5e4b6f7376c9ddd0c2d946e4b1f1e59b837f5bf295be7380"},
-    {file = "pycryptodome-3.9.6-cp27-cp27m-win32.whl", hash = "sha256:a719bd708207fa219fcbf4c8ebbcbc52846045f78179d00445b429fdabdbc1c4"},
-    {file = "pycryptodome-3.9.6-cp27-cp27m-win_amd64.whl", hash = "sha256:39e5ca2f66d1eac7abcba5ce1a03370d123dc6085620f1cd532dfee27e650178"},
-    {file = "pycryptodome-3.9.6-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:f4d2174e168d0eabd1fffaf88b4f62c2b6f30a67b8816f31024b8e48be3e2d75"},
-    {file = "pycryptodome-3.9.6-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:ec7d39589f9cfc2a8b83b1d2fc673441757c99d43283e97b2dd46e0e23730db8"},
-    {file = "pycryptodome-3.9.6-cp34-cp34m-manylinux1_i686.whl", hash = "sha256:9163fec630495c10c767991e3f8dab32f4427bfb2dfeaa59bb28fe3e52ba66f2"},
-    {file = "pycryptodome-3.9.6-cp34-cp34m-manylinux1_x86_64.whl", hash = "sha256:0a8d5f2dbb4bbe830ace54286b829bfa529f0853bedaab6225fcb2e6d1f7e356"},
-    {file = "pycryptodome-3.9.6-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:5817c0b3c263025d851da96b90cbc7e95348008f88b990e90d10683dba376666"},
-    {file = "pycryptodome-3.9.6-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:c41b7e10b72cef00cd63410f31fe50e72dc3a40eafbd146e288384fbe4208064"},
-    {file = "pycryptodome-3.9.6-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:f3204006869ab037604b1d9f045c4e84882ddd365e4ee8caa5eb1ff47a59188e"},
-    {file = "pycryptodome-3.9.6-cp35-cp35m-win32.whl", hash = "sha256:cdb0ad83a5d6bac986a37fcb7562bcbef0aabae8ea19505bab5cf83c4d18af12"},
-    {file = "pycryptodome-3.9.6-cp35-cp35m-win_amd64.whl", hash = "sha256:1259b8ca49662b8a941177357f08147d858595c0042e63ff81e9628e925b5c9d"},
-    {file = "pycryptodome-3.9.6-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:09bf05a489fe10f9280a5e0163f195e7b9630cafb15f7d72fb9c8f5eb2afa84f"},
-    {file = "pycryptodome-3.9.6-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:fcff8c9d88d58880f7eda2139c7c444552a38f98a9e77ba5970b6e78f54ac358"},
-    {file = "pycryptodome-3.9.6-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:9948c2d5c5c0ee45ed44cee0e2eba2ce60a03be006ed3074521f3da3be162e72"},
-    {file = "pycryptodome-3.9.6-cp36-cp36m-win32.whl", hash = "sha256:79320f1fc5c9ca682869087c565bb29ca6f334692e940d7365771e9a94382e12"},
-    {file = "pycryptodome-3.9.6-cp36-cp36m-win_amd64.whl", hash = "sha256:d8e480f65ac7105cbc288eec2417dc61eaac6ed6e75595aa15b8c7c77c53a68b"},
-    {file = "pycryptodome-3.9.6-cp37-cp37m-macosx_10_6_intel.whl", hash = "sha256:07daddb98f98f771ba027f8f835bdb675aeb84effe41ed5221f520b267429354"},
-    {file = "pycryptodome-3.9.6-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:da2d581da279bc7408d38e16ff77754f5448c4352f2acfe530a5d14d8fc6934a"},
-    {file = "pycryptodome-3.9.6-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:012ca77c2105600e3c6aef43188101ac1d95052c633a4ae8fbebffab20c25f8a"},
-    {file = "pycryptodome-3.9.6-cp37-cp37m-win32.whl", hash = "sha256:05b4d865710f9a6378d3ada28195ff78e52642d3ecffe6fa9d379d870b9bf29d"},
-    {file = "pycryptodome-3.9.6-cp37-cp37m-win_amd64.whl", hash = "sha256:9927aa8a8cb4af681279b6f28a1dcb14e0eb556c1aea8413a1e27608a8516e0c"},
-    {file = "pycryptodome-3.9.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:de61091dd68326b600422cf731eb4810c4c6363f18a65bccd6061784b7454f5b"},
-    {file = "pycryptodome-3.9.6-cp38-cp38-manylinux1_i686.whl", hash = "sha256:238d8b6dd27bd1a04816a68aa90a739e6dd23b192fcd83b50f9360958bff192a"},
-    {file = "pycryptodome-3.9.6-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:3d516df693c195b8da3795e381429bd420e87081b7e6c2871c62c9897c812cda"},
-    {file = "pycryptodome-3.9.6-cp38-cp38-win32.whl", hash = "sha256:3e486c5b7228e864665fc479e9f596b2547b5fe29c6f5c8ed3807784d06faed7"},
-    {file = "pycryptodome-3.9.6-cp38-cp38-win_amd64.whl", hash = "sha256:887d08beca6368d3d70dc75126607ad76317a9fd07fe61323d8c3cb42add12b6"},
-    {file = "pycryptodome-3.9.6.tar.gz", hash = "sha256:bc22ced26ebc46546798fa0141f4418f1db116dec517f0aeaecec87cf7b2416c"},
+    {file = "pycryptodome-3.9.7-cp27-cp27m-macosx_10_6_intel.whl", hash = "sha256:0e10f352ccbbcb5bb2dc4ecaf106564e65702a717d72ab260f9ac4c19753cfc2"},
+    {file = "pycryptodome-3.9.7-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:9c739b7795ccf2ef1fdad8d44e539a39ad300ee6786e804ea7f0c6a786eb5343"},
+    {file = "pycryptodome-3.9.7-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:9977086e0f93adb326379897437373871b80501e1d176fec63c7f46fb300c862"},
+    {file = "pycryptodome-3.9.7-cp27-cp27m-win32.whl", hash = "sha256:83295a3fb5cf50c48631eb5b440cb5e9832d8c14d81d1d45f4497b67a9987de8"},
+    {file = "pycryptodome-3.9.7-cp27-cp27m-win_amd64.whl", hash = "sha256:b1e332587b3b195542e77681389c296e1837ca01240399d88803a075447d3557"},
+    {file = "pycryptodome-3.9.7-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:9378c309aec1f8cd8bad361ed0816a440151b97a2a3f6ffdaba1d1a1fb76873a"},
+    {file = "pycryptodome-3.9.7-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:d4f94368ce2d65873a87ad867eb3bf63f4ba81eb97a9ee66d38c2b71ce5a7439"},
+    {file = "pycryptodome-3.9.7-cp34-cp34m-manylinux1_i686.whl", hash = "sha256:f655addaaaa9974108d4808f4150652589cada96074c87115c52e575bfcd87d5"},
+    {file = "pycryptodome-3.9.7-cp34-cp34m-manylinux1_x86_64.whl", hash = "sha256:9a94fca11fdc161460bd8659c15b6adef45c1b20da86402256eaf3addfaab324"},
+    {file = "pycryptodome-3.9.7-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:ea83bcd9d6c03248ebd46e71ac313858e0afd5aa2fa81478c0e653242f3eb476"},
+    {file = "pycryptodome-3.9.7-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:07024fc364869eae8d6ac0d316e089956e6aeffe42dbdcf44fe1320d96becf7f"},
+    {file = "pycryptodome-3.9.7-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:426c188c83c10df71f053e04b4003b1437bae5cb37606440e498b00f160d71d0"},
+    {file = "pycryptodome-3.9.7-cp35-cp35m-win32.whl", hash = "sha256:d61b012baa8c2b659e9890011358455c0019a4108536b811602d2f638c40802a"},
+    {file = "pycryptodome-3.9.7-cp35-cp35m-win_amd64.whl", hash = "sha256:1f4752186298caf2e9ff5354f2e694d607ca7342aa313a62005235d46e28cf04"},
+    {file = "pycryptodome-3.9.7-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:767ad0fb5d23efc36a4d5c2fc608ac603f3de028909bcf59abc943e0d0bc5a36"},
+    {file = "pycryptodome-3.9.7-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:2fbc472e0b567318fe2052281d5a8c0ae70099b446679815f655e9fbc18c3a65"},
+    {file = "pycryptodome-3.9.7-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:9230fcb5d948c3fb40049bace4d33c5d254f8232c2c0bba05d2570aea3ba4520"},
+    {file = "pycryptodome-3.9.7-cp36-cp36m-win32.whl", hash = "sha256:8f06556a8f7ea7b1e42eff39726bb0dca1c251205debae64e6eebea3cd7b438a"},
+    {file = "pycryptodome-3.9.7-cp36-cp36m-win_amd64.whl", hash = "sha256:d6e1bc5c94873bec742afe2dfadce0d20445b18e75c47afc0c115b19e5dd38dd"},
+    {file = "pycryptodome-3.9.7-cp37-cp37m-macosx_10_6_intel.whl", hash = "sha256:3ec3dc2f80f71fd0c955ce48b81bfaf8914c6f63a41a738f28885a1c4892968a"},
+    {file = "pycryptodome-3.9.7-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:cff31f5a8977534f255f729d5d2467526f2b10563a30bbdade92223e0bf264bd"},
+    {file = "pycryptodome-3.9.7-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:ed5761b37615a1f222c5345bbf45272ae2cf8c7dff88a4f53a1e9f977cbb6d95"},
+    {file = "pycryptodome-3.9.7-cp37-cp37m-win32.whl", hash = "sha256:f011cd0062e54658b7086a76f8cf0f4222812acc66e219e196ea2d0a8849d0ed"},
+    {file = "pycryptodome-3.9.7-cp37-cp37m-win_amd64.whl", hash = "sha256:626c0a1d4d83ec6303f970a17158114f75c3ba1736f7f2983f7b40a265861bd8"},
+    {file = "pycryptodome-3.9.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8be56bde3312e022d9d1d6afa124556460ad5c844c2fc63642f6af723c098d35"},
+    {file = "pycryptodome-3.9.7-cp38-cp38-manylinux1_i686.whl", hash = "sha256:c818dc1f3eace93ee50c2b6b5c2becf7c418fa5dd1ba6fc0ef7db279ea21d5e4"},
+    {file = "pycryptodome-3.9.7-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:09b6d6bcc01a4eb1a2b4deeff5aa602a108ec5aed8ac75ae554f97d1d7f0a5ad"},
+    {file = "pycryptodome-3.9.7-cp38-cp38-win32.whl", hash = "sha256:7ac729d9091ed5478af2b4a4f44f5335a98febbc008af619e4569a59fe503e40"},
+    {file = "pycryptodome-3.9.7-cp38-cp38-win_amd64.whl", hash = "sha256:c109a26a21f21f695d369ff9b87f5d43e0d6c768d8384e10bc74142bed2e092e"},
+    {file = "pycryptodome-3.9.7.tar.gz", hash = "sha256:f1add21b6d179179b3c177c33d18a2186a09cc0d3af41ff5ed3f377360b869f2"},
 ]
 pydocstyle = [
     {file = "pydocstyle-5.0.2-py3-none-any.whl", hash = "sha256:da7831660b7355307b32778c4a0dbfb137d89254ef31a2b2978f50fc0b4d7586"},
@@ -2654,31 +2655,31 @@ redis = [
     {file = "redis-3.4.1.tar.gz", hash = "sha256:0dcfb335921b88a850d461dc255ff4708294943322bd55de6cfd68972490ca1f"},
 ]
 regex = [
-    {file = "regex-2020.1.8-cp27-cp27m-win32.whl", hash = "sha256:4e8f02d3d72ca94efc8396f8036c0d3bcc812aefc28ec70f35bb888c74a25161"},
-    {file = "regex-2020.1.8-cp27-cp27m-win_amd64.whl", hash = "sha256:e6c02171d62ed6972ca8631f6f34fa3281d51db8b326ee397b9c83093a6b7242"},
-    {file = "regex-2020.1.8-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:4eae742636aec40cf7ab98171ab9400393360b97e8f9da67b1867a9ee0889b26"},
-    {file = "regex-2020.1.8-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:bd25bb7980917e4e70ccccd7e3b5740614f1c408a642c245019cff9d7d1b6149"},
-    {file = "regex-2020.1.8-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:3e77409b678b21a056415da3a56abfd7c3ad03da71f3051bbcdb68cf44d3c34d"},
-    {file = "regex-2020.1.8-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:07b39bf943d3d2fe63d46281d8504f8df0ff3fe4c57e13d1656737950e53e525"},
-    {file = "regex-2020.1.8-cp36-cp36m-win32.whl", hash = "sha256:23e2c2c0ff50f44877f64780b815b8fd2e003cda9ce817a7fd00dea5600c84a0"},
-    {file = "regex-2020.1.8-cp36-cp36m-win_amd64.whl", hash = "sha256:27429b8d74ba683484a06b260b7bb00f312e7c757792628ea251afdbf1434003"},
-    {file = "regex-2020.1.8-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:0e182d2f097ea8549a249040922fa2b92ae28be4be4895933e369a525ba36576"},
-    {file = "regex-2020.1.8-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:e3cd21cc2840ca67de0bbe4071f79f031c81418deb544ceda93ad75ca1ee9f7b"},
-    {file = "regex-2020.1.8-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:ecc6de77df3ef68fee966bb8cb4e067e84d4d1f397d0ef6fce46913663540d77"},
-    {file = "regex-2020.1.8-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:26ff99c980f53b3191d8931b199b29d6787c059f2e029b2b0c694343b1708c35"},
-    {file = "regex-2020.1.8-cp37-cp37m-win32.whl", hash = "sha256:7bcd322935377abcc79bfe5b63c44abd0b29387f267791d566bbb566edfdd146"},
-    {file = "regex-2020.1.8-cp37-cp37m-win_amd64.whl", hash = "sha256:10671601ee06cf4dc1bc0b4805309040bb34c9af423c12c379c83d7895622bb5"},
-    {file = "regex-2020.1.8-cp38-cp38-manylinux1_i686.whl", hash = "sha256:98b8ed7bb2155e2cbb8b76f627b2fd12cf4b22ab6e14873e8641f266e0fb6d8f"},
-    {file = "regex-2020.1.8-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:6a6ba91b94427cd49cd27764679024b14a96874e0dc638ae6bdd4b1a3ce97be1"},
-    {file = "regex-2020.1.8-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:6a6ae17bf8f2d82d1e8858a47757ce389b880083c4ff2498dba17c56e6c103b9"},
-    {file = "regex-2020.1.8-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:0932941cdfb3afcbc26cc3bcf7c3f3d73d5a9b9c56955d432dbf8bbc147d4c5b"},
-    {file = "regex-2020.1.8-cp38-cp38-win32.whl", hash = "sha256:d58e4606da2a41659c84baeb3cfa2e4c87a74cec89a1e7c56bee4b956f9d7461"},
-    {file = "regex-2020.1.8-cp38-cp38-win_amd64.whl", hash = "sha256:e7c7661f7276507bce416eaae22040fd91ca471b5b33c13f8ff21137ed6f248c"},
-    {file = "regex-2020.1.8.tar.gz", hash = "sha256:d0f424328f9822b0323b3b6f2e4b9c90960b24743d220763c7f07071e0778351"},
+    {file = "regex-2020.2.20-cp27-cp27m-win32.whl", hash = "sha256:99272d6b6a68c7ae4391908fc15f6b8c9a6c345a46b632d7fdb7ef6c883a2bbb"},
+    {file = "regex-2020.2.20-cp27-cp27m-win_amd64.whl", hash = "sha256:974535648f31c2b712a6b2595969f8ab370834080e00ab24e5dbb9d19b8bfb74"},
+    {file = "regex-2020.2.20-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:5de40649d4f88a15c9489ed37f88f053c15400257eeb18425ac7ed0a4e119400"},
+    {file = "regex-2020.2.20-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:82469a0c1330a4beb3d42568f82dffa32226ced006e0b063719468dcd40ffdf0"},
+    {file = "regex-2020.2.20-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:d58a4fa7910102500722defbde6e2816b0372a4fcc85c7e239323767c74f5cbc"},
+    {file = "regex-2020.2.20-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:f1ac2dc65105a53c1c2d72b1d3e98c2464a133b4067a51a3d2477b28449709a0"},
+    {file = "regex-2020.2.20-cp36-cp36m-win32.whl", hash = "sha256:8c2b7fa4d72781577ac45ab658da44c7518e6d96e2a50d04ecb0fd8f28b21d69"},
+    {file = "regex-2020.2.20-cp36-cp36m-win_amd64.whl", hash = "sha256:269f0c5ff23639316b29f31df199f401e4cb87529eafff0c76828071635d417b"},
+    {file = "regex-2020.2.20-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:bed7986547ce54d230fd8721aba6fd19459cdc6d315497b98686d0416efaff4e"},
+    {file = "regex-2020.2.20-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:046e83a8b160aff37e7034139a336b660b01dbfe58706f9d73f5cdc6b3460242"},
+    {file = "regex-2020.2.20-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:b33ebcd0222c1d77e61dbcd04a9fd139359bded86803063d3d2d197b796c63ce"},
+    {file = "regex-2020.2.20-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:bba52d72e16a554d1894a0cc74041da50eea99a8483e591a9edf1025a66843ab"},
+    {file = "regex-2020.2.20-cp37-cp37m-win32.whl", hash = "sha256:01b2d70cbaed11f72e57c1cfbaca71b02e3b98f739ce33f5f26f71859ad90431"},
+    {file = "regex-2020.2.20-cp37-cp37m-win_amd64.whl", hash = "sha256:113309e819634f499d0006f6200700c8209a2a8bf6bd1bdc863a4d9d6776a5d1"},
+    {file = "regex-2020.2.20-cp38-cp38-manylinux1_i686.whl", hash = "sha256:25f4ce26b68425b80a233ce7b6218743c71cf7297dbe02feab1d711a2bf90045"},
+    {file = "regex-2020.2.20-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:9b64a4cc825ec4df262050c17e18f60252cdd94742b4ba1286bcfe481f1c0f26"},
+    {file = "regex-2020.2.20-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:9ff16d994309b26a1cdf666a6309c1ef51ad4f72f99d3392bcd7b7139577a1f2"},
+    {file = "regex-2020.2.20-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:c7f58a0e0e13fb44623b65b01052dae8e820ed9b8b654bb6296bc9c41f571b70"},
+    {file = "regex-2020.2.20-cp38-cp38-win32.whl", hash = "sha256:200539b5124bc4721247a823a47d116a7a23e62cc6695744e3eb5454a8888e6d"},
+    {file = "regex-2020.2.20-cp38-cp38-win_amd64.whl", hash = "sha256:7f78f963e62a61e294adb6ff5db901b629ef78cb2a1cfce3cf4eeba80c1c67aa"},
+    {file = "regex-2020.2.20.tar.gz", hash = "sha256:9e9624440d754733eddbcd4614378c18713d2d9d0dc647cf9c72f64e39671be5"},
 ]
 requests = [
-    {file = "requests-2.22.0-py2.py3-none-any.whl", hash = "sha256:9cf5292fcd0f598c671cfc1e0d7d1a7f13bb8085e9a590f48c010551dc6c4b31"},
-    {file = "requests-2.22.0.tar.gz", hash = "sha256:11e007a8a2aa0323f5a921e9e6a2d7e4e67d9877e85773fba9ba6419025cbeb4"},
+    {file = "requests-2.23.0-py2.py3-none-any.whl", hash = "sha256:43999036bfa82904b6af1d99e4882b560e5e2c68e5c4b0aa03b655f3d7d73fee"},
+    {file = "requests-2.23.0.tar.gz", hash = "sha256:b3f43d496c6daba4493e7c431722aeb7dbc6288f52a6e04e7b6023b0247817e6"},
 ]
 restructuredtext-lint = [
     {file = "restructuredtext_lint-1.3.0.tar.gz", hash = "sha256:97b3da356d5b3a8514d8f1f9098febd8b41463bed6a1d9f126cf0a048b6fd908"},
@@ -2699,21 +2700,21 @@ six = [
     {file = "six-1.14.0-py2.py3-none-any.whl", hash = "sha256:8f3cd2e254d8f793e7f3d6d9df77b92252b52637291d0f0da013c76ea2724b6c"},
     {file = "six-1.14.0.tar.gz", hash = "sha256:236bdbdce46e6e6a3d61a337c0f8b763ca1e8717c03b369e87a7ec7ce1319c0a"},
 ]
-smmap2 = [
-    {file = "smmap2-2.0.5-py2.py3-none-any.whl", hash = "sha256:0555a7bf4df71d1ef4218e4807bbf9b201f910174e6e08af2e138d4e517b4dde"},
-    {file = "smmap2-2.0.5.tar.gz", hash = "sha256:29a9ffa0497e7f2be94ca0ed1ca1aa3cd4cf25a1f6b4f5f87f74b46ed91d609a"},
+smmap = [
+    {file = "smmap-3.0.1-py2.py3-none-any.whl", hash = "sha256:5fead614cf2de17ee0707a8c6a5f2aa5a2fc6c698c70993ba42f515485ffda78"},
+    {file = "smmap-3.0.1.tar.gz", hash = "sha256:171484fe62793e3626c8b05dd752eb2ca01854b0c55a1efc0dc4210fccb65446"},
 ]
 snowballstemmer = [
     {file = "snowballstemmer-2.0.0-py2.py3-none-any.whl", hash = "sha256:209f257d7533fdb3cb73bdbd24f436239ca3b2fa67d56f6ff88e86be08cc5ef0"},
     {file = "snowballstemmer-2.0.0.tar.gz", hash = "sha256:df3bac3df4c2c01363f3dd2cfa78cce2840a79b9f1c2d2de9ce8d31683992f52"},
 ]
 soupsieve = [
-    {file = "soupsieve-1.9.5-py2.py3-none-any.whl", hash = "sha256:bdb0d917b03a1369ce964056fc195cfdff8819c40de04695a80bc813c3cfa1f5"},
-    {file = "soupsieve-1.9.5.tar.gz", hash = "sha256:e2c1c5dee4a1c36bcb790e0fabd5492d874b8ebd4617622c4f6a731701060dda"},
+    {file = "soupsieve-2.0-py2.py3-none-any.whl", hash = "sha256:fcd71e08c0aee99aca1b73f45478549ee7e7fc006d51b37bec9e9def7dc22b69"},
+    {file = "soupsieve-2.0.tar.gz", hash = "sha256:e914534802d7ffd233242b785229d5ba0766a7f487385e3f714446a07bf540ae"},
 ]
 sphinx = [
-    {file = "Sphinx-2.4.1-py3-none-any.whl", hash = "sha256:5024a67f065fe60d9db2005580074d81f22a02dd8f00a5b1ec3d5f4d42bc88d8"},
-    {file = "Sphinx-2.4.1.tar.gz", hash = "sha256:f929b72e0cfe45fa581b8964d54457117863a6a6c9369ecc1a65b8827abd3bf2"},
+    {file = "Sphinx-2.4.3-py3-none-any.whl", hash = "sha256:776ff8333181138fae52df65be733127539623bb46cc692e7fa0fcfc80d7aa88"},
+    {file = "Sphinx-2.4.3.tar.gz", hash = "sha256:ca762da97c3b5107cbf0ab9e11d3ec7ab8d3c31377266fd613b962ed971df709"},
 ]
 sphinx-autodoc-typehints = [
     {file = "sphinx-autodoc-typehints-1.10.3.tar.gz", hash = "sha256:a6b3180167479aca2c4d1ed3b5cb044a70a76cccd6b38662d39288ebd9f0dff0"},
@@ -2732,8 +2733,8 @@ sphinxcontrib-django = [
     {file = "sphinxcontrib_django-0.5.1-py2.py3-none-any.whl", hash = "sha256:73ef7fdbf2ed6d4f35b7ae709032bd5ac493d93cedd0624ea7b51bf5fce41267"},
 ]
 sphinxcontrib-htmlhelp = [
-    {file = "sphinxcontrib-htmlhelp-1.0.2.tar.gz", hash = "sha256:4670f99f8951bd78cd4ad2ab962f798f5618b17675c35c5ac3b2132a14ea8422"},
-    {file = "sphinxcontrib_htmlhelp-1.0.2-py2.py3-none-any.whl", hash = "sha256:d4fd39a65a625c9df86d7fa8a2d9f3cd8299a3a4b15db63b50aac9e161d8eff7"},
+    {file = "sphinxcontrib-htmlhelp-1.0.3.tar.gz", hash = "sha256:e8f5bb7e31b2dbb25b9cc435c8ab7a79787ebf7f906155729338f3156d93659b"},
+    {file = "sphinxcontrib_htmlhelp-1.0.3-py2.py3-none-any.whl", hash = "sha256:3c0bc24a2c41e340ac37c85ced6dafc879ab485c095b1d65d2461ac2f7cca86f"},
 ]
 sphinxcontrib-jsmath = [
     {file = "sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8"},
@@ -2759,8 +2760,8 @@ termcolor = [
     {file = "termcolor-1.1.0.tar.gz", hash = "sha256:1d6d69ce66211143803fbc56652b41d73b4a400a2891d7bf7a1cdf4c02de613b"},
 ]
 testfixtures = [
-    {file = "testfixtures-6.12.0-py2.py3-none-any.whl", hash = "sha256:76eef0c048d6c1ad28bb74ae2b28fa9e3ea3a2f42a56715a4102480b8188e588"},
-    {file = "testfixtures-6.12.0.tar.gz", hash = "sha256:c352760016f0e5579a3e5565387e6d582ccad4db9791b6a293fdfc59d4591b97"},
+    {file = "testfixtures-6.14.0-py2.py3-none-any.whl", hash = "sha256:799144b3cbef7b072452d9c36cbd024fef415ab42924b96aad49dfd9c763de66"},
+    {file = "testfixtures-6.14.0.tar.gz", hash = "sha256:cdfc3d73cb6d3d4dc3c67af84d912e86bf117d30ae25f02fe823382ef99383d2"},
 ]
 "testing.common.database" = [
     {file = "testing.common.database-2.0.3-py2.py3-none-any.whl", hash = "sha256:e3ed492bf480a87f271f74c53b262caf5d85c8bc09989a8f534fa2283ec52492"},
@@ -2780,11 +2781,11 @@ toml = [
     {file = "toml-0.10.0.tar.gz", hash = "sha256:229f81c57791a41d65e399fc06bf0848bab550a9dfd5ed66df18ce5f05e73d5c"},
 ]
 tqdm = [
-    {file = "tqdm-4.42.1-py2.py3-none-any.whl", hash = "sha256:fe231261cfcbc6f4a99165455f8f6b9ef4e1032a6e29bccf168b4bf42012f09c"},
-    {file = "tqdm-4.42.1.tar.gz", hash = "sha256:251ee8440dbda126b8dfa8a7c028eb3f13704898caaef7caa699b35e119301e2"},
+    {file = "tqdm-4.43.0-py2.py3-none-any.whl", hash = "sha256:0d8b5afb66e23d80433102e9bd8b5c8b65d34c2a2255b2de58d97bd2ea8170fd"},
+    {file = "tqdm-4.43.0.tar.gz", hash = "sha256:f35fb121bafa030bd94e74fcfd44f3c2830039a2ddef7fc87ef1c2d205237b24"},
 ]
 twilio = [
-    {file = "twilio-6.35.4.tar.gz", hash = "sha256:02ece6926e36c1bd9588d95de0ecbcf42d53b14af178866faec974799a26de4b"},
+    {file = "twilio-6.35.5.tar.gz", hash = "sha256:d326f4ba5b215b283f127749f38401bdd551746a53f8fb4853b5f47e616370f8"},
 ]
 typed-ast = [
     {file = "typed_ast-1.4.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:73d785a950fc82dd2a25897d525d003f6378d1cb23ab305578394694202a58c3"},
@@ -2831,6 +2832,6 @@ yubiotp = [
     {file = "YubiOTP-0.2.2.post1.tar.gz", hash = "sha256:de83b1560226e38b5923f6ab919f962c8c2abb7c722104cb45b2b6db2ac86e40"},
 ]
 zipp = [
-    {file = "zipp-2.2.0-py36-none-any.whl", hash = "sha256:d65287feb793213ffe11c0f31b81602be31448f38aeb8ffc2eb286c4f6f6657e"},
-    {file = "zipp-2.2.0.tar.gz", hash = "sha256:5c56e330306215cd3553342cfafc73dda2c60792384117893f3a83f8a1209f50"},
+    {file = "zipp-3.0.0-py3-none-any.whl", hash = "sha256:12248a63bbdf7548f89cb4c7cda4681e537031eda29c02ea29674bc6854460c2"},
+    {file = "zipp-3.0.0.tar.gz", hash = "sha256:7c0f8e91abc0dc07a5068f315c52cb30c66bfbc581e5b50704c8a2f6ebae794a"},
 ]