diff --git a/api/views/autocomplete.py b/api/views/autocomplete.py
index 84a915bf..edc81ff7 100644
--- a/api/views/autocomplete.py
+++ b/api/views/autocomplete.py
@@ -70,23 +70,17 @@ class PublicResitelAutocomplete(LoginRequiredAjaxMixin, autocomplete.Select2Quer
 class OdevzdatelnyProblemAutocomplete(autocomplete.Select2QuerySetView):
 	""" View k :mod:`dal.autocomplete` pro vyhledávání problémů především v odevzdávátku. """
 	def get_queryset(self):
-		nastaveni = get_object_or_404(m.Nastaveni)
-		rocnik = nastaveni.aktualni_rocnik
-		# Od tohoto místa dál jsem zkoušel spoustu variací podle https://django-polymorphic.readthedocs.io/en/stable/advanced.html
-		temaQ = Q(Tema___rocnik = rocnik, stav=m.Problem.STAV_ZADANY)
-		ulohaQ = Q(Uloha___cislo_zadani__rocnik = rocnik, stav=m.Problem.STAV_ZADANY)
-		clanekQ = Q(Clanek___cislo__rocnik = rocnik, stav=m.Problem.STAV_ZADANY)
-		qs = m.Problem.objects.filter(temaQ | ulohaQ | clanekQ)
-		#print(temata, ulohy, clanky)
-		#ulohy.union(temata, all=True)
-		#print(ulohy)
-		#ulohy.union(clanky, all=True)
-		#print(ulohy)
-		#qs = ulohy
-		print(qs)
+		qs = m.Problem.objects.filter(stav=m.Problem.STAV_ZADANY)
 		if self.q:
 			qs = qs.filter(
 					Q(nazev__icontains=self.q))
+
+		nadproblem_id = int(self.forwarded.get("nadproblem_id", -1))
+		if nadproblem_id != -1:
+			# Seřadíme tak, aby ty s nadproblem==None byly dole (větší motivace tam naklikat konkrétní úlohy) a pak nějak rozumně.
+			# Tohle je řazení pro odevzdávátko, kde je definován nadproblém, proto je to v tomto ifu. (Jinde si to netroufám řadit)
+			qs = qs.order_by("nadproblem", "kod", "nazev")
+			qs = list(filter(lambda problem: problem.hlavni_problem.id == nadproblem_id, qs))
 		return qs
 
 class ProblemAutocomplete(autocomplete.Select2QuerySetView):
diff --git a/data/sitetree.json b/data/sitetree.json
index 7cfa87b0..29403e5a 100644
--- a/data/sitetree.json
+++ b/data/sitetree.json
@@ -437,7 +437,7 @@
 			"insitetree": true,
 			"parent": 21,
 			"sort_order": 36,
-			"title": "Poslat řešení",
+			"title": "Nahrát řešení",
 			"tree": 1,
 			"url": "seminar_nahraj_reseni",
 			"urlaspattern": true
@@ -476,9 +476,9 @@
 			"access_perm_type": 1,
 			"access_permissions": [
 				[
-					"change_hodnoceni",
-					"seminar",
-					"hodnoceni"
+					"org",
+					"auth",
+					"user"
 				]
 			],
 			"access_restricted": true,
@@ -719,7 +719,7 @@
 			"insitetree": true,
 			"parent": 21,
 			"sort_order": 36,
-			"title": "Nahrát řešení",
+			"title": "Vložit řešení",
 			"tree": 1,
 			"url": "seminar_vloz_reseni",
 			"urlaspattern": true
@@ -1026,6 +1026,36 @@
 		"model": "sitetree.treeitem",
 		"pk": 51
 	},
+	{
+		"fields": {
+			"access_guest": false,
+			"access_loggedin": false,
+			"access_perm_type": 1,
+			"access_permissions": [
+				[
+					"resitel",
+					"auth",
+					"user"
+				]
+			],
+			"access_restricted": true,
+			"alias": null,
+			"description": "",
+			"hidden": false,
+			"hint": "",
+			"inbreadcrumbs": true,
+			"inmenu": true,
+			"insitetree": true,
+			"parent": 23,
+			"sort_order": 52,
+			"title": "Nahrát řešení k nadproblému {{nadproblem_id}}",
+			"tree": 1,
+			"url": "seminar_nahraj_reseni nadproblem_id",
+			"urlaspattern": true
+		},
+		"model": "sitetree.treeitem",
+		"pk": 52
+	},
 	{
 		"fields": {
 			"access_guest": false,
@@ -1041,13 +1071,13 @@
 			"inmenu": true,
 			"insitetree": true,
 			"parent": 28,
-			"sort_order": 52,
+			"sort_order": 53,
 			"title": "Přidat PDF",
 			"tree": 1,
 			"url": "/admin/korektury/korekturovanepdf/add/",
 			"urlaspattern": false
 		},
 		"model": "sitetree.treeitem",
-		"pk": 52
+		"pk": 53
 	}
-]
\ No newline at end of file
+]
diff --git a/deploy_v2/admin_org_prava.json b/deploy_v2/admin_org_prava.json
index 2d07cf83..3ef169a5 100644
--- a/deploy_v2/admin_org_prava.json
+++ b/deploy_v2/admin_org_prava.json
@@ -64,6 +64,36 @@
 		"ct_app_label": "galerie",
 		"ct_model": "obrazek"
 	},
+	{
+		"codename": "add_fotkaheader",
+		"ct_app_label": "header_fotky",
+		"ct_model": "fotkaheader"
+	},
+	{
+		"codename": "change_fotkaheader",
+		"ct_app_label": "header_fotky",
+		"ct_model": "fotkaheader"
+	},
+	{
+		"codename": "view_fotkaheader",
+		"ct_app_label": "header_fotky",
+		"ct_model": "fotkaheader"
+	},
+	{
+		"codename": "add_fotkaurlvazba",
+		"ct_app_label": "header_fotky",
+		"ct_model": "fotkaurlvazba"
+	},
+	{
+		"codename": "change_fotkaurlvazba",
+		"ct_app_label": "header_fotky",
+		"ct_model": "fotkaurlvazba"
+	},
+	{
+		"codename": "view_fotkaurlvazba",
+		"ct_app_label": "header_fotky",
+		"ct_model": "fotkaurlvazba"
+	},
 	{
 		"codename": "add_komentar",
 		"ct_app_label": "korektury",
@@ -224,6 +254,21 @@
 		"ct_app_label": "seminar",
 		"ct_model": "clanek"
 	},
+	{
+		"codename": "add_deadline",
+		"ct_app_label": "seminar",
+		"ct_model": "deadline"
+	},
+	{
+		"codename": "change_deadline",
+		"ct_app_label": "seminar",
+		"ct_model": "deadline"
+	},
+	{
+		"codename": "view_deadline",
+		"ct_app_label": "seminar",
+		"ct_model": "deadline"
+	},
 	{
 		"codename": "add_konfera",
 		"ct_app_label": "seminar",
@@ -304,41 +349,21 @@
 		"ct_app_label": "seminar",
 		"ct_model": "novinky"
 	},
-	{
-		"codename": "add_organizator",
-		"ct_app_label": "seminar",
-		"ct_model": "organizator"
-	},
 	{
 		"codename": "change_organizator",
 		"ct_app_label": "seminar",
 		"ct_model": "organizator"
 	},
-	{
-		"codename": "delete_organizator",
-		"ct_app_label": "seminar",
-		"ct_model": "organizator"
-	},
 	{
 		"codename": "view_organizator",
 		"ct_app_label": "seminar",
 		"ct_model": "organizator"
 	},
-	{
-		"codename": "add_osoba",
-		"ct_app_label": "seminar",
-		"ct_model": "osoba"
-	},
 	{
 		"codename": "change_osoba",
 		"ct_app_label": "seminar",
 		"ct_model": "osoba"
 	},
-	{
-		"codename": "delete_osoba",
-		"ct_app_label": "seminar",
-		"ct_model": "osoba"
-	},
 	{
 		"codename": "view_osoba",
 		"ct_app_label": "seminar",
@@ -404,21 +429,11 @@
 		"ct_app_label": "seminar",
 		"ct_model": "problem"
 	},
-	{
-		"codename": "add_resitel",
-		"ct_app_label": "seminar",
-		"ct_model": "resitel"
-	},
 	{
 		"codename": "change_resitel",
 		"ct_app_label": "seminar",
 		"ct_model": "resitel"
 	},
-	{
-		"codename": "delete_resitel",
-		"ct_app_label": "seminar",
-		"ct_model": "resitel"
-	},
 	{
 		"codename": "view_resitel",
 		"ct_app_label": "seminar",
@@ -603,50 +618,5 @@
 		"codename": "view_taggeditem",
 		"ct_app_label": "taggit",
 		"ct_model": "taggeditem"
-	},
-	{
-		"codename": "add_fotkaheader",
-		"ct_app_label": "header_fotky",
-		"ct_model": "fotkaheader"
-	},
-	{
-		"codename": "change_fotkaheader",
-		"ct_app_label": "header_fotky",
-		"ct_model": "fotkaheader"
-	},
-	{
-		"codename": "view_fotkaheader",
-		"ct_app_label": "header_fotky",
-		"ct_model": "fotkaheader"
-	},
-	{
-		"codename": "add_fotkaurlvazba",
-		"ct_app_label": "header_fotky",
-		"ct_model": "fotkaurlvazba"
-	},
-	{
-		"codename": "change_fotkaurlvazba",
-		"ct_app_label": "header_fotky",
-		"ct_model": "fotkaurlvazba"
-	},
-	{
-		"codename": "view_fotkaurlvazba",
-		"ct_app_label": "header_fotky",
-		"ct_model": "fotkaurlvazba"
-	},
-	{
-		"codename": "add_deadline",
-		"ct_app_label": "seminar",
-		"ct_model": "deadline"
-	},
-	{
-		"codename": "change_deadline",
-		"ct_app_label": "seminar",
-		"ct_model": "deadline"
-	},
-	{
-		"codename": "view_deadline",
-		"ct_app_label": "seminar",
-		"ct_model": "deadline"
 	}
-]
+]
\ No newline at end of file
diff --git a/docs/dalsi_soubory.rst b/docs/dalsi_soubory.rst
index 1a59ee15..627a59d7 100644
--- a/docs/dalsi_soubory.rst
+++ b/docs/dalsi_soubory.rst
@@ -28,7 +28,7 @@ Generuje se za pomocí::
 
 nebo (v případě meníčka)::
 
-    ./manage.py dumpdata sitetree --natrual-foreign > data/sitetree_new.json
+    ./manage.py dumpdata sitetree --natural-foreign > data/sitetree_new.json
     ./fix_json.py data/sitetree_new.json data/sitetree.json
 
 deploy_v2
diff --git a/docs/index.rst b/docs/index.rst
index 5481bb88..d06c7e4a 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -27,6 +27,7 @@ Dokumentace (jak v ``docs/``, tak přímo v kódu) je psaná ve
    :titlesonly:
 
    vyvoj
+   zavislosti
    sphinx
    skripty
    modules/modules
