IMS-Datenbankabhängigkeitsanalyse

IMS-Datenbankabhängigkeitsanalyse: Was Modernisierungsteams vor der Migration wissen müssen

IMS ist kein veraltetes System im eigentlichen Sinne. Es ist die Datenbank-Engine hinter der Debitorenbuchhaltung großer Banken, der Policenverwaltung von Versicherungen und der Leistungsabrechnung von Krankenkassen. IBM entwickelt es kontinuierlich weiter. Das Problem ist nicht, dass IMS nicht mehr funktioniert, sondern dass alle Entwickler, die sich mit den hierarchischen Segmentstrukturen auskennen, in Rente gehen. Jede Änderung an einem IMS-basierten System erfordert das Verständnis eines Datenmodells ohne SQL, und jeder Migrationsplan, der IMS wie eine relationale Datenbank behandelt, macht die Unterschiede auf die harte Tour zu spüren.

Die schmerzhafte Erfahrung ist, mitten in der Migration festzustellen, dass ein COBOL-Programm nicht über eine einfache Schlüsselsuche, sondern über eine hierarchische Traversierung auf IMS zugreift, die im Zielsystem mit äquivalenter Navigationslogik repliziert werden muss. Oder die Entdeckung, dass eine logische Beziehung zwischen zwei physischen IMS-Datenbanken eine Abhängigkeit erzeugt, die in keiner der Datenbankbeschreibungen vollständig dokumentiert ist, und dass die Migration beide Datenbanken unabhängig voneinander konvertiert hat, während dabei stillschweigend alle Programme, die diese logische Beziehung nutzten, beeinträchtigt wurden. Oder die Entdeckung, dass eine sekundäre Indexdatenbank – eine Struktur, die in den meisten Migrationsplänen nicht berücksichtigt wird – der einzige Weg war, über den ein kritisches Berichtsprogramm auf seine Daten zugreifen konnte.

Keine dieser Überraschungen übersteht eine strenge Abhängigkeitsanalyse vor der Migration. Sie überstehen jedoch die Prüfung von Annahmen.

IMS-Abhängigkeitsanalyse auf Portfolioebene

SMART TS XL Identifiziert datenbankübergreifende IMS-Abhängigkeiten, die im COBOL-Quellcode allein nicht sichtbar sind.

Mehr Infos

Was unterscheidet die IMS-Abhängigkeitsanalyse?

Die Abhängigkeitsanalyse für relationale Datenbankumgebungen wie DB2, Oracle und SQL Server folgt einem etablierten Verfahren. Dabei wird der SQL-Code im Anwendungscode analysiert, Tabellen- und Spaltenreferenzen werden identifiziert, eine Zuordnung der Programme zu den jeweiligen Tabellen erstellt und anhand dieser Zuordnung Umfang und Reihenfolge der Migration bestimmt. Die Struktur ist explizit; die Abhängigkeiten sind im SQL-Text sichtbar.

Die IMS-Abhängigkeitsanalyse ist in jeder Hinsicht komplexer.

Die Struktur ist hierarchisch, nicht relational. Eine IMS-Datenbank ist als Baumstruktur von Segmenttypen organisiert, wobei jeder Segmenttyp eine definierte Eltern-Kind-Beziehung aufweist. Ein COBOL-Programm, das Patientendatensätze aus einer IMS-Datenbank liest, führt nicht aus SELECT * FROM PATIENTS WHERE ID = ?Es verwendet einen Get Unique-Aufruf (GU), um die Hierarchie bis zum Wurzelsegment zu durchlaufen, und anschließend Get Next Within Parent-Aufrufe (GNP), um die untergeordneten Elemente zu durchlaufen. Die Abhängigkeit des Programms besteht nicht in einer Tabelle, sondern in einem bestimmten Pfad durch eine hierarchische Struktur. Änderungen an dieser Struktur können Programme, die sie durchlaufen, auf eine Weise beeinträchtigen, die durch eine SQL-Analyse nicht erkennbar ist.

