Unterschiede

Hier werden die Unterschiede zwischen zwei Versionen angezeigt.

Link zu dieser Vergleichsansicht

Beide Seiten der vorigen Revision Vorhergehende Überarbeitung
Nächste Überarbeitung
Vorhergehende Überarbeitung
grafische_programmierung_mit_der_uml [2019/02/04 14:10]
127.0.0.1 Externe Bearbeitung
grafische_programmierung_mit_der_uml [2019/07/22 18:20] (aktuell)
huwi [Aggregation und Komposition]
Zeile 3: Zeile 3:
  
 ===== UML in der Entwicklungsumgebung SiSy ===== ===== UML in der Entwicklungsumgebung SiSy =====
->>​{{uml:​uml_kd_sq_editor.jpg?​750|}}+>​{{uml:​uml_kd_sq_editor.jpg?​750|}}
  
 Die folgende Abbildung zeigt Ihnen eine Kurzübersicht der Modellierungselemente des UML-Klassendiagramms. Die folgende Abbildung zeigt Ihnen eine Kurzübersicht der Modellierungselemente des UML-Klassendiagramms.
  
->>>​{{:​uml:​kurzuebersichtkd.jpg|}}+>​{{:​uml:​kurzuebersichtkd.jpg|}}
  
 **Darstellung von Attributen:​** \\ **Darstellung von Attributen:​** \\
Zeile 25: Zeile 25:
 Eine Klasse ist in der Programmierung der Name und die Beschreibung der Attribute und Operationen eines bestimmten Typs von Systembausteinen. Die UML fordert, eine Klasse als Rechteck darzustellen. Der Name der Klasse soll mit einem Großbuchstaben beginnen. Eine Klasse ist in der Programmierung der Name und die Beschreibung der Attribute und Operationen eines bestimmten Typs von Systembausteinen. Die UML fordert, eine Klasse als Rechteck darzustellen. Der Name der Klasse soll mit einem Großbuchstaben beginnen.
  
->>>​{{uml:​smd32pin.jpg?​100|}} {{uml:​klassecontroller.jpg|}}+>​{{uml:​smd32pin.jpg?​100|}} {{uml:​klassecontroller.jpg|}}
  
 Jeder Controller kann eingeschaltet werden und soll dann arbeiten. Das sind Operationen,​ die der Controller ausführen soll. Diese können in der UML der Klasse zugeordnet werden. Operationen erscheinen als Liste im Klassenrahmen. Jeder Controller kann eingeschaltet werden und soll dann arbeiten. Das sind Operationen,​ die der Controller ausführen soll. Diese können in der UML der Klasse zugeordnet werden. Operationen erscheinen als Liste im Klassenrahmen.
  
->>> {{uml:​controllerrun.jpg|}}+> {{uml:​controllerrun.jpg|}}
  
 ===== Objekte ===== ===== Objekte =====
 Objekte sind in der Programmierung Instanzen von Klassen. In der UML werden Objekte ebenfalls als Rechteck dargestellt. Die Kennzeichnung als Instanz erfolgt durch Unterstreichen des Namens. Zusätzlich kann der Typ der Instanz angezeigt werden. Die Instanzbeziehung zwischen einem Objekt und seiner Klasse wird als Abhängigkeit (gestrichelte Linie mit offenem Pfeil) und dem Stereotyp <<​instanceOf>>​ dargestellt. Objekte sind in der Programmierung Instanzen von Klassen. In der UML werden Objekte ebenfalls als Rechteck dargestellt. Die Kennzeichnung als Instanz erfolgt durch Unterstreichen des Namens. Zusätzlich kann der Typ der Instanz angezeigt werden. Die Instanzbeziehung zwischen einem Objekt und seiner Klasse wird als Abhängigkeit (gestrichelte Linie mit offenem Pfeil) und dem Stereotyp <<​instanceOf>>​ dargestellt.
  
->>>​{{uml:​instanceof.jpg|}}+>​{{uml:​instanceof.jpg|}}
  
 In der gezeigten UML-Darstellung wurde Folgendes festgelegt: In der gezeigten UML-Darstellung wurde Folgendes festgelegt:
