Wann ist es tabu, Loops in Loops zu haben?


23

Nur neugierig. Das meiste, was ich je hatte, war eine for-Schleife innerhalb einer for-Schleife, denn nachdem ich dies von Linus Torvalds gelesen hatte :

Tabulatoren bestehen aus 8 Zeichen und Einrückungen aus 8 Zeichen. Es gibt ketzerische Bewegungen, die versuchen, 4 (oder sogar 2!) Zeichen tief einzurücken, und das ist vergleichbar mit dem Versuch, den Wert von PI als 3 zu definieren.

Begründung: Die Idee hinter dem Einrücken besteht darin, klar zu definieren, wo ein Kontrollblock beginnt und endet. Vor allem, wenn Sie 20 Stunden hintereinander auf Ihren Bildschirm geschaut haben, können Sie die Funktionsweise des Einzugs bei großen Einzügen viel besser erkennen.

Nun behaupten einige Leute, dass sich der Code durch Einrückungen mit 8 Zeichen zu weit nach rechts bewegt und es schwierig macht, auf einem Terminalbildschirm mit 80 Zeichen zu lesen. Die Antwort darauf lautet: Wenn Sie mehr als drei Einrückungsstufen benötigen, sind Sie sowieso durchgedreht und sollten Ihr Programm reparieren.

https://www.kernel.org/doc/Documentation/CodingStyle

Ich dachte, es wäre eine inakzeptable Praxis für mich, zu einer dritten Schleife überzugehen und meinen Code neu zu strukturieren (hauptsächlich Qt).

Scherzte Linus?

Kommt es auf die Sprache oder Anwendung an?

Gibt es Dinge, die unbedingt drei oder mehr Schleifenstufen benötigen?


8
Ich bin verwirrt, warum Sie von der Einrückung zur Schleifenebene springen. Sie haben ein großes Zitat über Einrückungen und plötzlich folgt eine Frage zu verschachtelten Schleifen.
Pieter B

5
Linus ist wahrscheinlich nicht (nur) ein Scherz in diesem Abschnitt, aber beachten Sie, dass dies nur ein Styleguide ist, und derselbe Styleguide betont, dass "Kernel-Codierungsstil super einfach ist", dh mehr als andere Stile.

5
@Akiva Sie können eine 4-dimensionale Matrix nicht durchlaufen, ohne 4 verschachtelte Schleifen zu haben. Ich finde es verrückt, dass jemand die Anzahl der verschachtelten Schleifen, die Sie haben können, begrenzen würde. Linus war offensichtlich sehr allgemein und Sie sollten nicht alles, was Sie lesen, als heilige Schrift ansehen.
Alternatex

9
@Alternatex Wenn Sie 4 Schleifen benötigen, müssen diese nicht lexikalisch verschachtelt sein. Aus dem Zitat geht klar hervor, dass es um die Organisation des Codes und nicht um die Ausführung geht.

4
@delnan Ich sage nicht, dass 4 verschachtelte Schleifen optisch ansprechend sind, und ich bin mir bewusst, dass es andere Möglichkeiten gibt, dies zu tun, aber ich finde es albern, wie OP Linus 'Worte so wörtlich aufnahm. 4. Einrückungsebene = Ende der Welt. Gib mir eine Pause.
Alternatex

Antworten:


19

Der Kernel bevorzugt nachdrücklich einfache Algorithmen

Während für eine Vielzahl von Algorithmen möglicherweise tief verschachtelte Schleifen in Schleifen erforderlich sind, benötigen Sie im Kontext des Linux-Kernels (in dem das Zitat verwendet wurde) im Allgemeinen schnelle Echtzeitantworten. In diesem Zusammenhang ist Deep Nesting ein Geruch, der möglicherweise darauf hinweist, dass der Codefluss für diese Domäne zu komplex ist und aufgrund seiner Ausführungseigenschaften und nicht aufgrund von Lesbarkeits- oder Einrückungsproblemen geändert werden muss.

Darüber hinaus unterscheidet sich der Linux-Kernel in Bezug auf die Überprüfbarkeit und die Tests von den meisten Anwendungscodes - und würde es daher vorziehen, keinen verschachtelten Algorithmus der Stufe 4+ in einer einzelnen Funktion zu haben. Es sollte offensichtlich sein, was jedes Codefragment genau und ausführlich tut , einschließlich aller möglichen Kontrollflüsse und Randfälle. Tief verschachtelter Code behindert das.