Die Abhängigkeiten sind auf drei separate Strukturen verteilt. Um vollständig zu verstehen, was ein COBOL-Programm mit IMS macht, ist eine Analyse erforderlich:

  • Der DBD (Datenbankdeskriptor): Definiert die physische Segmenthierarchie, die Schlüsselfelder, die Zugriffsmethoden (HDAM, HIDAM, HISAM, HSAM) und alle sekundären Indizes oder logischen Beziehungen.
  • Der PSB (Programmspezifikationsblock): definiert, auf welche Datenbanken ein Programm über welche PCBs zugreifen darf und mit welchen Sensibilitäts- und Absichtsspezifikationen.
  • Der COBOL-Quellcode: enthält die eigentlichen DL/I-Aufrufe, die festlegen, auf welche Segmente mit welchen Aufruffunktionen in welcher Reihenfolge und mit welchen SSAs zugegriffen wird.

Keine einzelne Quelle liefert das vollständige Bild. Eine Analyse, die nur den COBOL-Quelltext liest, erfasst zwar die Aufruftypen und Segmentnamen, aber nicht die physische Datenbankstruktur. Eine Analyse, die nur die Datenbankdokumentation (DBD) und die Programmstrukturbeschreibung (PSB) liest, zeigt, was das Programm tun darf, aber nicht, was es tatsächlich tut.

Die Navigation ist positionsabhängig. In einer relationalen Datenbank ist jede Zeile unabhängig über ihren Schlüssel adressierbar. In IMS beeinflusst die aktuelle Position eines Programms in der Hierarchie, was nachfolgende Aufrufe zurückgeben. Ein GN-Aufruf (Get Next) gibt das nächste Segment in hierarchischer Reihenfolge ab der aktuellen Position des Programms zurück. Die Abhängigkeit besteht nicht nur vom Segmenttyp, sondern auch vom Pfad, der zur aktuellen Position geführt hat. Programme, die auf der impliziten hierarchischen Ordnung von IMS basieren, weisen eine Abhängigkeit auf, die verschwindet, wenn die Daten in eine relationale Datenbank migriert werden, in der keine äquivalente Ordnung garantiert ist.

Das DL/I-Aufrufinventar: Was der COBOL-Quellcode offenbart

Die aussagekräftigste Voranalyse vor der Migration ist eine vollständige Bestandsaufnahme aller DL/I-Aufrufe in jedem COBOL-Programm, das auf IMS zugreift. Diese Bestandsaufnahme zeigt dem Migrationsteam, was jedes Programm mit IMS macht – nicht, was es tun darf (was im PSB definiert ist), sondern was es tatsächlich tut.

DL/I-Aufrufe in COBOL treten in zwei Formen auf:

Cobol

* Form 1: EXEC DLI interface (CICS-compatible, high-level syntax)
       EXEC DLI
           GU DB2PCB
           SEGMENT(CUSTROOT)
           WHERE(CUSTID = WS-CUST-ID)
       END-EXEC

* Form 2: xxxTDLI call interface (batch programs, assembler-compatible)
       CALL 'CBLTDLI' USING WS-FUNCTION-CODE
                            PCB-CUSTOMER
                            WS-CUSTOMER-SEGMENT
                            WS-SSA-CUSTOMER

Beide Formen enthalten dieselben analytischen Informationen: den Funktionscode, die verwendete PCB, das Zielsegment und optional das SSA (Segment Search Argument), das den Aufruf qualifiziert. Eine vollständige DL/I-Aufrufinventur extrahiert all diese Informationen aus jedem Programm.

Die Funktionscode-Taxonomie und ihre Auswirkungen auf die Migration

Der DL/I-Funktionscode ist das migrationsrelevanteste Element jedes Aufrufs. Jeder Funktionscode impliziert ein anderes Datenzugriffsmuster, das in der Zieldatenbank repliziert werden muss:

Nur-Lese-Funktionen: GUGet Unique: Navigieren Sie direkt zu einem Segment mithilfe qualifizierter SSAs. Entspricht einer SELECT-Anweisung mit WHERE-Klausel in relationalen Datenbanken. Die Migration ist unkompliziert, wenn der Segmentschlüssel einem relationalen Primärschlüssel eindeutig zugeordnet ist.

GN„Get Next“: Gehe zum nächsten Segment in der hierarchischen Reihenfolge. Dieser Funktionscode hat kein direktes relationales Äquivalent; er basiert auf dem Positionszustand und der impliziten Ordnung von IMS. Programme, die GN intensiv nutzen, erfordern eine sorgfältige Analyse der zugrunde liegenden Ordnung.

