Projektverwaltung Best Practice

Am Anfang steht die Idee, dann kommt der Inhalt. Das ist die Geburt eines Webprojekts. Eine sorgfältige Planung des Projekts erleichtert dessen Umsetzung ungemein, diese Planung setzt ein ab dem Zeitpunkt, an dem die Inhalte feststehen. So wie es bei einem Roman Kapitel gibt, wird es bei einem Webprojekt Ordner oder auch Verzeichnisse geben.

Bereits in der Projektplanung und -Verwaltung erfolgt die Zuordnung der Inhalte zu bestimmten Seiten, die später eine URL bekommen. Jede Seite, die mit einer URL eindeutig identifiziert ist, wird schon in der Planung einem bestimmten Ordner zugewiesen. Je detaillierter jede URL und jeder Ordner beschrieben ist, desto skalierbarer ist letztendlich die Umsetzung des Projekts nach Webinhalten verschiedener Content-Typen.

Es ist nicht entscheidend, in welcher Form die Planung erfolgt, das kann auf dem Papier sein oder in elektronischer Form. Letztere bietet jedoch die Möglichkeit einer Automatisierung der Umsetzung des Projekts aus der Verwaltung heraus.

Was zu einer jeden URL geplant und verwaltet werden sollte:

Diese Aufzählung erhebt keinen Anspruch auf Vollständigkeit, andererseits sind manche "Eigenschaften" wie Autor optional. Genausogut kann der Content-Type entfallen, sofern die Site aus Inhalten einunddesselben Types besteht (z.B. Content-Type: text/html).

	Uns überfüllts, wir ordnen.
	Es zerfällt.
	Wir ordnen wieder und zerfallen selbst.
	
		Rainer Maria Rilke

Üblicherweise und auch aus Gewohnheit werden Dateien, die für das Web bestimmt sind in einer Verzeichnisstruktur auf der Festplatte abgelegt. Beispiele ausgehend von der sogenannten Webroot:

Aber haben Sie sich schoneinmal überlegt, was das eigentlich bringt!? Außer dass Sie ein bischen mehr Ordnung auf der lokalen Festplatte haben, nützt Ihnen eine solche Verzeichnisstruktur für das Web doch herzlich wenig. Ganz im Gegenteil: Sie brauchen, je nach Konfiguration des Webservers neben den einzelnen HTML-Dateien in einem Verzeichnis zusätzlich noch die Datei "index.html".

Ein weiterer Nachteil ergibt sich außerdem: Wenn eine Datei in ein anderes Verzeichnis verschoben wird, ändert sich die URL. Das könnte Ihre Stammgäste verärgern.

Ein weiteres Verzeichnis ist, je nach Webserverkonfiguration und eingekaufter Leistung das Verzeichnis /cgi-bin/. In diesem Verzeichnis liegen ausführbare Dateien, die CGI-Scripts. In der Regel ist seitens des Providers auch vorgegeben, dass diese Dateien grundsätzllich nur in diesem Verzeichnis abgelegt sind.

Sofern gewünscht ist, dass auch CGI-Scripts in einer hierarchischen Ordnerstruktur eingeordnet sein sollen, kommen Sie nicht umhin, virtuelle Ordnerstrukturen zu erzeugen. Somit kommen Sie zu dem Punkt, genau das auch für reguläre (HTML-)Dateien zu tun.

Ein virtueller Ordner im Sinne dieses Artikels ist praktisch eine HTML-Datei, in welcher die Links zu allen anderen HTML-Dateien sowie CGI-Scripts, die diesem Ordner zugeordnet wurden, aufgelistet sind.

Die Vorteile von virtuellen Ordnern

-liegen klar auf der Hand: Speicherort von Dateien und Ordnerhierarchie sind strikt voneinander getrennt. Sofern eine Datei einem anderen virtuellen Ordner zugeordnet wird, bleibt der URL der Datei erhalten. Die Ordnerhierarchie lässt sich unabhängig vom Dateisystem frei gestalten und auch die CGI-Scripts können in diese Hierarchie eingeordnet werden.

Aus der Trennung der virtuellen Ordnerstruktur vom Dateisystem ergibt sich ein weiterer Vorteil für die Verwaltung: Zu jeder Datei lassen sich weitere Angaben, wie z.B. der Titel und eine kurze Beschreibung notieren. Damit kann die virtuelle Ordnerstruktur, der Webtree dynamisch und auch statisch erzeugt werden, in dieser Übersicht findet der Besucher zu jedem Link einen aussagekräftigen Titel und eine Beschreibung.