Glauben Sie also, dass tief verschachtelte Schleifen bei Sprachen auf niedrigerer Ebene wie C im Allgemeinen mehr Tabuprojekte sind, bei becausedenen Sprachen auf niedrigerer Ebene verwendet werden, und von einem Codierungsstil profitieren, der sich auf einfachere Algorithmen konzentriert?
Akiva

4
@Akiva Ich würde es nicht an niedrigere Sprachen oder C als solches binden, sondern an die Domäne des Codes. Ich denke, dass ähnliche Richtlinien für jede Sprache gelten, wenn Code geschrieben wird, der robust, sicherheitsorientiert und auf Kosten anderer Dinge überprüfbar sein muss . ZB sollte eine in Java oder Haskell geschriebene Verschlüsselungsbibliothek auch in einem Stil geschrieben werden, der die Dinge so einfach wie möglich hält, das Verschachteln einschränkt und versucht, alles in Blöcke aufzuteilen, die leicht mit all ihren möglichen Konsequenzen analysiert werden können.
Peteris

Ein sehr aufschlussreicher und nützlicher Kommentar / eine nützliche Antwort. Nur neugierig; Was für ein Projekt, das heute eine einfache Sprache verwendet, würde sich nicht darauf konzentrieren, robust, überprüfbar und sicher zu sein?
Akiva

7
@Akiva zum Beispiel, Code für maschinelles Lernen, bei dem Sie C möglicherweise nur aus Leistungsgründen verwenden möchten, sich aber nicht um Robustheit oder Sicherheit kümmern, da es intern unter kontrollierten Bedingungen ausgeführt wird. Darüber hinaus können einfache Geschäftsfunktionen auf kleinen eingebetteten Mikrocontrollern implementiert werden. In der Praxis werden häufig Funktionen und Entwicklungsgeschwindigkeit auf Kosten von Qualität und Sicherheit in den Mittelpunkt gestellt, es werden jedoch einfache Sprachen verwendet.
Peteris

49

Bis zu einem gewissen Grad habe ich dieses Zitat bei "Tabs are 8 characters" nicht mehr ernst genommen . Der springende Punkt bei Tabulatoren ist, dass es sich nicht um eine feste Anzahl von Zeichen handelt (wenn überhaupt, ist ein Tabulator ein Zeichen). Was für ein Haufen Scheiße. Ebenso bin ich nicht ganz davon überzeugt, dass das Festlegen einer Hard-and-Fast-Regel mit "drei Einrückungsstufen" vernünftig ist (genauso wie das Festlegen einer Hard-and-Fast-Regel für alles vernünftig ist).

Das Einschränken der Einrückung ist jedoch im Allgemeinen ein vernünftiger Vorschlag und sollte Sie nicht überraschen.

Wenn Ihr Programm drei Iterationsebenen benötigt, ist dies letztendlich das, was Ihr Programm benötigt . Der Sinn des Zitats besteht nicht darin, diese Anforderung Ihres Projekts auf magische Weise zu mildern, sondern die Logik in Funktionen und Typen zu unterteilen, damit Ihr Code schärfer und aussagekräftiger wird.

Dies speist sich nur aus derselben Richtlinie, die oben in Bezug auf Einrückungsgrade angegeben wurde. Es geht darum, wie Sie Ihren Code strukturieren und lesbar, wartbar und unterhaltsam halten, damit er über Jahre hinweg geändert werden kann.


6
Ich glaube, dass die "Erklärung", dass Tabs 8 Zeichen lang sind, speziell im Zusammenhang mit der Kernelentwicklung steht. Dieses Zitat stammt aus einer Codierungsrichtlinie für ein bestimmtes Projekt und ist nicht als allgemeine Verwendungsrichtlinie gedacht. Daher wird davon ausgegangen, dass es sich um eine überzeugende Stellungnahme handelt.
Lie Ryan

6
@LieRyan: Dann ist es immer noch tosh - eine Codierungsrichtlinie für alles hat nichts damit zu tun, wie breit ich meine Tabs einstelle! Aber ich vermute, Linus weiß das.
Leichtigkeit Rennen mit Monica

