Möglichkeiten, auf Programmeinstellungen zuzugreifen...

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

Guten Morgen!

Für mein Kalenderprogramm verwende ich eine config-Datei, die verschiedenste Einstellungsparameter enthält. Die Datei schaut in etwa so aus:

Code: Alles auswählen

 [main]     
PIXEL_ALLOWANCE_MOUSE_TOP = 2
PIXEL_ALLOWANCE_MOUSE_BOTTOM = 1
PIXEL_SCROLL = 10

[mainview]
WEEKDAY = Montag, Dienstag, Mittwoch, Donnerstag, ...
MONTH = Januar, Februar, März, April, Mai, Juni, ...
START_DATE = 0  
FIRST_WEEKDAY = 0
DAYS_TOGETHER = false
KW_VIEW = false 
STATIC_SIZE = false
COLS = 7 
ROWS = 3 
FIRST_ITEM_ROW = 1
ORIENTATION_FIRST_ITEM = 0

und so weiter und so weiter
Nachdem ich die Datei eingelesen habe, stehen mir die Parameter in einem dict zur Verfügung. Jetzt möchte ich das dict nicht PUBLIC setzen, muss aber in verschiedenen Funktionen und/oder Klassen auf den Inhalt zugreifen. Demnach muss ich

- das dict oder Werte daraus zwischen den Namensräumen weiterreichen oder
- jede Funktion/Klasse, die Werte aus der config-Datei benötigt, liest diese jeweils ein

Ich stelle mir allerdings eine Möglichkeit vor, über die alle Programmteile gleichermaßen auf die Parameter der config-Datei zugreifen können, ohne dass diese entweder ständig durchgereicht oder eingelesen werden.

Wie verwaltet ihr Programmeinstellungen?

Gruß
mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
Barabbas
User
Beiträge: 349
Registriert: Dienstag 4. März 2008, 14:47

Sowas kannst du mit Klassenvariablen machen. Einfach mal googlen, dazu gibt es einige Informationen. Hier aber mal ein einfaches Beispiel:

Code: Alles auswählen

#!/usr/bin/env python
# coding:utf-8
class Plugin(object):
    def __init__(self):
        print Config.data
        
class Config(object):
    data = 0
    
    def __init__(self):
        pass
        
    def load(self):
        Config.data = {
                        "asd":123,
                        "bcd":456
        
                    }
        
c = Config()
c.load()
print Config.data

p = Plugin()

Wie du siehst hat die Klasse Plugin Zugriff auf das Dict "data" ohne dass irgendwelche Daten durchgereicht werden müssen. Das funktioniert auch über verschiedene Module hinweg.
Pekh
User
Beiträge: 482
Registriert: Donnerstag 22. Mai 2008, 09:09

Vor der Frage stehe ich auch jedes Mal. Je nach Programmstruktur kann die Antwort darauf etwas unterschiedlich ausfallen. In letzter Zeit bin ich dazu übergegangen, die Konfigurationsdatei möglichst früh (= noch im ifmain) einzulesen, ggf. noch mit über die Kommandozeile mitgegebenen Optionen anzureichern und dann als Parameter an die Funktionen / Objekte zu übergeben. Wenn es sehr viele Optionen werden sollten, könnte man diese auch als Liste oder Dict übergeben (oder den Handle, den ConfigParser zurückgibt), meistens finde ich es jedoch schöner, auch wirklich einzelne Parameter zu verwenden.

Davon, daß du die Konfigurationsdatei mehrfach einliest möchte ich dir abraten. Hintergrund ist, daß das Programm dann schwer zu testen wird. Datenbank- und Dateizugriffe sind immer schwierig zu testen, weshalb ich es vorziehe, Verbindungen nach "Außen" an bestimmten Punkten zu konzentrieren. Es ist sehr praktisch, wenn die meisten Methoden / Funktionen Dateiobjekte als Parameter erwarten und dann auf diesen arbeiten, anstatt eigene zu öffnen. In Tests lassen sich diese "Dateien" dann sehr gut durch Mocks ersetzen.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