Zeile 44: Zeile 44:
 Klassen können Eigenschaften von anderen Klassen erben. Die Verwendung von Klassenbibliotheken und der darin enthaltenen Klassen, als Basisklassen der eigenen Anwendung, beschleunigen die Entwicklungsarbeit enorm. Bei der Vererbung kann man auch je nach Lesart von einer Generalisierung (von unten nach oben gelesen) oder einer Spezialisierung (von oben nach unten gelesen) sprechen. Eine Generalisierung wird in der UML als Voll-Linie mit einem großen nicht ausgemalten Pfeil zur Basisklasse dargestellt. Die Eselsbrücke für die korrekte Richtung des Pfeils lautet //"ist ein"//​. Klassen können Eigenschaften von anderen Klassen erben. Die Verwendung von Klassenbibliotheken und der darin enthaltenen Klassen, als Basisklassen der eigenen Anwendung, beschleunigen die Entwicklungsarbeit enorm. Bei der Vererbung kann man auch je nach Lesart von einer Generalisierung (von unten nach oben gelesen) oder einer Spezialisierung (von oben nach unten gelesen) sprechen. Eine Generalisierung wird in der UML als Voll-Linie mit einem großen nicht ausgemalten Pfeil zur Basisklasse dargestellt. Die Eselsbrücke für die korrekte Richtung des Pfeils lautet //"ist ein"//​.
  
->>>​{{uml:​vererbungstm32.jpg|}}+>​{{uml:​vererbungstm32.jpg|}}
  
 In der gezeigten UML-Darstellung wurde Folgendes festgelegt: In der gezeigten UML-Darstellung wurde Folgendes festgelegt:
Zeile 57: Zeile 57:
 Die UML kennt ein zweites Ausdrucksmittel für den Sachverhalt //"ist ein"//​. Es gibt zahlreiche Anwendungsfälle,​ bei denen Vorlagen, Muster verwendet oder Vorschriften eingehalten werden sollen. So etwas können Struktur- oder Verhaltensmuster,​ aber auch Schnittstellendefinitionen sein. Da es sich hierbei nicht um eine Vererbung im eigentlichen Sinne handelt, wird zwar derselbe Pfeiltyp verwendet, aber die Linie wird gestrichelt dargestellt. In der UML spricht man von einer Realisierung. Die UML kennt ein zweites Ausdrucksmittel für den Sachverhalt //"ist ein"//​. Es gibt zahlreiche Anwendungsfälle,​ bei denen Vorlagen, Muster verwendet oder Vorschriften eingehalten werden sollen. So etwas können Struktur- oder Verhaltensmuster,​ aber auch Schnittstellendefinitionen sein. Da es sich hierbei nicht um eine Vererbung im eigentlichen Sinne handelt, wird zwar derselbe Pfeiltyp verwendet, aber die Linie wird gestrichelt dargestellt. In der UML spricht man von einer Realisierung.
  
->>>​{{uml:​realisierungarmapp.jpg|}} ​+>​{{uml:​realisierungarmapp.jpg|}} ​
  
 In der gezeigten UML-Darstellung wurde Folgendes festgelegt: In der gezeigten UML-Darstellung wurde Folgendes festgelegt:
Zeile 70: Zeile 70:
 Objektorientierte Programmiersprachen kennen verschiedene Konzepte, um die Stabilität von Anwendungen sicherzustellen. Eines der Konzepte ist die Kapselung. Dabei ist es möglich, Elementen, z. B. Attributen und Operationen von Klassen, sogenannte Sichtbarkeiten zuzuordnen. Damit kann verhindert werden, das geschützte Elemente unberechtigt benutzt werden. Die meisten Programmiersprachen unterstützen dies durch entsprechende Schlüsselworte wie //public//, //​protected//​ und //privat//. Die UML bietet Symbole, welche zwischen den Sichtbarkeiten //+ public//, //~ package//, //# protected// und //- privat// unterscheiden. Die Sichtbarkeit wird bei Operationen und Attributen dem Namen vorangestellt. Objektorientierte Programmiersprachen kennen verschiedene Konzepte, um die Stabilität von Anwendungen sicherzustellen. Eines der Konzepte ist die Kapselung. Dabei ist es möglich, Elementen, z. B. Attributen und Operationen von Klassen, sogenannte Sichtbarkeiten zuzuordnen. Damit kann verhindert werden, das geschützte Elemente unberechtigt benutzt werden. Die meisten Programmiersprachen unterstützen dies durch entsprechende Schlüsselworte wie //public//, //​protected//​ und //privat//. Die UML bietet Symbole, welche zwischen den Sichtbarkeiten //+ public//, //~ package//, //# protected// und //- privat// unterscheiden. Die Sichtbarkeit wird bei Operationen und Attributen dem Namen vorangestellt.
  