GNP„Nächstes Element innerhalb des übergeordneten Elements abrufen“: Ruft die nachfolgenden Kindelemente des aktuellen übergeordneten Segments ab. Entspricht dem Abrufen aller Zeilen in einer Fremdschlüsselbeziehung. Lässt sich im Allgemeinen problemlos einer SELECT-Anweisung mit einer WHERE-Klausel für Fremdschlüssel zuordnen.

Haltefunktionen (Voraussetzungen für das Update): GHU, GHN, GHNPDie Hold-Funktion entspricht den Befehlen GU, GN und GNP. Das „Hold“-Flag signalisiert, dass im Anschluss eine Aktualisierungs- (REPL) oder Löschoperation (DLET) erfolgt. Programme, die Hold-Aufrufe verwenden, sind Lese-Änderungs-Schreib-Programme; die Migration muss die Transaktionsintegrität während des Hold-Vorgangs und der nachfolgenden Aktualisierung gewährleisten.

Aktualisierungsfunktionen: ISRT, Einfügen: Fügt ein neues Segmentvorkommen hinzu. Entspricht INSERT. DLETLöschen: Entfernt das aktuell gehaltene Segment und alle seine Abhängigkeiten. Das Verhalten „alle Abhängigkeiten“ ist eine IMS-spezifische Kaskade, die im Zielsystem explizit implementiert werden muss. REPL, Ersetzen: Aktualisiert das aktuell gespeicherte Segment mit neuen Daten. Entspricht UPDATE.

Warum dies für den Migrationsumfang relevant ist: Ein Programm, das ausschließlich GU- und GNP-Aufrufe verwendet, greift nur lesend auf IMS-Daten zu, birgt ein geringeres Migrationsrisiko und ist einfacher zu validieren. Ein Programm, das GHU, REPL und DLET verwendet, ist ein Transaktionsverarbeitungsprogramm, das hierarchische Strukturen modifiziert; seine Migration erfordert die Wahrung der Transaktionsintegrität über alle Operationen hinweg, die IMS derzeit atomar sicherstellt.

Die drei Abhängigkeitstypen, die jede Migration zum Scheitern bringen

Logische Beziehungen

Logische Beziehungen in IMS verbinden Segmente über zwei physisch getrennte Datenbanken hinweg. Ein logisches Kindsegment in Datenbank A hat ein logisches Elternsegment in Datenbank B. Wenn ein COBOL-Programm durch eine logische Beziehung navigiert, durchläuft es einen Pfad, der physisch Datenbankgrenzen überschreitet. Diese Traversierung wird von IMS transparent verwaltet, geht aber verloren, wenn die Datenbanken unabhängig voneinander migriert werden.

Logische Beziehungen stellen bei der IMS-Migration aus einem einfachen Grund die risikoreichste Abhängigkeitsart dar: Sie sind im COBOL-Quellcode nicht sichtbar. Das COBOL-Programm ruft GNP auf, um die untergeordneten Elemente eines Segments zu ermitteln. Ob GNP dabei eine physische oder eine logische Eltern-Kind-Beziehung durchläuft, wird durch PSB und DBD bestimmt, nicht durch den COBOL-Code. Ein Migrationsteam, das nur den COBOL-Quellcode analysiert, kann ohne separate Analyse von PSB und DBD nicht feststellen, ob ein GNP-Aufruf eine logische Beziehungsgrenze überschreitet.

Programme, die logische Beziehungen verwenden, benötigen die Migration, um die Semantik der logischen Beziehung im Zielsystem zu replizieren, typischerweise einen JOIN im relationalen Modell, und um zu validieren, dass jedes Programm, das die Beziehung verwendet, vom JOIN die gleichen Ergebnisse erhält wie von der logischen Traversierung des IMS.

Sekundärindexdatenbanken

Sekundärindexdatenbanken von IMS bieten einen alternativen Zugriffspfad zu einer Primärdatenbank und ermöglichen es Programmen, Segmente anhand eines anderen Felds als des Stammschlüssels abzurufen. Eine Sekundärindexdatenbank ist eine separate IMS-Datenbank mit eigener Datenbankstruktur (DBD), deren Daten jedoch aus der Primärdatenbank stammen.