6
und natürlich ist es sprachabhängig - in c # ist es üblich, dass Sie innerhalb Ihres Namespaces, in Ihrer Klasse und in Ihrer Methode einrücken. Sie befinden sich bereits auf drei Einrückungsebenen, bevor Sie überhaupt von Kontrollflussanweisungskörpern sprechen eingerückt.
PeterL

3
@LightnessRacesinOrbit Ich interpretiere den Kommentar "Tabs are 8 characters" (Tabulatoren sind 8 Zeichen) so, dass Sie Tabulatoren in Ihrem Editor nicht als 8 breit anzeigen müssen, sondern zum Zweck anderer Regeln in der Stilrichtlinie (z. B. "Die Begrenzung der Zeilenlänge") ist 80 Spalten und dies ist eine stark bevorzugte Grenze. ") Tabulatoren müssen als 8 Spalten behandelt werden. Dies ist auch für andere Regeln bezüglich der Argumentausrichtung in Funktionsaufrufen relevant. Wiederum glaube ich nicht, dass die Absicht dieser Zeile Sie dazu zwingt, Tabs überhaupt auf diese Weise anzuzeigen. Ich habe zuvor Kernel-Patches mit 4 breiten Tabs durchgeführt und den Code am Ende neu formatiert.
Vality

4
@underscore_d: Es scheint, dass ich falsch liege: Outside of comments, documentation and except in Kconfig, spaces are never used for indentation, and the above example is deliberately broken.- 6 Absätze unter dem Zitat im OP.
Slebetman

16

Der Punkt ist derselbe wie für alle Flow-Control-Konstrukte: Wenn der Code schwer zu verstehen ist, müssen Sie ihn umgestalten. Wenn Sie eine einfache Manipulation eines mehrdimensionalen Arrays durchführen, kann es sinnvoll sein, Schleifen mit einer Tiefe von fünf oder sechs zu haben, solange die Logik in der innersten Schleife einfach ist. Wenn Sie jedoch eine komplizierte Geschäftslogik verarbeiten und der Rumpf Ihrer Schleife aus einem Dutzend Zeilen oder mehr besteht, möchten Sie wahrscheinlich nicht mehr als eine Schleife verschachteln. Sie können versuchen, die zyklomatische Komplexität des Codes zu berechnen . Entscheidend ist jedoch die Lesbarkeit und Wartbarkeit des betreffenden Codes.


11
Genau. Es ist zu einfach anzunehmen, dass Torvalds ein Idiot ist. (Er ist es natürlich.) Er ist vielleicht zu starr für Ihren Geschmack, aber er beschreibt ein echtes Entwicklungsproblem, das echte Probleme verursacht. Sie müssen nicht genau das tun, was er sagt, aber Sie sollten darüber nachdenken, warum er es sagt.
Scant Roger

7
@ScantRoger Eigentlich klingt das Torvalds-Zitat nur zu starr, wenn man seinen Sinn für Humor nicht versteht. Wie ich mich erinnere, schlägt er in demselben Dokument vor, eine Kopie der GNU-Richtlinien für Codierungsstile auszudrucken, um sie dann in einer Art Zeremonie zu verbrennen. Sie werden das kaum ernst nehmen, oder? In diesem Zitat ist es sein Hauptanliegen, die Einrückung für den Linux-Kernel auf acht Leerzeichen zu definieren, nicht mehr und nicht weniger, und genau darum geht es ihm. Der letzte Satz soll nur diesen Punkt unterstreichen, nicht aber, dass Sie keine weiteren Einrückungsstufen verwenden dürfen - keine implizite Starrheit.
cmaster

1
@cmaster Danke für den Kontext, genau richtig! Als Antwort auf Ihre Frage nehme ich kaum etwas ernst. ;)
Scant Roger

2
@cmaster und dann liest man seine Antworten auf Github-Pull-Anfragen und die Zeilenlänge von Commit-Nachrichten. Er ist total verrückt.
Gusdor,

3
Das feierliche Brennen der GNU-Codierungsrichtlinien ist zwar nicht unbedingt erforderlich, aber zu jedem Zeitpunkt völlig in Ordnung.
dmckee

13

Scherzte Linus?