Barabbas hat geschrieben:Das funktioniert auch über verschiedene Module hinweg.
Eben nicht. Dein Beispiel funktioniert, solange alles im selben Modul liegt. Lagere ich allerdings Plugin() in ein externes Modul aus, muss ich Config.data erst wieder übergeben. Und da suche ich eben eine Möglichkeit, dass auch importierte Klassen und Funktionen auf Konfigurationsdaten zugreifen können.
Pekh hat geschrieben:Wenn es sehr viele Optionen werden sollten, könnte man diese auch als Liste oder Dict übergeben
Genau da liegt für mich der Pfeffer im Korn. Nachdem viele Funktionen und Klassen dieselben Optionen verwenden, müsste ich ständig das Optionen-dict übergeben, quasi schon standardmäßig. Das muss doch irgendwie zu vermeiden sein... :(

Gruß
mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

mutetella hat geschrieben: Genau da liegt für mich der Pfeffer im Korn. Nachdem viele Funktionen und Klassen dieselben Optionen verwenden, müsste ich ständig das Optionen-dict übergeben, quasi schon standardmäßig. Das muss doch irgendwie zu vermeiden sein... :(
Wieso ist das so schlimm? Das wäre dann ja nur ein Parameter... sollen sie auf eine Config-Datei zugreifen (sprich neu einlesen oder was auch immer), so brauchen sie ja auch einen Parameter - ob nun Dateiname oder ein anderes Objekt ;-)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Benutzeravatar
/me
User
Beiträge: 3554
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

mutetella hat geschrieben:Nachdem viele Funktionen und Klassen dieselben Optionen verwenden, müsste ich ständig das Optionen-dict übergeben, quasi schon standardmäßig. Das muss doch irgendwie zu vermeiden sein... :(
Dann pack einfach die Daten in ein spezielles, nur dafür vorgesehenes, Modul und importiere das überall wo du es brauchst. Damit hast du nur einmal den import und nicht jedesmal eine Parameterübergabe.

Code: Alles auswählen

import mysettings

def foo(bar):
    return bar + mysettings.offset
Barabbas
User
Beiträge: 349
Registriert: Dienstag 4. März 2008, 14:47

mutetella hat geschrieben:
Barabbas hat geschrieben:Das funktioniert auch über verschiedene Module hinweg.
Eben nicht. Dein Beispiel funktioniert, solange alles im selben Modul liegt. Lagere ich allerdings Plugin() in ein externes Modul aus, muss ich Config.data erst wieder übergeben. Und da suche ich eben eine Möglichkeit, dass auch importierte Klassen und Funktionen auf Konfigurationsdaten zugreifen können.
Kann nicht sein: Ich habe das obige Beispiel zunächst in drei Dateien gesplittet (main, config und plug). Das hat funktioniert. Nur für das Forum habe ich es wieder zusammengefügt, weil drei Codesnippets doch sehr unübersichtlich sind.

Du musst natürlich darauf achten, dass du die Klassenvariabel nicht mit self.data setzt, sondern mit KLASSENNAME.data. Der Fehler unterläuft mir auch häufiger.

Hier die drei Dateien: http://bilder.xn--ngel-5qa.de/bilder/12 ... 1-test.zip

Ganz allgemein ist meine favorisierte Methode aber, eine Klasse Main bereit zu halten, die Verweise auf alle wichtigen Klassen hält (gui, config, events, player). So muss man jeder Klasse nur einen Verweis auf Main mitgeben. Ist übersichtlich und extrem leicht nachzuvollziehen, wenn jemand anderes den Code mal in die Hände bekommt.
Pekh
User
Beiträge: 482
Registriert: Donnerstag 22. Mai 2008, 09:09

mutetella hat geschrieben:
Pekh hat geschrieben:Wenn es sehr viele Optionen werden sollten, könnte man diese auch als Liste oder Dict übergeben
Genau da liegt für mich der Pfeffer im Korn. Nachdem viele Funktionen und Klassen dieselben Optionen verwenden, müsste ich ständig das Optionen-dict übergeben, quasi schon standardmäßig. Das muss doch irgendwie zu vermeiden sein... :(

Gruß
mutetella
Ich sehe das an sich nicht als schlimm an. Irgendwie müssen die Informationen ja zugeführt werden, und sauberer als über die offizielle Schnittstelle geht es halt nicht. Wenn du die selben Informationen an vielen verschiedenen Stellen im Programm benötigst, solltest du dir aber mal Gedanken darüber machen, ob nicht vielleicht ein Designfehler vorliegt. Klassen können zum Beispiel als Behälter begriffen werden, die Informationen mit den Funktionen bündeln, die auf/mit diesen Informationen arbeiten. Wenn du viele Instanzen dieser Klassen hast, die Informationen aber ihrem Wesen nach Konstanten sind, wären Klassenattribute das geeignete Mittel. Wenn du Informationen hast, die von mehreren Klassen verwendet werden, solltest du überlegen, ob du die Klassen nicht vielleicht sinnvoll zusammenlegen kannst.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

@Pekh:
Ich habe ein Modul view, das wiederum die Klasse View() und die Klasse Item() beinhaltet. View() ist für die Kalenderansicht (Monatsansicht, Wochenansicht etc.) zuständig, Item() für die einzelnen Elemente darin, in der Regel die enthaltenen Tage.
View() benötigt z. B. Informationen über Anzahl der Spalten und Zeilen der Ansicht oder den Abstand der Items zueinander und so weiter. Item() wiederum muss wissen, mit welcher Schrift Termineinträge oder dergleichen dargestellt werden.
Alle diese Infos liegen in der config-Datei. Wenn ich also die Konfigurationsdaten bereits im ifmain-Bereich einlese, muss ich diese erstmal an View() weiterreichen, View() ruft erstmal eine Funktion auf, die alle Tage, die in der view vorkommen ermittelt und zurückgibt. Diese Funktion benötigt ebenfalls Konfigurationsdaten. Dann ruft View() Item() auf und übergibt die Daten weiter. And so on....

Ist das normal so? Designfehler? Darüber muss ich nochmal nachdenken... Natürlich wäre es leichter, z. B. View() und Item() in eine Klasse zu legen, aber eine Trennung macht es z. B. leichter, nur das neu zu zeichnen, was sich auch geändert hat... Oh Mann....

@Barabbas:
Du hast Recht, ich war schlampig... Deine Methode der Main(), die an alle anderen verteilt, finde ich auch sehr reizvoll. Hatte allerdings kürzlich hier gelesen, dass das eher verpönt ist. Ich weiß leider nicht mehr warum... War vielleicht auch eine dieser "religiösen" Meinungen... :-)
/me hat geschrieben:Dann pack einfach die Daten in ein spezielles, nur dafür vorgesehenes, Modul und importiere das überall wo du es brauchst.
Das hatte ich auch schon gemacht, allerdings müssen dann pro import die Daten neu eingelesen werden. Außer das Modul selbst beinhaltet bereits die Konfigurationsparameter und -werte.


Ich denke mal, das Weiterreichen eines Konfig-dict wird wohl die beste Lösung sein...!?

Gruß
mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
midan23
User
Beiträge: 147
Registriert: Sonntag 21. Mai 2006, 21:41
Wohnort: Müchen
Kontaktdaten:

Wie wahrscheinlich viele andere auch hatte ich mal das gleiche Problem ...

Ich hatte es dann so gelöst, das ich ein Modul "config.py" hatte, das ungefähr so aussah:

Code: Alles auswählen

#
# coding: utf-8
import os
import ConfigParser

cfg = ConfigParser.SaveConfigParser()

def init():
    "initialisierung der Konfiguration"

def read(filename):
    init()
    if os.path.exists(filename):
        cfg.read(filename)

def write(filename):
    with open(filename, "wb") as f:
        cfg.write(f)
(Alles nur aus dem Kopf, also keine Garantie, das keine Fehler drin sind)

In der "init()"-Funktion hatte ich dann alle Sektionen und alle Optionen mit ihren Standard-Werten definiert.

Beim Starten meines Programms musste ich nur als erstes die "read()"-Funktion aufrufen und sicherstellen, das beim Beenden die Konfiguration mit "write()" gespeichert wurde.

In allen Modulen, in denen ich auf die Konfiguration zugreifen wollte, musste ich am Anfang nur ein

Code: Alles auswählen

from config import cfg
reinstellen ...

Auf Dauer wurde ich allerdings mit einigen Einschränkungen des SafeConfigParsers nicht glücklich.
Alternativen wie ConfigObj waren auch nicht ganz das richtige, also hab ich was eigenes auf die Beine gestellt ...
Barabbas
User
Beiträge: 349
Registriert: Dienstag 4. März 2008, 14:47

Hallo midan,

ich fürchte, dass das nicht die gesuchte Lösung ist. Der TE benutzt bereits ConfigObj (zumindest sehr wahrscheinlich - irgendwie muss er ja an das Dict kommen). Weiterhin ist deine Lösung nach meiner Einschätzung der hier bereits diskutierte "mehrfach einlesen"-Ansatz.

Dein eigener Ansatz ist vielleicht ganz nett, aber auch nicht mehr als eine zusätzliche Abstraktionsschicht um den ConfigParser drumrum. Da von "Einschränkungen" zu sprechen finde ich doch arg übertrieben. Natürlich muss man die Libs manchmal an den konkreten Bedarf anpassen. Dass das z.B. mit deinem EasyConfigParser so leicht geht ist wohl die Stärke dieser Libs und keine "Einschränkung". Im Endeffekt hast du ja mit deinen verschiedenen Options- und Sektions-Klassen zusätzlichen Bloat, den man in vielen Fällen gar nicht will.

Wie gesagt: Ich möchte deinen Ansatz gar nicht schlecht machen, aber ich wollte mal Partei für ConfigObj ergreifen. Man beschwert sich ja auch nicht, dass man in PyGTK keine Widgets für fertige TreeViews mit 3 Spalten des Types XYZ hat - man freut sich darüber, dass man genau so ein Widget mit PyGTK ohne viel Aufwand implementieren kann. Und das Ganze ist halt keine Einschränkung sondern die Macht der Bibliothek.


Schönen Gruß,

brb
Pekh
User
Beiträge: 482
Registriert: Donnerstag 22. Mai 2008, 09:09

mutetella hat geschrieben:@Pekh:
Ich habe ein Modul view, das wiederum die Klasse View() und die Klasse Item() beinhaltet. View() ist für die Kalenderansicht (Monatsansicht, Wochenansicht etc.) zuständig, Item() für die einzelnen Elemente darin, in der Regel die enthaltenen Tage.
View() benötigt z. B. Informationen über Anzahl der Spalten und Zeilen der Ansicht oder den Abstand der Items zueinander und so weiter. Item() wiederum muss wissen, mit welcher Schrift Termineinträge oder dergleichen dargestellt werden.
Alle diese Infos liegen in der config-Datei. Wenn ich also die Konfigurationsdaten bereits im ifmain-Bereich einlese, muss ich diese erstmal an View() weiterreichen, View() ruft erstmal eine Funktion auf, die alle Tage, die in der view vorkommen ermittelt und zurückgibt. Diese Funktion benötigt ebenfalls Konfigurationsdaten. Dann ruft View() Item() auf und übergibt die Daten weiter. And so on....

Ist das normal so? Designfehler? Darüber muss ich nochmal nachdenken... Natürlich wäre es leichter, z. B. View() und Item() in eine Klasse zu legen, aber eine Trennung macht es z. B. leichter, nur das neu zu zeichnen, was sich auch geändert hat... Oh Mann....

Ganz vermeiden lassen wird sich das Durchreichen von Daten wohl nie. Häufig ist es aber auch ein Zeichen dafür, daß du die Programmstruktur ungünstig ausgerichtet hast (Versuche sie dir als Baum der Abhängigkeiten vorzustellen). Vielleicht mußt du einfach nur irgendwo einen Zweig "abknapsen" und woanders dranhängen.

In diesem konkreten Fall solltest du dir noch mal überlegen, ob 'Item' nicht Aufgaben wahrnimmt, die in der übergeordneten Klasse 'View' besser aufgehoben wären. Deiner Beschreibung entnehme ich, daß beide Klassen für die Darstellung zuständig sind. Das ist in der Regel ungünstig, weil sie dann beide aufeinander Rücksicht nehmen müssen. Darstellung sollte zumindest innerhalb eines Fensters immer aus einer Hand erfolgen.
midan23
User
Beiträge: 147
Registriert: Sonntag 21. Mai 2006, 21:41
Wohnort: Müchen
Kontaktdaten:

Barabbas hat geschrieben:Weiterhin ist deine Lösung nach meiner Einschätzung der hier bereits diskutierte "mehrfach einlesen"-Ansatz.
Wo wird da was mehrfach eingelesen ?
  • Das "config.py"-Modul wird beim ersten Import gelesen.
  • Die Konfiguration wird beim Programmstart eingelesen und in der SaveConfigParser-Instanz gespeichert.
  • Diese steht über der Modul-Globalen Referenz "cfg" zur Verfügung und kann durch ein simples "from config import cfg" in den jeweiligen Namensraum eingefügt werden.
Das Ganze ist meiner Meinung nach eine einfache Möglichkeit folgende Vorgaben zu erfüllen:
  • Die Konfiguration wird beim Programmstart initialisiert und geladen.
  • Sie wird nirgends ein zweites mal geladen.
  • Sie steht jedem zum Programm gehörenden Modul zur Verfügung.
  • Sie wird beim Programmende gespeichert.
Oder lieg ich da verkehrt :mrgreen: :mrgreen: :mrgreen:
Barabbas
User
Beiträge: 349
Registriert: Dienstag 4. März 2008, 14:47

Mein Fehler, entschuldige. Irgendwie bin ich davon ausgegangen, dass bei jedem Import "cfg" überschrieben wird. Verstehe ich auch gerade auch irgendwie nicht, warum das nicht der Fall ist. Selbst wenn ich das ganze Modul importiere scheint das "cfg" immer die zuerst geladene Instanz des ConfigParsers zu referenzieren.

Naja /me ist offensichtlich noch einigen falschen Ansichten im Bezug auf Namensraum und Importe aufgesessen :?
midan23
User
Beiträge: 147
Registriert: Sonntag 21. Mai 2006, 21:41
Wohnort: Müchen
Kontaktdaten:

Na ja, wenn man es genau nimmt baut man mit meinem oben genannten Vorschlag im Prinzip ein Singleton ...
(Und das unabhängig von der verwendeten Bibliothek)

Hier kann man mehr zu dem Thema lesen.

Die interessante Frage wäre:

Ist für ein zentrale Programmkonfiguration ein Singleton/Borg vertretbar oder sollte man sich nach einer anderen Lösung (wie zB die Konfiguration beim Anlegen neuer Objekte mit auf den Weg geben) umsehen ?
Pekh
User
Beiträge: 482
Registriert: Donnerstag 22. Mai 2008, 09:09

midan23 hat geschrieben:
Die interessante Frage wäre:

Ist für ein zentrale Programmkonfiguration ein Singleton/Borg vertretbar oder sollte man sich nach einer anderen Lösung (wie zB die Konfiguration beim Anlegen neuer Objekte mit auf den Weg geben) umsehen ?
Im Grunde mußt du zur Beantwortung dieser Frage eine Kosten-Nutzen-Rechnung anstellen. Das per Singleton / Klassenvariablen / globalen Variablen zu lösen, ist zunächst einmal mit vergleichsweise wenig Aufwand verbunden. Der Preis dafür kommt in zweierlei Gestalt:

1) Die Nachvollziehbarkeit des Programmflusses leidet, weil hier Informationen an den eigentlichen Schnittstellen vorbeifließen.

2) Vor allem aber handelst du dir unter Umständen Probleme mit Nebeneffekten ein: Gerade wenn Nebenläufigkeit ins Spiel kommt (z.B. durch GUIs) kann es passieren, daß sich der Inhalt einer Konfigurationsoption ändert, ohne daß eine Funktion, die diese Optionen verwendet, etwas davon mitbekommt. Du müßtest also Locks / Semaphoren implementieren, und da wirds dann schon wieder reichlich kompliziert. Oder halt den Schreibzugriff untersagen. Ganz häßlich wirds beim (automatisierten) Testen: Du mußt vor jedem einzelnen Test sicherstellen, daß die Konfiguration genau die Werte enthält, von denen du ausgehst. Vergisst du das, und es gibt auch nur einen anderen Test, der an der Konfiguration etwas verändert, mußt du dich auf sehr seltsame Effekte einstellen. Dazu gehören Tests, die scheinbar völlig irrational mal durchlaufen und mal fehlschlagen, obwohl du am Code nichts veränderst.