diff --git a/docs/tabulka_prerekvizit.rst b/docs/tabulka_prerekvizit.rst
deleted file mode 100644
index 9dcce4c5..00000000
--- a/docs/tabulka_prerekvizit.rst
+++ /dev/null
@@ -1,25 +0,0 @@
-.. Není odkázaná z menu, je to záměr
-
-Tabulka prerekvizit v různých distribucích
-=========
-
-.. admonition:: Metodika
-
-   Na čistém repozitáři (``git clean -fxd``) a čistém systému spouštíme
-   ``make/init_local``. Když to spadne, tak do tabulky zapíšeme, co jsme
-   přiinstalovali. Protože větev ``makefiles`` aktuálně není mergenutá do
-   masteru, nefunguje synchronizace flatpages (a stejně nemáme SSH klíč), takže
-   tam ``make/init_local`` sestřelíme a vyzkoušíme, že ``make/test`` spustí
-   testy.
-
-.. Grafické tabulky (grid-tables, simple-tables) jsou strašný porod vyrábět, dlabu na to a cpu to do CSV…
-
-.. csv-table:: Prerekvizity v jednotlivých distribucích
-   :header: Distribuce / OS, Repozitář s Py3.9, venv, py knihovny, PostgreSQL knihovna, poznámky
-
-   Ubuntu 22.10, ??, ``python3-venv``, ``python3-dev``, ``libpq-dev``, "Je potřeba zapnout zdroj ``universe`` a nainstalovat kompilátor C (``gcc``)?"
-   Linux Mint 21, ??, ``python3-venv``, ``python3-dev``, ``libpq-dev``, ""
-   Archlinux 2022.11.01, AUR, vestavěný, vestavěné, ``postgresql-libs``, "Je potřeba céčkový kompilátor (``gcc``)"
-   openSUSE Leap 15.4, oficiální (``python39``), předinstalovaný?, ``python39-devel``, ??FIXME!!, "Výchozí verze pythonu je 3.6 a ta je moc stará, potřeba instalovat ``gcc``. Nevím jak sehnat pg_config."
-   Debian 11, "oficiální, výchozí", ??, ??, ??, "Určitě to tam rozběhat jde, protože Gimli. Nejspíš bude relativně podobné Ubuntu."
-
diff --git a/docs/vyvoj.rst b/docs/vyvoj.rst
index 0d23972a..2df0ae64 100644
--- a/docs/vyvoj.rst
+++ b/docs/vyvoj.rst
@@ -37,7 +37,7 @@ Kromě toho je potřeba mít účet na `Gitee <https://gitea.ks.matfyz.cz>`_, kd
 bydlí gitový repozitář s kódem.
 
 .. tip:: Potřebné balíčky v různých distribucích jsou sepsané v :ref:`tabulce
-   prerekvizit <Tabulka prerekvizit v různých distribucích>`.
+   prerekvizit <Alternativní jména balíčků>`.
 
 Doporučené
 ^^^^^^^^^^
diff --git a/docs/zavislosti.rst b/docs/zavislosti.rst
new file mode 100644
index 00000000..c2f684bd
--- /dev/null
+++ b/docs/zavislosti.rst
@@ -0,0 +1,97 @@
+Závislosti webu
+@@@@@@@@@@@@@@@
+
+Web ke svému běhu potřebuje různé další programy. Tahle stránka se snaží je pokrýt.
+
+Stránka je koncipována jako odrážkový seznam balíčků pro Ubuntu s případnými
+komentáři, na konci stránky jsou uvedena :ref:`jména balíčků <Alternativní jména
+balíčků>` v různých dalších distribucích. (Seznam mj. cílí na lokální
+rozchození, proto popisuji Ubuntu a ne Debian. I tak se ale snažíme popsat web
+v úplnosti.)
+
+.. I use Arch, btw.
+
+
+Základ webu
+===========
+
+- ``python3`` – Ideálně Python 3.9, jenž je na Gimlim
+- ``python3-pip`` pro instalaci dalších Pythoních balíčků podle ``requirements.txt``
+- ``python3-venv``
+- ``gcc`` – kompilace Pythoních knihoven ze zdrojových distribucí (sdist), možná (neotestováno) jde jako alternativu použít ``python3-wheel`` a stahovat bdists
+- ``python3-dev`` – taktéž
+- ``libpq-dev`` do třetice…
+- ``ghostscript`` TODO konverze PDF v korekturovátku
+- ``pdflatex`` FIXME! generování obálek a stvrzenek
+- ``git`` – používán :ref:`Make skripty`
+- ``locales`` pro české formáty
+
+Nasazení na produkci / testweb
+==============================
+
+(nejsou nutně potřeba k provozu lokální instance)
+
+- ``rsync``
+- ``pg_utils`` FIXME
+- ``htpasswd`` FIXME – aby testweb nepoužívali náhodní kolemjdoucí
+- ``postgresql-server`` TODO
+- ``acl`` pro nastavování práv přes ``setfacl``
+
+Pro testweb je potřeba i všechno pro :ref:`dokumentaci <Dokumentace>`, vizte níž.
+
+Předpokládá se nasazení v uWSGI pod Nginxem a služba běžící pod systemd, nicméně to už je spíš záležitost infrastruktury a ne specifikum mamwebu.
+
+Dokumentace
+===========
+
+- ``make`` pro zbuildění
+- Pythoní balíčky podle příslušné části ``requirements.txt``
+
+Vývojové nástroje
+=================
+
+(Nejsou nezbytně nutné, ale předpokládáme jejich užitečnost. Mohou se hodit i na produkci.)
+
+- ``psql`` TODO pro manuální dotazy do PostgreSQL
+- ``sqlite3`` TODO totéž pro SQLite3
+- ``ssh``
+- ``graphviz`` pro vygenerování schématu
+- ``rsync``
+- ``ipython3`` – hezčí interaktivní shell (stačí z ``requirements.txt``)
+
+Potenciální usnadnění života
+============================
+
+(Úplně zbytečné, ale sdílíme pozitivní zkušenosti :-))
+
+- ``tea`` – CLI klient pro Giteu, aby člověk nepotřeboval otevírat web pro založení PR
+
+
+Alternativní jména balíčků
+==========================
+
+Různé distribuce balí SW různě, takže to, co je v jedné distribuci jeden
+balíček může být v jiné rozděleno do víc. Pro usnadnění nasazení je tady
+přehled známých alternativních jmen.
+
+TODO: tabulka není úplná. Pokud na něco narazíte, tak ji prosím doplňte.
+
+.. admonition:: Jak se pozná, že web funguje, pro účely tabulky?
+
+   Na čistém repozitáři (``git clean -fxd``) a čistém systému spouštíme
+   ``make/init_local``. Když to spadne, tak do tabulky zapíšeme, co jsme
+   přiinstalovali. Protože nefunguje synchronizace flatpages (nemáme SSH klíč),
+   ``make/init_local`` sestřelíme při pokusu o synchronizaci a vyzkoušíme, že
+   ``make/test`` spustí testy.
+
+.. Grafické tabulky (grid-tables, simple-tables) jsou strašný porod vyrábět, dlabu na to a cpu to do CSV…
+
+.. csv-table:: Prerekvizity v jednotlivých distribucích
+   :header: Distribuce / OS, Repozitář s Py3.9, venv, py knihovny, PostgreSQL knihovna, poznámky
+
+   Ubuntu 22.10, ??, ``python3-venv``, ``python3-dev``, ``libpq-dev``, "Je potřeba zapnout zdroj ``universe`` a nainstalovat kompilátor C (``gcc``)?"
+   Linux Mint 21, ??, ``python3-venv``, ``python3-dev``, ``libpq-dev``, ""
+   Archlinux 2022.11.01, AUR, vestavěný, vestavěné, ``postgresql-libs``, "Je potřeba céčkový kompilátor (``gcc``)"
+   openSUSE Leap 15.4, oficiální (``python39``), předinstalovaný?, ``python39-devel``, ??FIXME!!, "Výchozí verze pythonu je 3.6 a ta je moc stará, potřeba instalovat ``gcc``. Nevím jak sehnat pg_config."
+   Debian 11, "oficiální, výchozí", ??, ??, ??, "Určitě to tam rozběhat jde, protože Gimli. Nejspíš bude relativně podobné Ubuntu."
+
diff --git a/korektury/migrations/0020_lepsi_popis_nazvu_PDF_v_adminu.py b/korektury/migrations/0020_lepsi_popis_nazvu_PDF_v_adminu.py
new file mode 100644
index 00000000..6ea07604
--- /dev/null
+++ b/korektury/migrations/0020_lepsi_popis_nazvu_PDF_v_adminu.py
@@ -0,0 +1,18 @@
+# Generated by Django 2.2.28 on 2023-06-19 19:38
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('korektury', '0019_auto_20221205_2014'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='korekturovanepdf',
+            name='nazev',
+            field=models.CharField(help_text='Název (např. `22.1 | analyza v4` nebo `propagace | letacek v0`) korekturovaného PDF', max_length=50, verbose_name='název PDF'),
+        ),
+    ]
diff --git a/korektury/models.py b/korektury/models.py
index ac82c14e..8906c00c 100644
--- a/korektury/models.py
+++ b/korektury/models.py
@@ -55,7 +55,7 @@ class KorekturovanePDF(models.Model):
 
 	cas = models.DateTimeField(u'čas vložení PDF',default=timezone.now,help_text = 'Čas vložení PDF')
 
-	nazev = models.CharField(u'název PDF',blank = False,max_length=50, help_text='Název (např. 22.1 verze 4) korekturovaného PDF')
+	nazev = models.CharField(u'název PDF',blank = False,max_length=50, help_text='Název (např. `22.1 | analyza v4` nebo `propagace | letacek v0`) korekturovaného PDF')
 
 	komentar = models.TextField(u'komentář k PDF',blank = True, help_text='Komentář ke korekturovanému PDF (např. na co se zaměřit)')
 
diff --git a/mamweb/settings_common.py b/mamweb/settings_common.py
index 03724d3d..71bae132 100644
--- a/mamweb/settings_common.py
+++ b/mamweb/settings_common.py
@@ -54,6 +54,9 @@ LOGIN_REDIRECT_URL = 'profil'
 SESSION_EXPIRE_AT_BROWSER_CLOSE = True
 DOBA_ODHLASENI_PRI_ZASKRTNUTI_NEODHLASOVAT = 365 * 24 * 3600  # rok
 
+# View pro chybu s CSRF tokenem (např. se sušenkami)
+CSRF_FAILURE_VIEW = 'various.views.csrf_error'
+
 # Modules configuration
 
 AUTHENTICATION_BACKENDS = (
@@ -151,6 +154,7 @@ INSTALLED_APPS = (
 	'soustredeni',
 	'treenode',
 	'vyroci',
+	'sifrovacka',
 
 	# Admin upravy:
 
diff --git a/mamweb/settings_prod.py b/mamweb/settings_prod.py
index 3a81c8c4..ebe827e4 100644
--- a/mamweb/settings_prod.py
+++ b/mamweb/settings_prod.py
@@ -27,8 +27,9 @@ DEBUG = False
 
 TEMPLATE_DEBUG = False
 
-ALLOWED_HOSTS = ['mam.mff.cuni.cz', 'www.mam.mff.cuni.cz', 'atrey.karlin.mff.cuni.cz', 
-		'mamweb.bezva.org','gimli.ms.mff.cuni.cz']
+ALLOWED_HOSTS = ['mam.mff.cuni.cz', # Hlavní a asi jediná funkční adresa
+		'mam.matfyz.cz', # Ne že by se tohle použilo, ale pro potenciální případ změny…
+		]
 
 # Database
 # https://docs.djangoproject.com/en/1.7/ref/settings/#databases
diff --git a/mamweb/settings_test.py b/mamweb/settings_test.py
index eac5a7b4..dc5beee8 100644
--- a/mamweb/settings_test.py
+++ b/mamweb/settings_test.py
@@ -32,7 +32,10 @@ DEBUG = True
 
 TEMPLATES[0]['OPTIONS']['debug'] = True
 
-ALLOWED_HOSTS = ['*.mam.mff.cuni.cz', 'atrey.karlin.mff.cuni.cz', 'mam.mff.cuni.cz', 'mam-test.kam.mff.cuni.cz', 'gimli.ms.mff.cuni.cz', 'mam-test.ks.matfyz.cz']
+ALLOWED_HOSTS = [
+	'mam-test.ks.matfyz.cz',
+	'*.mam.mff.cuni.cz', # Asi se nikdy nepoužije…
+	]
 
 # Database
 # https://docs.djangoproject.com/en/1.7/ref/settings/#databases
diff --git a/mamweb/static/css/mamweb.css b/mamweb/static/css/mamweb.css
index 3833ff92..84e4c79b 100644
--- a/mamweb/static/css/mamweb.css
+++ b/mamweb/static/css/mamweb.css
@@ -1,3 +1,4 @@
+@charset "utf-8"; /* vynuť utf-8 */
 @import url("rozliseni.css");
 
 @font-face {
@@ -53,6 +54,17 @@ a.login-ref-admin {
 	color: #fffbf6;
 }
 
+.napis-webarum {
+	display: inline;
+	color: #fffbf6;
+	float: right;
+}
+
+.napis-webarum a {
+	color: #f9d59e;
+	text-decoration: underline;
+}
+
 /* odkazy a nadpisy */
 
 a {
@@ -1233,6 +1245,7 @@ div.gdpr {
 .dosla_reseni tr th, .dosla_reseni tr td {
 	padding: 1px 10px 1px 10px;
 	border-collapse: collapse;
+	min-width: 8em; /*Nastřeleno, aby se řádky s řešeními nezalamovaly. Teoreticky není potřeba pro th, ale whatever.*/
 }
 
 .dosla_reseni tr:nth-child(even) {
@@ -1260,3 +1273,31 @@ label[for=id_skola] {
 .bodovani>input {
 	width: 4em;
 }
+
+.bodovani>input::placeholder {
+	color: lightgray;
+	opacity: 1;
+}
+
+.bodovani>input::-webkit-input-placeholder { /* Edge */
+	color: lightgray;
+}
+
+
+/* Select2 používaný hlavně multiple selectem. Přidání checkboxů a změna barvy. */
+/* Podle https://stackoverflow.com/a/48290544 */
+/* U autocomplete.ModelSelect2Multiple vyžaduje 'data-dropdown-css-class': 's2m-se-zaskrtavatky' */
+.s2m-se-zaskrtavatky .select2-results__option[aria-selected=true]:before {
+	content: '☑ ';
+	padding: 0 0 0 8px;
+}
+
+.s2m-se-zaskrtavatky .select2-results__option[aria-selected=false]:before {
+	content: '◻ ';
+	padding: 0 0 0 8px;
+}
+
+/* Oranžové zvýraznění v Select2 */
+.select2-results__option--highlighted {
+	background-color: #e84e10 !important;
+}
diff --git a/mamweb/templates/500.html b/mamweb/templates/500.html
index 71d8e651..67085a8f 100644
--- a/mamweb/templates/500.html
+++ b/mamweb/templates/500.html
@@ -3,7 +3,10 @@
 {% load static %}
 
 {% block errorheading %}
+      <br> {# Meníčko nedostaneme, protože dostáváme prázdný kontext. Tak alespoň ať se O-JO-JO-JO-JOJ neschovává pod ním #}
+    {% block nadpis1a %}
       O-jo-jo-jo-joj
+    {% endblock %}
 {% endblock %}
 
 {% block errortext %}
diff --git a/mamweb/templates/base.html b/mamweb/templates/base.html
index b10103e5..4281c6df 100644
--- a/mamweb/templates/base.html
+++ b/mamweb/templates/base.html
@@ -3,6 +3,7 @@
 <!DOCTYPE html>
 <html lang='cs'>
   <head>
+    <meta charset="utf-8"> {# vynuť UTF-8. #}
     <title>{% block title %}{% block nadpis1a %}🦊{% endblock %} | Korespondenční seminář M&amp;M{% endblock title %}</title>
     <meta name="viewport" content="width=device-width, initial-scale=1.0">
     <link rel="shortcut icon" href="{% static 'images/MATFYZ_MM_barevne.svg' %}" type="image/x-icon">
@@ -49,6 +50,8 @@
           <a class="login-ref-admin" href='{% url 'admin:flatpages_flatpage_change' flatpage.id %}'>[admin]</a>
         {% endif %}
         <a class="login-ref-admin" href='/admin'>[admin mainpage]</a>
+
+        <span class="napis-webarum">Něco ti nejde/nefunguje/mate tě? <a class="login-ref-admin" href='mailto:web@mam.mff.cuni.cz'>Napiš webařům!</a></span>
       </div>
     {% endif %}
 
diff --git a/mamweb/urls.py b/mamweb/urls.py
index 0855b6b6..9ef2750a 100644
--- a/mamweb/urls.py
+++ b/mamweb/urls.py
@@ -71,6 +71,8 @@ urlpatterns = [
 	# Výroční sraz
 	path('sraz/30-let/', include('vyroci.urls')),
 
+	# Miniapka na šifrovačku
+	path('sifrovacka/', include('sifrovacka.urls')),
 ]
 
 # This is only needed when using runserver.
diff --git a/odevzdavatko/__init__.py b/odevzdavatko/__init__.py
index a4ee2679..ee78a49b 100644
--- a/odevzdavatko/__init__.py
+++ b/odevzdavatko/__init__.py
@@ -4,8 +4,8 @@ Obsahuje vše, co se týká odevzdávání (+ nahrávání) a opravování řeš
 Slovníček:
     Moje řešení = Přehled řešení = Řešení, která odevzdal aktuálního uživatel sám.
     Došlá řešení = Tabulka + seznam + detail + ... = Řešení, která poslal někdo jiný.
-    Poslat řešení = Odevdat mé řešení. (Tj. řešení se vztahem k aktuálnímu uživateli.)
-    Nahrát řešení = Nahrání řešení bez vztahu k aktuálnímu uživateli.
+    Nahrát řešení = Odevdat mé řešení. (Tj. řešení se vztahem k aktuálnímu uživateli.)
+    Vlož řešení = Vložit řešení bez vztahu k aktuálnímu uživateli.
 
 TODO: Místo vložit řešení v nahrávání a posílání řešení dát něco jiného?
-"""
\ No newline at end of file
+"""
diff --git a/odevzdavatko/forms.py b/odevzdavatko/forms.py
index 0b93d555..583523e3 100644
--- a/odevzdavatko/forms.py
+++ b/odevzdavatko/forms.py
@@ -29,6 +29,8 @@ class PosliReseniForm(forms.Form):
 			attrs={
 				'data-placeholder--id': '-1',
 				'data-placeholder--text': '---',
+				'data-close-on-select': 'false',
+				'data-dropdown-css-class': 's2m-se-zaskrtavatky',
 				'data-allow-clear': 'true'
 				},
 			),
@@ -43,6 +45,8 @@ class PosliReseniForm(forms.Form):
 			url='autocomplete_resitel',
 			attrs = {'data-placeholder--id': '-1',
 				'data-placeholder--text' : '---',
+				'data-close-on-select': 'false',
+				'data-dropdown-css-class': 's2m-se-zaskrtavatky',
 				'data-allow-clear': 'true'})
     		)
 
@@ -62,12 +66,6 @@ class PosliReseniForm(forms.Form):
 	#poznamka = models.TextField('neveřejná poznámka', blank=True,
 	#	help_text='Neveřejná poznámka k řešení (plain text)')
 
-	#TODO body do cisla
-	#TODO prilohy
-
-	##def __init__(self, *args, **kwargs):
-	##	super().__init__(*args, **kwargs)
-	##	#self.fields['favorite_color'] = forms.ChoiceField(choices=[(color.id, color.name) for color in Resitel.objects.all()])
 
 class NahrajReseniForm(forms.ModelForm):
 	class Meta:
@@ -80,23 +78,40 @@ class NahrajReseniForm(forms.ModelForm):
 					url='autocomplete_problem_odevzdatelny',
 					attrs = {'data-placeholder--id': '-1',
 						'data-placeholder--text' : '---',
+						'data-close-on-select': 'false',
+						'data-dropdown-css-class': 's2m-se-zaskrtavatky',
 						'data-allow-clear': 'true'},
+					forward=["nadproblem_id"],
 				),
 				'resitele':
 				autocomplete.ModelSelect2Multiple(
 					url='autocomplete_resitel_public',
 					attrs = {'data-placeholder--id': '-1',
 						'data-placeholder--text' : '---',
+						'data-close-on-select': 'false',
+						'data-dropdown-css-class': 's2m-se-zaskrtavatky',
 						'data-allow-clear': 'true'},
 				)
 		}
 
+	nadproblem_id = forms.IntegerField(required=False, disabled=True, widget=forms.HiddenInput())
+
 	def __init__(self, *args, **kwargs):
 		super().__init__(*args, **kwargs)
 		# FIXME Z nějakého důvodu se do této třídy dostaneme i bez resitele
 		if 'resitele' in self.fields:
 			# FIXME Mnohem hezčí by to bylo u definice resitele výše, ale nepodařilo se mi to.
 			self.fields['resitele'].required = False
+			self.fields['resitele'].label = "Další autoři"
+		if 'problem' in self.fields:
+			self.fields['problem'].label = "Všechny řešené problémy"
+
+	def clean_problem(self):
+		problem = self.cleaned_data.get('problem')
+		for p in problem:
+			if p.stav != m.Problem.STAV_ZADANY:
+				raise forms.ValidationError("Problém " + str(p) + " již nelze řešit!")
+		return problem
 
 ReseniSPrilohamiFormSet = inlineformset_factory(m.Reseni,m.PrilohaReseni, 
 		form = NahrajReseniForm,
@@ -223,6 +238,7 @@ class OdevzdavatkoTabulkaFiltrForm(forms.Form):
 			'reseni_od': terminy[-2] if rocnik is None else terminy[0],
 			'reseni_do': terminy[-1],
 			'neobodovane': False,
+			'barvicky': True,
 		}
 		return initial
 
@@ -247,3 +263,4 @@ class OdevzdavatkoTabulkaFiltrForm(forms.Form):
 	reseni_od = forms.DateField(input_formats=[DATE_FORMAT])
 	reseni_do = forms.DateField(input_formats=[DATE_FORMAT])
 	neobodovane = forms.BooleanField(required=False)
+	barvicky = forms.BooleanField(required=False)
diff --git a/odevzdavatko/templates/odevzdavatko/nahraj_reseni.html b/odevzdavatko/templates/odevzdavatko/nahraj_reseni.html
index 739340c3..ca326d67 100644
--- a/odevzdavatko/templates/odevzdavatko/nahraj_reseni.html
+++ b/odevzdavatko/templates/odevzdavatko/nahraj_reseni.html
@@ -7,19 +7,20 @@
 {% block content %}
 <h1>
   {% block nadpis1a %}
-    Vložit řešení
+    Nahrát řešení
   {% endblock %}
 </h1>
 
-<p style="text-align: justify">Když řešení různých témátek vložíš každé zvlášť, lépe se v nich vyznáme a&nbsp;třeba ti je i&nbsp;rychleji opravíme.</p>
-
-  <p>Pokud řešíte ve více lidech, je <strong>nutné</strong> přidat tyto lidi jako „Autory řešení“. V tomto poli se vyhledává podle přezdívek, které si lze nastavit v „Osobní údaje“. Sebe vyplňovat nemusíte a za skupinu odevzdávejte pouze <strong>jednou</strong> (ne každý sám).</p>
-
-<form enctype="multipart/form-data" action="{% url 'seminar_nahraj_reseni' %}" method="post" onsubmit="return zkontroluj_prilohy();">
+<form enctype="multipart/form-data" action="{% url 'seminar_nahraj_reseni' nadproblem_id %}" method="post" onsubmit="return zkontroluj_prilohy();">
   {% csrf_token %}
-  <table class='form' id="reseni">
+  <table class='form'>
+    <tr>
+      <td><label class="field-label field-required" for="tema">Téma:</label></td>
+      <td><input id="tema" disabled="" type="text" value="{{ nadproblem }}"></td>
+    </tr>
+
+    {% with field=form.problem %}
     <tr>
-      {% for field in form %}
       <td>
         <label class="field-label{% if field.field.required %} field-required{% endif %}" for="{{ field.id_for_label }}">
           {{ field.label }}:
@@ -28,15 +29,54 @@
       <td>
         {{ field }}
       </td>
-      {% endfor %}
     </tr>
+
+    {% if field.errors %}
+      <tr>
+        <td colspan="2"><span class="field-error">{{ field.errors }}</span></td>
+      </tr>
+    {% endif %}
+
+    {% endwith %}
   </table>
 
+  {% for field in form.hidden_fields %}
+    {{ field }}
+  {% endfor %}
+
+  <hr>
+  <h4>Spolupráce s&nbsp;dalšími řešiteli</h4>
+
+  <p>Pokud řešíte ve více lidech, je <strong>potřeba</strong> přidat tyto lidi jako „Další autory“. V&nbsp;tomto poli se vyhledává podle přezdívek, které si lze nastavit v&nbsp;„Osobních údajích“. Sebe vyplňovat nemusíte a za skupinu odevzdávejte pouze <strong>jednou</strong> (ne každý sám).</p>
+
+  <table class='form'>
+    {% with field=form.resitele %}
+      <tr>
+        <td>
+          <label class="field-label{% if field.field.required %} field-required{% endif %}" for="{{ field.id_for_label }}">
+            {{ field.label }}:
+          </label>
+        </td>
+        <td>
+          {{ field }}
+        </td>
+      </tr>
+
+      {% if field.errors %}
+        <tr>
+          <td colspan="2"><span class="field-error">{{ field.errors }}</span></td>
+        </tr>
+      {% endif %}
+
+    {% endwith %}
+  </table>
 
 <hr>
 
 {% include "odevzdavatko/prilohy.html" %}
 
+{{form.non_field_errors}}
+
 <hr>
 <h4>Odevzdat řešení</h4>
 <input type="submit" value="Odevzdat">
diff --git a/odevzdavatko/templates/odevzdavatko/nahraj_reseni_nadproblem.html b/odevzdavatko/templates/odevzdavatko/nahraj_reseni_nadproblem.html
new file mode 100644
index 00000000..ccf505fa
--- /dev/null
+++ b/odevzdavatko/templates/odevzdavatko/nahraj_reseni_nadproblem.html
@@ -0,0 +1,21 @@
+{% extends "base.html" %}
+{% load static %}
+
+{% block content %}
+<h1>
+  {% block nadpis1a %}
+    Nahrát řešení
+  {% endblock %}
+</h1>
+
+<h4>Seznam témat k odevzdání</h4>
+
+<ul>
+  {% for problem in object_list %}
+    <li><a href="{% url 'seminar_nahraj_reseni' problem.id %}">{{ problem }}</a></li>
+  {% empty %}
+    <li>Nelze nic odevzdávat.</li>
+  {% endfor %}
+</ul>
+
+{% endblock %}
diff --git a/odevzdavatko/templates/odevzdavatko/prilohy.html b/odevzdavatko/templates/odevzdavatko/prilohy.html
index 4946546b..1e33376f 100644
--- a/odevzdavatko/templates/odevzdavatko/prilohy.html
+++ b/odevzdavatko/templates/odevzdavatko/prilohy.html
@@ -2,8 +2,9 @@
 
 <h4>Soubory s řešením</h4>
 
-<p style="text-align: justify">Maximální součet velikostí příloh je cca 49&nbsp;MB. Pokud je to možné a&nbsp;dává to smysl, pošli nám prosím své řešení ve formátu PDF, ostatní formáty nemusíme umět otevřít.</p>
-<p style="text-align: justify">Pokud svůj soubor rozumně pojmenuješ, urychlíš opravování a&nbsp;předejdeš tomu, že si nějakého tvého řešení nevšimneme. Například z&nbsp;<code>img_250921_101205.pdf</code> nepoznáme, kterou úlohu jsi odevzdal, zato <code>uloha_3.pdf</code> nebo <code>tema_1.pdf</code>, to už je něco jiného. Případně můžeš využít i&nbsp;poznámku řešitele.</p>
+<p style="text-align: justify">Pokud je to možné a&nbsp;dává to smysl (tj.&nbsp;není to třeba kód nebo doprovodný obrázek), pošli nám prosím své řešení ve formátu <strong>PDF</strong>, ostatní formáty nemusíme umět otevřít.</p>
+<p style="text-align: justify">Pokud svůj soubor <strong>rozumně pojmenuješ</strong>, urychlíš opravování a&nbsp;předejdeš tomu, že si nějakého tvého řešení nevšimneme. Například z&nbsp;<code>img_250921_101205.pdf</code> nepoznáme, kterou úlohu jsi odevzdal, zato <code>uloha_3.pdf</code> nebo <code>tema_1.pdf</code>, to už je něco jiného. Případně můžeš využít i&nbsp;poznámku řešitele.</p>
+<p style="text-align: justify">Maximální součet velikostí příloh je cca <strong>49&nbsp;MB</strong>.</p>
 
 <div id="form_set">
 {% for form in prilohy.forms %}
diff --git a/odevzdavatko/templates/odevzdavatko/tabulka.html b/odevzdavatko/templates/odevzdavatko/tabulka.html
index 6d1232d2..7cd317e5 100644
--- a/odevzdavatko/templates/odevzdavatko/tabulka.html
+++ b/odevzdavatko/templates/odevzdavatko/tabulka.html
@@ -1,6 +1,7 @@
 {% extends "base.html" %}
 
 {% load utils %} {# Možná by mohlo být někde výš v hierarchii templatů... #}
+{% load barvy_reseni %}
 
 {% block content %}
 
@@ -11,6 +12,7 @@
 Od data (vyjma): {{ filtr.reseni_od }}
 Do data (včetně): {{ filtr.reseni_do }}
 <span title="Jen neobodovaná řešení">🔨?</span> {{ filtr.neobodovane }}
+<span title="Obarvit shodná řešení shodně">🎨?</span> {{ filtr.barvicky }}
 <input type=submit value="→">
 </form>
 
@@ -36,12 +38,15 @@ Do data (včetně): {{ filtr.reseni_do }}
 			{# TODO: Chceme mít view i na řešení konkrétního řešitele ke všem problémům? #}
 			{{ resitel }}
 		</td>
-		{% for hodn in hodnoty %}
+		{% for soucet,bunka in hodnoty %}
 			<td>
-			{% if hodn %}
-			<a href="{% url 'odevzdavatko_reseni_resitele_k_problemu' problem=hodn.problem_id resitel=hodn.resitel_id %}">
-				{{ hodn.pocet_reseni }} řeš.<br>{{ hodn.body }} b<br>{{ hodn.posledni_odevzdani|kratke_datum|default_if_none:"Nikdy"|default:"???"}}
-			</a>
+			{% for reseni,hodnoceni in bunka %}
+			<a {% if barvicky %} style="color: {{reseni|barva_reseni}};" {% endif %} href="{% url 'odevzdavatko_detail_reseni' pk=reseni.id %}">
+					{{reseni.cas_doruceni | date:"j. n."}} ({{ hodnoceni.body|default_if_none:"🔨"}} b)
+				</a><br>
+			{% endfor %}
+			{% if bunka|length > 1 %}
+				<b>Σ: {{soucet}} b</b>
 			{% endif %}
 			</td>
 		{% endfor %}
diff --git a/odevzdavatko/templates/odevzdavatko/posli_reseni.html b/odevzdavatko/templates/odevzdavatko/vloz_reseni.html
similarity index 100%
rename from odevzdavatko/templates/odevzdavatko/posli_reseni.html
rename to odevzdavatko/templates/odevzdavatko/vloz_reseni.html
diff --git a/odevzdavatko/templatetags/barvy_reseni.py b/odevzdavatko/templatetags/barvy_reseni.py
new file mode 100644
index 00000000..5a3791fd
--- /dev/null
+++ b/odevzdavatko/templatetags/barvy_reseni.py
@@ -0,0 +1,15 @@
+from django import template
+register = template.Library()
+
+from functools import cache
+import seminar.models as m
+
+@register.filter
+@cache
+def barva_reseni(r: m.Reseni):
+	"""Vrátí nějakou barvu pro daný problém, ve tvaru '#RRGGBB'
+
+	Efektivně hešujeme do barev."""
+
+	#TODO: ne všechny barvy jsou dobře rozlišitelné a vidět…
+	return f'#{hash(str(r.id)) & 0xffffff:06x}'
diff --git a/odevzdavatko/urls.py b/odevzdavatko/urls.py
index 8c53de6b..6b021f2e 100644
--- a/odevzdavatko/urls.py
+++ b/odevzdavatko/urls.py
@@ -19,8 +19,9 @@ from seminar.utils import org_required, resitel_required, viewMethodSwitch, \
 from . import views
 
 urlpatterns = [
-	path('org/add_solution', org_required(views.PosliReseniView.as_view()), name='seminar_vloz_reseni'),
-	path('resitel/nahraj_reseni', resitel_required(views.NahrajReseniView.as_view()), name='seminar_nahraj_reseni'),
+	path('org/add_solution', org_required(views.VlozReseniView.as_view()), name='seminar_vloz_reseni'),
+	path('resitel/nahraj_reseni', resitel_required(views.NahrajReseniRozcestnikTematekView.as_view()), name='seminar_nahraj_reseni'),
+	path('resitel/nahraj_reseni/<int:nadproblem_id>/', resitel_required(views.NahrajReseniView.as_view()), name='seminar_nahraj_reseni'),
 	path('resitel/odevzdana_reseni/', resitel_or_org_required(views.PrehledOdevzdanychReseni.as_view()), name='seminar_resitel_odevzdana_reseni'),
 
 	path('org/reseni/', org_required(views.TabulkaOdevzdanychReseniView.as_view()), name='odevzdavatko_tabulka'),
diff --git a/odevzdavatko/views.py b/odevzdavatko/views.py
index e87e19ea..41af1dcb 100644
--- a/odevzdavatko/views.py
+++ b/odevzdavatko/views.py
@@ -13,6 +13,7 @@ from django.db.models import Q
 
 from dataclasses import dataclass
 import datetime
+from decimal import Decimal
 from itertools import groupby
 import logging
 
@@ -37,14 +38,6 @@ logger = logging.getLogger(__name__)
 # Taky se může hodit:
 # - Tabulka všech řešitelů x všech problémů?
 
-@dataclass
-class SouhrnReseni:
-	"""Dataclass reprezentující data o odevzdaných řešeních pro zobrazení v tabulce."""
-	pocet_reseni : int
-	posledni_odevzdani : datetime.datetime
-	body : float
-
-
 class TabulkaOdevzdanychReseniView(ListView):
 	template_name = 'odevzdavatko/tabulka.html'
 	model = m.Hodnoceni
@@ -70,6 +63,7 @@ class TabulkaOdevzdanychReseniView(ListView):
 			reseni_od = fcd["reseni_od"]
 			reseni_do = fcd["reseni_do"]
 			jen_neobodovane = fcd["neobodovane"]
+			self.barvicky = fcd["barvicky"]
 		else:
 			initial = FiltrForm.gen_initial(self.aktualni_rocnik)
 			resitele = initial['resitele']
@@ -77,6 +71,7 @@ class TabulkaOdevzdanychReseniView(ListView):
 			reseni_od = initial['reseni_od'][0]
 			reseni_do = initial['reseni_do'][0]
 			jen_neobodovane = initial["neobodovane"]
+			self.barvicky = initial["barvicky"]
 			
 
 		# Chceme jen letošní problémy
@@ -120,42 +115,45 @@ class TabulkaOdevzdanychReseniView(ListView):
 		return qs
 
 	def get_context_data(self, *args, **kwargs):
+		# TODO: refactor asi. Přepisoval jsem to jen syntakticky, nejspíš půlka kódu přestala dávat smysl…
 		# self.resitele, self.reseni a self.problemy jsou již nastavené
 
 		ctx = super().get_context_data(*args, **kwargs)
 		ctx['problemy'] = self.problemy
 		ctx['resitele'] = self.resitele
-		tabulka = dict()
+		tabulka: dict[m.Problem, dict[m.Resitel, list[tuple[m.Reseni, m.Hodnoceni]]]] = dict()
+		soucty: dict[m.Problem, dict[m.Resitel, Decimal]] = dict()
 
-		def pridej_reseni(problem, resitel, body, cas):
+		def pridej_reseni(resitel, hodnoceni):
+			problem = hodnoceni.problem
+			body = hodnoceni.body
+			cas = hodnoceni.reseni.cas_doruceni
+			reseni = hodnoceni.reseni
 			if problem not in tabulka:
 				tabulka[problem] = dict()
+				soucty[problem] = dict()
 			if resitel not in tabulka[problem]:
-				tabulka[problem][resitel] = SouhrnReseni(pocet_reseni=1, posledni_odevzdani=cas, body=body)
+				tabulka[problem][resitel] = [(reseni, hodnoceni)]
+				soucty[problem][resitel] = hodnoceni.body or 0 # Neobodované neřešíme
 			else:
-				tabulka[problem][resitel].posledni_odevzdani = max(tabulka[problem][resitel].posledni_odevzdani, cas)
-				# Zvětšení počtu bodů o aktuální počet, pokud se tam někde nevyskytuje None – pak je součet taky None ("Pozor, nezadané body")
-				tabulka[problem][resitel].body = tabulka[problem][resitel].body + body if body is not None and tabulka[problem][resitel].body is not None else None
-				tabulka[problem][resitel].pocet_reseni += 1
-			# Pro jednoduchost template si ještě poznamenáme ID problému a řešitele
-			tabulka[problem][resitel].problem_id = problem.id
-			tabulka[problem][resitel].resitel_id = resitel.id
+				tabulka[problem][resitel].append((reseni, hodnoceni))
+				soucty[problem][resitel] += hodnoceni.body or 0 # Neobodované neřešíme
 		
 		for hodnoceni in self.get_queryset():
 			for resitel in hodnoceni.reseni.resitele.all():
-				pridej_reseni(hodnoceni.problem, resitel, hodnoceni.body, hodnoceni.reseni.cas_doruceni)
+				pridej_reseni(resitel, hodnoceni)
 
-		hodnoty = []
-		resitele_do_tabulky = []
+		hodnoty: list[list[tuple[Decimal,list[tuple[m.Reseni, m.Hodnoceni]]]]] = [] # Seznam řádků výsledné tabulky podle self.resitele, v každém řádku buňky v pořadí podle self.problemy + jejich součty, v každé buňce seznam řešení k danému řešiteli a problému.
+		resitele_do_tabulky: list[m.Resitel] = []
 		for resitel in self.resitele:
 			dostal_body = False
-			resiteluv_radek = []
+			resiteluv_radek: list[tuple[Decimal,list[tuple[m.Reseni, m.Hodnoceni]]]] = [] # podle pořadí v self.problemy
 			for problem in self.problemy:
 				if problem in tabulka and resitel in tabulka[problem]:
-					resiteluv_radek.append(tabulka[problem][resitel])
+					resiteluv_radek.append((soucty[problem][resitel], tabulka[problem][resitel]))
 					dostal_body = True
 				else:
-					resiteluv_radek.append(None)
+					resiteluv_radek.append((Decimal(0),[]))
 			if self.chteni_resitele != FiltrForm.RESITELE_RELEVANTNI or dostal_body:
 				hodnoty.append(resiteluv_radek)
 				resitele_do_tabulky.append(resitel)
@@ -165,6 +163,7 @@ class TabulkaOdevzdanychReseniView(ListView):
 		ctx['form'] = ctx['filtr']
 		# Pro maximum v přesměrovátku ročníků
 		ctx['aktualni_rocnik'] = m.Nastaveni.get_solo().aktualni_rocnik
+		ctx['barvicky'] = self.barvicky
 		if 'rocnik' in self.kwargs:
 			ctx['rocnik'] = self.kwargs['rocnik']
 		else:
@@ -174,6 +173,11 @@ class TabulkaOdevzdanychReseniView(ListView):
 
 # Velmi silně inspirováno zdrojáky, FIXME: Nedá se to udělat smysluplněji?
 class ReseniProblemuView(MultipleObjectTemplateResponseMixin, MultipleObjectMixin, View):
+	"""Rozskok mezi více řešeními téhož problému od téhož řešitele.
+	
+	Asi už bude zastaralý v okamžiku, kdy se tenhle komentář nasadí na produkci :-)
+
+	V případě, že takové řešení existuje jen jedno, tak na něj přesměruje."""
 	model = m.Reseni
 	template_name = 'odevzdavatko/seznam.html'
 	
@@ -316,7 +320,8 @@ def hodnoceniReseniView(request, pk, *args, **kwargs):
 			if len(zmeny_bodu) == 1:
 				hodnoceni.__setattr__(zmeny_bodu[0], data_for_body[zmeny_bodu[0]])
 			# > jedna změna je špatně, ale 4 "změny" znamenají že nebylo nic zadáno
-			if len(zmeny_bodu) > 1 and len(zmeny_bodu) != 4:
+			if len(zmeny_bodu) > 1 and len(zmeny_bodu) != 4 and len(zmeny_bodu) != 2:
+				# 4 znamená vše už vyplněno a nic nezměněno, 2 znamená předvyplnili se součty a nic se nezměnilo
 				logger.warning(f"Hodnocení {hodnoceni} mělo mít nastavené víc různých bodů: {zmeny_bodu}. Nastavuji -0.1.")
 				hodnoceni.body = -0.1
 			hodnoceni.save()
@@ -367,8 +372,8 @@ class SeznamAktualnichReseniView(SeznamReseniView):
 		return qs
 
 
-class PosliReseniView(LoginRequiredMixin, FormView):
-	template_name = 'odevzdavatko/posli_reseni.html'
+class VlozReseniView(LoginRequiredMixin, FormView):
+	template_name = 'odevzdavatko/vloz_reseni.html'
 	form_class = f.PosliReseniForm
 
 	def form_valid(self, form):
@@ -399,12 +404,31 @@ class PosliReseniView(LoginRequiredMixin, FormView):
 		return data
 
 
+class NahrajReseniRozcestnikTematekView(LoginRequiredMixin, ListView):
+	model = m.Problem
+	template_name = 'odevzdavatko/nahraj_reseni_nadproblem.html'
+
+	def get_queryset(self):
+		return super().get_queryset().filter(stav=m.Problem.STAV_ZADANY, nadproblem__isnull=True)
+
+
 class NahrajReseniView(LoginRequiredMixin, CreateView):
 	model = m.Reseni
 	template_name = 'odevzdavatko/nahraj_reseni.html'
 	form_class = f.NahrajReseniForm
+	nadproblem: m.Problem
+
+	def setup(self, request, *args, **kwargs):
+		super().setup(request, *args, **kwargs)
+		nadproblem_id = self.kwargs["nadproblem_id"]
+		self.nadproblem = get_object_or_404(m.Problem, id=nadproblem_id)
 
 	def get(self, request, *args, **kwargs):
+		# Zaříznutí nezadaných problémů
+		if self.nadproblem.stav != m.Problem.STAV_ZADANY:
+			raise PermissionDenied()
+
+
 		# Zaříznutí starých řešitelů:
 		# FIXME: Je to tady dost naprasené, mělo by to asi být jinde…
 		osoba = m.Osoba.objects.get(user=self.request.user)
@@ -417,12 +441,23 @@ class NahrajReseniView(LoginRequiredMixin, CreateView):
 			})
 		return super().get(request, *args, **kwargs)
 
+	def get_initial(self):
+		nadproblem_id = self.nadproblem.id
+		return {
+			"nadproblem_id": nadproblem_id,
+			"problem": [] if self.nadproblem.podproblem.filter(stav=m.Problem.STAV_ZADANY).exists() else nadproblem_id
+
+		}
+
 	def get_context_data(self,**kwargs):
 		data = super().get_context_data(**kwargs)
 		if self.request.POST:
 			data['prilohy'] = f.ReseniSPrilohamiFormSet(self.request.POST,self.request.FILES)
 		else:
 			data['prilohy'] = f.ReseniSPrilohamiFormSet()
+
+		data["nadproblem_id"] = self.nadproblem.id
+		data["nadproblem"] = get_object_or_404(m.Problem, id=self.nadproblem.id)
 		return data
 
 	# FIXME prepsat tak, aby form_valid se volalo jen tehdy, kdyz je form i formset validni
@@ -474,4 +509,8 @@ class NahrajReseniView(LoginRequiredMixin, CreateView):
 			to=list(prijemci),
 		).send()
 
-		return formularOKView(self.request, text='Řešení úspěšně odevzdáno')
+		return formularOKView(
+			self.request,
+			text='Řešení úspěšně odevzdáno',
+			dalsi_odkazy=[("Odevzdat další řešení", reverse("seminar_nahraj_reseni"))],
+		)
diff --git a/personalni/admin.py b/personalni/admin.py
index fc3cadd4..14af2c2c 100644
--- a/personalni/admin.py
+++ b/personalni/admin.py
@@ -1,7 +1,9 @@
 from django.contrib import admin
 from django.contrib.auth.models import Group
 from django_reverse_admin import ReverseModelAdmin
+from django.contrib.messages import WARNING, ERROR, SUCCESS
 import seminar.models as m
+from datetime import datetime
 
 
 @admin.register(m.Osoba)
@@ -20,16 +22,24 @@ class OsobaAdmin(admin.ModelAdmin):
 
 	def udelej_orgem(self,request,queryset):
 		org_group = Group.objects.get(name='org')
-		print(queryset)
+		uspesne_vytvoreni_orgove = 0
 		for o in queryset:
+			if m.Organizator.objects.filter(osoba=o).exists():
+				# Ref: https://docs.djangoproject.com/en/3.2/ref/contrib/admin/#django.contrib.admin.ModelAdmin.message_user
+				self.message_user(request, f"Osoba {o} už je org, přeskakuji.", level=WARNING)
+				continue
 			user = o.user
-			print(user)
+			if user is None:
+				self.message_user(request, f"Osoba {o} nemá uživatele! Přeskakuji.", level=ERROR)
+				continue
 			user.groups.add(org_group)
 			user.is_staff = True
 			user.save()
-			org = m.Organizator.objects.create(osoba=o)
+			org = m.Organizator.objects.create(osoba=o, organizuje_od=datetime.now())
 			org.save()
-	udelej_orgem.short_description = "Udělej vybraných osob organizátory"
+			uspesne_vytvoreni_orgove += 1
+		self.message_user(request, f'Úspěšně vytvořeno {uspesne_vytvoreni_orgove} orgů.', level=SUCCESS)
+	udelej_orgem.short_description = "Udělej z vybraných osob organizátory"
 
 class OsobaInline(admin.TabularInline):
 	model = m.Osoba
diff --git a/personalni/templates/personalni/profil/resitel.html b/personalni/templates/personalni/profil/resitel.html
index 9c933f0a..0bd92d63 100644
--- a/personalni/templates/personalni/profil/resitel.html
+++ b/personalni/templates/personalni/profil/resitel.html
@@ -11,7 +11,7 @@
 
 <a href="{% url 'logout' %}">Odhlásit se</a><br>
 <a href="{% url 'seminar_resitel_edit' %}">Upravit údaje</a><br>
-<a href="{% url 'seminar_nahraj_reseni' %}">Poslat řešení</a><br>
+<a href="{% url 'seminar_nahraj_reseni' %}">Nahrát řešení</a><br>
 <a href="{% url 'seminar_resitel_odevzdana_reseni' %}">Již odevzdaná řešení</a><br>
 
 
diff --git a/personalni/tests.py b/personalni/tests.py
new file mode 100644
index 00000000..31aac8e8
--- /dev/null
+++ b/personalni/tests.py
@@ -0,0 +1,63 @@
+from django.test import TestCase, RequestFactory
+
+from django.contrib.auth.models import User, Group
+from django.contrib.admin.sites import AdminSite
+from personalni.admin import OsobaAdmin
+# Tohle bude peklo, až jednou ty modely fakt rozstřelíme… Možná vyrobit various.all_models, které půjdou importovat jako m? :-)
+import seminar.models as m
+
+import logging
+logger = logging.getLogger(__name__)
+
+class DelaniOrguTest(TestCase):
+	def setUp(self):
+		# Admin musí mít instanci
+		# Ref: https://www.argpar.se/posts/programming/testing-django-admin/
+		adm_site = AdminSite()
+		self.admin = OsobaAdmin(m.Osoba, adm_site)
+
+		from django.contrib.messages.storage.cookie import CookieStorage
+		self.request = RequestFactory().get('/admin')
+		self.request._messages = CookieStorage(self.request)
+
+		self.org_group = Group.objects.get(name='org')
+
+		novy_user = User.objects.create(username='osoba')
+		self.nova_osoba = m.Osoba.objects.create(
+			jmeno='Milada',
+			prijmeni='Von Kolej',
+			user = novy_user,
+			# Snad nic dalšího nepotřebujeme, kdyžtak se doplní…
+			)
+		stary_user = User.objects.create(username='stary_user')
+		stara_osoba = m.Osoba.objects.create(user=stary_user)
+		self.stary_org = m.Organizator.objects.create(osoba=stara_osoba)
+
+	def test_pridani_orga(self):
+		# Nejdřív to není org…
+		self.assertFalse(m.Organizator.objects.filter(osoba=self.nova_osoba).exists())
+		self.assertNotIn(self.org_group, self.nova_osoba.user.groups.all())
+		self.assertFalse(self.nova_osoba.user.has_perm('auth.org'))
+		self.assertFalse(self.nova_osoba.user.is_staff)
+
+		# Pak orga uděláme…
+		qs = m.Osoba.objects.filter(id=self.nova_osoba.id)
+		self.admin.udelej_orgem(self.request, qs)
+
+		# A pak už to org má být.
+		self.nova_osoba.refresh_from_db()
+		self.assertTrue(self.nova_osoba.user.is_staff)
+		# FIXME: V db nejsou práva. Nový org je sice ve skupině "org", ale ta nemá právo "auth.org"
+		# Očekávané řešení: dodat fixture, která to přidá.
+		#self.assertTrue(self.nova_osoba.user.has_perm('auth.org'))
+		self.assertIn(self.org_group, self.nova_osoba.user.groups.all())
+		self.assertTrue(m.Organizator.objects.filter(osoba=self.nova_osoba).exists())
+		novy_org = m.Organizator.objects.get(osoba=self.nova_osoba)
+		self.assertIsNotNone(novy_org.organizuje_od)
+
+	def test_pridani_stareho_orga(self):
+		self.admin.udelej_orgem(self.request, m.Osoba.objects.filter(id=self.stary_org.osoba.id)) # Ugly
+		# Když to spadne, tak jsem se to dozvěděl, takže už nepotřebuju nic kontrolovat.
+		# Jestli to funguje správně má řešit jiný test.
+
+
diff --git a/personalni/views.py b/personalni/views.py
index a45aee52..876cc7ec 100644
--- a/personalni/views.py
+++ b/personalni/views.py
@@ -173,7 +173,11 @@ def resitelEditView(request):
 					msg = "Unknown school {}, {}".format(fcd['skola_nazev'],fcd['skola_adresa'])
 				resitel_edit.save()
 			osoba_edit.save()
-			return formularOKView(request, text=f'Údaje byly úspěšně uloženy. <a href="{reverse("profil")}">Vrátit se zpět na profil.</a>')
+			return formularOKView(
+				request,
+				text='Údaje byly úspěšně uloženy.',
+				dalsi_odkazy=[("Vrátit se zpět na profil", reverse("profil"))],
+			)
 
 	return render(request, 'personalni/udaje/edit.html', {'form': form})
 
diff --git a/requirements.txt b/requirements.txt
index 8a6a46e9..d51645de 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -5,6 +5,7 @@ psycopg2
 html5lib
 ipython
 Pillow
+pilkit>=3.0 # Kvůli kompatibilitě s Pillow>=10.0.0
 pytz
 six
 pexpect
@@ -24,7 +25,7 @@ django-ckeditor
 django-cleanup  # Uklízí media/ od smazaných „databázových“ souborů
 django-flat-theme
 django-taggit
-django-autocomplete-light>=3.9.0rc1
+django-autocomplete-light>=3.9.0
 django-crispy-forms
 django-imagekit
 django-polymorphic
@@ -52,9 +53,6 @@ Werkzeug
 requests
 # requests-oauthlib
 
-# uWSGI
-uWSGI
-
 # Potřeba pro test data
 
 lorem
diff --git a/seminar/admin.py b/seminar/admin.py
index e88af140..8f589a03 100644
--- a/seminar/admin.py
+++ b/seminar/admin.py
@@ -12,15 +12,25 @@ from django.utils.safestring import mark_safe
 import seminar.models as m
 
 admin.site.register(m.Rocnik)
-
-admin.site.register(m.Deadline)
 admin.site.register(m.ZmrazenaVysledkovka)
 
+@admin.register(m.Deadline)
+class DeadlineAdmin(admin.ModelAdmin):
+	actions = ['pregeneruj_vysledkovku']
 
+	# Nikomu nezobrazovat, ale superuživatelům se může hodit :-)
+	@admin.action(permissions=['bazmek'], description= 'Přegeneruj výsledkovky vybraných deadlinů')
+	def pregeneruj_vysledkovku(self, req, qs):
+		for deadline in qs:
+			deadline.vygeneruj_vysledkovku()
+	
+	def has_bazmek_permission(self, request):
+		# Boilerplate: potřebujeme nějakou permission, protože nějaká haluz v Djangu…
+		return request.user.is_superuser
+	
 class DeadlineAdminInline(admin.TabularInline):
-    model = m.Deadline
-    extra = 0
-
+	model = m.Deadline
+	extra = 0
 
 class CisloForm(ModelForm):
 	class Meta:
@@ -71,7 +81,7 @@ class CisloForm(ModelForm):
 @admin.register(m.Cislo)
 class CisloAdmin(admin.ModelAdmin):
 	form = CisloForm
-	actions = ['force_publish']
+	actions = ['force_publish', 'pregeneruj_vysledkovky']
 	inlines = (DeadlineAdminInline,)
 
 	def force_publish(self,request,queryset):
@@ -111,6 +121,17 @@ class CisloAdmin(admin.ModelAdmin):
 
 	force_publish.short_description = 'Zveřejnit vybraná čísla a všechny návrhy úloh v nich učinit zadanými'
 
+	# Jen pro superuživatele
+	@admin.action(permissions=['bazmek'], description='Přegenerovat výsledkovky všech deadlinů vybraných čísel')
+	def pregeneruj_vysledkovky(self, req, qs):
+		for cislo in qs:
+			for deadline in cislo.deadline_v_cisle.all():
+				deadline.vygeneruj_vysledkovku()
+	
+	def has_bazmek_permission(self, request):
+		# Boilerplate: potřebujeme nějakou permission, protože nějaká haluz v Djangu…
+		return request.user.is_superuser
+
 
 @admin.register(m.Problem)
 class ProblemAdmin(PolymorphicParentModelAdmin):
diff --git a/seminar/models/tvorba.py b/seminar/models/tvorba.py
index 54e769c8..1c1a3285 100644
--- a/seminar/models/tvorba.py
+++ b/seminar/models/tvorba.py
@@ -491,7 +491,7 @@ class Problem(SeminarModelBase,PolymorphicModel):
 				return self.nadproblem.kod_v_rocniku+".{}".format(self.kod)
 			return str(self.kod)
 		logger.warning(f"K problému {self} byl vyžadován kód v ročníku, i když není zadaný ani vyřešený.")
-		return '<Není zadaný>'
+		return f'<Není zadaný: {self.kod}>'
 
 #	def verejne(self):
 #		# aktuálně podle stavu problému
@@ -571,9 +571,9 @@ class Tema(Problem):
 		if self.stav == Problem.STAV_ZADANY or self.stav == Problem.STAV_VYRESENY:
 			if self.nadproblem:
 				return self.nadproblem.kod_v_rocniku+".t{}".format(self.kod)
-			return "t{}".format(self.kod)
+			return 't'+self.kod
 		logger.warning(f"K problému {self} byl vyžadován kód v ročníku, i když není zadaný ani vyřešený.")
-		return '<Není zadaný>'
+		return f'<Není zadaný: {self.kod}>'
 
 	def save(self, *args, **kwargs):
 		super().save(*args, **kwargs)
@@ -607,9 +607,9 @@ class Clanek(Problem):
 # Nemělo by být potřeba
 #			if self.nadproblem:
 #				return self.nadproblem.kod_v_rocniku+".c{}".format(self.kod)
-			return "c{}".format(self.kod)
+			return "c" + self.kod
 		logger.warning(f"K problému {self} byl vyžadován kód v ročníku, i když není zadaný ani vyřešený.")
-		return '<Není zadaný>'
+		return f'<Není zadaný: {self.kod}>'
 	
 	def node(self):
 		return None
@@ -642,12 +642,9 @@ class Uloha(Problem):
 	@cached_property
 	def kod_v_rocniku(self):
 		if self.stav == Problem.STAV_ZADANY or self.stav == Problem.STAV_VYRESENY:
-			name="{}.u{}".format(self.cislo_zadani.poradi,self.kod)
-			if self.nadproblem:
-				return self.nadproblem.kod_v_rocniku+name
-			return name
+			return f"{self.cislo_zadani.poradi}.{self.kod}"
 		logger.warning(f"K problému {self} byl vyžadován kód v ročníku, i když není zadaný ani vyřešený.")
-		return '<Není zadaný>'
+		return f'<Není zadaný: {self.kod}>'
 
 	def save(self, *args, **kwargs):
 		super().save(*args, **kwargs)
diff --git a/seminar/views/views_all.py b/seminar/views/views_all.py
index 4627989e..8e71fed3 100644
--- a/seminar/views/views_all.py
+++ b/seminar/views/views_all.py
@@ -35,6 +35,7 @@ from django.conf import settings
 import unicodedata
 import logging
 import time
+from collections.abc import Sequence
 
 from seminar.utils import aktivniResitele
 
@@ -534,7 +535,9 @@ class PosledniCisloVysledkovkaView(generic.DetailView):
 	def get_context_data(self, **kwargs):
 		context = super(PosledniCisloVysledkovkaView, self).get_context_data()
 		rocnik = context['rocnik']
-		cislo = rocnik.cisla.order_by("poradi").last()
+		cislo = rocnik.cisla.order_by("poradi").filter(deadline_v_cisle__isnull=False).last()
+		if cislo is None:
+			raise Http404(f"Ročník {rocnik.rocnik} nemá číslo s deadlinem.")
 		cislopred = cislo.predchozi()
 		context['vysledkovka'] = VysledkovkaDoTeXu(
 			cislo,
@@ -677,9 +680,9 @@ def StavDatabazeView(request):
 
 
 # Interní, nemá se nikdy objevit v urls (jinak to účastníci vytrolí)
-def formularOKView(request, text=''):
+def formularOKView(request, text='', dalsi_odkazy: Sequence[tuple[str, str]] = ()):
 	template_name = 'seminar/formular_ok.html'
-	odkazy = [
+	odkazy = list(dalsi_odkazy) + [
 		# (Text, odkaz)
 		('Vrátit se na titulní stránku', reverse('titulni_strana')),
 		('Zobrazit aktuální zadání', reverse('seminar_aktualni_zadani')),
diff --git a/sifrovacka/__init__.py b/sifrovacka/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/sifrovacka/admin.py b/sifrovacka/admin.py
new file mode 100644
index 00000000..71d191d4
--- /dev/null
+++ b/sifrovacka/admin.py
@@ -0,0 +1,8 @@
+from django.contrib import admin
+
+from .models import OdpovedUcastnika, SpravnaOdpoved
+
+# Register your models here.
+
+admin.site.register(OdpovedUcastnika)
+admin.site.register(SpravnaOdpoved)
diff --git a/sifrovacka/apps.py b/sifrovacka/apps.py
new file mode 100644
index 00000000..e9f34de6
--- /dev/null
+++ b/sifrovacka/apps.py
@@ -0,0 +1,5 @@
+from django.apps import AppConfig
+
+
+class SifrovackaConfig(AppConfig):
+    name = 'sifrovacka'
diff --git a/sifrovacka/forms.py b/sifrovacka/forms.py
new file mode 100644
index 00000000..e3eba7c7
--- /dev/null
+++ b/sifrovacka/forms.py
@@ -0,0 +1,18 @@
+from django.core.exceptions import ValidationError
+from django.forms import ModelForm, Textarea
+from .models import OdpovedUcastnika, SpravnaOdpoved
+
+
+class SifrovackaForm(ModelForm):
+	class Meta:
+		model = OdpovedUcastnika
+		fields = ["sifra", "odpoved", ]
+		widgets = {
+			"odpoved": Textarea(attrs={'rows': 1, 'cols': 30}),
+		}
+
+	def clean_sifra(self):
+		sifra = self.cleaned_data.get('sifra')
+		if SpravnaOdpoved.objects.filter(sifra=sifra).count() == 0:
+			raise ValidationError("Tohle číslo šifry v databázi nemáme. Zkontrolujte si ho prosím.")
+		return sifra
diff --git a/sifrovacka/migrations/0001_initial.py b/sifrovacka/migrations/0001_initial.py
new file mode 100644
index 00000000..742461ef
--- /dev/null
+++ b/sifrovacka/migrations/0001_initial.py
@@ -0,0 +1,34 @@
+# Generated by Django 3.2.22 on 2023-10-14 09:20
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    initial = True
+
+    dependencies = [
+        ('seminar', '0113_resitel_zasilat_cislo_papirove'),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='SpravnaOdpoved',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('odpoved', models.TextField()),
+                ('sifra', models.IntegerField()),
+                ('skryty_text', models.TextField()),
+            ],
+        ),
+        migrations.CreateModel(
+            name='OdpovedUcastnika',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('odpoved', models.TextField(verbose_name='Tajenka')),
+                ('sifra', models.IntegerField(verbose_name='Číslo šifry')),
+                ('resitel', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='seminar.resitel')),
+            ],
+        ),
+    ]
diff --git a/sifrovacka/migrations/0002_auto_20231015_1944.py b/sifrovacka/migrations/0002_auto_20231015_1944.py
new file mode 100644
index 00000000..dea42891
--- /dev/null
+++ b/sifrovacka/migrations/0002_auto_20231015_1944.py
@@ -0,0 +1,28 @@
+# Generated by Django 3.2.22 on 2023-10-15 17:44
+
+from django.db import migrations, models
+import django.utils.timezone
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('sifrovacka', '0001_initial'),
+    ]
+
+    operations = [
+        migrations.AlterModelOptions(
+            name='odpoveducastnika',
+            options={'ordering': ['-timestamp']},
+        ),
+        migrations.AddField(
+            model_name='odpoveducastnika',
+            name='timestamp',
+            field=models.DateTimeField(default=django.utils.timezone.now, verbose_name='Timestamp'),
+        ),
+        migrations.AlterField(
+            model_name='odpoveducastnika',
+            name='odpoved',
+            field=models.TextField(verbose_name='Tajenka bez diakritiky'),
+        ),
+    ]
diff --git a/sifrovacka/migrations/0003_odpoveducastnika_uspech.py b/sifrovacka/migrations/0003_odpoveducastnika_uspech.py
new file mode 100644
index 00000000..1d61dd8c
--- /dev/null
+++ b/sifrovacka/migrations/0003_odpoveducastnika_uspech.py
@@ -0,0 +1,18 @@
+# Generated by Django 3.2.22 on 2023-10-16 17:51
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('sifrovacka', '0002_auto_20231015_1944'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='odpoveducastnika',
+            name='uspech',
+            field=models.BooleanField(default=False, verbose_name='Úspěch'),
+        ),
+    ]
diff --git a/sifrovacka/migrations/__init__.py b/sifrovacka/migrations/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/sifrovacka/models.py b/sifrovacka/models.py
new file mode 100644
index 00000000..6517c2e0
--- /dev/null
+++ b/sifrovacka/models.py
@@ -0,0 +1,27 @@
+from django.db import models
+from django.utils import timezone
+
+from seminar.models.personalni import Resitel
+
+
+# Create your models here.
+
+
+class OdpovedUcastnika(models.Model):
+	class Meta:
+		ordering = ["-timestamp"]
+
+	resitel = models.ForeignKey(Resitel, blank=False, null=False, on_delete=models.CASCADE)
+	odpoved = models.TextField("Tajenka bez diakritiky", blank=False, null=False,)
+	sifra = models.IntegerField("Číslo šifry", blank=False, null=False,)
+	timestamp = models.DateTimeField("Timestamp", blank=False, null=False, default=timezone.now)
+	uspech = models.BooleanField("Úspěch", blank=False, null=False, default=False)
+
+
+class SpravnaOdpoved(models.Model):
+	odpoved = models.TextField(blank=False, null=False,)
+	sifra = models.IntegerField(blank=False, null=False,)
+	skryty_text = models.TextField(blank=False, null=False,)
+
+	def __str__(self):
+		return f"{self.sifra}: {self.odpoved}"
diff --git a/sifrovacka/templates/sifrovacka/odpovedi_list.html b/sifrovacka/templates/sifrovacka/odpovedi_list.html
new file mode 100644
index 00000000..0024a7c1
--- /dev/null
+++ b/sifrovacka/templates/sifrovacka/odpovedi_list.html
@@ -0,0 +1,25 @@
+{% extends "base.html" %}
+
+{% block content %}
+
+  <h1>{% block nadpis1a %}Šifrovačka odpovědi{% endblock nadpis1a %}</h1>
+
+  <table class="dosla_reseni">
+    <tr>
+      <th>Timestamp</th>
+      <th>Řešitel</th>
+      <th>Šifra</th>
+      <th>Odpověď</th>
+    </tr>
+
+    {% for u in object_list %}
+      <tr>
+        <td>{{ u.timestamp }}</td>
+        <td>{{ u.resitel }}</td>
+        <td>{{ u.sifra }}</td>
+        <td style="color: {% if u.uspech %}green{% else %}red{% endif %};">{{ u.odpoved }}</td>
+      </tr>
+    {% endfor %}
+  </table>
+
+{% endblock content %}
diff --git a/sifrovacka/templates/sifrovacka/sifrovacka.html b/sifrovacka/templates/sifrovacka/sifrovacka.html
new file mode 100644
index 00000000..4e0cc15a
--- /dev/null
+++ b/sifrovacka/templates/sifrovacka/sifrovacka.html
@@ -0,0 +1,46 @@
+{% extends "base.html" %}
+
+{% block content %}
+
+  <br>
+
+  <h1>{% block nadpis1a %}M&Mí šifrovačka{% endblock nadpis1a %}</h1>
+
+  <br>
+
+  <h2>Zadat tajenku šifry:</h2>
+
+  <form action="{% url 'sifrovacka' %}" method="post">
+    <table class="form">
+      {{form.non_field_errors}}
+      {% for field in form %}
+        <tr>
+          <td>
+            <label class="field-label{% if field.field.required %} field-required{% endif %}" for="{{ field.id_for_label }}">
+              {{ field.label }}
+            </label>
+
+          </td>
+
+          <td {% if field.help_text %} class="field-with-comment"{% endif %}>
+            {{ field }}
+            <span class="field-comment">{{ field.help_text|safe }}</span>
+          </td>
+
+        </tr>
+
+
+        {% if field.errors %}
+          <tr>
+            <td colspan="2"><span class="field-error">{{ field.errors }}</span></td>
+          </tr>
+        {% endif %}
+      {% endfor %}
+    </table>
+
+    {% csrf_token %}
+
+    <input type="submit" value="Tak pravím!">
+  </form>
+
+{% endblock content %}
diff --git a/sifrovacka/urls.py b/sifrovacka/urls.py
new file mode 100644
index 00000000..a7af5e54
--- /dev/null
+++ b/sifrovacka/urls.py
@@ -0,0 +1,17 @@
+from django.urls import path
+
+from seminar.utils import org_required, resitel_or_org_required
+from .views import SifrovackaView, SifrovackaListView
+
+urlpatterns = [
+	path(
+		'',
+		resitel_or_org_required(SifrovackaView.as_view()),
+		name='sifrovacka'
+	),
+	path(
+		'odpovedi/',
+		org_required(SifrovackaListView.as_view()),
+		name='sifrovacka_odpovedi'
+	),
+]
diff --git a/sifrovacka/views.py b/sifrovacka/views.py
new file mode 100644
index 00000000..9c4af3ed
--- /dev/null
+++ b/sifrovacka/views.py
@@ -0,0 +1,33 @@
+from django.urls import reverse
+from django.views.generic import FormView, ListView
+
+from seminar.views import formularOKView
+from .forms import SifrovackaForm
+from .models import OdpovedUcastnika, SpravnaOdpoved
+from seminar.models.personalni import Resitel
+
+
+# Create your views here.
+
+class SifrovackaView(FormView):
+	template_name = 'sifrovacka/sifrovacka.html'
+	form_class = SifrovackaForm
+
+	def form_valid(self, form):
+		instance = form.save(commit=False)
+		resitel = Resitel.objects.get(osoba__user=self.request.user)
+		instance.resitel = resitel
+		instance.save()
+		sifra = SpravnaOdpoved.objects.filter(sifra=instance.sifra, odpoved__iexact=instance.odpoved.strip()).first()
+		if sifra is None:
+			return formularOKView(self.request, f'<h1>Bohužel vám hvězdy nebyly nakloněny. Rozumějte <i>máte to blbě</i>.</h1> <p><a href="{reverse("sifrovacka")}">Zkusit znovu.</a></p><br><br><br>')
+
+		instance.uspech = True
+		instance.save()
+		
+		return formularOKView(self.request, f'<h1>{sifra.skryty_text}</h1> <p><a href="{reverse("sifrovacka")}">Odevzdat další.</a></p><br><br><br>')
+
+
+class SifrovackaListView(ListView):
+	template_name = 'sifrovacka/odpovedi_list.html'
+	model = OdpovedUcastnika
diff --git a/various/static/various/img/zere_kostku.svg b/various/static/various/img/zere_kostku.svg
new file mode 100644
index 00000000..bac31662
--- /dev/null
+++ b/various/static/various/img/zere_kostku.svg
@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   version="1.1"
+   id="svg1"
+   width="624"
+   height="550.66669"
+   viewBox="0 0 624 550.66669"
+   sodipodi:docname="zere-kostku.svg"
+   inkscape:version="1.3 (0e150ed6c4, 2023-07-21)"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:svg="http://www.w3.org/2000/svg">
+  <defs
+     id="defs1" />
+  <sodipodi:namedview
+     id="namedview1"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:showpageshadow="2"
+     inkscape:pageopacity="0.0"
+     inkscape:pagecheckerboard="0"
+     inkscape:deskcolor="#d1d1d1"
+     showgrid="false"
+     inkscape:zoom="0.88942308"
+     inkscape:cx="312"
+     inkscape:cy="275.45946"
+     inkscape:window-width="1280"
+     inkscape:window-height="730"
+     inkscape:window-x="-6"
+     inkscape:window-y="-6"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="g1">
+    <inkscape:page
+       x="0"
+       y="0"
+       inkscape:label="1"
+       id="page1"
+       width="624"
+       height="550.66669"
+       margin="0"
+       bleed="0" />
+  </sodipodi:namedview>
+  <g
+     id="g1"
+     inkscape:groupmode="layer"
+     inkscape:label="1">
+    <path
+       id="path1"
+       d="m 1544.13,3717.76 c -27.5,-17.2 -52.75,-33.58 -55.79,-36.19 -3.09,-2.64 -11.9,-8.87 -19.84,-14.01 -7.89,-5.11 -25.15,-23.79 -38.6,-41.77 -13.45,-17.99 -27.63,-34.42 -31.73,-36.75 -4.23,-2.42 -7.4,-7.18 -7.4,-11.11 0,-3.76 -8.03,-22.21 -17.72,-40.72 -9.68,-18.51 -23.46,-48.22 -30.4,-65.57 -20.1,-50.24 -41.98,-78.55 -63.46,-82.1 -37.01,-6.11 -109.99,-66.72 -122.09,-101.4 -3.14,-8.99 -8.31,-14.24 -12.49,-12.69 -3.95,1.46 -16.13,4.18 -27.23,6.08 -11.06,1.89 -48.65,10.1 -83.56,18.24 -34.898,8.15 -77.019,17.56 -93.597,20.91 -40.504,8.2 -74.258,31.45 -121.684,83.8 -21.559,23.79 -33.57,24.77 -39.031,3.17 -3.172,-12.54 -2.004,-23.79 7.613,-73.5 17.828,-92.17 28.152,-271.81 26.281,-457.42 -1.632,-161.82 -1.324,-167.83 10.746,-210.47 11.832,-41.78 11.985,-44.38 3.176,-53.94 -5.09,-5.52 -14.015,-11.57 -19.832,-13.43 -22.008,-7.03 -128.941,-84.4 -159.054,-115.07 -43.856,-44.66 -51.438,-65.04 -54.895,-147.54 -1.574,-37.54 -4.883,-69.4 -7.355,-70.86 -2.368,-1.39 -4.497,-7.4 -4.497,-12.69 0,-15.77 -24.324,-57.01 -42.836,-72.62 -20.093,-16.95 -61.21,-43.72 -67.156,-43.72 -7.062,0 -47.511,-41.25 -64.301,-65.57 -30.664,-44.42 -56.015,-115.81 -60.843,-171.34 -1.84,-21.15 -7.016,-51.03 -11.453,-66.1 -9.059,-30.76 -55.524,-121.62 -85.18,-166.57 -10.902,-16.52 -35.895,-62.4 -55.313,-101.53 -48.543,-97.83 -63.484,-167.39 -51.796,-241.14 3.183,-20.09 9.109,-41.48 13.187,-47.59 4.055,-6.09 8.723,-31.2 10.32,-55.53 3.477,-52.88 7.207,-72.38 16.586,-86.72 13.184,-20.16 32.856,-79.32 43.961,-132.21 17.883,-85.133 80.301,-227.274 113.688,-258.891 3.199,-3.031 12.836,-15.027 21.414,-26.66 8.582,-11.637 17.031,-22.344 18.773,-23.797 1.801,-1.5 8.383,-9.519 15.196,-18.508 66.527,-87.785 171.285,-185.593 216.953,-202.566 4.593,-1.703 16.922,-8.34 26.968,-14.512 10.098,-6.203 33.051,-13.894 50.504,-16.922 17.614,-3.058 53.145,-14.234 79.055,-24.867 74.449,-30.551 97.301,-35.019 174.508,-34.121 103.114,1.195 150.284,2.922 182.444,6.676 16.2,1.894 45.47,4.355 66.09,5.562 32.65,1.911 120.05,18.707 224.75,43.196 30.97,7.242 147.01,17.55 302.48,26.867 34.9,2.094 71.38,1.027 95.19,-2.777 56.05,-8.957 70.67,-10.997 117.92,-16.446 23.34,-2.695 76.68,-8.824 118.98,-13.676 77.74,-8.914 251.97,-10.113 259.33,-1.785 4.94,5.606 87.04,15.532 129.35,15.641 58.17,0.152 112.49,10.723 169.22,32.934 46.53,18.218 67.16,27.394 171.86,76.472 34.9,16.363 59.12,24.18 79.32,25.61 39.13,2.773 215.23,12.093 293.49,15.539 89.9,3.953 138.83,7.089 212.06,13.578 78.26,6.937 101.58,2.218 127.9,-25.887 20.81,-22.211 38.14,-48.652 38.14,-58.172 0,-3.551 7.23,-17.976 16.43,-32.785 18.57,-29.895 48.62,-47.895 96.74,-57.957 50.76,-10.613 121.95,11.07 138.18,42.094 8.01,15.316 9.62,15.863 46.63,15.863 33.32,0 41.6,2.078 63.2,15.863 14.8,9.453 24.85,19.715 24.85,25.383 0,13.234 10.05,22.211 24.86,22.211 20.09,0 59.41,21.215 72.52,39.133 25.6,34.996 28.51,61.871 10.97,101.531 -7.02,15.863 -11.22,28.555 -9.46,28.555 1.73,0 -1.33,5.289 -6.73,11.633 -13.96,16.394 -23.41,34.121 -23.41,43.894 0,5.875 5.55,7.93 21.41,7.93 11.64,0 26.74,3.019 33.06,6.609 7.48,4.254 33.31,6.613 72.44,6.613 56.06,0 62.88,1.118 87.25,14.278 14.78,7.976 42.31,16.554 62.41,19.441 44.41,6.383 66.75,21.883 87.04,60.406 13.43,25.5 14.43,31.731 13.7,85.668 -0.74,53.409 -2.31,61.809 -19.27,102.589 -19.35,46.54 -34.56,66.75 -59.79,79.51 -8.46,4.27 -20.79,11.89 -27.5,17 -6.61,5.03 -24.59,13.35 -39.4,18.25 -14.81,4.88 -34.71,13.3 -43.63,18.45 -27.74,16.03 -80.38,23.42 -137.49,19.32 -5.81,-0.42 -58.16,-0.28 -116.33,0.3 l -105.77,1.05 44.95,29 c 86.73,55.96 170.35,90.86 232.68,97.11 29.61,2.98 34.37,4.92 34.37,14.03 0,9.21 -5.81,11.38 -44.95,16.82 -82.49,11.46 -167.89,6.77 -245.89,-13.51 -50.53,-13.13 -86.73,-20 -142.78,-27.12 -89.9,-11.4 -158.73,-20.73 -211.53,-28.65 -71.01,-10.65 -117.39,-10.07 -211.52,2.62 -43.89,5.93 -87.59,11.78 -97.83,13.11 -48.65,6.3 -116.69,26.25 -162.87,47.76 -15.58,7.25 -41.78,16.66 -57.64,20.7 -16.05,4.08 -56.59,16.67 -90.43,28.08 -64.63,21.77 -102.59,31.96 -171.33,46 -22.74,4.64 -41.25,10.19 -41.25,12.38 0,2.2 7.66,7.74 17.18,12.43 9.41,4.63 38.61,27.72 64.52,51.03 25.91,23.3 59.29,48.34 73.77,55.34 27.12,13.1 94.65,32.51 143.31,41.2 14.68,2.62 47.59,10.6 74.03,17.94 26.23,7.29 85.93,22.72 132.99,34.37 47.07,11.66 93.24,25.63 102.86,31.11 25.45,14.5 66.1,22.02 144.36,26.7 50.77,3.03 77.15,2.17 103.12,-3.34 19.08,-4.04 52.88,-7.88 74.56,-8.47 43.89,-1.17 70.44,8.25 105.24,37.4 l 18.51,15.5 -5.56,27.49 -5.55,27.5 17.45,7.31 c 24.33,10.2 35.55,28.94 31.09,51.92 -3.28,16.92 -2.23,19.21 12.27,26.78 19.04,9.93 32.79,27.98 32.79,43.02 0,11.67 -13.33,42.83 -42.98,100.48 -20.44,39.74 -28.94,46.35 -73.36,57.07 -14.81,3.57 -26.44,7.89 -26.44,9.82 0,1.96 -3.96,2.53 -9.25,1.32 -5.06,-1.16 -37.81,-4.25 -72.19,-6.82 -62.92,-4.71 -71.43,-7.98 -71.77,-27.55 -0.13,-7.38 10.17,-8.4 80.5,-7.93 76.68,0.5 81.94,-0.14 107.09,-12.99 30.83,-15.77 50.44,-41.48 65.92,-86.43 8.02,-23.27 9.3,-32.95 5.04,-38.08 -14.95,-18 -30.14,-3.17 -58.48,57.12 l -11.43,24.32 -40.19,3.44 c -22.21,1.9 -50.36,4.38 -62.93,5.55 -13.75,1.28 -21.48,0.13 -19.56,-2.91 1.71,-2.7 -3.18,-5.02 -10.58,-5.02 -7.4,0 -12.4,-2.2 -10.84,-4.76 1.63,-2.67 0,-5.92 -3.7,-7.4 -3.55,-1.42 -1.59,-2.89 4.23,-3.18 6.19,-0.3 14.8,-5.29 20.09,-11.63 6.18,-7.41 12.25,-9.85 18.25,-7.33 14.28,5.99 52.19,9.62 65.57,6.27 8.2,-2.05 17.09,-12.16 25.12,-28.55 6.73,-13.75 18.03,-34.35 24.65,-44.95 18.51,-29.62 20.51,-43.95 7.87,-56.58 -11.11,-11.11 -30.69,-15.74 -24.6,-5.82 1.58,2.57 -1.58,7.91 -6.86,11.63 -5.29,3.72 -10.49,9.31 -11.32,12.16 -3.62,12.42 -18.56,29.92 -31.25,36.59 -17.98,9.46 -67,6.84 -79.33,-4.24 -5.1,-4.59 -14.54,-8.55 -20.35,-8.55 -5.82,0 -13.79,-3.68 -17.19,-7.93 -5.08,-6.35 -4.63,-10.58 2.22,-21.15 10.16,-15.68 9.41,-15.62 33.74,-2.58 33.32,17.85 48.76,14.35 72.67,-16.46 11.49,-14.81 23.25,-29.6 26.09,-32.79 11.73,-13.22 23.92,-35.32 23.92,-43.36 0,-9.15 -24.85,-21.39 -65.04,-32.02 -20.75,-5.5 -33.84,-5.22 -79.32,1.68 -66.45,10.09 -60.81,10.03 -146.48,1.61 -67.16,-6.61 -127,-21.25 -163.93,-40.13 -11.76,-6 -147.01,-44.36 -195.66,-55.48 -215.23,-49.21 -231.24,-55.92 -326.28,-136.72 -48.12,-40.92 -53.2,-43.87 -71.12,-41.42 -10.62,1.46 -28.82,0.86 -40.46,-1.32 -14.41,-2.7 -32.79,-1 -57.64,5.34 -65.78,16.78 -177.15,53.62 -249.07,82.39 -39.13,15.65 -73.35,28.34 -76.41,28.34 -3.04,0 -26.18,9.84 -51.03,21.68 -24.85,11.85 -64.18,28.52 -86.73,36.76 -22.73,8.31 -54.77,22.45 -71.39,31.51 -38.96,21.26 -104.7,50.33 -151.76,67.12 -20.33,7.25 -66.1,27.16 -101.53,44.14 -35.44,16.99 -73.58,32.61 -84.62,34.64 -11.1,2.05 -22.45,5.43 -25.38,7.56 -12.32,8.98 -83.02,26.79 -134.84,33.96 -46.9,6.5 -211,20.25 -316.76,26.55 -15.86,0.95 -43.63,-0.43 -61.08,-3.03 -17.69,-2.62 -52.08,-7.17 -76.94,-10.15 -53.41,-6.42 -170,-28.61 -213.11,-40.56 -16.922,-4.7 -31.976,-7.21 -33.582,-5.6 -1.625,1.62 -10.84,-0.39 -20.886,-4.55 -21.153,-8.78 -77.684,-9.77 -93.598,-1.65 -6.465,3.3 -17.981,11.83 -25.914,19.2 -16.113,14.98 -32.801,13.7 -35.16,-2.69 -2.153,-14.93 38.863,-44.82 66.89,-48.73 23.942,-3.35 99.414,6.18 139.075,17.55 44.847,12.87 187.195,39.46 245.375,45.83 65.96,7.23 133.25,7.22 265.98,-0.03 135.38,-7.39 186.95,-17.13 320.99,-60.64 11.6,-3.76 53.41,-21.08 92.55,-38.33 39.13,-17.24 80.94,-34.57 92.54,-38.33 11.6,-3.77 58.17,-24.19 103.12,-45.22 44.94,-21.02 96.05,-43.23 113.16,-49.18 16.92,-5.88 35.31,-14.59 40.19,-19.03 4.76,-4.34 11.6,-8.2 14.54,-8.2 2.98,0 12.43,-3.51 20.36,-7.57 26.55,-13.57 170.81,-66.16 271.81,-99.08 53.94,-17.59 101.39,-33.2 105.76,-34.81 4.44,-1.63 13.75,-3.84 21.15,-5.02 7.28,-1.16 51.3,-11.28 97.83,-22.48 46.54,-11.19 98.18,-23.09 114.75,-26.44 16.55,-3.33 61.88,-16.45 100.48,-29.08 38.6,-12.63 85.12,-27.12 103.12,-32.12 35.95,-10 39.33,-18.38 7.4,-18.38 -19.49,0 -93.07,-23.08 -136.43,-42.79 -12.16,-5.53 -23.41,-10.09 -24.86,-10.09 -1.43,0 -14.28,-6.82 -28.02,-14.87 -28.03,-16.42 -130.81,-59.17 -142.25,-59.17 -8.03,0 -15.65,-22.74 -10.45,-31.2 2.01,-3.27 10.97,-5.81 20.49,-5.81 9.31,0 31.2,-6.18 48.65,-13.73 59.76,-25.87 110.93,-42.99 140.14,-46.9 16.11,-2.15 44.42,-7.19 63.46,-11.29 19.03,-4.1 44.28,-7.4 56.58,-7.4 31.73,0 31.73,-8.26 0,-20.06 -66.1,-24.58 -157.92,-42.72 -215.23,-42.51 -24.85,0.09 -48.02,-0.09 -51.82,-0.41 -9.48,-0.8 -7.93,-32.21 1.59,-32.21 8.05,0 74.56,-27.75 126.91,-52.946 17.45,-8.398 43.03,-16.816 56.85,-18.707 13.75,-1.882 25.12,-5.593 25.12,-8.199 0,-7.207 -77.74,-62.48 -119.52,-84.976 -26.44,-14.235 -47.93,-21.786 -68.21,-23.957 -16.39,-1.758 -30.91,-5.297 -32.53,-7.934 -5.7,-9.32 4.5,-25.211 18.25,-28.406 7.9,-1.836 34.37,-9.231 59.23,-16.543 39.29,-11.555 56.05,-13.321 133.26,-14.012 l 88.31,-0.793 -8.75,-13.219 c -8.58,-12.957 -49.95,-52.914 -82.73,-79.914 -8.7,-7.156 -21.35,-19.504 -29.21,-28.492 -29.12,-33.316 -64.17,-65.875 -79.2,-73.578 -8.43,-4.32 -37.02,-12.609 -63.46,-18.406 -41.24,-9.035 -78.87,-24.5 -73.42,-30.172 1.12,-1.164 19.75,1.332 41.43,5.551 21.68,4.222 40.07,6.957 40.89,6.082 2.06,-2.18 -77.64,-38.286 -109.9,-49.786 -39.5,-14.082 -116.34,-26.914 -195.66,-32.671 -36.49,-2.649 -89.79,-7.504 -118.98,-10.844 -57.12,-6.531 -210.01,-3.039 -251.19,5.734 -13.09,2.789 -42.83,7.332 -66.1,10.098 -23.17,2.75 -69.8,8.594 -103.12,12.918 -75.79,9.84 -111.05,10.418 -224.74,3.676 -116.34,-6.895 -165.02,-13.375 -271.81,-36.184 -48.12,-10.277 -105.7,-20.422 -127.44,-22.453 -21.68,-2.024 -55.25,-6.219 -74.04,-9.254 -18.97,-3.063 -63.98,-5.906 -100.47,-6.344 -36.49,-0.437 -81.026,-2.926 -99.417,-5.554 -60.41,-8.629 -135.375,11.027 -234.262,61.429 -25.382,12.938 -56.925,24.649 -71.39,26.5 -60.446,7.742 -172.785,107.731 -275.52,245.223 -20.547,27.496 -41.843,59.211 -47.054,70.066 -5.329,11.106 -11.145,19.832 -13.219,19.832 -2.02,0 -6.106,6.61 -8.992,14.539 -2.918,8.036 -14.871,39.399 -26.703,70.071 -11.762,30.492 -28.45,84.609 -37.016,120.035 -8.567,35.43 -24.539,83.11 -35.43,105.77 -16.273,33.84 -20.023,47.89 -20.89,78.26 -0.579,20.24 -6.477,54.99 -13.012,76.68 -19.141,63.49 -10.801,152.29 21.351,227.38 12.524,29.25 80.118,151.77 107.067,194.08 30.316,47.59 67.191,143.76 67.324,175.56 0.125,30.47 19.008,95.19 39.656,135.91 23.063,45.47 54.629,80.68 86.969,97 37.543,18.95 73.91,47.59 86.988,68.52 6.543,10.46 18.203,38.07 25.91,61.34 11.493,34.69 14.016,51.82 14.016,95.18 0,65.57 10.723,91.18 56.582,135.1 35.59,34.08 108.934,84.16 153.356,104.71 13.218,6.12 28.027,2.9 28.027,-6.07 0,-9.3 49.707,-52.69 75.09,-65.55 45.476,-23.04 88.129,-39.58 93.599,-36.3 3.29,1.97 5.82,8.78 5.82,15.65 0,10.54 -6.35,14.43 -47.595,29.19 -79.336,28.39 -119.863,75.52 -143.633,167 -10.75,41.37 -12.062,56.58 -10.031,116.34 3.793,111.57 3.324,276.84 -0.926,325.21 -5.734,65.33 4.305,33.32 14.098,-44.94 16.945,-135.38 24.254,-175.57 38,-208.88 7.851,-19.04 17.012,-37.91 20.527,-42.31 3.383,-4.23 7.653,-11.63 9.149,-15.86 3.98,-11.25 79.004,-103.65 109.921,-135.38 26.8,-27.5 93.68,-65.57 115.19,-65.57 8.67,0 11.63,3.44 11.63,13.48 0,11.68 -5.81,16.15 -43.35,33.32 -48.05,21.98 -66.67,38.87 -130.325,118.19 -36.922,46.01 -68.352,103.15 -79.402,144.36 -4.762,17.75 -16.356,89.9 -35.266,219.46 -3.594,24.63 -22.504,109.46 -37.484,168.16 -7.692,30.14 -6.637,47.7 2.125,35.43 2.062,-2.88 17,-15.38 32.863,-27.5 28.801,-22 62.926,-33.24 140.129,-46.17 11.7,-1.95 41.25,-8.26 66.11,-14.11 24.85,-5.85 50.26,-11.64 56.84,-12.96 7.41,-1.48 11.9,-6.37 11.9,-12.95 0,-12.69 14.21,-19.64 22.74,-11.11 3.06,3.06 10.58,5.82 15.86,5.82 12.43,0 59.76,-30.33 87.79,-56.25 56.58,-52.34 67.91,-65.03 78.69,-88.12 13.07,-28.02 19.66,-30.72 28.41,-11.63 5.31,11.58 3.71,16.66 -12.97,40.98 -10.32,15.05 -31.03,40.72 -45.22,56.06 l -26.17,28.29 10.84,18.51 c 22.23,37.97 78,57.93 176.36,63.15 35.95,1.91 65.57,2.28 65.57,0.83 0,-1.47 -8,-11.1 -17.99,-21.68 -24.22,-25.63 -39.81,-59.76 -46.39,-101.53 -7.57,-48.12 -5.81,-51.05 28.42,-47.38 35.96,3.86 105.76,-16.43 139.6,-40.58 37.55,-26.79 37.55,-26.79 -63.98,-51.43 -41.25,-10.01 -42.29,-10.64 -41.52,-25.34 0.44,-8.24 4.63,-30.4 9.26,-48.91 4.63,-18.51 7.26,-35.04 5.82,-36.49 -4.5,-4.49 -35.96,10.48 -62.93,29.95 -16.92,12.21 -29.4,26.59 -35.96,41.44 -7.94,17.98 -12.71,22.74 -22.74,22.74 -10.41,0 -13.68,-3.7 -18.23,-20.62 -5.97,-22.21 -25.89,-54.19 -35.71,-57.32 -7.62,-2.43 -20.58,24.53 -27.81,57.85 -4.36,20.09 -3.85,29.45 2.43,44.95 5.14,12.69 6.07,21.42 2.64,24.85 -8.82,8.83 -20.05,-1.06 -29.43,-25.91 -8.69,-23.05 -8.68,-25.91 0.09,-54.47 14.45,-47.06 35.62,-98.29 44.15,-106.82 10.45,-10.45 24.01,-1.06 27.49,19.04 1.44,8.32 7.18,23.79 12.56,33.84 16.97,31.73 27.27,34.27 42.8,10.58 6.78,-10.34 23.44,-22.35 45.12,-32.52 19.04,-8.94 39.1,-18.38 44.95,-21.16 5.7,-2.7 20.09,-13.45 31.2,-23.28 23.27,-20.6 32.44,-22.35 40.22,-7.65 6.67,12.6 2.62,23.21 -15.89,41.54 -15.53,15.39 -28.78,61.58 -25.54,89.07 1.44,12.22 5.44,15.91 22.89,21.08 52.88,15.68 75.83,18.49 94.66,11.61 14.8,-5.42 20.2,-5.36 26.97,0.29 32.17,26.89 -41.25,93.37 -138.02,124.98 -30.67,10.02 -60.02,18.14 -65.57,18.14 -12.98,0 -13.33,11.1 -1.51,47.59 7.01,21.62 15.52,33.32 39.84,54.73 24.33,21.42 30.6,30.06 29.36,40.45 -1.32,10.91 -5.29,13.87 -22.75,16.91 -65.57,11.43 -165.9,-2.74 -224.74,-31.73 -21.68,-10.69 -41.46,-20.39 -43.63,-21.4 -2.19,-1.02 -3.96,13.49 -3.96,32.53 0,36.32 3.84,45.47 39.93,95.18 8.83,12.16 19.95,30.58 24.58,40.72 4.63,10.12 21,46.53 36.14,80.38 29.1,65.04 64.51,114.72 103.47,145.14 25.91,20.24 74.75,47.43 78.37,43.64 1.4,-1.46 2.89,-39.92 3.33,-85.93 0.69,-71.92 2.57,-89.06 13.8,-125.59 19.5,-63.46 31.02,-86.91 56.12,-114.22 32.48,-35.36 52.89,-67.16 68.88,-107.35 16.63,-41.81 17.46,-41.22 -60.8,-43.74 -43.36,-1.4 -55.04,-3.5 -59.56,-10.73 -9.98,-15.98 3.51,-22.61 29.94,-14.72 14.94,4.46 52.89,6.65 110.53,6.4 152.3,-0.68 315.91,-35.32 374.92,-79.39 10.05,-7.5 19.24,-15.51 20.1,-17.52 0.87,-2.03 18.24,-17.13 38.34,-33.32 20.13,-16.22 52.29,-48.38 71.12,-71.12 18.83,-22.74 38.44,-43.16 43.37,-45.16 36.4,-14.75 155.46,-13.66 232.67,2.13 29.62,6.06 67.77,12.23 84.61,13.68 16.92,1.46 41.34,3.85 54.47,5.33 35.96,4.07 37.82,4.16 65.04,3.36 l 25.91,-0.76 -3.58,-21.15 c -4.39,-25.91 6.97,-52.23 30.55,-70.78 9.23,-7.25 27.5,-23.04 40.19,-34.72 12.69,-11.68 26.64,-21.42 30.68,-21.42 10.32,0 9,-7.4 -11.6,-65.57 -11.06,-31.2 -24.44,-58.55 -33.13,-67.68 -16.88,-17.76 -49.94,-28.4 -93.29,-30.02 -17.46,-0.65 -34.23,-3.09 -37.29,-5.42 -3.05,-2.32 -24.59,-5.54 -47.86,-7.14 -24.32,-1.67 -59.6,-8.75 -83.02,-16.65 -22.21,-7.5 -51.53,-13.75 -64.51,-13.75 -13.22,0 -30.03,-2.35 -37.81,-5.29 -7.67,-2.89 -29.35,-7.45 -47.86,-10.05 -20.1,-2.83 -39.54,-9.27 -47.86,-15.86 -7.93,-6.29 -17.45,-11.11 -21.94,-11.11 -7.5,0 -49.53,-30.14 -53.1,-38.07 -0.98,-2.2 -5.34,-4.23 -9.04,-4.23 -3.95,0 -10.21,-5.56 -14.01,-12.43 -3.81,-6.89 -12.3,-22.21 -19.04,-34.37 -6.74,-12.17 -18.76,-27.96 -26.97,-35.43 -8.1,-7.39 -17.81,-23.53 -21.46,-35.7 -11.71,-39.13 -36.19,-81.68 -54.16,-94.16 -9.52,-6.62 -18.65,-13.57 -20.09,-15.3 -1.48,-1.77 -19.04,-15.18 -39.66,-30.29 -44.42,-32.54 -52.86,-45.58 -47.8,-73.89 3.56,-19.96 37.75,-78.26 68.85,-117.39 8.91,-11.22 21.87,-30.14 29.32,-42.83 25.89,-44.07 56.45,-76.68 106.15,-113.31 28.03,-20.65 63.44,-47.59 79.06,-60.14 15.34,-12.33 37.13,-27.35 47.6,-32.79 18.93,-9.86 19.27,-10.58 17.71,-38.08 -0.87,-15.33 -0.44,-32.09 0.94,-37.01 4.38,-15.56 31.32,-20.8 72.04,-14.02 26.43,4.41 38.09,4.48 42.3,0.27 8.18,-8.18 -38.6,-36.75 -67.16,-41.01 -46.01,-6.86 -115.53,-4.31 -148.06,5.43 -39.67,11.87 -109.27,39.13 -115.81,45.36 -2.98,2.82 -9,5.03 -13.75,5.03 -23.8,0 -137.5,73.02 -137.5,88.31 0,3.82 -4.23,6.87 -9.51,6.87 -10.29,0 -26.04,15.34 -51.59,50.24 -22.34,30.51 -42.01,46.68 -93.84,77.14 -25.38,14.91 -47.19,28.93 -48.65,31.26 -1.46,2.35 -22.21,5.86 -46.53,7.89 -42.31,3.53 -93.51,-2.53 -114.22,-13.51 -10.05,-5.32 -69.77,-31.39 -71.92,-31.39 -7.57,0 -5.62,26.44 5.57,75.62 11.18,49.18 16.11,61.73 29.07,74.03 9.51,9.04 15.59,20.06 15.59,28.29 0,13.38 -0.26,13.46 -33.05,10.05 -20.61,-2.14 -54.73,-0.35 -90.69,4.77 -59.23,8.44 -144.47,6.93 -162.87,-2.89 -5.04,-2.68 -14.81,-4.79 -22.21,-4.79 -15.94,0 -18.06,12.17 -6.72,38.6 4.02,9.41 10.17,27.5 13.83,40.72 10.09,36.49 52.06,112.26 70.1,126.52 8.56,6.78 23.53,14.14 32.52,16 9.51,1.96 17.41,7.29 18.42,12.42 2.86,14.54 -36.67,20.91 -133.97,21.59 -71.39,0.49 -95.94,-1.28 -119.24,-8.63 -16.05,-5.06 -46.01,-12.73 -66.11,-16.92 -20.09,-4.19 -41.06,-9.23 -46.26,-11.11 -8.79,-3.17 -8.63,-1.06 2.11,27.5 6.36,16.92 15.58,35.73 20.36,41.51 4.88,5.93 12.37,16.39 17.01,23.8 8.9,14.18 20.01,28.02 52.63,65.57 26.27,30.24 45.55,74.04 50.05,113.7 3.73,32.78 3.59,33.28 -8.91,31.46 -11.21,-1.64 -13.1,-5.55 -16.21,-33.58 -4.47,-40.19 -14.62,-64.18 -39.81,-94.13 -70.31,-83.55 -77.4,-93.51 -100.4,-141.19 -10.46,-21.68 -20.82,-40.89 -22.84,-42.37 -13.948,-10.22 -7.94,-42.24 7.93,-42.24 4.04,0 15.33,6.85 24.85,15.07 11.64,10.05 26.18,16.39 43.63,19.04 14.51,2.2 45.74,9.62 70.07,16.66 36.23,10.47 54.73,12.6 106.03,12.16 34.37,-0.29 68.75,-2.07 76.94,-3.97 14.27,-3.31 14.46,-3.81 5.11,-14.01 -24.56,-26.79 -46.56,-68.22 -66,-124.27 -11.55,-33.32 -26.82,-72.53 -33.77,-86.73 -10.1,-20.62 -11.43,-27.42 -6.5,-33.31 7.78,-9.29 34.52,-6.66 67.84,6.66 26.56,10.63 114.22,13.07 195.66,5.47 55.52,-5.19 61.09,-6.76 54.26,-15.31 -2.79,-3.47 -12.97,-38.6 -22.53,-77.73 -9.57,-39.13 -21.03,-79.03 -25.38,-88.31 -6.45,-13.75 -6.7,-18.41 -1.36,-24.85 7.02,-8.46 32.03,-11.77 32.03,-4.23 0,7.4 71.91,43.36 86.72,43.36 7.72,0 23.27,-4.74 33.85,-10.31 10.76,-5.68 43.36,-21.26 72.44,-34.64 29.09,-13.38 70.85,-34.91 92.81,-47.86 23.48,-13.84 56.58,-27.67 80.38,-33.58 30.67,-7.61 46.59,-15.16 65.84,-31.2 64.79,-53.99 159.69,-103.12 262.28,-135.77 l 61.88,-19.7 58.69,6.02 c 80.38,8.25 147.54,37.76 147.54,64.84 0,9.16 3.18,9.77 35.96,6.88 48.65,-4.29 154.36,-4.92 202,-1.22 126.39,9.84 179.57,15 200.95,19.49 13.13,2.76 75.36,7.84 138.82,11.34 63.45,3.5 115.01,8.12 115.01,10.31 0,2.18 -6.08,7.9 -13.48,12.69 -12.11,7.84 -22.74,8.19 -104.18,3.44 -49.71,-2.9 -92.6,-4.09 -94.92,-2.64 -2.35,1.47 -17.72,-1.34 -34.64,-6.35 -16.86,-4.98 -56.31,-10.87 -88.57,-13.22 -32.11,-2.33 -87.79,-6.84 -124.27,-10.05 -36.49,-3.21 -82.69,-4.43 -103.12,-2.73 -33.73,2.81 -74.03,5.52 -156,10.49 -16.19,0.98 -42.57,2 -59.49,2.29 l -30.41,0.53 v 21.15 c 0,11.64 2.62,21.15 5.82,21.15 13.12,0 1.06,24.2 -16.39,32.88 -26.97,13.41 -32.82,23.49 -28.8,49.62 2.11,13.75 1.2,23.52 -2.4,25.65 -3.82,2.25 -5.91,42.04 -6.09,115.54 -0.14,61.87 -1.04,120.4 -2.01,130.62 -1.82,19.28 -7.96,153.35 -10.18,222.1 -0.71,22.21 -3.18,43.15 -5.52,46.8 -2.25,3.52 -1.15,10.31 2.38,14.54 5.08,6.1 5.19,11.11 0.43,21.68 -8.42,18.75 -4.92,20.61 19.93,10.62 19.04,-7.65 21.95,-7.71 29.08,-0.57 7.54,7.53 11.04,33.31 8.62,63.45 -2.09,26.02 26.29,36.81 111.42,42.36 l 56.06,3.65 16.92,-24.32 16.92,-24.33 -12.16,-2.77 c -14.14,-3.22 -78.79,-12 -123.74,-16.81 -32.79,-3.5 -44.42,-9.17 -44.42,-21.67 0,-12.7 13.22,-13.11 58.7,-1.8 63.98,15.9 141.36,15.59 172.92,-0.69 28.02,-14.46 41.44,-9.52 39.76,14.66 -6.63,95.18 -3.34,107.87 27.93,107.87 33.84,0 74,11.86 99.94,29.51 28.48,19.39 37.13,36.07 65.87,127.02 9.86,31.2 15.71,40.59 34.6,55.53 12.69,10.03 24.09,22.65 25.78,28.55 8.67,30.14 -0.57,112.64 -16.16,144.37 -9.44,19.21 -10.15,19.54 -38.7,18.51 -16.11,-0.59 -44.42,-6.01 -63.46,-12.17 -24.92,-8.05 -57.64,-12.41 -118.98,-15.86 -46.54,-2.62 -98.89,-8.57 -116.34,-13.22 -17.68,-4.71 -48.12,-10.69 -68.75,-13.49 -20.62,-2.79 -43.34,-6.25 -51.29,-7.8 -23.74,-4.62 -106.29,-4.67 -130.62,-0.07 -24.78,4.68 -36.59,14.49 -79.89,66.31 -34.91,41.77 -52.18,58.17 -61.3,58.17 -4.65,0 -17.14,9.51 -27.74,21.15 -23.63,25.91 -104.86,68.74 -130.37,68.74 -10.05,0 -19.24,2.1 -20.84,4.76 -2.69,4.49 -46.32,13.35 -92.86,18.86 -13.09,1.55 -38.07,5.2 -55.52,8.11 -17.45,2.91 -42.44,5.29 -55.53,5.29 -35.95,0 -46.27,4.21 -49.27,20.1 -6.89,36.48 -25.02,68.21 -80.64,141.19 -59.98,78.7 -76.19,132.2 -72.11,237.96 1.91,49.18 5.3,74.99 11.92,90.69 6.91,16.4 7.78,23.42 3.44,27.77 -9.4,9.39 -13.75,7.73 -67.16,-25.69 z m -284.24,-429.88 c -1.59,-35.43 -3.15,-65.14 -3.44,-65.58 -0.29,-0.43 -15.6,8.35 -34.11,19.57 -18.5,11.22 -36.19,21.19 -39.39,22.21 -4,1.27 -3.63,7.14 1.2,18.77 7.67,18.51 60.42,69.81 71.77,69.81 5.5,0 6.29,-12.96 3.97,-64.78 z m 1590.4,-309.62 c 0,-5.44 -38.61,-27.5 -48.13,-27.5 -9.6,0 -1.05,7.28 24.33,20.72 23.8,12.59 23.8,12.59 23.8,6.78 z m -214.17,-385.51 c -0.59,-22.73 -3.39,-41.5 -6.35,-42.49 -5.38,-1.81 -54.47,58.89 -54.47,67.35 0,4.5 32.79,14.37 50.77,15.29 10.38,0.54 11.04,-2.07 10.05,-40.15 z m -283.99,-50.76 c 1.07,-9.52 -0.86,-14.28 -5.8,-14.28 -11.1,0 -20.36,13.09 -16.45,23.27 5.21,13.55 20.42,7.4 22.25,-8.99 z m -64.82,-30.67 c 4.18,-18.51 1.42,-23.29 -10.78,-18.73 -11.64,4.34 -15.58,17.94 -7.89,27.19 9.74,11.72 14.61,9.52 18.67,-8.46 z m -13.43,-48.77 c 9.52,-4.87 12.71,-10.16 11.37,-18.92 -1.02,-6.7 2.07,-20.36 6.88,-30.41 6.23,-13.03 8.42,-29.87 7.66,-58.96 -0.58,-22.39 0.73,-64.51 2.91,-93.6 2.19,-29.13 4.56,-112.37 5.29,-185.34 0.73,-72.98 2.94,-135.09 4.92,-138.29 6.12,-9.9 -15.23,-18.04 -26.34,-10.03 -9.16,6.6 -9.07,7.91 2.12,34.89 8.78,21.15 10.21,29.71 5.85,34.9 -8.52,10.1 -15.37,9.21 -29.12,-3.8 -7.93,-7.51 -15.08,-9.92 -22.47,-7.57 -10.56,3.35 -10.5,3.96 2.68,24.06 15.94,24.32 14.69,44.23 -2.95,46.85 -6.87,1.01 -16.64,-2.34 -22.47,-7.72 -9.22,-8.5 -12.96,-8.82 -35.17,-2.96 -39.13,10.33 -51.17,21.94 -50.79,48.97 0.36,25.38 10.57,51.58 29.07,74.56 17.63,21.91 7.97,28.61 -30.1,20.88 -41.25,-8.36 -58.71,-7.69 -76.68,2.96 -29.88,17.72 -23.79,45.8 14.81,68.29 33.82,19.7 40.72,25.26 79.85,64.4 27.5,27.49 37.76,34.38 54.73,36.75 12.69,1.77 23.94,7.27 28.66,14.01 11.11,15.87 9.62,38.76 -3.01,46.57 -12.2,7.55 -13.14,14.25 -4.6,32.75 7.02,15.21 25.22,17.84 46.9,6.76 z m -68.74,-67.04 c 0,-3.02 -2.38,-5.29 -5.55,-5.29 -3.18,0 -4.2,2.27 -2.38,5.29 1.9,3.17 4.12,5.29 5.55,5.29 1.43,0 2.38,-2.12 2.38,-5.29 z m -79.32,-234.79 c 0,-7.41 -21.68,-50.77 -25.39,-50.77 -4.32,0 -30.79,30.67 -40.14,46.54 -2.86,4.84 4.45,6.34 30.89,6.34 19.03,0 34.64,-0.95 34.64,-2.11 z m 78.26,-154.68 -14.28,-14.01 -14.8,10.04 -14.81,10.05 23.79,3.17 c 13.23,1.77 26.15,3.53 29.09,3.97 2.94,0.44 -1.06,-5.44 -8.99,-13.22 z m -443.14,-12.68 c 46.53,-15.26 98.41,-45.37 127.97,-74.28 33.84,-33.1 38.6,-43.94 16.92,-38.56 -15.17,3.77 -92.54,43.03 -124.27,63.06 -11.1,7.01 -23.31,13.02 -26.44,13.02 -12.16,0 -88.62,39.15 -85.71,43.89 3.79,6.17 65.62,1.36 91.53,-7.13 z m 495.76,-38.09 c -1.29,-3.56 -5.56,-6.61 -9.26,-6.61 -3.7,0 -7.97,3.05 -9.25,6.61 -1.41,3.91 2.38,6.62 9.25,6.62 6.88,0 10.66,-2.71 9.26,-6.62 z m 1778.12,-577.19 c 0,-1.17 -8.99,-5.01 -20.09,-8.58 -38.61,-12.43 -125.62,-54.24 -139.08,-66.84 -7.4,-6.92 -15.43,-12.48 -18.24,-12.63 -2.8,-0.15 -14.28,-7.17 -25.92,-15.86 -11.63,-8.69 -22.53,-15.6 -24.59,-15.6 -8.53,0 -126.91,-73.48 -231.61,-143.77 -69.04,-46.35 -112.11,-73.1 -185.62,-115.316 -21.81,-12.523 -77.73,-50.496 -124.27,-84.379 -46.53,-33.882 -98.88,-71.242 -116.34,-83.023 -17.49,-11.805 -50.23,-34.23 -72.97,-49.973 -22.74,-15.742 -58.57,-39.171 -79.85,-52.214 -33.53,-20.547 -57.64,-38.36 -106.29,-78.5 -14.28,-11.782 -46.07,-35.184 -55,-40.477 -19.2,-11.391 7.93,19.832 50.76,58.414 25.39,22.863 53.75,49.969 62.41,59.633 8.74,9.762 27.4,29.348 41.57,43.625 27.28,27.5 30.6,43.23 9.72,46.035 -6.34,0.852 -15.24,-2.047 -19.57,-6.371 -4.37,-4.379 -21.68,-9.867 -38.6,-12.246 -41.78,-5.875 -138.08,-4.16 -160.23,2.851 -9.69,3.071 -28.82,8.493 -41.51,11.774 l -23.53,6.082 36.75,17.976 c 20.32,9.942 56.85,32.164 81.7,49.711 24.86,17.543 57.36,40.121 72.71,50.5 15.34,10.371 28.14,21.141 28.61,24.063 2.76,17.359 1.27,17.988 -43.15,18.246 -37.02,0.215 -50.08,2.687 -74.03,14.008 -16,7.561 -43.36,20.291 -60.82,28.291 l -31.72,14.54 68.74,12.02 c 138.02,24.13 245.9,65.48 245.9,94.27 0,4 -21.16,6.09 -67.69,6.68 -70.33,0.88 -180.75,18.87 -218.4,35.58 -9.83,4.36 -35.96,16.25 -57.64,26.22 l -39.66,18.25 74.03,35.44 c 148.07,70.88 185.33,82.82 245.9,78.76 21.68,-1.45 40.78,-3.68 42.84,-5 2.09,-1.34 8.98,-0.43 15.86,2.11 8.11,3 17.98,2.12 29.61,-2.65 16.79,-6.88 77.21,-19.22 165.52,-33.82 61.87,-10.23 254.93,-9.45 290.85,1.17 16.1,4.76 44.41,10.18 63.45,12.13 61.87,6.37 252.8,39.01 264.41,45.21 16.92,9.03 185.08,21.44 185.08,13.66 z m 58.17,-169.05 c 25.05,-4.45 58.17,-15.91 89.9,-31.1 27.5,-13.18 56.7,-25.71 64.51,-27.69 29.76,-7.56 66.82,-60.36 81.7,-116.42 23.16,-87.25 -6.39,-162.957 -67.95,-174.058 -23.25,-4.196 -26.48,-0.446 -31.43,36.57 -18.02,134.848 -22.85,149.528 -52.12,158.678 -10.05,3.14 -25.04,9.01 -32.79,12.84 -16.92,8.36 -30.67,4.25 -30.67,-9.17 0,-12.97 7.41,-18.55 35.43,-26.71 29.98,-8.72 36.74,-23 43.93,-92.802 3.16,-30.672 7.07,-59.406 8.64,-63.457 4.03,-10.449 -12.38,-33.813 -30.36,-43.223 -17.26,-9.039 -46.53,-9.976 -74.03,-2.379 l -19.57,5.411 0.53,59.492 c 0.44,49.707 -1.3,63.492 -10.57,83.816 -9.42,20.621 -14.81,25.772 -35.44,33.842 -13.53,5.3 -37.81,9.76 -54.73,10.05 -27.49,0.48 -30.56,-0.61 -31.99,-11.37 -1.43,-10.74 0.53,-11.901 20.09,-11.901 65.9,0 94.61,-44.945 83.43,-130.613 -5.32,-40.719 -10.57,-48.492 -36.36,-53.805 -26.44,-5.453 -41.6,-1.551 -46.75,12.028 -5.62,14.808 -60.88,71.918 -69.59,71.918 -3.46,0 -14.28,6.007 -23.8,13.218 -9.52,7.215 -20.09,13.223 -23.26,13.223 -3.15,0 -14.81,4.605 -25.38,10.02 -38.02,19.468 -206.24,44.093 -294.02,43.039 -32.26,-0.391 -75.97,-2.493 -97.04,-4.672 -21.16,-2.188 -38.34,-2.309 -38.34,-0.266 0,2.027 17.45,13.957 38.6,26.387 59.76,35.114 160.37,99.124 208.88,132.904 24.33,16.93 45.07,30.55 46.54,30.55 1.47,0 18.24,10.56 37.81,23.8 31.2,21.11 37.46,23.41 55.52,20.36 11.64,-1.97 25.35,-0.83 31.99,2.64 6.35,3.32 24.86,7.04 40.72,8.19 50.77,3.67 196.99,-2.07 237.97,-9.34 z M 3631.87,946.5 c 98.36,-10.066 144.13,-20.555 195.13,-44.723 54.99,-26.062 94.32,-59.254 111.07,-93.754 56.5,-116.339 70.31,-157.613 62.77,-187.73 -4.66,-18.66 -43.75,-44.996 -63.85,-43.016 -17.85,1.758 -17.94,2.297 -12.76,73.688 1.72,23.797 0.17,32.367 -7.39,40.719 -12.45,13.75 -67.93,42.625 -76.09,39.601 -14.14,-5.238 -6.35,-22.113 16.39,-35.48 38.71,-22.754 42.86,-33.735 35.12,-92.961 -3.59,-27.5 -8.96,-56.699 -11.85,-64.516 -6.6,-17.808 -29.09,-25.988 -59.76,-21.734 -20.09,2.785 -23.7,5.211 -26.44,17.769 -1.76,8.078 -1.58,23.004 0.4,33.578 5.55,29.614 -1.96,72.899 -15.59,89.899 -10.14,12.64 -19.18,16.59 -51.44,22.473 -21.68,3.957 -46.79,8.671 -56.32,10.578 -15.86,3.172 -17.18,2.359 -17.18,-10.578 0,-7.93 0.92,-14.012 2.11,-14.012 10.58,0 82.39,-17.192 91.49,-21.903 12.33,-6.386 24.94,-38.91 20.41,-52.66 -1.32,-4.015 -3.52,-21.679 -4.81,-38.601 -1.3,-16.922 -5.05,-32.774 -8.2,-34.637 -3.06,-1.812 -5.4,-8.199 -4.94,-13.488 1.93,-22.207 -1.6,-28.016 -22.03,-36.285 -28.34,-11.473 -59.75,-12.024 -95.18,-1.676 -35.36,10.328 -45.58,20.512 -71.54,71.277 -23.25,45.477 -66.38,88.047 -97.68,96.41 -11.45,3.059 -31.47,4.438 -43.63,3.008 -12.31,-1.449 -49.97,-4.437 -83.29,-6.613 -33.31,-2.172 -62.01,-4.258 -63.46,-4.613 -25.91,-6.348 -396.6,-21.559 -396.6,-16.274 0,5.074 123.21,98.82 142.77,108.633 13.3,6.668 36.76,21.973 53.15,34.676 16.39,12.699 40.09,29.441 53.67,37.918 30.75,19.187 81.97,54.82 154.42,107.425 49.18,35.711 59.89,41.391 72.97,38.684 8.47,-1.754 20.56,-0.566 26.97,2.641 6.32,3.16 20.1,6.715 30.14,7.773 40.89,4.324 172.93,3.43 221.05,-1.496"
+       style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
+       transform="matrix(0.13333333,0,0,-0.13333333,0,550.66667)" />
+    <path
+       id="path2"
+       d="m 2009.48,2892.98 c -7.41,-2.2 -19.73,-7.39 -26.71,-11.23 -7.11,-3.92 -47.32,-16.87 -89.1,-28.7 -79.32,-22.45 -93.35,-30.89 -81.93,-49.3 10.53,-16.96 30.1,-14.45 68.18,8.75 39.06,23.81 108.94,31.18 158.64,16.74 92.01,-26.73 123.39,-29.7 147.54,-13.98 12.34,8.04 14.26,12.29 11.55,25.51 -4.04,19.7 -14.19,27.76 -45.39,36.01 -13.22,3.49 -34.14,9.54 -47.07,13.6 -24.85,7.82 -73.71,9.14 -95.71,2.6"
+       style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
+       transform="matrix(0.13333333,0,0,-0.13333333,0,550.66667)" />
+    <path
+       id="path3"
+       d="m 2915.33,2820.67 c -1.44,-4.04 -1.2,-11.37 0.53,-16.13 2.76,-7.59 9.52,-8.26 52.35,-5.16 51.4,3.73 228.45,-4.1 288.2,-12.74 92.02,-13.3 112.11,-18 112.11,-26.25 0,-10.84 -55,-58.12 -86.73,-74.56 -66.09,-34.26 -120.91,-67.82 -126.92,-77.74 -5.25,-8.66 6.36,-18.48 16.4,-13.88 5.29,2.43 11.87,4.48 14.81,4.63 2.81,0.14 11.37,4.61 18.24,9.52 6.88,4.91 14.7,9.25 16.66,9.25 7,0 103.12,60.55 131.68,82.95 l 29.08,22.81 9.25,-11.1 c 7.33,-8.79 9.38,-21.68 9.84,-61.88 2.07,-179.79 3.99,-237.12 9.55,-283.96 3.44,-29.09 7.33,-66.45 8.64,-83.03 1.3,-16.39 4.79,-40.51 7.67,-52.88 2.9,-12.48 5.29,-34.9 5.29,-49.71 0,-20.09 2.69,-29.39 10.57,-36.49 5.82,-5.23 10.87,-7.85 11.22,-5.81 1.16,6.62 2.66,11.1 6.95,20.62 2.24,5 1.46,19.57 -1.77,32.79 -3.23,13.2 -7.11,42.04 -8.73,64.78 -1.61,22.72 -6.34,66.89 -10.61,99.15 -9.09,68.74 -14.83,348.36 -7.43,362.23 3.39,6.35 2.62,11.56 -2.32,15.64 -8.99,7.43 -14.33,26.67 -7.4,26.67 2.92,0 3.98,3.43 2.38,7.66 -1.61,4.24 0.41,10.43 4.49,13.82 19.3,16.01 -5.81,43.93 -28.55,31.74 -5.94,-3.18 -23.27,-3.31 -46.01,-0.34 -20.14,2.63 -90.95,6.06 -158.11,7.67 -67.16,1.6 -156.8,3.85 -200.16,5.02 -62.93,1.7 -79.05,0.65 -81.17,-5.29 z m 435.74,-37.01 c -1.71,-1.71 -6.35,-1.96 -10.05,-0.53 -4.34,1.67 -3.17,2.83 3.18,3.17 5.28,0.28 8.54,-0.98 6.87,-2.64 z m 31.73,-5.29 c -1.71,-1.71 -6.35,-1.96 -10.05,-0.53 -4.34,1.67 -3.17,2.84 3.17,3.17 5.29,0.28 8.55,-0.97 6.88,-2.64"
+       style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
+       transform="matrix(0.13333333,0,0,-0.13333333,0,550.66667)" />
+    <path
+       id="path4"
+       d="m 2940.18,2588.29 c -50.76,-3.64 -118.2,-8.43 -149.39,-10.61 -49.7,-3.47 -57.26,-5.29 -60.16,-14.54 -5.18,-16.48 5.43,-22.29 28.17,-15.43 29.36,8.87 122.16,16.74 242.2,20.54 71.39,2.27 108.94,5.5 115.54,9.96 9.32,6.3 9.26,6.89 -1.32,12.48 -12.96,6.85 -53.94,6.29 -175.04,-2.4"
+       style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
+       transform="matrix(0.13333333,0,0,-0.13333333,0,550.66667)" />
+    <path
+       id="path5"
+       d="m 3133.2,2534.88 c -5.57,-5.42 -7.69,-12.99 -5.58,-19.86 10.27,-33.45 13.04,-51.82 13.27,-87.78 0.13,-21.68 2.4,-49.25 5,-60.81 2.63,-11.7 6.41,-61.35 8.46,-111.05 2.05,-49.71 4.41,-91.09 5.29,-92.55 0.88,-1.45 3.13,-51.29 5.02,-111.05 1.9,-59.75 5.93,-128.1 8.99,-152.3 3.08,-24.32 4.38,-48.36 2.91,-53.93 -1.39,-5.29 0.62,-14.43 4.23,-19.3 6.09,-8.19 8.46,-8.43 20.62,-2.12 10.58,5.49 16.8,5.8 26.98,1.32 11.63,-5.12 14.35,-4.23 22.68,7.41 25.38,35.43 57.25,75.63 75.45,95.18 67.43,72.45 133.93,166.84 128.89,182.97 -4.78,15.28 -18.55,8.99 -33.59,-15.33 -25.81,-41.78 -55.42,-83.67 -72.14,-102.07 -33.66,-37.01 -73.79,-83.5 -88.57,-102.59 -8.19,-10.57 -18.04,-19.03 -22.15,-19.03 -4.04,0 -11.13,-5.29 -15.6,-11.63 -4.47,-6.35 -9.64,-10.2 -11.37,-8.47 -9.11,9.11 -18.56,92.02 -21.28,186.67 -1.67,58.17 -4.83,120.04 -7.01,137.49 -2.18,17.45 -4.44,55.53 -5.02,84.61 -0.59,29.09 -3.32,76.68 -6.09,105.77 -2.77,29.24 -5.84,78.52 -6.87,110.25 -1.33,41.25 -3.93,58.71 -9.25,62.11 -10.05,6.42 -13.22,5.89 -23.27,-3.91"
+       style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
+       transform="matrix(0.13333333,0,0,-0.13333333,0,550.66667)" />
+    <path
+       id="path6"
+       d="m 957.145,2232.46 c -41.543,-11.71 -94.657,-31.01 -147.008,-53.41 -21.68,-9.28 -48.918,-18.4 -61.078,-20.45 -17.45,-2.94 -22.317,-6.19 -23.754,-15.86 -3.18,-21.4 6.039,-22.22 44.644,-3.99 20.621,9.74 49.461,21.31 63.985,25.67 14.804,4.44 36.211,12.94 48.648,19.31 44.727,22.93 97.305,31.9 185.618,31.66 52.35,-0.13 94.38,-2.98 116.34,-7.87 19.03,-4.25 40.74,-9.14 48.64,-10.97 17.46,-4.02 19.5,4.53 4.23,17.66 -21.2,18.23 -53.41,23.76 -150.71,25.88 -80.38,1.74 -100.528,0.56 -129.555,-7.63"
+       style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
+       transform="matrix(0.13333333,0,0,-0.13333333,0,550.66667)" />
+    <path
+       id="path7"
+       d="m 1341.22,2138.51 c -5.99,-15.1 -3.86,-16.7 26.81,-20.18 36.49,-4.15 79.73,-23.12 111.05,-48.73 23.8,-19.46 38.6,-20.41 38.6,-2.48 0,16.78 -32.25,36.77 -95.18,58.98 -64.52,22.77 -76.45,24.59 -81.28,12.41"
+       style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
+       transform="matrix(0.13333333,0,0,-0.13333333,0,550.66667)" />
+  </g>
+</svg>
diff --git a/various/templates/various/403_csrf.html b/various/templates/various/403_csrf.html
new file mode 100644
index 00000000..d0082550
--- /dev/null
+++ b/various/templates/various/403_csrf.html
@@ -0,0 +1,19 @@
+{#{% extends "error_base.html" %} Z toho nedědíme, protože se nemá přecházet na titulní stránku. #}
+{% extends "base.html" %}
+
+{% load static %}
+
+{% block content %}
+
+  <h2>{% block nadpis1a %}O-jo-jo-jo-joj{% endblock nadpis1a %}</h2>
+
+  <p>
+    Problém se sušenkami či něčím podobným. Zkuste {% if url %}to prosím znovu: <a href="{{ url }}">{{ url }}</a>. Případně můžete {% endif %}přejít na <a href="/">titulní stránku</a>.
+  </p>
+
+  <p>Pokud problém přetrvává obraťte se na nás přes e-mail: <a href="mailto:mam@matfyz.cz">mailto:mam@matfyz.cz</a> a pošlete nám následující popis chyby: <code>{{ reason }}</code></p>
+
+  <img src="{% static 'various/img/zere_kostku.svg' %}">
+
+
+{% endblock %}
diff --git a/various/views.py b/various/views.py
index 91ea44a2..96d9a29d 100644
--- a/various/views.py
+++ b/various/views.py
@@ -1,3 +1,13 @@
+from django.http import HttpResponseForbidden
 from django.shortcuts import render
 
 # Create your views here.
+
+
+def csrf_error(request, reason=""):
+	""" Jednoduchý „template view“ (třída to být nemůže) pro CSRF chyby """
+	return render(
+		request, 'various/403_csrf.html',
+		{"url": request.META.get("HTTP_REFERER", None), "reason": reason},
+		status=HttpResponseForbidden.status_code,
+	)
diff --git a/vysledkovky/templates/vysledkovky/vysledkovka_cisla.html b/vysledkovky/templates/vysledkovky/vysledkovka_cisla.html
index ac53c811..4aa62953 100644
--- a/vysledkovky/templates/vysledkovky/vysledkovka_cisla.html
+++ b/vysledkovky/templates/vysledkovky/vysledkovka_cisla.html
@@ -4,11 +4,11 @@
         <th class='border-r'>#</th>
         <th class='border-r'>Jméno</th>
             {% for p in vysledkovka.temata_a_spol%}
-                <th class='border-r' id="problem{{ oznaceni_vysledkovky }}_{{ forloop.counter0 }}">{# <a href="{{ p.verejne_url }}"> #}{{ p.kod_v_rocniku }}{# </a> #}</th>
+                <th class='border-r' id="problem{{ oznaceni_vysledkovky }}_{{ forloop.counter0 }}">{# <a href="{{ p.verejne_url }}"> #}<span title="{{ p }}">{{ p.kod_v_rocniku }}</span>{# </a> #}</th>
 
                     {# TODELETE #}
                     {% for podproblemy in vysledkovka.podproblemy_iter.next %}
-                        <th class='border-r podproblem{{ oznaceni_vysledkovky }}_{{ forloop.parentloop.counter0 }} podproblem'>{# <a href="{{ podproblemy.verejne_url }}"> #}{{ podproblemy.kod_v_rocniku }}{# </a> #}</th>
+                        <th class='border-r podproblem{{ oznaceni_vysledkovky }}_{{ forloop.parentloop.counter0 }} podproblem'>{# <a href="{{ podproblemy.verejne_url }}"> #}<span title="{{ podproblemy }}">{{ podproblemy.kod_v_rocniku }}</span>{# </a> #}</th>
                     {% endfor %}
                 {# TODELETE #}
 
@@ -17,7 +17,7 @@
 
         {# TODELETE #}
         {% for podproblemy in vysledkovka.podproblemy_iter.next %}
-            <th class='border-r podproblem{{ oznaceni_vysledkovky }}_{{ vysledkovka.temata_a_spol| length }} podproblem'>{# <a href="{{ podproblemy.verejne_url }}"> #}{{ podproblemy.kod_v_rocniku }}{# </a> #}</th>
+            <th class='border-r podproblem{{ oznaceni_vysledkovky }}_{{ vysledkovka.temata_a_spol| length }} podproblem'>{# <a href="{{ podproblemy.verejne_url }}"> #}<span title="{{ podproblemy }}">{{ podproblemy.kod_v_rocniku }}</span>{# </a> #}</th>
         {% endfor %}
         {# TODELETE #}
 
diff --git a/vysledkovky/utils.py b/vysledkovky/utils.py
index 3ff59fb1..2036b9d3 100644
--- a/vysledkovky/utils.py
+++ b/vysledkovky/utils.py
@@ -257,7 +257,7 @@ class VysledkovkaCisla(Vysledkovka):
 		# (mají vlastní sloupeček ve výsledkovce, nemají nadproblém)
 		hlavni_problemy = set()
 		for p in self.problemy:
-			hlavni_problemy.add(p.hlavni_problem)
+			hlavni_problemy.add(p.hlavni_problem) # FIXME: proč tohle nemůže obsahovat reálné instance? Ve výsledkovce by se pak zobrazovaly správné kódy…
 
 		# zunikátnění
 		hlavni_problemy = list(hlavni_problemy)
@@ -313,7 +313,7 @@ class VysledkovkaCisla(Vysledkovka):
 
 		# Sečteme hodnocení
 		for hodnoceni in self.hodnoceni_do_cisla:
-			prob = hodnoceni.problem
+			prob = hodnoceni.problem.get_real_instance()
 			nadproblem = prob.hlavni_problem.id
 
 			# Když nadproblém není "téma", pak je "Ostatní"
@@ -366,18 +366,12 @@ class VysledkovkaCisla(Vysledkovka):
 		for problem in self.problemy:
 			h_problem = problem.hlavni_problem
 			if h_problem in temata_a_spol:
-				podproblemy[h_problem.id].append(problem)
+				podproblemy[h_problem.id].append(problem.get_real_instance())
 			else:
-				podproblemy[-1].append(problem)
+				podproblemy[-1].append(problem.get_real_instance())
 
 		for podproblem in podproblemy.keys():
-			def int_or_zero(p):
-				try:
-					return int(p.kod)
-				except ValueError:
-					return 0
-
-			podproblemy[podproblem] = sorted(podproblemy[podproblem], key=int_or_zero)
+			podproblemy[podproblem] = sorted(podproblemy[podproblem], key=lambda p: p.kod_v_rocniku)
 		return podproblemy
 
 	@cached_property