+ {% sitetree_menu from "main_menu" include "trunk" %}
+
+ {#
+ {% for item in menu_top %}
+
+ {{ item.name }}
+
+ {% if item.submenu %}
+
+ {% for menu in item.submenu %}
+
+ {% endfor %}
+
+ {% endif %}
+ {% endfor %}
+ #}
+
+
+
{% block content %}
{% endblock content %}
diff --git a/mamweb/urls.py b/mamweb/urls.py
index 6294fac4..0c8877a2 100644
--- a/mamweb/urls.py
+++ b/mamweb/urls.py
@@ -11,7 +11,6 @@ urlpatterns = [
# Admin a nastroje
path('admin/', admin.site.urls), # NOQA
path('ckeditor/', include('ckeditor_uploader.urls')),
- path('autocomplete/', include('autocomplete_light.urls')),
# Seminarova aplikace (ma vlastni podadresare)
path('', include('seminar.urls')),
diff --git a/requirements.txt b/requirements.txt
index 8dcb57b6..22f8e43c 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -22,11 +22,12 @@ django-solo
django-ckeditor
django-flat-theme
django-taggit
-django-autocomplete-light==2.3.6
+django-autocomplete-light
django-crispy-forms
django-imagekit
django-polymorphic
django-sitetree
+django_reverse_admin
# Comments
akismet==1.0.1
diff --git a/seminar/admin.py b/seminar/admin.py
index d02b4db7..6a9dd815 100644
--- a/seminar/admin.py
+++ b/seminar/admin.py
@@ -1,36 +1,171 @@
from django.contrib import admin
+from polymorphic.admin import PolymorphicParentModelAdmin, PolymorphicChildModelAdmin, PolymorphicChildModelFilter
+from reversion.admin import VersionAdmin
+from django_reverse_admin import ReverseModelAdmin
+
+# Todo: reversion
+
import seminar.models as m
-admin.site.register(m.Osoba)
admin.site.register(m.Skola)
admin.site.register(m.Prijemce)
-admin.site.register(m.Resitel)
admin.site.register(m.Rocnik)
admin.site.register(m.Cislo)
admin.site.register(m.Organizator)
admin.site.register(m.Soustredeni)
-admin.site.register(m.Problem)
-admin.site.register(m.Tema)
-admin.site.register(m.Clanek)
+
+@admin.register(m.Osoba)
+class OsobaAdmin(admin.ModelAdmin):
+ actions = ['synchronizuj_maily']
+
+ def synchronizuj_maily(self, request, queryset):
+ for o in queryset:
+ if o.user is not None:
+ u = o.user
+ u.email = o.email
+ u.save()
+ self.message_user(request, "E-maily synchronizovány.")
+ synchronizuj_maily.short_description = "Synchronizuj vybraným osobám e-maily do uživatelů"
+
+@admin.register(m.Problem)
+class ProblemAdmin(PolymorphicParentModelAdmin):
+ base_model = m.Problem
+ child_models = [
+ m.Tema,
+ m.Clanek,
+ m.Uloha,
+ ]
+
+@admin.register(m.Tema)
+class TemaAdmin(PolymorphicChildModelAdmin):
+ base_model = m.Tema
+ show_in_index = True
+
+@admin.register(m.Clanek)
+class ClanekAdmin(PolymorphicChildModelAdmin):
+ base_model = m.Clanek
+ show_in_index = True
+
+@admin.register(m.Uloha)
+class UlohaAdmin(PolymorphicChildModelAdmin):
+ base_model = m.Uloha
+ show_in_index = True
+
+class TextAdminInline(admin.TabularInline):
+ model = m.Text
+ exclude = ['text_zkraceny_set','text_zkraceny']
admin.site.register(m.Text)
-admin.site.register(m.Uloha)
-admin.site.register(m.Reseni)
-admin.site.register(m.Hodnoceni)
+
+class ResitelInline(admin.TabularInline):
+ model = m.Resitel
+ extra = 1
+admin.site.register(m.Resitel)
+
+class PrilohaReseniInline(admin.TabularInline):
+ model = m.PrilohaReseni
+ extra = 1
admin.site.register(m.PrilohaReseni)
+
+class Reseni_ResiteleInline(admin.TabularInline):
+ model = m.Reseni_Resitele
+
+@admin.register(m.Reseni)
+class ReseniAdmin(ReverseModelAdmin):
+ base_model = m.Reseni
+ inline_type = 'tabular'
+ inline_reverse = ['text_cely','resitele']
+ exclude = ['text_zkraceny', 'text_zkraceny_set']
+ inlines = [PrilohaReseniInline]
+# FAIL in template
+# inlines = [PrilohaReseniInline,Reseni_ResiteleInline]
+
+admin.site.register(m.Hodnoceni)
admin.site.register(m.Pohadka)
admin.site.register(m.Konfera)
admin.site.register(m.Obrazek)
-admin.site.register(m.TreeNode)
-admin.site.register(m.RocnikNode)
-admin.site.register(m.CisloNode)
-admin.site.register(m.MezicisloNode)
-admin.site.register(m.TemaVCisleNode)
-admin.site.register(m.KonferaNode)
-admin.site.register(m.ClanekNode)
-admin.site.register(m.UlohaZadaniNode)
-admin.site.register(m.PohadkaNode)
-admin.site.register(m.UlohaVzorakNode)
-admin.site.register(m.TextNode)
+
+
+# Polymorfismus pro stromy
+# TODO: Inlines podle https://django-polymorphic.readthedocs.io/en/stable/admin.html
+
+@admin.register(m.TreeNode)
+class TreeNodeAdmin(PolymorphicParentModelAdmin):
+ base_model = m.TreeNode
+ child_models = [
+ m.RocnikNode,
+ m.CisloNode,
+ m.MezicisloNode,
+ m.TemaVCisleNode,
+ m.KonferaNode,
+ m.ClanekNode,
+ m.UlohaZadaniNode,
+ m.PohadkaNode,
+ m.UlohaVzorakNode,
+ m.TextNode,
+ ]
+
+ actions = ['aktualizuj_nazvy']
+
+ # XXX: nejspíš je to totální DB HOG, nechcete to použít moc často.
+ def aktualizuj_nazvy(self, request, queryset):
+ newqs = queryset.get_real_instances()
+ for tn in newqs:
+ tn.aktualizuj_nazev()
+ tn.save()
+ self.message_user(request, "Názvy aktualizovány.")
+ aktualizuj_nazvy.short_description = "Aktualizuj vybraným TreeNodům názvy"
+
+@admin.register(m.RocnikNode)
+class RocnikNodeAdmin(PolymorphicChildModelAdmin):
+ base_model = m.RocnikNode
+ show_in_index = True
+
+@admin.register(m.CisloNode)
+class CisloNodeAdmin(PolymorphicChildModelAdmin):
+ base_model = m.CisloNode
+ show_in_index = True
+
+@admin.register(m.MezicisloNode)
+class MezicisloNodeAdmin(PolymorphicChildModelAdmin):
+ base_model = m.MezicisloNode
+ show_in_index = True
+
+@admin.register(m.TemaVCisleNode)
+class TemaVCisleNodeAdmin(PolymorphicChildModelAdmin):
+ base_model = m.TemaVCisleNode
+ show_in_index = True
+
+@admin.register(m.KonferaNode)
+class KonferaNodeAdmin(PolymorphicChildModelAdmin):
+ base_model = m.KonferaNode
+ show_in_index = True
+
+@admin.register(m.ClanekNode)
+class ClanekNodeAdmin(PolymorphicChildModelAdmin):
+ base_model = m.ClanekNode
+ show_in_index = True
+
+@admin.register(m.UlohaZadaniNode)
+class UlohaZadaniNodeAdmin(PolymorphicChildModelAdmin):
+ base_model = m.UlohaZadaniNode
+ show_in_index = True
+
+@admin.register(m.PohadkaNode)
+class PohadkaNodeAdmin(PolymorphicChildModelAdmin):
+ base_model = m.PohadkaNode
+ show_in_index = True
+
+@admin.register(m.UlohaVzorakNode)
+class UlohaVzorakNodeAdmin(PolymorphicChildModelAdmin):
+ base_model = m.UlohaVzorakNode
+ show_in_index = True
+
+@admin.register(m.TextNode)
+class TextNodeAdmin(PolymorphicChildModelAdmin):
+ base_model = m.TextNode
+ show_in_index = True
+
+
admin.site.register(m.Nastaveni)
admin.site.register(m.Novinky)
diff --git a/seminar/autocomplete_light_registry.py b/seminar/autocomplete_light_registry.py.old
similarity index 100%
rename from seminar/autocomplete_light_registry.py
rename to seminar/autocomplete_light_registry.py.old
diff --git a/seminar/forms.py b/seminar/forms.py
index 693e36df..6a0e7911 100644
--- a/seminar/forms.py
+++ b/seminar/forms.py
@@ -1,6 +1,257 @@
from django import forms
+from dal import autocomplete
+from django.core.exceptions import ObjectDoesNotExist
+from django.contrib.auth.models import User
+
+from .models import Skola, Resitel, Osoba, Problem
+import seminar.models as m
+
+from datetime import date
+import logging
+
+class LoginForm(forms.Form):
+ username = forms.CharField(label='Přihlašovací jméno',
+ max_length=256,
+ required=True)
+ password = forms.CharField(
+ label='Heslo',
+ max_length=256,
+ required=True,
+ widget=forms.PasswordInput())
+
+
+class PrihlaskaForm(forms.Form):
+ username = forms.CharField(label='Přihlašovací jméno',
+ max_length=256,
+ required=True,
+ help_text='Tímto jménem se následně budeš přihlašovat pro odevzdání řešení a další činnosti v semináři')
+ password = forms.CharField(
+ label='Heslo',
+ max_length=256,
+ required=True,
+ widget=forms.PasswordInput())
+ password_check = forms.CharField(
+ label='Ověření hesla',
+ max_length=256,
+ required=True,
+ widget=forms.PasswordInput())
+
+ jmeno = forms.CharField(label='Jméno', max_length=256, required=True)
+ prijmeni = forms.CharField(label='Příjmení', max_length=256, required=True)
+ pohlavi_muz = forms.ChoiceField(label='Pohlaví',
+ choices = ((True,'muž'),(False,'žena')), required=True)
+ email = forms.EmailField(label='E-mail',max_length=256, required=True)
+ telefon = forms.CharField(label='Telefon',max_length=256, required=False)
+ datum_narozeni = forms.DateField(label='Datum narození', required=False)
+ ulice = forms.CharField(label='Ulice', max_length=256, required=False)
+ mesto = forms.CharField(label='Město', max_length=256, required=False)
+ psc = forms.CharField(label='PSČ', max_length=32, required=False)
+ stat = forms.ChoiceField(label='Stát',
+ choices = (('CZ', 'Česká Republika'),
+ ('SK', 'Slovenská Republika'),
+ ('other', 'Jiné')),
+ required=False)
+ stat_text = forms.CharField(label='Stát', max_length=256, required=False)
+
+ skola = forms.ModelChoiceField(label="Škola",
+ queryset=Skola.objects.all(),
+ widget=autocomplete.ModelSelect2(
+ url='autocomplete_skola',
+ attrs = {'data-placeholder--id': '-1',
+ 'data-placeholder--text' : '---',
+ 'data-allow-clear': 'true'})
+ ,required=False)
+
+ skola_nazev = forms.CharField(label='Název školy', max_length=256, required=False)
+ skola_adresa = forms.CharField(label='Adresa školy', max_length=256, required=False)
+
+# trida = forms.CharField(label='Třída',max_length=10, required=True)
+
+ rok_maturity = forms.IntegerField(
+ label='Rok maturity',
+ min_value=date.today().year,
+ max_value=date.today().year+8,
+ required=True)
+ zasilat = forms.ChoiceField(label='Kam zasílat čísla a řešení',choices = Resitel.ZASILAT_CHOICES, required=True)
+ gdpr = forms.BooleanField(label='Souhlasím se zpracováním osobních údajů', required=True)
+ spam = forms.BooleanField(label='Souhlasím se zasíláním materiálů od MFF UK', required=False)
+
+ def clean_username(self):
+ err_logger = logging.getLogger('seminar.prihlaska.problem')
+ username = self.cleaned_data.get('username')
+ try:
+ User.objects.get(username=username)
+ msg = "Username {} exists".format(username)
+ err_logger.info(msg)
+ raise forms.ValidationError('Přihlašovací jméno je již použito')
+
+ except ObjectDoesNotExist:
+ pass
+ return username
+
+ def clean_email(self):
+ err_logger = logging.getLogger('seminar.prihlaska.problem')
+ email = self.cleaned_data.get('email')
+ try:
+ Osoba.objects.get(email=email)
+ msg = "Email {} exists".format(email)
+ err_logger.info(msg)
+ raise forms.ValidationError('Email je již použit')
+
+ except ObjectDoesNotExist:
+ pass
+ return email
+
+
+ def clean(self):
+ super().clean()
+
+ err_logger = logging.getLogger('seminar.prihlaska.problem')
+
+ data = self.cleaned_data
+ if data.get('password') != data.get('password_check'):
+ self.add_error('password_check',forms.ValidationError('Hesla se neshodují'))
+ if data.get('stat') != '' and data.get('stat_text') != '':
+ self.add_error('stat',forms.ValidationError('Nelze mít vybraný stát z menu a zároven zapsaný textem'))
+ if data.get('skola') and (data.get('skola_nazev') or data.get('skola_adresa')):
+ self.add_error('skola',forms.ValidationError('Pokud je škola v seznamu, nevypisujte ji ručně, pokud není, zrušte výběr ze seznamu (křížek vpravo)'))
+ if not data.get('skola'):
+ if data.get('skola_nazev')=='' and data.get('skola_adresa')=='':
+ self.add_error('skola',forms.ValidationError('Je nutné vyplnit školu'))
+ elif data.get('skola_nazev')=='':
+ self.add_error('skola_nazev',forms.ValidationError('Je nutné vyplnit název školy'))
+ elif data.get('skola_adresa')=='':
+ self.add_error('skola_adresa',forms.ValidationError('Je nutné vyplnit adresu školy'))
+
+
+class ProfileEditForm(forms.Form):
+ username = forms.CharField(label='Přihlašovací jméno',
+ max_length=256,
+ required=True)
+
+ jmeno = forms.CharField(label='Jméno', max_length=256, required=True)
+ prijmeni = forms.CharField(label='Příjmení', max_length=256, required=True)
+ pohlavi_muz = forms.ChoiceField(label='Pohlaví',
+ choices = ((True,'muž'),(False,'žena')), required=True)
+ email = forms.EmailField(label='E-mail',max_length=256, required=True)
+ telefon = forms.CharField(label='Telefon',max_length=256, required=False)
+ datum_narozeni = forms.DateField(label='Datum narození', required=False)
+ ulice = forms.CharField(label='Ulice', max_length=256, required=False)
+ mesto = forms.CharField(label='Město', max_length=256, required=False)
+ psc = forms.CharField(label='PSČ', max_length=32, required=False)
+ stat = forms.ChoiceField(label='Stát',
+ choices = (('CZ', 'Česká Republika'),
+ ('SK', 'Slovenská Republika'),
+ ('other', 'Jiné')),
+ required=False)
+ stat_text = forms.CharField(label='Stát', max_length=256, required=False)
+
+ skola = forms.ModelChoiceField(label="Škola",
+ queryset=Skola.objects.all(),
+ widget=autocomplete.ModelSelect2(
+ url='autocomplete_skola',
+ attrs = {'data-placeholder--id': '-1',
+ 'data-placeholder--text' : '---',
+ 'data-allow-clear': 'true'})
+ ,required=False)
+
+ skola_nazev = forms.CharField(label='Název školy', max_length=256, required=False)
+ skola_adresa = forms.CharField(label='Adresa školy', max_length=256, required=False)
+
+# trida = forms.CharField(label='Třída',max_length=10, required=True)
+
+ rok_maturity = forms.IntegerField(
+ label='Rok maturity',
+ min_value=date.today().year,
+ max_value=date.today().year+8,
+ required=True)
+ zasilat = forms.ChoiceField(label='Kam zasílat čísla a řešení',choices = Resitel.ZASILAT_CHOICES, required=True)
+ spam = forms.BooleanField(label='Souhlasím se zasíláním materiálů od MFF UK', required=False)
+# def clean_username(self):
+# err_logger = logging.getLogger('seminar.prihlaska.problem')
+# username = self.cleaned_data.get('username')
+# try:
+# User.objects.get(username=username)
+# msg = "Username {} exists".format(username)
+# err_logger.info(msg)
+# raise forms.ValidationError('Přihlašovací jméno je již použito')
+#
+# except ObjectDoesNotExist:
+# pass
+# return username
+#
+# def clean_email(self):
+# err_logger = logging.getLogger('seminar.prihlaska.problem')
+# email = self.cleaned_data.get('email')
+# try:
+# Osoba.objects.get(email=email)
+# msg = "Email {} exists".format(email)
+# err_logger.info(msg)
+# raise forms.ValidationError('Email je již použit')
+#
+# except ObjectDoesNotExist:
+# pass
+# return email
+ #def clean(self):
+ # super().clean()
+ #
+ # err_logger = logging.getLogger('seminar.prihlaska.problem')
+
+ # data = self.cleaned_data
+ # if data.get('password') != data.get('password_check'):
+ # self.add_error('password_check',forms.ValidationError('Hesla se neshodují'))
+ # if data.get('stat') != '' and data.get('stat_text') != '':
+ # self.add_error('stat',forms.ValidationError('Nelze mít vybraný stát z menu a zároven zapsaný textem'))
+ # if data.get('skola') and (data.get('skola_nazev') or data.get('skola_adresa')):
+ # self.add_error('skola',forms.ValidationError('Pokud je škola v seznamu, nevypisujte ji ručně, pokud není, zrušte výběr ze seznamu (křížek vpravo)'))
+ # if not data.get('skola'):
+ # if data.get('skola_nazev')=='' and data.get('skola_adresa')=='':
+ # self.add_error('skola',forms.ValidationError('Je nutné vyplnit školu'))
+ # elif data.get('skola_nazev')=='':
+ # self.add_error('skola_nazev',forms.ValidationError('Je nutné vyplnit název školy'))
+ # elif data.get('skola_adresa')=='':
+ # self.add_error('skola_adresa',forms.ValidationError('Je nutné vyplnit adresu školy'))
+
+class VlozReseniForm(forms.Form):
+ #FIXME jen podproblémy daného problému
+ problem = forms.ModelChoiceField(label='Problém',queryset=m.Problem.objects.all())
+ # to_field_name
+ #problem = models.ManyToManyField(Problem, verbose_name='problém', help_text='Problém',
+ # through='Hodnoceni')
+
+ # FIXME pridat vice resitelu
+ resitel = forms.ModelChoiceField(label="Řešitel",
+ queryset=Resitel.objects.all(),
+ widget=autocomplete.ModelSelect2(
+ url='autocomplete_resitel',
+ attrs = {'data-placeholder--id': '-1',
+ 'data-placeholder--text' : '---',
+ 'data-allow-clear': 'true'})
+ )
+
+
+ #resitele = models.ManyToManyField(Resitel, verbose_name='autoři řešení',
+ # help_text='Seznam autorů řešení', through='Reseni_Resitele')
+
+ cas_doruceni = forms.DateField(label="Čas doručení")
+
+ #cas_doruceni = models.DateTimeField('čas_doručení', default=timezone.now, blank=True)
+
+ forma = forms.ChoiceField(label="Forma řešení",choices = m.Reseni.FORMA_CHOICES)
+ #forma = models.CharField('forma řešení', max_length=16, choices=FORMA_CHOICES, blank=False,
+ # default=FORMA_EMAIL)
+
+ poznamka = forms.CharField(label='Neveřejná poznámka')
+ #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 NameForm(forms.Form):
- your_name = forms.CharField(label='Your name', max_length=100)
diff --git a/seminar/management/commands/nukedb.py b/seminar/management/commands/nukedb.py
new file mode 100644
index 00000000..f253841a
--- /dev/null
+++ b/seminar/management/commands/nukedb.py
@@ -0,0 +1,20 @@
+from mamweb.settings import INSTALLED_APPS
+from django.core.management.base import BaseCommand, CommandError
+from django.core.management import call_command
+
+class Command(BaseCommand):
+ help = "Odmigruje všechny moduly (i.e. smaže všechny tabulky, ale databázi nechá)"
+
+ def add_arguments(self, parser):
+ # TODO: --force (makat a neblábolit)
+ pass
+ def handle(self, *args, **options):
+ # TODO: zeptat se
+ for app in INSTALLED_APPS:
+ app = app.split('.')[-1]
+ try:
+ call_command('migrate', app, 'zero')
+ except CommandError:
+ # app nemá migrace (aspoň typicky)
+ pass
+ call_command('showmigrations')
diff --git a/seminar/management/commands/testdata.py b/seminar/management/commands/testdata.py
index 6a7fb30c..d7c65367 100644
--- a/seminar/management/commands/testdata.py
+++ b/seminar/management/commands/testdata.py
@@ -15,21 +15,34 @@ User = django.contrib.auth.get_user_model()
class Command(BaseCommand):
- help = "Clear database and load testing data."
-
- def handle(self, *args, **options):
- assert settings.DEBUG == True
- dbfile = settings.DATABASES['default']['NAME']
- if os.path.exists(dbfile):
- os.rename(dbfile, dbfile + '.old')
- self.stderr.write('Stara databaze prejmenovana na "%s"' % (dbfile + '.old'))
- call_command('migrate', no_input=True)
- self.stdout.write('Vytvarim uzivatele "admin" (heslo "admin") a pseudo-nahodna data ...')
- create_test_data(size=8)
- self.stdout.write('Vytvoreno {} uzivatelu, {} skol, {} resitelu, {} rocniku, {} cisel,'
- ' {} problemu, {} reseni.'.format(User.objects.count(), Skola.objects.count(),
- Resitel.objects.count(), Rocnik.objects.count(), Cislo.objects.count(),
- Problem.objects.count(), Reseni.objects.count()))
+ help = "Clear database and load testing data."
+
+ def add_arguments(self, parser):
+ parser.add_argument(
+ '--no-clean',
+ action='store_true',
+ help='Změny se provedou v aktuální DB, ne v čisté. Aktuální DB se nezachová. (jen k debugování)',
+ )
+ parser.add_argument(
+ '--no-migrate',
+ action='store_true',
+ help='Neprovádět migrace před generováním testovacích dat (jen k debugování)',
+ )
+
+ def handle(self, *args, **options):
+ assert settings.DEBUG == True
+ dbfile = settings.DATABASES['default']['NAME']
+ if os.path.exists(dbfile) and not options['no_clean']:
+ os.rename(dbfile, dbfile + '.old')
+ self.stderr.write('Stara databaze prejmenovana na "%s"' % (dbfile + '.old'))
+ if not options['no_migrate']:
+ call_command('migrate', no_input=True)
+ self.stdout.write('Vytvarim uzivatele "admin" (heslo "admin") a pseudo-nahodna data ...')
+ create_test_data(size=8)
+ self.stdout.write('Vytvoreno {} uzivatelu, {} skol, {} resitelu, {} rocniku, {} cisel,'
+ ' {} problemu, {} reseni.'.format(User.objects.count(), Skola.objects.count(),
+ Resitel.objects.count(), Rocnik.objects.count(), Cislo.objects.count(),
+ Problem.objects.count(), Reseni.objects.count()))
diff --git a/seminar/migrations/0065_treenode_polymorphic_ctype.py b/seminar/migrations/0065_treenode_polymorphic_ctype.py
new file mode 100644
index 00000000..71eef262
--- /dev/null
+++ b/seminar/migrations/0065_treenode_polymorphic_ctype.py
@@ -0,0 +1,31 @@
+# Generated by Django 2.2.4 on 2019-08-13 19:36
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+def vyrob_treenodum_ctypes(apps, schema_editor):
+ # Kód zkopírovaný z dokumentace: https://django-polymorphic.readthedocs.io/en/stable/migrating.html
+ # XXX: Nevím, jestli se tohle náhodou nemělo spustit na všech childech (jen/i)
+ TreeNode = apps.get_model('seminar', 'TreeNode')
+ ContentType = apps.get_model('contenttypes', 'ContentType')
+
+ new_ct = ContentType.objects.get_for_model(TreeNode)
+ TreeNode.objects.filter(polymorphic_ctype__isnull=True).update(polymorphic_ctype=new_ct)
+
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('contenttypes', '0002_remove_content_type_name'),
+ ('seminar', '0064_auto_20190610_2358'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='treenode',
+ name='polymorphic_ctype',
+ field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_seminar.treenode_set+', to='contenttypes.ContentType'),
+ ),
+ migrations.RunPython(vyrob_treenodum_ctypes, migrations.RunPython.noop),
+ ]
diff --git a/seminar/migrations/0066_problem_polymorphic_ctype.py b/seminar/migrations/0066_problem_polymorphic_ctype.py
new file mode 100644
index 00000000..f956217e
--- /dev/null
+++ b/seminar/migrations/0066_problem_polymorphic_ctype.py
@@ -0,0 +1,29 @@
+# Generated by Django 2.2.4 on 2019-08-13 19:45
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+def vyrob_problemum_ctypes(apps, schema_editor):
+ # Kód zkopírovaný z dokumentace: https://django-polymorphic.readthedocs.io/en/stable/migrating.html
+ # XXX: Nevím, jestli se tohle náhodou nemělo spustit na všech childech (jen/i)
+ Problem = apps.get_model('seminar', 'Problem')
+ ContentType = apps.get_model('contenttypes', 'ContentType')
+
+ new_ct = ContentType.objects.get_for_model(Problem)
+ Problem.objects.filter(polymorphic_ctype__isnull=True).update(polymorphic_ctype=new_ct)
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('contenttypes', '0002_remove_content_type_name'),
+ ('seminar', '0065_treenode_polymorphic_ctype'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='problem',
+ name='polymorphic_ctype',
+ field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_seminar.problem_set+', to='contenttypes.ContentType'),
+ ),
+ migrations.RunPython(vyrob_problemum_ctypes, migrations.RunPython.noop),
+ ]
diff --git a/seminar/migrations/0067_auto_20190814_0805.py b/seminar/migrations/0067_auto_20190814_0805.py
new file mode 100644
index 00000000..8a72a659
--- /dev/null
+++ b/seminar/migrations/0067_auto_20190814_0805.py
@@ -0,0 +1,18 @@
+# Generated by Django 2.2.4 on 2019-08-14 06:05
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('seminar', '0066_problem_polymorphic_ctype'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='konfera',
+ name='nazev',
+ field=models.CharField(help_text='Název konfery', max_length=100, verbose_name='název konfery'),
+ ),
+ ]
diff --git a/seminar/migrations/0068_treenode_nazev.py b/seminar/migrations/0068_treenode_nazev.py
new file mode 100644
index 00000000..bead85d3
--- /dev/null
+++ b/seminar/migrations/0068_treenode_nazev.py
@@ -0,0 +1,107 @@
+# Generated by Django 2.2.5 on 2019-09-26 19:35
+
+from django.db import migrations, models
+
+# Migrace nejspíš neumí volat metody modelů:
+# https://stackoverflow.com/questions/28777338/django-migrations-runpython-not-able-to-call-model-methods#37685925
+
+def fix_RocnikNode_names(apps,schema_editor):
+ Objects = apps.get_model('seminar', 'RocnikNode')
+ for obj in Objects.objects.all():
+ obj.nazev = str(obj.rocnik)+" (RocnikNode)"
+ obj.save()
+
+def fix_CisloNode_names(apps,schema_editor):
+ Objects = apps.get_model('seminar', 'CisloNode')
+ for obj in Objects.objects.all():
+ obj.nazev = str(obj.cislo)+" (CisloNode)"
+ obj.save()
+
+def fix_MezicisloNode_names(apps,schema_editor):
+ Objects = apps.get_model('seminar', 'MezicisloNode')
+ for obj in Objects.objects.all():
+ if obj.prev:
+ if (obj.prev.get_real_instance_class() != CisloNode and
+ obj.prev.get_real_instance_class() != MezicisloNode):
+ raise ValueError("Předchůdce není číslo!")
+ posledni = obj.prev.cislo
+ obj.nazev = "Mezičíslo po čísle"+str(posledni)+" (MezicisloNode)"
+ elif obj.root:
+ if obj.root.get_real_instance_class() != RocnikNode:
+ raise ValueError("Kořen stromu není ročník!")
+ rocnik = obj.root.rocnik
+ obj.nazev = "První mezičíslo ročníku "+" (MezicisloNode)"
+ else:
+ print("!!!!! Nějaké neidentifikované mezičíslo !!!!!")
+ obj.nazev = "Neidentifikovatelné mezičíslo! (MezicisloNode)"
+ obj.save()
+
+def fix_TemaVCisleNode_names(apps,schema_editor):
+ Objects = apps.get_model('seminar', 'TemaVCisleNode')
+ for obj in Objects.objects.all():
+ obj.nazev = str(obj.tema)+" (TemaVCisleNode)"
+ obj.save()
+
+def fix_KonferaNode_names(apps,schema_editor):
+ Objects = apps.get_model('seminar', 'KonferaNode')
+ for obj in Objects.objects.all():
+ obj.nazev = str(obj.konfera)+" (KonferaNode)"
+ obj.save()
+
+def fix_ClanekNode_names(apps,schema_editor):
+ Objects = apps.get_model('seminar', 'ClanekNode')
+ for obj in Objects.objects.all():
+ obj.nazev = str(obj.clanek)+" (ClanekNode)"
+ obj.save()
+
+def fix_UlohaZadaniNode_names(apps,schema_editor):
+ Objects = apps.get_model('seminar', 'UlohaZadaniNode')
+ for obj in Objects.objects.all():
+ obj.nazev = str(obj.uloha)+" (UlohaZadaniNode)"
+ obj.save()
+
+def fix_PohadkaNode_names(apps,schema_editor):
+ Objects = apps.get_model('seminar', 'PohadkaNode')
+ for obj in Objects.objects.all():
+ obj.nazev = str(obj.pohadka)+" (PohadkaNode)"
+ obj.save()
+
+def fix_UlohaVzorakNode_names(apps,schema_editor):
+ Objects = apps.get_model('seminar', 'UlohaVzorakNode')
+ for obj in Objects.objects.all():
+ obj.nazev = str(obj.uloha)+" (UlohaVzorakNode)"
+ obj.save()
+
+def fix_TextNode_names(apps,schema_editor):
+ Objects = apps.get_model('seminar', 'TextNode')
+ for obj in Objects.objects.all():
+ obj.nazev = str(obj.text)+" (TextNode)"
+ obj.save()
+
+def fix_all_names(apps,schema_editor):
+ fix_RocnikNode_names(apps,schema_editor)
+ fix_CisloNode_names(apps,schema_editor)
+ fix_MezicisloNode_names(apps,schema_editor)
+ fix_TemaVCisleNode_names(apps,schema_editor)
+ fix_KonferaNode_names(apps,schema_editor)
+ fix_ClanekNode_names(apps,schema_editor)
+ fix_UlohaZadaniNode_names(apps,schema_editor)
+ fix_PohadkaNode_names(apps,schema_editor)
+ fix_UlohaVzorakNode_names(apps,schema_editor)
+ fix_TextNode_names(apps,schema_editor)
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('seminar', '0067_auto_20190814_0805'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='treenode',
+ name='nazev',
+ field=models.TextField(help_text='Tento název se zobrazuje v nabídkách pro výběr vhodného TreeNode', null=True, verbose_name='název tohoto node'),
+ ),
+ migrations.RunPython(fix_all_names),
+ ]
diff --git a/seminar/migrations/0069_auto_20191120_2115.py b/seminar/migrations/0069_auto_20191120_2115.py
new file mode 100644
index 00000000..04c6d1dc
--- /dev/null
+++ b/seminar/migrations/0069_auto_20191120_2115.py
@@ -0,0 +1,28 @@
+# Generated by Django 2.2.7 on 2019-11-20 20:15
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('seminar', '0068_treenode_nazev'),
+ ]
+
+ operations = [
+ migrations.AlterModelOptions(
+ name='cislo',
+ options={'ordering': ['-rocnik__rocnik', '-poradi'], 'verbose_name': 'Číslo', 'verbose_name_plural': 'Čísla'},
+ ),
+ migrations.RenameField(
+ model_name='cislo',
+ old_name='cislo',
+ new_name='poradi',
+ ),
+ migrations.AlterField(
+ model_name='problem',
+ name='nadproblem',
+ field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='podproblem', to='seminar.Problem', verbose_name='nadřazený problém'),
+ ),
+ ]
diff --git a/seminar/migrations/0070_auto_20191120_2357.py b/seminar/migrations/0070_auto_20191120_2357.py
new file mode 100644
index 00000000..3bd5466f
--- /dev/null
+++ b/seminar/migrations/0070_auto_20191120_2357.py
@@ -0,0 +1,23 @@
+# Generated by Django 2.2.7 on 2019-11-20 22:57
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('seminar', '0069_auto_20191120_2115'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='tema',
+ name='abstrakt',
+ field=models.TextField(blank=True, verbose_name='Abstrakt na rozcestník'),
+ ),
+ migrations.AddField(
+ model_name='tema',
+ name='obrazek',
+ field=models.ImageField(null=True, upload_to='', verbose_name='Obrázek na rozcestník'),
+ ),
+ ]
diff --git a/seminar/migrations/0071_remove_nastaveni_aktualni_rocnik.py b/seminar/migrations/0071_remove_nastaveni_aktualni_rocnik.py
new file mode 100644
index 00000000..d20c1501
--- /dev/null
+++ b/seminar/migrations/0071_remove_nastaveni_aktualni_rocnik.py
@@ -0,0 +1,17 @@
+# Generated by Django 2.2.7 on 2019-11-21 17:38
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('seminar', '0070_auto_20191120_2357'),
+ ]
+
+ operations = [
+ migrations.RemoveField(
+ model_name='nastaveni',
+ name='aktualni_rocnik',
+ ),
+ ]
diff --git a/seminar/migrations/0072_auto_20191204_2257.py b/seminar/migrations/0072_auto_20191204_2257.py
new file mode 100644
index 00000000..f96b670a
--- /dev/null
+++ b/seminar/migrations/0072_auto_20191204_2257.py
@@ -0,0 +1,23 @@
+# Generated by Django 2.2.7 on 2019-12-04 21:57
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('seminar', '0071_remove_nastaveni_aktualni_rocnik'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='treenode',
+ name='srolovatelne',
+ field=models.BooleanField(blank=True, help_text='Bude na stránce témátka možnost tuto položku skrýt', null=True, verbose_name='Srolovatelné'),
+ ),
+ migrations.AddField(
+ model_name='treenode',
+ name='zajimave',
+ field=models.BooleanField(default=False, help_text='Zobrazí se daná věc na rozcestníku témátek', verbose_name='Zajímavé'),
+ ),
+ ]
diff --git a/seminar/migrations/0073_copy_osoba_email_to_user_email.py b/seminar/migrations/0073_copy_osoba_email_to_user_email.py
new file mode 100644
index 00000000..3b280209
--- /dev/null
+++ b/seminar/migrations/0073_copy_osoba_email_to_user_email.py
@@ -0,0 +1,22 @@
+# Generated by Django 2.2.9 on 2020-01-15 21:28
+
+from django.db import migrations
+
+def copy_mails(apps, schema_editor):
+ Osoba = apps.get_model('seminar', 'Osoba')
+
+ for o in Osoba.objects.all():
+ if o.user is not None:
+ u = o.user
+ u.email = o.email
+ u.save()
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('seminar', '0072_auto_20191204_2257'),
+ ]
+
+ operations = [
+ migrations.RunPython(copy_mails, migrations.RunPython.noop)
+ ]
diff --git a/seminar/models.py b/seminar/models.py
index e87aa325..f8c41ed0 100644
--- a/seminar/models.py
+++ b/seminar/models.py
@@ -21,10 +21,11 @@ from taggit.managers import TaggableManager
from reversion import revisions as reversion
-from seminar.utils import roman
+from seminar.utils import roman, FirstTagParser # Pro získání úryvku z TextNode
-from unidecode import unidecode
+from unidecode import unidecode # Používám pro získání ID odkazu (ještě je to někde po někom zakomentované)
+from polymorphic.models import PolymorphicModel
class SeminarModelBase(models.Model):
@@ -129,6 +130,17 @@ class Osoba(SeminarModelBase):
def __str__(self):
return self.plne_jmeno()
+ # Overridujeme save Osoby, aby když si změní e-mail, aby se projevil i v
+ # Userovi (a tak se dal poslat mail s resetem hesla)
+ def save(self, *args, **kwargs):
+ if self.user is not None:
+ u = self.user
+ # U svatého tučňáka, prosím ať tohle funguje.
+ # (Takhle se kódit asi nemá...)
+ u.email = self.email
+ u.save()
+ super().save()
+
#
# Mělo by být částečně vytaženo z Aesopa
# viz https://ovvp.mff.cuni.cz/wiki/aesop/export-skol.
@@ -352,7 +364,7 @@ class Rocnik(SeminarModelBase):
def verejna_cisla(self):
vc = [c for c in self.cisla.all() if c.verejne()]
- vc.sort(key=lambda c: c.cislo)
+ vc.sort(key=lambda c: c.poradi)
return vc
def posledni_verejne_cislo(self):
@@ -361,7 +373,7 @@ class Rocnik(SeminarModelBase):
def verejne_vysledkovky_cisla(self):
vc = list(self.cisla.filter(verejna_vysledkovka=True))
- vc.sort(key=lambda c: c.cislo)
+ vc.sort(key=lambda c: c.poradi)
return vc
def posledni_zverejnena_vysledkovka_cislo(self):
@@ -383,10 +395,18 @@ class Rocnik(SeminarModelBase):
cache.set(name, c, 300)
return c
+ def save(self, *args, **kwargs):
+ super().save(*args, **kwargs)
+ # *Node.save() aktualizuje název *Nodu.
+ try:
+ self.rocniknode.save()
+ except ObjectDoesNotExist:
+ # Neexistující *Node nemá smysl aktualizovat.
+ pass
def cislo_pdf_filename(self, filename):
rocnik = str(self.rocnik.rocnik)
- return os.path.join('cislo', 'pdf', rocnik, '{}-{}.pdf'.format(rocnik, self.cislo))
+ return os.path.join('cislo', 'pdf', rocnik, '{}-{}.pdf'.format(rocnik, self.poradi))
@reversion.register(ignore_duplicates=True)
class Cislo(SeminarModelBase):
@@ -395,7 +415,7 @@ class Cislo(SeminarModelBase):
db_table = 'seminar_cisla'
verbose_name = 'Číslo'
verbose_name_plural = 'Čísla'
- ordering = ['-rocnik__rocnik', '-cislo']
+ ordering = ['-rocnik__rocnik', '-poradi']
# Interní ID
id = models.AutoField(primary_key = True)
@@ -403,7 +423,7 @@ class Cislo(SeminarModelBase):
rocnik = models.ForeignKey(Rocnik, verbose_name='ročník', related_name='cisla',
db_index=True,on_delete=models.PROTECT)
- cislo = models.CharField('název čísla', max_length=32, db_index=True,
+ poradi = models.CharField('název čísla', max_length=32, db_index=True,
help_text='Většinou jen "1", vyjímečně "7-8", lexikograficky určuje pořadí v ročníku!')
datum_vydani = models.DateField('datum vydání', blank=True, null=True,
@@ -436,20 +456,20 @@ class Cislo(SeminarModelBase):
# CisloNode
def kod(self):
- return '%s.%s' % (self.rocnik.rocnik, self.cislo)
+ return '%s.%s' % (self.rocnik.rocnik, self.poradi)
kod.short_description = 'Kód čísla'
def __str__(self):
# Potenciální DB HOG, pokud by se ročník necachoval
r = Rocnik.cached_rocnik(self.rocnik_id)
- return '{}.{}'.format(r.rocnik, self.cislo)
+ return '{}.{}'.format(r.rocnik, self.poradi)
def verejne(self):
return self.verejne_db
verejne.boolean = True
def verejne_url(self):
- return reverse('seminar_cislo', kwargs={'rocnik': self.rocnik.rocnik, 'cislo': self.cislo})
+ return reverse('seminar_cislo', kwargs={'rocnik': self.rocnik.rocnik, 'cislo': self.poradi})
def nasledujici(self):
"Vrací None, pokud je toto poslední"
@@ -471,11 +491,20 @@ class Cislo(SeminarModelBase):
def get(cls, rocnik, cislo):
try:
r = Rocnik.objects.get(rocnik=rocnik)
- c = r.cisla.get(cislo=cislo)
+ c = r.cisla.get(poradi=cislo)
except ObjectDoesNotExist:
return None
return c
+ def save(self, *args, **kwargs):
+ super().save(*args, **kwargs)
+ # *Node.save() aktualizuje název *Nodu.
+ try:
+ self.cislonode.save()
+ except ObjectDoesNotExist:
+ # Neexistující *Node nemá smysl aktualizovat.
+ pass
+
@reversion.register(ignore_duplicates=True)
class Organizator(SeminarModelBase):
# zmena dedicnosti z models.Model na SeminarModelBase, potencialni vznik bugu
@@ -583,7 +612,8 @@ class Soustredeni(SeminarModelBase):
@reversion.register(ignore_duplicates=True)
-class Problem(SeminarModelBase):
+# Pozor na následující řádek. *Nekrmit, asi kouše!*
+class Problem(SeminarModelBase,PolymorphicModel):
class Meta:
# Není abstraktní, protože se na něj jinak nedají dělat ForeignKeys.
@@ -601,11 +631,11 @@ class Problem(SeminarModelBase):
id = models.AutoField(primary_key = True)
# Název
- nazev = models.CharField('název', max_length=256)
+ nazev = models.CharField('název', max_length=256) # Zveřejnitelný na stránky
# Problém má podproblémy
nadproblem = models.ForeignKey('self', verbose_name='nadřazený problém',
- related_name='nadproblem_%(class)s', null=True, blank=True,
+ related_name='podproblem', null=True, blank=True,
on_delete=models.SET_NULL)
STAV_NAVRH = 'navrh'
@@ -698,6 +728,9 @@ class Tema(Problem):
rocnik = models.ForeignKey(Rocnik, verbose_name='ročník',blank=True, null=True,
on_delete=models.PROTECT)
+ abstrakt = models.TextField('Abstrakt na rozcestník', blank=True)
+ obrazek = models.ImageField('Obrázek na rozcestník', null=True)
+
def kod_v_rocniku(self):
if self.stav == 'zadany':
if self.nadproblem:
@@ -705,6 +738,12 @@ class Tema(Problem):
return "t{}".format(self.kod)
return '
'
+ def save(self, *args, **kwargs):
+ super().save(*args, **kwargs)
+ # *Node.save() aktualizuje název *Nodu.
+ for tvcn in self.temavcislenode_set.all():
+ tvcn.save()
+
class Clanek(Problem):
class Meta:
db_table = 'seminar_clanky'
@@ -725,6 +764,15 @@ class Clanek(Problem):
return "c{}".format(self.kod)
return ''
+ def save(self, *args, **kwargs):
+ super().save(*args, **kwargs)
+ # *Node.save() aktualizuje název *Nodu.
+ try:
+ self.claneknode.save()
+ except ObjectDoesNotExist:
+ # Neexistující *Node nemá smysl aktualizovat.
+ pass
+
class Text(SeminarModelBase):
class Meta:
db_table = 'seminar_texty'
@@ -742,8 +790,17 @@ class Text(SeminarModelBase):
# obrázky mají návaznost opačným směrem (vazba z druhé strany)
+ def save(self, *args, **kwargs):
+ super().save(*args, **kwargs)
+ # *Node.save() aktualizuje název *Nodu.
+ for tn in self.textnode_set.all():
+ tn.save()
-
+ def __str__(self):
+ parser = FirstTagParser()
+ parser.feed(str(self.na_web))
+ return parser.firstTag
+
class Uloha(Problem):
class Meta:
db_table = 'seminar_ulohy'
@@ -770,12 +827,26 @@ class Uloha(Problem):
def kod_v_rocniku(self):
if self.stav == 'zadany':
- name="{}.u{}".format(self.cislo_zadani.cislo,self.kod)
+ name="{}.u{}".format(self.cislo_zadani.poradi,self.kod)
if self.nadproblem:
return self.nadproblem.kod_v_rocniku()+name
return name
return ''
+ def save(self, *args, **kwargs):
+ super().save(*args, **kwargs)
+ # *Node.save() aktualizuje název *Nodu.
+ try:
+ self.ulohazadaninode.save()
+ except ObjectDoesNotExist:
+ # Neexistující *Node nemá smysl aktualizovat.
+ pass
+ try:
+ self.ulohavzoraknode.save()
+ except ObjectDoesNotExist:
+ # Neexistující *Node nemá smysl aktualizovat.
+ pass
+
@reversion.register(ignore_duplicates=True)
class Reseni(SeminarModelBase):
@@ -828,7 +899,7 @@ class Reseni(SeminarModelBase):
# Konfera
def __str__(self):
- return "{}: {}".format(self.resitel.osoba.plne_jmeno(), self.problem.nazev)
+ return "{}({}): {}({})".format(self.resitele.first(),len(self.resitele.all()), self.problem.first() ,len(self.problem.all()))
# NOTE: Potenciální DB HOG (bez select_related)
## Pravdepodobne uz nebude potreba:
@@ -856,7 +927,8 @@ class Hodnoceni(SeminarModelBase):
reseni = models.ForeignKey(Reseni, verbose_name='řešení', on_delete=models.CASCADE)
- problem = models.ForeignKey(Problem, verbose_name='problém', on_delete=models.PROTECT)
+ problem = models.ForeignKey(Problem, verbose_name='problém',
+ related_name='hodnoceni', on_delete=models.PROTECT)
def __str__(self):
return "{}, {}, {}".format(self.problem, self.reseni, self.body)
@@ -957,6 +1029,14 @@ class Pohadka(SeminarModelBase):
uryvek = self.text if len(self.text) < 50 else self.text[:(50-3)]+"..."
return uryvek
+ def save(self, *args, **kwargs):
+ super().save(*args, **kwargs)
+ # *Node.save() aktualizuje název *Nodu.
+ try:
+ self.pohadkanode.save()
+ except ObjectDoesNotExist:
+ # Neexistující *Node nemá smysl aktualizovat.
+ pass
@reversion.register(ignore_duplicates=True)
class Soustredeni_Ucastnici(SeminarModelBase):
@@ -1020,7 +1100,7 @@ class Konfera(models.Model):
# Interní ID
id = models.AutoField(primary_key = True)
- nazev = models.CharField('název konfery', max_length=40, help_text = 'Název konfery')
+ nazev = models.CharField('název konfery', max_length=100, help_text = 'Název konfery')
anotace = models.TextField('anotace', blank=True,
help_text='Popis, o čem bude konfera.')
@@ -1067,6 +1147,15 @@ class Konfera(models.Model):
def __str__(self):
return "{}: ({})".format(self.nazev, self.soustredeni)
+ def save(self, *args, **kwargs):
+ super().save(*args, **kwargs)
+ # *Node.save() aktualizuje název *Nodu.
+ try:
+ self.konferanode.save()
+ except ObjectDoesNotExist:
+ # Neexistující *Node nemá smysl aktualizovat.
+ pass
+
# Vazebna tabulka. Mozna se generuje automaticky.
@reversion.register(ignore_duplicates=True)
@@ -1139,12 +1228,13 @@ class Obrazek(SeminarModelBase):
help_text = 'Černobílá verze obrázku do čísla',
upload_to = 'obrazky/%Y/%m/%d/', blank=True, null=True)
-class TreeNode(models.Model):
+class TreeNode(PolymorphicModel):
class Meta:
db_table = "seminar_nodes_treenode"
verbose_name = "TreeNode"
verbose_name_plural = "TreeNody"
+ # TODO: Nechceme radši jako root vyžadovat přímo RocnikNode?
root = models.ForeignKey('TreeNode',
related_name="potomci_set",
null = True,
@@ -1162,14 +1252,59 @@ class TreeNode(models.Model):
blank = True,
on_delete=models.SET_NULL,
verbose_name="další element na stejné úrovni")
+ nazev = models.TextField("název tohoto node",
+ help_text = "Tento název se zobrazuje v nabídkách pro výběr vhodného TreeNode",
+ blank=False,
+ null=True) # Nezveřejnitelný název na stránky - pouze do adminu
+ zajimave = models.BooleanField(default = False,
+ verbose_name = "Zajímavé",
+ help_text = "Zobrazí se daná věc na rozcestníku témátek")
+ srolovatelne = models.BooleanField(null = True, blank = True,
+ verbose_name = "Srolovatelné",
+ help_text = "Bude na stránce témátka možnost tuto položku skrýt")
+ # Slouží k debugování pro rychlé získání představy o podobě podstromu pod tímto TreeNode.
def print_tree(self,indent=0):
- print("{}TreeNode({})".format(" "*indent,self.id))
+ # FIXME: Tady se spoléháme na to, že nedeklarovaný primární klíč se jmenuje by default 'id', což není úplně správně
+ print("{}{} (id: {})".format(" "*indent,self, self.id))
if self.first_child:
self.first_child.print_tree(indent=indent+2)
if self.succ:
self.succ.print_tree(indent=indent)
-
+
+ def getOdkazStr(self): # String na rozcestník
+ return self.first_child.getOdkazStr()
+
+ def getOdkaz(self): # ID HTML tagu, na který se bude scrollovat #{{self.getOdkaz}}
+ # Jsem si vědom, že tu potenciálně vznikají kolize.
+ # Přijdou mi natolik nepravděpodobné, že je neřeším
+ # Chtěl jsem ale hezké odkazy
+ string = unidecode(self.getOdkazStr())
+ returnVal = ""
+ i = 0
+ while len(returnVal) < 16: # Max 15 znaků
+ if i == len(string):
+ break
+ if string[i] == " ":
+ returnVal += "-"
+ if string[i].isalnum():
+ returnVal += string[i].lower()
+ i += 1
+ return returnVal
+
+ def __str__(self):
+ if self.nazev:
+ return self.nazev
+ else:
+ #TODO: logování
+ return "Nepojmenovaný Treenode"
+
+ def save(self, *args, **kwargs):
+ self.aktualizuj_nazev()
+ super().save(*args, **kwargs)
+
+ def aktualizuj_nazev(self):
+ raise NotImplementedError("Pokus o aktualizaci názvu obecného TreeNode místo konkrétní instance")
class RocnikNode(TreeNode):
class Meta:
@@ -1180,6 +1315,9 @@ class RocnikNode(TreeNode):
on_delete = models.PROTECT, # Pokud chci mazat ročník, musím si Node pořešit ručně
verbose_name = "ročník")
+ def aktualizuj_nazev(self):
+ self.nazev = "RocnikNode: "+str(self.rocnik)
+
class CisloNode(TreeNode):
class Meta:
db_table = 'seminar_nodes_cislo'
@@ -1189,12 +1327,36 @@ class CisloNode(TreeNode):
on_delete = models.PROTECT, # Pokud chci mazat číslo, musím si Node pořešit ručně
verbose_name = "číslo")
+ def aktualizuj_nazev(self):
+ self.nazev = "CisloNode: "+str(self.cislo)
+
+ def getOdkazStr(self):
+ return "Číslo " + str(self.cislo)
+
class MezicisloNode(TreeNode):
class Meta:
db_table = 'seminar_nodes_mezicislo'
verbose_name = 'Mezičíslo (Node)'
verbose_name_plural = 'Mezičísla (Node)'
+ def aktualizuj_nazev(self):
+ if self.prev:
+ if (self.prev.get_real_instance_class() != CisloNode and
+ self.prev.get_real_instance_class() != MezicisloNode):
+ raise ValueError("Předchůdce není číslo!")
+ posledni = self.prev.cislo
+ self.nazev = "MezicisloNode: Mezičíslo po čísle"+str(posledni)
+ elif self.root:
+ if self.root.get_real_instance_class() != RocnikNode:
+ raise ValueError("Kořen stromu není ročník!")
+ rocnik = self.root.rocnik
+ self.nazev = "MezicisloNode: První mezičíslo ročníku "+str(rocnik)
+ else:
+ print("!!!!! Nějaké neidentifikované mezičíslo !!!!!")
+ self.nazev = "MezicisloNode: Neidentifikovatelné mezičíslo!"
+ def getOdkazStr(self):
+ return "Obsah dostupný pouze na webu"
+
class TemaVCisleNode(TreeNode):
""" Obsahuje příspěvky k tématu v daném čísle """
class Meta:
@@ -1205,6 +1367,12 @@ class TemaVCisleNode(TreeNode):
on_delete=models.PROTECT, # Pokud chci mazat téma, musím si Node pořešit ručně
verbose_name = "téma v čísle")
+ def aktualizuj_nazev(self):
+ self.nazev = "TemaVCisleNode: "+str(self.tema)
+
+ def getOdkazStr(self):
+ return str(self.tema)
+
class KonferaNode(TreeNode):
class Meta:
db_table = 'seminar_nodes_konfera'
@@ -1216,6 +1384,9 @@ class KonferaNode(TreeNode):
null=True,
blank=False)
+ def aktualizuj_nazev(self):
+ self.nazev = "KonferaNode: "+str(self.konfera)
+
class ClanekNode(TreeNode):
class Meta:
db_table = 'seminar_nodes_clanek'
@@ -1227,6 +1398,13 @@ class ClanekNode(TreeNode):
null=True,
blank=False)
+ def aktualizuj_nazev(self):
+ self.nazev = "ClanekNode: "+str(self.clanek)
+
+ def getOdkazStr(self):
+ return str(self.clanek)
+
+
class UlohaZadaniNode(TreeNode):
class Meta:
db_table = 'seminar_nodes_uloha_zadani'
@@ -1238,6 +1416,13 @@ class UlohaZadaniNode(TreeNode):
null=True,
blank=False)
+ def aktualizuj_nazev(self):
+ self.nazev = "UlohaZadaniNode: "+str(self.uloha)
+
+ def getOdkazStr(self):
+ return str(self.uloha)
+
+
class PohadkaNode(TreeNode):
class Meta:
db_table = 'seminar_nodes_pohadka'
@@ -1248,6 +1433,9 @@ class PohadkaNode(TreeNode):
verbose_name = "pohádka",
)
+ def aktualizuj_nazev(self):
+ self.nazev = "PohadkaNode: "+str(self.pohadka)
+
class UlohaVzorakNode(TreeNode):
class Meta:
db_table = 'seminar_nodes_uloha_vzorak'
@@ -1259,6 +1447,13 @@ class UlohaVzorakNode(TreeNode):
null=True,
blank=False)
+ def aktualizuj_nazev(self):
+ self.nazev = "UlohaVzorakNode: "+str(self.uloha)
+
+ def getOdkazStr(self):
+ return str(self.uloha)
+
+
class TextNode(TreeNode):
class Meta:
db_table = 'seminar_nodes_obsah'
@@ -1267,6 +1462,13 @@ class TextNode(TreeNode):
text = models.ForeignKey(Text,
on_delete=models.PROTECT,
verbose_name = 'text')
+
+ def aktualizuj_nazev(self):
+ self.nazev = "TextNode: "+str(self.text)
+
+ def getOdkazStr(self):
+ return str(self.text)
+
## FIXME: Logiku přesunout do views.
#class VysledkyBase(SeminarModelBase):
@@ -1292,7 +1494,7 @@ class TextNode(TreeNode):
#
# def __str__(self):
# return "%s: %sb (%s)".format(self.resitel.plne_jmeno(), self.body,
-# str(self.cislo))
+# str(self.poradi))
# # NOTE: DB zatez pri vypisu (ale nepouzivany)
@@ -1342,7 +1544,7 @@ class TextNode(TreeNode):
#
# def __str__(self):
# # NOTE: DB HOG (ale nepouzivany)
-# return "%s: %sb / %sb (do %s)" % (self.resitel.plne_jmeno(), self.body, self.body_celkem, str(self.cislo))
+# return "%s: %sb / %sb (do %s)" % (self.resitel.plne_jmeno(), self.body, self.body_celkem, str(self.poradi))
##mozna potreba upravit
@@ -1353,12 +1555,16 @@ class Nastaveni(SingletonModel):
db_table = 'seminar_nastaveni'
verbose_name = 'Nastavení semináře'
- aktualni_rocnik = models.ForeignKey(Rocnik, verbose_name='aktuální ročník',
- null=False, on_delete=models.PROTECT)
+# aktualni_rocnik = models.ForeignKey(Rocnik, verbose_name='aktuální ročník',
+# null=False, on_delete=models.PROTECT)
aktualni_cislo = models.ForeignKey(Cislo, verbose_name='poslední vydané číslo',
null=False, on_delete=models.PROTECT)
+ @property
+ def aktualni_rocnik(self):
+ return self.aktualni_cislo.rocnik
+
def __str__(self):
return 'Nastavení semináře'
@@ -1399,3 +1605,35 @@ class Novinky(models.Model):
return '[' + str(self.datum) + '] ' + self.text[0:50]
else:
return '[' + str(self.datum) + '] '
+
+
+
+
+# FIXME: Tohle nepatří do aplikace 'seminar'
+# Nefunkční alternativa vestavěného Usera, který má jméno a mail v přidružené Osobě
+# from django.contrib.auth.models import User as Django_User
+#
+# class Uzivatel(Django_User):
+# class Meta:
+# proxy = True
+#
+# @property
+# def first_name(self):
+# osoby = Osoba.objects.filter(user=self)
+# if len(osoby) == 0:
+# return None
+# return osoby.first().krestni_jmeno
+#
+# @property
+# def last_name(self):
+# osoby = Osoba.objects.filter(user=self)
+# if len(osoby) == 0:
+# return None
+# return osoby.first().prijmeni
+#
+# @property
+# def email(self):
+# osoby = Osoba.objects.filter(user=self)
+# if len(osoby) == 0:
+# return None
+# return osoby.first().email
diff --git a/seminar/static/seminar/lisak.eps b/seminar/static/seminar/lisak.eps
deleted file mode 100644
index 3a136212..00000000
--- a/seminar/static/seminar/lisak.eps
+++ /dev/null
@@ -1,1603 +0,0 @@
-%%BeginDocument: ./Eps/lisak.eps
-%!PS-Adobe-3.0 EPSF-3.0
-%%BoundingBox: -191 -97 769 946
-%%Creator: CorelDRAW 8
-%%Title: L:\Prace\MaM\Obrazky\Lisak.eps
-%%CreationDate: Tue May 11 17:28:49 1999
-%%For: Halef
-%%DocumentProcessColors: Black
-%%DocumentSuppliedResources: (atend)
-%%EndComments
-%%BeginProlog
-/AutoFlatness false def
-/AutoSteps 0 def
-/CMYKMarks true def
-/UseLevel 1 def
-%Color profile: PROFILES.CCM - Obecn profil tiskrny CMYK - d.
-%%BeginResource: procset wCorel8Dict 8.0 0
-/wCorel8Dict 300 dict def wCorel8Dict begin
-% Copyright (c)1992-97 Corel Corporation
-% All rights reserved. v8.0 r0.7
-/bd{bind def}bind def/ld{load def}bd/xd{exch def}bd/_ null def/rp{{pop}repeat}
-bd/@cp/closepath ld/@gs/gsave ld/@gr/grestore ld/@np/newpath ld/Tl/translate ld
-/$sv 0 def/@sv{/$sv save def}bd/@rs{$sv restore}bd/spg/showpage ld/showpage{}
-bd currentscreen/@dsp xd/$dsp/@dsp def/$dsa xd/$dsf xd/$sdf false def/$SDF
-false def/$Scra 0 def/SetScr/setscreen ld/setscreen{pop pop pop}bd/@ss{2 index
-0 eq{$dsf 3 1 roll 4 -1 roll pop}if exch $Scra add exch load SetScr}bd
-/SepMode_5 where{pop}{/SepMode_5 0 def}ifelse/CurrentInkName_5 where{pop}
-{/CurrentInkName_5(Composite)def}ifelse/$ink_5 where{pop}{/$ink_5 -1 def}
-ifelse/$c 0 def/$m 0 def/$y 0 def/$k 0 def/$t 1 def/$n _ def/$o 0 def/$fil 0
-def/$C 0 def/$M 0 def/$Y 0 def/$K 0 def/$T 1 def/$N _ def/$O 0 def/$PF false
-def/s1c 0 def/s1m 0 def/s1y 0 def/s1k 0 def/s1t 0 def/s1n _ def/$bkg false def
-/SK 0 def/SM 0 def/SY 0 def/SC 0 def/$op false def matrix currentmatrix/$ctm xd
-/$ptm matrix def/$ttm matrix def/$stm matrix def/$ffpnt true def
-/CorelDrawReencodeVect[16#0/grave 16#5/breve 16#6/dotaccent 16#8/ring
-16#A/hungarumlaut 16#B/ogonek 16#C/caron 16#D/dotlessi 16#27/quotesingle
-16#60/grave 16#7C/bar
-16#82/quotesinglbase/florin/quotedblbase/ellipsis/dagger/daggerdbl
-16#88/circumflex/perthousand/Scaron/guilsinglleft/OE
-16#91/quoteleft/quoteright/quotedblleft/quotedblright/bullet/endash/emdash
-16#98/tilde/trademark/scaron/guilsinglright/oe 16#9F/Ydieresis
-16#A1/exclamdown/cent/sterling/currency/yen/brokenbar/section
-16#a8/dieresis/copyright/ordfeminine/guillemotleft/logicalnot/minus/registered/macron
-16#b0/degree/plusminus/twosuperior/threesuperior/acute/mu/paragraph/periodcentered
-16#b8/cedilla/onesuperior/ordmasculine/guillemotright/onequarter/onehalf/threequarters/questiondown
-16#c0/Agrave/Aacute/Acircumflex/Atilde/Adieresis/Aring/AE/Ccedilla
-16#c8/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute/Icircumflex/Idieresis
-16#d0/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis/multiply
-16#d8/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute/Thorn/germandbls
-16#e0/agrave/aacute/acircumflex/atilde/adieresis/aring/ae/ccedilla
-16#e8/egrave/eacute/ecircumflex/edieresis/igrave/iacute/icircumflex/idieresis
-16#f0/eth/ntilde/ograve/oacute/ocircumflex/otilde/odieresis/divide
-16#f8/oslash/ugrave/uacute/ucircumflex/udieresis/yacute/thorn/ydieresis]def
-/L2?/languagelevel where{pop languagelevel 2 ge}{false}ifelse def
-/@BeginSysCorelDict{systemdict/Corel30Dict known{systemdict/Corel30Dict get
-exec}if systemdict/CorelLexDict known{1 systemdict/CorelLexDict get exec}if}bd
-/@EndSysCorelDict{systemdict/Corel30Dict known{end}if/EndCorelLexDict where
-{pop EndCorelLexDict}if}bd AutoFlatness{/@ifl{dup currentflat exch sub 10 gt{
-([Error: PathTooComplex; OffendingCommand: AnyPaintingOperator]\n)print flush
-@np exit}{currentflat 2 add setflat}ifelse}bd/@fill/fill ld/fill{currentflat{
-{@fill}stopped{@ifl}{exit}ifelse}bind loop setflat}bd/@eofill/eofill ld/eofill
-{currentflat{{@eofill}stopped{@ifl}{exit}ifelse}bind loop setflat}bd/@clip
-/clip ld/clip{currentflat{{@clip}stopped{@ifl}{exit}ifelse}bind loop setflat}
-bd/@eoclip/eoclip ld/eoclip{currentflat{{@eoclip}stopped{@ifl}{exit}ifelse}
-bind loop setflat}bd/@stroke/stroke ld/stroke{currentflat{{@stroke}stopped
-{@ifl}{exit}ifelse}bind loop setflat}bd}if L2?{/@ssa{true setstrokeadjust}bd}{
-/@ssa{}bd}ifelse/d/setdash ld/j/setlinejoin ld/J/setlinecap ld/M/setmiterlimit
-ld/w/setlinewidth ld/O{/$o xd}bd/R{/$O xd}bd/W/eoclip ld/c/curveto ld/C/c ld/l
-/lineto ld/L/l ld/rl/rlineto ld/m/moveto ld/n/newpath ld/N/newpath ld/P{11 rp}
-bd/u{}bd/U{}bd/A{pop}bd/q/@gs ld/Q/@gr ld/&{}bd/@j{@sv @np}bd/@J{@rs}bd/g{1
-exch sub/$k xd/$c 0 def/$m 0 def/$y 0 def/$t 1 def/$n _ def/$fil 0 def}bd/G{1
-sub neg/$K xd _ 1 0 0 0/$C xd/$M xd/$Y xd/$T xd/$N xd}bd/k{1 index type
-/stringtype eq{/$t xd/$n xd}{/$t 0 def/$n _ def}ifelse/$k xd/$y xd/$m xd/$c xd
-/$fil 0 def}bd/K{1 index type/stringtype eq{/$T xd/$N xd}{/$T 0 def/$N _ def}
-ifelse/$K xd/$Y xd/$M xd/$C xd}bd/x/k ld/X/K ld/sf{1 index type/stringtype eq{
-/s1t xd/s1n xd}{/s1t 0 def/s1n _ def}ifelse/s1k xd/s1y xd/s1m xd/s1c xd}bd/i{
-dup 0 ne{setflat}{pop}ifelse}bd/v{4 -2 roll 2 copy 6 -2 roll c}bd/V/v ld/y{2
-copy c}bd/Y/y ld/@w{matrix rotate/$ptm xd matrix scale $ptm dup concatmatrix
-/$ptm xd 1 eq{$ptm exch dup concatmatrix/$ptm xd}if 1 w}bd/@g{1 eq dup/$sdf xd
-{/$scp xd/$sca xd/$scf xd}if}bd/@G{1 eq dup/$SDF xd{/$SCP xd/$SCA xd/$SCF xd}
-if}bd/@D{2 index 0 eq{$dsf 3 1 roll 4 -1 roll pop}if 3 copy exch $Scra add exch
-load SetScr/$dsp xd/$dsa xd/$dsf xd}bd/$ngx{$SDF{$SCF SepMode_5 0 eq{$SCA}
-{$dsa}ifelse $SCP @ss}if}bd/p{/$pm xd 7 rp/$pyf xd/$pxf xd/$pn xd/$fil 1 def}
-bd/@MN{2 copy le{pop}{exch pop}ifelse}bd/@MX{2 copy ge{pop}{exch pop}ifelse}bd
-/InRange{3 -1 roll @MN @MX}bd/@sqr{dup 0 rl dup 0 exch rl neg 0 rl @cp}bd
-/currentscale{1 0 dtransform matrix defaultmatrix idtransform dup mul exch dup
-mul add sqrt 0 1 dtransform matrix defaultmatrix idtransform dup mul exch dup
-mul add sqrt}bd/@unscale{}bd/wDstChck{2 1 roll dup 3 -1 roll eq{1 add}if}bd
-/@dot{dup mul exch dup mul add 1 exch sub}bd/@lin{exch pop abs 1 exch sub}bd
-/cmyk2rgb{3{dup 5 -1 roll add 1 exch sub dup 0 lt{pop 0}if exch}repeat pop}bd
-/rgb2cmyk{3{1 exch sub 3 1 roll}repeat 3 copy @MN @MN 3{dup 5 -1 roll sub neg
-exch}repeat}bd/rgb2g{2 index .299 mul 2 index .587 mul add 1 index .114 mul add
-4 1 roll pop pop pop}bd/WaldoColor_5 where{pop}{/SetRgb/setrgbcolor ld/GetRgb
-/currentrgbcolor ld/SetGry/setgray ld/GetGry/currentgray ld/SetRgb2 systemdict
-/setrgbcolor get def/GetRgb2 systemdict/currentrgbcolor get def/SetHsb
-systemdict/sethsbcolor get def/GetHsb systemdict/currenthsbcolor get def
-/rgb2hsb{SetRgb2 GetHsb}bd/hsb2rgb{3 -1 roll dup floor sub 3 1 roll SetHsb
-GetRgb2}bd/setcmykcolor where{pop/SetCmyk_5/setcmykcolor ld}{/SetCmyk_5{
-cmyk2rgb SetRgb}bd}ifelse/currentcmykcolor where{pop/GetCmyk/currentcmykcolor
-ld}{/GetCmyk{GetRgb rgb2cmyk}bd}ifelse/setoverprint where{pop}{/setoverprint{
-/$op xd}bd}ifelse/currentoverprint where{pop}{/currentoverprint{$op}bd}ifelse
-/@tc_5{5 -1 roll dup 1 ge{pop}{4{dup 6 -1 roll mul exch}repeat pop}ifelse}bd
-/@trp{exch pop 5 1 roll @tc_5}bd/setprocesscolor_5{SepMode_5 0 eq{SetCmyk_5}{0
-4 $ink_5 sub index exch pop 5 1 roll pop pop pop pop SepsColor true eq{$ink_5 3
-gt{1 sub neg SetGry}{0 0 0 4 $ink_5 roll SetCmyk_5}ifelse}{1 sub neg SetGry}
-ifelse}ifelse}bd/findcmykcustomcolor where{pop}{/findcmykcustomcolor{5 array
-astore}bd}ifelse/setcustomcolor where{pop}{/setcustomcolor{exch aload pop
-SepMode_5 0 eq{pop @tc_5 setprocesscolor_5}{CurrentInkName_5 eq{4 index}{0}
-ifelse 6 1 roll 5 rp 1 sub neg SetGry}ifelse}bd}ifelse/@scc_5{dup type
-/booleantype eq{setoverprint}{1 eq setoverprint}ifelse dup _ eq{pop
-setprocesscolor_5 pop}{findcmykcustomcolor exch setcustomcolor}ifelse SepMode_5
-0 eq{true}{GetGry 1 eq currentoverprint and not}ifelse}bd/colorimage where{pop
-/ColorImage{colorimage}def}{/ColorImage{/ncolors xd pop/dataaq xd{dataaq
-ncolors dup 3 eq{/$dat xd 0 1 $dat length 3 div 1 sub{dup 3 mul $dat 1 index
-get 255 div $dat 2 index 1 add get 255 div $dat 3 index 2 add get 255 div rgb2g
-255 mul cvi exch pop $dat 3 1 roll put}for $dat 0 $dat length 3 idiv
-getinterval pop}{4 eq{/$dat xd 0 1 $dat length 4 div 1 sub{dup 4 mul $dat 1
-index get 255 div $dat 2 index 1 add get 255 div $dat 3 index 2 add get 255 div
-$dat 4 index 3 add get 255 div cmyk2rgb rgb2g 255 mul cvi exch pop $dat 3 1
-roll put}for $dat 0 $dat length ncolors idiv getinterval}if}ifelse}image}bd
-}ifelse/setcmykcolor{1 5 1 roll _ currentoverprint @scc_5/$ffpnt xd}bd
-/currentcmykcolor{0 0 0 0}bd/setrgbcolor{rgb2cmyk setcmykcolor}bd
-/currentrgbcolor{currentcmykcolor cmyk2rgb}bd/sethsbcolor{hsb2rgb setrgbcolor}
-bd/currenthsbcolor{currentrgbcolor rgb2hsb}bd/setgray{dup dup setrgbcolor}bd
-/currentgray{currentrgbcolor rgb2g}bd/InsideDCS false def/IMAGE systemdict
-/image get def/image{InsideDCS{IMAGE}{/EPSDict where{pop SepMode_5 0 eq{IMAGE}
-{dup type/dicttype eq{dup/ImageType get 1 ne{IMAGE}{dup dup/BitsPerComponent
-get 8 eq exch/BitsPerComponent get 1 eq or currentcolorspace 0 get/DeviceGray
-eq and{CurrentInkName_5(Black)eq{IMAGE}{dup/DataSource get/TCC xd/Height get
-abs{TCC pop}repeat}ifelse}{IMAGE}ifelse}ifelse}{2 index 1 ne{CurrentInkName_5
-(Black)eq{IMAGE}{/TCC xd pop pop exch pop abs{TCC pop}repeat}ifelse}{IMAGE}
-ifelse}ifelse}ifelse}{IMAGE}ifelse}ifelse}bd}ifelse/WaldoColor_5 true def/@sft
-{$tllx $pxf add dup $tllx gt{$pwid sub}if/$tx xd $tury $pyf sub dup $tury lt
-{$phei add}if/$ty xd}bd/@stb{pathbbox/$ury xd/$urx xd/$lly xd/$llx xd}bd/@ep{{
-cvx exec}forall}bd/@tp{@sv/$in true def 2 copy dup $lly le{/$in false def}if
-$phei sub $ury ge{/$in false def}if dup $urx ge{/$in false def}if $pwid add
-$llx le{/$in false def}if $in{@np 2 copy m $pwid 0 rl 0 $phei neg rl $pwid neg
-0 rl 0 $phei rl clip @np $pn cvlit load aload pop 7 -1 roll 5 index sub 7 -1
-roll 3 index sub Tl matrix currentmatrix/$ctm xd @ep pop pop pop pop}{pop pop
-}ifelse @rs}bd/@th{@sft 0 1 $tly 1 sub{dup $psx mul $tx add{dup $llx gt{$pwid
-sub}{exit}ifelse}loop exch $phei mul $ty exch sub 0 1 $tlx 1 sub{$pwid mul 3
-copy 3 -1 roll add exch @tp pop}for pop pop}for}bd/@tv{@sft 0 1 $tlx 1 sub{dup
-$pwid mul $tx add exch $psy mul $ty exch sub{dup $ury lt{$phei add}{exit}
-ifelse}loop 0 1 $tly 1 sub{$phei mul 3 copy sub @tp pop}for pop pop}for}bd/$fm
-0 def/wfill{1 $fm eq{fill}{eofill}ifelse}bd/wclip{1 $fm eq{clip}{eoclip}ifelse
-}bd/@pf{@gs $ctm setmatrix $pm concat @stb wclip @sv Bburx Bbury $pm itransform
-/$tury xd/$turx xd Bbllx Bblly $pm itransform/$tlly xd/$tllx xd newpath $tllx
-$tlly m $tllx $tury l $turx $tury l $turx $tlly l $tllx $tlly m @cp pathbbox
-@rs/$tury xd/$turx xd/$tlly xd/$tllx xd/$wid $turx $tllx sub def/$hei $tury
-$tlly sub def @gs $vectpat{1 0 0 0 0 _ $o @scc_5{wfill}if}{$t $c $m $y $k $n $o
-@scc_5{SepMode_5 0 eq $pfrg or{$tllx $tlly Tl $wid $hei scale <00> 8 1 false[8
-0 0 1 0 0]{}imagemask}{/$bkg true def}ifelse}if}ifelse @gr $wid 0 gt $hei 0 gt
-and{$pn cvlit load aload pop/$pd xd 3 -1 roll sub/$phei xd exch sub/$pwid xd
-$wid $pwid div ceiling 1 add/$tlx xd $hei $phei div ceiling 1 add/$tly xd $psx
-0 eq{@tv}{@th}ifelse}if @gr @np/$bkg false def}bd/@Pf{@sv SepMode_5 0 eq $Psc 0
-ne or $ink_5 3 eq or{0 J 0 j[]0 d $t $c $m $y $k $n $o @scc_5 pop $ctm
-setmatrix 72 1000 div dup matrix scale dup concat dup Bburx exch Bbury exch
-itransform ceiling cvi/Bbury xd ceiling cvi/Bburx xd Bbllx exch Bblly exch
-itransform floor cvi/Bblly xd floor cvi/Bbllx xd $Prm aload pop $Psn load exec
-}{1 SetGry wfill}ifelse @rs @np}bd/F{matrix currentmatrix $sdf{$scf $sca $scp
-@ss}if $fil 1 eq{@pf}{$fil 2 eq{@ff}{$fil 3 eq{@Pf}{$t $c $m $y $k $n $o @scc_5
-{wfill}{@np}ifelse}ifelse}ifelse}ifelse $sdf{$dsf $dsa $dsp @ss}if setmatrix}
-bd/f{@cp F}bd/S{matrix currentmatrix $ctm setmatrix $SDF{$SCF $SCA $SCP @ss}if
-$T $C $M $Y $K $N $O @scc_5{matrix currentmatrix $ptm concat stroke setmatrix}
-{@np}ifelse $SDF{$dsf $dsa $dsp @ss}if setmatrix}bd/s{@cp S}bd/B{@gs F @gr S}
-bd/b{@cp B}bd/_E{5 array astore exch cvlit xd}bd/@cc{currentfile $dat
-readhexstring pop}bd/@sm{/$ctm $ctm currentmatrix def}bd/@E{/Bbury xd/Bburx xd
-/Bblly xd/Bbllx xd}bd/@c{@cp}bd/@p{/$fil 1 def 1 eq dup/$vectpat xd{/$pfrg true
-def}{@gs $t $c $m $y $k $n $o @scc_5/$pfrg xd @gr}ifelse/$pm xd/$psy xd/$psx xd
-/$pyf xd/$pxf xd/$pn xd}bd/@P{/$fil 3 def/$Psn xd/$Psc xd array astore/$Prm xd
-}bd/@ii{concat 3 index 3 index m 3 index 1 index l 2 copy l 1 index 3 index l 3
-index 3 index l clip pop pop pop pop}bd/tcc{@cc}def/@i{@sm @gs @ii 6 index 1 ne
-{/$frg true def pop pop}{1 eq{s1t s1c s1m s1y s1k s1n $O @scc_5/$frg xd}{/$frg
-false def}ifelse 1 eq{@gs $ctm setmatrix F @gr}if}ifelse @np/$ury xd/$urx xd
-/$lly xd/$llx xd/$bts xd/$hei xd/$wid xd/$dat $wid $bts mul 8 div ceiling cvi
-string def $bkg $frg or{$SDF{$SCF $SCA $SCP @ss}if $llx $lly Tl $urx $llx sub
-$ury $lly sub scale $bkg{$t $c $m $y $k $n $o @scc_5 pop}if $wid $hei abs $bts
-1 eq{$bkg}{$bts}ifelse[$wid 0 0 $hei neg 0 $hei 0 gt{$hei}{0}ifelse]/tcc load
-$bts 1 eq{imagemask}{image}ifelse $SDF{$dsf $dsa $dsp @ss}if}{$hei abs{tcc pop}
-repeat}ifelse @gr $ctm setmatrix}bd/@I{@sm @gs @ii @np/$ury xd/$urx xd/$lly xd
-/$llx xd/$ncl xd/$bts xd/$hei xd/$wid xd/$dat $wid $bts mul $ncl mul 8 div
-ceiling cvi string def $ngx $llx $lly Tl $urx $llx sub $ury $lly sub scale $wid
-$hei abs $bts[$wid 0 0 $hei neg 0 $hei 0 gt{$hei}{0}ifelse]/@cc load false $ncl
-ColorImage $SDF{$dsf $dsa $dsp @ss}if @gr $ctm setmatrix}bd/COMP 0 def
-/MaskedImage false def L2?{/@I_2{@sm @gs @ii @np/$ury xd/$urx xd/$lly xd/$llx
-xd/$ncl xd/$bts xd/$hei xd/$wid xd/$dat $wid $bts mul $ncl mul 8 div ceiling
-cvi string def $ngx $ncl 1 eq{/DeviceGray}{$ncl 3 eq{/DeviceRGB}{/DeviceCMYK}
-ifelse}ifelse setcolorspace $llx $lly Tl $urx $llx sub $ury $lly sub scale 8
-dict begin/ImageType 1 def/Width $wid def/Height $hei abs def/BitsPerComponent
-$bts def/Decode $ncl 1 eq{[0 1]}{$ncl 3 eq{[0 1 0 1 0 1]}{[0 1 0 1 0 1 0 1]}
-ifelse}ifelse def/ImageMatrix[$wid 0 0 $hei neg 0 $hei 0 gt{$hei}{0}ifelse]def
-/DataSource currentfile/ASCII85Decode filter COMP 1 eq{/DCTDecode filter}{COMP
-2 eq{/RunLengthDecode filter}if}ifelse def currentdict end image $SDF{$dsf $dsa
-$dsp @ss}if @gr $ctm setmatrix}bd}{/@I_2{}bd}ifelse/@I_3{@sm @gs @ii @np/$ury
-xd/$urx xd/$lly xd/$llx xd/$ncl xd/$bts xd/$hei xd/$wid xd/$dat $wid $bts mul
-$ncl mul 8 div ceiling cvi string def $ngx $ncl 1 eq{/DeviceGray}{$ncl 3 eq
-{/DeviceRGB}{/DeviceCMYK}ifelse}ifelse setcolorspace $llx $lly Tl $urx $llx sub
-$ury $lly sub scale/ImageDataDict 8 dict def ImageDataDict begin/ImageType 1
-def/Width $wid def/Height $hei abs def/BitsPerComponent $bts def/Decode $ncl 1
-eq{[0 1]}{$ncl 3 eq{[0 1 0 1 0 1]}{[0 1 0 1 0 1 0 1]}ifelse}ifelse def
-/ImageMatrix[$wid 0 0 $hei neg 0 $hei 0 gt{$hei}{0}ifelse]def/DataSource
-currentfile/ASCII85Decode filter COMP 1 eq{/DCTDecode filter}{COMP 2 eq{
-/RunLengthDecode filter}if}ifelse def end/MaskedImageDict 7 dict def
-MaskedImageDict begin/ImageType 3 def/InterleaveType 3 def/MaskDict
-ImageMaskDict def/DataDict ImageDataDict def end MaskedImageDict image $SDF
-{$dsf $dsa $dsp @ss}if @gr $ctm setmatrix}bd/@SetMask{/$mbts xd/$mhei xd/$mwid
-xd/ImageMaskDict 8 dict def ImageMaskDict begin/ImageType 1 def/Width $mwid def
-/Height $mhei abs def/BitsPerComponent $mbts def/DataSource maskstream def
-/ImageMatrix[$mwid 0 0 $mhei neg 0 $mhei 0 gt{$mhei}{0}ifelse]def/Decode[1 0]
-def end}bd/@B{@gs S @gr F}bd/@b{@cp @B}bd/@sep{CurrentInkName_5(Composite)eq
-{/$ink_5 -1 def}{CurrentInkName_5(Cyan)eq{/$ink_5 0 def}{CurrentInkName_5
-(Magenta)eq{/$ink_5 1 def}{CurrentInkName_5(Yellow)eq{/$ink_5 2 def}{
-CurrentInkName_5(Black)eq{/$ink_5 3 def}{/$ink_5 4 def}ifelse}ifelse}ifelse}
-ifelse}ifelse}bd/@whi{@gs -72000 dup m -72000 72000 l 72000 dup l 72000 -72000
-l @cp 1 SetGry fill @gr}bd/@neg{[{1 exch sub}/exec cvx currenttransfer/exec
-cvx]cvx settransfer @whi}bd/deflevel 0 def/@sax{/deflevel deflevel 1 add def}
-bd/@eax{/deflevel deflevel dup 0 gt{1 sub}if def deflevel 0 gt{/eax load}{eax}
-ifelse}bd/eax{{exec}forall}bd/@rax{deflevel 0 eq{@rs @sv}if}bd/@daq{dup type
-/arraytype eq{{}forall}if}bd/@BMP{/@cc xd UseLevel 3 eq MaskedImage true eq and
-{7 -2 roll pop pop @I_3}{12 index 1 gt UseLevel 2 eq UseLevel 3 eq or and{7 -2
-roll pop pop @I_2}{11 index 1 eq{12 -1 roll pop @i}{7 -2 roll pop pop @I}
-ifelse}ifelse}ifelse}bd systemdict/pdfmark known not{/pdfmark/cleartomark ld}
-if
-end
-%%EndResource
-%%EndProlog
-%%BeginSetup
-wCorel8Dict begin
-@BeginSysCorelDict
-2.6131 setmiterlimit
-1.00 setflat
-/$fst 128 def
-%%EndSetup
-
-%%Page: 1 1
-%LogicalPage: 1
-%%BeginPageSetup
-@sv
-@sm
-@sv
-%%EndPageSetup
-@rax %Note: Object
-482.82180 -96.51912 768.51780 183.48888 @E
- 1 O 0 @g
-0.00 0.00 0.00 1.00 k
-/$fm 0 def
-614.79780 -96.51912 m
-610.54980 -96.23112 606.30180 -96.01512 602.05380 -95.79912 C
-594.49380 -90.75912 581.53380 -79.52712 580.23780 -71.31912 C
-573.54180 -72.90312 569.86980 -76.71912 564.46980 -80.75112 C
-552.15780 -82.69512 539.12580 -86.94312 527.60580 -86.36712 C
-523.57380 -78.30312 530.26980 -71.10312 536.96580 -68.29512 C
-538.76580 -62.10312 543.30180 -61.16712 548.62980 -57.71112 C
-548.05380 -50.00712 537.32580 -44.82312 535.88580 -36.61512 C
-535.38180 -36.61512 534.87780 -36.61512 534.37380 -36.61512 C
-532.50180 -26.82312 531.70980 -26.10312 531.34980 -23.79912 C
-533.65380 -22.64712 533.65380 -22.64712 534.37380 -20.77512 C
-547.33380 -17.96712 552.58980 -17.03112 564.82980 -26.10312 C
-565.04580 -28.04712 576.56580 -35.39112 580.23780 -35.89512 C
-582.54180 -11.48712 580.59780 7.59288 565.98180 27.10488 C
-565.18980 27.24888 564.39780 27.39288 563.67780 27.46488 C
-562.23780 18.17688 557.84580 10.32888 552.01380 2.55288 C
-540.92580 -2.05512 538.54980 13.64088 536.60580 19.90488 C
-535.81380 19.90488 535.09380 19.90488 534.37380 19.90488 C
-529.40580 9.89688 520.69380 -0.83112 508.81380 -0.83112 C
-494.26980 8.88888 501.90180 18.60888 506.94180 32.00088 C
-510.03780 38.04888 513.13380 44.09688 516.30180 50.07288 C
-502.62180 47.69688 487.28580 43.37688 482.82180 60.58488 C
-482.82180 75.92088 495.99780 80.81688 508.81380 83.62488 C
-509.17380 86.21688 509.17380 86.21688 507.66180 90.03288 C
-511.62180 108.96888 509.53380 106.66488 525.73380 108.82488 C
-525.80580 109.83288 525.94980 110.84088 526.09380 111.84888 C
-531.06180 111.56088 536.31780 105.94488 538.11780 100.54488 C
-543.08580 102.27288 544.45380 108.17688 546.75780 112.64088 C
-552.80580 120.12888 556.18980 122.79288 556.90980 124.66488 C
-559.21380 123.58488 559.21380 123.58488 561.80580 123.94488 C
-562.16580 125.09688 562.52580 126.24888 562.95780 127.32888 C
-566.34180 126.68088 572.67780 117.10488 574.54980 113.36088 C
-574.54980 105.87288 573.68580 99.60888 571.95780 91.54488 C
-577.50180 91.83288 580.09380 94.92888 587.00580 94.92888 C
-589.95780 92.91288 592.98180 90.89688 596.00580 88.88088 C
-606.15780 73.32888 587.65380 57.34488 575.70180 48.20088 C
-568.93380 45.17688 568.93380 45.17688 565.54980 42.51288 C
-565.40580 41.28888 565.26180 40.06488 565.18980 38.76888 C
-565.69380 38.76888 566.19780 38.76888 566.70180 38.76888 C
-575.12580 25.16088 585.85380 9.10488 587.72580 -7.95912 C
-592.83780 -6.08712 598.74180 27.75288 600.90180 34.23288 C
-603.99780 38.76888 605.72580 44.45688 606.87780 49.28088 C
-618.97380 73.40088 624.94980 83.19288 625.30980 85.49688 C
-605.86980 84.77688 614.79780 105.15288 618.18180 116.38488 C
-622.42980 122.72088 625.74180 126.39288 631.35780 131.14488 C
-631.21380 151.08888 626.38980 166.28088 648.63780 171.39288 C
-648.34980 172.40088 648.13380 173.40888 647.91780 174.41688 C
-658.42980 174.05688 660.15780 170.45688 661.45380 158.57688 C
-667.93380 160.16088 680.46180 184.42488 687.01380 177.87288 C
-688.74180 178.37688 690.46980 178.88088 692.26980 179.38488 C
-692.62980 181.25688 692.62980 181.25688 691.47780 183.48888 C
-700.90980 182.98488 702.42180 175.13688 702.42180 166.13688 C
-697.09380 155.62488 697.09380 155.62488 696.73380 153.32088 C
-709.47780 152.88888 712.14180 142.30488 712.14180 129.99288 C
-706.95780 120.63288 695.50980 108.96888 684.70980 106.95288 C
-681.90180 104.57688 680.74980 103.35288 677.22180 102.84888 C
-677.72580 90.24888 664.33380 71.67288 652.38180 67.06488 C
-639.49380 70.16088 648.34980 87.36888 644.17380 94.92888 C
-643.38180 95.07288 642.58980 95.21688 641.86980 95.28888 C
-641.14980 93.41688 637.76580 90.75288 625.66980 72.68088 C
-611.91780 47.40888 601.26180 22.64088 597.51780 -6.44712 C
-612.63780 -1.04712 612.49380 24.29688 632.07780 22.92888 C
-632.07780 22.42488 632.07780 21.92088 632.07780 21.41688 C
-632.58180 21.41688 633.08580 21.41688 633.58980 21.41688 C
-635.10180 12.99288 632.29380 6.72888 629.84580 -1.98312 C
-638.62980 3.99288 643.23780 15.36888 654.68580 18.03288 C
-660.01380 23.64888 665.41380 25.95288 672.32580 29.69688 C
-673.26180 48.12888 680.02980 58.78488 697.09380 66.63288 C
-695.43780 84.92088 694.28580 92.19288 710.26980 103.20888 C
-714.08580 103.20888 714.80580 102.48888 721.21380 102.84888 C
-721.71780 103.85688 722.22180 104.86488 722.72580 105.87288 C
-723.58980 106.01688 724.45380 106.16088 725.31780 106.23288 C
-729.06180 102.48888 731.94180 99.75288 732.87780 93.05688 C
-740.29380 95.21688 745.04580 103.20888 753.90180 103.20888 C
-754.69380 102.48888 754.69380 102.48888 757.64580 102.48888 C
-762.03780 106.88088 763.98180 104.50488 768.51780 100.54488 C
-767.65380 91.25688 763.33380 83.84088 757.64580 76.06488 C
-753.32580 75.05688 749.07780 67.13688 747.92580 62.88888 C
-749.36580 62.67288 750.87780 62.38488 752.38980 62.09688 C
-754.47780 57.05688 758.79780 53.60088 758.79780 46.25688 C
-751.30980 29.62488 738.06180 20.26488 720.06180 20.26488 C
-715.45380 15.00888 703.64580 1.47288 695.65380 6.36888 C
-691.11780 13.13688 694.57380 20.84088 695.29380 27.46488 C
-675.78180 25.01688 656.34180 16.16088 642.66180 2.19288 C
-640.35780 -1.55112 638.48580 -2.70312 638.12580 -5.00712 C
-643.38180 -5.36712 643.38180 -5.36712 645.25380 -6.44712 C
-645.25380 -20.84712 643.74180 -31.14312 637.76580 -44.89512 C
-636.25380 -46.40712 636.25380 -46.40712 635.89380 -48.71112 C
-648.99780 -49.07112 665.12580 -49.79112 678.73380 -51.73512 C
-678.73380 -52.23912 678.73380 -52.74312 678.73380 -53.24712 C
-663.39780 -63.61512 643.09380 -80.31912 623.86980 -81.11112 C
-625.81380 -93.99912 627.97380 -95.00712 614.79780 -96.51912 C
-@c
-F
-
-@rax %Note: Object
-587.00580 -92.77512 618.15345 -70.52712 @E
- 1 O 0 @g
-0.00 0.00 0.00 0.00 k
-/$fm 0 def
-613.28580 -92.77512 m
-609.68580 -86.58312 600.61380 -91.40712 596.79780 -82.62312 C
-596.29380 -82.62312 595.78980 -82.62312 595.28580 -82.62312 C
-591.61380 -77.36712 589.16580 -75.85512 587.00580 -70.52712 C
-594.49380 -70.88712 598.88580 -71.03112 603.92580 -78.08712 C
-609.54180 -80.75112 609.54180 -80.75112 617.10180 -82.62312 C
-618.39780 -87.15912 619.69380 -92.77512 613.28580 -92.77512 C
-@c
-F
-
-@rax %Note: Object
-534.37380 -79.95912 573.46980 -64.09020 @E
- 1 O 0 @g
-0.00 0.00 0.00 0.00 k
-/$fm 0 def
-535.88580 -79.95912 m
-535.38180 -79.81512 534.87780 -79.67112 534.37380 -79.59912 C
-539.77380 -60.80712 558.34980 -63.54312 573.46980 -65.27112 C
-567.13380 -78.01512 550.14180 -74.19912 539.62980 -78.44712 C
-538.11780 -79.95912 538.11780 -79.95912 535.88580 -79.95912 C
-@c
-F
-
-@rax %Note: Object
-612.20580 -75.42312 656.91780 -55.75946 @E
- 1 O 0 @g
-0.00 0.00 0.00 0.00 k
-/$fm 0 def
-620.05380 -75.42312 m
-616.88580 -74.63112 612.63780 -68.79912 612.20580 -66.06312 C
-630.34980 -54.75912 634.95780 -54.03912 656.91780 -57.71112 C
-651.44580 -68.15112 631.64580 -75.42312 620.05380 -75.42312 C
-@c
-F
-
-@rax %Note: Object
--104.09528 -70.16712 339.97380 514.40088 @E
- 1 O 0 @g
-0.00 0.00 0.00 1.00 k
-/$fm 0 def
-226.14180 -70.16712 m
-220.81380 -64.83912 220.23780 -58.86312 212.60580 -56.99112 C
-211.66980 -58.21512 210.80580 -59.43912 209.94180 -60.73512 C
-201.08580 -61.02312 198.63780 -59.36712 198.63780 -50.94312 C
-196.04580 -47.41512 195.90180 -47.19912 197.55780 -44.17512 C
-195.54180 -44.17512 193.52580 -44.17512 191.50980 -44.17512 C
-185.82180 -54.83112 185.96580 -59.22312 174.22980 -61.09512 C
-169.18980 -57.71112 169.62180 -56.55912 168.61380 -51.73512 C
-167.67780 -51.59112 166.81380 -51.44712 165.94980 -51.30312 C
-153.34980 -67.43112 148.02180 -71.17512 140.38980 -51.73512 C
-133.62180 -54.32712 133.62180 -54.32712 127.64580 -58.07112 C
-116.48580 -58.07112 114.75780 -54.18312 114.10980 -44.89512 C
-106.04580 -45.47112 99.63780 -55.19112 92.29380 -59.58312 C
-89.26980 -59.58312 86.24580 -59.58312 83.29380 -59.58312 C
-78.46980 -54.75912 78.32580 -52.81512 78.75780 -47.19912 C
-72.06180 -48.49512 70.47780 -55.11912 62.19780 -55.11912 C
-57.66180 -49.35912 58.38180 -47.05512 57.73380 -40.43112 C
-53.91780 -41.51112 53.91780 -41.51112 47.94180 -44.53512 C
-24.54180 -44.53512 29.36580 -27.11112 40.45380 -14.36712 C
-48.66180 -9.83112 47.79780 -10.62312 56.94180 -10.62312 C
-77.24580 9.68088 33.90180 36.53688 22.38180 45.17688 C
-2.36580 55.18488 -17.72220 68.07288 -33.99420 82.11288 C
--37.66620 83.91288 -45.44220 89.60088 -47.53020 90.03288 C
--47.53020 90.53688 -47.53020 91.04088 -47.53020 91.54488 C
--60.56220 102.63288 -68.84220 110.04888 -77.98620 122.43288 C
--79.49820 126.96888 -82.52220 130.71288 -91.52220 146.55288 C
--107.50620 182.40888 -113.69820 219.12888 -77.62620 243.46488 C
--59.26620 249.65688 -50.26620 247.64088 -30.25020 244.90488 C
--29.31420 243.96888 -8.21820 236.12088 -4.69020 235.47288 C
--4.47420 234.89688 -4.25820 234.24888 -3.97020 233.60088 C
-4.23780 232.23288 8.19780 227.40888 16.33380 224.96088 C
-16.33380 224.45688 16.33380 223.95288 16.33380 223.44888 C
-19.06980 221.93688 21.80580 220.42488 24.61380 218.91288 C
-24.61380 218.40888 24.61380 217.90488 24.61380 217.40088 C
-34.26180 213.44088 44.84580 189.68088 49.45380 178.95288 C
-57.08580 182.84088 50.60580 193.78488 52.04580 201.56088 C
-52.04580 207.82488 50.82180 221.00088 54.27780 226.47288 C
-51.61380 269.67288 66.66180 315.53688 81.34980 355.35288 C
-84.37380 359.09688 84.37380 359.09688 93.37380 377.96088 C
-109.71780 400.35288 123.39780 430.23288 135.49380 454.85688 C
-141.97380 473.57688 150.68580 493.88088 154.28580 512.88888 C
-155.43780 514.04088 155.43780 514.04088 159.97380 514.40088 C
-154.71780 483.22488 139.81380 451.47288 126.13380 422.81688 C
-125.62980 422.74488 125.12580 422.60088 124.62180 422.45688 C
-120.37380 404.38488 103.74180 389.55288 97.90980 371.91288 C
-95.10180 366.44088 92.36580 360.89688 89.62980 355.35288 C
-85.74180 353.91288 78.18180 327.84888 76.88580 320.64888 C
-67.23780 302.07288 65.14980 271.11288 61.04580 249.80088 C
-61.04580 236.98488 58.81380 218.91288 58.09380 200.84088 C
-60.32580 164.62488 60.32580 164.62488 60.32580 155.62488 C
-58.74180 153.96888 56.79780 151.88088 54.70980 151.44888 C
-51.18180 157.92888 51.54180 163.25688 47.50980 168.44088 C
-36.99780 191.04888 34.04580 195.51288 32.53380 199.32888 C
-8.77380 229.06488 -34.28220 244.61688 -70.85820 238.92888 C
--76.76220 236.55288 -83.81820 233.74488 -86.26620 227.19288 C
--102.17820 211.28088 -97.06620 190.32888 -93.82620 169.95288 C
--88.28220 156.12888 -74.09820 119.55288 -59.55420 113.36088 C
--56.60220 108.10488 -39.97020 91.18488 -32.48220 90.03288 C
--32.48220 89.52888 -32.48220 89.02488 -32.48220 88.52088 C
--29.38620 86.79288 -26.29020 84.99288 -23.12220 83.19288 C
--23.05020 82.76088 -22.90620 82.25688 -22.76220 81.75288 C
--12.17820 77.00088 -1.16220 63.75288 10.35780 61.01688 C
-12.51780 58.85688 23.53380 52.52088 27.63780 51.58488 C
-30.73380 43.16088 45.27780 42.15288 49.45380 32.72088 C
-57.15780 29.98488 64.71780 19.11288 67.81380 10.83288 C
-67.81380 2.33688 69.61380 -5.36712 63.70980 -12.85512 C
-51.18180 -16.23912 38.50980 -18.90312 38.50980 -34.38312 C
-40.02180 -35.89512 40.02180 -35.89512 40.45380 -37.40712 C
-44.70180 -36.75912 48.94980 -36.11112 53.19780 -35.46312 C
-55.71780 -31.14312 61.33380 -27.83112 66.37380 -28.33512 C
-66.37380 -34.31112 64.93380 -40.14312 65.22180 -47.19912 C
-77.38980 -43.45512 72.70980 -30.92712 84.80580 -29.84712 C
-85.23780 -36.90312 83.86980 -43.88712 85.52580 -51.73512 C
-98.26980 -50.72712 104.67780 -40.64712 115.62180 -34.74312 C
-119.43780 -25.23912 121.30980 -18.18312 132.90180 -16.31112 C
-132.90180 -17.03112 132.90180 -17.75112 132.90180 -18.54312 C
-145.64580 -14.65512 139.59780 -8.46312 143.77380 0.32088 C
-143.77380 10.11288 143.77380 19.90488 143.77380 29.69688 C
-140.89380 49.49688 138.66180 68.86488 134.77380 87.72888 C
-134.77380 126.68088 107.70180 164.26488 107.70180 203.07288 C
-106.18980 206.88888 103.16580 233.24088 102.44580 233.96088 C
-96.32580 258.51288 101.07780 285.94488 102.44580 310.13688 C
-103.16580 313.16088 104.67780 314.67288 105.10980 319.20888 C
-106.69380 318.99288 108.27780 318.70488 109.93380 318.41688 C
-107.70180 289.76088 107.70180 289.76088 106.90980 289.04088 C
-106.90980 256.85688 110.65380 226.04088 114.46980 193.28088 C
-117.99780 181.11288 123.18180 165.92088 124.98180 152.60088 C
-132.97380 144.60888 141.75780 91.54488 143.77380 80.96088 C
-145.28580 64.40088 146.79780 59.07288 150.54180 24.44088 C
-150.25380 12.63288 150.03780 0.82488 149.82180 -10.98312 C
-142.69380 -25.31112 131.67780 -18.75912 123.46980 -31.35912 C
-122.31780 -36.47112 119.14980 -44.46312 122.38980 -49.79112 C
-132.46980 -55.04712 136.21380 -39.35112 146.43780 -38.48712 C
-146.94180 -45.25512 146.07780 -50.58312 150.18180 -56.55912 C
-153.20580 -56.55912 153.20580 -56.55912 158.02980 -54.75912 C
-161.05380 -47.91912 167.10180 -38.12712 169.76580 -32.43912 C
-171.49380 -32.58312 173.22180 -32.72712 175.02180 -32.87112 C
-175.38180 -47.19912 175.38180 -47.19912 176.53380 -52.09512 C
-185.67780 -52.09512 184.38180 -46.40712 187.40580 -38.91912 C
-188.91780 -21.71112 190.71780 -3.85512 184.38180 12.34488 C
-183.22980 23.36088 182.43780 30.12888 184.02180 40.28088 C
-183.51780 40.28088 183.01380 40.28088 182.50980 40.28088 C
-182.07780 54.39288 183.30180 68.14488 184.38180 81.75288 C
-180.13380 90.10488 179.41380 99.39288 177.97380 107.74488 C
-177.46980 107.88888 176.96580 108.03288 176.53380 108.10488 C
-175.38180 114.87288 176.10180 115.66488 175.02180 124.66488 C
-165.66180 122.50488 166.02180 122.57688 163.35780 131.50488 C
-163.35780 140.50488 164.07780 141.29688 164.79780 148.06488 C
-164.07780 148.78488 164.79780 167.64888 164.07780 193.28088 C
-163.06980 201.63288 162.06180 209.91288 161.05380 218.19288 C
-155.72580 218.62488 156.51780 215.52888 151.33380 219.70488 C
-145.57380 239.93688 152.98980 260.88888 153.92580 280.76088 C
-151.69380 280.40088 149.46180 278.09688 147.94980 278.09688 C
-138.22980 287.81688 162.34980 335.91288 163.71780 344.84088 C
-157.59780 344.26488 152.19780 327.63288 146.79780 332.74488 C
-146.79780 337.28088 148.30980 340.30488 149.02980 344.04888 C
-154.21380 353.62488 179.55780 393.36888 177.97380 404.02488 C
-177.18180 404.02488 176.46180 404.02488 175.74180 404.02488 C
-172.50180 400.13688 170.77380 397.18488 165.94980 397.18488 C
-161.48580 401.64888 168.97380 410.14488 171.56580 414.17688 C
-179.26980 431.45688 190.14180 449.60088 194.17380 467.67288 C
-198.34980 473.50488 197.91780 485.24088 205.04580 486.53688 C
-205.90980 467.38488 189.92580 438.80088 181.35780 421.66488 C
-178.83780 419.14488 179.19780 419.72088 178.76580 415.68888 C
-181.71780 416.33688 184.74180 416.98488 187.76580 417.56088 C
-188.48580 417.05688 189.20580 416.55288 189.99780 416.04888 C
-191.29380 396.46488 165.15780 373.42488 160.69380 352.32888 C
-165.30180 354.99288 168.03780 359.52888 173.50980 359.52888 C
-175.02180 358.01688 175.02180 358.01688 175.38180 356.14488 C
-166.45380 336.92088 159.68580 321.44088 155.43780 300.34488 C
-160.90980 303.08088 156.58980 308.91288 165.58980 307.83288 C
-165.58980 305.60088 165.58980 303.36888 165.58980 301.06488 C
-159.75780 280.61688 156.73380 260.09688 156.22980 238.49688 C
-158.60580 239.36088 158.53380 240.94488 159.18180 243.03288 C
-161.41380 243.03288 163.64580 243.03288 165.94980 243.03288 C
-167.53380 211.42488 170.62980 179.60088 171.99780 147.27288 C
-172.57380 147.56088 173.22180 147.84888 173.86980 148.06488 C
-175.38180 156.34488 175.38180 156.34488 177.97380 163.11288 C
-179.70180 163.11288 181.50180 163.11288 183.30180 163.11288 C
-183.44580 155.55288 183.22980 150.65688 181.35780 142.80888 C
-182.14980 125.45688 182.86980 124.66488 182.50980 114.87288 C
-183.01380 114.87288 183.51780 114.87288 184.02180 114.87288 C
-183.58980 104.00088 184.02180 99.75288 188.55780 89.24088 C
-194.53380 90.68088 208.35780 129.05688 211.45380 136.76088 C
-212.17380 144.03288 211.81380 152.16888 219.73380 145.76088 C
-220.30980 140.50488 220.95780 135.24888 221.60580 129.99288 C
-222.46980 130.28088 223.33380 130.49688 224.19780 130.71288 C
-227.22180 138.27288 230.24580 143.52888 236.22180 160.08888 C
-240.54180 168.58488 241.83780 180.75288 248.31780 187.23288 C
-248.17380 189.75288 248.02980 192.27288 247.95780 194.79288 C
-251.70180 195.15288 251.70180 195.15288 254.72580 194.07288 C
-257.02980 188.81688 259.40580 183.56088 261.78180 178.23288 C
-262.42980 178.16088 263.07780 178.01688 263.72580 177.87288 C
-270.13380 197.96088 269.34180 223.44888 269.34180 243.82488 C
-270.85380 247.56888 270.85380 252.10488 272.00580 253.97688 C
-279.99780 252.46488 282.73380 238.78488 284.74980 231.00888 C
-286.62180 231.72888 286.62180 231.72888 287.41380 233.24088 C
-288.34980 262.04088 284.53380 290.98488 285.90180 319.20888 C
-287.41380 320.64888 287.41380 320.64888 289.28580 321.08088 C
-292.52580 318.48888 296.05380 311.43288 300.51780 310.49688 C
-301.95780 318.27288 294.10980 335.98488 291.87780 343.32888 C
-288.85380 349.44888 278.77380 368.96088 282.08580 374.21688 C
-287.12580 374.57688 290.29380 369.39288 294.90180 370.40088 C
-292.66980 377.96088 292.66980 377.96088 289.64580 384.72888 C
-280.64580 397.54488 267.10980 413.38488 266.74980 414.89688 C
-246.51780 429.87288 232.18980 452.55288 221.24580 473.72088 C
-218.22180 477.03288 215.19780 480.27288 212.17380 483.51288 C
-210.66180 488.76888 210.66180 488.76888 209.22180 490.28088 C
-211.09380 510.51288 215.34180 492.22488 219.73380 488.76888 C
-221.10180 480.63288 230.31780 470.04888 233.98980 460.90488 C
-249.03780 440.52888 249.03780 440.52888 258.03780 430.73688 C
-260.98980 429.65688 276.03780 412.37688 276.46980 410.36088 C
-276.97380 410.36088 277.47780 410.36088 277.98180 410.36088 C
-277.98180 409.85688 277.98180 409.35288 277.98180 408.84888 C
-278.48580 408.84888 278.98980 408.84888 279.49380 408.84888 C
-279.56580 408.12888 279.70980 407.40888 279.85380 406.61688 C
-290.94180 394.23288 299.29380 382.49688 303.54180 365.14488 C
-304.04580 365.14488 304.54980 365.14488 305.05380 365.14488 C
-307.21380 360.82488 305.41380 356.50488 300.51780 356.50488 C
-297.78180 360.10488 295.26180 362.26488 291.51780 362.91288 C
-295.04580 340.80888 308.43780 322.30488 308.43780 297.32088 C
-307.93380 296.60088 307.42980 295.88088 306.92580 295.08888 C
-306.06180 295.01688 305.19780 294.87288 304.33380 294.72888 C
-300.15780 298.83288 297.13380 307.11288 292.30980 307.83288 C
-291.87780 298.04088 294.18180 258.08088 294.18180 236.98488 C
-293.82180 231.08088 295.76580 212.72088 287.77380 210.99288 C
-285.10980 215.16888 285.10980 215.16888 283.23780 220.42488 C
-283.81380 220.71288 284.46180 220.92888 285.10980 221.14488 C
-284.96580 221.79288 284.82180 222.44088 284.74980 223.08888 C
-279.20580 225.39288 278.91780 232.88088 277.98180 237.77688 C
-277.18980 237.77688 276.46980 237.77688 275.74980 237.77688 C
-274.95780 215.02488 274.38180 188.52888 268.54980 165.41688 C
-265.88580 162.60888 265.59780 162.39288 262.21380 162.39288 C
-261.78180 165.92088 261.42180 169.44888 261.06180 172.90488 C
-255.37380 175.56888 255.80580 176.93688 253.93380 181.61688 C
-252.92580 181.76088 251.91780 181.90488 250.90980 181.97688 C
-241.54980 157.85688 233.91780 137.69688 230.24580 111.84888 C
-224.41380 90.17688 215.55780 70.01688 207.70980 48.56088 C
-204.68580 32.00088 204.68580 32.00088 198.63780 6.36888 C
-198.34980 -8.96712 198.06180 -23.22312 199.42980 -38.91912 C
-202.45380 -46.40712 202.45380 -46.40712 203.53380 -51.30312 C
-204.75780 -51.30312 206.05380 -51.30312 207.34980 -51.30312 C
-210.44580 -47.48712 209.86980 -46.40712 209.58180 -41.94312 C
-212.67780 -39.99912 212.38980 -39.99912 216.70980 -40.43112 C
-220.02180 -46.98312 220.45380 -54.18312 225.34980 -61.88712 C
-226.42980 -61.74312 227.58180 -61.59912 228.73380 -61.52712 C
-231.54180 -54.68712 230.46180 -45.90312 230.60580 -38.91912 C
-239.53380 -41.51112 238.95780 -53.60712 247.16580 -53.60712 C
-255.94980 -42.66312 244.14180 -32.29512 236.22180 -26.10312 C
-229.30980 -11.55912 231.68580 13.49688 240.75780 25.16088 C
-253.06980 55.32888 270.13380 81.17688 285.90180 108.82488 C
-309.94980 168.44088 309.94980 168.44088 314.41380 181.97688 C
-323.34180 215.45688 327.30180 248.64888 330.97380 282.27288 C
-335.36580 286.23288 330.39780 325.25688 334.35780 332.38488 C
-343.35780 332.38488 338.10180 314.16888 339.97380 306.39288 C
-337.02180 261.89688 337.02180 261.89688 334.71780 245.26488 C
-329.67780 231.72888 328.23780 216.46488 326.50980 201.56088 C
-318.51780 172.68888 307.14180 144.53688 296.41380 116.38488 C
-281.36580 88.52088 278.34180 84.70488 269.70180 67.78488 C
-269.19780 67.71288 268.69380 67.56888 268.18980 67.42488 C
-253.06980 37.47288 235.93380 15.65688 240.75780 -18.54312 C
-245.22180 -24.23112 254.14980 -28.83912 256.16580 -37.40712 C
-257.89380 -37.26312 259.62180 -37.11912 261.42180 -36.97512 C
-264.94980 -41.15112 275.67780 -57.85512 284.38980 -56.19912 C
-284.24580 -52.88712 284.10180 -49.64712 284.02980 -46.40712 C
-289.57380 -47.41512 293.53380 -48.35112 294.54180 -55.47912 C
-295.04580 -55.47912 295.54980 -55.47912 296.05380 -55.47912 C
-293.74980 -61.59912 290.86980 -64.04712 285.54180 -68.65512 C
-274.09380 -65.34312 266.67780 -52.81512 254.72580 -52.81512 C
-250.18980 -60.66312 250.33380 -63.03912 241.18980 -60.73512 C
-241.18980 -60.23112 241.18980 -59.72712 241.18980 -59.22312 C
-239.67780 -58.71912 238.16580 -58.21512 236.65380 -57.71112 C
-234.27780 -63.32712 233.34180 -70.16712 226.14180 -70.16712 C
-@c
-F
-
-@rax %Note: Object
-298.07433 -67.14312 601.62180 853.66488 @E
- 1 O 0 @g
-0.00 0.00 0.00 1.00 k
-/$fm 0 def
-303.54180 -67.14312 m
-302.02980 -66.63912 300.51780 -66.13512 299.07780 -65.63112 C
-297.92580 -63.03912 297.92580 -63.03912 298.28580 -58.86312 C
-300.01380 -58.86312 301.74180 -58.86312 303.54180 -58.86312 C
-307.50180 -54.90312 306.70980 -44.53512 306.20580 -39.63912 C
-311.10180 -39.27912 311.10180 -39.27912 314.05380 -40.43112 C
-320.82180 -51.30312 322.69380 -52.45512 323.84580 -55.11912 C
-327.30180 -54.97512 330.82980 -54.83112 334.35780 -54.75912 C
-334.35780 -53.75112 334.35780 -52.74312 334.35780 -51.73512 C
-334.86180 -51.73512 335.36580 -51.73512 335.86980 -51.73512 C
-337.02180 -47.19912 337.02180 -47.19912 337.02180 -44.17512 C
-327.80580 -25.67112 327.44580 -15.66312 330.25380 3.34488 C
-332.34180 8.96088 337.16580 16.08888 338.17380 21.41688 C
-338.74980 21.70488 339.32580 21.92088 339.97380 22.13688 C
-346.38180 37.68888 373.66980 51.36888 389.29380 57.20088 C
-406.57380 69.87288 430.47780 82.11288 444.51780 98.31288 C
-454.38180 105.65688 464.31780 113.14488 470.43780 123.94488 C
-483.39780 133.95288 486.99780 162.24888 488.86980 178.23288 C
-482.38980 195.80088 481.30980 201.92088 463.66980 206.52888 C
-442.64580 206.52888 442.64580 206.52888 441.92580 205.73688 C
-427.74180 200.55288 413.19780 196.66488 399.80580 190.68888 C
-390.22980 183.20088 380.72580 175.64088 371.22180 168.08088 C
-364.52580 159.51288 354.22980 131.28888 347.89380 130.35288 C
-345.30180 132.94488 346.23780 134.60088 346.02180 137.48088 C
-354.87780 167.43288 364.52580 198.24888 369.34980 228.70488 C
-381.44580 270.10488 388.86180 308.91288 390.37380 351.60888 C
-388.86180 373.42488 388.86180 373.42488 384.39780 409.64088 C
-383.60580 411.15288 382.88580 417.92088 381.37380 420.94488 C
-380.58180 425.48088 379.86180 426.20088 373.81380 456.36888 C
-370.86180 464.64888 364.81380 475.95288 358.83780 489.56088 C
-357.03780 501.72888 349.69380 514.11288 345.66180 524.98488 C
-344.65380 524.98488 343.64580 524.98488 342.63780 524.98488 C
-342.27780 528.00888 340.76580 529.52088 339.25380 533.26488 C
-338.60580 536.79288 337.95780 540.32088 337.38180 543.84888 C
-336.87780 543.84888 336.37380 543.84888 335.86980 543.84888 C
-332.77380 559.97688 327.80580 575.81688 324.99780 591.29688 C
-321.32580 630.10488 322.76580 667.40088 323.48580 705.92088 C
-327.94980 740.55288 327.94980 740.55288 329.46180 744.36888 C
-331.33380 745.16088 333.20580 745.88088 335.14980 746.60088 C
-336.44580 742.85688 334.28580 731.98488 332.48580 728.52888 C
-328.95780 684.89688 327.44580 639.46488 331.76580 595.11288 C
-335.36580 576.75288 339.75780 557.74488 345.66180 539.31288 C
-346.23780 539.09688 346.88580 538.80888 347.53380 538.52088 C
-349.40580 530.09688 353.86980 523.11288 357.32580 514.40088 C
-358.18980 514.18488 359.05380 513.96888 359.91780 513.68088 C
-365.89380 545.43288 375.18180 574.88088 382.88580 605.62488 C
-401.53380 651.27288 424.42980 692.74488 448.26180 736.01688 C
-458.12580 763.37688 472.38180 786.70488 476.84580 815.93688 C
-476.84580 828.60888 479.58180 841.92888 482.46180 853.66488 C
-484.47780 853.66488 486.49380 853.66488 488.50980 853.66488 C
-488.43780 834.94488 486.13380 815.36088 490.38180 796.35288 C
-493.26180 789.72888 496.14180 783.10488 499.02180 776.40888 C
-507.44580 777.41688 514.14180 809.96088 526.09380 807.29688 C
-527.24580 805.42488 527.24580 805.42488 528.68580 798.58488 C
-528.25380 776.55288 526.81380 759.12888 533.65380 737.52888 C
-534.58980 737.67288 535.59780 737.81688 536.60580 737.96088 C
-542.22180 746.60088 542.22180 746.60088 552.80580 766.18488 C
-555.39780 767.33688 555.39780 767.33688 558.42180 767.33688 C
-560.29380 765.46488 560.43780 756.53688 558.78180 753.36888 C
-560.14980 737.67288 562.88580 723.27288 565.98180 707.43288 C
-566.41380 707.43288 566.91780 707.43288 567.42180 707.43288 C
-567.78180 704.40888 568.57380 703.61688 572.31780 692.31288 C
-577.57380 664.44888 579.08580 660.63288 582.10980 642.56088 C
-585.13380 631.25688 588.08580 615.41688 589.59780 611.67288 C
-596.79780 564.80088 599.96580 516.05688 601.62180 467.67288 C
-598.74180 428.57688 594.06180 394.52088 585.85380 356.14488 C
-581.31780 341.81688 579.87780 340.30488 573.82980 321.44088 C
-555.82980 286.30488 540.78180 254.48088 516.66180 222.65688 C
-508.52580 217.97688 501.32580 198.68088 493.04580 196.30488 C
-492.61380 194.28888 492.25380 192.27288 491.89380 190.25688 C
-492.90180 188.02488 493.90980 185.79288 494.91780 183.48888 C
-496.28580 148.49688 481.45380 117.60888 452.43780 96.44088 C
-426.80580 70.80888 395.05380 55.11288 364.81380 36.46488 C
-364.45380 35.88888 364.09380 35.24088 363.73380 34.59288 C
-342.70980 24.87288 336.66180 4.78488 335.50980 -17.03112 C
-341.55780 -32.94312 352.06980 -51.66312 333.63780 -64.11912 C
-322.83780 -64.11912 320.60580 -52.88712 314.05380 -51.73512 C
-313.26180 -57.99912 312.10980 -67.14312 303.54180 -67.14312 C
-@c
-F
-
-@rax %Note: Object
-541.14180 -56.55912 585.85380 -26.96088 @E
- 1 O 0 @g
-0.00 0.00 0.00 0.00 k
-/$fm 0 def
-570.44580 -56.55912 m
-563.46180 -53.24712 556.11780 -54.68712 552.44580 -47.91912 C
-551.94180 -47.91912 551.43780 -47.91912 550.93380 -47.91912 C
-547.26180 -39.20712 540.42180 -37.55112 541.14180 -27.18312 C
-559.35780 -25.95912 558.78180 -29.70312 574.18980 -40.43112 C
-577.35780 -44.96712 579.73380 -50.07912 585.49380 -52.81512 C
-585.56580 -53.46312 585.70980 -54.11112 585.85380 -54.75912 C
-583.26180 -55.11912 580.23780 -53.60712 574.18980 -53.96712 C
-573.90180 -54.83112 573.68580 -55.69512 573.46980 -56.55912 C
-572.46180 -56.55912 571.45380 -56.55912 570.44580 -56.55912 C
-@c
-F
-
-@rax %Note: Object
-598.30980 -56.55912 637.40580 -21.56712 @E
- 1 O 0 @g
-0.00 0.00 0.00 0.00 k
-/$fm 0 def
-602.77380 -56.55912 m
-601.26180 -56.41512 599.74980 -56.27112 598.30980 -56.19912 C
-599.82180 -48.35112 607.95780 -48.63912 614.07780 -44.53512 C
-618.90180 -36.90312 629.98980 -23.79912 637.40580 -21.56712 C
-635.82180 -34.02312 633.87780 -42.37512 624.58980 -50.58312 C
-612.56580 -53.60712 605.79780 -56.55912 602.77380 -56.55912 C
-@c
-F
-
-@rax %Note: Object
--189.56041 -47.56365 -38.17020 169.95288 @E
- 1 O 0 @g
-0.00 0.00 0.00 1.00 k
-/$fm 0 def
--111.46620 -47.55912 m
--128.09820 -39.13512 -147.17820 -16.16712 -147.17820 2.55288 C
--140.19420 11.33688 -142.42620 15.65688 -129.46620 11.98488 C
--126.51420 9.96888 -106.42620 -5.72712 -103.90620 -5.72712 C
--103.90620 -6.44712 -103.90620 -7.16712 -103.90620 -7.95912 C
--98.93820 -11.48712 -95.91420 -15.59112 -91.88220 -21.13512 C
--91.01820 -20.99112 -90.15420 -20.84712 -89.29020 -20.77512 C
--90.73020 17.67288 -95.98620 41.64888 -120.10620 71.88888 C
--120.75420 72.17688 -121.40220 72.46488 -121.97820 72.68088 C
--121.97820 73.18488 -121.97820 73.68888 -121.97820 74.19288 C
--122.98620 74.19288 -123.99420 74.19288 -125.00220 74.19288 C
--128.31420 62.02488 -131.12220 48.20088 -146.02620 48.20088 C
--155.53020 54.17688 -156.82620 67.49688 -155.02620 77.21688 C
--164.09820 76.35288 -177.56220 44.96088 -189.29820 60.58488 C
--190.30620 82.25688 -189.44220 95.07288 -172.37820 109.97688 C
--172.30620 110.91288 -172.16220 111.77688 -172.01820 112.64088 C
--188.43420 129.48888 -190.16220 134.16888 -186.63420 157.13688 C
--185.91420 157.49688 -185.19420 157.85688 -184.40220 158.21688 C
--179.79420 172.11288 -168.70620 168.87288 -158.05020 163.54488 C
--157.33020 161.60088 -150.92220 156.34488 -150.56220 154.83288 C
--149.55420 154.97688 -148.54620 155.12088 -147.53820 155.26488 C
--142.85820 161.88888 -136.01820 162.17688 -133.28220 169.95288 C
--112.76220 169.01688 -117.44220 150.00888 -120.89820 135.24888 C
--120.75420 133.73688 -120.61020 132.22488 -120.46620 130.71288 C
--87.05820 139.13688 -95.77020 106.80888 -106.57020 87.72888 C
--110.53020 84.27288 -112.69020 83.26488 -117.44220 81.75288 C
--115.42620 71.88888 -107.36220 66.48888 -102.39420 56.84088 C
--92.89020 53.31288 -84.17820 2.62488 -82.52220 -6.44712 C
--81.65820 -6.51912 -80.79420 -6.66312 -79.85820 -6.80712 C
--69.99420 3.05688 -64.23420 16.66488 -52.06620 24.80088 C
--42.34620 34.52088 -41.98620 32.50488 -38.17020 19.90488 C
--38.17020 -14.36712 -48.53820 -36.83112 -85.11420 -42.30312 C
--95.12220 -47.91912 -100.81020 -47.55912 -111.46620 -47.55912 C
-@c
-F
-
-@rax %Note: Object
-588.87780 -47.55912 627.61380 15.36888 @E
- 1 O 0 @g
-0.00 0.00 0.00 0.00 k
-/$fm 0 def
-590.74980 -47.55912 m
-590.10180 -47.12712 589.45380 -46.76712 588.87780 -46.40712 C
-588.87780 -37.62312 595.42980 -24.01512 599.38980 -17.03112 C
-599.53380 -16.81512 619.54980 13.92888 627.61380 15.36888 C
-626.38980 4.42488 602.70180 -47.55912 590.74980 -47.55912 C
-@c
-F
-
-@rax %Note: Object
--139.86539 -40.79112 -93.03420 6.00888 @E
- 1 O 0 @g
-0.00 0.00 0.00 0.00 k
-/$fm 0 def
--106.21020 -40.79112 m
--121.61820 -36.83112 -128.67420 -23.43912 -137.38620 -11.77512 C
--138.68220 -4.14312 -143.29020 0.39288 -135.51420 6.00888 C
--126.94620 6.00888 -99.94620 -15.08712 -98.65020 -24.59112 C
--93.82620 -27.83112 -94.40220 -31.28712 -93.03420 -37.40712 C
--94.18620 -38.48712 -99.44220 -39.99912 -106.21020 -40.79112 C
-@c
-F
-
-@rax %Note: Object
--81.37020 -33.23112 -44.62016 20.62488 @E
- 1 O 0 @g
-0.00 0.00 0.00 0.00 k
-/$fm 0 def
--77.62620 -33.23112 m
--78.92220 -32.72712 -80.14620 -32.22312 -81.37020 -31.71912 C
--83.60220 -18.25512 -57.89820 18.39288 -45.29820 20.62488 C
--41.84220 -1.04712 -51.41820 -33.23112 -77.62620 -33.23112 C
-@c
-F
-
-@rax %Note: Object
-629.12580 -17.39112 637.40580 -7.95912 @E
- 1 O 0 @g
-0.00 0.00 0.00 0.00 k
-/$fm 0 def
-630.63780 -17.39112 m
-629.48580 -16.31112 629.48580 -16.31112 629.12580 -14.00712 C
-632.94180 -12.56712 632.79780 -8.75112 637.40580 -7.95912 C
-635.38980 -11.99112 633.80580 -14.22312 630.63780 -17.39112 C
-@c
-F
-
-@rax %Note: Object
-506.97326 6.00888 539.26980 55.32888 @E
- 1 O 0 @g
-0.00 0.00 0.00 0.00 k
-/$fm 0 def
-509.53380 6.00888 m
-498.73380 12.70488 521.55780 53.60088 533.65380 55.32888 C
-534.73380 50.79288 536.31780 48.56088 539.26980 44.02488 C
-537.68580 32.57688 522.99780 6.00888 509.53380 6.00888 C
-@c
-F
-
-@rax %Note: Object
-543.60794 8.96088 557.79506 45.17688 @E
- 1 O 0 @g
-0.00 0.00 0.00 0.00 k
-/$fm 0 def
-547.18980 8.96088 m
-543.80580 18.10488 540.78180 38.04888 547.90980 45.17688 C
-549.49380 45.03288 551.14980 44.88888 552.80580 44.74488 C
-552.87780 44.31288 553.02180 43.80888 553.16580 43.30488 C
-554.17380 43.08888 555.18180 42.80088 556.18980 42.51288 C
-560.22180 31.20888 556.26180 18.68088 549.42180 8.96088 C
-548.62980 8.96088 547.90980 8.96088 547.18980 8.96088 C
-@c
-F
-
-@rax %Note: Object
-188.91780 12.34488 223.83780 123.15288 @E
- 1 O 0 @g
-0.00 0.00 0.00 0.00 k
-/$fm 0 def
-191.50980 12.34488 m
-189.42180 32.00088 188.91780 50.28888 188.91780 69.65688 C
-193.81380 75.56088 193.81380 77.28888 194.89380 84.70488 C
-201.37380 96.80088 206.41380 110.98488 212.96580 122.43288 C
-213.82980 122.72088 214.69380 122.93688 215.62980 123.15288 C
-216.42180 121.06488 216.49380 121.35288 219.37380 120.12888 C
-218.22180 117.89688 218.22180 117.89688 218.22180 113.36088 C
-220.09380 111.48888 220.38180 110.76888 223.83780 110.33688 C
-214.26180 85.35288 203.24580 59.36088 198.63780 32.72088 C
-195.39780 29.48088 195.68580 21.27288 195.68580 16.16088 C
-195.03780 15.94488 194.38980 15.65688 193.81380 15.36888 C
-193.52580 14.50488 193.23780 13.64088 193.02180 12.77688 C
-192.51780 12.63288 192.01380 12.48888 191.50980 12.34488 C
-@c
-F
-
-@rax %Note: Object
-699.67219 12.77688 716.67780 40.64088 @E
- 1 O 0 @g
-0.00 0.00 0.00 0.00 k
-/$fm 0 def
-700.54980 12.77688 m
-697.38180 15.72888 703.35780 27.96888 704.65380 32.00088 C
-708.39780 36.17688 709.83780 39.92088 715.59780 40.64088 C
-715.95780 35.52888 716.31780 30.34488 716.67780 25.16088 C
-711.78180 20.55288 706.95780 14.14488 700.54980 12.77688 C
-@c
-F
-
-@rax %Note: Object
-724.59780 27.82488 753.30454 57.27969 @E
- 1 O 0 @g
-0.00 0.00 0.00 0.00 k
-/$fm 0 def
-728.34180 27.82488 m
-727.04580 28.25688 725.82180 28.61688 724.59780 28.97688 C
-727.18980 37.97688 727.98180 38.76888 728.34180 41.79288 C
-727.69380 42.08088 727.04580 42.29688 726.46980 42.51288 C
-726.46980 43.30488 726.46980 44.02488 726.46980 44.74488 C
-736.69380 52.23288 737.55780 60.94488 753.18180 55.76088 C
-755.55780 42.58488 740.72580 27.82488 728.34180 27.82488 C
-@c
-F
-
-@rax %Note: Object
-678.83386 34.59288 711.42180 59.81074 @E
- 1 O 0 @g
-0.00 0.00 0.00 0.00 k
-/$fm 0 def
-680.24580 34.59288 m
-674.98980 39.84888 685.14180 50.14488 687.73380 54.24888 C
-699.68580 60.94488 699.03780 62.02488 711.42180 55.32888 C
-711.42180 42.51288 689.67780 34.59288 680.24580 34.59288 C
-@c
-F
-
-@rax %Note: Object
-719.07591 48.20088 727.83128 59.07288 @E
- 1 O 0 @g
-0.00 0.00 0.00 0.00 k
-/$fm 0 def
-719.34180 48.20088 m
-718.90980 53.81688 718.90980 53.81688 720.06180 59.07288 C
-727.62180 58.71288 730.28580 58.92888 725.31780 51.22488 C
-720.85380 48.20088 720.85380 48.20088 719.34180 48.20088 C
-@c
-F
-
-@rax %Note: Object
-557.36759 50.79288 593.94898 88.52088 @E
- 1 O 0 @g
-0.00 0.00 0.00 0.00 k
-/$fm 0 def
-558.42180 50.79288 m
-555.54180 56.62488 559.35780 65.84088 560.29380 71.16888 C
-570.22980 81.10488 576.06180 89.38488 591.54180 88.52088 C
-601.98180 73.76088 578.36580 56.62488 565.98180 51.22488 C
-563.46180 51.08088 560.94180 50.93688 558.42180 50.79288 C
-@c
-F
-
-@rax %Note: Object
-540.92665 51.58488 551.95087 69.33402 @E
- 1 O 0 @g
-0.00 0.00 0.00 0.00 k
-/$fm 0 def
-541.86180 51.58488 m
-540.78180 56.84088 540.78180 56.84088 541.14180 59.50488 C
-541.71780 59.86488 542.36580 60.22488 543.01380 60.58488 C
-543.22980 62.88888 543.44580 65.19288 543.73380 67.42488 C
-555.61380 76.28088 554.38980 52.73688 541.86180 51.58488 C
-@c
-F
-
-@rax %Note: Object
-488.86980 54.24888 525.73380 75.31569 @E
- 1 O 0 @g
-0.00 0.00 0.00 0.00 k
-/$fm 0 def
-496.78980 54.24888 m
-492.75780 56.12088 490.81380 56.98488 488.86980 59.86488 C
-488.86980 72.96888 502.11780 78.15288 513.34980 73.83288 C
-517.16580 68.93688 519.25380 65.33688 525.73380 62.88888 C
-524.94180 58.71288 501.68580 54.24888 496.78980 54.24888 C
-@c
-F
-
-@rax %Note: Object
--148.92803 55.76088 -131.77020 92.92195 @E
- 1 O 0 @g
-0.00 0.00 0.00 0.00 k
-/$fm 0 def
--145.30620 55.76088 m
--145.81020 55.90488 -146.31420 56.04888 -146.81820 56.12088 C
--150.41820 68.28888 -149.05020 78.72888 -145.66620 90.03288 C
--141.63420 92.55288 -138.03420 95.72088 -137.02620 88.52088 C
--136.52220 88.52088 -136.01820 88.52088 -135.51420 88.52088 C
--130.25820 81.03288 -129.53820 60.58488 -139.25820 55.76088 C
--141.27420 55.76088 -143.29020 55.76088 -145.30620 55.76088 C
-@c
-F
-
-@rax %Note: Object
--184.04220 63.24888 -154.66620 105.08088 @E
- 1 O 0 @g
-0.00 0.00 0.00 0.00 k
-/$fm 0 def
--182.89020 63.24888 m
--183.32220 63.89688 -183.68220 64.54488 -184.04220 65.12088 C
--184.04220 83.04888 -181.16220 106.30488 -158.48220 105.08088 C
--157.69020 100.54488 -156.17820 98.31288 -154.66620 90.03288 C
--160.06620 82.11288 -173.89020 63.24888 -182.89020 63.24888 C
-@c
-F
-
-@rax %Note: Object
-726.10980 64.04088 761.46180 97.16088 @E
- 1 O 0 @g
-0.00 0.00 0.00 0.00 k
-/$fm 0 def
-731.36580 64.04088 m
-729.85380 65.55288 729.85380 65.55288 726.10980 66.63288 C
-734.53380 86.00088 738.70980 95.00088 761.46180 97.16088 C
-762.39780 85.92888 740.36580 64.04088 731.36580 64.04088 C
-@c
-F
-
-@rax %Note: Object
-701.93367 66.63288 726.32353 97.52088 @E
- 1 O 0 @g
-0.00 0.00 0.00 0.00 k
-/$fm 0 def
-714.80580 66.63288 m
-714.80580 67.13688 714.80580 67.64088 714.80580 68.14488 C
-711.99780 68.07288 709.26180 67.92888 706.52580 67.78488 C
-694.86180 84.92088 706.81380 98.45688 724.95780 97.52088 C
-728.12580 89.81688 725.74980 83.26488 719.70180 77.21688 C
-718.98180 73.68888 718.62180 68.28888 714.80580 66.63288 C
-@c
-F
-
-@rax %Note: Object
-514.93266 70.01688 535.14000 103.06035 @E
- 1 O 0 @g
-0.00 0.00 0.00 0.00 k
-/$fm 0 def
-533.65380 70.01688 m
-516.73380 80.31288 510.75780 83.19288 517.81380 102.05688 C
-521.55780 103.20888 521.55780 103.20888 530.19780 102.84888 C
-536.10180 92.40888 535.38180 82.97688 534.73380 70.37688 C
-534.37380 70.30488 534.01380 70.16088 533.65380 70.01688 C
-@c
-F
-
-@rax %Note: Object
-651.61899 74.55288 671.53380 110.33688 @E
- 1 O 0 @g
-0.00 0.00 0.00 0.00 k
-/$fm 0 def
-654.68580 74.55288 m
-653.67780 74.69688 652.66980 74.84088 651.66180 74.91288 C
-651.51780 89.88888 651.30180 97.80888 658.42980 110.33688 C
-659.65380 110.33688 660.87780 110.33688 662.17380 110.33688 C
-662.46180 105.51288 666.63780 104.36088 671.53380 102.05688 C
-670.45380 89.31288 664.69380 84.77688 656.19780 74.55288 C
-655.69380 74.55288 655.18980 74.55288 654.68580 74.55288 C
-@c
-F
-
-@rax %Note: Object
-544.45153 76.85688 568.13386 119.04888 @E
- 1 O 0 @g
-0.00 0.00 0.00 0.00 k
-/$fm 0 def
-550.14180 76.85688 m
-549.63780 77.36088 549.13380 77.86488 548.62980 78.36888 C
-547.33380 78.22488 546.10980 78.08088 544.88580 77.93688 C
-543.08580 96.22488 546.10980 107.31288 561.44580 119.04888 C
-562.45380 119.04888 563.46180 119.04888 564.46980 119.04888 C
-574.54980 108.96888 561.87780 76.85688 550.14180 76.85688 C
-@c
-F
-
-@rax %Note: Object
--133.33408 89.67288 -102.20400 126.60888 @E
- 1 O 0 @g
-0.00 0.00 0.00 0.00 k
-/$fm 0 def
--119.74620 89.67288 m
--134.07420 91.25688 -135.15420 102.99288 -131.77020 115.30488 C
--122.12220 122.14488 -117.80220 126.60888 -105.41820 126.60888 C
--97.57020 116.16888 -105.56220 101.26488 -110.31420 90.75288 C
--113.69820 89.67288 -113.69820 89.67288 -119.74620 89.67288 C
-@c
-F
-
-@rax %Note: Object
-580.23780 90.75288 584.77380 93.05688 @E
- 1 O 0 @g
-0.00 0.00 0.00 0.00 k
-/$fm 0 def
-580.23780 90.75288 m
-580.23780 91.54488 580.23780 92.33688 580.23780 93.05688 C
-581.74980 92.98488 583.26180 92.84088 584.77380 92.69688 C
-583.26180 92.04888 581.74980 91.40088 580.23780 90.75288 C
-@c
-F
-
-@rax %Note: Object
-619.22239 92.69688 651.30180 125.09688 @E
- 1 O 0 @g
-0.00 0.00 0.00 0.00 k
-/$fm 0 def
-620.84580 92.69688 m
-614.72580 102.56088 626.24580 119.33688 633.58980 125.09688 C
-638.84580 125.09688 639.63780 124.30488 650.94180 123.94488 C
-650.50980 117.17688 651.30180 115.66488 651.30180 113.36088 C
-642.87780 105.65688 632.00580 94.06488 620.84580 92.69688 C
-@c
-F
-
-@rax %Note: Object
--152.07420 97.95288 -138.89820 120.81515 @E
- 1 O 0 @g
-0.00 0.00 0.00 0.00 k
-/$fm 0 def
--148.25820 97.95288 m
--149.05020 98.31288 -149.84220 98.67288 -150.56220 99.03288 C
--150.56220 99.53688 -150.56220 100.04088 -150.56220 100.54488 C
--151.06620 100.54488 -151.57020 100.54488 -152.07420 100.54488 C
--152.00220 106.01688 -150.41820 129.41688 -138.89820 117.89688 C
--138.89820 111.84888 -139.97820 97.95288 -148.25820 97.95288 C
-@c
-F
-
-@rax %Note: Object
-668.58180 110.76888 708.03780 145.07943 @E
- 1 O 0 @g
-0.00 0.00 0.00 0.00 k
-/$fm 0 def
-672.68580 110.76888 m
-671.31780 111.63288 669.94980 112.49688 668.58180 113.36088 C
-668.58180 118.54488 672.10980 120.41688 675.34980 123.94488 C
-678.15780 136.40088 691.04580 146.55288 704.29380 145.04088 C
-705.08580 142.66488 704.86980 142.16088 708.03780 140.50488 C
-704.50980 120.41688 691.98180 113.93688 672.68580 110.76888 C
-@c
-F
-
-@rax %Note: Object
--183.02854 116.81688 -152.93820 161.29474 @E
- 1 O 0 @g
-0.00 0.00 0.00 0.00 k
-/$fm 0 def
--167.12220 116.81688 m
--180.44220 127.32888 -186.49020 138.92088 -181.01820 154.83288 C
--174.03420 163.47288 -170.21820 162.17688 -160.35420 158.57688 C
--160.35420 158.14488 -160.35420 157.64088 -160.35420 157.13688 C
--148.83420 149.00088 -153.73020 135.89688 -155.45820 123.15288 C
--159.77820 119.69688 -161.72220 116.81688 -167.12220 116.81688 C
-@c
-F
-
-@rax %Note: Object
-659.14980 119.04888 668.26687 128.48088 @E
- 1 O 0 @g
-0.00 0.00 0.00 0.00 k
-/$fm 0 def
-659.14980 119.04888 m
-658.64580 125.24088 662.82180 127.54488 668.22180 128.48088 C
-668.43780 124.23288 667.93380 123.72888 665.55780 119.40888 C
-663.39780 119.33688 661.23780 119.19288 659.14980 119.04888 C
-@c
-F
-
-@rax %Note: Object
--144.71291 122.79288 -122.98989 162.75288 @E
- 1 O 0 @g
-0.00 0.00 0.00 0.00 k
-/$fm 0 def
--134.72220 122.79288 m
--138.10620 125.60088 -140.62620 127.25688 -144.51420 126.17688 C
--144.15420 144.39288 -147.97020 150.65688 -134.00220 162.75288 C
--114.05820 162.75288 -126.08220 134.38488 -130.97820 123.58488 C
--132.49020 122.79288 -132.49020 122.79288 -134.72220 122.79288 C
-@c
-F
-
-@rax %Note: Object
-665.14394 133.73688 696.37380 175.20888 @E
- 1 O 0 @g
-0.00 0.00 0.00 0.00 k
-/$fm 0 def
-665.91780 133.73688 m
-665.48580 143.16888 662.89380 150.65688 670.09380 157.85688 C
-671.31780 163.11288 683.91780 172.11288 688.52580 174.84888 C
-690.97380 174.99288 693.49380 175.13688 696.01380 175.20888 C
-696.08580 172.47288 696.22980 169.73688 696.37380 166.92888 C
-692.62980 159.36888 674.98980 135.96888 665.91780 133.73688 C
-@c
-F
-
-@rax %Note: Object
-636.69175 135.60888 655.88287 167.28888 @E
- 1 O 0 @g
-0.00 0.00 0.00 0.00 k
-/$fm 0 def
-638.84580 135.60888 m
-634.02180 140.43288 638.41380 156.77688 640.35780 162.39288 C
-644.96580 164.04888 645.25380 167.28888 652.38180 167.28888 C
-656.91780 162.75288 657.06180 142.59288 652.74180 135.96888 C
-648.06180 135.89688 643.45380 135.75288 638.84580 135.60888 C
-@c
-F
-
-@rax %Note: Object
-694.14180 147.70488 699.03780 151.80888 @E
- 1 O 0 @g
-0.00 0.00 0.00 0.00 k
-/$fm 0 def
-694.50180 147.70488 m
-694.35780 148.85688 694.21380 150.00888 694.14180 151.08888 C
-695.22180 151.37688 696.37380 151.59288 697.52580 151.80888 C
-697.52580 151.30488 697.52580 150.80088 697.52580 150.29688 C
-698.02980 150.29688 698.53380 150.29688 699.03780 150.29688 C
-698.74980 149.72088 698.46180 149.07288 698.24580 148.42488 C
-696.94980 148.20888 695.72580 147.99288 694.50180 147.70488 C
-@c
-F
-
-@rax %Note: Object
-363.73380 173.69688 594.13380 799.37688 @E
- 1 O 0 @g
-0.00 0.00 0.00 0.00 k
-/$fm 0 def
-363.73380 173.69688 m
-364.81380 180.46488 370.86180 203.07288 376.83780 231.00888 C
-377.62980 231.72888 380.58180 242.31288 381.37380 243.03288 C
-388.42980 277.59288 394.98180 310.78488 397.93380 345.56088 C
-397.93380 357.65688 397.14180 359.09688 397.14180 367.44888 C
-391.16580 413.38488 391.16580 413.38488 390.37380 414.17688 C
-387.27780 428.14488 383.38980 442.18488 381.73380 455.64888 C
-381.22980 455.64888 380.72580 455.64888 380.22180 455.64888 C
-379.06980 462.41688 376.11780 469.18488 372.73380 482.79288 C
-372.22980 482.79288 371.72580 482.79288 371.22180 482.79288 C
-369.78180 488.33688 368.41380 493.88088 367.04580 499.35288 C
-365.74980 522.24888 371.22180 547.44888 378.70980 568.32888 C
-379.28580 568.25688 379.93380 568.11288 380.58180 567.96888 C
-382.52580 555.94488 384.25380 532.25688 398.29380 526.85688 C
-416.29380 526.85688 428.74980 537.72888 443.36580 547.95288 C
-444.37380 548.09688 445.38180 548.24088 446.38980 548.31288 C
-446.74980 547.59288 447.10980 546.87288 447.54180 546.08088 C
-448.18980 527.43288 444.30180 464.28888 473.46180 464.28888 C
-484.40580 472.35288 489.80580 482.21688 499.02180 491.43288 C
-499.88580 491.36088 500.74980 491.21688 501.68580 491.07288 C
-501.68580 479.26488 501.68580 467.45688 501.68580 455.64888 C
-503.62980 446.21688 505.14180 430.52088 514.78980 424.32888 C
-533.72580 424.32888 535.09380 444.48888 550.14180 446.57688 C
-552.80580 426.20088 552.80580 426.20088 553.52580 412.66488 C
-558.06180 400.20888 568.28580 389.19288 582.10980 399.84888 C
-582.10980 405.60888 575.12580 403.44888 571.23780 403.59288 C
-570.80580 404.38488 570.44580 405.17688 570.08580 405.89688 C
-567.70980 406.18488 565.33380 406.40088 562.95780 406.61688 C
-558.42180 421.08888 558.13380 435.20088 556.54980 449.60088 C
-553.88580 452.98488 552.44580 453.34488 552.44580 454.85688 C
-541.35780 452.62488 536.46180 446.28888 529.47780 438.29688 C
-525.51780 435.27288 521.77380 431.16888 517.09380 431.16888 C
-501.97380 449.96088 511.54980 482.93688 506.58180 504.60888 C
-489.51780 503.96088 486.27780 471.84888 466.69380 471.84888 C
-457.62180 480.92088 455.89380 512.24088 455.02980 523.47288 C
-455.02980 533.26488 455.24580 549.03288 451.64580 557.38488 C
-450.13380 557.52888 448.62180 557.67288 447.18180 557.74488 C
-433.71780 551.33688 410.60580 528.22488 396.78180 535.13688 C
-386.98980 553.20888 386.62980 568.25688 386.62980 588.27288 C
-398.36580 638.45688 425.07780 681.44088 449.77380 726.22488 C
-452.00580 732.27288 455.02980 736.80888 467.05380 762.44088 C
-471.44580 774.75288 475.83780 787.06488 480.22980 799.37688 C
-480.94980 799.37688 481.66980 799.37688 482.46180 799.37688 C
-491.10180 775.97688 491.10180 775.97688 495.63780 766.18488 C
-496.78980 765.10488 496.78980 765.10488 500.17380 765.46488 C
-506.50980 775.54488 514.35780 784.90488 519.32580 795.63288 C
-520.33380 795.63288 521.34180 795.63288 522.34980 795.63288 C
-522.27780 785.91288 517.59780 728.88888 536.60580 728.88888 C
-539.62980 731.91288 539.62980 731.91288 549.42180 748.47288 C
-550.28580 748.40088 551.14980 748.25688 552.01380 748.11288 C
-552.80580 746.60088 552.80580 746.60088 554.24580 728.52888 C
-562.09380 698.00088 570.66180 668.62488 576.06180 636.51288 C
-588.37380 596.69688 589.59780 550.11288 594.13380 508.35288 C
-593.34180 506.12088 593.34180 506.12088 594.13380 462.41688 C
-589.16580 405.24888 584.19780 356.21688 557.26980 304.88088 C
-549.56580 283.92888 537.10980 267.87288 527.24580 247.56888 C
-526.30980 247.06488 525.44580 246.56088 524.58180 246.05688 C
-523.93380 236.48088 501.54180 217.68888 494.55780 206.52888 C
-493.54980 206.16888 492.54180 205.80888 491.53380 205.37688 C
-491.24580 204.29688 490.95780 203.14488 490.74180 201.99288 C
-489.22980 201.20088 489.22980 201.20088 485.48580 201.56088 C
-473.38980 217.90488 461.94180 215.45688 443.36580 214.01688 C
-434.29380 211.42488 427.88580 209.69688 420.10980 205.01688 C
-396.27780 205.01688 384.46980 179.60088 363.73380 173.69688 C
-@c
-F
-
-@rax %Note: Object
--27.22620 483.15288 195.36180 602.63660 @E
- 1 O 0 @g
-0.00 0.00 0.00 1.00 k
-/$fm 0 def
-41.17380 483.15288 m
-28.42980 484.80888 15.75780 488.33688 5.46180 494.81688 C
-5.17380 497.26488 -3.32220 500.57688 -5.41020 502.01688 C
--8.14620 507.20088 -12.17820 508.56888 -13.69020 512.88888 C
--14.69820 513.32088 -15.70620 513.68088 -16.71420 514.04088 C
--18.51420 521.31288 -28.16220 522.68088 -27.22620 533.62488 C
--24.27420 535.92888 -24.27420 535.92888 -22.76220 535.92888 C
--19.09020 532.25688 -16.64220 520.80888 -9.94620 518.93688 C
--7.42620 513.68088 5.60580 506.04888 6.61380 502.37688 C
-11.86980 499.71288 11.86980 499.71288 22.38180 496.32888 C
-22.38180 495.82488 22.38180 495.32088 22.38180 494.81688 C
-42.68580 491.43288 42.68580 491.43288 49.45380 491.43288 C
-50.96580 492.22488 69.75780 494.45688 93.80580 498.99288 C
-97.04580 501.29688 100.28580 503.52888 103.59780 505.76088 C
-113.24580 507.41688 132.90180 522.96888 137.79780 530.24088 C
-149.24580 539.38488 155.79780 556.44888 160.33380 569.48088 C
-160.18980 575.24088 160.04580 581.00088 159.97380 586.76088 C
-160.54980 587.04888 161.19780 587.33688 161.84580 587.55288 C
-161.91780 588.56088 162.06180 589.56888 162.20580 590.57688 C
-161.41380 590.57688 160.69380 590.57688 159.97380 590.57688 C
-158.31780 595.32888 157.09380 597.41688 158.02980 601.88088 C
-159.18180 602.02488 160.33380 602.16888 161.48580 602.24088 C
-171.63780 596.26488 182.58180 604.47288 194.53380 602.24088 C
-195.61380 599.57688 195.54180 598.56888 194.89380 595.11288 C
-185.24580 594.03288 175.38180 593.67288 166.74180 590.57688 C
-167.17380 560.98488 161.62980 547.16088 141.54180 523.47288 C
-141.39780 522.75288 141.25380 521.96088 141.18180 521.16888 C
-157.23780 523.47288 169.69380 532.11288 180.99780 543.48888 C
-183.01380 543.63288 185.02980 543.77688 187.04580 543.84888 C
-187.04580 543.34488 187.04580 542.84088 187.04580 542.33688 C
-187.54980 542.33688 188.05380 542.33688 188.55780 542.33688 C
-186.97380 530.81688 155.58180 517.78488 146.43780 513.32088 C
-143.98980 513.46488 141.61380 513.60888 139.23780 513.68088 C
-138.87780 515.48088 138.51780 517.20888 138.15780 518.93688 C
-130.59780 516.70488 129.37380 509.86488 121.59780 507.27288 C
-98.70180 490.35288 68.89380 483.15288 41.17380 483.15288 C
-@c
-F
-
-@rax %Note: Object
--72.73020 540.46488 248.32205 910.38784 @E
- 1 O 0 @g
-0.00 0.00 0.00 1.00 k
-/$fm 0 def
--45.29820 540.46488 m
--47.60220 540.96888 -49.83420 541.47288 -52.06620 541.97688 C
--66.61020 549.10488 -69.77820 554.50488 -72.73020 569.48088 C
--69.85020 596.98488 -42.77820 613.40088 -26.14620 585.24888 C
--25.06620 582.00888 -23.91420 578.76888 -22.76220 575.45688 C
--8.65020 576.46488 6.90180 589.35288 18.63780 596.98488 C
-30.87780 608.64888 58.81380 634.71288 58.81380 653.14488 C
-56.50980 655.95288 54.27780 658.68888 52.04580 661.42488 C
-50.24580 677.76888 50.96580 688.49688 54.27780 703.61688 C
-57.01380 707.72088 57.94980 708.87288 56.22180 712.68888 C
-55.71780 712.68888 55.21380 712.68888 54.70980 712.68888 C
-53.34180 720.75288 49.66980 727.52088 55.42980 733.42488 C
-56.94180 733.06488 58.45380 732.70488 59.96580 732.27288 C
-61.62180 739.47288 62.12580 740.26488 67.81380 744.36888 C
-66.66180 752.07288 62.62980 751.85688 58.45380 756.03288 C
-54.78180 761.14488 53.12580 763.73688 48.66180 766.61688 C
-33.32580 785.33688 13.45380 808.37688 5.46180 830.26488 C
-3.94980 838.54488 3.15780 850.64088 0.20580 866.48088 C
-1.28580 881.31288 6.03780 894.99288 7.69380 908.67288 C
-11.29380 912.27288 14.38980 909.39288 18.63780 907.59288 C
-29.94180 905.79288 40.16580 903.63288 51.68580 900.03288 C
-52.69380 897.00888 74.43780 889.37688 79.54980 888.29688 C
-79.54980 887.79288 79.54980 887.28888 79.54980 886.78488 C
-80.26980 886.78488 80.98980 886.78488 81.78180 886.78488 C
-81.78180 886.28088 81.78180 885.77688 81.78180 885.27288 C
-84.66180 884.19288 90.70980 879.08088 90.06180 874.40088 C
-84.01380 875.40888 84.08580 878.79288 80.26980 881.16888 C
-68.74980 882.60888 58.74180 890.02488 47.94180 892.83288 C
-47.94180 893.33688 47.94180 893.84088 47.94180 894.34488 C
-36.27780 897.15288 25.04580 900.46488 13.74180 899.60088 C
-12.22980 894.34488 11.43780 893.62488 11.07780 891.32088 C
-17.70180 889.08888 31.38180 881.74488 33.68580 873.96888 C
-34.54980 873.75288 35.41380 873.53688 36.27780 873.24888 C
-36.34980 871.95288 43.47780 862.30488 46.06980 861.15288 C
-46.14180 860.43288 46.28580 859.71288 46.42980 858.92088 C
-47.00580 858.70488 47.65380 858.48888 48.30180 858.20088 C
-62.19780 838.76088 69.10980 816.51288 78.03780 793.76088 C
-78.54180 793.61688 79.04580 793.47288 79.54980 793.32888 C
-83.00580 809.38488 85.45380 817.01688 93.37380 831.05688 C
-100.93380 840.05688 100.93380 840.05688 101.29380 841.56888 C
-87.39780 840.92088 80.62980 835.59288 80.62980 850.64088 C
-92.65380 864.96888 92.65380 864.96888 98.70180 870.94488 C
-113.60580 881.96088 125.12580 885.63288 143.41380 889.08888 C
-143.41380 889.88088 143.41380 890.60088 143.41380 891.32088 C
-142.62180 891.32088 141.90180 891.32088 141.18180 891.32088 C
-141.18180 891.82488 141.18180 892.32888 141.18180 892.83288 C
-140.53380 893.12088 139.88580 893.40888 139.23780 893.62488 C
-139.45380 894.92088 139.74180 896.14488 140.02980 897.36888 C
-166.59780 907.08888 193.88580 913.92888 222.39780 905.28888 C
-229.09380 899.24088 229.09380 899.24088 230.60580 898.88088 C
-231.82980 895.92888 231.68580 894.34488 235.14180 892.47288 C
-235.50180 890.60088 235.86180 888.72888 236.22180 886.78488 C
-236.86980 886.56888 237.51780 886.35288 238.16580 886.06488 C
-238.02180 884.55288 237.87780 883.04088 237.73380 881.52888 C
-247.59780 848.48088 253.78980 819.03288 241.54980 784.25688 C
-234.56580 771.51288 237.44580 776.26488 226.86180 777.48888 C
-225.56580 769.06488 213.10980 758.26488 206.55780 753.00888 C
-193.38180 753.00888 195.25380 765.24888 194.53380 774.46488 C
-182.36580 773.60088 175.66980 746.67288 159.97380 743.21688 C
-157.95780 744.72888 155.94180 746.24088 153.92580 747.75288 C
-152.70180 757.76088 153.99780 764.96088 155.43780 774.46488 C
-142.26180 769.78488 132.03780 733.78488 115.62180 744.72888 C
-108.13380 761.00088 114.46980 783.39288 119.36580 799.37688 C
-105.97380 797.21688 99.27780 777.84888 83.29380 776.76888 C
-82.93380 773.52888 82.42980 770.43288 78.03780 769.64088 C
-75.08580 772.44888 76.09380 773.38488 72.78180 774.46488 C
-73.14180 769.20888 78.32580 766.25688 79.90980 760.13688 C
-79.40580 759.41688 78.90180 758.69688 78.39780 757.90488 C
-76.95780 757.68888 75.58980 757.47288 74.22180 757.18488 C
-74.43780 754.95288 74.72580 752.64888 75.01380 750.34488 C
-76.23780 750.12888 77.46180 749.91288 78.75780 749.62488 C
-80.12580 745.95288 84.22980 748.25688 83.29380 742.49688 C
-81.78180 741.70488 81.78180 741.70488 69.75780 742.85688 C
-69.82980 741.34488 69.97380 739.83288 70.11780 738.32088 C
-65.07780 733.28088 68.24580 727.37688 69.75780 720.96888 C
-74.94180 720.53688 79.47780 721.90488 85.52580 720.60888 C
-88.62180 733.92888 91.42980 749.84088 92.29380 763.16088 C
-92.79780 763.16088 93.30180 763.16088 93.80580 763.16088 C
-93.80580 760.71288 93.80580 758.19288 93.80580 755.67288 C
-94.52580 755.31288 95.24580 754.95288 96.03780 754.52088 C
-96.10980 748.40088 96.25380 742.20888 96.39780 736.01688 C
-90.85380 716.64888 92.72580 698.21688 88.90980 677.98488 C
-86.24580 671.28888 76.81380 653.28888 69.75780 651.63288 C
-67.16580 642.99288 66.51780 646.52088 61.47780 641.48088 C
-51.46980 613.97688 24.75780 593.45688 1.35780 577.40088 C
--6.13020 573.58488 -12.89820 567.75288 -21.25020 567.17688 C
--24.85020 552.56088 -28.52220 540.46488 -45.29820 540.46488 C
-@c
-F
-
-@rax %Note: Object
--53.21820 559.25688 -38.27197 582.29688 @E
- 1 O 0 @g
-0.00 0.00 0.00 0.00 k
-/$fm 0 def
--46.01820 559.25688 m
--49.83420 562.28088 -49.83420 562.28088 -51.27420 562.64088 C
--51.27420 563.64888 -51.27420 564.65688 -51.27420 565.66488 C
--51.92220 565.95288 -52.57020 566.24088 -53.21820 566.45688 C
--53.21820 576.96888 -53.21820 576.96888 -52.06620 579.63288 C
--50.19420 580.78488 -50.19420 580.78488 -49.83420 582.29688 C
--36.73020 581.86488 -35.14620 568.97688 -43.06620 559.25688 C
--44.07420 559.25688 -45.08220 559.25688 -46.01820 559.25688 C
-@c
-F
-
-@rax %Note: Object
-147.81487 656.52888 195.99846 740.98488 @E
- 1 O 0 @g
-0.00 0.00 0.00 1.00 k
-/$fm 0 def
-156.94980 656.52888 m
-150.18180 661.06488 150.18180 661.06488 149.02980 662.93688 C
-147.08580 679.35288 146.14980 700.08888 156.58980 713.40888 C
-156.66180 714.92088 156.80580 716.43288 156.94980 717.94488 C
-160.26180 718.59288 161.91780 718.80888 164.43780 721.32888 C
-179.77380 725.14488 180.20580 727.73688 187.76580 740.98488 C
-189.34980 740.84088 191.00580 740.69688 192.66180 740.55288 C
-192.66180 732.27288 182.86980 724.28088 184.02180 719.09688 C
-184.52580 719.09688 185.02980 719.09688 185.53380 719.09688 C
-188.12580 722.55288 191.07780 726.72888 195.32580 727.37688 C
-198.42180 721.97688 190.50180 712.47288 185.89380 708.87288 C
-185.89380 699.36888 184.45380 671.50488 172.71780 668.19288 C
-171.42180 662.86488 161.98980 657.75288 156.94980 656.52888 C
-@c
-F
-
-@rax %Note: Object
-56.77965 660.27288 85.64995 708.51288 @E
- 1 O 0 @g
-0.00 0.00 0.00 0.00 k
-/$fm 0 def
-61.47780 660.27288 m
-52.33380 671.64888 56.79780 704.91288 71.98980 708.51288 C
-85.16580 708.51288 86.10180 707.14488 85.52580 692.74488 C
-85.02180 692.74488 84.51780 692.74488 84.01380 692.74488 C
-80.70180 697.71288 78.25380 697.13688 73.50180 698.72088 C
-55.71780 692.38488 60.54180 675.96888 62.98980 661.06488 C
-62.48580 660.84888 61.98180 660.56088 61.47780 660.27288 C
-@c
-F
-
-@rax %Note: Object
-153.92580 682.52088 180.26476 710.53682 @E
- 1 O 0 @g
-0.00 0.00 0.00 0.00 k
-/$fm 0 def
-153.92580 682.52088 m
-155.79780 698.57688 159.03780 718.66488 178.76580 707.43288 C
-179.55780 702.89688 181.50180 699.36888 179.12580 694.61688 C
-175.02180 700.44888 173.65380 700.23288 167.46180 700.23288 C
-163.86180 696.27288 157.30980 684.03288 153.92580 682.52088 C
-@c
-F
-
-@rax %Note: Object
-86.24580 748.83288 242.26980 902.10132 @E
- 1 O 0 @g
-0.00 0.00 0.00 0.00 k
-/$fm 0 def
-120.08580 748.83288 m
-114.46980 772.44888 126.13380 790.95288 129.51780 812.19288 C
-122.10180 819.60888 98.62980 786.20088 86.24580 785.04888 C
-86.60580 791.60088 86.96580 798.15288 87.39780 804.63288 C
-95.67780 826.16088 102.30180 835.16088 120.87780 847.97688 C
-122.24580 850.20888 123.61380 851.72088 123.10980 854.02488 C
-120.08580 854.81688 120.08580 854.81688 115.62180 854.02488 C
-106.40580 849.41688 96.82980 847.32888 87.03780 846.82488 C
-92.65380 870.44088 128.00580 880.59288 148.66980 883.40088 C
-157.66980 883.68888 166.66980 883.97688 175.74180 884.19288 C
-177.97380 886.42488 178.69380 886.92888 179.12580 889.80888 C
-175.52580 893.40888 159.32580 892.68888 153.20580 893.62488 C
-153.20580 894.41688 153.20580 895.13688 153.20580 895.85688 C
-175.88580 901.47288 197.26980 905.21688 220.88580 898.52088 C
-227.22180 892.83288 227.22180 892.83288 230.96580 887.57688 C
-230.96580 878.28888 233.98980 863.02488 238.88580 854.02488 C
-239.38980 853.95288 239.89380 853.80888 240.39780 853.66488 C
-238.88580 843.72888 241.83780 828.96888 242.26980 817.44888 C
-241.54980 809.16888 241.54980 809.16888 235.86180 785.40888 C
-234.85380 785.33688 233.84580 785.19288 232.90980 785.04888 C
-232.47780 791.81688 232.62180 791.96088 227.65380 793.32888 C
-224.12580 784.40088 213.90180 759.27288 202.09380 760.92888 C
-201.80580 770.72088 201.51780 780.51288 201.30180 790.30488 C
-199.50180 790.30488 197.77380 790.30488 196.04580 790.30488 C
-190.57380 781.66488 169.62180 752.14488 159.97380 751.13688 C
-159.46980 764.45688 161.77380 774.24888 165.58980 786.56088 C
-165.44580 789.00888 165.30180 791.38488 165.22980 793.76088 C
-149.89380 793.76088 138.58980 751.42488 120.08580 748.83288 C
-@c
-F
-
-@rax %Note: Object
-252.06180 759.77688 393.39780 945.96888 @E
- 1 O 0 @g
-0.00 0.00 0.00 1.00 k
-/$fm 0 def
-332.12580 759.77688 m
-331.33380 759.92088 330.61380 760.06488 329.89380 760.13688 C
-329.60580 762.65688 329.31780 765.17688 329.10180 767.69688 C
-333.42180 768.34488 338.02980 768.27288 338.89380 773.74488 C
-350.91780 778.85688 365.10180 789.36888 373.81380 799.37688 C
-395.05380 838.90488 384.97380 892.04088 376.47780 933.51288 C
-369.42180 930.99288 368.70180 928.83288 367.04580 922.20888 C
-344.43780 914.79288 332.77380 895.06488 319.74180 876.27288 C
-308.58180 858.20088 288.92580 830.12088 292.30980 806.93688 C
-303.61380 812.55288 310.09380 821.84088 320.10180 829.90488 C
-322.33380 830.04888 324.56580 830.19288 326.86980 830.26488 C
-326.50980 823.06488 319.45380 813.56088 315.92580 806.93688 C
-315.27780 802.18488 314.62980 797.43288 314.05380 792.60888 C
-322.40580 793.04088 323.26980 798.29688 334.35780 795.63288 C
-336.73380 790.52088 337.30980 778.20888 333.99780 772.95288 C
-333.13380 772.88088 332.26980 772.73688 331.40580 772.59288 C
-328.23780 775.76088 329.89380 785.55288 329.89380 789.58488 C
-327.37380 789.22488 324.85380 788.86488 322.33380 788.43288 C
-300.15780 777.12888 307.21380 792.75288 310.30980 809.88888 C
-301.52580 809.31288 299.22180 798.22488 289.28580 798.22488 C
-280.71780 811.32888 286.90980 824.07288 291.15780 837.82488 C
-303.18180 861.15288 303.18180 861.15288 315.20580 880.80888 C
-320.24580 887.14488 330.18180 898.37688 332.91780 905.64888 C
-307.64580 899.67288 288.27780 875.33688 265.23780 864.17688 C
-262.64580 859.13688 259.54980 855.53688 253.93380 855.53688 C
-251.70180 857.76888 252.27780 858.70488 252.06180 861.15288 C
-257.24580 863.52888 258.46980 864.75288 261.78180 869.50488 C
-288.27780 887.79288 315.70980 905.07288 344.14980 920.40888 C
-355.52580 927.89688 369.56580 934.80888 377.98980 945.96888 C
-385.83780 945.96888 383.31780 942.00888 383.60580 933.51288 C
-386.05380 923.21688 390.44580 908.24088 389.29380 897.36888 C
-389.79780 897.36888 390.30180 897.36888 390.80580 897.36888 C
-392.60580 872.45688 393.39780 870.94488 393.39780 855.89688 C
-390.44580 849.92088 390.73380 829.47288 390.37380 825.00888 C
-384.75780 798.51288 374.89380 788.43288 351.27780 772.95288 C
-347.60580 766.25688 339.68580 759.77688 332.12580 759.77688 C
-@c
-F
-
-@rax %Note: Object
-6.60359 765.82488 72.78180 884.91288 @E
- 1 O 0 @g
-0.00 0.00 0.00 0.00 k
-/$fm 0 def
-62.19780 765.82488 m
-57.30180 769.56888 50.67780 774.96888 47.94180 779.79288 C
-47.43780 779.79288 46.93380 779.79288 46.42980 779.79288 C
-34.33380 794.33688 21.66180 812.19288 13.74180 828.03288 C
-9.63780 842.14488 2.36580 872.38488 9.56580 884.91288 C
-18.56580 883.32888 33.54180 869.57688 37.42980 860.43288 C
-37.93380 860.43288 38.43780 860.43288 38.94180 860.43288 C
-44.19780 852.51288 44.19780 852.51288 46.06980 851.36088 C
-53.05380 838.90488 74.94180 795.41688 72.78180 785.40888 C
-70.47780 785.40888 68.96580 786.20088 64.50180 786.20088 C
-63.34980 785.04888 63.34980 785.04888 62.98980 781.30488 C
-63.56580 781.08888 64.21380 780.80088 64.86180 780.51288 C
-64.86180 779.00088 64.06980 778.28088 63.70980 772.95288 C
-66.51780 771.65688 67.23780 771.00888 66.73380 767.33688 C
-64.50180 765.82488 64.50180 765.82488 62.19780 765.82488 C
-@c
-F
-
-%%PageTrailer
-@rs
-@rs
-%%Trailer
-@EndSysCorelDict
-end
-%%DocumentSuppliedResources: procset wCorel8Dict
-%%EOF
-
-%%EndDocument
-
diff --git a/seminar/static/seminar/lisak.pdf b/seminar/static/seminar/lisak.pdf
new file mode 100644
index 00000000..f90b2784
Binary files /dev/null and b/seminar/static/seminar/lisak.pdf differ
diff --git a/seminar/static/seminar/prihlaska.js b/seminar/static/seminar/prihlaska.js
new file mode 100644
index 00000000..81f91d28
--- /dev/null
+++ b/seminar/static/seminar/prihlaska.js
@@ -0,0 +1,32 @@
+function addrCountryChanged(){
+ var stat_select = document.getElementById('id_stat');
+ var stat_text = document.getElementById('id_li_stat_text');
+ var stat = stat_select[stat_select.selectedIndex].value;
+ if (stat === "other"){
+ stat_text.style.display="block";
+ } else {
+ stat_text.style.display="none";
+ $('#id_stat_text').val("");
+ }
+}
+function hideSchoolTextfields(){
+ var skola_nazev = document.getElementById('id_li_skola_nazev');
+ var skola_adresa = document.getElementById('id_li_skola_adresa');
+ skola_nazev.style.display="none";
+ skola_adresa.style.display="none";
+
+}
+function schoolNotInList(){
+ var skola_nazev = document.getElementById('id_li_skola_nazev');
+ var skola_adresa = document.getElementById('id_li_skola_adresa');
+ // FIXME nefunguje a nevim proc (TypeError: $(...).select2 is not a function)
+ //var skola_select = $('#id_skola').select2();
+ //skola_select.val(null).trigger('change');
+ skola_nazev.style.display="block";
+ skola_adresa.style.display="block";
+}
+
+document.addEventListener("DOMContentLoaded", function(){
+ addrCountryChanged();
+ hideSchoolTextfields();
+});
diff --git a/seminar/templates/seminar/archiv/obalky.tex b/seminar/templates/seminar/archiv/obalky.tex
index ea20f63d..5f2d8e07 100644
--- a/seminar/templates/seminar/archiv/obalky.tex
+++ b/seminar/templates/seminar/archiv/obalky.tex
@@ -86,7 +86,8 @@
% Tohle makro vysází samotnou obálku
\def\obalka#1#2#3#4#5#6#7{
% Horní a pravý okraj je zároveň okraj stránky, resetujeme odsazení
-\includegraphics[height=2.55cm]{lisak.eps}\hskip 1 em\vbox{%
+\includegraphics[height=2.55cm]{lisak.pdf}
+\vbox{%
\adresaMaM}
\vskip 7.3 cm % Od oka
\hskip\toskip%
diff --git a/seminar/templates/seminar/edit.html b/seminar/templates/seminar/edit.html
new file mode 100644
index 00000000..3f3e0d99
--- /dev/null
+++ b/seminar/templates/seminar/edit.html
@@ -0,0 +1,78 @@
+{% extends "seminar/zadani/base.html" %}
+{% load staticfiles %}
+
+{% block script %}
+
+ {{form.media}}
+
+{% endblock %}
+{% block content %}
+
+ {% block nadpis1a %}{% block nadpis1b %}
+ Změna osobních údajů
+ {% endblock %}{% endblock %}
+
+
+
+{% endblock %}
+
diff --git a/seminar/templates/seminar/gdpr.html b/seminar/templates/seminar/gdpr.html
new file mode 100644
index 00000000..74e253f5
--- /dev/null
+++ b/seminar/templates/seminar/gdpr.html
@@ -0,0 +1,49 @@
+
+TL;DR:
+K tomu, abychom mohli zpracovávat Tvá data (uložit si tvou adresu, zobrazit Tvé jméno ve výsledkové listině, opravit Tvá řešení) od Tebe potřebujeme souhlas.
+Pokud se zpracováváním souhlasíš dle níže uvedených podmínek, zaškrtni políčko níže.
+
+
+
+Získáváme od Tebe údaje vyplněné v přihlášce do semináře (jméno, příjmení, poštovní a e-mailovou adresu, školu, kterou navštěvuješ a rok maturity), případně v přihlášce na soustředění (navíc datum narození, telefonní číslo). Také uchováváme všechna řešení, která nám pošleš, a jejich hodnocení.
+
+
+Slibujeme Ti, že Tvá osobní data nezneužijeme k ničemu, co by nesouviselo s M&M nebo s dalšími aktivitami Matfyzu, a nikdy je nepředáme nikomu cizímu. Údaje využíváme k zajištění chodu semináře a také je sdílíme s ostatními propagačními akcemi Matfyzu, abychom mohli vyhodnocovat úspěšnost akcí. Pokud budeš mít zájem, budeme Ti také posílat zajímavé zprávy a novinky týkajíci se Matfyzu.
+
+
+Veřejně vystavujeme pouze výsledkové listiny, které také uchováváme pro archivní účely. Pokud ale z nějakého důvodu nebudeš chtít mít své jméno či školu uvedené ve výsledkové listině, není problém to zařídit, napiš nám. Z tištěných materiálů samozřejmě údaje už odstranit nemůžeme.
+
+
+Na soustředěních a dalších akcích semináře navíc pořizujeme fotografie a videozáznamy a používáme je ke zpravodajským a propagačním účelům. Pro propagační účely si od Tebe vyžádáme samostatný souhlas na začátku akce.
+
+
+Souhlas se zpracováním osobních údajů pro potřeby chodu semináře
+
+
+Tímto uděluji souhlas Univerzitě Karlově, se sídlem Ovocný trh 560/5, 116 36 Praha 1, IČO 00216208 (dále jen UK), která je správcem osobních údajů všech fakult a součástí UK, ke zpracování osobních údajů pro potřeby Korespondenčního semináře M&M a Matematicko-fyzikální fakulty UK (dále jen M&M a MFF UK).
+
+
+Tento souhlas uděluji pro všechny výše uvedené osobní údaje, a to po dobu účasti v semináři a 10 let poté, a dále souhlasím s uchováváním potřebných dat pro archivní účely i po této lhůtě (vystavené výsledkové listiny aj.).
+
+
+MFF UK tyto údaje zpracovává za účelem evidence řešitelů a účastníků M&M, k zajištění celoročního fungování semináře, analýze účinnosti jednotlivých propagačních akcí MFF UK a zpravodajským účelům. Osobám, které o to projeví zájem v nastavení svého účtu, bude MFF UK také zasílat propagační materiály.
+
+
+Údaje nebudou předány třetí osobě ani využívány k jiným účelům, než ke kterým byly poskytnuty.
+
+
+Tento souhlas uděluji ze své vlastní a svobodné vůle a beru na vědomí, že jej mohu kdykoliv odvolat zasláním e-mailu na adresu mam@matfyz.cz. Stejně tak může být požadováno vymazání i z archivních údajů M&M, pokud to bude technicky možné. Beru na vědomí, že údaje z tištěných publikací není možné zpětně odstranit.
+
+
+Dále máte právo:
+
diff --git a/seminar/templates/seminar/login.html b/seminar/templates/seminar/login.html
new file mode 100644
index 00000000..6319ecc0
--- /dev/null
+++ b/seminar/templates/seminar/login.html
@@ -0,0 +1,26 @@
+{% extends "seminar/zadani/base.html" %}
+{% load staticfiles %}
+
+
+{% block content %}
+
+ {% block nadpis1a %}{% block nadpis1b %}
+ Přihlášení
+ {% endblock %}{% endblock %}
+
+
+
+Zapomněl jsem heslo
+Zaregistrovat
+
+
+{% endblock %}
+
diff --git a/seminar/templates/seminar/logout.html b/seminar/templates/seminar/logout.html
new file mode 100644
index 00000000..ab41a8c8
--- /dev/null
+++ b/seminar/templates/seminar/logout.html
@@ -0,0 +1,18 @@
+{% extends "seminar/zadani/base.html" %}
+{% load staticfiles %}
+
+
+{% block content %}
+
+ {% block nadpis1a %}{% block nadpis1b %}
+ Odhlášení
+ {% endblock %}{% endblock %}
+
+
+Byl jsi úspěšně odhlášen
+{# Tohle by se asi mělo udělat přes kontext (title), ale kašlu na to, stejně je to jen jednojazyčná stránka #}
+
+{# TODO: odkaz na znovupřihlášení? #}
+
+{% endblock %}
+
diff --git a/seminar/templates/seminar/org/obalkovani.html b/seminar/templates/seminar/org/obalkovani.html
new file mode 100644
index 00000000..fa130bc7
--- /dev/null
+++ b/seminar/templates/seminar/org/obalkovani.html
@@ -0,0 +1,30 @@
+{% extends "base.html" %}
+
+{% block content %}
+
+ {% block nadpis1a %}{% block nadpis1b %}
+ Obálkování {{ cislo }}
+ {% endblock %}{% endblock %}
+
+
+ {% for reseni in object_list %}
+ {% ifchanged reseni.resitele %}
+ {% if not forloop.first %}
+
+ {% endif %}
+ {% for resitel in reseni.resitele.all %}{{resitel.osoba}},{% endfor %}
+
+ {% endifchanged %}
+
+ Celkem {{reseni.hodnoceni__body__sum}} bodů z {{reseni.hodnoceni__count}} hodnocení
+
+ {% for h in reseni.hodnoceni_set.all %}
+ {{ h.problem }}: {{ h.body }}b
+ {% endfor %}
+
+
+ {% endfor %}
+
+
+
+{% endblock content %}
diff --git a/seminar/templates/seminar/org/vloz_reseni.html b/seminar/templates/seminar/org/vloz_reseni.html
new file mode 100644
index 00000000..bfe4f6f6
--- /dev/null
+++ b/seminar/templates/seminar/org/vloz_reseni.html
@@ -0,0 +1,21 @@
+{% extends "seminar/zadani/base.html" %}
+{% load staticfiles %}
+{% block script %}
+
+ {{form.media}}
+
+{% endblock %}
+
+{% block content %}
+
+ {% block nadpis1a %}{% block nadpis1b %}
+ Vložit řešení
+ {% endblock %}{% endblock %}
+
+
+
+{% endblock %}
diff --git a/seminar/templates/seminar/prihlaska.html b/seminar/templates/seminar/prihlaska.html
index 891bdb6d..8b17c0bd 100644
--- a/seminar/templates/seminar/prihlaska.html
+++ b/seminar/templates/seminar/prihlaska.html
@@ -1,5 +1,112 @@
-
+
+
+
+{% endblock %}
+
diff --git a/seminar/templates/seminar/prihlaska_field.html b/seminar/templates/seminar/prihlaska_field.html
new file mode 100644
index 00000000..e37549ed
--- /dev/null
+++ b/seminar/templates/seminar/prihlaska_field.html
@@ -0,0 +1,4 @@
+ {{ field.label }}:
+ {{field}}
+ {% if field.help_text %}{{ field.help_text|safe }} {% endif %}
+ {% if field.errors %}{{ field.errors }} {% endif %}
diff --git a/seminar/templates/seminar/resitel.html b/seminar/templates/seminar/resitel.html
new file mode 100644
index 00000000..3a38a085
--- /dev/null
+++ b/seminar/templates/seminar/resitel.html
@@ -0,0 +1,17 @@
+{% extends "seminar/zadani/base.html" %}
+{% load staticfiles %}
+
+
+{% block content %}
+
+ {% block nadpis1a %}{% block nadpis1b %}
+ Stránka řešitele - {{ object.osoba.jmeno }} {{ object.osoba.prijmeni }}
+ {% endblock %}{% endblock %}
+
+
+Odhlásit se
+Upravit údaje
+
+
+{% endblock %}
+
diff --git a/seminar/templates/seminar/tematka/rozcestnik.html b/seminar/templates/seminar/tematka/rozcestnik.html
new file mode 100644
index 00000000..b13d6075
--- /dev/null
+++ b/seminar/templates/seminar/tematka/rozcestnik.html
@@ -0,0 +1,14 @@
+{% for tematko in tematka %}
+{{tematko.nazev}}
+{{tematko.abstrakt}}
+
+ {% for cislo in tematko.cisla %}
+ {{cislo.0.0}}
+
+ {% for odkaz in cislo.1 %}
+ {{odkaz.0}}
+ {% endfor %}
+
+ {% endfor %}
+
+{% endfor %}
diff --git a/seminar/templates/seminar/tematka/toaletak.html b/seminar/templates/seminar/tematka/toaletak.html
new file mode 100644
index 00000000..8b556c6c
--- /dev/null
+++ b/seminar/templates/seminar/tematka/toaletak.html
@@ -0,0 +1 @@
+Stránká témátka
diff --git a/seminar/testutils.py b/seminar/testutils.py
index 9ff32b53..b6583f12 100644
--- a/seminar/testutils.py
+++ b/seminar/testutils.py
@@ -1,11 +1,13 @@
# -*- coding: utf-8 -*-
import datetime
+from pytz import timezone
import random
import lorem
import django.contrib.auth
from django.db import transaction
import unidecode
+import logging
from seminar.models import Skola, Resitel, Rocnik, Cislo, Problem, Reseni, PrilohaReseni, Nastaveni, Soustredeni, Soustredeni_Ucastnici, Soustredeni_Organizatori, Osoba, Organizator, Prijemce, Tema, Uloha, Konfera, KonferaNode, TextNode, UlohaVzorakNode, RocnikNode, CisloNode, TemaVCisleNode, Text, Hodnoceni, UlohaZadaniNode, Novinky
@@ -15,7 +17,11 @@ from django.contrib.sites.models import Site
User = django.contrib.auth.get_user_model()
zlinska = None # tohle bude speciální škola, které později dodáme kontaktní osobu
+logger = logging.getLogger(__name__)
+
def gen_osoby(rnd, size):
+ logger.info('Generuji osoby (size={})...'.format(size))
+
jmena_m = ['Aleš', 'Tomáš', 'Martin', 'Jakub', 'Petr', 'Lukáš', 'Cyril', 'Pavel Karel']
jmena_f = ['Eva', 'Karolína', 'Zuzana', 'Sylvie', 'Iva', 'Jana', 'Marie',
'Marta Iva', 'Shu Shan']
@@ -67,6 +73,8 @@ def gen_osoby(rnd, size):
def gen_skoly(): #TODO někdy to přepsat, aby jich bylo více
+ logger.info('Generuji školy...')
+
skoly = []
prvnizs = Skola.objects.create(mesto='Praha', stat='CZ', psc='101 00',
ulice='Krátká 5', nazev='První ZŠ', je_zs=True, je_ss=False)
@@ -90,22 +98,26 @@ def gen_skoly(): #TODO někdy to přepsat, aby jich bylo více
return skoly
def gen_resitele(rnd, osoby, skoly):
+ logger.info('Generuji řešitele...')
+
resitele = []
for os in osoby:
rand = rnd.randint(0, 8)
if not (rand % 8 == 0):
resitele.append(Resitel.objects.create(osoba=os, skola=rnd.choice(skoly),
rok_maturity=rnd.randint(2019, 2029),
- zasilat=rnd.choice(Resitel.ZASILAT_CHOICES)))
+ zasilat=rnd.choice(Resitel.ZASILAT_CHOICES)[0]))
return resitele
def gen_prijemci(rnd, osoby, kolik=10):
+ logger.info('Generuji příjemce (kolik={})...'.format(kolik))
prijemci = []
for i in rnd.sample(osoby, kolik):
prijemci.append(Prijemce.objects.create(osoba=i))
return prijemci
def gen_organizatori(rnd, osoby, last_rocnik, users):
+ logger.info('Generuji organizátory...')
organizatori = []
@@ -118,9 +130,18 @@ def gen_organizatori(rnd, osoby, last_rocnik, users):
rand = rnd.randint(0, 8)
if (rand % 8 == 0):
pusobnost = rnd.randint(1, last_rocnik)
- od = datetime.date(1993 + pusobnost, rnd.randint(1, 12), rnd.randint(1, 28))
- do = datetime.date(od.year + rnd.randint(1, 6), rnd.randint(1, 12),
- rnd.randint(1, 28))
+ od = datetime.datetime(
+ year=1993 + pusobnost,
+ month=rnd.randint(1, 12),
+ day=rnd.randint(1, 28),
+ tzinfo=timezone('CET'),
+ )
+ do = datetime.datetime(
+ year=od.year + rnd.randint(1, 6),
+ month=rnd.randint(1, 12),
+ day=rnd.randint(1, 28),
+ tzinfo=timezone('CET'),
+ )
#aktualni organizatori jeste nemaji vyplnene organizuje_do
#popis orga
@@ -136,6 +157,8 @@ def gen_organizatori(rnd, osoby, last_rocnik, users):
return organizatori
def gen_ulohy_do_cisla(rnd, organizatori, resitele, rocnik_cisla, rocniky, size):
+ logger.info('Generuji úlohy do čísla (size={})...'.format(size))
+
# ulohy resene v cisle
jaka = ["Šachová", "Černá", "Větrná", "Dlouhá", "Křehká", "Rychlá",
"Zákeřná", "Fyzikální"]
@@ -158,7 +181,14 @@ def gen_ulohy_do_cisla(rnd, organizatori, resitele, rocnik_cisla, rocniky, size)
for rocnik in rocniky:
k+=1
cisla = rocnik_cisla[k-1]
- for ci in range(3, len(cisla)+1):
+ for ci in range(3, len(cisla)+1): # pro všechna čísla
+ resitele_size = round(7/8 * 30 * size) # očekáváný celkový počet řešitelů
+ poc_res = rnd.randint(round(resitele_size/8), round(3*resitele_size/4))
+ # dané číslo řeší něco mezi osminou a tříčtvrtinou všech řešitelů
+ # (náhodná hausnumera, možno změnit)
+ # účelem je, aby se řešení generovala z menší množiny řešitelů a tedy
+ # bylo více řešení od jednoho řešitele daného čísla
+ resitele_cisla = rnd.sample(resitele, poc_res)
for pi in range(1, ((size + 1) // 2) + 1):
poc_op = rnd.randint(1, 4) # počet opravovatelů
@@ -199,6 +229,7 @@ def gen_ulohy_do_cisla(rnd, organizatori, resitele, rocnik_cisla, rocniky, size)
p.ulohazadaninode = uloha_zadani
otec_syn(cisla[ci-2-1].cislonode, uloha_zadani)
+ # generování vzorového textu
text_vzoraku = Text.objects.create(
na_web = rnd.choice(reseni),
do_cisla = rnd.choice(reseni)
@@ -211,17 +242,18 @@ def gen_ulohy_do_cisla(rnd, organizatori, resitele, rocnik_cisla, rocniky, size)
p.opravovatele.set(rnd.sample(organizatori,poc_op))
p.save()
- # reseni ulohy
+ # generování řešení
poc_reseni = rnd.randint(size // 2, size * 2)
- #poc_resitel = rnd.randint(1, 3) <- k čemu je himbajs tahle proměnná?
- # vybereme nahodny vzorek resitelu o delce poctu reseni
- # (nebo skoro vsechny resitele, pokud jich je mene nez pocet reseni)
+ # generujeme náhodný počet řešení
for ri in range(poc_reseni):
- res_vyber = rnd.sample(resitele, rnd.randint(1, 5))
+ if rnd.randint(1, 10) == 6:
+ # cca desetina řešení od více řešitelů
+ res_vyber = rnd.sample(resitele_cisla, rnd.randint(2, 5))
+ else:
+ res_vyber = rnd.sample(resitele_cisla, 1)
+ res = Reseni.objects.create(forma=rnd.choice(Reseni.FORMA_CHOICES)[0])
# problem a resitele přiřadíme později, ManyToManyField
# se nedá vyplnit v create()
- res = Reseni.objects.create(forma=rnd.choice(Reseni.FORMA_CHOICES))
- #res.save() <- asi smazat
res.resitele.set(res_vyber)
res.save()
hod = Hodnoceni.objects.create(
@@ -234,29 +266,33 @@ def gen_ulohy_do_cisla(rnd, organizatori, resitele, rocnik_cisla, rocniky, size)
return
def gen_soustredeni(rnd, resitele, organizatori):
- soustredeni = []
- for _ in range(1, 10): #FIXME Tu range si změňte jak chcete, nevím, co přesně znamená size (asi Anet?)
- datum_zacatku=datetime.date(rnd.randint(2000, 2020), rnd.randint(1, 12), rnd.randint(1, 28))
- working_sous = Soustredeni.objects.create(
- rocnik=Rocnik.objects.order_by('?').first(),
- verejne_db=rnd.choice([True, False]),
- misto=rnd.choice(['Kremrolovice', 'Indiánov', 'U zmzliny', 'Vafláreň', 'Větrník', 'Horní Rakvička', 'Dolní cheesecake']),
- typ=rnd.choice(['jarni', 'podzimni', 'vikend']),
- datum_zacatku=datum_zacatku,
- datum_konce=datum_zacatku + datetime.timedelta(days=7))
- ucastnici = rnd.sample(resitele, min(len(resitele), 20))
- working_sous.ucastnici.set(ucastnici)
- #for res in rnd.sample(resitele, min(len(resitele), 20)):
- # Soustredeni_Ucastnici.objects.create(resitel=res, soutredeni=working_sous)
- orgove_vyber = rnd.sample(organizatori, min(len(organizatori), 20))
- working_sous.organizatori.set(orgove_vyber)
- #for org in rnd.sample(organizatori, min(len(organizatori), 20)):
- # Soustredeni_Organizatori.objects.create(organizator=org, soutredeni=working_sous)
- working_sous.save()
- soustredeni.append(working_sous)
- return soustredeni
+ logger.info('Generuji soustředění...')
+
+ soustredeni = []
+ for _ in range(1, 10): #FIXME Tu range si změňte jak chcete, nevím, co přesně znamená size (asi Anet?)
+ datum_zacatku=datetime.date(rnd.randint(2000, 2020), rnd.randint(1, 12), rnd.randint(1, 28))
+ working_sous = Soustredeni.objects.create(
+ rocnik=Rocnik.objects.order_by('?').first(),
+ verejne_db=rnd.choice([True, False]),
+ misto=rnd.choice(['Kremrolovice', 'Indiánov', 'U zmzliny', 'Vafláreň', 'Větrník', 'Horní Rakvička', 'Dolní cheesecake']),
+ typ=rnd.choice(['jarni', 'podzimni', 'vikend']),
+ datum_zacatku=datum_zacatku,
+ datum_konce=datum_zacatku + datetime.timedelta(days=7))
+ ucastnici = rnd.sample(resitele, min(len(resitele), 20))
+ working_sous.ucastnici.set(ucastnici)
+ #for res in rnd.sample(resitele, min(len(resitele), 20)):
+ # Soustredeni_Ucastnici.objects.create(resitel=res, soutredeni=working_sous)
+ orgove_vyber = rnd.sample(organizatori, min(len(organizatori), 20))
+ working_sous.organizatori.set(orgove_vyber)
+ #for org in rnd.sample(organizatori, min(len(organizatori), 20)):
+ # Soustredeni_Organizatori.objects.create(organizator=org, soutredeni=working_sous)
+ working_sous.save()
+ soustredeni.append(working_sous)
+ return soustredeni
def gen_rocniky(last_rocnik, size):
+ logger.info('Generuji ročníky (size={})...'.format(size))
+
rocniky = []
node = None
for ri in range(min(last_rocnik - size, 1), last_rocnik + 1):
@@ -268,6 +304,8 @@ def gen_rocniky(last_rocnik, size):
return rocniky
def gen_konfery(size, rnd, organizatori, resitele, soustredeni):
+ logger.info('Generuji konfery (size={})...'.format(size))
+
konfery = []
for _ in range(1, size): #FIXME Tu range si změňte jak chcete, nevím, co přesně znamená size (asi Anet?)
# Anet: size je parametr udávající velikost testovacích dat a dá se pomocí ní škálovat,
@@ -292,6 +330,8 @@ def gen_konfery(size, rnd, organizatori, resitele, soustredeni):
return konfery
def gen_cisla(rnd, rocniky):
+ logger.info('Generuji čísla...')
+
rocnik_cisla = []
for rocnik in rocniky:
otec = True
@@ -317,7 +357,7 @@ def gen_cisla(rnd, rocniky):
cislo = Cislo.objects.create(
rocnik = rocnik,
- cislo = str(ci),
+ poradi = str(ci),
datum_vydani=vydano,
datum_deadline=deadline,
verejne_db=True
@@ -335,6 +375,8 @@ def gen_cisla(rnd, rocniky):
return rocnik_cisla
def gen_temata(rnd, rocniky, rocnik_cisla, organizatori):
+ logger.info('Generuji témata...')
+
jake = ["Hravé", "Fyzikální", "Nejlepší", "Totálně masakrální",
"Šokující", "Magnetické", "Modré", "Překvapivé",
"Plasmatické", "Novoroční"]
@@ -361,8 +403,9 @@ def gen_temata(rnd, rocniky, rocnik_cisla, organizatori):
garant=rnd.choice(organizatori),
kod=str(n),
# atributy třídy Téma
- tema_typ=rnd.choice(Tema.TEMA_CHOICES),
- rocnik=rocnik
+ tema_typ=rnd.choice(Tema.TEMA_CHOICES)[0],
+ rocnik=rocnik,
+ abstrakt = "Abstrakt tematka {}".format(n)
)
konec_tematu = min(rnd.randint(ci, 7), len(cisla))
for i in range(ci, konec_tematu+1):
@@ -378,6 +421,8 @@ def gen_temata(rnd, rocniky, rocnik_cisla, organizatori):
def gen_ulohy_k_tematum(rnd, rocniky, rocnik_cisla, rocnik_temata, organizatori):
+ logger.info('Generuji úlohy k tématům...')
+
# ulohy resene v cisle
jaka = ["Šachová", "Černá", "Větrná", "Dlouhá", "Křehká", "Rychlá",
"Zákeřná", "Fyzikální"]
@@ -474,6 +519,8 @@ def gen_ulohy_k_tematum(rnd, rocniky, rocnik_cisla, rocnik_temata, organizatori)
return
def gen_novinky(rnd, organizatori):
+ logger.info('Generuji novinky...')
+
jake = ["zábavné", "veselé", "dobrodružné", "skvělé"]
co = ["soustředění", "Fyziklání", "víkendové setkání"]
@@ -495,6 +542,8 @@ def otec_syn(otec, syn):
@transaction.atomic
def create_test_data(size = 6, rnd = None):
+ logger.info('Vyrábím testovací data (size={})...'.format(size))
+
assert size >= 1
# pevna pseudo-nahodnost
rnd = rnd or random.Random(x=42)
@@ -575,5 +624,5 @@ def create_test_data(size = 6, rnd = None):
# obecné nastavení semináře, musí být už přidané ročníky a čísla, jinak se nastaví divně
- nastaveni = Nastaveni.objects.create(aktualni_rocnik = Rocnik.objects.last(),
+ nastaveni = Nastaveni.objects.create(
aktualni_cislo = Cislo.objects.all()[1])
diff --git a/seminar/urls.py b/seminar/urls.py
index 67d0b526..bc1c89a8 100644
--- a/seminar/urls.py
+++ b/seminar/urls.py
@@ -3,10 +3,14 @@ from django.contrib.auth.decorators import user_passes_test
from . import views, export
from .utils import staff_member_required
from django.views.generic.base import RedirectView
+from django.contrib.auth import views as auth_views
staff_member_required = user_passes_test(lambda u: u.is_staff)
urlpatterns = [
+ path('aktualni/temata/', views.TemataRozcestnikView),
+ path('/t/', views.TematkoView),
+
# REDIRECTy
path('jak-resit/', RedirectView.as_view(url='/co-je-MaM/jak-resit/')),
@@ -85,19 +89,36 @@ urlpatterns = [
path('stav',
staff_member_required(views.StavDatabazeView), name='stav_databaze'),
path('cislo/./obalkovani',
- staff_member_required(views.obalkovaniView), name='seminar_cislo_resitel_obalkovani'),
+ staff_member_required(views.ObalkovaniView.as_view()), name='seminar_cislo_resitel_obalkovani'),
path('cislo/./tex-download.json',
staff_member_required(views.texDownloadView), name='seminar_tex_download'),
path('soustredeni//obalky.pdf',
staff_member_required(views.soustredeniObalkyView), name='seminar_soustredeni_obalky'),
- path('tex-upload/login/', views.LoginView, name='seminar_login'),
+ path('tex-upload/login/', views.TeXUploadLoginView, name='seminar_login'),
path(
'tex-upload/',
staff_member_required(views.texUploadView),
name='seminar_tex_upload'
),
- path('prihlaska/',views.get_name),
+ path('org/vloz_body//',
+ staff_member_required(views.VlozBodyView.as_view()),name='seminar_org_vlozbody'),
+ path('auth/prihlaska/',views.prihlaskaView, name='seminar_prihlaska'),
+ path('auth/login/', views.LoginView.as_view(), name='login'),
+ path('auth/logout/', views.LogoutView.as_view(), name='logout'),
+ path('auth/resitel/', views.ResitelView.as_view(), name='seminar_resitel'),
+ path('autocomplete/skola/',views.SkolaAutocomplete.as_view(), name='autocomplete_skola'),
+ path('autocomplete/resitel/',views.ResitelAutocomplete.as_view(), name='autocomplete_resitel'),
+ path('auth/reset_password/', views.PasswordResetView.as_view(), name='reset_password'),
+ path('auth/change_password/', views.PasswordChangeView.as_view(), name='change_password'),
+ path('auth/reset_password_done/', views.PasswordResetDoneView.as_view(), name='reset_password_done'),
+ path('auth/reset_password_confirm///', views.PasswordResetConfirmView.as_view(), name='password_reset_confirm'),
+ path('auth/reset_password_complete/', views.PasswordResetCompleteView.as_view(), name='reset_password_complete'),
+ path('auth/resitel_edit', views.resitelEditView, name='seminar_resitel_edit'),
+
+
+ path('temp/add_solution', views.AddSolutionView.as_view(),name='seminar_vloz_reseni'),
+
path('', views.TitulniStranaView.as_view(), name='titulni_strana'),
# Ceka na autocomplete v3
diff --git a/seminar/utils.py b/seminar/utils.py
index 75092384..d910a5b6 100644
--- a/seminar/utils.py
+++ b/seminar/utils.py
@@ -2,9 +2,18 @@
import datetime
from django.contrib.auth.decorators import user_passes_test
+from html.parser import HTMLParser
staff_member_required = user_passes_test(lambda u: u.is_staff)
+class FirstTagParser(HTMLParser):
+ def __init__(self, *args, **kwargs):
+ self.firstTag = None
+ super().__init__(*args, **kwargs)
+ def handle_data(self, data):
+ if self.firstTag == None:
+ self.firstTag = data
+
def histogram(seznam):
d = {}
for i in seznam:
diff --git a/seminar/views.py b/seminar/views.py
index 57c85b65..e174ab28 100644
--- a/seminar/views.py
+++ b/seminar/views.py
@@ -2,22 +2,31 @@
from django.shortcuts import get_object_or_404, render
from django.http import HttpResponse, HttpResponseRedirect, HttpResponseForbidden, JsonResponse
-from django.urls import reverse
+from django.urls import reverse,reverse_lazy
from django.core.exceptions import PermissionDenied, ObjectDoesNotExist
from django.views import generic
from django.utils.translation import ugettext as _
from django.http import Http404,HttpResponseBadRequest,HttpResponseRedirect
-from django.db.models import Q
+from django.db.models import Q, Sum, Count
from django.views.decorators.csrf import ensure_csrf_cookie
-from django.contrib.auth import authenticate, login
-
-from .models import Problem, Cislo, Reseni, Nastaveni, Rocnik, Soustredeni, Organizator, Resitel, Novinky, Soustredeni_Ucastnici, Pohadka, Tema, Clanek
+from django.views.generic.edit import FormView
+from django.contrib.auth import authenticate, login, get_user_model, logout
+from django.contrib.auth import views as auth_views
+from django.contrib.auth.models import User
+from django.contrib.auth.mixins import LoginRequiredMixin
+from django.db import transaction
+from dal import autocomplete
+
+import seminar.models as s
+from .models import Problem, Cislo, Reseni, Nastaveni, Rocnik, Soustredeni, Organizator, Resitel, Novinky, Soustredeni_Ucastnici, Pohadka, Tema, Clanek, Osoba, Skola # Tohle je stare a chceme se toho zbavit. Pouzivejte s.ToCoChci
#from .models import VysledkyZaCislo, VysledkyKCisluZaRocnik, VysledkyKCisluOdjakziva
from . import utils
from .unicodecsv import UnicodeWriter
-from .forms import NameForm
+from .forms import PrihlaskaForm, LoginForm, ProfileEditForm
+import seminar.forms as f
from datetime import timedelta, date, datetime
+from django.utils import timezone
from itertools import groupby
import tempfile
import subprocess
@@ -30,6 +39,7 @@ import json
import traceback
import sys
import csv
+import logging
def verejna_temata(rocnik):
@@ -37,6 +47,45 @@ def verejna_temata(rocnik):
"""
return Problem.objects.filter(typ=Problem.TYP_TEMA, cislo_zadani__rocnik=rocnik, cislo_zadani__verejne_db=True).order_by('kod')
+def temata_v_rocniku(rocnik):
+ return Problem.objects.filter(typ=Problem.TYP_TEMA, rocnik=rocnik)
+
+def get_problemy_k_tematu(tema):
+ return Problemy.objects.filter(nadproblem = tema)
+
+
+class VlozBodyView(generic.ListView):
+ template_name = 'seminar/org/vloz_body.html'
+
+ def get_queryset(self):
+ self.tema = get_object_or_404(Problem,id=self.kwargs['tema'])
+ print(self.tema)
+ self.problemy = Problem.objects.filter(nadproblem = self.tema)
+ print(self.problemy)
+ self.reseni = Reseni.objects.filter(problem__in=self.problemy)
+ print(self.reseni)
+ return self.reseni
+
+
+class ObalkovaniView(generic.ListView):
+ template_name = 'seminar/org/obalkovani.html'
+
+ def get_queryset(self):
+ rocnik = get_object_or_404(Rocnik,rocnik=self.kwargs['rocnik'])
+ cislo = get_object_or_404(Cislo,rocnik=rocnik,poradi=self.kwargs['cislo'])
+ self.cislo = cislo
+ self.hodnoceni = s.Hodnoceni.objects.filter(cislo_body=cislo)
+ self.reseni = Reseni.objects.filter(hodnoceni__in = self.hodnoceni).annotate(Sum('hodnoceni__body')).annotate(Count('hodnoceni')).order_by('resitele__osoba')
+ return self.reseni
+
+ def get_context_data(self, **kwargs):
+ context = super(ObalkovaniView, self).get_context_data(**kwargs)
+ print(self.cislo)
+ context['cislo'] = self.cislo
+ return context
+
+
+
def AktualniZadaniView(request):
nastaveni = get_object_or_404(Nastaveni)
@@ -67,6 +116,99 @@ def ZadaniTemataView(request):
}
)
+# TODO Napsat tuto funkci znovu rekurzivně podle Jethrorad. Potom se podívat, jak lehce se dá modifikovat pro Rozcestník. Pokud lehce, rozšířit ji. Pokud složitě - použít tuhle
+def vytahniZLesaSeznam(tematko, koren, pouze_zajimave=False):
+ returnVal = []
+
+ stack = []
+ stack.append((koren.first_child, 0, False)) #Tuple of node, depth and relevance
+
+ while len(stack) > 0:
+ wn, wd, wr = stack.pop()
+
+ if wn.succ != None:
+ stack.append((wn.succ, wd, wr))
+ if isinstance(wn, s.TemaVCisleNode):
+ print("TEMA")
+ print(wn.tema.id)
+ print(tematko.id)
+ if wn.tema.id == tematko.id:
+ returnVal.append((posledni_cislo, 0))
+ print("PRIDANO")
+ wr = True
+ wd = 1
+
+ if wn.srolovatelne:
+ tagOpen = s.Text(na_web = "Otevírací srolovací tag")
+ tagOpenNode = s.TextNode(text = tagOpen)
+ tagClose = s.Text(na_web = "Zavírací srolovací tag")
+ tagCloseNode = s.TextNode(text = tagClose)
+ stack.append((tagCloseNode, wd, True))
+
+ if wn.first_child != None:
+ stack.append((wn.first_child, wd + 1, wr))
+
+ if isinstance(wn, s.CisloNode):
+ posledni_cislo = wn
+ print(wn)
+
+ if wr:
+ print("ZAJIMAVE")
+ if pouze_zajimave:
+ if not wn.zajimave:
+ continue
+ returnVal.append((wn, wd))
+ return returnVal
+
+def TematkoView(request, rocnik, tematko):
+ nastaveni = s.Nastaveni.objects.first()
+ rocnik_object = s.Rocnik.objects.filter(rocnik=rocnik)
+ tematko_object = s.Tema.objects.filter(rocnik=rocnik_object[0], kod=tematko)
+ seznam = vytahniZLesaSeznam(tematko_object[0], nastaveni.aktualni_rocnik().rocniknode)
+ for node, depth in seznam:
+ if node.isinstance(node, s.KonferaNode):
+ raise Exception("Not implemented yet")
+ if node.isinstance(node, s.PohadkaNode): # Mohu ignorovat, má pod sebou
+ pass
+
+ return render(request, 'seminar/tematka/toaletak.html', {})
+
+
+def TemataRozcestnikView(request):
+ print("=============================================")
+ nastaveni = s.Nastaveni.objects.first()
+ tematka_objects = s.Tema.objects.filter(rocnik=nastaveni.aktualni_rocnik())
+ tematka = [] #List tematka obsahuje pro kazde tematko object a list vsech TemaVCisleNodu - implementované pomocí slovníku
+ for tematko_object in tematka_objects:
+ print("AKTUALNI TEMATKO")
+ print(tematko_object.id)
+ odkazy = vytahniZLesaSeznam(tematko_object, nastaveni.aktualni_rocnik().rocniknode, pouze_zajimave = True) #Odkazy jsou tuply (node, depth) v listu
+ print(odkazy)
+ cisla = [] # List tuplů (nazev cisla, list odkazů)
+ vcisle = []
+ cislo = None
+ for odkaz in odkazy:
+ if odkaz[1] == 0:
+ if cislo != None:
+ cisla.append((cislo, vcisle))
+ cislo = (odkaz[0].getOdkazStr(), odkaz[0].getOdkaz())
+ vcisle = []
+ else:
+ print(odkaz[0].getOdkaz())
+ vcisle.append((odkaz[0].getOdkazStr(), odkaz[0].getOdkaz()))
+ if cislo != None:
+ cisla.append((cislo, vcisle))
+
+ print(cisla)
+ tematka.append({
+ "kod" : tematko_object.kod,
+ "nazev" : tematko_object.nazev,
+ "abstrakt" : tematko_object.abstrakt,
+ "obrazek": tematko_object.obrazek,
+ "cisla" : cisla
+ })
+ return render(request, 'seminar/tematka/rozcestnik.html', {"tematka": tematka, "rocnik" : nastaveni.aktualni_rocnik().rocnik})
+
#def ZadaniAktualniVysledkovkaView(request):
# nastaveni = get_object_or_404(Nastaveni)
@@ -143,7 +285,7 @@ class StareNovinkyView(generic.ListView):
# Organizatori
-def aktivniOrganizatori(datum=date.today()):
+def aktivniOrganizatori(datum=timezone.now()):
return Organizator.objects.exclude(
organizuje_do__isnull=False,
organizuje_do__lt=datum
@@ -252,26 +394,115 @@ class ArchivView(generic.ListView):
context["nahledy"] = "\n".join(tags)
return context
-
-def sloupec_s_poradim(vysledky):
- # počet řešitelů ve výsledkovce nad aktuálním
- lepsich_resitelu = 0
-
- poradi_l = []
- # projdeme skupiny řešitelů se stejným počtem bodů
- for skupina in (list(x) for _, x in groupby(vysledky, lambda x: x.body)):
-
- # připravíme si obsahy buněk ve sloupci pořadí pro skupinu
- if len(skupina) == 1:
- poradi_l += ["{}.".format(lepsich_resitelu + 1)]
- # je-li účastníků se stejným počtem bodů víc, pořadí (rozsah X.-Y.) je jen u prvního
+### Výsledky
+
+# ze setřízeného(!) seznamu všech bodů vytvoří seznam s pořadími (včetně 3.-5. a pak 2 volná místa atp.)
+def sloupec_s_poradim(seznam_s_body):
+ aktualni_poradi = 1
+ sloupec_s_poradim = []
+
+ # seskupíme seznam všech bodů podle hodnot
+ for index in range(0, len(seznam_s_body)):
+ # pokud je pořadí větší než číslo řádku, tak jsme vypsali větší rozsah a chceme
+ # vypsat už jen prázdné místo, než dojdeme na správný řádek
+ if (index + 1) < aktualni_poradi:
+ sloupec_s_poradim.append("")
+ continue
+ velikost_skupiny = 0
+ # zjistíme počet po sobě jdoucích stejných hodnot
+ while seznam_s_body[index] == seznam_s_body[index + velikost_skupiny]:
+ velikost_skupiny = velikost_skupiny + 1
+ # na konci musíme ošetřit přetečení seznamu
+ if (index + velikost_skupiny) > len(seznam_s_body) - 1:
+ break
+ # pokud je velikost skupiny 1, vypíšu pořadí
+ if velikost_skupiny == 1:
+ sloupec_s_poradim.append("{}.".format(aktualni_poradi))
+ # pokud je skupina větší, vypíšu rozsah
else:
- poradi_l += [u"{}.–{}.".format(lepsich_resitelu + 1, lepsich_resitelu + len(skupina))] + [""] * (len(skupina)-1)
- lepsich_resitelu += len(skupina)
- #pomlcka je opravdu pomlcka v unicode!!dulezite pro vysledkovku v TeXu
-
- return poradi_l
-
+ sloupec_s_poradim.append("{}.–{}.".format(aktualni_poradi,
+ aktualni_poradi+velikost_skupiny-1))
+ # zvětšíme aktuální pořadí o tolik, kolik pozic bylo přeskočeno
+ aktualni_poradi = aktualni_poradi + velikost_skupiny
+ return sloupec_s_poradim
+
+# spočítá součet bodů získaných daným řešitelem za zadaný problém a všechny jeho podproblémy
+def __soucet_resitele_problemu(problem, resitel, cislo, soucet):
+ # sečteme body za daný problém přes všechna řešení daného problému
+ # od daného řešitele
+ reseni_resitele = problem.hodnoceni_set.filter(reseni__resitele=resitel,
+ cislo_body=cislo)
+ # XXX chyba na řádku výše - řešení může mít více řešitelů, asi chceme contains
+ # nebo in
+ for r in reseni_resitele:
+ soucet += r.body
+
+ # a přičteme k tomu hodnocení všech podproblémů
+ for p in problem.podproblem.all():
+ # i přes jméno by to měla být množina jeho podproblémů
+ soucet += __soucet_resitele_problemu(p, resitel, soucet)
+ return soucet
+
+# spočítá součet všech bodů ze všech podproblémů daného problému daného řešitele
+def body_resitele_problemu_v_cisle(problem, resitel, cislo):
+ # probably FIXED: nezohledňuje číslo, do kterého se body počítají
+ return __soucet_resitele_problemu(problem, resitel, cislo, 0)
+
+# vrátí list všech problémů s body v daném čísle, které již nemají nadproblém
+def hlavni_problemy_cisla(cislo):
+ hodnoceni = cislo.hodnoceni.select_related('problem', 'reseni').all() # hodnocení, která se vážou k danému číslu
+
+ reseni = [h.reseni for h in hodnoceni]
+ problemy = [h.problem for h in hodnoceni]
+ problemy_set = set(problemy) # chceme každý problém unikátně,
+ problemy = (list(problemy_set)) # převedení na množinu a zpět to zaručí
+
+ # hlavní problémy čísla
+ # (mají vlastní sloupeček ve výsledkovce, nemají nadproblém)
+ hlavni_problemy = []
+ for p in problemy:
+ while not(p.nadproblem == None):
+ p = p.nadproblem
+ hlavni_problemy.append(p)
+
+ # zunikátnění
+ hlavni_problemy_set = set(hlavni_problemy)
+ hlavni_problemy = list(hlavni_problemy_set)
+ hlavni_problemy.sort(key=lambda k: k.kod_v_rocniku()) # setřídit podle t1, t2, c3, ...
+
+ return hlavni_problemy
+
+def body_resitele_odjakziva(resitel):
+ body = 0
+ resitelova_hodnoceni = Hodnoceni.objects.select_related('body').all().filter(reseni_resitele=resitel)
+ # TODO: v radku nahore chceme _in nebo _contains
+ for hodnoceni in resitelova_hodnoceni:
+ body = body + hodnoceni.body
+ return body
+
+# spočítá součet všech bodů řešitele za dané číslo
+def body_resitele_v_cisle(resitel, cislo):
+ hlavni_problemy = hlavni_problemy_cisla(cislo)
+ body_resitele = 0
+ for h in hlavni_problemy:
+ body_resitele = body_resitele + body_resitele_problemu_v_cisle(h, resitel, cislo)
+ # TODO: je rozdíl mezi odevzdanou úlohou za 0 a tím, když řešitel nic neodevzdal
+ # řešit přes kontrolu velikosti množiny řešení daného problému do daného čísla?
+ # Tady to ale nevadí, tady se počítá součet za číslo.
+ return body_resitele
+
+# spočítá součet všech bodů řešitele za daný rok (nebo jen do daného čísla včetně)
+def body_resitele_v_rocniku(resitel, rocnik, do_cisla=None):
+ # pokud do_cisla=None, tak do posledního čísla v ročníku
+ # do_cisla je objekt Cislo
+ cisla = rocnik.cisla.all() # funkce vrátí pole objektů
+ # Cislo už lexikograficky setřízené, viz models
+ body = 0
+ for cislo in cisla:
+ if cislo.poradi == do_cisla.poradi: break
+ # druhá část zaručuje, že máme výsledky do daného čísla včetně
+ body = body + body_resitele_v_cisle(resitel, cislo)
+ return body
#def vysledkovka_rocniku(rocnik, jen_verejne=True):
# """Přebírá ročník (např. context["rocnik"]) a vrací výsledkovou listinu ve
@@ -288,7 +519,7 @@ def sloupec_s_poradim(vysledky):
# return None
#
# #vybere vsechny vysledky z posledniho (verejneho) cisla a setridi sestupne dle bodu
-# vysledky = list(cisla_v_rocniku.filter(cislo = cisla_v_rocniku[0].cislo).order_by('-body', 'resitel__prijmeni', 'resitel__jmeno').select_related('resitel'))
+# vysledky = list(cisla_v_rocniku.filter(cislo = cisla_v_rocniku[0].poradi).order_by('-body', 'resitel__prijmeni', 'resitel__jmeno').select_related('resitel'))
#
# class Vysledkovka:
# def __init__(self):
@@ -304,7 +535,7 @@ def sloupec_s_poradim(vysledky):
# v.poradi = poradi
# v.resitel.rocnik = v.resitel.rocnik(rocnik)
#
-# verejne_vysl_odjakziva = VysledkyKCisluOdjakziva.objects.filter(cislo__rocnik=rocnik, cislo=cisla_v_rocniku[0].cislo)
+# verejne_vysl_odjakziva = VysledkyKCisluOdjakziva.objects.filter(cislo__rocnik=rocnik, cislo=cisla_v_rocniku[0].poradi)
# if jen_verejne:
# verejne_vysl_odjakziva = verejne_vysl_odjakziva.filter(cislo__verejna_vysledkovka=True)
#
@@ -380,16 +611,17 @@ class ProblemView(generic.DetailView):
class VysledkyResitele(object):
"""Pro daného řešitele ukládá počet bodů za jednotlivé úlohy a celkový
- počet bodů za číslo."""
-
- def __init__(self, jmeno, prijmeni):
- resitel_jmeno = jmeno
- resitel_prijmeni = prijmeni
- body = {}
- body_cislo = 0
-
- def body_za_cislo(self):
- return sum(body.values())
+ počet bodů za konkrétní ročník do daného čísla a za dané číslo."""
+
+ def __init__(self, resitel, cislo, rocnik):
+ self.resitel = resitel
+ self.cislo = cislo
+ self.body_cislo = body_resitele_v_cisle(resitel, cislo)
+ self.body = []
+ self.rocnik = rocnik
+ self.body_rocnik = body_resitele_v_rocniku(resitel, rocnik, cislo)
+ self.body_celkem_odjakziva = resitel.vsechny_body()
+ self.poradi = 0
class CisloView(generic.DetailView):
model = Cislo
@@ -400,8 +632,8 @@ class CisloView(generic.DetailView):
if queryset is None:
queryset = self.get_queryset()
rocnik_arg = self.kwargs.get('rocnik')
- cislo_arg = self.kwargs.get('cislo')
- queryset = queryset.filter(rocnik__rocnik=rocnik_arg, cislo=cislo_arg)
+ poradi_arg = self.kwargs.get('cislo')
+ queryset = queryset.filter(rocnik__rocnik=rocnik_arg, poradi=poradi_arg)
try:
obj = queryset.get()
@@ -410,88 +642,53 @@ class CisloView(generic.DetailView):
{'verbose_name': queryset.model._meta.verbose_name})
return obj
- # spočítá součet bodů získaných daným řešitelem za zadaný problém a všechny jeho podproblémy
- def __soucet_resitele_problemu(problem, resitel, soucet):
- # FIXME: správně je nadproblem_(typ problemu), ale to by bylo potřeba nějak
- # zjistit, jaký typ nodu to vlastně je a aplikovat to ve volání funkce
-
- # sečteme body za daný problém přes všechna řešení daného problému
- # od daného řešitele
- reseni_resitele = problem.hodnoceni_set.filter(reseni_resitele__contains=resitel)
- for r in reseni_resitele:
- soucet += r.body
-
- for p in problem.nadproblem_set:
- # i přes jméno by to měla být množina jeho podproblémů
- soucet += __soucet_resitele_problemu(p, resitel, soucet)
- return soucet
-
-
- def vysledky_resitele_problemu(problem, resitel, cislo):
- return __soucet_resitele_problemu(problem, resitel, 0)
-
-
def get_context_data(self, **kwargs):
context = super(CisloView, self).get_context_data(**kwargs)
## TODO upravit dle nového modelu
cislo = context['cislo']
- hodnoceni = cislo.hodnoceni_set # hodnocení, která se vážou k danému číslu
-
- reseni = [h.reseni for h in hodnoceni]
- problemy = [h.problem for h in hodnoceni]
- problemy_set = set(problemy) # chceme každý problém unikátně,
- problemy = (list(problemy_set)) # převedení na množinu a zpět to zaručí
-
- # hlavní problémy čísla
- # (mají vlastní sloupeček ve výsledkovce, nemají nadproblém)
- hlavni_problemy = []
- for p in problemy:
- while not(p.nadproblem == None):
- p = nadproblem
- hlavni_problemy.append(p)
-
- # zunikátnění
- hlavni_problemy_set = set(hlavni_problemy)
- hlavni_problemy = list(hlavni_problemy_set)
+ hlavni_problemy = hlavni_problemy_cisla(cislo)
## TODO dostat pro tyto problémy součet v daném čísle pro daného řešitele
## TODO možná chytřeji vybírat aktivní řešitele
## chceme letos něco poslal
aktivni_resitele = Resitel.objects.filter(
- rok_maturity__gte=context['rocnik'].druhy_rok())
+ rok_maturity__gte=cislo.rocnik.druhy_rok())
+ # TODO: zkusit hodnoceni__rocnik...
#.filter(hodnoceni_set__rocnik__eq=cislo_rocnik)
radky_vysledkovky = []
for ar in aktivni_resitele:
- vr = VysledkyResitele(ar.jmeno, ar.prijmeni)
- for h in hlavni_problemy:
- body = vysledky_resitele_problemu(h, ar, cislo)
- vr.body[h.kod_v_rocniku] = body
- vr.body_cislo = vr.body_cislo + body
+ # získáme výsledky řešitele - součty přes číslo a ročník
+ vr = VysledkyResitele(ar, cislo, cislo.rocnik)
+ for hp in hlavni_problemy:
+ vr.body.append(
+ body_resitele_problemu_v_cisle(hp, ar, cislo))
radky_vysledkovky.append(vr)
- ## TODO: spočítat počet bodů řešitele v daném ročníku a seřadit je podle toho
- ## TODO: možná použít tyto funkce i v RocnikVysledkovkaView (a umístit sem nebo tam)?
-
+ # setřídíme řádky výsledkovky/objekty VysledkyResitele podle bodů
+ radky_vysledkovky.sort(key=lambda vr: vr.body_rocnik, reverse=True)
-# vysledky = VysledkyKCisluZaRocnik.objects.filter(cislo = context['cislo']).\
-# order_by('-body', 'resitel__prijmeni', 'resitel__jmeno')
-# reseni = Reseni.objects.filter(cislo_body = context['cislo']).select_related("resitel")
+ # generujeme sloupec s pořadím pomocí stejně zvané funkce
+ pocty_bodu = [rv.body_rocnik for rv in radky_vysledkovky]
+ sloupec_poradi = sloupec_s_poradim(pocty_bodu)
+
+ # každému řádku výsledkovky přidáme jeho pořadí
+ i = 0
+ for rv in radky_vysledkovky:
+ rv.poradi = sloupec_poradi[i]
+ i = i + 1
+
+ # vytahané informace předáváme do kontextu
+ context['cislo'] = cislo
+ context['radky_vysledkovky'] = radky_vysledkovky
+ context['problemy'] = hlavni_problemy
+# context['v_cisle_zadane'] = TODO
+# context['resene_problemy'] = resene_problemy
+ #XXX testovat
+ #XXX opravit to, že se nezobrazují body za jednotlivé úlohy
- # typy úloh, které se mají zobrazovat u čísla, tj. těch, které byly
- # v čísle skutečně zadány
-# typy_skutecne_zadanych = [Problem.TYP_ULOHA, Problem.TYP_SERIAL, Problem.TYP_ORG_CLANEK]
-# v_cisle_zadane = Problem.objects.filter(cislo_zadani=context['cislo']).filter(typ__in=typy_skutecne_zadanych).order_by('kod')
+ return context
-# resene_problemy = Problem.objects.filter(cislo_reseni=context['cislo']).filter(typ__in=typy_skutecne_zadanych).order_by('cislo_zadani__cislo', 'kod')
-#
-# poradi_typu = {
-# Problem.TYP_ULOHA: 1,
-# Problem.TYP_SERIAL: 2,
-# Problem.TYP_ORG_CLANEK: 3,
-# Problem.TYP_TEMA: 4,
-# Problem.TYP_RES_CLANEK: 5
-# }
# problemy = sorted(set(r.problem for r in reseni), key=lambda x:(poradi_typu[x.typ], x.kod_v_rocniku()))
# #setridi problemy podle typu a poradi zadani
# problem_index = {}
@@ -529,7 +726,6 @@ class CisloView(generic.DetailView):
# context['problemy'] = problemy
# context['v_cisle_zadane'] = v_cisle_zadane
# context['resene_problemy'] = resene_problemy
-# return context
class ArchivTemataView(generic.ListView):
model = Problem
@@ -601,9 +797,9 @@ def obalkyView(request,resitele):
tex = render(request,'seminar/archiv/obalky.tex', {'resitele': resitele}).content
tempdir = tempfile.mkdtemp()
- with open(tempdir+"/obalky.tex","wb") as texfile:
+ with open(tempdir+"/obalky.tex","w") as texfile:
texfile.write(tex)
- shutil.copy(os.path.join(settings.STATIC_ROOT, 'seminar/lisak.eps'),tempdir)
+ shutil.copy(os.path.join(settings.STATIC_ROOT, 'seminar/lisak.pdf'),tempdir)
subprocess.call(["pdflatex","obalky.tex"],cwd = tempdir)
with open(tempdir+"/obalky.pdf","rb") as pdffile:
@@ -612,7 +808,7 @@ def obalkyView(request,resitele):
return response
-def obalkovaniView(request, rocnik, cislo):
+def oldObalkovaniView(request, rocnik, cislo):
rocnik = Rocnik.objects.get(rocnik=rocnik)
cislo = Cislo.objects.get(rocnik=rocnik, cislo=cislo)
@@ -749,7 +945,7 @@ def StavDatabazeView(request):
@ensure_csrf_cookie
-def LoginView(request):
+def TeXUploadLoginView(request):
"""Pro přihlášení při nahrávání z texu"""
q = request.POST
# nastavení cookie csrftoken
@@ -938,7 +1134,7 @@ def texDownloadView(request, rocnik, cislo):
"body": p.body,
"zadani": p.text_zadani,
"reseni": p.text_reseni,
- "cislo_zadani": p.cislo_zadani.cislo,
+ "cislo_zadani": p.cislo_zadani.poradi,
} for p in resene
],
}
@@ -947,26 +1143,213 @@ def texDownloadView(request, rocnik, cislo):
cislo.save()
return JsonResponse(response)
+class ResitelView(LoginRequiredMixin,generic.DetailView):
+ model = Resitel
+ template_name = 'seminar/resitel.html'
+
+ def get_object(self, queryset=None):
+ print(self.request.user)
+ return Resitel.objects.get(osoba__user=self.request.user)
+
## Formulare
+class AddSolutionView(LoginRequiredMixin, FormView):
+ template_name = 'seminar/org/vloz_reseni.html'
+ form_class = f.VlozReseniForm
+ success_url = '/'
+
+def resetPasswordView(request):
+ pass
-def get_name(request):
- # if this is a POST request we need to process the form data
+def loginView(request):
if request.method == 'POST':
- # create a form instance and populate it with data from the request:
- form = NameForm(request.POST)
- # check whether it's valid:
+ form = LoginForm(request.POST)
if form.is_valid():
- # process the data in form.cleaned_data as required
- # ...
- # redirect to a new URL:
+ user = authenticate(request,
+ username=form.cleaned_data['username'],
+ password=form.cleaned_data['password'])
+ print(form.cleaned_data)
+ if user is not None:
+ login(request,user)
+ return HttpResponseRedirect('/')
+ else:
+ return render(request,
+ 'seminar/login.html',
+ {'form': form, 'login_error': 'Neplatné jméno nebo heslo'})
+
+ else:
+ form = LoginForm()
+ return render(request, 'seminar/login.html', {'form': form})
+
+def logoutView(request):
+ form = LoginForm()
+ if request.user.is_authenticated:
+ logout(request)
+ return render(request, 'seminar/login.html', {'form': form, 'login_error': 'Byli jste úspěšně odhlášeni'})
+ return render(request, 'seminar/login.html', {'form': form})
+
+
+def prihlaska_log_gdpr_safe(logger, gdpr_logger, msg, form_data):
+ msg = "{}, form_hash:{}".format(msg,hash(form_data))
+ logger.warn(msg)
+ gdpr_logger.warn(msg+", form:{}".format(form_data))
+
+from django.forms.models import model_to_dict
+def resitelEditView(request):
+ err_logger = logging.getLogger('seminar.prihlaska.problem')
+ ## Načtení objektu Osoba a Resitel, patrici k aktuálně přihlášenému uživately
+ u = request.user
+ osoba_edit = Osoba.objects.get(user=u)
+ resitel_edit = osoba_edit.resitel
+ user_edit = osoba_edit.user
+ ## Vytvoření slovníku, kterým předvyplním formulář
+ prefill_1=model_to_dict(user_edit)
+ prefill_2=model_to_dict(resitel_edit)
+ prefill_3=model_to_dict(osoba_edit)
+ prefill_1.update(prefill_2)
+ prefill_1.update(prefill_3)
+ form = ProfileEditForm(initial=prefill_1)
+ ## Změna údajů a jejich uložení
+ if request.method == 'POST':
+ form = ProfileEditForm(request.POST)
+ if form.is_valid():
+ ## Změny v osobě
+ fcd = form.cleaned_data
+ osoba_edit.jmeno = fcd['jmeno']
+ osoba_edit.prijmeni = fcd['prijmeni']
+ osoba_edit.pohlavi_muz = fcd['pohlavi_muz']
+ osoba_edit.email = fcd['email']
+ osoba_edit.telefon = fcd['telefon']
+ osoba_edit.ulice = fcd['ulice']
+ osoba_edit.mesto = fcd['mesto']
+ osoba_edit.psc = fcd['psc']
+ ## Změny v osobě s podmínkami
+ if fcd.get('spam',False):
+ osoba_edit.datum_souhlasu_zasilani = date.today()
+ if fcd.get('stat','') in ('CZ','SK'):
+ osoba_edit.stat = fcd['stat']
+ else:
+ ## Neznámá země
+ msg = "Unknown country {}".format(fcd['stat_text'])
+
+ ## Změny v řešiteli
+ resitel_edit.skola = fcd['skola']
+ resitel_edit.rok_maturity = fcd['rok_maturity']
+ resitel_edit.zasilat = fcd['zasilat']
+ if fcd.get('skola'):
+ resitel_edit.skola = fcd['skola']
+ else:
+ # Unknown school - log it
+ msg = "Unknown school {}, {}".format(fcd['skola_nazev'],fcd['skola_adresa'])
+ resitel_edit.save()
+ osoba_edit.save()
+ return HttpResponseRedirect('/thanks/')
+ else:
+ ## Stránka před odeslaním formuláře = předvyplněný formulář
+ return render(request, 'seminar/edit.html', {'form': form})
+
+def prihlaskaView(request):
+ generic_logger = logging.getLogger('seminar.prihlaska')
+ err_logger = logging.getLogger('seminar.prihlaska.problem')
+ form_logger = logging.getLogger('seminar.prihlaska.form')
+ if request.method == 'POST':
+ form = PrihlaskaForm(request.POST)
+ # TODO vyresit, co se bude v jakych situacich zobrazovat
+ if form.is_valid():
+ generic_logger.info("Form valid")
+ fcd = form.cleaned_data
+ form_hash = hash(fcd)
+ form_logger.info(fcd,form_hash=form_hash)
+
+ with transaction.atomic():
+ u = User.objects.create_user(
+ username=fcd['username'],
+ password=fcd['password'],
+ email = fcd['email'])
+ u.save()
+
+ o = Osoba(
+ jmeno = fcd['jmeno'],
+ prijmeni = fcd['prijmeni'],
+ pohlavi_muz = fcd['pohlavi_muz'],
+ email = fcd['email'],
+ telefon = fcd.get('telefon',''),
+ datum_narozeni = fcd.get('datum_narozeni',None),
+ datum_souhlasu_udaje = date.today(),
+ datum_registrace = date.today(),
+ ulice = fcd.get('ulice',''),
+ mesto = fcd.get('mesto',''),
+ psc = fcd.get('psc',''),
+ poznamka = str(fcd)
+ )
+ if fcd.get('spam',False):
+ o.datum_souhlasu_zasilani = date.today()
+ if fcd.get('stat','') in ('CZ','SK'):
+ o.stat = fcd['stat']
+ else:
+ # Unknown country - log it
+ msg = "Unknown country {}".format(fcd['stat_text'])
+ err_logger.warn(msg,form_hash=form_hash)
+
+ o.save()
+ o.user = u
+ o.save()
+
+ r = Resitel(
+ rok_maturity = fcd['rok_maturity'],
+ zasilat = fcd['zasilat']
+ )
+
+ r.save()
+ r.osoba = o
+ if fcd.get('skola'):
+ r.skola = fcd['skola']
+ else:
+ # Unknown school - log it
+ msg = "Unknown school {}, {}".format(fcd['skola_nazev'],fcd['skola_adresa'])
+ err_logger.warn(msg,form_hash=form_hash)
+ r.save()
+
+
return HttpResponseRedirect('/thanks/')
# if a GET (or any other method) we'll create a blank form
else:
- form = NameForm()
+ form = PrihlaskaForm()
return render(request, 'seminar/prihlaska.html', {'form': form})
+class SkolaAutocomplete(autocomplete.Select2QuerySetView):
+ def get_queryset(self):
+ # Don't forget to filter out results depending on the visitor !
+ qs = Skola.objects.all()
+ if self.q:
+ qs = qs.filter(
+ Q(nazev__istartswith=self.q)|
+ Q(kratky_nazev__istartswith=self.q)|
+ Q(ulice__istartswith=self.q)|
+ Q(mesto__istartswith=self.q))
+
+ return qs
+
+class LoginRequiredAjaxMixin(object):
+ def dispatch(self, request, *args, **kwargs):
+ #if request.is_ajax() and not request.user.is_authenticated: # Pokud to otevřu jako stránku, tak se omezení neuplatní, takže to asi nechceme
+ if not request.user.is_authenticated:
+ return JsonResponse(data={'results': [], 'pagination': {}}, status=401)
+ return super(LoginRequiredAjaxMixin, self).dispatch(request, *args, **kwargs)
+
+class ResitelAutocomplete(LoginRequiredAjaxMixin,autocomplete.Select2QuerySetView):
+ def get_queryset(self):
+ qs = Resitel.objects.all()
+ if self.q:
+ qs = qs.filter(
+ Q(osoba__jmeno__startswith=self.q)|
+ Q(osoba__prijmeni__startswith=self.q)|
+ Q(osoba__prezdivka__startswith=self.q)
+ )
+ return qs
+
+
# Ceka na autocomplete v3
# class OrganizatorAutocomplete(autocomplete.Select2QuerySetView):
# def get_queryset(self):
@@ -987,3 +1370,46 @@ def get_name(request):
# Q(user__last_name__isstartswith=query))
#
# return qs
+
+# FIXME: Tohle asi vlastně vůbec nepatří do aplikace 'seminar'
+class LoginView(auth_views.LoginView):
+ # Jen vezmeme vestavěný a dáme mu vhodný template a přesměrovací URL
+ template_name = 'seminar/login.html'
+
+ # Přesměrovací URL má být v kontextu:
+ def get_context_data(self, **kwargs):
+ ctx = super().get_context_data(**kwargs)
+ ctx['next'] = reverse('titulni_strana')
+ return ctx
+
+class LogoutView(auth_views.LogoutView):
+ # Jen vezmeme vestavěný a dáme mu vhodný template a přesměrovací URL
+ template_name = 'seminar/logout.html'
+ # Pavel: Vůbec nevím, proč to s _lazy funguje, ale bez toho to bylo rozbité.
+ next_page = reverse_lazy('titulni_strana')
+
+# "Chci resetovat heslo"
+class PasswordResetView(auth_views.PasswordResetView):
+ #template_name = 'seminar/password_reset.html'
+ # TODO: vlastní email_template_name a subject_template_name a html_email_template_name
+ success_url = reverse_lazy('reset_password_done')
+ from_email = 'login@mam.mff.cuni.cz'
+
+# "Poslali jsme e-mail (pokud bylo kam))"
+class PasswordResetDoneView(auth_views.PasswordResetDoneView):
+ #template_name = 'seminar/password_reset_done.html'
+ pass
+
+# "Vymysli si heslo"
+class PasswordResetConfirmView(auth_views.PasswordResetConfirmView):
+ #template_name = 'seminar/password_confirm_done.html'
+ success_url = reverse_lazy('reset_password_complete')
+
+# "Heslo se asi změnilo."
+class PasswordResetCompleteView(auth_views.PasswordResetCompleteView):
+ #template_name = 'seminar/password_complete_done.html'
+ pass
+
+class PasswordChangeView(auth_views.PasswordChangeView):
+ #template_name = 'seminar/password_change.html'
+ success_url = reverse_lazy('titulni_strana')