Migrationsteams entdecken sekundäre Indexdatenbanken häufig eher während der Analyse als während der Planung, weil:

  • Sie sind in DBDs definiert, die nicht immer mit den primären Datenbank-DBDs gruppiert sind.
  • Programme, die Sekundärindizes verwenden, benennen die Indexdatenbank in ihren PSBs, aber Programme, die über einen Sekundärindex zur Primärdatenbank navigieren, machen dies im COBOL-Quellcode möglicherweise nicht deutlich.
  • Die Dokumentation beschreibt möglicherweise die primäre Datenbank, ohne deren sekundäre Indizes zu erwähnen.

Ein Programm, das über einen Sekundärindex auf IMS zugreift, weist eine Zugriffsmusterabhängigkeit auf, die im Zielsystem als Nicht-Primärschlüsselindex oder durch eine andere Abfragestrategie repliziert werden muss. Wird dies bei der Migration vernachlässigt, läuft das Programm zwar fehlerfrei, findet aber die gesuchten Datensätze nicht.

GSAM-Datenbanken

GSAM-Datenbanken (Generalized Sequential Access Method) sind die Schnittstelle von IMS für die sequentielle Stapelverarbeitung und ermöglichen es COBOL-Stapelprogrammen, DL/I-Aufrufe für funktional sequentielle Datei-E/A zu verwenden. GSAM-Datenbanken verfügen nicht über Segmenthierarchien; es handelt sich um flache sequentielle Strukturen, auf die über IMS zugegriffen wird, um von den Wiederherstellungs- und Neustartfunktionen von IMS zu profitieren.

Programme, die GSAM-Datenbanken verwenden, sind Batch-Programme, deren Wiederherstellungsverhalten von der Checkpoint-/Restart-Unterstützung von IMS abhängt. Bei der Migration muss dieses Wiederherstellungsverhalten beibehalten oder durch einen gleichwertigen Mechanismus auf der Zielplattform ersetzt werden.

Erstellung des Abhängigkeitsinventars vor der Migration

Eine vollständige IMS-Abhängigkeitsanalyse liefert sechs Ergebnisse, die zusammen den Umfang, das Risiko und die Reihenfolge der Migration definieren.

Liefergegenstand 1: Leiterplatten-zu-Datenbank-Zuordnung

Jede PCB in jedem PSB ist einer bestimmten DBD (einer spezifischen IMS-Datenbank) zugeordnet. Die Auflistung aller PCBs in allen PSBs und die Zuordnung jeder PCB zu ihrer jeweiligen DBD ergibt die maßgebliche Liste, welche Programme auf welche Datenbanken zugreifen dürfen. Dies ist der Ausgangspunkt für das Verständnis des Umfangs, überschätzt jedoch die tatsächlichen Abhängigkeiten, da Programme PSBs mit mehr Datenbanken enthalten können, als sie tatsächlich nutzen.

Ergebnis 2: Tatsächlicher Anrufbestand pro Programm

Die Analyse der DL/I-Aufrufe jedes COBOL-Programms liefert die tatsächliche Nutzungsliste: welche PCBs jedes Programm aufruft, welche Funktionscodes es verwendet, auf welche Segmenttypen es zugreift und ob es qualifizierte SSAs (Segment Key Access) oder unqualifizierte Navigation (Positionsnavigation) nutzt. Dadurch wird der Fokus von den PSB-definierten Berechtigungen auf das tatsächliche Programmverhalten verlagert.

Ergebnis 3: Nutzungsdiagramm für logische Beziehungen

Durch den Abgleich des Aufrufinventars mit den DBDs lässt sich feststellen, welche GNP- oder GN-Aufrufe von Programmen logische Beziehungen durchlaufen. Dies erfordert die Analyse nicht nur des COBOL-Quellcodes und des PSB, sondern auch der DBD-Strukturen, die definieren, welche Eltern-Kind-Beziehungen physisch und welche logisch sind.

Ergebnis 4: Nutzungsübersicht des Sekundärindex

Programme, die in ihren PSBs sekundäre Indexdatenbanken angeben oder Aufrufe mit SSAs durchführen, die auf Nicht-Root-Schlüsselfelder verweisen, werden als sekundäre Indexnutzer identifiziert. Die Übersicht dokumentiert, welche sekundären Indizes existieren, welche primären Datenbanken sie unterstützen und welche Programme von ihnen abhängen.

Ergebnis 5: Anruftypenverteilung pro Datenbank