Das Stück ist in einem spielerischen Stil verfasst, der darauf hindeutet, dass der Autor mit der Art und Weise vertraut ist, wie Codierungsstile unter ernsthaften Praktizierenden diskutiert werden: Wir alle haben unsere Vorlieben und verteidigen sie tollwütig, aber zumindest teilweise mit der Zunge im Gesicht. Wir verstehen sehr gut, dass vieles nur eine Frage des persönlichen Geschmacks ist. Er sagt in so vielen Worten "Coding style is very personal, and I won't _force_ my views on anybody"- zumindest außerhalb des von ihm persönlich gepflegten Codes. Die Konsistenz des Stils in einem bestimmten Projekt ist jedoch eine sehr gute Idee. Ich codiere lieber einen Stil, den ich nicht mag, als mich mit mehreren Stilen in einer bestimmten Funktion zu befassen.

Hier ist ein Beispiel für deutlich verspieltes Schreiben:

However, there is one special case, namely functions: they have the
opening brace at the beginning of the next line, thus:

int function(int x)
{
    body of function
}

Heretic people all over the world have claimed that this inconsistency
is ...  well ...  inconsistent, but all right-thinking people know that
(a) K&R are _right_ and (b) K&R are right.  Besides, functions are
special anyway (you can't nest them in C).

Verspielt (1).

Es ist wohl ein guter Rat, zu versuchen, Einrückungen zu vermeiden, die außer Kontrolle geraten, obwohl ein Maximum von drei Ebenen möglicherweise hyperbolisch ist. Ich werde nicht die Kernelquelle durchsuchen und Sequenzen von vier Tabulatoren zählen, aber ich wette, Sie könnten mindestens eine finden, die Torvalds geschrieben hat.

Wenn andererseits jemand den Linux-Kernel schreiben kann, ohne häufig drei Einrückungsstufen zu überschreiten, ist eine dreistufige Beschränkung möglicherweise eine Übung, die es sich lohnt, eine Weile in Ihrem eigenen Code auszuprobieren, nur um zu sehen, wohin es Sie führt. Das ist nicht wie eine Geschlechtsumwandlung, weißt du? Es ist keine lebenslange Verpflichtung.

Wenn Sie jemandem im Internet begegnen, der glaubt, er verstehe das Programmieren viel besser als Torvalds (2), dann wissen Sie, welche Art von Leuten im Internet gerne groß reden.

Andererseits irrt er sich kriminell, wenn es um Tabulatoren mit acht Leerzeichen geht. Das ist das Schwärmen eines Mannes, der in Fesseln gehalten und durch einen Schlitz gefüttert werden sollte. Vier Leerzeichen sind offensichtlich richtig.

(1) Beachten Sie jedoch, wie er fälschlicherweise ein Leerzeichen vor die Ellipsen und zwei Leerzeichen nach ihnen und zwei Leerzeichen nach einem Punkt setzt. FALSCH, FALSCH, FALSCH. Und dann hat er die dreiste Galle, um Ketzer zu züchtigen. Der Ketzer bist du, Torvalds! DU BIST ES!

(2) Wenn Sie darüber sprechen möchten, wie man ein Quellcodeverwaltungssystem entwirft , gibt es möglicherweise Raum für Diskussionen.

Hinweis: Sehr geehrter Mitbenutzer, der wiederholt dieselbe Bearbeitung eingereicht hat: Die Formatierung im zitierten Material wird genau so beibehalten, wie es der Autor beabsichtigt hat. Das liegt daran, dass es sich um einen Aufsatz handelt, der sich mit der Formatierung von Text mit fester Breite befasst, der in Text mit fester Breite geschrieben wurde, und von jemandem, der die Formatierung von Text mit fester Breite gründlich überlegt hat. Die Formatierung ist ein bewusster und bewusster Teil der Absicht des Autors und für das Thema relevant.

Außerdem habe ich in meinem eigenen Text auf diese Formatierung zurückgegriffen. Wenn Sie die Vorformatierung herausnehmen, wird meine Fußnote (1) Kauderwelsch. Wenn die Vorformatierung entfernt wird, sollte sich der Text in meiner Fußnote (1) auf die Leerzeichenpaare nach den vollständigen Anschlägen an den Satzenden beziehen. Ich kann ohnehin einen Grund dafür sehen, diese Fußnote zu entfernen, weil sie weniger lustig ist, als es schien, als ich sie schrieb. Das Entfernen der Formatierung ohne Entfernen der Fußnote ist jedoch nicht hilfreich.


3
Wunderbare Antwort. Einer der Fälle, die eine +2 verdienen würden ... (Hinweis: Keine falschen Leerzeichen .in diesem Kommentar ;-))
cmaster