Der Besucher sieht eine klar definierte (virtuelle) Verzeichnisstruktur innerhalb derer er sich bewegen kann.

Nachteile von virtuellen Ordnern

Sofern alle Dateien in einem Verzeichnis abgelegt sind, könnte das, je nach Anzahl dieser relativ schnell unübersichtlich werden. Das lässt sich jedoch dadurch vermeiden, dass den Dateien aussagekräftige Namen gegeben werden und auch den weiteren Ressourcen, welche in diesem Dateien eingebunden sind (Images). Außerdem besteht die Möglichkeit, die Images in einem, zur HTML-Datei gehörigen extra Verzeichnis abzulegen.

Praktische Realisierung

Es stellt sich nun die Frage, in welcher Form und an welchem Ort die virtuelle Ordnerstruktur abgelegt ist. Das kann eine Textdatei sein oder eine Tabelle in einer Datenbank. Bewährt hat sich in meiner Praxis eine Textdatei im Format einer ini-Datei, eine Solche ist wie folgt aufgebaut (linkbase.ini):

[Intern.Artikel.Perl]
	link1=/mail.html
	title1=Mit Perl Mails senden und empfangen
	descr1=Empfangen Sie Mails, die einfach nur durchnumeriert sind...

[Intern.Artikel.Webmaster]
	link1=/webtree.html
	title1=Verzeichnisstruktur und virtuelle Ordner im Webverzeichnis-Baum
	descr1=Die Abbildung des Web-Tree auf Dateiebene in einer Verzeichnisstruktur...

[Intern.Webtools]
	link1=/cgi-bin/netcalc.cgi
	title1=Komfortabler Subnetz-Kalkulator
	descr1=Teilen Sie ein Basisnetz in mehrere Subnetze...
	
	link2=...

Diese Datei lässt sich mit Perl und dem Modul Config::IniFiles sehr gut parsen und damit die virtuelle Ordnerstruktur erzeugen. Gegenüber einer Datenbank hat eine Textdatei neben der einfachen Bearbeitung mit einem Texteditor auch den Vorteil der besseren Verfügbarkeit: Im Falle eines Ausfalls der Datenbank ist die Navigation trotzdem gewährleistet.

Für die Verwaltung des Webs ergeben sich weitere Vereinfachungen, z.B. sind zum Hinzufügen eines neuen CGI-Scripts lediglich diese zwei Schritte notwendig:

Im Fall einer HTML-Datei wird ganz ähnlich verfahren:

Zu schreiben sind also lediglich die Bodies der HTML-Dateien, etwaige CGI-Scripts und die Datei linkbase.ini. Was bleibt und mit einem lokalen Perl-Script automatisiert wird, ist das Erstellen der Dateien für die virtuellen Ordner, die Erzeugung des Verzeichnisbaums in diesen Dateien, sowie der Einbau der Navigation. Letztere ist ein Menu als Liste und wird mit einer Funktion, die in einem zentralen Modul definiert ist, in einer jeden Datei erzeugt.

Für das Navigationsmenu hat sich die Methode nach BreadCrumbs (Brotkrümel zum Zurückfinden, dem Märchen 'Hänsel und Gretel' entlehnt) bewährt, so handhabe ich das auch hier und das funktioniert so, dass dies mit der Tiefe der Hierarchie nach rechts verlängert wird. Der Startordner für diese Navigation ist der Hauptindex mit dem Gesamnten Verzeichnisbaum, physisch die Datei map.html als Link mit dem Titel Hauptindex.

Einmal angenommen, der Besucher hat auf dem Menupunkt Hauptindex geklickt, ist der Platz rechts neben dem Punkt Hauptindex leer. Klickt der Besucher auf den Ordner Intern im Hauptindex, wird das Navigationsmenu um diesen Ordnernamen verlängert:

Hauptindex Intern

Ein weiteres "Vordringen" in die Tiefe der Hierarchie sieht dann so aus:

Gewählte Datei map.html
Hauptindex

Gewählte Datei Intern.html
Hauptindex Intern

Gewählte Datei Intern.Artikel.html
Hauptindex Intern Artikel