Für jede im Geltungsbereich stehende IMS-Datenbank gibt die Verteilung der Aufruftypen über alle Programme, die darauf zugreifen, Aufschluss über die Komplexität ihrer Migration:

  • Datenbanken, auf die nur über Lesefunktionen (GU, GN, GNP) zugegriffen wird, sind einfacher zu migrieren.
  • Datenbanken, auf die durch Haltefunktionen und Aktualisierungen zugegriffen wird (GHU + REPL, GHN + DLET), erfordern eine Replikation der Transaktionsintegrität.
  • Datenbanken mit hoher GN-Nutzung weisen auf Abhängigkeiten in der Positionsnavigation hin, die eine Ordnungsanalyse erfordern.
  • Datenbanken mit logischen Beziehungen erfordern datenbankübergreifende JOIN-Semantik im Zielsystem.

Ergebnis 6: Risikoklassifizierung des Programms

Anhand der Aufruftypverteilung und des Abhängigkeitstypinventars wird jedes Programm nach seinem Migrationsrisiko klassifiziert:

Programme, die ausschließlich GU und GNP mit qualifizierten SSAs nutzen, auf eine einzige Datenbank ohne logische Beziehungen zugreifen und keine Hold/Update-Aufrufe durchführen, stellen die risikoärmsten Kandidaten für frühe Migrationswellen dar. Programme, die GN umfassend nutzen, über logische Beziehungen auf mehrere Datenbanken zugreifen oder komplexe Hold/Update-Sequenzen durchführen, bergen das höchste Risiko und erfordern vor der Migration eine besonders gründliche Analyse und Validierung.

Was die Analyse an der Migrationsplanung ändert

Die Abhängigkeitsanalyse dokumentiert nicht nur den Ist-Zustand, sondern verändert auch die darauf folgenden Entscheidungen.

Reihenfolgeentscheidungen. Programme, die über logische Beziehungen auf IMS-Datenbanken zugreifen, können nicht unabhängig voneinander migriert werden. Liest Programm A ein logisches Kindsegment, dessen logisches Elternsegment sich in derselben Datenbank wie das Stammsegment von Programm B befindet, führt die Migration von A ohne gleichzeitige Migration von B (oder ohne Erstellung einer Brücke) zu einem Fehler in A. Der Abhängigkeitsgraph bestimmt, welche Programme gemeinsam migriert werden müssen.

Zieldesignentscheidungen. Die Verteilung der Aufruftypen bestimmt die Struktur des relationalen Zielschemas. Eine hierarchische Eltern-Kind-Beziehung, auf die ausschließlich über schlüsselqualifizierte GU- und GNP-Aufrufe zugegriffen wird, lässt sich problemlos in eine Fremdschlüsselbeziehung im Zielsystem abbilden. Dieselbe Beziehung, auf die über GN-Aufrufe mit Positionsabhängigkeiten zugegriffen wird, erfordert, dass das Zielschema die äquivalente Reihenfolge beibehält, entweder durch explizites ORDER BY, ein Sequenzfeld oder ein anderes Zugriffsmuster, das dasselbe Ergebnis erzielt.

Festlegung des Validierungsumfangs. Die Analyse identifiziert Programme, die IMS-Daten nur lesend verarbeiten und solche, die Transaktionen verarbeiten. Leseprogramme lassen sich validieren, indem die Ausgaberesultate des ursprünglichen IMS-Systems mit denen des migrierten Systems verglichen werden. Für Transaktionsverarbeitungsprogramme ist ein Test auf Transaktionsäquivalenz erforderlich, der sicherstellt, dass dieselbe Operationsfolge im Zielsystem äquivalente Datenzustandsänderungen wie im Originalsystem erzeugt.

Risikoklassifizierung. Die logischen Beziehungen und die Ergebnisse der Sekundärindexanalyse bilden die Grundlage für die Risikoklassifizierung. Jedes Migrationsprogramm verfügt über ein Risikoregister. Die IMS-Abhängigkeitsanalyse zeigt dem Team, welche Einträge darin vorgenommen werden müssen.

Wie SMART TS XL Führt eine IMS-Abhängigkeitsanalyse durch