2
Der Intro-Absatz von Linus, auf den Sie hingewiesen haben, ist sehr wichtig. Vielen Dank, dass Sie das getan haben! Ich denke, der erste Satz ist auch sehr wichtig für den Kontext, preferred coding stylegenau wiebut this is what goes for anything that I have to be able to maintain
Chris Haas

9

Linus hat einen sehr stumpfen Sprechstil und einen trockenen Sinn für Humor, aber er hat in diesem Fall keinen Scherz gemacht. Es gibt Situationen, in denen ein Algorithmus tiefer als zwei Ebenen verschachtelt werden muss. Sie können dies jedoch auch auf andere Weise als durch Einrücken des Codes erreichen. Der Linux-Kernel-Styleguide bevorzugt diese anderen Methoden aufgrund der Schwierigkeit, tief verschachtelte Schleifen beizubehalten, und genau das sagt Linus hier.

Für einige Beispiele alternativer Methoden können Sie die Rekursion verwenden, innere Schleifen in ihre eigenen Funktionen aufteilen oder dazwischen liegende Datenstrukturen erstellen.

Übermäßiges Verschachteln ist einer dieser Fälle, die einfacher zu schreiben, aber schwerer zu lesen sind. Das Einstellen einer großen Tabulatortiefe ist Linus 'Art, das Schreiben zu nerven.


3

Es gibt viele Fragen, bei denen der Rat für jemanden, der die Frage stellt, anders ist als für jemanden, der nicht fragt. Wenn Sie die Frage "Sollte ich jemals Schleifen haben, die mehr als zwei Ebenen tief verschachtelt sind" stellen, lautet die Antwort für Sie, die Person, die diese Frage stellt, NEIN. Wenn Sie fragen, dann tun Sie es nicht. Wenn Sie genug Erfahrung haben, die Sie nicht zu fragen brauchen, dann wissen Sie, was in jedem Fall die richtige Antwort ist. Und streite nicht, wenn du mit der Antwort nicht einverstanden bist, denn die Antwort ist nichts für dich.


1

Dies scheint ein Lehrbuchfall zu sein, in dem der Schwanz mit dem Hund wedelt.

Wenn Sie eine Anzeige mit 80 Zeichen haben, werden Sie natürlich versuchen, den Code so gut wie möglich anzupassen, auch wenn er nicht die beste Struktur für den Code ergibt .

Wenn Sie den Rest Ihrer Punkte in Angriff nehmen, gehen Sie folgendermaßen vor:

Ich dachte, es sei eine inakzeptable Praxis.

Ich denke, Sie lesen zu viel darüber. Widerstehen Sie dem Drang, alles, was Sie lesen, als Evangelium zu betrachten, ohne den Kontext richtig zu verstehen.

Scherzte er?

Es ist schwer, den Kontext zu bestimmen, aber siehe meinen ursprünglichen Punkt oben.

Kommt es auf die Sprache oder Anwendung an?

Besonders gern. Verwenden Sie eine beliebige Mainframe- / Midrange-Sprache, in der Sie wahrscheinlich auf einem Terminal (oder Terminalemulator) codieren.

Gibt es Dinge, die unbedingt drei oder mehr Schleifenstufen benötigen?

Ja, das ist bei einigen Brute-Force-Algorithmen sehr häufig. Siehe Aufgabe 31 zu Project Euler. Dies ist ein klassisches Beispiel für ein Problem, das mit brachialer Gewalt mithilfe einer Reihe von Schleifen gelöst werden könnte (8, um genau zu sein).


1
Es sieht so aus, als ob das Problem 31 keine Bruteforce-Methode erfordert und mithilfe eines dynamischen Programmieralgorithmus gelöst werden könnte (Bearbeiten: Dies bedeutet, dass Ihre Codestruktur nicht die beste ist, wenn Sie einen Bruteforce-Algorithmus verwenden). Linus meint auch, dass, wenn Ihr Code viele Einrückungsstufen erfordert, dies wahrscheinlich nicht die beste Struktur für den Code ist.
Vincent Savard