Gewählte Datei Intern.Artikel.Webmaster.html
Hauptindex Intern Artikel Webmaster

usw.

Der Zusammenhang zwischen den einzelnen Sektionen der oben beschriebenen Datei linkbase.ini ist somit verständlich. Eine kleine Anmerkung zum Menu auf dieser Seite:

Startseite Impressum Aktuelles Gästebuch Suche Hauptindex Intern Artikel Webmaster
|---------------  menu.ini ------------------|  map.html  |--- linkbase.ini -----|                                                                    

Zur Funktion der Steuerdatei menu.ini nur soviel, als dass damit ein sog. Grundmenu erstellt wird mit Links zu den wichtigsten Seiten, wobei dieses Menu auf jeder Seite zur Verfügung steht. Die BreadCrumbs werden aus der Datei linkbase.ini heraus erzeugt, wobei:

Befindet sich der Besucher im Ordner Webmaster ist dieser Ordner als Link ausgeblendet. Ruft der Besucher hingegen ein Dokument aus dem Ordner Webmaster ab, gibt es auch den Link zum Ordner. Dieses Verhalten wird über die CGI-Umgebungs-Variable REQUEST_URI gesteuert in der Funktion, welche die BreadCrumbs erzeugt.

Erstellen der HTML-Dateien lokal

Da, wie bisher gezeigt, die Titel der HTML-Dateien getrennt von diesen verwaltet werden, lässt sich die Erzeugung dieser weitestgehend automatisieren, dahingehend, dass lediglich der body geschrieben werden muss. Die fertige HTML-Datei wird mit einem lokalen Perl-Script erzeugt, womit folgendes gegeben ist:

Punkt 3 (Skalierbarkeit) meint, dass es sehr einfach ist, an allen Dateien Änderungen gleichermaßen vornehmen zu können, z.B. einen Seitenaufrufzähler einzubauen oder den Stil bestimmter Abschnitte anzupassen.

Dem Perl-Script, was alle HTMl-Dateien lokal erstellt, steht Folgendes zur Verfügung:

Nach dem Durchlaufen dieses Scripts liegen alle HTML-Dateien komplett mit Header, Footer und Navigationsmenu im Stammverzeichnis des Webservers, das lokale Web ist somit fertig und kann per FTP zum entfernten Webserver geschafft werden. Auch dieser Filetransfer lässt sich weiter automatisieren...

Inhalte Publizieren

Untenstehendes Schema verdeutlicht den bisherigen Zusammenhang, d.h., wie das Publizieren prinzipiell abläuft. Dabei wird unter Publizieren der Vorgang verstanden, in welchem die lokal erstellten Inhalte auf dem Webserver veröffentlicht werden. Hierbei wird unter "Remote" ausnahmsweise auch der lokale Webserver verstanden, der zum Testen dient.

Lokal                                                 Remote (Webserver)
=============================================================================================
linkbase.ini                                          public.ini
[Ordner]                                              [/url_1.html]
 descr = Beschreibung des Ordners                      title = Titel der URL
                                                       descr = Beschreibung...
 url_1 = /url_1.html                 == >              ordner = Ordner
 tit_1 = Titel zu url_1              Publizieren       time = Last-Modified
 des_1 = Beschreibung zu url_1       == > 

[Ordner.Unterordner]                                  Variante 1: HTML-Dateien erzeugen
 usw....                                                 komplett mit HTML-Header und Footer
                                                      Variante 2: Bodies in eine MySQL-DB schreiben
/lokales_body_verzeichnis                             Variante 3: Bodies in eine Datei DB_File schreiben
 url_1.html
 url_2.html

In Variante 1 ist die public.ini nicht unbedingt notwendig. Es ist jedoch gut, solche eine Datei serverseitig zu haben, daraus lässt sich nämlich recht einfach ein sitemap oder ein RSS-Feed erstellen, was z.B. für Suchmaschinen interessant ist.

In Variante 2 kann die public.ini ebenfalls entfallen, sofern alle dort notierten Attribute einer Webseite in der MySQL-DB verfügbar sind (siehe Tabellenbeispiel weiter unten). Unumgänglich ist die public.ini, wenn der Content (Body) einer einzelnen HTML-Datei aus DB_File gelesen wird (Variante 3, kommt hier zum Einsatz).

Das Web aus der Datenbank