SMART TS XL statische Code-Analyse Das Tool analysiert die DL/I-Aufrufe jedes COBOL-Programms, sowohl die EXEC DLI- als auch die xxxTDLI-Aufrufschnittstellen, und extrahiert aus jedem Aufruf den Funktionscode, die Leiterplattenreferenz, den Segmentnamen und die SSA-Struktur. Dadurch wird das tatsächliche Aufrufinventar auf Programmebene für das gesamte COBOL-Portfolio erstellt, ohne dass ein laufendes IMS-System oder eine manuelle Codeüberprüfung erforderlich ist.

Die Abbildung von Anwendungsabhängigkeiten erweitert diese Bestandsaufnahme zu einem programmübergreifenden Abhängigkeitsgraphen: Welche Programme greifen auf welche IMS-Datenbanken zu? Welche Programme verwenden dieselben PCBs? Welche Programme weisen Zugriffsüberschneidungen auf, die eine koordinierte Migration erfordern? Wenn eine logische Beziehung Segmente über Datenbanken hinweg verbindet, stellt die Abhängigkeitsabbildung diese datenbankübergreifende Verbindung als explizite Beziehung dar, die im Zielsystem erhalten bleiben muss.

Die Auswirkungsanalyse beantwortet die Frage, die jedes Migrationsteam vor der Konvertierung einer Datenbank klären muss: Welche Programme sind von der Migration dieser IMS-Datenbank betroffen? Welche Zugriffsmuster müssen repliziert werden? Welche Testfälle müssen validiert werden, um die Äquivalenz zu bestätigen? Die Antwort ist keine Schätzung, sondern eine detaillierte Liste, die aus dem tatsächlichen DL/I-Aufrufinventar abgeleitet wird.

Die JCL-Erweiterungsfunktion fügt den operativen Kontext hinzu: Welche JCL-Jobschritte rufen welche Programme auf, die auf IMS zugreifen, in welcher Reihenfolge und mit welchen PSB-Spezifikationen? Die operative Abhängigkeitskette, also die Batch-Jobsequenz, die IMS-Daten über mehrere Programme verarbeitet, ist für die Migrationsplanung ebenso wichtig wie die Zugriffsmuster auf Programmebene. Wird die Datenbank migriert, ohne die zugehörige Batch-Job-Orchestrierung zu migrieren, verarbeitet das System Datensätze zwar isoliert korrekt, versagt aber im Produktivbetrieb, sobald die Jobsequenz ausgeführt wird.

Für Teams, die durchführen Modernisierung des Altbestands von IMS-gestützten Systemen, die strukturellen Beweise, die von SMART TS XL ist die Grundlage jeder nachfolgenden Migrationsentscheidung: Welche Programme werden in welcher Welle migriert, welche Datenbanken können unabhängig voneinander konvertiert werden und welche erfordern eine koordinierte Konvertierung, welche Zugriffsmuster erfordern eine Re-Architektur anstelle einer direkten Übersetzung. Wie im Kontext von beschrieben Migration von IMS- und VSAM-Strukturen zusammen mit COBOL-ProgrammenDie Verknüpfung zwischen COBOL-Programmen und bestehenden Datenstrukturen erfordert, dass Datenmigration und Codeanalyse parallel erfolgen. Das Abhängigkeitsinventar ist der Mechanismus, der eine parallele Planung ermöglicht.

Die Bestandsaufnahme ist nicht die Migration

Die IMS-Abhängigkeitsanalyse generiert Erkenntnisse. Die Migration erfordert weiterhin Entscheidungen, technische Planung und Validierung. Die Analyse verbessert jedoch die Qualität der Entscheidungen, die Vollständigkeit des Planungsumfangs und die Zuverlässigkeit der Validierung.

Die Organisationen, die IMS-Datenbanken erfolgreich migrieren, sind nicht diejenigen mit den ambitioniertesten Zeitplänen oder den größten Migrationsbudgets. Sie sind diejenigen, die vor Beginn der Migration genau wussten, was sie hatten: jedes Programm, das auf die jeweilige Datenbank zugreift, jeden Funktionscode, der das Zugriffsmuster jedes Programms offenbart, jede logische Beziehung, die datenbankübergreifende Abhängigkeiten erzeugt, und jeden Sekundärindex, der einen Zugriffspfad bereitstellt, der ohne explizite Replikation bei der Konvertierung nicht erhalten geblieben wäre.

Dieses Wissen stammt nicht aus der Dokumentation, sondern aus der Analyse des Codes.