commit bd1d2e051c856abac342ab9bf7cbcc54bdb14513
Author: github-classroom[bot] <66690702+github-classroom[bot]@users.noreply.github.com>
Date: Wed Apr 27 10:00:50 2022 +0000
Initial commit
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..51220d5
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,29 @@
+# EditorConfig is awesome: https://EditorConfig.org
+
+# top-most EditorConfig file
+root = true
+
+# Default formatting Unix-style newlines with a newline ending every file
+[*]
+charset = utf-8
+end_of_line = lf
+insert_final_newline = true
+trim_trailing_whitespace = true
+indent_style = space
+indent_size = 4
+
+# do not trim trailing whitespace in markdown files
+[*.md]
+trim_trailing_whitespace = false
+
+# explicit 4 space indentation
+[*.py]
+indent_size = 4
+
+# explicit 2 space indentation
+[*.{json, yml, yaml, xml, ddl, sql}]
+indent_size = 2
+
+# windows specific files
+[*.{bat, cmd}]
+end_of_line = crlf
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..022b841
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,5 @@
+#
+# https://help.github.com/articles/dealing-with-line-endings/
+#
+# These are explicitly windows files and should use crlf
+*.bat text eol=crlf
diff --git a/.github/classroom/autograding.json b/.github/classroom/autograding.json
new file mode 100644
index 0000000..1e1107f
--- /dev/null
+++ b/.github/classroom/autograding.json
@@ -0,0 +1,14 @@
+{
+ "tests": [
+ {
+ "name": "Run PA unit tests",
+ "setup": "",
+ "run": "gradle :Herzschlag:autograding --info",
+ "input": "",
+ "output": "",
+ "comparison": "included",
+ "timeout": 10,
+ "points": 2
+ }
+ ]
+}
diff --git a/.github/workflows/classroom.yml b/.github/workflows/classroom.yml
new file mode 100644
index 0000000..06a5358
--- /dev/null
+++ b/.github/workflows/classroom.yml
@@ -0,0 +1,15 @@
+name: GitHub Classroom Workflow
+
+on: [push]
+
+jobs:
+ build:
+ name: Autograding
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ - name: Set up JDK 17
+ uses: actions/setup-java@v1
+ with:
+ java-version: '17'
+ - uses: education/autograding@v1
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..9e7c379
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,70 @@
+# InelliJ IDEA files
+*.iml
+*.ipr
+*.ids
+*.iws
+.idea/
+
+# Eclipse files
+.project
+.metadata
+.classpath
+.settings/
+.loadpath
+bin/
+
+# Netbeans
+nbactions.xml
+
+# Visual Studio Code
+.vscode
+
+# Maven
+target/
+
+# gradle files
+.gradle
+build/
+
+# ignore logfiles
+*.log*
+
+# OS dependant files
+.DS_Store
+.Spotlight-V100
+.Trashes
+Thumbs.db
+Desktop.ini
+*~
+# Thumbnails
+._*
+
+# compiled files
+*.com
+*.class
+*.dll
+*.exe
+*.o
+*.so
+
+# packages
+*.7z
+#*.jar
+*.rar
+*.zip
+*.gz
+*.bzip
+*.xz
+*.lzma
+*~$*
+
+# package managment formats
+*.dmg
+*.xpi
+*.gem
+*.egg
+*.deb
+*.rpm
+
+# databases
+*.sqlite
diff --git a/README.adoc b/README.adoc
new file mode 100644
index 0000000..d981c80
--- /dev/null
+++ b/README.adoc
@@ -0,0 +1,210 @@
+:source-highlighter: coderay
+:icons: font
+:experimental:
+:!sectnums:
+:imagesdir: ./images/
+:handout: ./code/
+
+:logo: IT.PROG2 -
+ifdef::backend-html5[]
+:logo: image:PROG2-300x300.png[IT.PROG2,100,100,role=right,fit=none,position=top right]
+endif::[]
+ifdef::backend-pdf[]
+:logo:
+endif::[]
+ifdef::env-github[]
+:tip-caption: :bulb:
+:note-caption: :information_source:
+:important-caption: :heavy_exclamation_mark:
+:caution-caption: :fire:
+:warning-caption: :warning:
+endif::[]
+
+// references
+:mockito-home: http://mockito.org/[Mockito Homepage]
+:mockito-docs: http://mockito.github.io/mockito/docs/current/org/mockito/Mockito.html[Mockito Dokumentation]
+:mockito-annotations: https://www.baeldung.com/mockito-annotations[Konkrete Beispiele mit Mockito]
+:planet-wissen-herz: https://www.planet-wissen.de/video-das-herz--wie-funktioniert-es-100.html[Planet Wissen]
+:maven-central: https://search.maven.org/search?q=a:mockito-core[MavenCentral]
+
+
+= {logo} Praktikum Mock-Testing
+
+== Einleitung
+
+Ziele dieses Praktikums sind:
+
+* Anwenden von erweiterten Testverfahren (Mocks, Spys)
+* Übung des Umgangs mit Mockito
+
+=== Voraussetzungen
+
+* Vorlesung Mock-Testing
+
+=== Tooling
+* Installiertes JDK 17+.
+* Gradle 7.4+
+* Mockito ab Version 2.
+
+=== Struktur
+Das Praktikum enthält verschiedene Arten von Aufgaben, die wie folgt gekennzeichnet sind:
+
+[TU] – Theoretische Übung::
+Dient der Repetition bzw. Vertiefung des Stoffes aus der Vorlesung und als Vorbereitung für die nachfolgenden Übungen.
+
+[PU] – Praktische Übung::
+Übungsaufgaben zur praktischen Vertiefung von Teilaspekten des behandelten Themas.
+
+[PA] – Pflichtaufgabe::
+Übergreifende Aufgabe zum Abschluss. Das Lösen dieser Aufgaben ist Pflicht. Sie muss bis zum definierten Zeitpunkt abgegeben werden, wird bewertet und ist Teil der Vornote.
+
+
+=== Zeit und Bewertung
+Für das Praktikum stehen zwei Wochen in den Praktikumslektionen und im Selbststudium zur Verfügung.
+
+Je nach Kenntniss- und Erfahrungsstufe benötigen Sie mehr oder weniger Zeit.
+Nutzen Sie die Gelegenheit, den Stoff zu vertiefen, auszuprobieren, Fragen zu stellen und Lösungen zu diskutieren (Intensive-Track).
+
+Falls Sie das Thema schon beherrschen, müssen Sie nur die Pflichtaufgaben lösen und bis zum angegebenen Zeitpunkt abgeben (Fast-Track).
+
+Sie können die Lösungen der Textaufgaben in diesem Praktikum direkt in den Java-Files als Kommentar hinzufügen - oder als Markdown-File neben den Java-Files.
+
+=== Referenzen
+
+* link:{handout}[Praktikumsverzeichnis – Quellcode, Projektstruktur]
+* link:{mockito-home}
+* link:{mockito-docs}
+* link:{mockito-annotations}
+
+:sectnums:
+:sectnumlevels: 2
+// Beginn des Aufgabenblocks
+
+== Herz
+Das menschliche Herz ist ein lebenswichtiges und kompliziertes Organ.
+Nur, wenn seine einzelnen "Bauteile" richtig koordiniert werden, kann es eine ausreichende Blutversorgung unseres Körpers gewährleisten.
+
+Da es beim Mocking um das Testen des Verhaltens eines Objekts geht, bietet sich das Herz als Beispiel an.
+Darum simulieren wir in dieser Aufgabe ein menschliches Herz.
+Eine kurze Erklärung der Funktionsweise des Herzens gibt es auf link:{planet-wissen-herz}.
+
+Einige Fakten über das Herz, die bei dieser Aufgabe helfen können -
+im Projekt werden englische Begriffe verwendet, die Sie in Klammern finden:
+
+* Das Herz (Heart) besteht aus zwei Hälften.
+* Jede Herzhälfte (Half) hat einen Vorhof (Atrium) und eine Herzkammer (Ventricle).
+ Vorhöfe sammeln Blut, Herzkammern pressen es in den Körper.
+* Zwei Phasen wechseln sich jeweils ab.
+ ** Anspannungsphase: Systole
+ ** Entspannungsphase: Diastole
+* Die Herzklappen sind eine Art Rücklaufventile, es gibt 2 verschiedene:
+ ** 2 Segelklappen (AtrioventricularValve): verhindern, dass Blut in der Systole in den Vorhof zurückfliesst.
+ ** 2 Taschenklappen (SemilunarValve): verhindern, dass in der Diastole Blut ins Herz zurückfliesst.
+
+image:Heart_diagram-en.svg.png[pdfwidth=75%, width=600px]
+
+=== Ablauf des Herzschlags
+
+==== Diastole – Blut sammelt sich im Vorhof ("atrium")
+
+* Segelklappen ("atrioventricular valves") öffnen
+* Taschenklappen ("semilunar valves") schliessen
+* Vorhöfe ("atria") entspannen
+* Herzkammern ("ventricle") entspannen
+* Warten auf Systole
+
+==== Systole
+
+* Segelklappen schliessen
+* Taschenklappen öffnen
+* Herzkammern kontrahieren
+* Vorhöfe kontrahieren
+* Warten auf Diastole
+
+Es gibt die folgenden Klassen im Projekt:
+
+image:heartbeat_classdiagram.png[pdfwidth=75%, width=600px]
+
+Darüber hinaus gibt es eine Klasse `HeartTest`, die bereits mehrere Tests implementiert.
+
+Stubs sind nicht sehr intelligent und daher kann man häufig nur oberflächlich mit Stubs testen.
+Sie sollen mit Hilfe von Mock-Objekten die Tests noch gründlicher gestalten.
+
+Die Abhängigkeit für Mockito ist bereits für Sie in build.gradle erfasst worden.
+Studieren Sie kurz in diesem File, wie das gemacht wurde.
+Informationen dazu finden Sie auf der link:{mockito-home} und auf link:{maven-central}.
+
+Studieren bzw. überfliegen Sie bei dieser Gelegenheit auch gerade die link:{mockito-docs}.
+
+
+== Aufgaben
+
+=== Einführung in Mockito [PU]
+[loweralpha]
+. Studieren Sie die Testmethoden `HeartTest::testValveStatus()` und `HeartTest::testExecuteHartBeatErrorBehaviour()`.
+ Dort wird *ein Teil* des Verhaltens des Herzens getestet.
+
+. Implementieren Sie die Methoden `Heart::executeDiastole()`, `Heart::executeSystole()` und `Heart::executeHeartBeat()` sodass die bestehenden Tests durchlaufen und das oben beschriebene Verhalten des Herzens modelliert wird.
+
+. (optional) Ein echtes Herz hat eine Schlagfrequenz.
+Implementieren Sie, dass das Herz nach jeder Systole pausiert.
+Sie können z. B. den aktuellen Thread 1000 ms lang anhalten mit
++
+[source, Java]
+----
+try {
+ Thread.currentThread().sleep(1000);
+} catch (InterruptedException e) {
+ e.printStackTrace();
+}
+----
+
+=== Fragen zu Testing [TU]
+[loweralpha]
+. Testing kann in zwei unterschiedliche Strategien aufgeteilt werden.
+Zum einen gibt es White-Box Testing und zum zweiten Black-Box Testing.
+Was für Java Libraries gibt es um diese zwei Strategien zu testen?
+Wann wenden Sie welche Strategie an?
+
+. Das Erstellen von guten automatisierten Unit-Tests kann manchmal schwierig umzusetzen sein.
+Was ist der Hauptgrund dafür? Wie können Sie dieses Problem entschärfen?
+
+. Der Testfokus war bisher auf der Klasse `Heart`.
+Testen Sie jetzt die Klasse `Half`. Wo verwenden Sie Stubbing, wo Mocking?
+
+=== Vorbedingungen, Exceptions und Callback-Funktionen [PA]
+[loweralpha]
+. Testen Sie, dass beim Ausführen der Diastole und Systole alle Herzklappen in der richtigen Reihenfolge geöffnet und geschlossen werden.
+Implementieren Sie dafür die Methode `HeartTest::testValvesBehavior()` und benutzen Sie die von Mockito bereitgestellte Klasse `InOrder`. +
+Testen Sie auch, dass keine Methode unnötig oft aufgerufen wird (mit der Methode `Inorder::verifyNoMoreInteractions()`). +
+Benutzen Sie mindestens einmal die statische Methode `mock()` und einmal die Annotation `@Mock` von Mockito.
+
+. Die vorhandene Implementation des Testfalls `HeartTest::testExecuteHartBeatErrorBehaviour()` verwendet keine Mock-Objekte für die linke und rechte Herzhälfte.
+Implementieren Sie die Testmethode `HeartTest::testExecuteHartBeatErrorBehaviourWithStubbing()` analog zur bestehenden Variante, aber diesmal setzen Sie entsprechende Mock-Objekte für die Herzhälften ein.
++
+TIP: Für das Stubbing werden Sie die `doThrow`- Methode von Mockito benötigen.
+ Mit Stubbing ist die Konfiguration von Ihrem Mock-Objekt gemeint.
+
+. Die bestehende Implementierung hat einen ungenügenden Exception-Mechanismus.
+Beispielsweise führt die Herzhälfte (`Half`) ihre Methoden aus, auch wenn die notwendigen Vorbedingungen (d.h., die Klappenstellungen von `SemilunarValve` und `AtrioVentricularValve`)
+nicht gelten. +
+Beheben Sie dieses Problem, indem Sie in `Heart::executeDiastole()` und `Heart::executeSystole()` eine `InvalidValvePositionException` werfen,
+falls die notwendigen Vorbedingungen nicht in der korrekten Position (offen, geschlossen) sind. +
+Erstellen Sie zwei Methoden `testDiastoleException()` und `testSystoleException()` und setzen Sie Mocking und Stubbing ein, um diesen Exception-Mechanismus zu testen.
+
+. Die Klasse Pacemaker ist eine Implementation für einen Herzschrittmacher.
+Es ist eine unvollständige Implementation, reduziert auf das Wesentliche für den Inhalt des Praktikums.
+Ihre Aufgabe ist es, die Methode `Pacemaker::setHeartRate` mit zwei vorgegeben Testfällen zu testen. +
+Implementieren Sie Test-Methoden `PacemakerTest::testSetHeartRateRejectsFrequenciesOutOfRange` und `PacemakerTest::testSetHeartRateAppliesFrequenciesInsideRange`. +
+Die beiden Testfälle prüfen die Methode `Pacemaker::setHeartRate` darauf, ob sie korrekt reagiert, wenn das Herz die gewünschte Frequenz im einen Fall anwenden und im anderen Fall nicht anwenden kann.
+In diesem Szenario ist die Klasse `Pacemaker` die Class-Under-Test und die Klasse `Heart` eine Abhängigkeit für `Pacemaker`. +
+Verwenden Sie für die Klasse `Heart` ein entsprechendes Mock-Objekt und stubben Sie das Verhalten gemäss der Spezifikation von der Methode `Heart::setHeartRate()`.
+Eine Voraussetzung ist, dass Sie für beide Testfälle dasselbe Mock-Objekt mit demselben Stubbing verwenden können.
+Die Callback-Methode wird Ihnen dabei eine Hilfe sein.
+
+
+== Abschluss
+Stellen Sie sicher, dass die Tests der Pflichtaufgabe mittels `gradlew test` gestartet werden können und pushen Sie die Lösung vor der Deadline in Ihr Abgaberepository.
+
+
+
diff --git a/code/Herzschlag/build.gradle b/code/Herzschlag/build.gradle
new file mode 100644
index 0000000..ac770a2
--- /dev/null
+++ b/code/Herzschlag/build.gradle
@@ -0,0 +1,74 @@
+/*
+ * This file was generated by the Gradle 'init' task.
+ *
+ * This generated file contains a sample Java application project to get you started.
+ * For more details take a look at the 'Building Java & JVM projects' chapter in the Gradle
+ * User Manual available at https://docs.gradle.org/7.2/userguide/building_java_projects.html
+ */
+
+plugins {
+ // Apply the application plugin to add support for building a CLI application in Java.
+ id 'application'
+}
+
+repositories {
+ // Use Maven Central for resolving dependencies.
+ mavenCentral()
+}
+
+dependencies {
+ // Junit 5 dependencies
+ testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.+'
+ testImplementation 'org.junit.jupiter:junit-jupiter-params:5.8.+'
+ testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.+'
+ // Mockito dependencies
+ testImplementation 'org.mockito:mockito-core:4.3.+'
+}
+
+// Test task configuration
+test {
+ // Use JUnit platform for unit tests
+ useJUnitPlatform()
+ // Output results of individual tests
+ testLogging {
+ events "PASSED", "SKIPPED", "FAILED"
+ }
+}
+
+application {
+ // Define the main class for the application.
+ mainClass = 'ch.zhaw.prog2.heartbeat.Heart'
+}
+
+// Java plugin configuration
+java {
+ // By default the Java version of the gradle process is used as source/target version.
+ // This can be overridden, to ensure a specific version. Enable only if required.
+ // sourceCompatibility = JavaVersion.VERSION_17 // ensure Java source code compatibility
+ // targetCompatibility = JavaVersion.VERSION_17 // version of the created byte-code
+
+ // Java compiler specific options
+ compileJava {
+ // source files should be UTF-8 encoded
+ options.encoding = 'UTF-8'
+ // for more options see https://docs.gradle.org/current/dsl/org.gradle.api.tasks.compile.CompileOptions.html
+ }
+}
+
+task autograding(type: Test) {
+ description = "Runs specific tests for autograding"
+ group = 'verification'
+
+ useJUnitPlatform()
+ testLogging {
+ events "PASSED", "SKIPPED", "FAILED"
+ }
+ filter {
+ failOnNoMatchingTests true
+ includeTestsMatching "PacemakerTest"
+ includeTestsMatching "HeartTest.testExecuteHartBeatErrorBehaviourWithStubbing"
+ includeTestsMatching "HeartTest.testValvesBehavior"
+ includeTestsMatching "HeartTest.testDiastoleException"
+ includeTestsMatching "HeartTest.testSystoleException"
+ }
+}
diff --git a/code/Herzschlag/src/main/java/ch/zhaw/prog2/heartbeat/Half.java b/code/Herzschlag/src/main/java/ch/zhaw/prog2/heartbeat/Half.java
new file mode 100644
index 0000000..e7bd3c5
--- /dev/null
+++ b/code/Herzschlag/src/main/java/ch/zhaw/prog2/heartbeat/Half.java
@@ -0,0 +1,100 @@
+package ch.zhaw.prog2.heartbeat;
+
+import ch.zhaw.prog2.heartbeat.parts.*;
+
+/**
+ * Represents one half of a heart.
+ *
+ * @author wahl, muon
+ */
+public class Half {
+
+ public enum Side {LEFT, RIGHT}
+
+ private Atrium atrium; // "Vorhof"
+ private Ventricle ventricle; // "Herzkammer"
+ private AtrioventricularValve atrioventricularValve; // "Segelklappe"
+ private SemilunarValve semilunarValve; // "Taschenklappe"
+ private final Side side;
+
+ public Half(Side side) {
+ this.side = side;
+ atrium = new Atrium(side);
+ ventricle = new Ventricle(side);
+ atrioventricularValve = new AtrioventricularValve(side);
+ semilunarValve = new SemilunarValve(side);
+ }
+
+ public void initializeState(Heart.State state) {
+ atrioventricularValve.initializeState(state);
+ semilunarValve.initializeState(state);
+ }
+
+ public AtrioventricularValve getAtrioventricularValve() {
+ return atrioventricularValve;
+ }
+
+ public SemilunarValve getSemilunarValve() {
+ return semilunarValve;
+ }
+
+ public boolean isAtrioventricularValveOpen() {
+ return atrioventricularValve.isOpen();
+ }
+
+ public boolean isSemilunarValveOpen() {
+ return semilunarValve.isOpen();
+ }
+
+ /**
+ * Closes the valve
+ *
+ * @throws IllegalStateException when valve is already closed
+ */
+ public void closeSemilunarValve() throws Valve.IllegalValveStateException {
+ semilunarValve.close();
+ }
+
+ /**
+ * Opens the valve
+ *
+ * @throws Valve.IllegalValveStateException when the valve is already open
+ */
+ public void openSemilunarValve() throws Valve.IllegalValveStateException {
+ semilunarValve.open();
+ }
+
+ /**
+ * Closes the valve
+ *
+ * @throws Valve.IllegalValveStateException when valve is already closed
+ */
+ public void closeAtrioventricularValve() throws Valve.IllegalValveStateException {
+ atrioventricularValve.close();
+ }
+
+ /**
+ * Opens the valve
+ *
+ * @throws Valve.IllegalValveStateException when the valve is already open
+ */
+ public void openAtrioventricularValve() throws Valve.IllegalValveStateException {
+ atrioventricularValve.open();
+ }
+
+ public void contractVentricle() {
+ ventricle.contract();
+ }
+
+ public void relaxVentricle() {
+ ventricle.relax();
+ }
+
+ public void contractAtrium() {
+ atrium.contract();
+ }
+
+ public void relaxAtrium() {
+ atrium.relax();
+ }
+}
diff --git a/code/Herzschlag/src/main/java/ch/zhaw/prog2/heartbeat/Heart.java b/code/Herzschlag/src/main/java/ch/zhaw/prog2/heartbeat/Heart.java
new file mode 100644
index 0000000..d7df62c
--- /dev/null
+++ b/code/Herzschlag/src/main/java/ch/zhaw/prog2/heartbeat/Heart.java
@@ -0,0 +1,145 @@
+package ch.zhaw.prog2.heartbeat;
+
+import ch.zhaw.prog2.heartbeat.parts.Valve;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class represents a human heart (https://en.wikipedia.org/wiki/Heart).
+ *
+ *
+ * Example tests: before Chamber::contract() is called, the atrioventricular
+ * valves must be closed.
+ *
+ * @author wahl
+ */
+public class Heart {
+ private final static int AVERAGE_HEART_RATE = 60;
+
+ /**
+ * Encodes the states of the heart
+ *
+ * @author wahl
+ */
+ public enum State {
+ SYSTOLE, DIASTOLE
+ }
+
+ private List halves;
+ private State state;
+ private int heartRate;
+
+ /**
+ * The default constructor calls the more specific constructor with a new left
+ * and right half.
+ */
+ public Heart() {
+ this(new Half(Half.Side.LEFT), new Half(Half.Side.RIGHT));
+ }
+
+ /**
+ * The default constructor adds the left and the right half that are specified
+ * as parameters and sets the start state to diastole.
+ */
+ public Heart(Half leftHalf, Half rightHalf) {
+ state = State.DIASTOLE;
+ heartRate = AVERAGE_HEART_RATE;
+ halves = new ArrayList<>();
+ halves.add(leftHalf);
+ halves.add(rightHalf);
+ initalizeState();
+ }
+
+ public void initalizeState(){
+ for(Half half : halves){
+ half.initializeState(state);
+ }
+ }
+
+ /**
+ * Executes a sequence of diastole and systole, beginning with the current
+ * state.
+ *
+ * @throws HeartBeatDysfunctionException when Valve.IllegalValveStateException or
+ * InvalidValvePositionException occurs during diastole or systole
+ * TODO Implement a pause mechanism based on the current heart rate
+ */
+ public void executeHeartBeat() throws HeartBeatDysfunctionException{
+ //TODO implement
+ }
+
+ /**
+ * Executes the diastole phase of the heart.
+ *
+ * @throws Valve.IllegalValveStateException when one of the valves has an illegal State
+ */
+ public void executeDiastole() {
+ //TODO implement
+ }
+
+ /**
+ * Executes the systole phase of the heart.
+ *
+ * @throws Valve.IllegalValveStateException when one of the valves has an illegal State
+ */
+ public void executeSystole() {
+ //TODO implement
+ }
+
+ public State getState() {
+ return state;
+ }
+
+ public void setState(State state) {
+ this.state = state;
+ }
+
+ /**
+ * Sets the heart rate to the parameter value in Hz.
+ * Rate has to be inside range >30 && <220
+ * If rate is outside of range method rejects the change
+ * and returns false.
+ *
+ * @param frequencyInHz which should be applied to the heart
+ * @return true if the heart rate could be set, false otherwise
+ */
+ public boolean setHeartRate(int frequencyInHz) {
+ if (frequencyInHz < 30 || frequencyInHz > 220) {
+ return false;
+ }
+ this.heartRate = frequencyInHz;
+ return true;
+ }
+
+ public int getHeartRate() {
+ return heartRate;
+ }
+
+ public List getHalves() {
+ return halves;
+ }
+
+ public static class HeartBeatDysfunctionException extends Exception {
+ public HeartBeatDysfunctionException() {
+ }
+
+ public HeartBeatDysfunctionException(String message) {
+ super(message);
+ }
+
+ public HeartBeatDysfunctionException(String message, Throwable cause) {
+ super(message, cause);
+ }
+ }
+
+ /**
+ * The main method instantiates a heart object and executes a single heartbeat.
+ *
+ * @param args
+ */
+ public static void main(String[] args) throws HeartBeatDysfunctionException {
+ Heart heart = new Heart();
+ heart.executeHeartBeat();
+ }
+}
diff --git a/code/Herzschlag/src/main/java/ch/zhaw/prog2/heartbeat/Pacemaker.java b/code/Herzschlag/src/main/java/ch/zhaw/prog2/heartbeat/Pacemaker.java
new file mode 100644
index 0000000..f0e1feb
--- /dev/null
+++ b/code/Herzschlag/src/main/java/ch/zhaw/prog2/heartbeat/Pacemaker.java
@@ -0,0 +1,44 @@
+package ch.zhaw.prog2.heartbeat;
+/**
+ * This class represents a pacemaker for a human hart.
+ *
+ * This is an incomplete implementation, reduced to the essentials for the content of the lab.
+ * There would be a lot more code needed to implement a pacemaker, but this is not part of this lab :-)
+ *
+ * @author muon
+ *
+ */
+public class Pacemaker {
+ Heart heart;
+
+ /**
+ * Constructor of Pacemaker
+ * @param heart
+ */
+ public Pacemaker(Heart heart) {
+ this.heart = heart;
+ }
+
+ /**
+ * Sets the heart rate to the parameter value in Hz.
+ * Rate has to be inside range >30 && <220
+ * If frequency can be applied on heart, the current frequency will be returned.
+ * If heart does reject the change the method throws an exception.
+ *
+ * @param frequencyInHz needs to be applied on heart
+ * @return current frequency of the heart
+ * @throws IllegalArgumentException when heart does reject the change
+ */
+ public int setHeartRate(int frequencyInHz) {
+ if(heart.setHeartRate(frequencyInHz) == false){
+ throw new IllegalArgumentException("Frequency could not be set.");
+ }
+ return heart.getHeartRate();
+ }
+
+ /*
+ ...
+ There would be a lot more code needed to implement a pacemaker, but this is not part of this lab :-)
+ ...
+ */
+}
diff --git a/code/Herzschlag/src/main/java/ch/zhaw/prog2/heartbeat/parts/AtrioventricularValve.java b/code/Herzschlag/src/main/java/ch/zhaw/prog2/heartbeat/parts/AtrioventricularValve.java
new file mode 100644
index 0000000..480d4c5
--- /dev/null
+++ b/code/Herzschlag/src/main/java/ch/zhaw/prog2/heartbeat/parts/AtrioventricularValve.java
@@ -0,0 +1,19 @@
+package ch.zhaw.prog2.heartbeat.parts;
+
+import ch.zhaw.prog2.heartbeat.Half.Side;
+import ch.zhaw.prog2.heartbeat.Heart;
+
+public class AtrioventricularValve extends Valve {
+
+ public AtrioventricularValve(Side side) {
+ super (side);
+ }
+
+ public void initializeState(Heart.State state) {
+ if(Heart.State.DIASTOLE.equals(state)){
+ setOpen(false);
+ }else{
+ setOpen(true);
+ }
+ }
+}
diff --git a/code/Herzschlag/src/main/java/ch/zhaw/prog2/heartbeat/parts/Atrium.java b/code/Herzschlag/src/main/java/ch/zhaw/prog2/heartbeat/parts/Atrium.java
new file mode 100644
index 0000000..5db2e3c
--- /dev/null
+++ b/code/Herzschlag/src/main/java/ch/zhaw/prog2/heartbeat/parts/Atrium.java
@@ -0,0 +1,20 @@
+package ch.zhaw.prog2.heartbeat.parts;
+
+import ch.zhaw.prog2.heartbeat.Half.Side;
+
+public class Atrium {
+ private Side side;
+
+ public Atrium (Side side) {
+ this.side = side;
+ }
+
+ public void contract() {
+ System.out.println("Atrium "+ side + " is contracting.");
+ }
+
+ public void relax() {
+ System.out.println("Atrium "+ side + " is relaxing.");
+ }
+
+}
diff --git a/code/Herzschlag/src/main/java/ch/zhaw/prog2/heartbeat/parts/SemilunarValve.java b/code/Herzschlag/src/main/java/ch/zhaw/prog2/heartbeat/parts/SemilunarValve.java
new file mode 100644
index 0000000..4f19597
--- /dev/null
+++ b/code/Herzschlag/src/main/java/ch/zhaw/prog2/heartbeat/parts/SemilunarValve.java
@@ -0,0 +1,20 @@
+package ch.zhaw.prog2.heartbeat.parts;
+
+import ch.zhaw.prog2.heartbeat.Half.Side;
+import ch.zhaw.prog2.heartbeat.Heart;
+
+public class SemilunarValve extends Valve {
+
+ public SemilunarValve(Side side) {
+ super (side);
+ }
+
+ public void initializeState(Heart.State state) {
+ if(Heart.State.DIASTOLE.equals(state)){
+ setOpen(true);
+ }else{
+ setOpen(false);
+ }
+ }
+
+}
diff --git a/code/Herzschlag/src/main/java/ch/zhaw/prog2/heartbeat/parts/Valve.java b/code/Herzschlag/src/main/java/ch/zhaw/prog2/heartbeat/parts/Valve.java
new file mode 100644
index 0000000..ae1a22d
--- /dev/null
+++ b/code/Herzschlag/src/main/java/ch/zhaw/prog2/heartbeat/parts/Valve.java
@@ -0,0 +1,61 @@
+package ch.zhaw.prog2.heartbeat.parts;
+
+import ch.zhaw.prog2.heartbeat.Half.Side;
+
+public abstract class Valve {
+
+ private boolean open;
+ private Side side;
+
+ public Valve(Side side) {
+ this.side = side;
+ }
+
+ /**
+ * Opens the valve
+ *
+ * @throws IllegalValveStateException when the valve is already open
+ */
+ public void open() throws IllegalValveStateException {
+ if (open) {
+ throw new IllegalValveStateException(this.getClass().getSimpleName() + " " + side + " valve is already open.");
+ }
+ System.out.println(this.getClass().getSimpleName() + " " + side + " is opening.");
+ open = true;
+ }
+
+ /**
+ * Closes the valve
+ *
+ * @throws IllegalValveStateException when valve is already closed
+ */
+ public void close() throws IllegalValveStateException {
+ if (!open) {
+ throw new IllegalValveStateException(this.getClass().getSimpleName() + " " + side + " valve is already closed.");
+ }
+ System.out.println(this.getClass().getSimpleName() + " " + side + " is closing.");
+ open = false;
+ }
+
+ public boolean isOpen() {
+ return open;
+ }
+
+ protected void setOpen(Boolean open) {
+ this.open = open;
+ }
+
+ public static class IllegalValveStateException extends Exception {
+
+ public IllegalValveStateException() {
+ }
+
+ public IllegalValveStateException(String message) {
+ super(message);
+ }
+
+ public IllegalValveStateException(String message, Throwable cause) {
+ super(message, cause);
+ }
+ }
+}
diff --git a/code/Herzschlag/src/main/java/ch/zhaw/prog2/heartbeat/parts/Ventricle.java b/code/Herzschlag/src/main/java/ch/zhaw/prog2/heartbeat/parts/Ventricle.java
new file mode 100644
index 0000000..8b03e9b
--- /dev/null
+++ b/code/Herzschlag/src/main/java/ch/zhaw/prog2/heartbeat/parts/Ventricle.java
@@ -0,0 +1,20 @@
+package ch.zhaw.prog2.heartbeat.parts;
+
+import ch.zhaw.prog2.heartbeat.Half.Side;
+
+public class Ventricle {
+ private Side side;
+
+ public Ventricle (Side side) {
+ this.side = side;
+ }
+
+ public void contract() {
+ System.out.println("Chamber "+ side + " is contracting.");
+ }
+
+ public void relax() {
+ System.out.println("Chamber "+ side + " is relaxing.");
+ }
+
+}
diff --git a/code/Herzschlag/src/test/java/ch/zhaw/prog2/heartbeat/HeartTest.java b/code/Herzschlag/src/test/java/ch/zhaw/prog2/heartbeat/HeartTest.java
new file mode 100644
index 0000000..d3b7968
--- /dev/null
+++ b/code/Herzschlag/src/test/java/ch/zhaw/prog2/heartbeat/HeartTest.java
@@ -0,0 +1,100 @@
+/*
+ * Test Class for Heart
+ */
+package ch.zhaw.prog2.heartbeat;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+import ch.zhaw.prog2.heartbeat.parts.Valve;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+
+import ch.zhaw.prog2.heartbeat.Heart.State;
+
+class HeartTest {
+ /**
+ * This is a very simple test to check if Junit and Mockito are properly set up.
+ */
+ @Test
+ void testTheTest() {
+ Heart classUnderTest = new Heart();
+ assertNotNull(classUnderTest.getState(), "The heart must have a state.");
+ }
+
+ /**
+ * Tests a single heartbeat
+ */
+ @Test
+ void testHeartBeat() throws Heart.HeartBeatDysfunctionException {
+ Heart heart = new Heart();
+ State startState = heart.getState();
+
+ heart.executeHeartBeat();
+
+ // after one heartbeat, the heart must be in the same state as before
+ assertEquals(startState, heart.getState());
+ }
+
+ /**
+ * Tests if the valves are open or closed depending on the status of the heart
+ */
+ @Test
+ void testValveStatus() throws Heart.HeartBeatDysfunctionException {
+ Heart heart = new Heart();
+
+ heart.executeHeartBeat();
+
+ State state = heart.getState();
+
+ if (state.equals(Heart.State.DIASTOLE)) {
+ for (Half half : heart.getHalves()) {
+ assertFalse(half.isAtrioventricularValveOpen());
+ assertTrue(half.isSemilunarValveOpen());
+ }
+ } else if ((state.equals(Heart.State.SYSTOLE))) {
+ for (Half half : heart.getHalves()) {
+ assertTrue(half.isAtrioventricularValveOpen());
+ assertFalse(half.isSemilunarValveOpen());
+ }
+ }
+ }
+
+ /**
+ * Tests if the hart throws the appropriate Exception, when malfunction was detected during hartBeat
+ */
+ @Test
+ void testExecuteHeartBeatErrorBehaviour() {
+ Heart heart = new Heart();
+ // prepare error situation due to wrong initialization
+ heart.setState(State.SYSTOLE);
+
+ assertThrows(Heart.HeartBeatDysfunctionException .class, // verification using lambda
+ () -> heart.executeHeartBeat());
+ }
+
+ /**
+ * Tests if the hart throws the appropriate Exception, when malfunction was detected during hartBeat
+ * with exception Stubbing
+ */
+ @Test
+ void testExecuteHartBeatErrorBehaviourWithStubbing() throws Valve.IllegalValveStateException {
+ //TODO implement
+ fail();
+ }
+
+ /**
+ * We test if Heart::executeHeartbeat() sends the right signals to both of its
+ * halves.
+ *
+ * When Half::contractVentricle() is called, Half::closeAtrioventricularValve()
+ * and Half::openSemilunarValve() must have been called earlier.
+ *
+ */
+ @Test
+ void testValvesBehavior() {
+ //TODO implement
+ fail();
+ }
+
+}
diff --git a/code/Herzschlag/src/test/java/ch/zhaw/prog2/heartbeat/PacemakerTest.java b/code/Herzschlag/src/test/java/ch/zhaw/prog2/heartbeat/PacemakerTest.java
new file mode 100644
index 0000000..52d353f
--- /dev/null
+++ b/code/Herzschlag/src/test/java/ch/zhaw/prog2/heartbeat/PacemakerTest.java
@@ -0,0 +1,30 @@
+package ch.zhaw.prog2.heartbeat;
+
+import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.*;
+
+/*
+ * Test Class for Pacemaker
+ */
+public class PacemakerTest {
+
+ /**
+ * Test if setHeartRate does throw correct exception when rate is rejected (because frequency is out of range)
+ */
+ @Test
+ void testSetHeartRateRejectsFrequenciesOutOfRange() {
+ //TODO implement
+ fail();
+ }
+
+
+ /**
+ * Test if setHeartRate does correctly set the rate when frequency is inside range
+ */
+ @Test
+ void testSetHeartRateAppliesFrequenciesInsideRange() {
+ //TODO implement
+ fail();
+ }
+
+}
diff --git a/gradle.properties b/gradle.properties
new file mode 100644
index 0000000..1b09d63
--- /dev/null
+++ b/gradle.properties
@@ -0,0 +1,7 @@
+# Used to set properties for gradle builds
+# (see https://dev.to/jmfayard/configuring-gradle-with-gradle-properties-211k)
+
+# gradle configuration
+# (https://docs.gradle.org/current/userguide/build_environment.html#sec:gradle_configuration_properties)
+#org.gradle.warning.mode=(all,fail,summary,none) default: summary
+org.gradle.warning.mode=all
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..41d9927
Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..41dfb87
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
new file mode 100755
index 0000000..1b6c787
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,234 @@
+#!/bin/sh
+
+#
+# Copyright © 2015-2021 the original authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+#
+# Gradle start up script for POSIX generated by Gradle.
+#
+# Important for running:
+#
+# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+# noncompliant, but you have some other compliant shell such as ksh or
+# bash, then to run this script, type that shell name before the whole
+# command line, like:
+#
+# ksh Gradle
+#
+# Busybox and similar reduced shells will NOT work, because this script
+# requires all of these POSIX shell features:
+# * functions;
+# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+# * compound commands having a testable exit status, especially «case»;
+# * various built-in commands including «command», «set», and «ulimit».
+#
+# Important for patching:
+#
+# (2) This script targets any POSIX shell, so it avoids extensions provided
+# by Bash, Ksh, etc; in particular arrays are avoided.
+#
+# The "traditional" practice of packing multiple parameters into a
+# space-separated string is a well documented source of bugs and security
+# problems, so this is (mostly) avoided, by progressively accumulating
+# options in "$@", and eventually passing that to Java.
+#
+# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+# see the in-line comments for details.
+#
+# There are tweaks for specific operating systems such as AIX, CygWin,
+# Darwin, MinGW, and NonStop.
+#
+# (3) This script is generated from the Groovy template
+# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# within the Gradle project.
+#
+# You can find Gradle at https://github.com/gradle/gradle/.
+#
+##############################################################################
+
+# Attempt to set APP_HOME
+
+# Resolve links: $0 may be a link
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+ APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
+ [ -h "$app_path" ]
+do
+ ls=$( ls -ld "$app_path" )
+ link=${ls#*' -> '}
+ case $link in #(
+ /*) app_path=$link ;; #(
+ *) app_path=$APP_HOME$link ;;
+ esac
+done
+
+APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
+
+APP_NAME="Gradle"
+APP_BASE_NAME=${0##*/}
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD=maximum
+
+warn () {
+ echo "$*"
+} >&2
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+} >&2
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "$( uname )" in #(
+ CYGWIN* ) cygwin=true ;; #(
+ Darwin* ) darwin=true ;; #(
+ MSYS* | MINGW* ) msys=true ;; #(
+ NONSTOP* ) nonstop=true ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD=$JAVA_HOME/jre/sh/java
+ else
+ JAVACMD=$JAVA_HOME/bin/java
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD=java
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+ case $MAX_FD in #(
+ max*)
+ MAX_FD=$( ulimit -H -n ) ||
+ warn "Could not query maximum file descriptor limit"
+ esac
+ case $MAX_FD in #(
+ '' | soft) :;; #(
+ *)
+ ulimit -n "$MAX_FD" ||
+ warn "Could not set maximum file descriptor limit to $MAX_FD"
+ esac
+fi
+
+# Collect all arguments for the java command, stacking in reverse order:
+# * args from the command line
+# * the main class name
+# * -classpath
+# * -D...appname settings
+# * --module-path (only if needed)
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if "$cygwin" || "$msys" ; then
+ APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+ CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
+
+ JAVACMD=$( cygpath --unix "$JAVACMD" )
+
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ for arg do
+ if
+ case $arg in #(
+ -*) false ;; # don't mess with options #(
+ /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
+ [ -e "$t" ] ;; #(
+ *) false ;;
+ esac
+ then
+ arg=$( cygpath --path --ignore --mixed "$arg" )
+ fi
+ # Roll the args list around exactly as many times as the number of
+ # args, so each arg winds up back in the position where it started, but
+ # possibly modified.
+ #
+ # NB: a `for` loop captures its iteration list before it begins, so
+ # changing the positional parameters here affects neither the number of
+ # iterations, nor the values presented in `arg`.
+ shift # remove old arg
+ set -- "$@" "$arg" # push replacement arg
+ done
+fi
+
+# Collect all arguments for the java command;
+# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
+# shell script including quotes and variable substitutions, so put them in
+# double quotes to make sure that they get re-expanded; and
+# * put everything else in single quotes, so that it's not re-expanded.
+
+set -- \
+ "-Dorg.gradle.appname=$APP_BASE_NAME" \
+ -classpath "$CLASSPATH" \
+ org.gradle.wrapper.GradleWrapperMain \
+ "$@"
+
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+# set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
+
+eval "set -- $(
+ printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+ xargs -n1 |
+ sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+ tr '\n' ' '
+ )" '"$@"'
+
+exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 0000000..107acd3
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,89 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/images/Heart_diagram-en.svg.png b/images/Heart_diagram-en.svg.png
new file mode 100644
index 0000000..3cc1272
Binary files /dev/null and b/images/Heart_diagram-en.svg.png differ
diff --git a/images/PROG2-300x300.png b/images/PROG2-300x300.png
new file mode 100644
index 0000000..584dd90
Binary files /dev/null and b/images/PROG2-300x300.png differ
diff --git a/images/heartbeat_classdiagram.png b/images/heartbeat_classdiagram.png
new file mode 100644
index 0000000..4f398b1
Binary files /dev/null and b/images/heartbeat_classdiagram.png differ
diff --git a/settings.gradle b/settings.gradle
new file mode 100644
index 0000000..b69a234
--- /dev/null
+++ b/settings.gradle
@@ -0,0 +1,45 @@
+/*
+ * Dynamic Multi-Module project structure
+ * automatically adds each exercise as a sub-project (module)
+ */
+
+// use current directory name as root project name
+rootProject.name = file('.').name
+
+// dynamically add sub-projects in handout folder
+File handoutDir = file('code')
+if (handoutDir.isDirectory()) {
+ handoutDir.eachDir { dir ->
+ String subProjectName = ":${dir.name}"
+ include(subProjectName)
+ project(subProjectName).projectDir = dir
+ }
+}
+
+// dynamically add sub-projects in solutions* folders
+//List solutionDirs = List.of(file('.').listFiles((File dir, String name) -> name.startsWith("solutions")))
+file('.').eachDirMatch( name -> name.startsWith('solutions')) { solutionDir ->
+ if (solutionDir.isDirectory()) {
+ solutionDir.eachDir { dir ->
+ if (!dir.name.equals('images')) {
+ String subProjectName = ":${dir.name}-sol"
+ include(subProjectName)
+ project(subProjectName).projectDir = dir
+ }
+ }
+ }
+}
+
+// lab preparation tasks
+File classroomDir = file('classroom')
+if (classroomDir.isDirectory()) {
+ String subProjectName = ":${classroomDir.name}"
+ include(subProjectName)
+}
+
+// Example: manually adding sub-project with name == folder
+//include 'module1'
+
+// Example: manually adding sub-projects with different name & folder
+//include(':lab00-module1')
+//project(':lab00-module1').projectDir = file('handout/module1')
\ No newline at end of file
diff --git a/solutions-exercises/Herzschlag/build.gradle b/solutions-exercises/Herzschlag/build.gradle
new file mode 100644
index 0000000..ac770a2
--- /dev/null
+++ b/solutions-exercises/Herzschlag/build.gradle
@@ -0,0 +1,74 @@
+/*
+ * This file was generated by the Gradle 'init' task.
+ *
+ * This generated file contains a sample Java application project to get you started.
+ * For more details take a look at the 'Building Java & JVM projects' chapter in the Gradle
+ * User Manual available at https://docs.gradle.org/7.2/userguide/building_java_projects.html
+ */
+
+plugins {
+ // Apply the application plugin to add support for building a CLI application in Java.
+ id 'application'
+}
+
+repositories {
+ // Use Maven Central for resolving dependencies.
+ mavenCentral()
+}
+
+dependencies {
+ // Junit 5 dependencies
+ testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.+'
+ testImplementation 'org.junit.jupiter:junit-jupiter-params:5.8.+'
+ testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.+'
+ // Mockito dependencies
+ testImplementation 'org.mockito:mockito-core:4.3.+'
+}
+
+// Test task configuration
+test {
+ // Use JUnit platform for unit tests
+ useJUnitPlatform()
+ // Output results of individual tests
+ testLogging {
+ events "PASSED", "SKIPPED", "FAILED"
+ }
+}
+
+application {
+ // Define the main class for the application.
+ mainClass = 'ch.zhaw.prog2.heartbeat.Heart'
+}
+
+// Java plugin configuration
+java {
+ // By default the Java version of the gradle process is used as source/target version.
+ // This can be overridden, to ensure a specific version. Enable only if required.
+ // sourceCompatibility = JavaVersion.VERSION_17 // ensure Java source code compatibility
+ // targetCompatibility = JavaVersion.VERSION_17 // version of the created byte-code
+
+ // Java compiler specific options
+ compileJava {
+ // source files should be UTF-8 encoded
+ options.encoding = 'UTF-8'
+ // for more options see https://docs.gradle.org/current/dsl/org.gradle.api.tasks.compile.CompileOptions.html
+ }
+}
+
+task autograding(type: Test) {
+ description = "Runs specific tests for autograding"
+ group = 'verification'
+
+ useJUnitPlatform()
+ testLogging {
+ events "PASSED", "SKIPPED", "FAILED"
+ }
+ filter {
+ failOnNoMatchingTests true
+ includeTestsMatching "PacemakerTest"
+ includeTestsMatching "HeartTest.testExecuteHartBeatErrorBehaviourWithStubbing"
+ includeTestsMatching "HeartTest.testValvesBehavior"
+ includeTestsMatching "HeartTest.testDiastoleException"
+ includeTestsMatching "HeartTest.testSystoleException"
+ }
+}
diff --git a/solutions-exercises/Herzschlag/src/main/java/ch/zhaw/prog2/heartbeat/Half.java b/solutions-exercises/Herzschlag/src/main/java/ch/zhaw/prog2/heartbeat/Half.java
new file mode 100644
index 0000000..e7bd3c5
--- /dev/null
+++ b/solutions-exercises/Herzschlag/src/main/java/ch/zhaw/prog2/heartbeat/Half.java
@@ -0,0 +1,100 @@
+package ch.zhaw.prog2.heartbeat;
+
+import ch.zhaw.prog2.heartbeat.parts.*;
+
+/**
+ * Represents one half of a heart.
+ *
+ * @author wahl, muon
+ */
+public class Half {
+
+ public enum Side {LEFT, RIGHT}
+
+ private Atrium atrium; // "Vorhof"
+ private Ventricle ventricle; // "Herzkammer"
+ private AtrioventricularValve atrioventricularValve; // "Segelklappe"
+ private SemilunarValve semilunarValve; // "Taschenklappe"
+ private final Side side;
+
+ public Half(Side side) {
+ this.side = side;
+ atrium = new Atrium(side);
+ ventricle = new Ventricle(side);
+ atrioventricularValve = new AtrioventricularValve(side);
+ semilunarValve = new SemilunarValve(side);
+ }
+
+ public void initializeState(Heart.State state) {
+ atrioventricularValve.initializeState(state);
+ semilunarValve.initializeState(state);
+ }
+
+ public AtrioventricularValve getAtrioventricularValve() {
+ return atrioventricularValve;
+ }
+
+ public SemilunarValve getSemilunarValve() {
+ return semilunarValve;
+ }
+
+ public boolean isAtrioventricularValveOpen() {
+ return atrioventricularValve.isOpen();
+ }
+
+ public boolean isSemilunarValveOpen() {
+ return semilunarValve.isOpen();
+ }
+
+ /**
+ * Closes the valve
+ *
+ * @throws IllegalStateException when valve is already closed
+ */
+ public void closeSemilunarValve() throws Valve.IllegalValveStateException {
+ semilunarValve.close();
+ }
+
+ /**
+ * Opens the valve
+ *
+ * @throws Valve.IllegalValveStateException when the valve is already open
+ */
+ public void openSemilunarValve() throws Valve.IllegalValveStateException {
+ semilunarValve.open();
+ }
+
+ /**
+ * Closes the valve
+ *
+ * @throws Valve.IllegalValveStateException when valve is already closed
+ */
+ public void closeAtrioventricularValve() throws Valve.IllegalValveStateException {
+ atrioventricularValve.close();
+ }
+
+ /**
+ * Opens the valve
+ *
+ * @throws Valve.IllegalValveStateException when the valve is already open
+ */
+ public void openAtrioventricularValve() throws Valve.IllegalValveStateException {
+ atrioventricularValve.open();
+ }
+
+ public void contractVentricle() {
+ ventricle.contract();
+ }
+
+ public void relaxVentricle() {
+ ventricle.relax();
+ }
+
+ public void contractAtrium() {
+ atrium.contract();
+ }
+
+ public void relaxAtrium() {
+ atrium.relax();
+ }
+}
diff --git a/solutions-exercises/Herzschlag/src/main/java/ch/zhaw/prog2/heartbeat/Heart.java b/solutions-exercises/Herzschlag/src/main/java/ch/zhaw/prog2/heartbeat/Heart.java
new file mode 100644
index 0000000..a0c293b
--- /dev/null
+++ b/solutions-exercises/Herzschlag/src/main/java/ch/zhaw/prog2/heartbeat/Heart.java
@@ -0,0 +1,168 @@
+package ch.zhaw.prog2.heartbeat;
+
+import ch.zhaw.prog2.heartbeat.parts.Valve;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class represents a human heart (https://en.wikipedia.org/wiki/Heart).
+ *
+ *
+ * Example tests: before Chamber::contract() is called, the atrioventricular
+ * valves must be closed.
+ *
+ * @author wahl
+ */
+public class Heart {
+ private final static int AVERAGE_HEART_RATE = 60;
+
+ /**
+ * Encodes the states of the heart
+ *
+ * @author wahl
+ */
+ public enum State {
+ SYSTOLE, DIASTOLE
+ }
+
+ private List halves;
+ private State state;
+ private int heartRate;
+
+ /**
+ * The default constructor calls the more specific constructor with a new left
+ * and right half.
+ */
+ public Heart() {
+ this(new Half(Half.Side.LEFT), new Half(Half.Side.RIGHT));
+ }
+
+ /**
+ * The default constructor adds the left and the right half that are specified
+ * as parameters and sets the start state to diastole.
+ */
+ public Heart(Half leftHalf, Half rightHalf) {
+ state = State.DIASTOLE;
+ heartRate = AVERAGE_HEART_RATE;
+ halves = new ArrayList<>();
+ halves.add(leftHalf);
+ halves.add(rightHalf);
+ initalizeState();
+ }
+
+ public void initalizeState(){
+ for(Half half : halves){
+ half.initializeState(state);
+ }
+ }
+
+ /**
+ * Executes a sequence of diastole and systole, beginning with the current
+ * state.
+ *
+ * @throws HeartBeatDysfunctionException when Valve.IllegalValveStateException or
+ * InvalidValvePositionException occurs during diastole or systole
+ * TODO Implement a pause mechanism based on the current heart rate
+ */
+ public void executeHeartBeat() throws HeartBeatDysfunctionException {
+ try {
+ if (state.equals(State.DIASTOLE)) {
+ executeDiastole();
+ executeSystole();
+ } else {
+ executeSystole();
+ executeDiastole();
+ }
+ } catch (Valve.IllegalValveStateException | InvalidValvePositionException e) {
+ System.out.println(e.getMessage());
+ throw new HeartBeatDysfunctionException("Heart is in an invalid state!", e);
+ }
+ }
+
+ /**
+ * Executes the diastole phase of the heart.
+ *
+ * @throws Valve.IllegalValveStateException when one of the valves has an illegal State
+ */
+ public void executeDiastole() throws Valve.IllegalValveStateException {
+ for (Half half : halves) {
+ half.closeSemilunarValve();
+ half.openAtrioventricularValve();
+ half.relaxAtrium();
+ half.relaxVentricle();
+ }
+ state = State.SYSTOLE;
+ }
+
+ /**
+ * Executes the systole phase of the heart.
+ *
+ * @throws Valve.IllegalValveStateException when one of the valves has an illegal State
+ */
+ public void executeSystole() throws Valve.IllegalValveStateException {
+ for (Half half : halves) {
+ half.openSemilunarValve();
+ half.closeAtrioventricularValve();
+ half.contractAtrium();
+ half.contractVentricle();
+ }
+ state = State.DIASTOLE;
+ }
+
+ public State getState() {
+ return state;
+ }
+
+ public void setState(State state) {
+ this.state = state;
+ }
+
+ /**
+ * Sets the heart rate to the parameter value in Hz.
+ * Rate has to be inside range >30 && <220
+ * If rate is outside of range method rejects the change
+ * and returns false.
+ *
+ * @param frequencyInHz which should be applied to the heart
+ * @return true if the heart rate could be set, false otherwise
+ */
+ public boolean setHeartRate(int frequencyInHz) {
+ if (frequencyInHz < 30 || frequencyInHz > 220) {
+ return false;
+ }
+ this.heartRate = frequencyInHz;
+ return true;
+ }
+
+ public int getHeartRate() {
+ return heartRate;
+ }
+
+ public List getHalves() {
+ return halves;
+ }
+
+ public static class HeartBeatDysfunctionException extends Exception {
+ public HeartBeatDysfunctionException() {
+ }
+
+ public HeartBeatDysfunctionException(String message) {
+ super(message);
+ }
+
+ public HeartBeatDysfunctionException(String message, Throwable cause) {
+ super(message, cause);
+ }
+ }
+
+ /**
+ * The main method instantiates a heart object and executes a single heartbeat.
+ *
+ * @param args
+ */
+ public static void main(String[] args) throws HeartBeatDysfunctionException {
+ Heart heart = new Heart();
+ heart.executeHeartBeat();
+ }
+}
diff --git a/solutions-exercises/Herzschlag/src/main/java/ch/zhaw/prog2/heartbeat/InvalidValvePositionException.java b/solutions-exercises/Herzschlag/src/main/java/ch/zhaw/prog2/heartbeat/InvalidValvePositionException.java
new file mode 100644
index 0000000..e36dc18
--- /dev/null
+++ b/solutions-exercises/Herzschlag/src/main/java/ch/zhaw/prog2/heartbeat/InvalidValvePositionException.java
@@ -0,0 +1,9 @@
+package ch.zhaw.prog2.heartbeat;
+
+public class InvalidValvePositionException extends RuntimeException {
+
+ public InvalidValvePositionException (String message) {
+ super (message);
+ }
+
+}
diff --git a/solutions-exercises/Herzschlag/src/main/java/ch/zhaw/prog2/heartbeat/Pacemaker.java b/solutions-exercises/Herzschlag/src/main/java/ch/zhaw/prog2/heartbeat/Pacemaker.java
new file mode 100644
index 0000000..d97dc1f
--- /dev/null
+++ b/solutions-exercises/Herzschlag/src/main/java/ch/zhaw/prog2/heartbeat/Pacemaker.java
@@ -0,0 +1,44 @@
+package ch.zhaw.prog2.heartbeat;
+/**
+ * This class represents a pacemaker for a human hart.
+ *
+ * This is an incomplete implementation, reduced to the essentials for the content of the lab.
+ * There would be a lot more code needed to implement a pacemaker, but this is not part of this lab :-)
+ *
+ * @author muon
+ *
+ */
+public class Pacemaker {
+ Heart heart;
+
+ /**
+ * Constructor of Pacemaker
+ * @param heart
+ */
+ public Pacemaker(Heart heart) {
+ this.heart = heart;
+ }
+
+ /**
+ * Sets the heart rate to the parameter value in Hz.
+ * Rate has to be inside range >30 && <220
+ * If frequency can be applied on heart, the current frequency will be returned.
+ * If heart does reject the change the method throws an exception.
+ *
+ * @param frequencyInHz needs to be applied on heart
+ * @return current frequency of the heart
+ * @throws IllegalArgumentException when heart does reject the change
+ */
+ public int setHeartRate(int frequencyInHz) {
+ if(!heart.setHeartRate(frequencyInHz)){
+ throw new IllegalArgumentException("Frequency could not be set.");
+ }
+ return heart.getHeartRate();
+ }
+
+ /*
+ ...
+ There would be a lot more code needed to implement a pacemaker, but this is not part of this lab :-)
+ ...
+ */
+}
diff --git a/solutions-exercises/Herzschlag/src/main/java/ch/zhaw/prog2/heartbeat/parts/AtrioventricularValve.java b/solutions-exercises/Herzschlag/src/main/java/ch/zhaw/prog2/heartbeat/parts/AtrioventricularValve.java
new file mode 100644
index 0000000..480d4c5
--- /dev/null
+++ b/solutions-exercises/Herzschlag/src/main/java/ch/zhaw/prog2/heartbeat/parts/AtrioventricularValve.java
@@ -0,0 +1,19 @@
+package ch.zhaw.prog2.heartbeat.parts;
+
+import ch.zhaw.prog2.heartbeat.Half.Side;
+import ch.zhaw.prog2.heartbeat.Heart;
+
+public class AtrioventricularValve extends Valve {
+
+ public AtrioventricularValve(Side side) {
+ super (side);
+ }
+
+ public void initializeState(Heart.State state) {
+ if(Heart.State.DIASTOLE.equals(state)){
+ setOpen(false);
+ }else{
+ setOpen(true);
+ }
+ }
+}
diff --git a/solutions-exercises/Herzschlag/src/main/java/ch/zhaw/prog2/heartbeat/parts/Atrium.java b/solutions-exercises/Herzschlag/src/main/java/ch/zhaw/prog2/heartbeat/parts/Atrium.java
new file mode 100644
index 0000000..5db2e3c
--- /dev/null
+++ b/solutions-exercises/Herzschlag/src/main/java/ch/zhaw/prog2/heartbeat/parts/Atrium.java
@@ -0,0 +1,20 @@
+package ch.zhaw.prog2.heartbeat.parts;
+
+import ch.zhaw.prog2.heartbeat.Half.Side;
+
+public class Atrium {
+ private Side side;
+
+ public Atrium (Side side) {
+ this.side = side;
+ }
+
+ public void contract() {
+ System.out.println("Atrium "+ side + " is contracting.");
+ }
+
+ public void relax() {
+ System.out.println("Atrium "+ side + " is relaxing.");
+ }
+
+}
diff --git a/solutions-exercises/Herzschlag/src/main/java/ch/zhaw/prog2/heartbeat/parts/SemilunarValve.java b/solutions-exercises/Herzschlag/src/main/java/ch/zhaw/prog2/heartbeat/parts/SemilunarValve.java
new file mode 100644
index 0000000..4f19597
--- /dev/null
+++ b/solutions-exercises/Herzschlag/src/main/java/ch/zhaw/prog2/heartbeat/parts/SemilunarValve.java
@@ -0,0 +1,20 @@
+package ch.zhaw.prog2.heartbeat.parts;
+
+import ch.zhaw.prog2.heartbeat.Half.Side;
+import ch.zhaw.prog2.heartbeat.Heart;
+
+public class SemilunarValve extends Valve {
+
+ public SemilunarValve(Side side) {
+ super (side);
+ }
+
+ public void initializeState(Heart.State state) {
+ if(Heart.State.DIASTOLE.equals(state)){
+ setOpen(true);
+ }else{
+ setOpen(false);
+ }
+ }
+
+}
diff --git a/solutions-exercises/Herzschlag/src/main/java/ch/zhaw/prog2/heartbeat/parts/Valve.java b/solutions-exercises/Herzschlag/src/main/java/ch/zhaw/prog2/heartbeat/parts/Valve.java
new file mode 100644
index 0000000..ae1a22d
--- /dev/null
+++ b/solutions-exercises/Herzschlag/src/main/java/ch/zhaw/prog2/heartbeat/parts/Valve.java
@@ -0,0 +1,61 @@
+package ch.zhaw.prog2.heartbeat.parts;
+
+import ch.zhaw.prog2.heartbeat.Half.Side;
+
+public abstract class Valve {
+
+ private boolean open;
+ private Side side;
+
+ public Valve(Side side) {
+ this.side = side;
+ }
+
+ /**
+ * Opens the valve
+ *
+ * @throws IllegalValveStateException when the valve is already open
+ */
+ public void open() throws IllegalValveStateException {
+ if (open) {
+ throw new IllegalValveStateException(this.getClass().getSimpleName() + " " + side + " valve is already open.");
+ }
+ System.out.println(this.getClass().getSimpleName() + " " + side + " is opening.");
+ open = true;
+ }
+
+ /**
+ * Closes the valve
+ *
+ * @throws IllegalValveStateException when valve is already closed
+ */
+ public void close() throws IllegalValveStateException {
+ if (!open) {
+ throw new IllegalValveStateException(this.getClass().getSimpleName() + " " + side + " valve is already closed.");
+ }
+ System.out.println(this.getClass().getSimpleName() + " " + side + " is closing.");
+ open = false;
+ }
+
+ public boolean isOpen() {
+ return open;
+ }
+
+ protected void setOpen(Boolean open) {
+ this.open = open;
+ }
+
+ public static class IllegalValveStateException extends Exception {
+
+ public IllegalValveStateException() {
+ }
+
+ public IllegalValveStateException(String message) {
+ super(message);
+ }
+
+ public IllegalValveStateException(String message, Throwable cause) {
+ super(message, cause);
+ }
+ }
+}
diff --git a/solutions-exercises/Herzschlag/src/main/java/ch/zhaw/prog2/heartbeat/parts/Ventricle.java b/solutions-exercises/Herzschlag/src/main/java/ch/zhaw/prog2/heartbeat/parts/Ventricle.java
new file mode 100644
index 0000000..8b03e9b
--- /dev/null
+++ b/solutions-exercises/Herzschlag/src/main/java/ch/zhaw/prog2/heartbeat/parts/Ventricle.java
@@ -0,0 +1,20 @@
+package ch.zhaw.prog2.heartbeat.parts;
+
+import ch.zhaw.prog2.heartbeat.Half.Side;
+
+public class Ventricle {
+ private Side side;
+
+ public Ventricle (Side side) {
+ this.side = side;
+ }
+
+ public void contract() {
+ System.out.println("Chamber "+ side + " is contracting.");
+ }
+
+ public void relax() {
+ System.out.println("Chamber "+ side + " is relaxing.");
+ }
+
+}
diff --git a/solutions-exercises/Herzschlag/src/test/java/ch/zhaw/prog2/heartbeat/HeartTest.java b/solutions-exercises/Herzschlag/src/test/java/ch/zhaw/prog2/heartbeat/HeartTest.java
new file mode 100644
index 0000000..5530835
--- /dev/null
+++ b/solutions-exercises/Herzschlag/src/test/java/ch/zhaw/prog2/heartbeat/HeartTest.java
@@ -0,0 +1,118 @@
+/*
+ * Test Class for Heart
+ */
+package ch.zhaw.prog2.heartbeat;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+import ch.zhaw.prog2.heartbeat.parts.Valve;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+
+import ch.zhaw.prog2.heartbeat.Heart.State;
+
+class HeartTest {
+ /**
+ * This is a very simple test to check if Junit and Mockito are properly set up.
+ */
+ @Test
+ void testTheTest() {
+ Heart classUnderTest = new Heart();
+ assertNotNull(classUnderTest.getState(), "The heart must have a state.");
+ }
+
+ /**
+ * Tests a single heartbeat
+ */
+ @Test
+ void testHeartBeat() throws Heart.HeartBeatDysfunctionException {
+ Heart heart = new Heart();
+ State startState = heart.getState();
+
+ heart.executeHeartBeat();
+
+ // after one heartbeat, the heart must be in the same state as before
+ assertEquals(startState, heart.getState());
+ }
+
+ /**
+ * Tests if the valves are open or closed depending on the status of the heart
+ */
+ @Test
+ void testValveStatus() throws Heart.HeartBeatDysfunctionException {
+ Heart heart = new Heart();
+
+ heart.executeHeartBeat();
+
+ State state = heart.getState();
+
+ if (state.equals(Heart.State.DIASTOLE)) {
+ for (Half half : heart.getHalves()) {
+ assertFalse(half.isAtrioventricularValveOpen());
+ assertTrue(half.isSemilunarValveOpen());
+ }
+ } else if ((state.equals(Heart.State.SYSTOLE))) {
+ for (Half half : heart.getHalves()) {
+ assertTrue(half.isAtrioventricularValveOpen());
+ assertFalse(half.isSemilunarValveOpen());
+ }
+ }
+ }
+
+ /**
+ * Tests if the hart throws the appropriate Exception, when malfunction was detected during hartBeat
+ */
+ @Test
+ void testExecuteHeartBeatErrorBehaviour() {
+ Heart heart = new Heart();
+ // prepare error situation due to wrong initialization
+ heart.setState(State.SYSTOLE);
+
+ assertThrows(Heart.HeartBeatDysfunctionException .class, // verification using lambda
+ () -> heart.executeHeartBeat());
+ }
+
+ /**
+ * Tests if the hart throws the appropriate Exception, when malfunction was detected during hartBeat
+ * with exception Stubbing
+ */
+ @Disabled
+ void testExecuteHartBeatErrorBehaviourWithStubbing() throws Valve.IllegalValveStateException {
+ //TODO implement and replace the annotation @Disabled by @Test
+ fail();
+ }
+
+ /**
+ * We test if Heart::executeHeartbeat() sends the right signals to both of its
+ * halves.
+ *
+ * When Half::contractVentricle() is called, Half::closeAtrioventricularValve()
+ * and Half::openSemilunarValve() must have been called earlier.
+ *
+ */
+ @Disabled
+ void testValvesBehavior() {
+ //TODO implementand replace the annotation @Disabled by @Test
+ fail();
+ }
+
+ /**
+ * This is code used for the lecture slide.
+ */
+ @Test
+ void testForSlide() throws Valve.IllegalValveStateException {
+ Half mockedHalf = mock(Half.class);
+ Heart heart = new Heart(mockedHalf, new Half(Half.Side.RIGHT));
+ heart.setState(State.SYSTOLE);
+ heart.initalizeState();
+
+ when(mockedHalf.isAtrioventricularValveOpen()).thenReturn(false);
+ when(mockedHalf.isSemilunarValveOpen()).thenReturn(true);
+ heart.executeSystole();
+
+ verify(mockedHalf).contractVentricle();
+ verify(mockedHalf, times(1)).contractAtrium();
+ }
+
+}
diff --git a/solutions-exercises/Herzschlag/src/test/java/ch/zhaw/prog2/heartbeat/PacemakerTest.java b/solutions-exercises/Herzschlag/src/test/java/ch/zhaw/prog2/heartbeat/PacemakerTest.java
new file mode 100644
index 0000000..2413314
--- /dev/null
+++ b/solutions-exercises/Herzschlag/src/test/java/ch/zhaw/prog2/heartbeat/PacemakerTest.java
@@ -0,0 +1,31 @@
+package ch.zhaw.prog2.heartbeat;
+
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.*;
+
+/*
+ * Test Class for Pacemaker
+ */
+public class PacemakerTest {
+
+ /**
+ * Test if setHeartRate does throw correct exception when rate is rejected (because frequency is out of range)
+ */
+ @Disabled
+ void testSetHeartRateRejectsFrequenciesOutOfRange() {
+ //TODO implement and replace the annotation @Disabled by @Test
+ fail();
+ }
+
+
+ /**
+ * Test if setHeartRate does correctly set the rate when frequency is inside range
+ */
+ @Disabled
+ void testSetHeartRateAppliesFrequenciesInsideRange() {
+ //TODO implement and replace the annotation @Disabled by @Test
+ fail();
+ }
+
+}
diff --git a/solutions-exercises/solutions-exercises.adoc b/solutions-exercises/solutions-exercises.adoc
new file mode 100644
index 0000000..0be1c85
--- /dev/null
+++ b/solutions-exercises/solutions-exercises.adoc
@@ -0,0 +1,99 @@
+:source-highlighter: coderay
+:icons: font
+:experimental:
+:!sectnums:
+:imagesdir: ../images/
+:handout: ./code/
+
+:logo: IT.PROG2 -
+ifdef::backend-html5[]
+:logo: image:PROG2-300x300.png[IT.PROG2,100,100,role=right,fit=none,position=top right]
+endif::[]
+ifdef::backend-pdf[]
+:logo:
+endif::[]
+ifdef::env-github[]
+:tip-caption: :bulb:
+:note-caption: :information_source:
+:important-caption: :heavy_exclamation_mark:
+:caution-caption: :fire:
+:warning-caption: :warning:
+endif::[]
+
+= {logo} Lösungen zum Praktikum Mock-Testing
+
+:sectnums:
+:sectnumlevels: 2
+// Beginn des Aufgabenblocks
+
+== Herz
+
+****
+Funktionserläuterung zum Herzschlag finden Sie in der Aufgabenstellung
+****
+
+== Aufgaben
+
+=== Einführung in Mockito
+[loweralpha]
+. Studieren Sie die Testmethoden `HeartTest::testValveStatus()` und `HeartTest::testExecuteHartBeatErrorBehaviour()`.
+Dort wird *ein Teil* des Verhaltens des Herzens getestet.
+
+. Implementieren Sie die Methoden `Heart::executeDiastole()`, `Heart::executeSystole()` und `Heart::executeHeartBeat()` sodass die bestehenden Tests durchlaufen und das oben beschriebene Verhalten des Herzens modelliert wird.
+
+. (optional) Ein echtes Herz hat eine Schlagfrequenz.
+Implementieren Sie, dass das Herz nach jeder Systole pausiert.
+
+****
+Siehe Musterlösung: `Heart.executeDiastole()`, `Heart.executeSystole()` und `Heart.executeHeartBeat()`
+****
+
+
+=== Fragen zu Testing [TU]
+[loweralpha]
+. Testing kann in zwei unterschiedliche Strategien aufgeteilt werden.
+Zum einen gibt es White-Box-Testing und zum zweiten Black-Box-Testing.
+Was für Java Libraries gibt es, um diese zwei Strategien zu testen?
+Wann wenden Sie welche Strategie an?
++
+****
+* JUnit ist ein Framework für Unit-Tests (auch Modul-Tests genannt).
+Es wird sowohl für White-Box-Testing als auch für Black-Box-Testing angewendet.
+
+* Für White-Box-Testing eignet sich Mockito, weil damit die Abläufe innerhalb einer Klasse getestet werden können (behavior testing).
+
+* Black-Box-Testing trifft keine Annahmen darüber, *wie* eine Klasse oder Methode eine Aufgabe erledigt.
+Es wird lediglich überprüft, ob auf eine bestimmte Eingabe die erwartete Ausgabe erfolgt.
+
+* Nichttriviale Methoden sollten immer mindestens mit Black-Box-Testing getestet werden.
+Diese Tests werden am besten von einer anderen Person geschrieben als von der Programmierer:in.
+
+* Für White-Box-Testing werden Informationen benötigt, *wie* eine Klasse oder Methode eine Aufgabe erledigt.
+****
+
+. Das Erstellen von guten automatisierten Unit-Tests kann manchmal schwierig umzusetzen sein.
+Was ist der Hauptgrund dafür? Wie können Sie dieses Problem entschärfen?
++
+****
+* Das Setup eines Unit-Tests kann kompliziert werden, wenn mehrere Klassen dafür instanziiert und konfiguriert werden müssen.
+* Das Problem kann entschärft werden, indem
+** die verschiedenen Klassen besser entkoppelt werden und
+** die Klassen, von denen die zu testende Klasse abhängig ist, zu mocken.
+****
+
+. Der Testfokus war bisher auf der Klasse `Heart`.
+Testen Sie jetzt die Klasse `Half`. Wo verwenden Sie Stubbing, wo Mocking?
++
+****
+* Die Funktionalität der Klasse Half nicht besonders umfangreich.
+Alle Methoden der Klasse bestehen aus nur genau einer Zeile und die Klasse hat bis auf das Datenfeld `Half.side` keinen State.
+Was schieflaufen könnte ist, dass jemand beispielweise auf einem Ventil anstatt der `close()` Methode die `open()` Methode aufruft.
+Weil wir in der Klasse `Half` nicht wirklich einen Status prüfen können, macht es mehr Sinn das Verhalten der Klasse zu prüfen (ruft die Klasse die richtigen Methoden auf)
+→ Das können wir mit Mocking (in Mockito mit `verify`) erreichen.
+Entsprechend würde sich hier ein Mock besser eignen als ein Stub.
+Über die Frage, wie sinnvoll es ist solch einfache Klassen zu simulieren, lässt sich Diskutieren und ist abhängig vom jeweiligen Testkonzept.
+
+* Beim Auftrag die Klasse `Half` zu testen, stossen Sie auf das Problem, dass Sie weder Stubs noch Mocks anwenden können, weil die Klassen von welchen `Half` abhängt direkt im Konstruktor von `Half` initialisiert werden.
+Damit können Sie kein Test-Double verwenden (injecten).
+Das Problem könnten Sie lösen, wenn es einen entsprechenden Konstruktor in der Klasse `Half` gäbe, welche die Instanzen der Abhängigen Typen entgegennimmt (analog zu `Heart`).
+****
diff --git a/solutions-exercises/solutions-exercises.pdf b/solutions-exercises/solutions-exercises.pdf
new file mode 100644
index 0000000..c6489a2
--- /dev/null
+++ b/solutions-exercises/solutions-exercises.pdf
@@ -0,0 +1,3132 @@
+%PDF-1.4
+%
+1 0 obj
+<< /Title
+/Creator (Asciidoctor PDF 1.6.2, based on Prawn 2.4.0)
+/Producer (Asciidoctor PDF 1.6.2, based on Prawn 2.4.0)
+/ModDate (D:20220410182534+02'00')
+/CreationDate (D:20220410182727+02'00')
+>>
+endobj
+2 0 obj
+<< /Type /Catalog
+/Pages 3 0 R
+/Names 10 0 R
+/Outlines 22 0 R
+/PageLabels 28 0 R
+/PageMode /UseOutlines
+/OpenAction [7 0 R /FitH 841.89]
+/ViewerPreferences << /DisplayDocTitle true
+>>
+>>
+endobj
+3 0 obj
+<< /Type /Pages
+/Count 2
+/Kids [7 0 R 21 0 R]
+>>
+endobj
+4 0 obj
+<< /Length 2
+>>
+stream
+q
+
+endstream
+endobj
+5 0 obj
+<< /Type /Page
+/Parent 3 0 R
+/MediaBox [0 0 595.28 841.89]
+/CropBox [0 0 595.28 841.89]
+/BleedBox [0 0 595.28 841.89]
+/TrimBox [0 0 595.28 841.89]
+/ArtBox [0 0 595.28 841.89]
+/Contents 4 0 R
+/Resources << /ProcSet [/PDF /Text /ImageB /ImageC /ImageI]
+>>
+>>
+endobj
+6 0 obj
+<< /Length 14954
+>>
+stream
+q
+/DeviceRGB cs
+0.1294 0.1451 0.1608 scn
+/DeviceRGB CS
+0.1294 0.1451 0.1608 SCN
+
+BT
+56.6929 758.2318 Td
+/F2.0 22 Tf
+<4c9a73756e67656e207a756d205072616b74696b756d204d6f636b2d54657374696e67> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.7294 0.2235 0.1451 scn
+0.7294 0.2235 0.1451 SCN
+
+BT
+56.6929 725.1698 Td
+/F2.0 20 Tf
+<312e204865727a> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+q
+0.9333 0.9333 0.9333 scn
+60.6929 715.5498 m
+534.5871 715.5498 l
+536.7962 715.5498 538.5871 713.7589 538.5871 711.5498 c
+538.5871 680.5212 l
+538.5871 678.3121 536.7962 676.5212 534.5871 676.5212 c
+60.6929 676.5212 l
+58.4838 676.5212 56.6929 678.3121 56.6929 680.5212 c
+56.6929 711.5498 l
+56.6929 713.7589 58.4838 715.5498 60.6929 715.5498 c
+h
+f
+0.8824 0.8824 0.8824 SCN
+0.5 w
+60.6929 715.5498 m
+534.5871 715.5498 l
+536.7962 715.5498 538.5871 713.7589 538.5871 711.5498 c
+538.5871 680.5212 l
+538.5871 678.3121 536.7962 676.5212 534.5871 676.5212 c
+60.6929 676.5212 l
+58.4838 676.5212 56.6929 678.3121 56.6929 680.5212 c
+56.6929 711.5498 l
+56.6929 713.7589 58.4838 715.5498 60.6929 715.5498 c
+h
+S
+Q
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+71.6929 692.1555 Td
+/F1.0 10 Tf
+<46756e6b74696f6e7365726c8a75746572756e67207a756d204865727a7363686c61672066696e64656e2053696520696e2064657220417566676162656e7374656c6c756e67> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.7294 0.2235 0.1451 scn
+0.7294 0.2235 0.1451 SCN
+
+BT
+56.6929 649.5612 Td
+/F2.0 20 Tf
+<322e20417566676162656e> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.7294 0.2235 0.1451 scn
+0.7294 0.2235 0.1451 SCN
+
+BT
+56.6929 620.8532 Td
+/F2.0 16 Tf
+<322e312e2045696e669f6872756e6720696e204d6f636b69746f> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+
+-0.5 Tc
+
+0.0 Tc
+
+-0.5 Tc
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+61.7929 600.8029 Td
+/F1.0 10 Tf
+<612e> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+
+0.0 Tc
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+74.6929 600.8029 Td
+/F1.0 10 Tf
+<53747564696572656e205369652064696520546573746d6574686f64656e20> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.2 0.4 0.6667 scn
+0.2 0.4 0.6667 SCN
+
+BT
+228.0129 600.8029 Td
+/F3.0 10 Tf
+<4865617274546573743a3a7465737456616c76655374617475732829> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+396.0129 600.8029 Td
+/F1.0 10 Tf
+<20756e64> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.2 0.4 0.6667 scn
+0.2 0.4 0.6667 SCN
+
+BT
+74.6929 585.7744 Td
+/F3.0 10 Tf
+<4865617274546573743a3a746573744578656375746548617274426561744572726f724265686176696f75722829> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+350.6929 585.7744 Td
+/F1.0 10 Tf
+<2e20446f7274207769726420> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+404.8729 585.7744 Td
+/F4.0 10 Tf
+<65696e205465696c> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+442.6029 585.7744 Td
+/F1.0 10 Tf
+<206465732056657268616c74656e7320646573> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+74.6929 570.7458 Td
+/F1.0 10 Tf
+<4865727a656e732067657465737465742e> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+
+-0.5 Tc
+
+0.0 Tc
+
+-0.5 Tc
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+61.2829 551.7172 Td
+/F1.0 10 Tf
+<622e> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+
+0.0 Tc
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+74.6929 551.7172 Td
+/F1.0 10 Tf
+<496d706c656d656e74696572656e2053696520646965204d6574686f64656e20> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.2 0.4 0.6667 scn
+0.2 0.4 0.6667 SCN
+
+BT
+239.4729 551.7172 Td
+/F3.0 10 Tf
+<48656172743a3a6578656375746544696173746f6c652829> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+383.4729 551.7172 Td
+/F1.0 10 Tf
+<2c20> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.2 0.4 0.6667 scn
+0.2 0.4 0.6667 SCN
+
+BT
+388.5629 551.7172 Td
+/F3.0 10 Tf
+<48656172743a3a65786563757465537973746f6c652829> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+526.5629 551.7172 Td
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+74.6929 536.6887 Td
+/F1.0 10 Tf
+<756e6420> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.2 0.4 0.6667 scn
+0.2 0.4 0.6667 SCN
+
+BT
+96.2029 536.6887 Td
+/F3.0 10 Tf
+<48656172743a3a657865637574654865617274426561742829> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+246.2029 536.6887 Td
+/F1.0 10 Tf
+<20736f646173732064696520626573746568656e64656e2054657374732064757263686c617566656e20756e6420646173206f62656e> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+74.6929 521.6601 Td
+/F1.0 10 Tf
+<626573636872696562656e652056657268616c74656e20646573204865727a656e73206d6f64656c6c6965727420776972642e> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+
+-0.5 Tc
+
+0.0 Tc
+
+-0.5 Tc
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+62.4929 502.6315 Td
+/F1.0 10 Tf
+<632e> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+
+0.0 Tc
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+74.6929 502.6315 Td
+/F1.0 10 Tf
+<286f7074696f6e616c292045696e20656368746573204865727a206861742065696e65205363686c61676672657175656e7a2e20496d706c656d656e74696572656e205369652c206461737320646173204865727a206e616368206a65646572> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+74.6929 487.6029 Td
+/F1.0 10 Tf
+<537973746f6c652070617573696572742e> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+q
+0.9333 0.9333 0.9333 scn
+60.6929 471.9687 m
+534.5871 471.9687 l
+536.7962 471.9687 538.5871 470.1778 538.5871 467.9687 c
+538.5871 422.2315 l
+538.5871 420.0224 536.7962 418.2315 534.5871 418.2315 c
+60.6929 418.2315 l
+58.4838 418.2315 56.6929 420.0224 56.6929 422.2315 c
+56.6929 467.9687 l
+56.6929 470.1778 58.4838 471.9687 60.6929 471.9687 c
+h
+f
+0.8824 0.8824 0.8824 SCN
+0.5 w
+60.6929 471.9687 m
+534.5871 471.9687 l
+536.7962 471.9687 538.5871 470.1778 538.5871 467.9687 c
+538.5871 422.2315 l
+538.5871 420.0224 536.7962 418.2315 534.5871 418.2315 c
+60.6929 418.2315 l
+58.4838 418.2315 56.6929 420.0224 56.6929 422.2315 c
+56.6929 467.9687 l
+56.6929 470.1778 58.4838 471.9687 60.6929 471.9687 c
+h
+S
+Q
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+71.6929 448.5744 Td
+/F1.0 10 Tf
+<5369656865204d75737465726c9a73756e673a20> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.2 0.4 0.6667 scn
+0.2 0.4 0.6667 SCN
+
+BT
+170.7429 448.5744 Td
+/F3.0 10 Tf
+<48656172742e6578656375746544696173746f6c652829> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+308.7429 448.5744 Td
+/F1.0 10 Tf
+<2c20> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.2 0.4 0.6667 scn
+0.2 0.4 0.6667 SCN
+
+BT
+313.8329 448.5744 Td
+/F3.0 10 Tf
+<48656172742e65786563757465537973746f6c652829> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+445.8329 448.5744 Td
+/F1.0 10 Tf
+<20756e64> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.2 0.4 0.6667 scn
+0.2 0.4 0.6667 SCN
+
+BT
+71.6929 433.9458 Td
+/F3.0 10 Tf
+<48656172742e657865637574654865617274426561742829> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.7294 0.2235 0.1451 scn
+0.7294 0.2235 0.1451 SCN
+
+BT
+56.6929 395.1435 Td
+/F2.0 16 Tf
+<322e322e2046726167656e207a752054657374696e67205b54555d> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+
+-0.5 Tc
+
+0.0 Tc
+
+-0.5 Tc
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+61.7929 375.0932 Td
+/F1.0 10 Tf
+<612e> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+
+0.0 Tc
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+74.6929 375.0932 Td
+/F1.0 10 Tf
+<54657374696e67206b616e6e20696e207a77656920756e7465727363686965646c69636865205374726174656769656e2061756667657465696c742077657264656e2e205a756d2065696e656e20676962742065732057686974652d> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+74.6929 360.0647 Td
+/F1.0 10 Tf
+<426f782d54657374696e6720756e64207a756d207a77656974656e20426c61636b2d426f782d54657374696e672e2057617320669f72204a617661204c696272617269657320676962742065732c20756d206469657365207a776569> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+74.6929 345.0361 Td
+/F1.0 10 Tf
+<5374726174656769656e207a752074657374656e3f2057616e6e2077656e64656e205369652077656c6368652053747261746567696520616e3f> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+q
+0.9333 0.9333 0.9333 scn
+78.6929 329.4018 m
+534.5871 329.4018 l
+536.7962 329.4018 538.5871 327.6109 538.5871 325.4018 c
+538.5871 113.0589 l
+538.5871 110.8498 536.7962 109.0589 534.5871 109.0589 c
+78.6929 109.0589 l
+76.4838 109.0589 74.6929 110.8498 74.6929 113.0589 c
+74.6929 325.4018 l
+74.6929 327.6109 76.4838 329.4018 78.6929 329.4018 c
+h
+f
+0.8824 0.8824 0.8824 SCN
+0.5 w
+78.6929 329.4018 m
+534.5871 329.4018 l
+536.7962 329.4018 538.5871 327.6109 538.5871 325.4018 c
+538.5871 113.0589 l
+538.5871 110.8498 536.7962 109.0589 534.5871 109.0589 c
+78.6929 109.0589 l
+76.4838 109.0589 74.6929 110.8498 74.6929 113.0589 c
+74.6929 325.4018 l
+74.6929 327.6109 76.4838 329.4018 78.6929 329.4018 c
+h
+S
+Q
+
+-0.5 Tc
+
+0.0 Tc
+
+-0.5 Tc
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+98.8729 306.0075 Td
+/F1.1 10 Tf
+<21> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+
+0.0 Tc
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+107.6929 306.0075 Td
+/F1.0 10 Tf
+<4a556e6974206973742065696e204672616d65776f726b20669f7220556e69742d5465737473202861756368204d6f64756c2d54657374732067656e616e6e74292e204573207769726420736f776f686c20669f72> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+107.6929 290.9789 Td
+/F1.0 10 Tf
+<57686974652d426f782d54657374696e6720616c73206175636820669f7220426c61636b2d426f782d54657374696e6720616e676577656e6465742e> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+
+-0.5 Tc
+
+0.0 Tc
+
+-0.5 Tc
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+98.8729 271.9504 Td
+/F1.1 10 Tf
+<21> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+
+0.0 Tc
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+107.6929 271.9504 Td
+/F1.0 10 Tf
+<469f722057686974652d426f782d54657374696e67206569676e65742073696368204d6f636b69746f2c207765696c2064616d6974206469652041626c8a75666520696e6e657268616c622065696e6572> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+107.6929 256.9218 Td
+/F1.0 10 Tf
+<4b6c617373652067657465737465742077657264656e206b9a6e6e656e20286265686176696f722074657374696e67292e> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+
+-0.5 Tc
+
+0.0 Tc
+
+-0.5 Tc
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+98.8729 237.8932 Td
+/F1.1 10 Tf
+<21> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+
+0.0 Tc
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+107.6929 237.8932 Td
+/F1.0 10 Tf
+<426c61636b2d426f782d54657374696e6720747269666674206b65696e6520416e6e61686d656e206461729f6265722c20> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+348.5929 237.8932 Td
+/F4.0 10 Tf
+<776965> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+366.3629 237.8932 Td
+/F1.0 10 Tf
+<2065696e65204b6c61737365206f646572204d6574686f64652065696e65> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+107.6929 222.8647 Td
+/F1.0 10 Tf
+<417566676162652065726c65646967742e2045732077697264206c656469676c696368209f62657270729f66742c206f62206175662065696e652062657374696d6d74652045696e6761626520646965> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+107.6929 207.8361 Td
+/F1.0 10 Tf
+<6572776172746574652041757367616265206572666f6c67742e> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+
+-0.5 Tc
+
+0.0 Tc
+
+-0.5 Tc
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+98.8729 188.8075 Td
+/F1.1 10 Tf
+<21> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+
+0.0 Tc
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+107.6929 188.8075 Td
+/F1.0 10 Tf
+<4e696368747472697669616c65204d6574686f64656e20736f6c6c74656e20696d6d6572206d696e64657374656e73206d697420426c61636b2d426f782d54657374696e67206765746573746574> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+107.6929 173.7789 Td
+/F1.0 10 Tf
+<77657264656e2e2044696573652054657374732077657264656e20616d2062657374656e20766f6e2065696e657220616e646572656e20506572736f6e20676573636872696562656e20616c7320766f6e> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+107.6929 158.7504 Td
+/F1.0 10 Tf
+<6465722050726f6772616d6d69657265723a696e2e> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+
+-0.5 Tc
+
+0.0 Tc
+
+-0.5 Tc
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+98.8729 139.7218 Td
+/F1.1 10 Tf
+<21> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+
+0.0 Tc
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+107.6929 139.7218 Td
+/F1.0 10 Tf
+<469f722057686974652d426f782d54657374696e672077657264656e20496e666f726d6174696f6e656e2062656e9a746967742c20> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+373.7329 139.7218 Td
+/F4.0 10 Tf
+<776965> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+391.5029 139.7218 Td
+/F1.0 10 Tf
+<2065696e65204b6c61737365206f646572204d6574686f6465> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+107.6929 124.6932 Td
+/F1.0 10 Tf
+<65696e6520417566676162652065726c65646967742e> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+
+-0.5 Tc
+
+0.0 Tc
+
+-0.5 Tc
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+61.2829 93.6647 Td
+/F1.0 10 Tf
+<622e> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+
+0.0 Tc
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+74.6929 93.6647 Td
+/F1.0 10 Tf
+<4461732045727374656c6c656e20766f6e20677574656e206175746f6d6174697369657274656e20556e69742d5465737473206b616e6e206d616e63686d616c2073636877696572696720756d7a757365747a656e207365696e2e> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+74.6929 78.6361 Td
+/F1.0 10 Tf
+<57617320697374206465722048617570746772756e64206461669f723f20576965206b9a6e6e656e20536965206469657365732050726f626c656d20656e747363688a7266656e3f> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+q
+0.0 0.0 0.0 scn
+0.0 0.0 0.0 SCN
+1 w
+0 J
+0 j
+[] 0 d
+/Stamp1 Do
+
+q
+77.9133 0.0 0.0 42.2697 56.6929 785.4471 cm
+/I1 Do
+Q
+0.6 0.6 0.6 scn
+0.6 0.6 0.6 SCN
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.6 0.6 0.6 scn
+0.6 0.6 0.6 SCN
+
+BT
+413.0011 802.2483 Td
+/F1.0 9 Tf
+<50726f6772616d6d696572656e203220d02049542e50524f4732> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+Q
+q
+0.0 0.0 0.0 scn
+0.0 0.0 0.0 SCN
+1 w
+0 J
+0 j
+[] 0 d
+/Stamp3 Do
+0.6 0.6 0.6 scn
+0.6 0.6 0.6 SCN
+
+BT
+57.6929 26.7827 Td
+/F1.0 9 Tf
+<312e204865727a> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.6 0.6 0.6 scn
+0.6 0.6 0.6 SCN
+
+BT
+291.313 26.7827 Td
+/F1.0 9 Tf
+<312f32> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.6 0.6 0.6 scn
+0.6 0.6 0.6 SCN
+
+BT
+480.8511 26.7827 Td
+/F1.0 9 Tf
+<405a48415720496e4954> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+Q
+Q
+
+endstream
+endobj
+7 0 obj
+<< /Type /Page
+/Parent 3 0 R
+/MediaBox [0 0 595.28 841.89]
+/CropBox [0 0 595.28 841.89]
+/BleedBox [0 0 595.28 841.89]
+/TrimBox [0 0 595.28 841.89]
+/ArtBox [0 0 595.28 841.89]
+/Contents 6 0 R
+/Resources << /ProcSet [/PDF /Text /ImageB /ImageC /ImageI]
+/Font << /F2.0 8 0 R
+/F1.0 13 0 R
+/F3.0 16 0 R
+/F4.0 17 0 R
+/F1.1 19 0 R
+>>
+/XObject << /Stamp1 29 0 R
+/I1 31 0 R
+/Stamp3 32 0 R
+>>
+>>
+>>
+endobj
+8 0 obj
+<< /Type /Font
+/BaseFont /9784ac+Inter-Regular
+/Subtype /TrueType
+/FontDescriptor 35 0 R
+/FirstChar 32
+/LastChar 255
+/Widths 37 0 R
+/ToUnicode 36 0 R
+>>
+endobj
+9 0 obj
+[7 0 R /XYZ 0 748.1298 null]
+endobj
+10 0 obj
+<< /Type /Names
+/Dests 11 0 R
+>>
+endobj
+11 0 obj
+<< /Names [(0x5f65696e66c3bc6872756e675f696e5f6d6f636b69746f) 15 0 R (__anchor-top) 9 0 R (_aufgaben) 14 0 R (_fragen_zu_testing_tu) 18 0 R (_herz) 12 0 R]
+>>
+endobj
+12 0 obj
+[7 0 R /XYZ 0 748.1298 null]
+endobj
+13 0 obj
+<< /Type /Font
+/BaseFont /1e4d58+NotoSerif
+/Subtype /TrueType
+/FontDescriptor 39 0 R
+/FirstChar 32
+/LastChar 255
+/Widths 41 0 R
+/ToUnicode 40 0 R
+>>
+endobj
+14 0 obj
+[7 0 R /XYZ 0 672.5212 null]
+endobj
+15 0 obj
+[7 0 R /XYZ 0 639.9412 null]
+endobj
+16 0 obj
+<< /Type /Font
+/BaseFont /48783d+JetBrainsMono-Regular
+/Subtype /TrueType
+/FontDescriptor 43 0 R
+/FirstChar 32
+/LastChar 255
+/Widths 45 0 R
+/ToUnicode 44 0 R
+>>
+endobj
+17 0 obj
+<< /Type /Font
+/BaseFont /73a4c0+NotoSerif-Bold
+/Subtype /TrueType
+/FontDescriptor 47 0 R
+/FirstChar 32
+/LastChar 255
+/Widths 49 0 R
+/ToUnicode 48 0 R
+>>
+endobj
+18 0 obj
+[7 0 R /XYZ 0 414.2315 null]
+endobj
+19 0 obj
+<< /Type /Font
+/BaseFont /f67774+NotoSerif
+/Subtype /TrueType
+/FontDescriptor 51 0 R
+/FirstChar 32
+/LastChar 255
+/Widths 53 0 R
+/ToUnicode 52 0 R
+>>
+endobj
+20 0 obj
+<< /Length 12618
+>>
+stream
+q
+q
+/DeviceRGB cs
+0.9333 0.9333 0.9333 scn
+78.6929 779.5278 m
+534.5871 779.5278 l
+536.7962 779.5278 538.5871 777.7369 538.5871 775.5278 c
+538.5871 672.3849 l
+538.5871 670.1758 536.7962 668.3849 534.5871 668.3849 c
+78.6929 668.3849 l
+76.4838 668.3849 74.6929 670.1758 74.6929 672.3849 c
+74.6929 775.5278 l
+74.6929 777.7369 76.4838 779.5278 78.6929 779.5278 c
+h
+f
+/DeviceRGB CS
+0.8824 0.8824 0.8824 SCN
+0.5 w
+78.6929 779.5278 m
+534.5871 779.5278 l
+536.7962 779.5278 538.5871 777.7369 538.5871 775.5278 c
+538.5871 672.3849 l
+538.5871 670.1758 536.7962 668.3849 534.5871 668.3849 c
+78.6929 668.3849 l
+76.4838 668.3849 74.6929 670.1758 74.6929 672.3849 c
+74.6929 775.5278 l
+74.6929 777.7369 76.4838 779.5278 78.6929 779.5278 c
+h
+S
+Q
+
+-0.5 Tc
+
+0.0 Tc
+
+-0.5 Tc
+/DeviceRGB cs
+0.1294 0.1451 0.1608 scn
+/DeviceRGB CS
+0.1294 0.1451 0.1608 SCN
+
+BT
+98.8729 756.1335 Td
+/F1.1 10 Tf
+<21> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+
+0.0 Tc
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+107.6929 756.1335 Td
+/F1.0 10 Tf
+<4461732053657475702065696e657320556e69742d5465737473206b616e6e206b6f6d706c697a696572742077657264656e2c2077656e6e206d656872657265204b6c617373656e206461669f72> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+107.6929 741.1049 Td
+/F1.0 10 Tf
+<696e7374616e7a696965727420756e64206b6f6e6669677572696572742077657264656e206d9f7373656e2e> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+
+-0.5 Tc
+
+0.0 Tc
+
+-0.5 Tc
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+98.8729 722.0764 Td
+/F1.1 10 Tf
+<21> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+
+0.0 Tc
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+107.6929 722.0764 Td
+/F1.0 10 Tf
+<4461732050726f626c656d206b616e6e20656e747363688a7266742077657264656e2c20696e64656d> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+
+-0.5 Tc
+
+0.0 Tc
+
+-0.5 Tc
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+116.8729 703.0478 Td
+/F1.1 10 Tf
+<22> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+
+0.0 Tc
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+125.6929 703.0478 Td
+/F1.0 10 Tf
+<64696520766572736368696564656e656e204b6c617373656e2062657373657220656e746b6f7070656c742077657264656e20756e64> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+
+-0.5 Tc
+
+0.0 Tc
+
+-0.5 Tc
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+116.8729 684.0192 Td
+/F1.1 10 Tf
+<22> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+
+0.0 Tc
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+125.6929 684.0192 Td
+/F1.0 10 Tf
+<646965204b6c617373656e2c20766f6e2064656e656e20646965207a752074657374656e6465204b6c61737365206162688a6e676967206973742c207a75206d6f636b656e2e> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+
+-0.5 Tc
+
+0.0 Tc
+
+-0.5 Tc
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+62.4929 652.9907 Td
+/F1.0 10 Tf
+<632e> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+
+0.0 Tc
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+74.6929 652.9907 Td
+/F1.0 10 Tf
+<4465722054657374666f6b757320776172206269736865722061756620646572204b6c6173736520> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.2 0.4 0.6667 scn
+0.2 0.4 0.6667 SCN
+
+BT
+266.9029 652.9907 Td
+/F3.0 10 Tf
+<4865617274> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+296.9029 652.9907 Td
+/F1.0 10 Tf
+<2e2054657374656e20536965206a65747a7420646965204b6c6173736520> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.2 0.4 0.6667 scn
+0.2 0.4 0.6667 SCN
+
+BT
+425.4629 652.9907 Td
+/F3.0 10 Tf
+<48616c66> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+449.4629 652.9907 Td
+/F1.0 10 Tf
+<2e20576f2076657277656e64656e> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+74.6929 637.9621 Td
+/F1.0 10 Tf
+<536965205374756262696e672c20776f204d6f636b696e673f> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+q
+0.9333 0.9333 0.9333 scn
+78.6929 622.3278 m
+534.5871 622.3278 l
+536.7962 622.3278 538.5871 620.5369 538.5871 618.3278 c
+538.5871 357.7907 l
+538.5871 355.5815 536.7962 353.7907 534.5871 353.7907 c
+78.6929 353.7907 l
+76.4838 353.7907 74.6929 355.5815 74.6929 357.7907 c
+74.6929 618.3278 l
+74.6929 620.5369 76.4838 622.3278 78.6929 622.3278 c
+h
+f
+0.8824 0.8824 0.8824 SCN
+0.5 w
+78.6929 622.3278 m
+534.5871 622.3278 l
+536.7962 622.3278 538.5871 620.5369 538.5871 618.3278 c
+538.5871 357.7907 l
+538.5871 355.5815 536.7962 353.7907 534.5871 353.7907 c
+78.6929 353.7907 l
+76.4838 353.7907 74.6929 355.5815 74.6929 357.7907 c
+74.6929 618.3278 l
+74.6929 620.5369 76.4838 622.3278 78.6929 622.3278 c
+h
+S
+Q
+
+-0.5 Tc
+
+0.0 Tc
+
+-0.5 Tc
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+98.8729 598.9335 Td
+/F1.1 10 Tf
+<21> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+
+0.0 Tc
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+107.6929 598.9335 Td
+/F1.0 10 Tf
+<4469652046756e6b74696f6e616c69748a7420646572204b6c617373652048616c66206e69636874206265736f6e6465727320756d66616e6772656963682e20416c6c65204d6574686f64656e20646572> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+107.6929 583.9049 Td
+/F1.0 10 Tf
+<4b6c6173736520626573746568656e20617573206e75722067656e61752065696e6572205a65696c6520756e6420646965204b6c617373652068617420626973206175662064617320446174656e66656c64> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.2 0.4 0.6667 scn
+0.2 0.4 0.6667 SCN
+
+BT
+107.6929 568.8764 Td
+/F3.0 10 Tf
+<48616c662e73696465> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+161.6929 568.8764 Td
+/F1.0 10 Tf
+<206b65696e656e2053746174652e20576173207363686965666c617566656e206b9a6e6e7465206973742c2064617373206a656d616e6420626569737069656c776569736520617566> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+107.6929 553.8478 Td
+/F1.0 10 Tf
+<65696e656d2056656e74696c20616e73746174742064657220> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.2 0.4 0.6667 scn
+0.2 0.4 0.6667 SCN
+
+BT
+225.1329 553.8478 Td
+/F3.0 10 Tf
+<636c6f73652829> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+267.1329 553.8478 Td
+/F1.0 10 Tf
+<204d6574686f64652064696520> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.2 0.4 0.6667 scn
+0.2 0.4 0.6667 SCN
+
+BT
+331.4029 553.8478 Td
+/F3.0 10 Tf
+<6f70656e2829> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+367.4029 553.8478 Td
+/F1.0 10 Tf
+<204d6574686f646520617566727566742e205765696c2077697220696e> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+107.6929 538.8192 Td
+/F1.0 10 Tf
+<646572204b6c6173736520> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.2 0.4 0.6667 scn
+0.2 0.4 0.6667 SCN
+
+BT
+159.1529 538.8192 Td
+/F3.0 10 Tf
+<48616c66> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+183.1529 538.8192 Td
+/F1.0 10 Tf
+<206e69636874207769726b6c6963682065696e656e205374617475732070729f66656e206b9a6e6e656e2c206d61636874206573206d6568722053696e6e20646173> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+107.6929 523.7907 Td
+/F1.0 10 Tf
+<56657268616c74656e20646572204b6c61737365207a752070729f66656e20287275667420646965204b6c61737365206469652072696368746967656e204d6574686f64656e206175662920> Tj
+/F1.1 10 Tf
+<2320> Tj
+/F1.0 10 Tf
+<446173> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+107.6929 508.7621 Td
+/F1.0 10 Tf
+<6b9a6e6e656e20776972206d6974204d6f636b696e672028696e204d6f636b69746f206d697420> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.2 0.4 0.6667 scn
+0.2 0.4 0.6667 SCN
+
+BT
+303.3429 508.7621 Td
+/F3.0 10 Tf
+<766572696679> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+339.3429 508.7621 Td
+/F1.0 10 Tf
+<292065727265696368656e2e20456e74737072656368656e6420779f7264652073696368> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+107.6929 493.7335 Td
+/F1.0 10 Tf
+<686965722065696e204d6f636b20626573736572206569676e656e20616c732065696e20537475622e2086626572206469652046726167652c207769652073696e6e766f6c6c2065732069737420736f6c6368> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+107.6929 478.7049 Td
+/F1.0 10 Tf
+<65696e6661636865204b6c617373656e207a752073696d756c696572656e2c206c8a7373742073696368204469736b7574696572656e20756e6420697374206162688a6e67696720766f6d206a657765696c6967656e> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+107.6929 463.6764 Td
+/F1.0 10 Tf
+<546573746b6f6e7a6570742e> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+
+-0.5 Tc
+
+0.0 Tc
+
+-0.5 Tc
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+98.8729 444.6478 Td
+/F1.1 10 Tf
+<21> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+
+0.0 Tc
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+107.6929 444.6478 Td
+/F1.0 10 Tf
+<4265696d204175667472616720646965204b6c6173736520> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.2 0.4 0.6667 scn
+0.2 0.4 0.6667 SCN
+
+BT
+223.6329 444.6478 Td
+/F3.0 10 Tf
+<48616c66> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+247.6329 444.6478 Td
+/F1.0 10 Tf
+<207a752074657374656e2c2073746f7373656e2053696520617566206461732050726f626c656d2c206461737320536965207765646572> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+107.6929 429.6192 Td
+/F1.0 10 Tf
+<5374756273206e6f6368204d6f636b7320616e77656e64656e206b9a6e6e656e2c207765696c20646965204b6c617373656e20766f6e2077656c6368656e20> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.2 0.4 0.6667 scn
+0.2 0.4 0.6667 SCN
+
+BT
+432.2229 429.6192 Td
+/F3.0 10 Tf
+<48616c66> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+456.2229 429.6192 Td
+/F1.0 10 Tf
+<206162688a6e6774> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+107.6929 414.5907 Td
+/F1.0 10 Tf
+<646972656b7420696d204b6f6e737472756b746f7220766f6e20> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.2 0.4 0.6667 scn
+0.2 0.4 0.6667 SCN
+
+BT
+235.5729 414.5907 Td
+/F3.0 10 Tf
+<48616c66> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+259.5729 414.5907 Td
+/F1.0 10 Tf
+<20696e697469616c6973696572742077657264656e2e2044616d6974206b9a6e6e656e20536965206b65696e20546573742d> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+107.6929 399.5621 Td
+/F1.0 10 Tf
+<446f75626c652076657277656e64656e2028696e6a656374656e292e204461732050726f626c656d206b9a6e6e74656e20536965206c9a73656e2c2077656e6e2065732065696e656e> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+107.6929 384.5335 Td
+/F1.0 10 Tf
+<656e74737072656368656e64656e204b6f6e737472756b746f7220696e20646572204b6c6173736520> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.2 0.4 0.6667 scn
+0.2 0.4 0.6667 SCN
+
+BT
+311.7129 384.5335 Td
+/F3.0 10 Tf
+<48616c66> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+335.7129 384.5335 Td
+/F1.0 10 Tf
+<20678a62652c2077656c6368652064696520496e7374616e7a656e20646572> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+107.6929 369.5049 Td
+/F1.0 10 Tf
+<4162688a6e676967656e20547970656e20656e74676567656e6e696d6d742028616e616c6f67207a7520> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.2 0.4 0.6667 scn
+0.2 0.4 0.6667 SCN
+
+BT
+329.7929 369.5049 Td
+/F3.0 10 Tf
+<4865617274> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.1294 0.1451 0.1608 scn
+0.1294 0.1451 0.1608 SCN
+
+BT
+359.7929 369.5049 Td
+/F1.0 10 Tf
+<292e> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+q
+0.0 0.0 0.0 scn
+0.0 0.0 0.0 SCN
+1 w
+0 J
+0 j
+[] 0 d
+/Stamp2 Do
+0.6 0.6 0.6 scn
+0.6 0.6 0.6 SCN
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.6 0.6 0.6 scn
+0.6 0.6 0.6 SCN
+
+BT
+56.6929 802.2483 Td
+/F1.0 9 Tf
+<4c9a73756e67656e207a756d205072616b74696b756d204d6f636b2d54657374696e67> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.6 0.6 0.6 scn
+0.6 0.6 0.6 SCN
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.6 0.6 0.6 scn
+0.6 0.6 0.6 SCN
+
+BT
+413.0011 802.2483 Td
+/F1.0 9 Tf
+<50726f6772616d6d696572656e203220d02049542e50524f4732> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+Q
+q
+0.0 0.0 0.0 scn
+0.0 0.0 0.0 SCN
+1 w
+0 J
+0 j
+[] 0 d
+/Stamp4 Do
+0.6 0.6 0.6 scn
+0.6 0.6 0.6 SCN
+
+BT
+57.6929 26.7827 Td
+/F1.0 9 Tf
+<405a48415720496e4954> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.6 0.6 0.6 scn
+0.6 0.6 0.6 SCN
+
+BT
+291.313 26.7827 Td
+/F1.0 9 Tf
+<322f32> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+0.6 0.6 0.6 scn
+0.6 0.6 0.6 SCN
+
+BT
+423.8541 26.7827 Td
+/F1.0 9 Tf
+<322e322e2046726167656e207a752054657374696e67205b54555d> Tj
+ET
+
+0.0 0.0 0.0 SCN
+0.0 0.0 0.0 scn
+Q
+Q
+
+endstream
+endobj
+21 0 obj
+<< /Type /Page
+/Parent 3 0 R
+/MediaBox [0 0 595.28 841.89]
+/CropBox [0 0 595.28 841.89]
+/BleedBox [0 0 595.28 841.89]
+/TrimBox [0 0 595.28 841.89]
+/ArtBox [0 0 595.28 841.89]
+/Contents 20 0 R
+/Resources << /ProcSet [/PDF /Text /ImageB /ImageC /ImageI]
+/Font << /F1.1 19 0 R
+/F1.0 13 0 R
+/F3.0 16 0 R
+>>
+/XObject << /Stamp2 30 0 R
+/Stamp4 33 0 R
+>>
+>>
+>>
+endobj
+22 0 obj
+<< /Type /Outlines
+/Count 5
+/First 23 0 R
+/Last 25 0 R
+>>
+endobj
+23 0 obj
+<< /Title
+/Parent 22 0 R
+/Count 0
+/Next 24 0 R
+/Dest [7 0 R /XYZ 0 841.89 null]
+>>
+endobj
+24 0 obj
+<< /Title
+/Parent 22 0 R
+/Count 0
+/Next 25 0 R
+/Prev 23 0 R
+/Dest [7 0 R /XYZ 0 748.1298 null]
+>>
+endobj
+25 0 obj
+<< /Title
+/Parent 22 0 R
+/Count 2
+/First 26 0 R
+/Last 27 0 R
+/Prev 24 0 R
+/Dest [7 0 R /XYZ 0 672.5212 null]
+>>
+endobj
+26 0 obj
+<< /Title
+/Parent 25 0 R
+/Count 0
+/Next 27 0 R
+/Dest [7 0 R /XYZ 0 639.9412 null]
+>>
+endobj
+27 0 obj
+<< /Title
+/Parent 25 0 R
+/Count 0
+/Prev 26 0 R
+/Dest [7 0 R /XYZ 0 414.2315 null]
+>>
+endobj
+28 0 obj
+<< /Nums [0 << /P (1)
+>> 1 << /P (2)
+>>]
+>>
+endobj
+29 0 obj
+<< /Type /XObject
+/Subtype /Form
+/BBox [0 0 595.28 841.89]
+/Length 164
+>>
+stream
+q
+/DeviceRGB cs
+0.0 0.0 0.0 scn
+/DeviceRGB CS
+0.0 0.0 0.0 SCN
+1 w
+0 J
+0 j
+[] 0 d
+q
+0.5 w
+/DeviceRGB CS
+0.6 0.6 0.6 SCN
+56.6929 799.3703 m
+538.5871 799.3703 l
+S
+Q
+Q
+
+endstream
+endobj
+30 0 obj
+<< /Type /XObject
+/Subtype /Form
+/BBox [0 0 595.28 841.89]
+/Length 164
+>>
+stream
+q
+/DeviceRGB cs
+0.0 0.0 0.0 scn
+/DeviceRGB CS
+0.0 0.0 0.0 SCN
+1 w
+0 J
+0 j
+[] 0 d
+q
+0.5 w
+/DeviceRGB CS
+0.6 0.6 0.6 SCN
+56.6929 799.3703 m
+538.5871 799.3703 l
+S
+Q
+Q
+
+endstream
+endobj
+31 0 obj
+<< /Type /XObject
+/Subtype /Image
+/ColorSpace /DeviceRGB
+/BitsPerComponent 8
+/Width 1364
+/Height 740
+/Length 308262
+/Filter [/DCTDecode]
+>>
+stream
+ JFIF Exif MM * b j( 1 r2 i D ' D 'Adobe Photoshop CS4 Macintosh 2010:10:20 16:41:04 T &( . H H JFIF H H Adobe_CM Adobe d
+
W "
+?
+
+ 3 !1AQa"q2B#$Rb34rC%Scs5&DTdE£t6UeuF'Vfv7GWgw 5 !1AQaq"2B#R3$brCScs4%&5DTdEU6teuFVfv'7GWgw ? mv5*,x{E\ ˝ ů3
qe̱C]}O VZul;Ä? FuMϫ};qSc}ƲֺѶ[p_G1`(5$O贽3+q}.Yto 1tګX=61w:Y˿JFakZKw8L~n KwTҫ`kCݸmW7U_ !ߗWr?Kt6[oWus^kUU{voN ?IېEjfq꾣X]eiStuWStƋǦc'6 !I[6ꈀqu[>ϡ? ER^;c26{a!1n\l
fSXax5i?*_kzo1aIq&F~M }?Sӽ/KkF='{ 9iK?kfuUVEoXƸ\ָOmFclxA 6z?"YX
h.qѻ"ǧJasv9Y X%$B@$j$I)I$JRI$I$TLHh.q5$J]$a܊o/Wh(2Ʒ+%(iǞh㧹ato7_EiosZjݯ?~]U:s^X44{<}V /M /Vr,F5slppSĒoMBcIk&ͤhZ DYZyYWדTEH1 6DI@T$eTֽcsIH
+g=
|JdI$$Ǵ=i8%2I%RS=HݲFJdI$UӤ~qpmΆ}"˿II:0&"Q1;OOY c eǹ%sd{l]ןYzsȩ:Fĭ߹ r] _뗛gLńhmp 8} j-oM_&><LGw+&)Ҕ].]s4^Eu% wF UebK Go]_T륭c kZƵk~Z'MH@0|pe\Ԛbɋ /ts謹JߺϱgCԲ:w_u$ʵ{lwScen[` z =y'E :w ϵsbQأ6/lGZ>dW5&ۛ][*ٶϡ Iz}羰}V6ޝȮ~q]햽~j\3v#A GxlWOًԟ;f#MjOS!>~33!kTv;Uܳ_QtWUm܍܃[͍ C
XFYVSs{s22ny/n $MlT}_1yӆ'G]oձ3
7Qxa2 +:. {ax=n=W :?fegh
ǐfo5!} [Vi~VEcʙk@MVao*/ (o?}`tNv>U=r__QAw1 і
Ӡ@
A jӾ~2ml4㜋_hދ6}^]3zvpǠ.wOMɒ&1Gp]LHomtXٗ
+fQN?ܿQ7KV:ֲ2uƀMdYIk{6V=<