Ich würde sagen: Für Code, der nur mal schnell hingeworfen wird, nicht kritisch (im Sinne von finanziellen, gesundheitlichen oder sonstigen Schäden) ist und den du nicht aus den Händen gibst, mag ein Singleton in Ordnung sein. Weil du als Urheber wissen solltest, wo die Gefahren lauern. Für alles andere solltest du den etwas "umständlicheren" aber solideren Weg einschlagen und Abhängigkeiten ausschließlich als Parameter übergeben.
Benutzeravatar
/me
User
Beiträge: 3554
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

mutetella hat geschrieben:
/me hat geschrieben:Dann pack einfach die Daten in ein spezielles, nur dafür vorgesehenes, Modul und importiere das überall wo du es brauchst.
Das hatte ich auch schon gemacht, allerdings müssen dann pro import die Daten neu eingelesen werden.
Warum? Der im Modul enthaltende Code wird doch nicht bei jedem Import neu ausgeführt.

Ein Modul wirkt unter Python quasi wie ein Singleton.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

Pekh hat geschrieben:In diesem konkreten Fall solltest du dir noch mal überlegen, ob 'Item' nicht Aufgaben wahrnimmt, die in der übergeordneten Klasse 'View' besser aufgehoben wären.
Zuerst hatte ich das auch. Eine View(), die das macht, was sie soll: Eine vorher festgelegte Kalenderansicht zeichnen. Dann begann ich damit, bereits gezeichnete Ansichten zu cachen, damit einmal berechnete Koordinaten während der Navigation nicht ständig neu berechnet werden müssen. Irgendwann stand ich dann vor der Notwendigkeit, nur einzelne Tage (Items) innerhalb der Kalenderansicht neu zu zeichnen bzw. aus den eventuell im Cache vorhandenen Koordinaten abzubilden. Das alles wurde dann für mein nicht allzu leistungsfähiges Gehirn zu komplex. Deshalb begann ich, die eigentliche Kalenderansicht von den darin enthaltenen Items zu trennen.
Aber Du hast wohl Recht: Die Trennung erfolgte nur, weil die Programmstruktur schlecht gestaltet und deshalb kaum noch beherrschbar war. Ein schlechter Grund, muss ich zugeben. Ich werde darüber nachdenken, wieder zusammenzufügen, was zusammen gehört.
/me hat geschrieben:Warum? Der im Modul enthaltende Code wird doch nicht bei jedem Import neu ausgeführt.
Stimmt. Da hab' ich schneller widersprochen als überlegt... :wink:


Zum jetzigen Zeitpunkt werde ich erst einmal Pekh's Rat folgen, die Programmstruktur entschlacken und das Konfigurations-dict oder Teile daraus per Parameter weiterreichen. Gehört ja schließlich zu den Kernaufgaben der Parameterübergabe...

Vielen Dank für Eure Beiträge. Neben meiner eigentlichen Frage habe ich wieder mal viel von Euch lernen können. Das ist total Klasse!!!

Gruß
mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
Antworten