Mit dem Schritt dahingegend, die Inhalte (nur den Body) aller Webseiten in einer Datenbank abzulegen, ergeben sich weitere Möglichkeiten der Automatisierung. Ich beschreibe hier im Folgenden, wie ich das auf dieser Website realisiert habe und was für ein solches Vorhaben gebraucht wird. Ausgehend von obenstehender INI-Datei, in der jede Einzelseite einem virtuellen Ordner zugeordnet ist, ergibt sich hinsichtlich Datenhaltung eine Abstraktion für die Tabelle mit vier Spalten:

url title content ordner
/webtree.html Verzeichnisstruktur und virtuelle Ordner Body ohne header, ohne footer, nur der Inhalt als HTML Intern.Artikel.Webmaster

In einer solchen Tabelle sind alle Einzelseiten gespeichert, es gibt auf dem Webserver praktisch keine HTML-Dateien mehr. Die erste Spalte ist der Primary Key, womit Abfragen, also das Auslesen eines HTML-Contents performant vonstatten gehen.

Das "Web in der Datenbank" ermöglicht von vornherein eine einfach zu realisierende Volltextsuche in den Inhalten und ist mit den passenden "Werkzeugen" verblüffend einfach zu Editieren. Die nächsten Abschnitte befassen sich mit Fragen wie:

Der Index in der lokalen Datei linkbase.ini

Die INI-Datei wird wie gehabt mit einem Texteditor erstellt und editiert. Steht das Erstellen einer neuen Seite an, wird diese in den entsprechenden Abschnitt der INI-Datei eingetragen:

[Intern.Artikel.Webmaster]
	link1=/webtree.html
	title1=Verzeichnisstruktur und virtuelle Ordner im Webverzeichnis-Baum
	descr1=Die Abbildung des Web-Tree auf Dateiebene in einer Verzeichnisstruktur...

Lokale HTML-Dateien mit dem Body

Jede HTML-Seite wird lokal in einem gesonderten Verzeichnis bodydir erstellt, editiert und abgespeichert. Der Dateiname muss natürlich mit dem in der linkbase.ini eingetragenen Namen übereinstimmen. Geschrieben wird in diesen Dateien nur der body ohne <head></head> und ohne </body></html>.

Content-Management per HTTP

Gebraucht werden dazu ganze zwei Scripts, die ich in Perl geschrieben habe. Das lokale Script manager.pl kommuniziert mit dem Zweiten, einem CGI-Script auf dem Webserver (lokal oder remote) per Hyper Text Tranfer Protocol.

Das lokale Perlscript zum Content-Management

Betrachten wir die Aufgabenstellung, das Script muss können:

Zum Steuern des Scripts, was auf der Kommandozeile bedient wird, gibt es das Perl-Modul Getopt::Std und für die Kommunikation das Modul LWP::UserAgent. Die Bedienung des Scripts manager.pl sieht bei mir so aus:

Management Local
manager.pl -l -i              # erzeugt den Index mit virtuellen Ordnern
manager.pl -l -f webtree.html # schreibt die Datei "webtree.html" in die DB lokal

Management Remote
manager.pl -r -i
manager.pl -r -f webtree.html
# wie Management Local, nur dass nun die DB auf dem produktiven Webserver beschrieben wird

Diese Kommandozeilen lassen sich komfortabel direkt aus meinem Editor TextPad heraus aufrufen, für den Fall mit Schalter -f gleich mit der aktuell geladenen Datei (im TextPad $file). MySQL-proprietär, dafür sehr komfortabel ist die Verwendung von REPLACE anstelle von INSERT, mit demselben SQL-Syntax kann somit die Tabelle auf dem neuesten Stand gehalten werden, ohne diese erst leerzumachen und neu beschreiben zu müssen.

Die HTTP-Schnittstelle zur Datenbank auf dem Webserver

Das CGI-Script für diese Aufgabenstellung habe ich hier ausführlich beschrieben, so dass hierzu nicht weiter eingegangen werden muss. Anzumerken ist lediglich, dass dieses Script sowohl auf dem lokalen Webserver als auch auf dem Webserver beim Provider zum Einsaz kommt, womit die Arbeitsabläufe zum Erstellen/Editieren von Inhalten auf beiden Maschinen absolut identisch sind.

Mod Rewrite und ein CGI-Script

Betrachte die Datei .htaccess auf dem Server:

DirectoryIndex /cgi-bin/view.cgi?/index.html

RewriteEngine on
RewriteRule ^(.*).html$ /cgi-bin/view.cgi?/$1.html

Diese Zeilen bewirken, dass alle Requests like datei.html an das CGI-Script view.cgi weitergereicht werden. Dabei ist der Bezeichner vor dem .html ein Parameter für view.cgi. Beispielsweise wurde der URL /index.html mit einem Browser angefordert. Mittels der RewriteRule wird der Name index als erster Klammerausdruck geparst und der Parameter /index.html für das CGI-Script in den QUERY_STRING geschrieben.

view.cgi schaut nun serverseitig in die Tabelle auf dem MySQL-Server nach url, title, content, ordner. Sofern es die angeforderte Datei gibt, wird ein einheitlicher HTML-Header und HTMl-Footer eingebaut und die Datei zum Browser geschickt. Hierbei wird auch die komplette Navigation zu den anderen Einzelseiten oder CGI-Scripts eingebaut.

Sofern die angeforderte Seite nicht oder nicht mehr in der DB vorhanden ist, wird auf eine Standardseite umgeleitet, die dem Besucher hoffentlich weiterhilft. Bei mir gibt es dazu das CGI-Script 404.cgi.

Hier nun das Script womit der HTML-Content aus der DB gelesen wird:

#!/usr/bin/perl
###########################################################################
# Bodies aus der Datenbank laden und zum Browser schicken
# Tabelle "suchindex"
# url, title, content, ordner
###########################################################################
use strict;
use Basic;
use DBI;

my $dbh = connMySQL || redir('/cgi-bin/fallback.cgi'); # siehe weiter unten

