Browse Source

Pre, unmanage, create. Snad ve finální podobě.

pull/47/head
Pavel "LEdoian" Turinsky 7 months ago
parent
commit
cdc1472595
  1. 13
      galerie/migrations/0011_pre_split_soustredeni.py
  2. 13
      personalni/migrations/0006_pre_split_soustredeni.py
  3. 13
      prednasky/migrations/0016_pre_split_soustredeni.py
  4. 16
      seminar/migrations/0122_pre_split_soustredeni.py
  5. 33
      seminar/migrations/0123_soustredeni_unmanage.py
  6. 25
      seminar/models/soustredeni.py
  7. 119
      soustredeni/migrations/0001_split_from_seminar.py
  8. 221
      soustredeni/models.py
  9. 3
      split-apps-meta/create.notes
  10. 3
      split-apps-meta/unmanage.notes

13
galerie/migrations/0011_pre_split_soustredeni.py

@ -0,0 +1,13 @@
# Generated by Django 4.2.11 on 2024-04-30 21:53
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('galerie', '0010_auto_20200819_0947'),
]
operations = [
]

13
personalni/migrations/0006_pre_split_soustredeni.py

@ -0,0 +1,13 @@
# Generated by Django 4.2.11 on 2024-04-30 21:53
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('personalni', '0005_personalni_post_migrate'),
]
operations = [
]

13
prednasky/migrations/0016_pre_split_soustredeni.py

@ -0,0 +1,13 @@
# Generated by Django 4.2.11 on 2024-04-30 21:53
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('prednasky', '0015_personalni_post_migrate'),
]
operations = [
]

16
seminar/migrations/0122_pre_split_soustredeni.py

@ -0,0 +1,16 @@
# Generated by Django 4.2.11 on 2024-04-30 21:54
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('seminar', '0121_personalni_post_migrate'),
('personalni', '0006_pre_split_soustredeni'),
('galerie', '0011_pre_split_soustredeni'),
('prednasky', '0016_pre_split_soustredeni'),
]
operations = [
]

33
seminar/migrations/0123_soustredeni_unmanage.py

@ -0,0 +1,33 @@
# Generated by Django 4.2.11 on 2024-04-30 22:17
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('seminar', '0122_pre_split_soustredeni'),
]
operations = [
migrations.AlterModelOptions(
name='konfera',
options={'managed': False, 'verbose_name': 'Konfera', 'verbose_name_plural': 'Konfery'},
),
migrations.AlterModelOptions(
name='konfery_ucastnici',
options={'managed': False, 'ordering': ['konfera', 'resitel'], 'verbose_name': 'Účast na konfeře', 'verbose_name_plural': 'Účasti na konfeře'},
),
migrations.AlterModelOptions(
name='soustredeni',
options={'managed': False, 'ordering': ['-rocnik__rocnik', '-datum_zacatku'], 'verbose_name': 'Soustředění', 'verbose_name_plural': 'Soustředění'},
),
migrations.AlterModelOptions(
name='soustredeni_organizatori',
options={'managed': False, 'ordering': ['soustredeni', 'organizator'], 'verbose_name': 'Účast organizátorů na soustředění', 'verbose_name_plural': 'Účasti organizátorů na soustředění'},
),
migrations.AlterModelOptions(
name='soustredeni_ucastnici',
options={'managed': False, 'ordering': ['soustredeni', 'resitel'], 'verbose_name': 'Účast na soustředění', 'verbose_name_plural': 'Účasti na soustředění'},
),
]

25
seminar/models/soustredeni.py