2
@VincentSavard Sagte nie, dass es roher Gewalt bedarf . Stimmen Sie nicht mit Ihrem zweiten Punkt überein - manchmal ist es der klarste und prägnanteste Ansatz, ganz zu schweigen von dem, der in einigen Fällen am effizientesten ist.
Robbie Dee

1
Bei solchen Problemen rücke ich die Schleifen normalerweise nicht ein. Ich glaube, ich hatte einen Fall mit 20 verschachtelten Schleifen, der absolut trivial zu schreiben war, und keine Einrückung, sodass man sehen konnte, dass die Schleifen fast identisch waren.
gnasher729

1
@RobbieDee: Mein Punkt ist, dass Ihr Algorithmus als Beispiel für ein durch viele Schleifen gelöstes Problem nicht so effizient ist wie eine dynamische Programmierlösung, für die nicht so viele Einrückungsebenen erforderlich sind. So können, wie Linus sagte, Ihre Einrückungsgrade durch Verwendung einer besseren Lösung entfernt werden. Sie haben auch meinen zweiten Punkt falsch verstanden, weil ich mit dem übereinstimme, was Sie gesagt haben. Manchmal ist es die beste Lösung. Manchmal nicht oft und wahrscheinlich auch nicht.
Vincent Savard

1
Das Linus-Zitat sagt so ziemlich explizit, dass, wenn ein Code so etwas wie das Erzwingen von Problem-31 erfordert, Sie sowieso einen Fehler machen - es wird weder schnell noch einfach sein, und Kernel-Operationen müssen schnell und einfach sein. Das Einbeziehen eines beliebigen O (n ^ 4) -Algorithmus in den Kernel birgt ein erhebliches Risiko für die Leistung oder für Denial-of-Service-Probleme. In diesem Zusammenhang warnt die Empfehlung lediglich, dass dies ein Zeichen für Code ist, der unter Linux möglicherweise grundsätzlich unangemessen und erwünscht ist.
Peteris

0

Scherzte Linus?

Nein, das sind die offiziellen Richtlinien.

Kommt es auf die Sprache oder Anwendung an?

Codierungsrichtlinien hängen im Allgemeinen von der Sprache und der Anwendung ab. Tief verschachtelter Code belastet den Leser jedoch immer .

Das Problem mit verschachteltem Code ist, dass die zyklomatische Komplexität im Allgemeinen zunimmt. Das heißt, je mehr der Code verschachtelt ist, desto mehr potenzielle Ausführungspfade gibt es in der Funktion. Eine kombinatorische Explosion potenzieller Ausführungspfade erschwert die Begründung des Codes und sollte daher generell vermieden werden.

Warum also 3? Eine subjektive Kodierungsrichtlinie ist sowohl schwer durchzusetzen als auch unmöglich automatisch durchzusetzen. Um eine objektive Kodierungsrichtlinie für die maximale Einrückung zu erstellen, muss eine Zahl festgelegt werden: Im Linux-Kernel wurde 3 ausgewählt.

Es ist willkürlich und anscheinend ausreichend für sie.

Gibt es Dinge, die unbedingt drei oder mehr Schleifenstufen benötigen?

Algorithmisch gesehen können Sie den Code jedoch in ausreichend aussagekräftigen Sprachen immer wieder in kleinere Teile zerlegen (ob mit Funktionen oder Closures).

Sie können offensichtlich verschachtelten Code mit wenig Verschachtelung und vielen kleinen Funktionen schreiben, die sich gegenseitig aufrufen, ohne jemals ihren Vertrag zu buchstabieren ...

... jedoch sind kleine Funktionen mit klaren Verträgen viel einfacher zu prüfen als große Funktionen mit klaren Verträgen im Allgemeinen.


2
Obwohl dies die offizielle Richtlinie sein mag, ist es trivial, Stellen im Kernel-Code zu finden, an denen die Richtlinie nicht durchgesetzt wird.
MikeB

1
@ MikeB: Umso mehr Gründe, Richtlinien automatisch durchzusetzen ...
Matthieu M.

1
@MatthieuM. Sind Sie sicher, dass Sie den Unterschied zwischen Richtlinien und verbindlichen Anforderungen verstehen? Als allgemeine "Faustregel" (eine Richtlinie, wenn Sie möchten) sind Richtlinien eher Empfehlungen und werden nicht durchgesetzt.
Brendan
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.