if($ENV{QUERY_STRING}){
	# prüfen, ob in DB
	my($url, $title, $body, $ordner) = 
	 $dbh->selectrow_array("SELECT url, title, content, ordner 
	 FROM suchindex WHERE url='$ENV{QUERY_STRING}'");
	
	if(!$url){
		# URL nicht in DB, also nicht auf WebSite verfügbar
		# Hier sollte der Status: 410 Gone gesendet werden
		# und eine Seite, die dem Besucher weiterhilft
		print "Status: 410 Gone\n";
		print "Content-type: text/html\n\n";
		# ...
		exit;
	}
	
	print cgiHeader;
	print htmlUp($title);
	print $body;
	print htmlDown($ordner,$url,''); # ordner, datei, ''
}
else{
	redir('/cgi-bin/404.cgi');
}


exit;

Abstrakt - Objektorientierte Projektverwaltung

Content-Management beginnt mit der Projektverwaltung und nicht etwa mit der Serverkonfiguration. Die RewriteEngine ist zwar ein mächtiges Werkzeug zum Verbessern der Performance und der Flexibilität eines Webauftritts, dieser selbst sollte jedoch auch ohne Mode Rewrite funktionieren. HTML ist die Basis zur Darstellung von Ressourcen (Images, PDF-Dateien usw.) im Internet und das setzt eine sorgfältige Planung des Projekts voraus. Letztendlich hat auf der Darstellungsebene jeder HTML-Datei nicht nur einen URL sonderen auch weitere Eigenschaften wie z.B. eine Beschreibung, einen Titel, das Erstellungsdatum, eine bestimmte Zeichenkodierung (charset), weitere Inhalte verschiedener Content-Types wie z.B. Images usw. und eine bereits in der Projektverwaltung festgelegte Ordnerzugehörigkeit.

Einige der beschreibenden Eigenschaften, das sind beispielsweise Titel sowie die Beschreibung, finden sich nach der Umsetzung im Kopf einer jeder HTML-Datei wieder. Aus der Ordnerzugehörigkeit ergibt sich die Navigation. Somit haben alle HTML-Ressourcen einen einheitlichen Header/Footer und eine konsistente Navigation.

Eine gewissenhafte Planung erleichtert die Umsetzung ungemein und ist durchweg objektorientiert: Jede URL ist dabei als Objekt zu betrachten, mit bestimmten Eigenschaften, die bereits in der Planung Berücksichtigung finden. Der Vorteil von Mode_Rewrite gegenüber statischen HTML-Dateien liegt auf der Hand:

Zum Performance eine Anmerkung: Der größte Overhead entsteht beim Starten eines CGI-Prozesses auf dem Server und beim Connecten mit einer Datenbank wobei ein Handle erstellt wird. Ist dieses DB-Handle einmal vorhanden, erweist sich der Zugriff auf die Tabellen als sehr performant, insbesondere dann, wenn diese zweckmäßig indiziert sind. Eine empfohlene Möglichkeit zur Verringerung des genannten Overheads ist der Einsatz von FastCGI, dies muss jedoch vom Provider her unterstützt werden.

Fallback Szenario

Von besonderem Interesse ist die Zeile, in welcher der Database-Handle $dbh angefordert wird. Für den Fall, dass der DB-Server nämlich einmal nicht erreichbar sein sollte, wird auf eine für den Besucher verständliche URL umgeleitet, die einen Hinweis zeigt, dass alle Dienste mit DB-Anbindung vorübergehend nicht verfügbar sind. Diese URL ist in meinem Fall das CGI-Script fallback.cgi, weil ja alle *.html-Ressourcen per Mod Rewrite umgeschrieben wurden.

Merke: In allen Anwendungen, die eine Datenbankanbindung erfordern, sollte diese als Erstes geprüft werden damit im Fall der Nicht-Erreichbarkeit des Datenbankservers eine aussagekräftige Meldung im Browser gezeigt wird. Das betrifft unter anderem Scripts für Gästebücher oder Feedbackformulare.

Alternative zu MySQL

Insbesondere in dem Fall, wo der MySQL-Server mit dem HTML-Content nicht auf derselben Maschine zu finden ist, wie der Webserver, ist das Erzeugen von HTML-Inhalten aus der Datenbank unperformant und nicht mehr sinnvoll. Ein Request würde erst zum Webserver gehen, dieser holt über das Netz den Inhalt vom DB-Server und liefert erst dann die Seite aus. Wenn unbedingt daran festgehalten werden soll, die Seiten dynamisch zu erzeugen, muss eine andere Lösung her.

Eine solche Lösung heißt DB-File, das sind lineare Datenbanken, an der Universität Berkeley entwickelt. In Perl gibt es dazu eine recht einfache Schnittstelle, das Modul DB_File und die Anbindung ist denkbar einfach: Das Modul stellt eine Methode bereit, mit welcher die Datei an einen Hash gebunden wird. Ein solcher besteht aus Key-Value und hierzu passt die Zuordnung REQUEST_URI => Content.

Da in einem Hash die Datenhaltung je Record per Key-Value erfolgt, sind für die weiteren Attribute einer HTML-Seite, wie Title, Last-Modified, Description usw. weitere Maßnahmen zur serverseitigen Datenhaltung erforderlich. Beispielsweise könnte je Attribut eine DB-Datei angelegt werden, nach dem Schema title.db, descr.db, lastmod.db usw. oder eine Textdatei im Format einer INI wie folgt:

[/url.html]
title=Titel der Webseite
descr=Beschreibung der Seite für den Meta-Tag im HTML-Header
time=Last Modified Date

Die hier gerade eben zu lesende Seite wurde aus DB_File erstellt und die Attribute dazu sind in einer INI-Datei gespeichert.

Anmerkungen zur Scalierbarkeit

Wie jede WebSite, "lebt" auch diese hier und neue Features werden gewünscht. So sind ein paar neue Attribute zu jeder URL hinzugekommen, ein Abschnitt in meiner public.ini sieht derzeit so aus:

[/korfu.html]
descr=Wir überfliegen den Alpenhauptkamm ...
pics=/korfu
title=Korfu Ostküste am ionischen Meer 2005
ordner=Intern.Urlaub
time=1252002395

Der Paramter time ermöglicht das einheitliche Management von Last-Modified und das Senden eines entsprechenden Headers, womit Webserver und UserAgent das Cachen aushandeln können. Mit diesem Attribut wird auch der Aufbau der News-Seite dynamisch gesteuert.

Interessant ist der Parameter pics. Über dieses Attribut wird der automatische Einbau einer Bildergalerie ermöglicht. Ist zu diesem Parameter ein Verzeichnis angegeben, werden aus dem Verzeichnis die sog. Thumbnails in die Seite geladen. Darauf wiederum setzt ein CGI-Script auf, was die Einzelseiten zu jedem Picture erzeugt einschließlich Link zur Hauptseite.

Last-Modified: Tue, 22 Jun 2010 19:50:30 GMT