->>> {{uml:​grundgeruestarm.jpg|}}+> {{uml:​grundgeruestarm.jpg|}}
  
 In der gezeigten UML-Darstellung wurde Folgendes festgelegt: In der gezeigten UML-Darstellung wurde Folgendes festgelegt:
Zeile 84: Zeile 84:
 Zusätzlich sind in dieser Darstellung die Rückgabetypen der Operationen auf //void// festgelegt worden. Dieses UML-Klassendiagramm kann jetzt in Quellcode überführt werden. Dieser kann, hier als vereinfachter Ausschnitt, so aussehen: Zusätzlich sind in dieser Darstellung die Rückgabetypen der Operationen auf //void// festgelegt worden. Dieses UML-Klassendiagramm kann jetzt in Quellcode überführt werden. Dieser kann, hier als vereinfachter Ausschnitt, so aussehen:
  
->>><​code cpp>+><​code cpp>
 // SiSy UML C++ Codegenerator ////////////////////////////////////////////////​ // SiSy UML C++ Codegenerator ////////////////////////////////////////////////​
 class Controller : public STM32F4 class Controller : public STM32F4
Zeile 111: Zeile 111:
 Systeme bestehen aus Komponenten,​ die Komponenten aus Bausteinen, diese wiederum aus Einzelteilen usw. Diese Ganz-Teil-Struktur lässt sich in der UML als Aggregation bzw. Komposition abbilden. Dabei wird durch den oben angesprochenen Codegenerator solch eine Aggregation als Attribut im Code abgebildet. ​ Systeme bestehen aus Komponenten,​ die Komponenten aus Bausteinen, diese wiederum aus Einzelteilen usw. Diese Ganz-Teil-Struktur lässt sich in der UML als Aggregation bzw. Komposition abbilden. Dabei wird durch den oben angesprochenen Codegenerator solch eine Aggregation als Attribut im Code abgebildet. ​
  
-{{uml:​ledaggregation.jpg|}}+>{{uml:​ledaggregation.jpg|}}
  
 In der gezeigten UML-Darstellung wurde Folgendes festgelegt: In der gezeigten UML-Darstellung wurde Folgendes festgelegt:
Zeile 125: Zeile 125:
     * **Die Klasse //​DigitalOut//​ wird unter dem Namen //led// in der Klasse Controller als öffentliches Attribut aggregiert.**     * **Die Klasse //​DigitalOut//​ wird unter dem Namen //led// in der Klasse Controller als öffentliches Attribut aggregiert.**
  
-<code cpp>+><code cpp>
 // SiSy UML C++ Codegenerator ////////////////////////////////////////////////​ // SiSy UML C++ Codegenerator ////////////////////////////////////////////////​
 class Controller : public STM32F4 class Controller : public STM32F4
Zeile 152: Zeile 152:
 Die Aggregation entspricht also einem Attribut der Klasse. Somit ist die folgende UML-Darstellung letztlich genau dasselbe. Die Attributdarstellung spart Platz, ist aber weniger übersichtlich was die Systemarchitektur betrifft. ​ Die Aggregation entspricht also einem Attribut der Klasse. Somit ist die folgende UML-Darstellung letztlich genau dasselbe. Die Attributdarstellung spart Platz, ist aber weniger übersichtlich was die Systemarchitektur betrifft. ​
  
-{{uml:​ledattribut.jpg?​550|}}+>{{uml:​ledattribut.jpg?​550|}}
  
 ===== Erster UML Versuch mit SiSy ===== ===== Erster UML Versuch mit SiSy =====
Zeile 161: Zeile 161:
 Wählen Sie das **ARM-Vorgehensmodell**. Schließen Sie ggf. Ihre Hardware an. Dann laden Sie aus dem SiSy LibStore die Vorlage **PEC Framework - Portable Embedded Classes**. ​ Wählen Sie das **ARM-Vorgehensmodell**. Schließen Sie ggf. Ihre Hardware an. Dann laden Sie aus dem SiSy LibStore die Vorlage **PEC Framework - Portable Embedded Classes**. ​
  