@ -20,6 +20,7 @@ logger = logging.getLogger(__name__)
class Soustredeni(SeminarModelBase):
class Meta:
managed = False
db_table = 'seminar_soustredeni'
verbose_name = 'Soustředění'
verbose_name_plural = 'Soustředění'
@ -28,7 +29,7 @@ class Soustredeni(SeminarModelBase):
# Interní ID
id = models.AutoField(primary_key = True)
rocnik = models.ForeignKey(am.Rocnik, verbose_name='ročník', related_name='soustredeni',
rocnik = models.ForeignKey(am.Rocnik, verbose_name='ročník', related_name='soustredeni_old',
on_delete=models.PROTECT)
datum_zacatku = models.DateField('datum začátku', blank=True, null=True,
@ -43,9 +44,11 @@ class Soustredeni(SeminarModelBase):
help_text='Místo (název obce, volitelně též objektu')
ucastnici = models.ManyToManyField(Resitel, verbose_name='účastníci soustředění',
related_name='soustredeni_old',
help_text='Seznam účastníků soustředění', through='Soustredeni_Ucastnici')
organizatori = models.ManyToManyField(Organizator,
related_name='soustredeni_old',
verbose_name='Organizátoři soustředění',
help_text='Seznam organizátorů soustředění',
through='Soustredeni_Organizatori')
@ -84,6 +87,7 @@ class Soustredeni_Ucastnici(SeminarModelBase):
# zmena dedicnosti z models.Model na SeminarModelBase, potencialni vznik bugu
class Meta:
managed = False
db_table = 'seminar_soustredeni_ucastnici'
verbose_name = 'Účast na soustředění'
verbose_name_plural = 'Účasti na soustředění'
@ -92,9 +96,12 @@ class Soustredeni_Ucastnici(SeminarModelBase):
# Interní ID
id = models.AutoField(primary_key = True)
resitel = models.ForeignKey(Resitel, verbose_name='řešitel', on_delete=models.PROTECT)
resitel = models.ForeignKey(Resitel, verbose_name='řešitel',
related_name='sous_ucastnici',
on_delete=models.PROTECT)
soustredeni = models.ForeignKey(Soustredeni, verbose_name='soustředění',
related_name='sous_ucastnici',
on_delete=models.PROTECT)
poznamka = models.TextField('neveřejná poznámka', blank=True,
@ -110,6 +117,7 @@ class Soustredeni_Organizatori(SeminarModelBase):
# zmena dedicnosti z models.Model na SeminarModelBase, potencialni vznik bugu
class Meta:
managed = False
db_table = 'seminar_soustredeni_organizatori'
verbose_name = 'Účast organizátorů na soustředění'
verbose_name_plural = 'Účasti organizátorů na soustředění'
@ -119,9 +127,11 @@ class Soustredeni_Organizatori(SeminarModelBase):
id = models.AutoField(primary_key = True)
organizator = models.ForeignKey(Organizator, verbose_name='organizátor',
related_name='sous_orgove',
on_delete=models.PROTECT)
soustredeni = models.ForeignKey(Soustredeni, verbose_name='soustředění',
related_name='sous_orgove',
on_delete=models.PROTECT)
poznamka = models.TextField('neveřejná poznámka', blank=True,
@ -152,10 +162,13 @@ def generate_filename_konfera(self, filename):
@reversion.register(ignore_duplicates=True)
class Konfera(am.Problem):
class Meta:
managed = False
db_table = 'seminar_konfera'
verbose_name = 'Konfera'
verbose_name_plural = 'Konfery'
problem_ptr_old = models.OneToOneField(am.Problem, parent_link=True, related_name='konfera_old', on_delete=models.PROTECT, primary_key=True)
anotace = models.TextField('anotace', blank=True,
help_text='Popis, o čem bude konfera.')
@ -164,10 +177,11 @@ class Konfera(am.Problem):
# FIXME: Umíme omezit jen na účastníky daného soustřeďka?
ucastnici = models.ManyToManyField(Resitel, verbose_name='účastníci konfery',
related_name='konfera_old',
help_text='Seznam účastníků konfery', through='Konfery_Ucastnici')
soustredeni = models.ForeignKey(Soustredeni, verbose_name='soustředění',
related_name='konfery', on_delete = models.SET_NULL, null=True)
related_name='konfery_old', on_delete = models.SET_NULL, null=True)
TYP_VELETRH = 'veletrh'
TYP_PREZENTACE = 'prezentace'
@ -196,6 +210,7 @@ class Konfera(am.Problem):
class Konfery_Ucastnici(models.Model):
class Meta:
managed = False
db_table = 'seminar_konfery_ucastnici'
verbose_name = 'Účast na konfeře'
verbose_name_plural = 'Účasti na konfeře'
@ -204,9 +219,9 @@ class Konfery_Ucastnici(models.Model):
# Interní ID
id = models.AutoField(primary_key = True)
resitel = models.ForeignKey(Resitel, verbose_name='řešitel', on_delete=models.PROTECT)
resitel = models.ForeignKey(Resitel, verbose_name='řešitel', on_delete=models.PROTECT, related_name='konf_uc')
konfera = models.ForeignKey(Konfera, verbose_name='konfera', on_delete=models.CASCADE)
konfera = models.ForeignKey(Konfera, verbose_name='konfera', on_delete=models.CASCADE, related_name='konf_uc')
poznamka = models.TextField('neveřejná poznámka', blank=True,
help_text='Neveřejná poznámka k účasti (plain text)')

119
soustredeni/migrations/0001_split_from_seminar.py

@ -0,0 +1,119 @@
# Generated by Django 4.2.11 on 2024-04-30 22:53
from django.db import migrations, models
import django.db.models.deletion
import soustredeni.models
def nastav_nove_contenttypes(apps, schema_editor):
ContentType = apps.get_model('contenttypes', 'ContentType')
for m in ('konfera', 'soustredeni', 'soustredeni_ucastnici', 'soustredeni_organizatori', 'konfery_ucastnici'):
oct = ContentType.objects.filter(app_label='seminar', model=m)
oct.update(app_label='soustredeni')
def nastav_stare_contenttypes(apps, schema_editor):
ContentType = apps.get_model('contenttypes', 'ContentType')
for m in ('konfera', 'soustredeni', 'soustredeni_ucastnici', 'soustredeni_organizatori', 'konfery_ucastnici'):
nct = ContentType.objects.filter(app_label='soustredeni', model=m)
nct.update(app_label='seminar')
class Migration(migrations.Migration):
initial = True
dependencies = [
('seminar', '0123_soustredeni_unmanage'),
]
operations = [
migrations.RunPython(nastav_nove_contenttypes, nastav_stare_contenttypes),
migrations.CreateModel(
name='Konfera',
fields=[
('problem_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='seminar.problem')),
('anotace', models.TextField(blank=True, help_text='Popis, o čem bude konfera.', verbose_name='anotace')),
('abstrakt', models.TextField(blank=True, help_text='Abstrakt konfery tak, jak byl uveden ve sborníku', verbose_name='abstrakt')),
('typ_prezentace', models.CharField(choices=[('veletrh', 'Veletrh (postery)'), ('prezentace', 'Prezentace (přednáška)')], default='veletrh', max_length=16, verbose_name='typ prezentace')),
('prezentace', models.FileField(blank=True, help_text='Prezentace nebo fotka posteru', upload_to=soustredeni.models.generate_filename_konfera, verbose_name='prezentace')),
('materialy', models.FileField(blank=True, help_text='Další materiály ke konfeře zabalené do jednoho souboru', upload_to=soustredeni.models.generate_filename_konfera, verbose_name='materialy')),
('soustredeni', models.ForeignKey(to='soustredeni.soustredeni', verbose_name='soustředění', on_delete=models.PROTECT)),
],
options={
'verbose_name': 'Konfera',
'verbose_name_plural': 'Konfery',
'db_table': 'seminar_konfera',
'managed': False,
},
bases=('seminar.problem',),
),
migrations.CreateModel(
name='Konfery_Ucastnici',
fields=[
('id', models.AutoField(primary_key=True, serialize=False)),
('poznamka', models.TextField(blank=True, help_text='Neveřejná poznámka k účasti (plain text)', verbose_name='neveřejná poznámka')),
('resitel', models.ForeignKey(to='personalni.resitel', verbose_name='řešitel', on_delete=models.PROTECT)),
('konfera', models.ForeignKey(to='soustredeni.konfera', verbose_name='konfera', on_delete=models.CASCADE)),
],
options={
'verbose_name': 'Účast na konfeře',
'verbose_name_plural': 'Účasti na konfeře',
'db_table': 'seminar_konfery_ucastnici',
'ordering': ['konfera', 'resitel'],
'managed': False,
},
),
migrations.CreateModel(
name='Soustredeni',
fields=[
('id', models.AutoField(primary_key=True, serialize=False)),
('datum_zacatku', models.DateField(blank=True, help_text='První den soustředění', null=True, verbose_name='datum začátku')),
('datum_konce', models.DateField(blank=True, help_text='Poslední den soustředění', null=True, verbose_name='datum konce')),
('verejne_db', models.BooleanField(db_column='verejne', default=False, verbose_name='soustředění zveřejněno')),
('misto', models.CharField(blank=True, default='', help_text='Místo (název obce, volitelně též objektu', max_length=256, verbose_name='místo soustředění')),
('text', models.TextField(blank=True, default='', verbose_name='text k soustředění (HTML)')),
('typ', models.CharField(choices=[('jarni', 'Jarní soustředění'), ('podzimni', 'Podzimní soustředění'), ('vikend', 'Víkendový sraz'), ('vylet', 'Výlet')], default='podzimni', max_length=16, verbose_name='typ akce')),
('exportovat', models.BooleanField(db_column='exportovat', default=False, help_text='Exportuje se jen podle tohoto flagu (ne veřejnosti)', verbose_name='export do AESOPa')),
('rocnik', models.ForeignKey(to='seminar.rocnik', verbose_name='ročník', related_name='soustredeni', on_delete=models.PROTECT)),
],
options={
'verbose_name': 'Soustředění',
'verbose_name_plural': 'Soustředění',
'db_table': 'seminar_soustredeni',
'ordering': ['-rocnik__rocnik', '-datum_zacatku'],
'managed': False,
},
),
migrations.CreateModel(
name='Soustredeni_Organizatori',
fields=[
('id', models.AutoField(primary_key=True, serialize=False)),
('poznamka', models.TextField(blank=True, help_text='Neveřejná poznámka k účasti organizátora (plain text)', verbose_name='neveřejná poznámka')),
('organizator', models.ForeignKey(to='personalni.organizator', verbose_name='organizátor', on_delete=models.PROTECT)),
('soustredeni', models.ForeignKey(to='soustredeni.soustredeni', verbose_name='soustředění', on_delete=models.PROTECT)),
],
options={
'verbose_name': 'Účast organizátorů na soustředění',
'verbose_name_plural': 'Účasti organizátorů na soustředění',
'db_table': 'seminar_soustredeni_organizatori',
'ordering': ['soustredeni', 'organizator'],
'managed': False,
},
),
migrations.CreateModel(
name='Soustredeni_Ucastnici',
fields=[
('id', models.AutoField(primary_key=True, serialize=False)),
('poznamka', models.TextField(blank=True, help_text='Neveřejná poznámka k účasti (plain text)', verbose_name='neveřejná poznámka')),
('resitel', models.ForeignKey(to='personalni.resitel', verbose_name='řešitel', on_delete=models.PROTECT)),
('soustredeni', models.ForeignKey(to='soustredeni.soustredeni', verbose_name='soustředění', on_delete=models.PROTECT)),
],
options={
'verbose_name': 'Účast na soustředění',
'verbose_name_plural': 'Účasti na soustředění',
'db_table': 'seminar_soustredeni_ucastnici',
'ordering': ['soustredeni', 'resitel'],
'managed': False,
},
),
]

221
soustredeni/models.py

@ -0,0 +1,221 @@
# -*- coding: utf-8 -*-
import logging
import os
from django.db import models
from django.urls import reverse
from reversion import revisions as reversion
from django.conf import settings
from personalni.models import Resitel, Organizator
from seminar.models.base import SeminarModelBase
from seminar.models import tvorba as am
logger = logging.getLogger(__name__)
@reversion.register(ignore_duplicates=True)
class Soustredeni(SeminarModelBase):
class Meta:
managed = False
db_table = 'seminar_soustredeni'
verbose_name = 'Soustředění'
verbose_name_plural = 'Soustředění'
ordering = ['-rocnik__rocnik', '-datum_zacatku']
# Interní ID
id = models.AutoField(primary_key = True)
rocnik = models.ForeignKey(am.Rocnik, verbose_name='ročník', related_name='soustredeni',
on_delete=models.PROTECT)
datum_zacatku = models.DateField('datum začátku', blank=True, null=True,
help_text='První den soustředění')
datum_konce = models.DateField('datum konce', blank=True, null=True,
help_text='Poslední den soustředění')
verejne_db = models.BooleanField('soustředění zveřejněno', db_column='verejne', default=False)
misto = models.CharField('místo soustředění', max_length=256, blank=True, default='',
help_text='Místo (název obce, volitelně též objektu')
ucastnici = models.ManyToManyField(Resitel, verbose_name='účastníci soustředění',
help_text='Seznam účastníků soustředění', through='Soustredeni_Ucastnici')
organizatori = models.ManyToManyField(Organizator,
verbose_name='Organizátoři soustředění',
help_text='Seznam organizátorů soustředění',
through='Soustredeni_Organizatori')
text = models.TextField('text k soustředění (HTML)', blank=True, default='')
TYP_JARNI = 'jarni'
TYP_PODZIMNI = 'podzimni'
TYP_VIKEND = 'vikend'
TYP_VYLET = 'vylet'
TYP_CHOICES = [
(TYP_JARNI, 'Jarní soustředění'),
(TYP_PODZIMNI, 'Podzimní soustředění'),
(TYP_VIKEND, 'Víkendový sraz'),
(TYP_VYLET, 'Výlet'),
]
typ = models.CharField('typ akce', max_length=16, choices=TYP_CHOICES, blank=False, default=TYP_PODZIMNI)
exportovat = models.BooleanField('export do AESOPa', db_column='exportovat', default=False,
help_text='Exportuje se jen podle tohoto flagu (ne veřejnosti)')
def __str__(self):
return '{} ({})'.format(self.misto, self.datum_zacatku)
def verejne(self):
return self.verejne_db
verejne.boolean = True
def verejne_url(self):
#return reverse('seminar_soustredeni', kwargs={'pk': self.id})
return reverse('seminar_seznam_soustredeni')
@reversion.register(ignore_duplicates=True)
class Soustredeni_Ucastnici(SeminarModelBase):
# zmena dedicnosti z models.Model na SeminarModelBase, potencialni vznik bugu
class Meta:
managed = False
db_table = 'seminar_soustredeni_ucastnici'
verbose_name = 'Účast na soustředění'
verbose_name_plural = 'Účasti na soustředění'
ordering = ['soustredeni', 'resitel']
# Interní ID
id = models.AutoField(primary_key = True)
resitel = models.ForeignKey(Resitel, verbose_name='řešitel', on_delete=models.PROTECT)
soustredeni = models.ForeignKey(Soustredeni, verbose_name='soustředění',
on_delete=models.PROTECT)
poznamka = models.TextField('neveřejná poznámka', blank=True,
help_text='Neveřejná poznámka k účasti (plain text)')
def __str__(self):
return '{} na {}'.format(self.resitel, self.soustredeni)
# NOTE: Poteciální DB HOG bez select_related
@reversion.register(ignore_duplicates=True)
class Soustredeni_Organizatori(SeminarModelBase):
# zmena dedicnosti z models.Model na SeminarModelBase, potencialni vznik bugu
class Meta:
managed = False
db_table = 'seminar_soustredeni_organizatori'
verbose_name = 'Účast organizátorů na soustředění'
verbose_name_plural = 'Účasti organizátorů na soustředění'
ordering = ['soustredeni', 'organizator']
# Interní ID
id = models.AutoField(primary_key = True)
organizator = models.ForeignKey(Organizator, verbose_name='organizátor',
on_delete=models.PROTECT)
soustredeni = models.ForeignKey(Soustredeni, verbose_name='soustředění',
on_delete=models.PROTECT)
poznamka = models.TextField('neveřejná poznámka', blank=True,
help_text='Neveřejná poznámka k účasti organizátora (plain text)')
def __str__(self):
return '{} na {}'.format(self.organizator, self.soustredeni)
# NOTE: Poteciální DB HOG bez select_related
# FIXME cycle import
# Django neumí jednoduše serializovat partial nebo třídu s __call__
# (https://docs.djangoproject.com/en/1.8/topics/migrations/),
# neprojdou pak migrace. Takže rozlišení funkcí generujících názvy souboru
# podle adresáře řešíme takto.
##
def generate_filename_konfera(self, filename):
return os.path.join(
settings.SEMINAR_KONFERY_DIR,
am.aux_generate_filename(self, filename)
)
##
@reversion.register(ignore_duplicates=True)
class Konfera(am.Problem):
class Meta:
managed = False
db_table = 'seminar_konfera'
verbose_name = 'Konfera'
verbose_name_plural = 'Konfery'
anotace = models.TextField('anotace', blank=True,
help_text='Popis, o čem bude konfera.')
abstrakt = models.TextField('abstrakt', blank=True,
help_text='Abstrakt konfery tak, jak byl uveden ve sborníku')
# FIXME: Umíme omezit jen na účastníky daného soustřeďka?
ucastnici = models.ManyToManyField(Resitel, verbose_name='účastníci konfery',
help_text='Seznam účastníků konfery', through='Konfery_Ucastnici')
soustredeni = models.ForeignKey(Soustredeni, verbose_name='soustředění',
related_name='konfery', on_delete = models.SET_NULL, null=True)
TYP_VELETRH = 'veletrh'
TYP_PREZENTACE = 'prezentace'
TYP_CHOICES = [
(TYP_VELETRH, 'Veletrh (postery)'),
(TYP_PREZENTACE, 'Prezentace (přednáška)'),
]
typ_prezentace = models.CharField('typ prezentace', max_length=16, choices=TYP_CHOICES,
blank=False, default=TYP_VELETRH)
prezentace = models.FileField('prezentace',help_text = 'Prezentace nebo fotka posteru',
upload_to = generate_filename_konfera, blank=True)
materialy = models.FileField('materialy',
help_text = 'Další materiály ke konfeře zabalené do jednoho souboru',
upload_to = generate_filename_konfera, blank=True)
def __str__(self):
return "{}: ({})".format(self.nazev, self.soustredeni)
def cislo_node(self):
return None
@reversion.register(ignore_duplicates=True)
class Konfery_Ucastnici(models.Model):
class Meta:
managed = False
db_table = 'seminar_konfery_ucastnici'
verbose_name = 'Účast na konfeře'
verbose_name_plural = 'Účasti na konfeře'
ordering = ['konfera', 'resitel']
# Interní ID
id = models.AutoField(primary_key = True)
resitel = models.ForeignKey(Resitel, verbose_name='řešitel', on_delete=models.PROTECT)
konfera = models.ForeignKey(Konfera, verbose_name='konfera', on_delete=models.CASCADE)
poznamka = models.TextField('neveřejná poznámka', blank=True,
help_text='Neveřejná poznámka k účasti (plain text)')
def __str__(self):
return '{} na {}'.format(self.resitel, self.konfera)
# NOTE: Poteciální DB HOG bez select_related

3
split-apps-meta/create.notes

@ -1,6 +1,7 @@
Prostě zkopírovat vedle, s původními (=správnými) related names.
(Případně opravit *všechny* relativní importy)
makemigrations
! Doplnit hack kolem content-types (jako první operace při migraci)
! Doplnit ForeignKeys (TODO: jak? Já jsem je ukradl až zpětně…)
! Doplnit ForeignKeys (Vypadá to, že se dá vesměs zkopírovat předpis z models.py, jen místo prvního fieldu dát `to='app.model'. Dokonce asi funguje použít už novou aplikaci pro vazby v rámci aplikace.)
doplnit závislost na unmanage
migrate

3
split-apps-meta/unmanage.notes

@ -16,6 +16,9 @@ vim seminar/models/whatever
HINT: Add or change a related_name argument to the definition for 'seminar.Resitel.osoba' or 'seminar.Prijemce.osoba'.
Snadné řešení: dočasné related names mít unikátní. Stejně to nikoho nezajímá.
!! Zkontrolovat, že všechno má nastavenou db_table (jinak se to potom pokusí vybastlit jméno tabulky podle aplikace…)
Pro tip: related names nejsou součástí DB schématu, takže když se tohle opraví později (typicky při create spadne makemigrations), nevadí to a nemělo by být potřeba měnit migrace).
Pro multi-table inheritance je potřeba explicitně přidat 1to1Field s parent_link=True (<https://docs.djangoproject.com/en/5.0/topics/db/models/#specifying-the-parent-link-field>)
Je potřeba to udělat správně (třeba nemít FK), migrace potřeba není, protože je to stejně unmanaged…
makemigrations, bez úprav
migrate?

Loading…
Cancel
Save