Webbasierte Anwendungen mit LAMP Walter Herglotz © 2001 Eine Überblicks − Tour Beginnen wir zuerst einmal mit einer kleinen Rundtour durch unser Thema. Schließlich wollen wir ja zu Anwendungen kommen, die auf mehreren Grundtechnologien aufbauen. Wir fangen mit einer ganz einfachen Seite für das Internet an und publizieren sie auf einem Server. Damit könnten wir schon ganze Web−Auftritte realisieren. Allerdings nur durch statische Webseiten ähnlich den seiten eines gebundenen Buches. Im nächsten Schritt werden wir diese Seite durch ein Programm erzeugen lassen. Da nun die Seite dynamisch erzeugt wird, hängt ihr Aussehen vom Programm ab. Der letzte Schritt unseres Spazierganges verwendet dann schon eine Datenbank. Damit haben wir dann auch unsere Themen vorgestellt. Der Beginn − HTML Im Internet, dem weltweiten Datenübertragungssystem, gibt es viele verschiedene Dienste. Die einen kopieren Dateien über das Netz, andere synchronisieren die Zeitbasis Ihres Rechners mit weltweit verfügbaren Atomuhren und schließlich können Sie mit dem HTTP−Dienst und einem Browser im WWW (world wide web / weltweites Informationsgeflecht) surfen. Die Sprache des WWW ist HTML (hypertext markup language / Hypertext Auszeichnungs− Sprache). Wenn jemand eine Information im WWW veröffentlichen will, dann muss diese Information mit Hilfe der Sprache HTML auf einem Rechner (engl. host, web server) bereitgestellt werden. Die Daten werden dann von diesem Rechner z.B. zu Ihrem Rechner mit Hilfe von HTTP (hypertext transfer protocol / Hypertext Übertragungssteuerung) geschickt und schließlich von Ihrem Browser angezeigt. Also schreiben wir einmal einen kleinen Text mit Hilfe von HTML. Vergessen Sie, wenn Sie den Text abtippen sollten, bitte die spitzen Klammern nicht. <html> <!−− Datei: html_001.html −−> <head> <title>Erstes Beispiel des LAMP−Buches</title> </head> <body> <h1>LAMP−Buch: 1. Beispiel</h1> Im ersten Beispiel geben wir ein kurzen Text aus, der auch einen Umlaut enthält − ein ’ä’. </body> </html> Dieses Text können mit Hilfe eines einfachen Editors erstellen und in einer Datei speichern (oder von der Buch−Webseite abholen. Alle Web−Seiten sind mit der Sprache HTML aufgebaut. Wir werden uns einen Überblick über die wichtigsten HTML−Befehle verschaffen und als Seiten im geplanten Web−Auftritt ablegen. Die Datei, die wir gerade geschrieben oder auch kopiert haben, enthält den Hypertext. Als 1 Webbasierte Anwendungen mit LAMP Walter Herglotz © 2001 Hypertext beschreibt man eine Mischung aus lesbarem Text und Steuerinformationen. HTML erkennt Steuerinformationen an spitzen Klammern. Vielleicht ist Ihnen auch aufgefallen, dass die Steueranweisungen (also die Befehle) in den spitzen Klammern hier immer paarweise aufgetreten sind. Am Anfang steht "<html>" und am Ende das Gegenstück dazu "</html>". Es ist wie in der Mathematik −einer öffnenden Klammer folgt irgendwann eine schließende, Mit der Anweisung "<html>" haben wir den Befehl gegeben, den folgenden Inhalt gemäß den Spielregeln der Sprache HTML zu interpretieren. Innerhalb der äußeren Klammer mit "<html>" stehen zwei zusammen gehörende, weitere Gruppen − eine "<head>"−Gruppe und eine "<body>"−Gruppe. Im Kopf (engl. Head) stehen Informationen über die ganze Datei und die Informationen, die im Körper (engl. Body) folgen werden. Hier steht nur ein Titel (engl. title). Diese Struktur gilt für alle einfachen HTML−Seiten. Vermutlich sind sogar die meisten Web− Seiten so aufgebaut. Damit haben wir bereits den groben Aufbau kennen gelernt. Innerhalb des Körpers werden nun weitere Befehle (oder Auszeichnungsanweisungen) in spitzen Klammern hinzugefügt. Der Befehl "<h1>" startet eine Überschrift. Die Wichtigkeit wird durch Ziffern von eins bis sechs angegeben − je kleiner desto wichtiger. Ein einzelnes Zeichen sollten wir noch kurz diskutieren − den deutschen Umlaut ’ä’ im Text. Es ist gar nicht so lange her, da druckten große Firmen und Verwaltungen kein Umlaute − ihre Großrechner konnten es nicht. Und so wurde eben der Hr. Mueller in Muenchen angeschrieben. In HTML−Texten ist das anders. Wenn nichts anderes angegeben wird, dann wird unterstellt, dass der Text mit Hilfe des Zeichensatzes ISO−8859−1 (Latin−1) darstellbar ist. Und dieser Zeichensatz kennt unsere Umlaute. Später werden wir den jeweils verwendeten Zeichensatz im Kopf angeben. Anzeigen der Datei als Web−Seite Haben wir die Datei erstellt, sollten wir sie zuerst einmal auf unserem Computer speichern. Wichtig ist dabei die Dateiendung (oder Dateikennung, also die Buchstaben hinter dem letzten Punkt). Die meisten Programme werden "*.html" erwarten. Programme von Microsoft erwarten nur "*.htm", da die alten Windows−Systeme nur sehr kurze Dateinamen verarbeiten konnten und nachfolgende Betriebssysteme dieser Firma dieses Manko nun aktiv weiter unterstützen.. Nehmen wir nun an, dass Sie den oben angegebenen Text eingetippt und in Ihrer Datei "html_001.html" abgespeichert haben. Natürlich müssen Sie sich noch den Ort an hand des Verzeichnispfades merken − und bei Windows zusätzlich noch einen sogenannten Laufwerksbuchstaben, der meist für eine Partition auf einer Festplatte steht. 2 Webbasierte Anwendungen mit LAMP Walter Herglotz © 2001 Das Bild wurde beim Speichern unter Linux und dem Programm "StarOffice" aufgenommen. Der Pfad ist dabei im oberen Teil angezeigt. Mit den beiden Informationen Pfad (evtl. mit dem Festplattenbuchstaben) und dem Dateinamen ausgerüstet, können wir nun einen Browser starten (z.B. Netscape, Opera, Konquerer, Explorer) und damit die gleiche Datei wieder öffnen. Allerdings wird nun der Browser die spitzen Klammern verstehen und sie als Befehle akzeptieren. Unsere Datei wird nun als richtige Web−Seite angezeigt − wenn sich kein Fehler beim Abtippen eingeschlichen hat. Im Browser sehen wir nur den "Netto"−Inhalt ohne die Befehle. Damit haben wir den grundlegende Schritt geschafft. Wir haben ein möglichst einfaches Beispiel gewählt und damit den ganzen Kreislauf Schreiben, Speichern und Anzeigen durchlaufen. In der Welt der Programmierung ist dies fest mit dem "hello world"−Beispiel von Kernighan und Ritchie, 3 Webbasierte Anwendungen mit LAMP Walter Herglotz © 2001 den Entwicklern der Sprache "C" verbunden. Während andere Entwickler von Computer−Sprachen stets einen möglichst hochtrabenden und schwierigen Zugang zu ihren Erfindungen für richtig hielten, luden die "C"−Erfinder ihre Leser ein, ihnen auf einem möglichst einfachen und sinnvollen Weg zu folgen. Gut − nicht wahr? Publizieren im Internet Die Überschrift zeigt uns den nun folgenden Schritt. Unsere Datei, die wir bisher als ganz normale Datei auf unserer Festplatte gespeichert und auch wieder im Browser angesehen haben, soll nun unter den Bedingungen des Internets getestet werden. Dazu müssen wir sie an einen Ort bringen, der sozusagen ein teil des Internets ist oder zumindest sein könnte. Ein solcher Platz ist der Publikationsbereich eines Web−Servers. Der Begriff "Web Server" ist, wie bei vielen eingedeutschten Begriffen etwas missverständlich. Aber das geschieht im Grunde mit jedem Wort, dass in eine andere Sprache verpflanzt wird. Ein "Web−Server" soll hier ein Programm oder ein Programm zusammen mit dem Rechner, auf dem es läuft, bedeuten. Ein Web−Server soll Informationen den Benutzern des WWW, des "world wide web", bekannt machen. Eines der Programme, die sehr häufig im Internet eingesetzt werden, heißt "Apache". Wie so oft in der Welt der offenen Software, ist der Name ein Wortspiel mit einem gehörigen Schuss an Humor. Der Name leitet sich von einigen Verbesserungen ab, die eine Gruppe von Programmierern einem der ersten Server (dem NCSA−Server) zu Gute haben kommen lassen. Eine solche Verbesserung in der Software nennt man auch eine "patch" − einen Flicken. Ein "ge− patchter" Server ist also ein Server, dem man noch einige Flicken angebracht hat. Wir könnten auch Flickwerk dazu sagen. Wenn man den riesigen Erfolg dieser Qualitätssoftware betrachtet, dann ist das sicher mehr als nur eine kleine Untertreibung. Übrigens − einen Menschen, der den Quelltext lesen kann, ihn versteht, eine Verbesserung einfügt und dann diese Änderung wieder den Anwendern zur Verfügung stellt, nennt man Hacker. Unsere HTML−Datei müssen wir nun in den Bereich eines Rechners bringen, den der zugehörige Web−Server benutzt, um anderen Rechnern diese Information zur Verfügung zu stellen. Wollen wir unsere Datei nun betrachten, dann muss der Browser mit dem Web−Server in Verbindung treten, sich die Datei geben lassen und anzeigen. Meist sind hier nun zwei Rechner beteiligt, die über das Internet verbunden sind. Wir können die Situation auch auf einem einzigen Rechner nachspielen. Dazu muss dieser Rechner beiden Seiten, also den Benutzer (engl. Client) und den Server gleichzeitig bedienen können. Lokales Publizieren Am einfachsten scheint mir die Benutzung unter Linux. Hier besorgt man sich am besten eine sogenannte Distribution, eine angepasste Sammlung von Software−Paketen für Linux. Angenehm ist, dass die Distributionen sich um die notwendigen Einstellungen für die ortsüblichen Darstellungen, wie Zeichensatz oder Zahlendarstellung kümmern. Die Details finden Sie im Anhang 2. Nun müssen wir herausbekommen, wo der reservierte Bereich liegt, in dem der Web−Server die Dateien erwartet, die er anderen über das Netz zur Verfügung stellt. Dazu können wir einen Blick in die zugehörige Konfigurationsdatei werfen. 4 Webbasierte Anwendungen mit LAMP Walter Herglotz © 2001 Der Bereich wird als Document Root bezeichnet (Beginn des Pubikationsbereiches.) Im Auszug der Konfigurationsdatei finden wir, dass es sich um den Pfad "usr/local/httpd/htdocs" handelt. In diesem Verzeichnis und darunter müssen also alle Dateien stehen, die wir anderen über das Netz zur Verfügung stellen wollen. Also müssen wir unsere Datei hierhin verschieben oder noch einmal kopieren. Um ein wenig Ordnung zu halten und auch um das Beispiel möglichst echt zu gestalten, wurde unter dem Beginn des Publikationsverzeichnisses (also der Root für Dokumente) ein Verzeichnis "lamp_buch" angelegt. Dahinein legen wir die Kopie unserer Datei. Das kann nur einen Kopierbefehl (cp im Terminal−Fenster), eine Verschieben mit der Maus (drag und drop) oder durch den Befehl "Speichern unter" geschehen, wenn die Datei gerade im Browser angezeigt wird. 5 Webbasierte Anwendungen mit LAMP Walter Herglotz © 2001 Damit steht die Datei zwar genauso wie vorher auf der lokalen Festplatte, aber an einer ganz bestimmten Stelle. Starten wir nun den Browser und geben die passende Web−Adresse ein. Solche Adressen heißen auch URL’s (uniform resource locator − einheitliche Ortsangabe für Datenquellen). Bei Bedarf finden Sie eine nähere Beschreibung des URL’s im Anhang 3. Die Seite ist natürlich die gleiche wie vorher. Nur die Adresse ist keine Dateiangabe mehr, sondern eine richtige Adresse, wie sie ganz ähnlich auch im Internet verwendet wird. Allerdings wird ein spezieller Rechnername verwendet: "localhost". Das ist ein besonderer Name des Rechners, vor 6 Webbasierte Anwendungen mit LAMP Walter Herglotz © 2001 dem man gerade sitzt. Nach dem Rechnernamen folgt das Verzeichnis im Publikationsbereich und schließlich der gewünschte Dateiname mit seiner Kennung. Damit haben wir auf einem Rechner sowohl den Client (den Browser) und den Server (Apache) benutzt, um eine Datei anzuzeigen. Können wir HTML und sind wir in der Lage die erstellten Dateien auf einen Server im Internet abzulegen, können wir schon komplette Web−Auftritte produzieren. Für unser Thema brauchen wir aber noch weitere Schritte. HTML−Seiten mit einem Programm erzeugen Gehen wir einen wichtigen Schritt weiter. Alle Seiten in einem Buch sind statisch und so lange nicht zu ändern, bis eine neue Auflage erscheint. Genauso verhält es sich mit den CD’s, die vielen Büchern beiliegen. Mir geht es meist so, dass ein neues Buch erst ein wenig warten muss, bis ich es lesen kann. Oft sind dann die CD’s auch schon wieder veraltet, da eine neuerer Version im Internet zur Verfügung steht. Anders ist es, wenn man die Web− oder Buchseiten automatisch immer dann erzeugt (generiert), wenn ein Besucher sie lesen will. Dann könnten die aktuellsten Änderungen (z.B. der gerade entdeckte Tippfehler), sofort einfließen. Also schaffen wir die Voraussetzungen, um dies zu erreichen. Wir lernen einfach ein wenig programmieren. Eine sehr weit verbreitete Sprache im Web ist PHP (PHP−Hypertext Präprozessor). Diese Sprache kann beliebige Texte ausgeben und auf sehr viele Funktionen zugreifen. PHP ist eine Scriptspache. Sie wird also bei Nutzung gelesen und interpretiert. Die für das Buch schönste Eigenschaft ist die einfache Integration in Web−Seiten. Schreiben wir jetzt erst einmal die vorhanden HTML−Datei ein wenig um. <html> <!−− Datei: html_002.php / oder html_002.php3 −−> <head> <title>Erstes Programm−Beispiel des LAMP−Buches</title> </head> <body> <h1>LAMP−Buch: 1. Beispiel − programmiert</h1> <?php echo ("Im ersten Beispiel geben wir ein kurzen Text aus, der auch einen Umlaut enthält − ein ’ä’."); ?> </body> </html> Der Text gleicht dem Text der bisherigen Datei sehr. Allerdings finden wir nach der Überschrift 7 Webbasierte Anwendungen mit LAMP Walter Herglotz © 2001 eine Zeile, in der "<?php" steht. Diese Zeichenfolge gibt den Beginn eines eingebetteten Programmes an. Innerhalb der normalen HTML−Seite kann also ein Programmstück eingeschoben werden. Das Programm endet gleich wieder nach nur einem Befehl in der Zeile, die "?>" enthält. Der Beginn und das Ende des Programmes müssen nicht in eigenen Zeilen stehen, sondern können auch innerhalb des HTML−Textes auftauchen. Aber so ist es einfacher zu lesen. Der Befehl heißt "echo" und gibt einen Text aus. Aus reiner Gewohnheit steht der Text innerhalb eines Klammerpaares, als wäre es eine Funktion. Der Text wird durch Anführungszeichen begrenzt. Ein wenig Vorsicht ist hier geboten, denn PHP verlangt die einfache Variante der Anführungszeichen. Die graphischen Anführungszeichen, die man am Beginn unten und am Ende oben setzt, funktionieren nicht. Verwenden Sie einen einfachen Text−Editor oder einen HTML− Editor. Und wieder sieht, eine vollständige Installation des Rechners vorausgesetzt, das Ergebnis sehr bekannt aus. Geändert hat sich nur die Dateikennung. Sie endet auf "php". Falls Sie die Version 3 von PHP benutzen, dann ist die Kennung "php3". So einfach kann ein wenig Programmieren sein. Zugriff auf Datenbanken Mit Hilfe der Programmierung können wir die Gestaltung und auch den Inhalt der einzelnen Web− Seite gut anpassen. Schreiben wir z.B. die Befehle, die dem beginn der Seite ein charakteristisches Aussehen geben, dann können diesen Code auch in eine eigene Datei legen und in jeder anderen Datei einbinden. Damit kann man die Gestaltung aller Seiten des Web−Auftrittes leicht steuern. Noch schöner ist es, wenn Daten den Aufbau und den Inhalt der Seiten beeinflussen. Daten kann man in ganz einfachen Textdateien ablegen, wenn es sich um wenige Daten handelt. 8 Webbasierte Anwendungen mit LAMP Walter Herglotz © 2001 Die Adressliste einer kleinen Firma mit wenigen Kunden kann dafür ein Beispiel sein. Hier müssen wir die Daten in der Datei selbst anordnen, sortieren und durchsuchen. Große Datenmengen, wie die Kundendatei einer Bank mit vielleicht Millionen an Kunden, benötigen ein aufwendigeres Speichersystem für die Kundeninformationen. Hier stellt man die Daten in Datenbanken und überlässt einen großen Teil der Verwaltung dem Datenbank−Management−System. Datenbank−Management−Systeme können gleichzeitig mehrere Datenbanken verwalten. Eine einzelne Datenbank ist dabei eine Ansammlung von Tabellen, die untereinander vernetzt sein können. In der Mathematik nennt man den Aufbau einer Tabelle mit den Spalten einer Zeile auch eine Relation. Daher heißen die heute meist verbreiteten Datenbanken auch "relationale" Datenbanken. Die Kommunikation mit Datenbanken geschieht mit der Sprachen SQL (structured query language) Natürlich arbeitet wieder jeder Hersteller mit ein paar Tricks, um seine Kunden an sich zu binden. Allerdings gibt es auch einen gemeinsamen Kern mit dem man praktisch jede Datenbank ansprechen und steuern kann. Nehmen wir an dieser Stelle einfach an, dass auf unserem Testrechner, sei es nun ein Rechner im Netz oder der lokale Rechner, komplett mit Web−Server, PHP−Interpreter und einer MySQL− Datenbank ausgestattet ist. Wie schon erwähnt, wird man Befehle, die immer wieder benutzt werden müssen, in kleine Dateien auslagern, um bei Änderungen immer nur eine Stelle ändern zu müssen. Es ist die alte Regel jedes guten Programmierers: versuche eine Sache nur an einer Stelle zu beschreiben. Die Verbindung zur Datenbank ist so eine Stelle, die in jedem Datenbank−Programm angegeben werden muss. Gliedern wir also diese Zeilen in einer eigenen Datei aus. <?php $connect = mysql_connect("walter03","myroot") or die ("Cannot connect to walter03"); $db=mysql_select_db("walter_digital",$connect) or die ("No DB connection to walter_digital"); echo mysql_error(); $bild_server="http://walter03"; ?> Das PHP−Programm verbindet mit mysql_connect() mit dem Server, auf dem MySQl läuft.Die Verbindungsnummer wird in der Variablen "$connect" gespeichert. Im Fehlerfall gibt die Verbindungsfunktion "false" (falsch) zurück. Dann wir der zweite Teil der Zeile ausgeführt, der mit der Funktion "die()" (sterbe) das Programm abbricht. Der Rechnername in diesem Beispiel ist "walter03" und der Benutzer des RDBMS MySQL (relationales Datenbank Management System) heißt hier "myroot". Hier fehlt der dritte Parameter, der bei dieser Funktion normalerweise angegeben wird. Das ist dann das Passwort. Diesen Leichtsinn sollte man sich besser nur auf dem privaten Rechner leisten. Der zweite Befehl arbeitet ähnlich. Er verbindet dann innerhalb des RDBMS mit der gewünschten Datenbank. Ein RDBMS kann mehrere Datenbanken verwalten und bedienen. 9 Webbasierte Anwendungen mit LAMP Walter Herglotz © 2001 Im Beispiel wird dann zusätzlich noch eine Variable mit einem URL−Text gefüllt. Die besprochenen Befehle speichern wir in einer Datei mit dem Namen "db_connect.inc" im Publikationsverzeichnis des Web−Servers. Nach dieser Vorarbeit können wir das eigentlich Beispiel schreiben. Nehmen wir einfach an, wir hätten in der Datenbank eine Tabelle von Teilnehmern an Seminaren. Die Teilnehmer sollen nach dem Seminar durch die Informationen in der Datenbank weiter unterstützt werden. Nur sie sollen Zugang erhalten. Deshalb überprüfen wir den Zugang mit Anmelde−Namen und einem Passwort. Der letzte Schritt ist leider nicht ganz so einfach nachzuvollziehen, wie die vorhergegangenen. Der Grund ist einerseits, dass hier eine Datei steht, die erst am Ende des Buches vollständig besprochen werden kann, und andererseits benötigt das Beispiel schon die vollständige Installation der Datenbank, mit einer gefüllten Tabelle. Betrachten Sie daher diesen Schritt für den Moment nur als Text und nicht als nachvollziehbares Beispiel, bis wir die Grundlagen geschaffen haben. <?php // Datei: anmeldung.php (oder .php3) // Die Eingaben werden gegen die Tabelle teilnehmer geprüft. if (! isset ($PHP_AUTH_USER) ) { // Anmeldeboy anfordern, falls Name leer header(’WWW−Authenticate: Basic realm="walter−digital: Verwaltung"’); header(’HTTP/1.0 401 Unauthorized’); exit; } include ("db_connect.inc"); if (isset($PHP_AUTH_USER)) { // SQL Befehl schreiben $sql = "SELECT * FROM teilnehmer WHERE tn_login = ’$PHP_AUTH_USER’ and tn_passwort = ’$PHP_AUTH_PW’;"; // Abfrage starten $result = mysql_query($sql); // Anzahl der Ergebniszeilen ermitteln und prüfen $num = mysql_numrows($result); if ($num == 0) { echo "Kein Zugang möglich, Benutzer nicht gefunden"; exit; } } ?> <html> 10 Webbasierte Anwendungen mit LAMP Walter Herglotz © 2001 <head> <title> Der geschützte Bereich </title> </head> <body text=#ffffff bgcolor=#000f00> <h1> Der geschützte Bereich </h1> </body> </html> Die Datei besteht aus zwei Teilen: einem Programmteil und einem sehr einfachen HTML−Teil. Im Programmteil wird geprüft, ob die Variablen gefüllt wurden, die die Anmeldeinformationen enthalten. Falls dies nicht der fall ist, sagt das Programm mit einem sogenannten "header" dem Browser Bescheid, dass er ein Fenster aufmacht und den Anmeldenamen und das Passwort abfragt. Diese Information fließt dann wieder zu unserem Programm zurück. Wenn die Anmeldeinformation vorliegt, laden wir die schon besprochene Datei, die die Befehle enthält, um die Verbindung zu unserer Datenbank aufzunehmen. Nun können wir einen Zugriff auf die Tabelle "teilnehmer" in der Datenbank vorbereiten. Dazu schreiben wir einen passenden SQL− Befehl in die Variable "sql". Das ist nicht zwingend notwendig, aber durchaus praktisch. Der Befehl wird danach ausgeführt. Üblicherweise spricht man von einer Abfrage (engl. query), wenn man einen Befehl zur Datenbank schickt. Das Ergebnis der Abfrage wird in der Variablen "$result" gespeichert. An das Ergebnis wird noch die Frage gestellt, wie viele Zeilen (engl. row) es enthält. Gibt es den gewünschten Benutzer mit seinem Passwort in der Tabelle, ist das Ergebnis "1", gibt es ihn nicht, natürlich "0". Die Anmeldung sieht am Browser des möglichen Benutzers wie folgt aus. Das bringt uns zum Ende unserer Tour durch die Themen des Buches. Vielleicht stellen Sie sich hier die Frage: na und? Ein paar HTML−Zeilen, ein Web−Server, ein paar Befehle und eine Datenbank − was bringt uns das? 11 Webbasierte Anwendungen mit LAMP Walter Herglotz © 2001 Die Antwort darauf ist mehr eine geschäftliche denn eine technische Antwort. Stellen Sie sich einen einfachen Texteditor vor, der aus einer Web−Seiten besteht. Oder den Zugang zu einem fernen Zentralrechner für ihre Reisekostenabrechnung. Oder denken Sie an eine Lernumgebung, ein Dokumentenverwaltungssystem oder eine beliebige andere Anwendung von ganz klein bis ganz groß. Alles ist hier möglich. Und da das Programm auf einem zentralen (Groß−) Rechner läuft, kann jeder das Programm nutzen, ohne es zu installieren und zu warten. Sicherlich für viele ein schöner Gedanke. 12