->>>​{{uml:​libstorepec.png?​600|}}+>​{{uml:​libstorepec.png?​600|}}
  
->>>​{{:​uml:​umlprojektohnebeispiel.jpg?​600|}}+>​{{:​uml:​umlprojektohnebeispiel.jpg?​600|}}
  
 Legen Sie ein **Klassendiagramm** mit dem Namen "//​test1//"​ an, indem Sie das entsprechende Objekt per Drag & Drop aus der Objektbibliothek in das Diagramm ziehen. Überprüfen Sie die korrekten Einstellungen der **Zielsprache ARM C++**. Wählen Sie im nächsten Fenster die Hardware **STM32F407 Discovery** und den Programmer **ST-Link V2** aus. Legen Sie ein **Klassendiagramm** mit dem Namen "//​test1//"​ an, indem Sie das entsprechende Objekt per Drag & Drop aus der Objektbibliothek in das Diagramm ziehen. Überprüfen Sie die korrekten Einstellungen der **Zielsprache ARM C++**. Wählen Sie im nächsten Fenster die Hardware **STM32F407 Discovery** und den Programmer **ST-Link V2** aus.
  
->>>​{{:​uml:​libsoreggclass.jpg?​700|}}+>​{{:​uml:​libsoreggclass.jpg?​700|}}
  
 Öffnen Sie das Klassendiagramm. Wählen Sie dafür auf dem Klassendiagramm rechte Maustaste nach unten (öffnen). Aus der Liste der angebotenen Diagrammvorlagen wählen Sie bitte **Applikation Grundgerüst für PEC XMC,​STM32,​AVR,​SAM)**. Weisen Sie dieser portablen Vorlage das plattformspezifische Treiberpaket **MCU_STM32F4** zu. Öffnen Sie das Klassendiagramm. Wählen Sie dafür auf dem Klassendiagramm rechte Maustaste nach unten (öffnen). Aus der Liste der angebotenen Diagrammvorlagen wählen Sie bitte **Applikation Grundgerüst für PEC XMC,​STM32,​AVR,​SAM)**. Weisen Sie dieser portablen Vorlage das plattformspezifische Treiberpaket **MCU_STM32F4** zu.
  
->>>​{{:​uml:​treiberpaketstm.jpg?​700|}}+>​{{:​uml:​treiberpaketstm.jpg?​700|}}
  
 Vergleichen wir die soeben geladene Vorlage mit unseren Vorüberlegungen,​ so finden wir hier die gewünschte Operation für die Startsequenz und die Laufzeitoperation für den Controller. Desweiteren ist die Instanz der Anwendungsklasse zu erkennen und das die Klasse Controller die Merkmale eines //​AppKernel//​ realisiert. Übrigens kann man sich das recht nett anschauen, was mit dieser scheinbar schmucklosen Realisierungsbeziehung bereits an vorgeferigter Funktionalität bereitgestellt wird. Sie können das Template //​AppKernel//​ selektieren und über das Rechte-Maustasten-Menü zum **Quelldiagramm** des Templates gelangen. Die Abbildung zeigt eine vereinfachte Darstellung. Vergleichen wir die soeben geladene Vorlage mit unseren Vorüberlegungen,​ so finden wir hier die gewünschte Operation für die Startsequenz und die Laufzeitoperation für den Controller. Desweiteren ist die Instanz der Anwendungsklasse zu erkennen und das die Klasse Controller die Merkmale eines //​AppKernel//​ realisiert. Übrigens kann man sich das recht nett anschauen, was mit dieser scheinbar schmucklosen Realisierungsbeziehung bereits an vorgeferigter Funktionalität bereitgestellt wird. Sie können das Template //​AppKernel//​ selektieren und über das Rechte-Maustasten-Menü zum **Quelldiagramm** des Templates gelangen. Die Abbildung zeigt eine vereinfachte Darstellung.
  
->>>​{{uml:​projekt12.jpg?​450|}}+>​{{uml:​projekt12.jpg?​450|}}
  
 Wenn wir das im oben begonnen Stil fortsetzen, können wir zu der geladenen Vorlage folgende Aussagen treffen: Wenn wir das im oben begonnen Stil fortsetzen, können wir zu der geladenen Vorlage folgende Aussagen treffen:
Zeile 199: Zeile 199:
 Mit diesem UML-Grundgerüst wollen wir jetzt weiter arbeiten. Als Nächstes schließen wir eine LED an den Controller an. Ziehen Sie eine Klasse aus der Objektbibliothek in das Diagramm und geben dieser den Namen //Led//. Verbinden Sie die //LED//, ausgehend vom //​Controller//,​ mit einer Aggregation. Die Verbindung wird als Attribut im Controller abgebildet. Der Rollenname //+led// wird das öffentliche Attribut //led// vom Typ //Led//. Mit diesem UML-Grundgerüst wollen wir jetzt weiter arbeiten. Als Nächstes schließen wir eine LED an den Controller an. Ziehen Sie eine Klasse aus der Objektbibliothek in das Diagramm und geben dieser den Namen //Led//. Verbinden Sie die //LED//, ausgehend vom //​Controller//,​ mit einer Aggregation. Die Verbindung wird als Attribut im Controller abgebildet. Der Rollenname //+led// wird das öffentliche Attribut //led// vom Typ //Led//.
  
->>>​{{uml:​neueLED.JPG?​700|}}+>​{{uml:​neueLED.JPG?​700|}}
  
  
Zeile 216: Zeile 216:
 Wählen Sie die Operation //onStart// in der Klasse //​Controller//​ aus. Notieren Sie folgende kurze Codesequenz im Quelltexteditor. Verfolgen Sie dabei das Fenster mit dem Sequenzdiagramm. Wählen Sie die Operation //onStart// in der Klasse //​Controller//​ aus. Notieren Sie folgende kurze Codesequenz im Quelltexteditor. Verfolgen Sie dabei das Fenster mit dem Sequenzdiagramm.
  
->>><​code cpp>+><​code cpp>
 uint8_t wert; uint8_t wert;
 wert=led.getBlinkCode();​ wert=led.getBlinkCode();​
Zeile 225: Zeile 225:
 Das entsprechende Sequenzdiagramm sieht dann so aus: Das entsprechende Sequenzdiagramm sieht dann so aus:
  
->>>​{{uml:​seqonstart.jpg|}}+>​{{uml:​seqonstart.jpg|}}
  
 ===== Polymorphie ===== ===== Polymorphie =====
Zeile 238: Zeile 238:
 Ziehen Sie aus der Objektbibliothek eine Operation auf die Klasse //Taster//. Das Werkzeug SiSy erkennt jetzt, dass virtuelle Operationen vorhanden sind, welche sich überschreiben lassen und bietet diese im //​MethodenWizard//​ zur Auswahl an. Wir überschreiben die Operation //onClick// und erstellen somit einen eigenen Ereignisbehandler auf das Click-Ereignis des //​PecButtonClickAndHold//​. Dort notieren wir den Quelltext zum Weiterschalten des Blinkcodes: Ziehen Sie aus der Objektbibliothek eine Operation auf die Klasse //Taster//. Das Werkzeug SiSy erkennt jetzt, dass virtuelle Operationen vorhanden sind, welche sich überschreiben lassen und bietet diese im //​MethodenWizard//​ zur Auswahl an. Wir überschreiben die Operation //onClick// und erstellen somit einen eigenen Ereignisbehandler auf das Click-Ereignis des //​PecButtonClickAndHold//​. Dort notieren wir den Quelltext zum Weiterschalten des Blinkcodes:
  
->>><​code cpp>+><​code cpp>
 app.led.nextBlinkCode();​ app.led.nextBlinkCode();​
 </​code>​ </​code>​
Zeile 244: Zeile 244:
 Das Board STM32F4 weist noch eine Besonderheit auf: es müssen die Realisierungsparameter definiert werden. Markieren Sie dafür die Klasse //Taster// und öffnen Sie mit der rechten Maistaste das Kontextmenü;​ wählen Sie //​Definieren//​. Aktivieren Sie die Schaltfläche //​Realisierungsparameter//​. In dem sich öffnenden Dialogfenster wählen Sie für %pinLogic% den Wert //​High-Aktiv//​ und für %pinPull% den Wert //NoPull//. Das Board STM32F4 weist noch eine Besonderheit auf: es müssen die Realisierungsparameter definiert werden. Markieren Sie dafür die Klasse //Taster// und öffnen Sie mit der rechten Maistaste das Kontextmenü;​ wählen Sie //​Definieren//​. Aktivieren Sie die Schaltfläche //​Realisierungsparameter//​. In dem sich öffnenden Dialogfenster wählen Sie für %pinLogic% den Wert //​High-Aktiv//​ und für %pinPull% den Wert //NoPull//.
  
-{{uml:​realisierungsparameter.jpg?​700|}}+>{{uml:​realisierungsparameter.jpg?​700|}}
  
 ===== Assoziation ===== ===== Assoziation =====
 Den Umstand, das der Taster sich direkt um die LED kümmert, können wir im Klassendiagramm mit einer //​Assoziation//​ dokumentieren. Dazu ziehen wir eine Verbindung vom Typ //​gerichtete Assoziation//​ vom //Taster// zur //Led// und beschriften diese. Den Umstand, das der Taster sich direkt um die LED kümmert, können wir im Klassendiagramm mit einer //​Assoziation//​ dokumentieren. Dazu ziehen wir eine Verbindung vom Typ //​gerichtete Assoziation//​ vom //Taster// zur //Led// und beschriften diese.
  
->>>​{{uml:​tasterasso.jpg?​700|}}+>​{{uml:​tasterasso.jpg?​700|}}
  
 ===== Zustände ===== ===== Zustände =====
Zeile 260: Zeile 260:
 Bei dieser Gelegenheit schauen wir uns an, wie die Entwickler dieses schon nicht mehr ganz triviale Verhalten des Tasters konstruiert haben. Selektieren Sie den Baustein //​PecButtonClickAndHold//​. Wählen Sie im Kontextmenü (rechte Maustaste) //​Quelldiagramm öffnen//. Bei dieser Gelegenheit schauen wir uns an, wie die Entwickler dieses schon nicht mehr ganz triviale Verhalten des Tasters konstruiert haben. Selektieren Sie den Baustein //​PecButtonClickAndHold//​. Wählen Sie im Kontextmenü (rechte Maustaste) //​Quelldiagramm öffnen//.
  
->>>​{{uml:​gehezursm.jpg?​700|}}+>​{{uml:​gehezursm.jpg?​700|}}
  
 Dort finden Sie das Attribut //state//. Aus diesem können Sie im Kontextmenü //nach unten// wählen und gelangen zum Zustandsdiagramm für Button. Dort finden Sie das Attribut //state//. Aus diesem können Sie im Kontextmenü //nach unten// wählen und gelangen zum Zustandsdiagramm für Button.
  
->>>​{{uml:​smbutton.jpg?​700|}}+>​{{uml:​smbutton.jpg?​700|}}
  
 Die Modellierung von Zustandsdiagrammen wird in unserem Lehrbuch [[http://​shop.myavr.de/​Literatur/​Software%20Engineering%20f%C3%BCr%20Embedded%20Systems.htm?​sp=article.sp.php&​artID=200045|Software Engineering für Embedded Systems]] Die Modellierung von Zustandsdiagrammen wird in unserem Lehrbuch [[http://​shop.myavr.de/​Literatur/​Software%20Engineering%20f%C3%BCr%20Embedded%20Systems.htm?​sp=article.sp.php&​artID=200045|Software Engineering für Embedded Systems]]
Zeile 272: Zeile 272:
 Mit dem soeben Erlernten sollten sich die im [[Framework|ARM C++ Framework]] präsentierten UML Diagramme jetzt lesen und nachvollziehen lassen. Und hier diesen Abschnitt wiederum als Videozusammenfassung. Mit dem soeben Erlernten sollten sich die im [[Framework|ARM C++ Framework]] präsentierten UML Diagramme jetzt lesen und nachvollziehen lassen. Und hier diesen Abschnitt wiederum als Videozusammenfassung.
  
->>><​html><​iframe width="​640"​ height="​440"​ src="​https://​www.youtube.com/​embed/​KNim1z3Fy_A"​ frameborder="​0"​ allowfullscreen></​iframe></​html>​+><​html><​iframe width="​640"​ height="​440"​ src="​https://​www.youtube.com/​embed/​KNim1z3Fy_A"​ frameborder="​0"​ allowfullscreen></​iframe></​html>​
  
 ====== Seminarhinweise ====== ====== Seminarhinweise ======