summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--00-pflichtenheft/.gitignore302
-rw-r--r--00-pflichtenheft/.gitlab-ci.yml15
-rw-r--r--00-pflichtenheft/.latexmkrc7
-rw-r--r--00-pflichtenheft/Makefile10
-rw-r--r--00-pflichtenheft/assets/KIT_Deckblatt.pdfbin0 -> 11836 bytes
-rw-r--r--00-pflichtenheft/assets/logo.pdfbin0 -> 11797 bytes
-rw-r--r--00-pflichtenheft/assets/logo.svg211
-rw-r--r--00-pflichtenheft/assets/ui/help-desktop.pngbin0 -> 194287 bytes
-rw-r--r--00-pflichtenheft/assets/ui/listening-progess-account-dropdown.pngbin0 -> 215738 bytes
-rw-r--r--00-pflichtenheft/assets/ui/listening-progress-desktop.pngbin0 -> 206009 bytes
-rw-r--r--00-pflichtenheft/assets/ui/listening-progress-mobile.pngbin0 -> 362434 bytes
-rw-r--r--00-pflichtenheft/assets/ui/login-desktop.pngbin0 -> 140797 bytes
-rw-r--r--00-pflichtenheft/assets/ui/login-mobile.pngbin0 -> 212227 bytes
-rw-r--r--00-pflichtenheft/assets/ui/podcasts-desktop-change-language.pngbin0 -> 436348 bytes
-rw-r--r--00-pflichtenheft/assets/ui/podcasts-desktop.pngbin0 -> 429403 bytes
-rw-r--r--00-pflichtenheft/assets/ui/podcasts-mobile.pngbin0 -> 346260 bytes
-rw-r--r--00-pflichtenheft/assets/ui/settings-desktop-1.pngbin0 -> 197214 bytes
-rw-r--r--00-pflichtenheft/assets/ui/settings-desktop-2.pngbin0 -> 187062 bytes
-rw-r--r--00-pflichtenheft/assets/ui/settings-mobile-1.pngbin0 -> 290715 bytes
-rw-r--r--00-pflichtenheft/assets/ui/settings-mobile-2.pngbin0 -> 297685 bytes
-rw-r--r--00-pflichtenheft/pflichtenheft.tex94
-rw-r--r--00-pflichtenheft/pgf-umlsd.sty329
-rw-r--r--00-pflichtenheft/sections/2-produkteinsatz.tex73
-rw-r--r--00-pflichtenheft/sections/TikzPictures/ActivityLogin.tex56
-rw-r--r--00-pflichtenheft/sections/TikzPictures/ActivityRegister.tex60
-rw-r--r--00-pflichtenheft/sections/TikzPictures/ActivityResetPass.tex70
-rw-r--r--00-pflichtenheft/sections/TikzPictures/SequenceSynchroniseSubscription.tex79
-rw-r--r--00-pflichtenheft/sections/TikzPictures/UseCaseUML.tex46
-rw-r--r--00-pflichtenheft/sections/anforderungsanalyse.tex219
-rw-r--r--00-pflichtenheft/sections/benutzeroberflaeche.tex183
-rw-r--r--00-pflichtenheft/sections/einleitung.tex34
-rw-r--r--00-pflichtenheft/sections/glossar.tex272
-rw-r--r--00-pflichtenheft/sections/produktdaten.tex83
-rw-r--r--00-pflichtenheft/sections/produktfunktionen.tex215
-rw-r--r--00-pflichtenheft/sections/produktuebersicht.tex184
-rw-r--r--00-pflichtenheft/sections/tests.tex605
-rw-r--r--00-pflichtenheft/tikz-uml.sty5377
-rw-r--r--00-pflichtenheft/titlepage.tex75
-rw-r--r--01-pflichtenheft-kolloquium/.gitignore302
-rw-r--r--01-pflichtenheft-kolloquium/.gitlab-ci.yml15
-rw-r--r--01-pflichtenheft-kolloquium/CHANGELOG.md34
-rw-r--r--01-pflichtenheft-kolloquium/Makefile10
-rw-r--r--01-pflichtenheft-kolloquium/README.md118
-rw-r--r--01-pflichtenheft-kolloquium/logos/banner_2020_kit.jpgbin0 -> 96829 bytes
-rw-r--r--01-pflichtenheft-kolloquium/notizen40
-rw-r--r--01-pflichtenheft-kolloquium/presentation.tex60
-rw-r--r--01-pflichtenheft-kolloquium/sdqbeamer.cls954
-rw-r--r--01-pflichtenheft-kolloquium/slides/einführung.tex40
-rw-r--r--01-pflichtenheft-kolloquium/slides/features.tex37
-rw-r--r--01-pflichtenheft-kolloquium/slides/synchronisation.tex36
-rw-r--r--01-pflichtenheft-kolloquium/slides/zielsetzung.tex39
-rw-r--r--01-pflichtenheft-kolloquium/tikz-uml.sty5377
-rw-r--r--10-entwurfsheft/.gitignore302
-rw-r--r--10-entwurfsheft/.gitlab-ci.yml36
-rw-r--r--10-entwurfsheft/.latexmkrc7
-rw-r--r--10-entwurfsheft/Makefile18
-rw-r--r--10-entwurfsheft/README.md31
-rw-r--r--10-entwurfsheft/assets/.gitignore3
-rw-r--r--10-entwurfsheft/assets/KIT_Deckblatt.pdfbin0 -> 11836 bytes
-rw-r--r--10-entwurfsheft/assets/diagrams/backendComponentDiagram.puml61
-rw-r--r--10-entwurfsheft/assets/diagrams/classdiagram.puml463
-rw-r--r--10-entwurfsheft/assets/diagrams/componentdiagram.puml53
-rw-r--r--10-entwurfsheft/assets/diagrams/db.puml78
-rw-r--r--10-entwurfsheft/assets/diagrams/deployment.puml59
-rw-r--r--10-entwurfsheft/assets/diagrams/sequencediagram-forgotAndResetPW.puml41
-rw-r--r--10-entwurfsheft/assets/diagrams/sequencediagram-getEpisodeActions.puml38
-rw-r--r--10-entwurfsheft/assets/diagrams/sequencediagram-getEpisodeActionsOfPodcastSince.puml32
-rw-r--r--10-entwurfsheft/assets/diagrams/sequencediagram-getSubscriptions.puml38
-rw-r--r--10-entwurfsheft/assets/diagrams/sequencediagram-register.puml26
-rw-r--r--10-entwurfsheft/assets/diagrams/sequencediagram-uploadEpisodeActions.puml38
-rw-r--r--10-entwurfsheft/assets/diagrams/sequencediagram-uploadSubscriptions.puml32
-rw-r--r--10-entwurfsheft/assets/episode.pngbin0 -> 10778 bytes
-rw-r--r--10-entwurfsheft/assets/help.pngbin0 -> 14423 bytes
-rw-r--r--10-entwurfsheft/assets/lastupdate.pngbin0 -> 9363 bytes
-rw-r--r--10-entwurfsheft/assets/logo.pdfbin0 -> 11797 bytes
-rw-r--r--10-entwurfsheft/assets/logo.svg211
-rw-r--r--10-entwurfsheft/assets/navbar.pngbin0 -> 8940 bytes
-rw-r--r--10-entwurfsheft/assets/password-margin.pngbin0 -> 8701 bytes
-rw-r--r--10-entwurfsheft/assets/password.pngbin0 -> 8781 bytes
-rw-r--r--10-entwurfsheft/assets/subscription.pngbin0 -> 79929 bytes
-rw-r--r--10-entwurfsheft/entwurfsheft.tex90
-rw-r--r--10-entwurfsheft/pgf-umlsd.sty329
-rw-r--r--10-entwurfsheft/sections/apidoc.tex558
-rw-r--r--10-entwurfsheft/sections/aufbau.tex89
-rw-r--r--10-entwurfsheft/sections/backend.tex28
-rw-r--r--10-entwurfsheft/sections/changes.tex41
-rw-r--r--10-entwurfsheft/sections/einleitung.tex22
-rw-r--r--10-entwurfsheft/sections/frontend.tex150
-rw-r--r--10-entwurfsheft/sections/glossar.tex371
-rw-r--r--10-entwurfsheft/sections/structure.tex104
-rw-r--r--10-entwurfsheft/tikz-uml.sty5377
-rw-r--r--10-entwurfsheft/titlepage.tex75
-rw-r--r--11-entwurfsheft-kolloquium/.gitignore302
-rw-r--r--11-entwurfsheft-kolloquium/.gitlab-ci.yml36
-rw-r--r--11-entwurfsheft-kolloquium/CHANGELOG.md34
-rw-r--r--11-entwurfsheft-kolloquium/Makefile18
-rw-r--r--11-entwurfsheft-kolloquium/README.md118
-rw-r--r--11-entwurfsheft-kolloquium/assets/.gitignore3
-rw-r--r--11-entwurfsheft-kolloquium/assets/.gitingnore3
-rw-r--r--11-entwurfsheft-kolloquium/assets/KIT_Deckblatt.pdfbin0 -> 11836 bytes
-rw-r--r--11-entwurfsheft-kolloquium/assets/diagrams/backendComponentDiagram.puml61
-rw-r--r--11-entwurfsheft-kolloquium/assets/diagrams/classdiagram-authentication.puml112
-rw-r--r--11-entwurfsheft-kolloquium/assets/diagrams/classdiagram-episode-actions.puml84
-rw-r--r--11-entwurfsheft-kolloquium/assets/diagrams/classdiagram-model.puml109
-rw-r--r--11-entwurfsheft-kolloquium/assets/diagrams/classdiagram-subscriptions.puml75
-rw-r--r--11-entwurfsheft-kolloquium/assets/diagrams/classdiagram-util.puml43
-rw-r--r--11-entwurfsheft-kolloquium/assets/diagrams/classdiagram.puml68
-rw-r--r--11-entwurfsheft-kolloquium/assets/diagrams/componentdiagram.puml53
-rw-r--r--11-entwurfsheft-kolloquium/assets/diagrams/db.puml78
-rw-r--r--11-entwurfsheft-kolloquium/assets/diagrams/deployment.puml59
-rw-r--r--11-entwurfsheft-kolloquium/assets/diagrams/sequencediagram-forgotAndResetPW.puml41
-rw-r--r--11-entwurfsheft-kolloquium/assets/diagrams/sequencediagram-getEpisodeActions.puml38
-rw-r--r--11-entwurfsheft-kolloquium/assets/diagrams/sequencediagram-getEpisodeActionsOfPodcastSince.puml32
-rw-r--r--11-entwurfsheft-kolloquium/assets/diagrams/sequencediagram-getSubscriptions.puml36
-rw-r--r--11-entwurfsheft-kolloquium/assets/diagrams/sequencediagram-register.puml26
-rw-r--r--11-entwurfsheft-kolloquium/assets/diagrams/sequencediagram-uploadEpisodeActions.puml38
-rw-r--r--11-entwurfsheft-kolloquium/assets/diagrams/sequencediagram-uploadSubscriptions.puml32
-rw-r--r--11-entwurfsheft-kolloquium/assets/episode.pngbin0 -> 10778 bytes
-rw-r--r--11-entwurfsheft-kolloquium/assets/help.pngbin0 -> 14423 bytes
-rw-r--r--11-entwurfsheft-kolloquium/assets/lastupdate.pngbin0 -> 9363 bytes
-rw-r--r--11-entwurfsheft-kolloquium/assets/logo.pdfbin0 -> 11797 bytes
-rw-r--r--11-entwurfsheft-kolloquium/assets/logo.svg211
-rw-r--r--11-entwurfsheft-kolloquium/assets/navbar.pngbin0 -> 8940 bytes
-rw-r--r--11-entwurfsheft-kolloquium/assets/password-margin.pngbin0 -> 8701 bytes
-rw-r--r--11-entwurfsheft-kolloquium/assets/password.pngbin0 -> 8781 bytes
-rw-r--r--11-entwurfsheft-kolloquium/assets/subscription.pngbin0 -> 79929 bytes
-rw-r--r--11-entwurfsheft-kolloquium/logos/banner_2020_kit.jpgbin0 -> 96829 bytes
-rw-r--r--11-entwurfsheft-kolloquium/notizen40
-rw-r--r--11-entwurfsheft-kolloquium/presentation.tex52
-rw-r--r--11-entwurfsheft-kolloquium/presentation.tex.orig68
-rw-r--r--11-entwurfsheft-kolloquium/sdqbeamer.cls975
-rw-r--r--11-entwurfsheft-kolloquium/slides/apiExtension.tex39
-rw-r--r--11-entwurfsheft-kolloquium/slides/architecture.tex7
-rw-r--r--11-entwurfsheft-kolloquium/slides/changes.tex22
-rw-r--r--11-entwurfsheft-kolloquium/slides/classdiagram.tex57
-rw-r--r--11-entwurfsheft-kolloquium/slides/frontend.tex21
-rw-r--r--11-entwurfsheft-kolloquium/slides/pattern.tex26
-rw-r--r--11-entwurfsheft-kolloquium/slides/sequence.tex7
-rw-r--r--20-implementierungsheft/.gitignore305
-rw-r--r--20-implementierungsheft/.gitlab-ci.yml36
-rw-r--r--20-implementierungsheft/.latexmkrc7
-rw-r--r--20-implementierungsheft/Makefile18
-rw-r--r--20-implementierungsheft/README.md31
-rw-r--r--20-implementierungsheft/assets/.gitignore3
-rw-r--r--20-implementierungsheft/assets/KIT_Deckblatt.pdfbin0 -> 11836 bytes
-rw-r--r--20-implementierungsheft/assets/diagrams/backendComponentDiagram.puml61
-rw-r--r--20-implementierungsheft/assets/diagrams/class_after.puml574
-rw-r--r--20-implementierungsheft/assets/diagrams/classdiagram.puml463
-rw-r--r--20-implementierungsheft/assets/diagrams/componentdiagram.puml79
-rw-r--r--20-implementierungsheft/assets/diagrams/db.puml78
-rw-r--r--20-implementierungsheft/assets/diagrams/deployment.puml59
-rw-r--r--20-implementierungsheft/assets/diagrams/gantt-plan.puml31
-rw-r--r--20-implementierungsheft/assets/diagrams/gantt-reality.puml39
-rw-r--r--20-implementierungsheft/assets/diagrams/sequencediagram-forgotAndResetPW.puml41
-rw-r--r--20-implementierungsheft/assets/diagrams/sequencediagram-getEpisodeActions.puml38
-rw-r--r--20-implementierungsheft/assets/diagrams/sequencediagram-getEpisodeActionsOfPodcastSince.puml32
-rw-r--r--20-implementierungsheft/assets/diagrams/sequencediagram-getSubscriptions.puml38
-rw-r--r--20-implementierungsheft/assets/diagrams/sequencediagram-register.puml26
-rw-r--r--20-implementierungsheft/assets/diagrams/sequencediagram-uploadEpisodeActions.puml38
-rw-r--r--20-implementierungsheft/assets/diagrams/sequencediagram-uploadSubscriptions.puml32
-rw-r--r--20-implementierungsheft/assets/episode.pngbin0 -> 10778 bytes
-rw-r--r--20-implementierungsheft/assets/errorlog.pngbin0 -> 23928 bytes
-rw-r--r--20-implementierungsheft/assets/floatinglabelinput.pngbin0 -> 6125 bytes
-rw-r--r--20-implementierungsheft/assets/gantt-plan-eps-converted-to.pdfbin0 -> 99852 bytes
-rw-r--r--20-implementierungsheft/assets/gantt-plan.eps8314
-rw-r--r--20-implementierungsheft/assets/gantt-plan.pdf0
-rw-r--r--20-implementierungsheft/assets/gantt-reality-eps-converted-to.pdfbin0 -> 135081 bytes
-rw-r--r--20-implementierungsheft/assets/gantt-reality.eps11142
-rw-r--r--20-implementierungsheft/assets/gantt.pngbin0 -> 39076 bytes
-rw-r--r--20-implementierungsheft/assets/help.pngbin0 -> 14423 bytes
-rw-r--r--20-implementierungsheft/assets/lastupdate.pngbin0 -> 9363 bytes
-rw-r--r--20-implementierungsheft/assets/loading.pngbin0 -> 5236 bytes
-rw-r--r--20-implementierungsheft/assets/logo.pdfbin0 -> 11797 bytes
-rw-r--r--20-implementierungsheft/assets/logo.svg211
-rw-r--r--20-implementierungsheft/assets/navbar.pngbin0 -> 8940 bytes
-rw-r--r--20-implementierungsheft/assets/password-margin.pngbin0 -> 8701 bytes
-rw-r--r--20-implementierungsheft/assets/password.pngbin0 -> 8781 bytes
-rw-r--r--20-implementierungsheft/assets/passwordinput.pngbin0 -> 6856 bytes
-rw-r--r--20-implementierungsheft/assets/passwordvalidator.pngbin0 -> 24197 bytes
-rw-r--r--20-implementierungsheft/assets/progresstime.pngbin0 -> 4222 bytes
-rw-r--r--20-implementierungsheft/assets/subscription.pngbin0 -> 79929 bytes
-rw-r--r--20-implementierungsheft/implementierungsheft.tex98
-rw-r--r--20-implementierungsheft/sections/anforderungsanalyse.tex185
-rw-r--r--20-implementierungsheft/sections/apidoc.tex191
-rw-r--r--20-implementierungsheft/sections/aufbau.tex47
-rw-r--r--20-implementierungsheft/sections/backend.tex28
-rw-r--r--20-implementierungsheft/sections/changes.tex241
-rw-r--r--20-implementierungsheft/sections/einleitung.tex11
-rw-r--r--20-implementierungsheft/sections/features.tex43
-rw-r--r--20-implementierungsheft/sections/features.tex.orig82
-rw-r--r--20-implementierungsheft/sections/frontend.tex196
-rw-r--r--20-implementierungsheft/sections/glossar.tex371
-rw-r--r--20-implementierungsheft/sections/methodology.tex16
-rw-r--r--20-implementierungsheft/sections/tests.tex21
-rw-r--r--20-implementierungsheft/sections/timeline.tex7
-rw-r--r--20-implementierungsheft/titlepage.tex75
-rw-r--r--21-implementierungsheft-kolloquium/.gitignore302
-rw-r--r--21-implementierungsheft-kolloquium/.gitlab-ci.yml37
-rw-r--r--21-implementierungsheft-kolloquium/CHANGELOG.md34
-rw-r--r--21-implementierungsheft-kolloquium/Makefile19
-rw-r--r--21-implementierungsheft-kolloquium/README.md118
-rw-r--r--21-implementierungsheft-kolloquium/assets/.gitignore3
-rw-r--r--21-implementierungsheft-kolloquium/assets/.gitingnore3
-rw-r--r--21-implementierungsheft-kolloquium/assets/commits-dashboard.pngbin0 -> 44171 bytes
-rw-r--r--21-implementierungsheft-kolloquium/assets/commits-server.pngbin0 -> 36705 bytes
-rw-r--r--21-implementierungsheft-kolloquium/assets/contributors-dashboard.pngbin0 -> 193750 bytes
-rw-r--r--21-implementierungsheft-kolloquium/assets/contributors-server.pngbin0 -> 222521 bytes
-rw-r--r--21-implementierungsheft-kolloquium/assets/diagrams/backendComponentDiagram.puml61
-rw-r--r--21-implementierungsheft-kolloquium/assets/diagrams/classdiagram-authentication.puml112
-rw-r--r--21-implementierungsheft-kolloquium/assets/diagrams/classdiagram-episode-actions.puml84
-rw-r--r--21-implementierungsheft-kolloquium/assets/diagrams/classdiagram-model.puml109
-rw-r--r--21-implementierungsheft-kolloquium/assets/diagrams/classdiagram-subscriptions.puml75
-rw-r--r--21-implementierungsheft-kolloquium/assets/diagrams/classdiagram-util.puml43
-rw-r--r--21-implementierungsheft-kolloquium/assets/diagrams/classdiagram.puml68
-rw-r--r--21-implementierungsheft-kolloquium/assets/diagrams/componentdiagram.puml53
-rw-r--r--21-implementierungsheft-kolloquium/assets/diagrams/db.puml78
-rw-r--r--21-implementierungsheft-kolloquium/assets/diagrams/deployment.puml59
-rw-r--r--21-implementierungsheft-kolloquium/assets/diagrams/sequencediagram-forgotAndResetPW.puml41
-rw-r--r--21-implementierungsheft-kolloquium/assets/diagrams/sequencediagram-getEpisodeActions.puml38
-rw-r--r--21-implementierungsheft-kolloquium/assets/diagrams/sequencediagram-getEpisodeActionsOfPodcastSince.puml32
-rw-r--r--21-implementierungsheft-kolloquium/assets/diagrams/sequencediagram-getSubscriptions.puml38
-rw-r--r--21-implementierungsheft-kolloquium/assets/diagrams/sequencediagram-register.puml26
-rw-r--r--21-implementierungsheft-kolloquium/assets/diagrams/sequencediagram-uploadEpisodeActions.puml38
-rw-r--r--21-implementierungsheft-kolloquium/assets/diagrams/sequencediagram-uploadSubscriptions.puml32
-rw-r--r--21-implementierungsheft-kolloquium/assets/episode.pngbin0 -> 10778 bytes
-rw-r--r--21-implementierungsheft-kolloquium/assets/gantt-plan.puml31
-rw-r--r--21-implementierungsheft-kolloquium/assets/gantt-reality.puml39
-rw-r--r--21-implementierungsheft-kolloquium/assets/help.pngbin0 -> 14423 bytes
-rw-r--r--21-implementierungsheft-kolloquium/assets/lastupdate.pngbin0 -> 9363 bytes
-rw-r--r--21-implementierungsheft-kolloquium/assets/logo.svg211
-rw-r--r--21-implementierungsheft-kolloquium/assets/navbar.pngbin0 -> 8940 bytes
-rw-r--r--21-implementierungsheft-kolloquium/assets/password-margin.pngbin0 -> 8701 bytes
-rw-r--r--21-implementierungsheft-kolloquium/assets/password.pngbin0 -> 8781 bytes
-rw-r--r--21-implementierungsheft-kolloquium/assets/subscription.pngbin0 -> 79929 bytes
-rw-r--r--21-implementierungsheft-kolloquium/logos/banner_2020_kit.jpgbin0 -> 96829 bytes
-rw-r--r--21-implementierungsheft-kolloquium/notizen40
-rw-r--r--21-implementierungsheft-kolloquium/presentation.tex53
-rw-r--r--21-implementierungsheft-kolloquium/sdqbeamer.cls975
-rw-r--r--21-implementierungsheft-kolloquium/slides/changes.tex84
-rw-r--r--21-implementierungsheft-kolloquium/slides/classdiagram.tex36
-rw-r--r--21-implementierungsheft-kolloquium/slides/components.tex7
-rw-r--r--21-implementierungsheft-kolloquium/slides/difficulties.tex34
-rw-r--r--21-implementierungsheft-kolloquium/slides/einführung.tex40
-rw-r--r--21-implementierungsheft-kolloquium/slides/features.tex37
-rw-r--r--21-implementierungsheft-kolloquium/slides/gantt.tex11
-rw-r--r--21-implementierungsheft-kolloquium/slides/integrationstrategie.tex82
-rw-r--r--21-implementierungsheft-kolloquium/slides/pattern.tex12
-rw-r--r--21-implementierungsheft-kolloquium/slides/requirements.tex58
-rw-r--r--21-implementierungsheft-kolloquium/slides/statistics.tex85
-rw-r--r--21-implementierungsheft-kolloquium/slides/synchronisation.tex36
-rw-r--r--21-implementierungsheft-kolloquium/slides/zielsetzung.tex39
-rw-r--r--21-implementierungsheft-kolloquium/tikz-uml.sty5377
-rw-r--r--30-qualitaetsheft/.gitignore305
-rw-r--r--30-qualitaetsheft/.gitlab-ci.yml36
-rw-r--r--30-qualitaetsheft/.latexmkrc7
-rw-r--r--30-qualitaetsheft/Makefile18
-rw-r--r--30-qualitaetsheft/README.md31
-rw-r--r--30-qualitaetsheft/assets/.gitignore3
-rw-r--r--30-qualitaetsheft/assets/ChangedPassword.PNGbin0 -> 2976 bytes
-rw-r--r--30-qualitaetsheft/assets/KIT_Deckblatt.pdfbin0 -> 11836 bytes
-rw-r--r--30-qualitaetsheft/assets/WrongUser.PNGbin0 -> 2847 bytes
-rw-r--r--30-qualitaetsheft/assets/coverage/authenticationService.pngbin0 -> 26274 bytes
-rw-r--r--30-qualitaetsheft/assets/coverage/episodeActionService.pngbin0 -> 14649 bytes
-rw-r--r--30-qualitaetsheft/assets/coverage/server.pngbin0 -> 42666 bytes
-rw-r--r--30-qualitaetsheft/assets/coverage/subscriptionsService.pngbin0 -> 14334 bytes
-rw-r--r--30-qualitaetsheft/assets/coverage/util.pngbin0 -> 17510 bytes
-rw-r--r--30-qualitaetsheft/assets/lasttest/goodSpecsApdex.pngbin0 -> 20917 bytes
-rw-r--r--30-qualitaetsheft/assets/lasttest/goodSpecsResponse.pngbin0 -> 22682 bytes
-rw-r--r--30-qualitaetsheft/assets/lasttest/goodSpecsTable.pngbin0 -> 46496 bytes
-rw-r--r--30-qualitaetsheft/assets/lasttest/minimumSpecsApdex.pngbin0 -> 22565 bytes
-rw-r--r--30-qualitaetsheft/assets/lasttest/minimumSpecsResponse.pngbin0 -> 21284 bytes
-rw-r--r--30-qualitaetsheft/assets/lasttest/minimumSpecsTable.pngbin0 -> 46556 bytes
-rw-r--r--30-qualitaetsheft/assets/logo.pdfbin0 -> 11797 bytes
-rw-r--r--30-qualitaetsheft/assets/logo.svg211
-rw-r--r--30-qualitaetsheft/assets/notifications.pngbin0 -> 34492 bytes
-rw-r--r--30-qualitaetsheft/assets/select-subscriptions.pngbin0 -> 67845 bytes
-rw-r--r--30-qualitaetsheft/assets/sources/checkstyle-after-processed.txt1
-rw-r--r--30-qualitaetsheft/assets/sources/checkstyle-after.txt22
-rw-r--r--30-qualitaetsheft/assets/sources/checkstyle-before-processed.txt23
-rw-r--r--30-qualitaetsheft/assets/sources/checkstyle-before.txt820
-rw-r--r--30-qualitaetsheft/assets/sources/linter-dashboard-after-processed.txt1
-rw-r--r--30-qualitaetsheft/assets/sources/linter-dashboard-after.txt10
-rw-r--r--30-qualitaetsheft/assets/sources/linter-dashboard-before-processed.txt22
-rw-r--r--30-qualitaetsheft/assets/sources/linter-dashboard-before.txt358
-rw-r--r--30-qualitaetsheft/assets/unsubscribe-podcasts.pngbin0 -> 80156 bytes
-rw-r--r--30-qualitaetsheft/qualitaetsheft.tex106
-rw-r--r--30-qualitaetsheft/sections/backend.tex28
-rw-r--r--30-qualitaetsheft/sections/changes.tex67
-rw-r--r--30-qualitaetsheft/sections/codestyle.tex224
-rw-r--r--30-qualitaetsheft/sections/coverage.tex59
-rw-r--r--30-qualitaetsheft/sections/einleitung.tex13
-rw-r--r--30-qualitaetsheft/sections/frontend.tex196
-rw-r--r--30-qualitaetsheft/sections/glossar.tex391
-rw-r--r--30-qualitaetsheft/sections/lasttest.tex105
-rw-r--r--30-qualitaetsheft/sections/problems.tex65
-rw-r--r--30-qualitaetsheft/sections/testfaelle.tex182
-rw-r--r--30-qualitaetsheft/sections/tests.tex21
-rw-r--r--30-qualitaetsheft/titlepage.tex75
-rw-r--r--31-qualitaetsheft-kolloquium/.gitignore303
-rw-r--r--31-qualitaetsheft-kolloquium/.gitlab-ci.yml37
-rw-r--r--31-qualitaetsheft-kolloquium/CHANGELOG.md34
-rw-r--r--31-qualitaetsheft-kolloquium/Makefile19
-rw-r--r--31-qualitaetsheft-kolloquium/README.md118
-rw-r--r--31-qualitaetsheft-kolloquium/assets/.gitignore3
-rw-r--r--31-qualitaetsheft-kolloquium/assets/.gitingnore3
-rw-r--r--31-qualitaetsheft-kolloquium/assets/commits-dashboard.pngbin0 -> 44171 bytes
-rw-r--r--31-qualitaetsheft-kolloquium/assets/commits-server.pngbin0 -> 36705 bytes
-rw-r--r--31-qualitaetsheft-kolloquium/assets/contributors-dashboard.pngbin0 -> 193750 bytes
-rw-r--r--31-qualitaetsheft-kolloquium/assets/contributors-server.pngbin0 -> 222521 bytes
-rw-r--r--31-qualitaetsheft-kolloquium/assets/coverage/authenticationService.pngbin0 -> 26274 bytes
-rw-r--r--31-qualitaetsheft-kolloquium/assets/coverage/episodeActionService.pngbin0 -> 14649 bytes
-rw-r--r--31-qualitaetsheft-kolloquium/assets/coverage/server.pngbin0 -> 42666 bytes
-rw-r--r--31-qualitaetsheft-kolloquium/assets/coverage/subscriptionsService.pngbin0 -> 14334 bytes
-rw-r--r--31-qualitaetsheft-kolloquium/assets/coverage/util.pngbin0 -> 17510 bytes
-rw-r--r--31-qualitaetsheft-kolloquium/assets/diagrams/backendComponentDiagram.puml61
-rw-r--r--31-qualitaetsheft-kolloquium/assets/diagrams/classdiagram-authentication.puml112
-rw-r--r--31-qualitaetsheft-kolloquium/assets/diagrams/classdiagram-episode-actions.puml84
-rw-r--r--31-qualitaetsheft-kolloquium/assets/diagrams/classdiagram-model.puml109
-rw-r--r--31-qualitaetsheft-kolloquium/assets/diagrams/classdiagram-subscriptions.puml75
-rw-r--r--31-qualitaetsheft-kolloquium/assets/diagrams/classdiagram-util.puml43
-rw-r--r--31-qualitaetsheft-kolloquium/assets/diagrams/classdiagram.puml68
-rw-r--r--31-qualitaetsheft-kolloquium/assets/diagrams/componentdiagram.puml53
-rw-r--r--31-qualitaetsheft-kolloquium/assets/diagrams/db.puml78
-rw-r--r--31-qualitaetsheft-kolloquium/assets/diagrams/deployment.puml59
-rw-r--r--31-qualitaetsheft-kolloquium/assets/diagrams/sequencediagram-forgotAndResetPW.puml41
-rw-r--r--31-qualitaetsheft-kolloquium/assets/diagrams/sequencediagram-getEpisodeActions.puml38
-rw-r--r--31-qualitaetsheft-kolloquium/assets/diagrams/sequencediagram-getEpisodeActionsOfPodcastSince.puml32
-rw-r--r--31-qualitaetsheft-kolloquium/assets/diagrams/sequencediagram-getSubscriptions.puml38
-rw-r--r--31-qualitaetsheft-kolloquium/assets/diagrams/sequencediagram-register.puml26
-rw-r--r--31-qualitaetsheft-kolloquium/assets/diagrams/sequencediagram-uploadEpisodeActions.puml38
-rw-r--r--31-qualitaetsheft-kolloquium/assets/diagrams/sequencediagram-uploadSubscriptions.puml32
-rw-r--r--31-qualitaetsheft-kolloquium/assets/episode.pngbin0 -> 10778 bytes
-rw-r--r--31-qualitaetsheft-kolloquium/assets/gantt-plan.puml31
-rw-r--r--31-qualitaetsheft-kolloquium/assets/gantt-reality.puml39
-rw-r--r--31-qualitaetsheft-kolloquium/assets/help.pngbin0 -> 14423 bytes
-rw-r--r--31-qualitaetsheft-kolloquium/assets/lasttest/goodSpecsApdex.pngbin0 -> 20917 bytes
-rw-r--r--31-qualitaetsheft-kolloquium/assets/lasttest/goodSpecsResponse.pngbin0 -> 22682 bytes
-rw-r--r--31-qualitaetsheft-kolloquium/assets/lasttest/goodSpecsTable.pngbin0 -> 46496 bytes
-rw-r--r--31-qualitaetsheft-kolloquium/assets/lasttest/minimumSpecsApdex.pngbin0 -> 22565 bytes
-rw-r--r--31-qualitaetsheft-kolloquium/assets/lasttest/minimumSpecsResponse.pngbin0 -> 21284 bytes
-rw-r--r--31-qualitaetsheft-kolloquium/assets/lasttest/minimumSpecsTable.pngbin0 -> 46556 bytes
-rw-r--r--31-qualitaetsheft-kolloquium/assets/lastupdate.pngbin0 -> 9363 bytes
-rw-r--r--31-qualitaetsheft-kolloquium/assets/logo.svg211
-rw-r--r--31-qualitaetsheft-kolloquium/assets/navbar.pngbin0 -> 8940 bytes
-rw-r--r--31-qualitaetsheft-kolloquium/assets/password-margin.pngbin0 -> 8701 bytes
-rw-r--r--31-qualitaetsheft-kolloquium/assets/password.pngbin0 -> 8781 bytes
-rw-r--r--31-qualitaetsheft-kolloquium/assets/sources/checkstyle-after-processed.txt1
-rw-r--r--31-qualitaetsheft-kolloquium/assets/sources/checkstyle-after.txt22
-rw-r--r--31-qualitaetsheft-kolloquium/assets/sources/checkstyle-before-processed.txt23
-rw-r--r--31-qualitaetsheft-kolloquium/assets/sources/checkstyle-before.txt820
-rw-r--r--31-qualitaetsheft-kolloquium/assets/sources/linter-dashboard-after-processed.txt1
-rw-r--r--31-qualitaetsheft-kolloquium/assets/sources/linter-dashboard-after.txt10
-rw-r--r--31-qualitaetsheft-kolloquium/assets/sources/linter-dashboard-before-processed.txt22
-rw-r--r--31-qualitaetsheft-kolloquium/assets/sources/linter-dashboard-before.txt358
-rw-r--r--31-qualitaetsheft-kolloquium/assets/subscription.pngbin0 -> 79929 bytes
-rw-r--r--31-qualitaetsheft-kolloquium/logos/banner_2020_kit.jpgbin0 -> 96829 bytes
-rw-r--r--31-qualitaetsheft-kolloquium/logos/kitlogo_de_rgb.pdfbin0 -> 11304 bytes
-rw-r--r--31-qualitaetsheft-kolloquium/logos/kitlogo_en_rgb.pdfbin0 -> 6459 bytes
-rw-r--r--31-qualitaetsheft-kolloquium/logos/pse_logo.pdfbin0 -> 11797 bytes
-rw-r--r--31-qualitaetsheft-kolloquium/notizen40
-rw-r--r--31-qualitaetsheft-kolloquium/presentation.tex62
-rw-r--r--31-qualitaetsheft-kolloquium/sdqbeamer.cls975
-rw-r--r--31-qualitaetsheft-kolloquium/slides/changes.tex146
-rw-r--r--31-qualitaetsheft-kolloquium/slides/classdiagram.tex36
-rw-r--r--31-qualitaetsheft-kolloquium/slides/codestyle.tex179
-rw-r--r--31-qualitaetsheft-kolloquium/slides/components.tex7
-rw-r--r--31-qualitaetsheft-kolloquium/slides/coverage.tex23
-rw-r--r--31-qualitaetsheft-kolloquium/slides/difficulties.tex34
-rw-r--r--31-qualitaetsheft-kolloquium/slides/einführung.tex40
-rw-r--r--31-qualitaetsheft-kolloquium/slides/features.tex37
-rw-r--r--31-qualitaetsheft-kolloquium/slides/gantt.tex11
-rw-r--r--31-qualitaetsheft-kolloquium/slides/integrationstrategie.tex82
-rw-r--r--31-qualitaetsheft-kolloquium/slides/pattern.tex12
-rw-r--r--31-qualitaetsheft-kolloquium/slides/performance.tex56
-rw-r--r--31-qualitaetsheft-kolloquium/slides/problems.tex59
-rw-r--r--31-qualitaetsheft-kolloquium/slides/requirements.tex58
-rw-r--r--31-qualitaetsheft-kolloquium/slides/statistics.tex85
-rw-r--r--31-qualitaetsheft-kolloquium/slides/synchronisation.tex36
-rw-r--r--31-qualitaetsheft-kolloquium/slides/testing.tex59
-rw-r--r--31-qualitaetsheft-kolloquium/slides/zielsetzung.tex39
-rw-r--r--31-qualitaetsheft-kolloquium/tikz-uml.sty5377
-rw-r--r--40-abschlusspraesentation/.gitignore26
-rw-r--r--40-abschlusspraesentation/.gitlab-ci.yml25
-rw-r--r--40-abschlusspraesentation/LICENSE674
-rw-r--r--40-abschlusspraesentation/Makefile10
-rw-r--r--40-abschlusspraesentation/README.md26
-rw-r--r--40-abschlusspraesentation/assets/.gitignore3
-rw-r--r--40-abschlusspraesentation/assets/LastUpdateComp.pngbin0 -> 7796 bytes
-rw-r--r--40-abschlusspraesentation/assets/balken-old.svg301
-rw-r--r--40-abschlusspraesentation/assets/balken-optimized.svg301
-rw-r--r--40-abschlusspraesentation/assets/bootstrap.svg1
-rw-r--r--40-abschlusspraesentation/assets/checkstyle.pngbin0 -> 137220 bytes
-rw-r--r--40-abschlusspraesentation/assets/coffee.gifbin0 -> 568658 bytes
-rw-r--r--40-abschlusspraesentation/assets/commits.gnumericbin0 -> 4680 bytes
-rw-r--r--40-abschlusspraesentation/assets/commits.svg1662
-rw-r--r--40-abschlusspraesentation/assets/component6.drawio114
-rw-r--r--40-abschlusspraesentation/assets/component6.svg4
-rw-r--r--40-abschlusspraesentation/assets/diagrams/componentdiagram.puml79
-rw-r--r--40-abschlusspraesentation/assets/diagrams/packageDiagram1.puml67
-rw-r--r--40-abschlusspraesentation/assets/diagrams/packageDiagram2.puml59
-rw-r--r--40-abschlusspraesentation/assets/diagrams/packageDiagram3.puml51
-rw-r--r--40-abschlusspraesentation/assets/diagrams/packageDiagram4.puml59
-rw-r--r--40-abschlusspraesentation/assets/docker.webpbin0 -> 10998 bytes
-rw-r--r--40-abschlusspraesentation/assets/fontawesome/LICENSE.txt165
-rw-r--r--40-abschlusspraesentation/assets/fontawesome/css/all.css7955
-rw-r--r--40-abschlusspraesentation/assets/fontawesome/css/all.min.css9
-rw-r--r--40-abschlusspraesentation/assets/fontawesome/css/brands.css1522
-rw-r--r--40-abschlusspraesentation/assets/fontawesome/css/brands.min.css6
-rw-r--r--40-abschlusspraesentation/assets/fontawesome/css/fontawesome.css6372
-rw-r--r--40-abschlusspraesentation/assets/fontawesome/css/fontawesome.min.css9
-rw-r--r--40-abschlusspraesentation/assets/fontawesome/css/regular.css19
-rw-r--r--40-abschlusspraesentation/assets/fontawesome/css/regular.min.css6
-rw-r--r--40-abschlusspraesentation/assets/fontawesome/css/solid.css19
-rw-r--r--40-abschlusspraesentation/assets/fontawesome/css/solid.min.css6
-rw-r--r--40-abschlusspraesentation/assets/fontawesome/webfonts/fa-brands-400.ttfbin0 -> 187208 bytes
-rw-r--r--40-abschlusspraesentation/assets/fontawesome/webfonts/fa-brands-400.woff2bin0 -> 108020 bytes
-rw-r--r--40-abschlusspraesentation/assets/fontawesome/webfonts/fa-regular-400.ttfbin0 -> 63952 bytes
-rw-r--r--40-abschlusspraesentation/assets/fontawesome/webfonts/fa-regular-400.woff2bin0 -> 24948 bytes
-rw-r--r--40-abschlusspraesentation/assets/fontawesome/webfonts/fa-solid-900.ttfbin0 -> 394628 bytes
-rw-r--r--40-abschlusspraesentation/assets/fontawesome/webfonts/fa-solid-900.woff2bin0 -> 150124 bytes
-rw-r--r--40-abschlusspraesentation/assets/fontawesome/webfonts/fa-v4compatibility.ttfbin0 -> 10172 bytes
-rw-r--r--40-abschlusspraesentation/assets/fontawesome/webfonts/fa-v4compatibility.woff2bin0 -> 4564 bytes
-rw-r--r--40-abschlusspraesentation/assets/gitlab.svg60
-rw-r--r--40-abschlusspraesentation/assets/jmeter.svg159
-rw-r--r--40-abschlusspraesentation/assets/latex.svg8
-rw-r--r--40-abschlusspraesentation/assets/lets-encrypt.svg1
-rw-r--r--40-abschlusspraesentation/assets/logo.pngbin0 -> 20530 bytes
-rw-r--r--40-abschlusspraesentation/assets/logo.svg234
-rw-r--r--40-abschlusspraesentation/assets/mariadb.svg15
-rw-r--r--40-abschlusspraesentation/assets/performance.svg466
-rw-r--r--40-abschlusspraesentation/assets/plantuml.svg41
-rw-r--r--40-abschlusspraesentation/assets/spring.svg51
-rw-r--r--40-abschlusspraesentation/assets/tachodiagramm.svg1683
-rw-r--r--40-abschlusspraesentation/assets/ui-components/full (Kopie 1).pngbin0 -> 92372 bytes
-rw-r--r--40-abschlusspraesentation/assets/ui-components/full.pngbin0 -> 92372 bytes
-rw-r--r--40-abschlusspraesentation/assets/ui-components/layer1.pngbin0 -> 11541 bytes
-rw-r--r--40-abschlusspraesentation/assets/ui-components/layer2.pngbin0 -> 23536 bytes
-rw-r--r--40-abschlusspraesentation/assets/ui-components/layer3.pngbin0 -> 71591 bytes
-rw-r--r--40-abschlusspraesentation/assets/vue.svg2
-rw-r--r--40-abschlusspraesentation/package-lock.json4126
-rw-r--r--40-abschlusspraesentation/package.json23
-rw-r--r--40-abschlusspraesentation/presentation.md222
-rw-r--r--40-abschlusspraesentation/script.js16
-rw-r--r--40-abschlusspraesentation/style.css29
444 files changed, 100165 insertions, 0 deletions
diff --git a/00-pflichtenheft/.gitignore b/00-pflichtenheft/.gitignore
new file mode 100644
index 0000000..87ec682
--- /dev/null
+++ b/00-pflichtenheft/.gitignore
@@ -0,0 +1,302 @@
+## Core latex/pdflatex auxiliary files:
+*.aux
+*.lof
+*.log
+*.lot
+*.fls
+*.out
+*.toc
+*.fmt
+*.fot
+*.cb
+*.cb2
+.*.lb
+
+## Intermediate documents:
+*.dvi
+*.xdv
+*-converted-to.*
+# these rules might exclude image files for figures etc.
+# *.ps
+# *.eps
+*.pdf
+!assets/*.pdf
+
+## Generated if empty string is given at "Please type another file name for output:"
+.pdf
+
+## Bibliography auxiliary files (bibtex/biblatex/biber):
+*.bbl
+*.bcf
+*.blg
+*-blx.aux
+*-blx.bib
+*.run.xml
+
+## Build tool auxiliary files:
+*.fdb_latexmk
+*.synctex
+*.synctex(busy)
+*.synctex.gz
+*.synctex.gz(busy)
+*.pdfsync
+
+## Build tool directories for auxiliary files
+# latexrun
+latex.out/
+
+## Auxiliary and intermediate files from other packages:
+# algorithms
+*.alg
+*.loa
+
+# achemso
+acs-*.bib
+
+# amsthm
+*.thm
+
+# beamer
+*.nav
+*.pre
+*.snm
+*.vrb
+
+# changes
+*.soc
+
+# comment
+*.cut
+
+# cprotect
+*.cpt
+
+# elsarticle (documentclass of Elsevier journals)
+*.spl
+
+# endnotes
+*.ent
+
+# fixme
+*.lox
+
+# feynmf/feynmp
+*.mf
+*.mp
+*.t[1-9]
+*.t[1-9][0-9]
+*.tfm
+
+#(r)(e)ledmac/(r)(e)ledpar
+*.end
+*.?end
+*.[1-9]
+*.[1-9][0-9]
+*.[1-9][0-9][0-9]
+*.[1-9]R
+*.[1-9][0-9]R
+*.[1-9][0-9][0-9]R
+*.eledsec[1-9]
+*.eledsec[1-9]R
+*.eledsec[1-9][0-9]
+*.eledsec[1-9][0-9]R
+*.eledsec[1-9][0-9][0-9]
+*.eledsec[1-9][0-9][0-9]R
+
+# glossaries
+*.acn
+*.acr
+*.glg
+*.glo
+*.gls
+*.glsdefs
+*.lzo
+*.lzs
+*.slg
+*.slo
+*.sls
+
+# uncomment this for glossaries-extra (will ignore makeindex's style files!)
+*.ist
+
+# gnuplot
+*.gnuplot
+*.table
+
+# gnuplottex
+*-gnuplottex-*
+
+# gregoriotex
+*.gaux
+*.glog
+*.gtex
+
+# htlatex
+*.4ct
+*.4tc
+*.idv
+*.lg
+*.trc
+*.xref
+
+# hyperref
+*.brf
+
+# knitr
+*-concordance.tex
+# TODO Uncomment the next line if you use knitr and want to ignore its generated tikz files
+# *.tikz
+*-tikzDictionary
+
+# listings
+*.lol
+
+# luatexja-ruby
+*.ltjruby
+
+# makeidx
+*.idx
+*.ilg
+*.ind
+
+# minitoc
+*.maf
+*.mlf
+*.mlt
+*.mtc[0-9]*
+*.slf[0-9]*
+*.slt[0-9]*
+*.stc[0-9]*
+
+# minted
+_minted*
+*.pyg
+
+# morewrites
+*.mw
+
+# newpax
+*.newpax
+
+# nomencl
+*.nlg
+*.nlo
+*.nls
+
+# pax
+*.pax
+
+# pdfpcnotes
+*.pdfpc
+
+# sagetex
+*.sagetex.sage
+*.sagetex.py
+*.sagetex.scmd
+
+# scrwfile
+*.wrt
+
+# svg
+svg-inkscape/
+
+# sympy
+*.sout
+*.sympy
+sympy-plots-for-*.tex/
+
+# pdfcomment
+*.upa
+*.upb
+
+# pythontex
+*.pytxcode
+pythontex-files-*/
+
+# tcolorbox
+*.listing
+
+# thmtools
+*.loe
+
+# TikZ & PGF
+*.dpth
+*.md5
+*.auxlock
+
+# titletoc
+*.ptc
+
+# todonotes
+*.tdo
+
+# vhistory
+*.hst
+*.ver
+
+# easy-todo
+*.lod
+
+# xcolor
+*.xcp
+
+# xmpincl
+*.xmpi
+
+# xindy
+*.xdy
+
+# xypic precompiled matrices and outlines
+*.xyc
+*.xyd
+
+# endfloat
+*.ttt
+*.fff
+
+# Latexian
+TSWLatexianTemp*
+
+## Editors:
+# WinEdt
+*.bak
+*.sav
+
+# Texpad
+.texpadtmp
+
+# LyX
+*.lyx~
+
+# Kile
+*.backup
+
+# gummi
+.*.swp
+
+# KBibTeX
+*~[0-9]*
+
+# TeXnicCenter
+*.tps
+
+# auto folder when using emacs and auctex
+./auto/*
+*.el
+
+# expex forward references with \gathertags
+*-tags.tex
+
+# standalone packages
+*.sta
+
+# Makeindex log files
+*.lpz
+
+# xwatermark package
+*.xwm
+
+# REVTeX puts footnotes in the bibliography by default, unless the nofootinbib
+# option is specified. Footnotes are the stored in a file with suffix Notes.bib.
+# Uncomment the next line to have this generated file ignored.
+#*Notes.bib
diff --git a/00-pflichtenheft/.gitlab-ci.yml b/00-pflichtenheft/.gitlab-ci.yml
new file mode 100644
index 0000000..2cf812b
--- /dev/null
+++ b/00-pflichtenheft/.gitlab-ci.yml
@@ -0,0 +1,15 @@
+image: texlive/texlive
+
+pages:
+ script:
+ - mkdir public
+ - make
+ - mv pflichtenheft.pdf public
+ artifacts:
+ paths:
+ - public
+ rules:
+ - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
+
+
+
diff --git a/00-pflichtenheft/.latexmkrc b/00-pflichtenheft/.latexmkrc
new file mode 100644
index 0000000..bec2b38
--- /dev/null
+++ b/00-pflichtenheft/.latexmkrc
@@ -0,0 +1,7 @@
+# https://tex.stackexchange.com/questions/1226/how-to-make-latexmk-use-makeglossaries
+add_cus_dep('glo', 'gls', 0, 'makeglo2gls');
+add_cus_dep('acn', 'acr', 0, 'makeglo2gls');
+sub makeglo2gls {
+ system("makeglossaries $_[0]");
+}
+
diff --git a/00-pflichtenheft/Makefile b/00-pflichtenheft/Makefile
new file mode 100644
index 0000000..6277cc3
--- /dev/null
+++ b/00-pflichtenheft/Makefile
@@ -0,0 +1,10 @@
+MAIN = pflichtenheft
+FLAGS = -pdf
+
+all:
+ latexmk $(FLAGS) $(MAIN)
+dev:
+ latexmk $(FLAGS) -pvc $(MAIN)
+clean:
+ latexmk -C
+
diff --git a/00-pflichtenheft/assets/KIT_Deckblatt.pdf b/00-pflichtenheft/assets/KIT_Deckblatt.pdf
new file mode 100644
index 0000000..7de8ed4
--- /dev/null
+++ b/00-pflichtenheft/assets/KIT_Deckblatt.pdf
Binary files differ
diff --git a/00-pflichtenheft/assets/logo.pdf b/00-pflichtenheft/assets/logo.pdf
new file mode 100644
index 0000000..91fd334
--- /dev/null
+++ b/00-pflichtenheft/assets/logo.pdf
Binary files differ
diff --git a/00-pflichtenheft/assets/logo.svg b/00-pflichtenheft/assets/logo.svg
new file mode 100644
index 0000000..1609066
--- /dev/null
+++ b/00-pflichtenheft/assets/logo.svg
@@ -0,0 +1,211 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ version="1.2"
+ width="87.589989mm"
+ height="52.16547mm"
+ viewBox="0 0 8758.9989 5216.547"
+ preserveAspectRatio="xMidYMid"
+ fill-rule="evenodd"
+ stroke-width="28.222"
+ stroke-linejoin="round"
+ xml:space="preserve"
+ id="svg206"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg">
+ <defs
+ class="ClipPathGroup"
+ id="defs8" />
+ <defs
+ id="defs51"><font
+ id="EmbeddedFont_1"
+ horiz-adv-x="2048"
+ horiz-origin-x="0"
+ horiz-origin-y="0"
+ vert-origin-x="512"
+ vert-origin-y="768"
+ vert-adv-y="1024">
+ <font-face
+ font-family="Noto Sans Display Light embedded"
+ units-per-em="2048"
+ font-weight="normal"
+ font-style="normal"
+ ascent="2170"
+ descent="609"
+ id="font-face10" />
+ <missing-glyph
+ horiz-adv-x="2048"
+ d="M 0,0 L 2047,0 2047,2047 0,2047 0,0 Z"
+ id="missing-glyph12" />
+ <glyph
+ unicode="y"
+ horiz-adv-x="927"
+ d="M 2,1089 L 127,1089 367,413 C 388,352 407,298 422,250 437,203 449,161 457,124 L 463,124 C 471,156 483,196 498,246 513,296 530,350 551,409 L 786,1089 913,1089 453,-193 C 418,-290 377,-364 328,-416 279,-468 213,-494 131,-494 107,-494 84,-493 63,-490 43,-487 25,-482 8,-476 L 8,-377 C 23,-383 40,-387 57,-391 75,-394 95,-396 117,-396 170,-396 214,-378 249,-342 284,-307 314,-252 340,-179 L 403,4 2,1089 Z"
+ id="glyph14" />
+ <glyph
+ unicode="t"
+ horiz-adv-x="610"
+ d="M 465,80 C 494,80 521,82 547,87 573,91 595,97 614,105 L 614,11 C 594,3 569,-5 541,-11 512,-17 481,-20 449,-20 363,-20 296,5 249,56 202,106 178,189 178,304 L 178,996 27,996 27,1061 178,1100 219,1350 295,1350 295,1090 608,1090 608,996 295,996 295,310 C 295,157 352,80 465,80 Z"
+ id="glyph16" />
+ <glyph
+ unicode="s"
+ horiz-adv-x="742"
+ d="M 817,289 C 817,191 782,115 713,61 643,7 545,-20 418,-20 347,-20 284,-14 228,-1 173,12 126,29 88,50 L 88,162 C 134,138 186,118 244,102 301,86 360,78 420,78 520,78 592,96 636,133 680,169 702,218 702,281 702,341 679,387 632,419 585,451 515,484 422,519 359,542 303,565 255,589 207,613 169,643 142,680 116,717 102,768 102,832 102,919 136,987 204,1037 271,1086 361,1110 473,1110 535,1110 592,1104 646,1092 700,1080 750,1063 795,1043 L 754,946 C 713,964 667,980 617,993 568,1006 518,1012 469,1012 388,1012 326,997 283,967 239,937 217,893 217,836 217,792 228,758 249,733 270,707 301,686 342,668 383,650 433,630 492,609 553,585 608,562 657,537 707,512 745,481 774,443 803,405 817,353 817,289 Z"
+ id="glyph18" />
+ <glyph
+ unicode="r"
+ horiz-adv-x="583"
+ d="M 596,1108 C 646,1108 692,1102 733,1091 L 717,983 C 674,995 632,1001 590,1001 497,1001 423,964 368,890 312,817 285,719 285,598 L 285,-1 168,-1 168,1089 266,1089 279,886 285,886 C 311,948 350,1000 402,1043 455,1086 520,1108 596,1108 Z"
+ id="glyph20" />
+ <glyph
+ unicode="o"
+ horiz-adv-x="927"
+ d="M 1030,547 C 1030,433 1012,333 976,248 940,164 887,98 818,51 749,4 665,-20 565,-20 471,-20 390,3 322,50 253,96 201,162 164,247 127,333 109,433 109,547 109,723 150,861 232,961 315,1061 429,1110 575,1110 672,1110 755,1087 822,1040 890,993 941,927 977,842 1012,757 1030,659 1030,547 Z M 229,547 C 229,407 257,294 312,208 368,123 453,80 567,80 685,80 771,123 826,209 882,295 909,408 909,547 909,637 898,717 875,787 851,856 815,911 766,951 717,990 653,1010 573,1010 459,1010 373,969 315,887 258,805 229,692 229,547 Z"
+ id="glyph22" />
+ <glyph
+ unicode="n"
+ horiz-adv-x="847"
+ d="M 633,1110 C 749,1110 838,1078 900,1014 962,950 993,850 993,713 L 993,1 877,1 877,705 C 877,809 854,885 810,935 766,985 701,1010 616,1010 395,1010 285,871 285,594 L 285,1 168,1 168,1090 262,1090 279,901 287,901 C 314,962 357,1011 416,1051 474,1091 547,1110 633,1110 Z"
+ id="glyph24" />
+ <glyph
+ unicode="m"
+ horiz-adv-x="1430"
+ d="M 1245,1110 C 1348,1110 1427,1080 1485,1018 1542,957 1571,860 1571,727 L 1571,1 1454,1 1454,723 C 1454,820 1434,892 1393,939 1352,986 1296,1010 1227,1010 1130,1010 1056,980 1005,919 953,858 928,764 928,637 L 928,1 811,1 811,723 C 811,820 791,892 750,939 709,986 653,1010 584,1010 487,1010 413,978 361,914 310,850 285,751 285,619 L 285,1 168,1 168,1090 262,1090 279,918 287,918 C 313,971 352,1016 403,1054 455,1092 521,1110 600,1110 675,1110 739,1093 791,1059 842,1025 879,975 899,908 L 907,908 C 936,972 980,1022 1038,1057 1097,1093 1166,1110 1245,1110 Z"
+ id="glyph26" />
+ <glyph
+ unicode="i"
+ horiz-adv-x="187"
+ d="M 227,1493 C 279,1493 305,1464 305,1405 305,1345 279,1315 227,1315 175,1315 150,1345 150,1405 150,1464 175,1493 227,1493 Z M 285,1090 L 285,0 168,0 168,1090 285,1090 Z"
+ id="glyph28" />
+ <glyph
+ unicode="h"
+ horiz-adv-x="847"
+ d="M 285,1059 C 285,1031 284,1003 283,977 281,951 279,926 276,901 L 285,901 C 312,962 355,1011 413,1051 471,1091 543,1110 629,1110 746,1110 836,1078 899,1014 962,950 993,850 993,713 L 993,1 877,1 877,705 C 877,809 854,885 810,935 766,985 701,1010 616,1010 395,1010 285,871 285,594 L 285,1 168,1 168,1557 285,1557 285,1059 Z"
+ id="glyph30" />
+ <glyph
+ unicode="f"
+ horiz-adv-x="689"
+ d="M 575,995 L 332,995 332,-1 213,-1 213,995 27,995 27,1058 213,1093 213,1202 C 213,1445 316,1566 522,1566 559,1566 593,1563 623,1557 653,1551 680,1544 705,1536 L 678,1439 C 655,1448 630,1454 603,1460 577,1465 550,1468 524,1468 456,1468 407,1447 377,1405 347,1362 332,1295 332,1202 L 332,1089 575,1089 575,995 Z"
+ id="glyph32" />
+ <glyph
+ unicode="e"
+ horiz-adv-x="874"
+ d="M 559,1110 C 646,1110 720,1089 779,1046 839,1003 883,944 913,869 943,794 958,708 958,611 L 958,531 229,531 C 231,386 262,275 325,198 387,121 476,82 592,82 656,82 712,88 759,100 806,111 858,130 915,156 L 915,50 C 865,25 814,7 764,-4 713,-15 655,-20 588,-20 434,-20 315,30 232,129 150,229 109,365 109,537 109,648 126,746 162,832 197,918 249,986 315,1036 382,1085 464,1110 559,1110 Z M 559,1012 C 465,1012 389,979 333,912 276,845 243,750 233,627 L 838,627 C 838,742 815,835 769,906 723,977 653,1012 559,1012 Z"
+ id="glyph34" />
+ <glyph
+ unicode="d"
+ horiz-adv-x="900"
+ d="M 535,-20 C 398,-20 293,27 219,120 145,214 109,352 109,535 109,722 147,865 224,963 301,1061 408,1110 545,1110 629,1110 698,1090 752,1050 805,1010 845,961 872,904 L 881,904 C 879,935 878,970 876,1009 873,1048 872,1084 872,1117 L 872,1557 989,1557 989,0 895,0 879,191 872,191 C 845,132 805,82 751,41 697,0 625,-20 535,-20 Z M 553,80 C 669,80 752,119 801,195 850,271 875,382 875,527 L 875,545 C 875,695 850,810 801,890 752,970 671,1010 559,1010 451,1010 369,969 313,886 257,804 229,686 229,533 229,385 256,273 309,196 363,119 444,80 553,80 Z"
+ id="glyph36" />
+ <glyph
+ unicode="c"
+ horiz-adv-x="768"
+ d="M 580,-20 C 429,-20 313,29 231,127 150,226 109,363 109,539 109,662 129,766 170,850 211,935 269,1000 343,1044 417,1088 504,1110 602,1110 651,1110 698,1106 742,1096 787,1087 825,1074 858,1057 L 825,957 C 791,972 754,984 714,993 673,1002 636,1006 600,1006 481,1006 390,964 326,881 261,798 229,685 229,541 229,405 258,294 314,210 371,126 459,84 580,84 630,84 678,90 723,101 768,112 809,125 846,142 L 846,37 C 812,20 773,6 729,-5 685,-15 636,-20 580,-20 Z"
+ id="glyph38" />
+ <glyph
+ unicode="a"
+ horiz-adv-x="822"
+ d="M 535,1108 C 651,1108 737,1078 795,1018 852,958 881,863 881,734 L 881,0 793,0 772,185 766,185 C 729,123 684,74 631,36 578,-1 503,-20 408,-20 311,-20 233,6 176,59 119,111 90,187 90,285 90,394 132,477 215,533 298,589 420,621 580,629 L 764,639 764,715 C 764,822 744,897 705,942 665,987 606,1010 528,1010 477,1010 426,1002 378,987 329,972 281,953 231,928 L 195,1022 C 242,1047 295,1067 352,1084 410,1100 470,1108 535,1108 Z M 594,543 C 466,536 370,512 307,470 244,429 213,367 213,285 213,217 232,165 271,131 310,96 363,78 430,78 535,78 617,111 676,176 735,240 764,330 764,445 L 764,551 594,543 Z"
+ id="glyph40" />
+ <glyph
+ unicode="S"
+ horiz-adv-x="875"
+ d="M 956,381 C 956,294 936,220 894,160 852,100 796,55 724,25 652,-5 571,-20 479,-20 396,-20 324,-14 262,-2 201,11 147,26 102,46 L 102,162 C 152,142 209,124 273,109 338,94 409,87 485,87 589,87 673,110 738,158 803,206 836,278 836,373 836,431 823,478 798,515 772,553 734,586 682,614 630,642 565,670 485,699 410,726 345,757 291,791 236,825 194,868 164,919 134,970 119,1035 119,1112 119,1192 138,1259 176,1314 214,1369 267,1411 333,1440 399,1469 474,1483 559,1483 626,1483 689,1476 750,1463 810,1449 868,1430 924,1405 L 883,1303 C 772,1352 663,1377 555,1377 462,1377 386,1354 328,1310 269,1266 240,1200 240,1114 240,1052 252,1001 278,964 303,926 340,895 389,869 438,843 498,817 567,791 648,762 717,731 775,698 833,664 878,623 909,573 941,523 956,459 956,381 Z"
+ id="glyph42" />
+ <glyph
+ unicode="P"
+ horiz-adv-x="848"
+ d="M 539,1462 C 869,1462 1034,1325 1034,1049 1034,908 992,798 907,718 823,638 690,598 510,598 L 311,598 311,0 193,0 193,1462 539,1462 Z M 528,1358 L 311,1358 311,702 498,702 C 629,702 730,727 803,776 875,825 911,914 911,1043 911,1152 880,1232 818,1282 756,1333 659,1358 528,1358 Z"
+ id="glyph44" />
+ <glyph
+ unicode="E"
+ horiz-adv-x="769"
+ d="M 950,0 L 193,0 193,1462 950,1462 950,1356 311,1356 311,821 913,821 913,715 311,715 311,107 950,107 950,0 Z"
+ id="glyph46" />
+ <glyph
+ unicode=" "
+ horiz-adv-x="503"
+ id="glyph48" />
+ </font></defs>
+ <defs
+ class="TextShapeIndex"
+ id="defs55" />
+ <defs
+ class="EmbeddedBulletChars"
+ id="defs87" />
+
+ <g
+ id="id10"
+ clip-path="none"
+ transform="translate(-700.00001,-2550)">
+
+ <text
+ class="SVGTextShape"
+ id="text151"
+ x="217.60002"
+ y="-56.506969"
+ style="letter-spacing:4.7625px;word-spacing:104.775px"><tspan
+ class="TextParagraph"
+ font-family="'Noto Sans Display Light', sans-serif"
+ font-size="494px"
+ font-weight="400"
+ id="tspan149"><tspan
+ class="TextPosition"
+ x="650.59998"
+ y="7647.4932"
+ id="tspan147"><tspan
+ fill="#808080"
+ stroke="none"
+ style="white-space:pre"
+ id="tspan145"
+ dx="2.1199999">Podcast Synchronisation made Efficient</tspan></tspan></tspan></text>
+ </g><g
+ id="g1277"
+ transform="translate(-700.00001,-2550)"><path
+ id="path131-3"
+ d="m 6694.0006,4763 c -559.5515,4.407 -980.3924,428.0893 -986.038,985.9863 18.2894,552.8957 454.3127,974.1166 989.0352,986.0379 v -235.0244 c -406.8751,-27.3888 -715.1078,-362.1649 -719.0259,-748.0163 12.7874,-421.0793 236.9242,-746.3999 750.0318,-749.98 895.0688,1.4728 1915.5158,0 2730.9957,0 V 4763 Z"
+ style="fill:#0084d1;fill-opacity:1"
+ clip-path="none" /><path
+ id="path131"
+ d="m 6685.0183,2562.996 c -559.5515,4.407 -980.3924,428.0893 -986.038,985.9863 18.2894,552.8957 454.3127,974.1167 989.0352,986.038 v -235.0244 c -406.8751,-27.3888 -715.1078,-362.165 -719.0259,-748.0164 12.7874,-421.0792 236.9242,-746.3998 750.0318,-749.98 895.0688,1.4728 1915.5158,0 2730.996,0 V 2562.996 Z"
+ style="fill:#0084d1;fill-opacity:1"
+ clip-path="none" /></g><g
+ id="g1263"
+ transform="translate(-700.00001,-2550)"><path
+ fill="none"
+ stroke="#069a2e"
+ stroke-width="265"
+ stroke-linejoin="round"
+ d="m 2793,5962 c 1283,0 429,-2762 1712,-2762"
+ id="path124" /><path
+ id="path110-6"
+ d="M 3198.0212,6550 V 6300.0411 H 2448.0411 V 6050.0305 5550.0094 H 2198.0305 V 6300.0411 6550 H 2448.0411 2698 Z"
+ style="fill:#069a2e;fill-opacity:1" /><path
+ id="path110"
+ d="m 4111.997,2550.0252 v 249.9589 h 749.9801 v 250.0106 500.0211 h 250.0106 v -750.0317 -249.9589 h -250.0106 -249.9589 z"
+ style="fill:#069a2e;fill-opacity:1" /></g>
+ <g
+ id="g1249"
+ transform="translate(-700.00001,-2550)"><path
+ fill="#ff8000"
+ stroke="none"
+ d="M 2215,4164 C 2412.6918,3832.6035 2379.3124,3383.7591 2135.4189,3084.8193 1956.8564,2857.4026 1671.3097,2718.8851 1382,2721 c 0,-52.6667 0,-105.3333 0,-158 -60.1303,-1.0792 190.6585,-1.2724 121.9814,2.7933 434.6311,30.3756 832.6257,336.7309 974.9655,748.2365 148.7336,402.6249 41.0263,883.7477 -266.0719,1183.8452 C 1996.6852,4716.1853 1689.0048,4838.6187 1382,4830 c 0,-61.6667 0,-123.3333 0,-185 338.199,2.9253 666.226,-186.816 833,-481 z"
+ id="path193" /><path
+ fill="#ff8000"
+ stroke="none"
+ d="m 1936,3979 c 175.8129,-283.3241 59.7943,-700.6319 -239.8255,-849.407 -94.2713,-50.9942 -201.887,-77.9344 -309.1745,-74.593 0,-57 0,-114 0,-171 396.3865,-24.0968 777.5367,297.6517 818.5878,693.1841 44.0348,337.5467 -149.4277,694.9971 -466.4953,826.9493 -110.1027,49.0687 -231.5272,73.543 -352.0925,67.8666 0,-61.6667 0,-123.3333 0,-185 220.6353,7.5804 440.8554,-115.3286 549,-308 z"
+ id="path186" /><path
+ fill="#ff8000"
+ stroke="none"
+ d="m 1659,3822 c 86.3933,-138.0398 18.2474,-344.669 -134.6962,-402.3205 C 1483.44,3402.2177 1438.3524,3394.2432 1394,3398 c 0,-56.6667 0,-113.3333 0,-170 223.1964,-19.6143 444.7886,153.3254 478.4886,375.1817 32.646,181.6951 -54.6854,381.4331 -217.3127,472.2205 -78.2316,46.131 -170.3991,69.3119 -261.1759,62.5978 0,-58.3333 0,-116.6667 0,-175 105.6736,9.5509 212.8962,-49.2218 265,-141 z"
+ id="path179" /><rect
+ class="BoundingBox"
+ stroke="none"
+ fill="none"
+ x="700"
+ y="2550"
+ width="501"
+ height="4001"
+ id="rect136"
+ style="fill:#ff8000;fill-opacity:1" /></g>
+
+</svg>
diff --git a/00-pflichtenheft/assets/ui/help-desktop.png b/00-pflichtenheft/assets/ui/help-desktop.png
new file mode 100644
index 0000000..b3d1231
--- /dev/null
+++ b/00-pflichtenheft/assets/ui/help-desktop.png
Binary files differ
diff --git a/00-pflichtenheft/assets/ui/listening-progess-account-dropdown.png b/00-pflichtenheft/assets/ui/listening-progess-account-dropdown.png
new file mode 100644
index 0000000..df69bdc
--- /dev/null
+++ b/00-pflichtenheft/assets/ui/listening-progess-account-dropdown.png
Binary files differ
diff --git a/00-pflichtenheft/assets/ui/listening-progress-desktop.png b/00-pflichtenheft/assets/ui/listening-progress-desktop.png
new file mode 100644
index 0000000..cf69719
--- /dev/null
+++ b/00-pflichtenheft/assets/ui/listening-progress-desktop.png
Binary files differ
diff --git a/00-pflichtenheft/assets/ui/listening-progress-mobile.png b/00-pflichtenheft/assets/ui/listening-progress-mobile.png
new file mode 100644
index 0000000..4fe4e1f
--- /dev/null
+++ b/00-pflichtenheft/assets/ui/listening-progress-mobile.png
Binary files differ
diff --git a/00-pflichtenheft/assets/ui/login-desktop.png b/00-pflichtenheft/assets/ui/login-desktop.png
new file mode 100644
index 0000000..bb26027
--- /dev/null
+++ b/00-pflichtenheft/assets/ui/login-desktop.png
Binary files differ
diff --git a/00-pflichtenheft/assets/ui/login-mobile.png b/00-pflichtenheft/assets/ui/login-mobile.png
new file mode 100644
index 0000000..78f619d
--- /dev/null
+++ b/00-pflichtenheft/assets/ui/login-mobile.png
Binary files differ
diff --git a/00-pflichtenheft/assets/ui/podcasts-desktop-change-language.png b/00-pflichtenheft/assets/ui/podcasts-desktop-change-language.png
new file mode 100644
index 0000000..68e2339
--- /dev/null
+++ b/00-pflichtenheft/assets/ui/podcasts-desktop-change-language.png
Binary files differ
diff --git a/00-pflichtenheft/assets/ui/podcasts-desktop.png b/00-pflichtenheft/assets/ui/podcasts-desktop.png
new file mode 100644
index 0000000..33337a1
--- /dev/null
+++ b/00-pflichtenheft/assets/ui/podcasts-desktop.png
Binary files differ
diff --git a/00-pflichtenheft/assets/ui/podcasts-mobile.png b/00-pflichtenheft/assets/ui/podcasts-mobile.png
new file mode 100644
index 0000000..d4939f7
--- /dev/null
+++ b/00-pflichtenheft/assets/ui/podcasts-mobile.png
Binary files differ
diff --git a/00-pflichtenheft/assets/ui/settings-desktop-1.png b/00-pflichtenheft/assets/ui/settings-desktop-1.png
new file mode 100644
index 0000000..ed995fb
--- /dev/null
+++ b/00-pflichtenheft/assets/ui/settings-desktop-1.png
Binary files differ
diff --git a/00-pflichtenheft/assets/ui/settings-desktop-2.png b/00-pflichtenheft/assets/ui/settings-desktop-2.png
new file mode 100644
index 0000000..cdce478
--- /dev/null
+++ b/00-pflichtenheft/assets/ui/settings-desktop-2.png
Binary files differ
diff --git a/00-pflichtenheft/assets/ui/settings-mobile-1.png b/00-pflichtenheft/assets/ui/settings-mobile-1.png
new file mode 100644
index 0000000..acdf7ca
--- /dev/null
+++ b/00-pflichtenheft/assets/ui/settings-mobile-1.png
Binary files differ
diff --git a/00-pflichtenheft/assets/ui/settings-mobile-2.png b/00-pflichtenheft/assets/ui/settings-mobile-2.png
new file mode 100644
index 0000000..2389d6b
--- /dev/null
+++ b/00-pflichtenheft/assets/ui/settings-mobile-2.png
Binary files differ
diff --git a/00-pflichtenheft/pflichtenheft.tex b/00-pflichtenheft/pflichtenheft.tex
new file mode 100644
index 0000000..cd174f4
--- /dev/null
+++ b/00-pflichtenheft/pflichtenheft.tex
@@ -0,0 +1,94 @@
+% \documentclass[a4paper, UTF8, 12pt]{article}
+% \documentclass[a4paper, UTF8, 12pt]{scrbook}
+\documentclass[parskip=half, a4paper, 12pt]{scrartcl}
+
+\usepackage[german]{babel}
+\usepackage[dvipsnames]{xcolor}
+\usepackage{tikz}
+\usetikzlibrary{positioning}
+\usetikzlibrary{calc}
+\usetikzlibrary{arrows}
+\usetikzlibrary{intersections}
+\usepackage{tikz-uml}
+\usepackage{pgf-umlsd}
+\usepgflibrary{arrows} % for pgf-umlsd
+\tikzumlset{fill usecase=white}
+\usepackage[margin=2.5cm]{geometry}
+\usepackage{csquotes}
+\usepackage[T1]{fontenc}
+\usepackage{amsmath}
+\usepackage{pdflscape}
+\usepackage{graphicx}
+\usepackage{caption}
+\usepackage{subcaption}
+\usepackage{float}
+\usepackage{enumitem}
+\usepackage{textpos}
+\usepackage{hyperref}
+\usepackage{fancyhdr}
+\usepackage{multicol}
+
+\hypersetup{
+% ‘texdoc hyperref‘ for options
+ pdftitle={
+ PSE\textsuperscript{2}
+ - Podcast Synchronisation made Efficient Pflichtenheft
+ },
+ bookmarks=true,
+}
+\usepackage{csquotes}
+\usepackage[toc]{glossaries}
+\usepackage{lastpage}
+
+\include{sections/glossar}
+
+\title{Pflichtenheft}
+\author{KIT Students et al}
+\date{2.12.2022}
+
+\pagestyle{fancy}
+\setkomafont{pageheadfoot}{\footnotesize\scshape}
+\fancyhead{} % clear all header fields
+% \fancyhead[L]{Pflichtenheft}
+\fancyhead[L]{PSE\textsuperscript{2} - Podcast Synchronisation made Efficient}
+% \fancyhead[R]{2.12.2022}
+\fancyfoot{} % clear all footer fields
+\fancyfoot[R]{\thepage{} / \pageref{LastPage}}
+\fancyfoot[L]{Praxis der Softwareentwicklung}
+\fancyfoot[C]{}
+
+\begin{document}
+
+\include{titlepage}
+\setcounter{page}{1}
+
+\tableofcontents
+
+\include{sections/einleitung}
+\newpage
+
+\include{sections/anforderungsanalyse}
+\newpage
+
+\include{sections/2-produkteinsatz}
+\newpage
+
+\include{sections/produktuebersicht}
+\newpage
+
+\include{sections/produktfunktionen}
+\newpage
+
+\include{sections/produktdaten}
+\newpage
+
+\include{sections/benutzeroberflaeche}
+\newpage
+
+\include{sections/tests}
+\newpage
+
+\printglossaries
+\glsaddall
+
+\end{document}
diff --git a/00-pflichtenheft/pgf-umlsd.sty b/00-pflichtenheft/pgf-umlsd.sty
new file mode 100644
index 0000000..99847db
--- /dev/null
+++ b/00-pflichtenheft/pgf-umlsd.sty
@@ -0,0 +1,329 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Start of pgf-umlsd.sty
+%
+% Some macros for UML Sequence Diagrams.
+% Home page of project: http://pgf-umlsd.googlecode.com/
+% Author: Xu Yuan <xuyuan.cn@gmail.com>, Southeast University, China
+% Contributor: Nobel Huang <nobel1984@gmail.com>, Southeast University, China
+%
+% History:
+% v0.7 2012/03/05
+% - unify interface of call and callself
+% - non-instantaneous message
+% - bugfix: conflits with tikz library backgrounds
+% v0.6 2011/07/27
+% - Fix Issue 6 reported by frankmorgner@gmail.com
+% - diagram without a thread
+% - allows empty diagram
+% - New manual
+% v0.5 2009/09/30 Fix Issue 2 reported by vlado.handziski
+% - Nested callself is supported
+% - Rename sdloop and sdframe to sdblock
+% v0.4 2008/12/08 Fix Issue 1 reported by MathStuf:
+% Nested sdloop environment hides outer loop
+% v0.3 2008/11/10 in Berlin, fix for the PGF cvs version:
+% - the list items in \foreach are not evaluated by default now,
+% the `evaluate' opinion should be used
+% v0.2 2008/03/20 create project at http://pgf-umlsd.googlecode.com/
+% - use `shadows' library
+% Thanks for Dr. Ludger Humbert's <humbert@uni-wuppertal.de> feedback!
+% - reduce the parameter numbers, the user can write the content
+% of instance (such as no colon)
+% - the user can redefine the `inststyle'
+% - new option: switch underlining of the instance text
+% - new option: switch rounded corners
+% v0.1 2008/01/25 first release at http://www.fauskes.net/pgftikzexamples/
+%
+
+\NeedsTeXFormat{LaTeX2e}[1999/12/01]
+\ProvidesPackage{pgf-umlsd}[2011/07/27 v0.6 Some LaTeX macros for UML
+Sequence Diagrams.]
+
+\RequirePackage{tikz}
+\usetikzlibrary{arrows,shadows}
+
+\RequirePackage{ifthen}
+
+% Options
+% ? the instance name under line ?
+\newif\ifpgfumlsdunderline\pgfumlsdunderlinetrue
+\DeclareOption{underline}{\pgfumlsdunderlinetrue}
+\DeclareOption{underline=true}{\pgfumlsdunderlinetrue}
+\DeclareOption{underline=false}{\pgfumlsdunderlinefalse}
+% ? the instance box with rounded corners ?
+\newif\ifpgfumlsdroundedcorners\pgfumlsdroundedcornersfalse
+\DeclareOption{roundedcorners}{\pgfumlsdroundedcornerstrue}
+\DeclareOption{roundedcorners=true}{\pgfumlsdroundedcornerstrue}
+\DeclareOption{roundedcorners=false}{\pgfumlsdroundedcornersfalse}
+\ProcessOptions
+
+% new counters
+\newcounter{preinst}
+\newcounter{instnum}
+\newcounter{threadnum}
+\newcounter{seqlevel} % level
+\newcounter{callevel}
+\newcounter{callselflevel}
+\newcounter{blocklevel}
+
+% new an instance
+% Example:
+% \newinst[edge distance]{var}{name:class}
+\newcommand{\newinst}[3][0.2]{
+ \stepcounter{instnum}
+ \path (inst\thepreinst.east)+(#1,0) node[inststyle] (inst\theinstnum)
+ {\ifpgfumlsdunderline
+ \underline{#3}
+ \else
+ #3
+ \fi};
+ \path (inst\theinstnum)+(0,-0.5*\unitfactor) node (#2) {};
+ \tikzstyle{instcolor#2}=[]
+ \stepcounter{preinst}
+}
+
+% new an instance thread
+% Example:
+% \newinst[color]{var}{name}{class}
+\newcommand{\newthread}[3][gray!30]{
+ \newinst{#2}{#3}
+ \stepcounter{threadnum}
+ \node[below of=inst\theinstnum,node distance=0.8cm] (thread\thethreadnum) {};
+ \tikzstyle{threadcolor\thethreadnum}=[fill=#1]
+ \tikzstyle{instcolor#2}=[fill=#1]
+}
+
+% draw running (thick) line, should not call directly
+\newcommand*{\drawthread}[2]{
+ \begin{pgfonlayer}{umlsd@threadlayer}
+ \draw[threadstyle] (#1.west) -- (#1.east) -- (#2.east) -- (#2.west) -- cycle;
+ \end{pgfonlayer}
+}
+
+% a function call
+% Example:
+% \begin{call}[height]{caller}{function}{callee}{return}
+% \end{call}
+\newenvironment{call}[5][1]{
+\ifthenelse{\equal{#2}{#4}}
+{
+ \begin{callself}[#1]{#2}{#3}{#5}
+}
+{
+ \begin{callanother}[#1]{#2}{#3}{#4}{#5}
+}
+}
+{
+\ifthenelse{\equal{\f\thecallevel}{\t\thecallevel}}
+{
+ \end{callself}
+}
+{
+ \end{callanother}
+}
+}
+
+% function call to another instance
+% interal use only
+\newenvironment*{callanother}[5][1]{
+ \stepcounter{seqlevel}
+ \stepcounter{callevel} % push
+ \path
+ (#2)+(0,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (cf\thecallevel) {}
+ (#4.\threadbias)+(0,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (ct\thecallevel) {};
+
+ \draw[->,>=triangle 60] ({cf\thecallevel}) -- (ct\thecallevel)
+ node[midway, above] {#3};
+ \def\l\thecallevel{#1}
+ \def\f\thecallevel{#2}
+ \def\t\thecallevel{#4}
+ \def\returnvalue{#5}
+ \tikzstyle{threadstyle}+=[instcolor#2]
+}
+{
+ \addtocounter{seqlevel}{\l\thecallevel}
+ \path
+ (\f\thecallevel)+(0,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (rf\thecallevel) {}
+ (\t\thecallevel.\threadbias)+(0,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (rt\thecallevel) {};
+ \draw[dashed,->,>=angle 60] ({rt\thecallevel}) -- (rf\thecallevel)
+ node[midway, above]{\returnvalue};
+ \drawthread{ct\thecallevel}{rt\thecallevel}
+ \addtocounter{callevel}{-1} % pop
+}
+
+% a function do not need call others
+% interal use only
+% Example:
+% \begin{callself}[height]{caller}{function}{return}
+% \end{callself}
+\newenvironment*{callself}[4][1]{
+ \stepcounter{seqlevel}
+ \stepcounter{callevel} % push
+ \stepcounter{callselflevel}
+
+ \path
+ (#2)+(\thecallselflevel*0.1-0.1,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (sc\thecallevel) {}
+ ({sc\thecallevel}.east)+(0,-0.33*\unitfactor) node (scb\thecallevel) {};
+
+ \draw[->,>=triangle 60] ({sc\thecallevel}.east) -- ++(0.8,0)
+ node[near start, above right] {#3} -- ++(0,-0.33*\unitfactor)
+ -- (scb\thecallevel);
+ \def\l\thecallevel{#1}
+ \def\f\thecallevel{#2}
+ \def\t\thecallevel{#2}
+ \def\returnvalue{#4}
+ \tikzstyle{threadstyle}+=[instcolor#2]
+}{
+ \addtocounter{seqlevel}{\l\thecallevel}
+ \path (\f\thecallevel)+(\thecallselflevel*0.1-0.1,-\theseqlevel*\unitfactor-0.33*\unitfactor) node
+ (sct\thecallevel) {};
+
+ \draw[dashed,->,>=angle 60] ({sct\thecallevel}.east) node
+ (sce\thecallevel) {} -- ++(0.8,0) -- node[midway, right]{\returnvalue} ++(0,-0.33*\unitfactor) -- ++(-0.8,0);
+ \drawthread{scb\thecallevel}{sce\thecallevel}
+ \addtocounter{callevel}{-1} % pop
+ \addtocounter{callselflevel}{-1}
+}
+
+% message between threads
+% Example:
+% \mess[delay]{sender}{message content}{receiver}
+\newcommand{\mess}[4][0]{
+ \stepcounter{seqlevel}
+ \path
+ (#2)+(0,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (mess from) {};
+ \addtocounter{seqlevel}{#1}
+ \path
+ (#4)+(0,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (mess to) {};
+ \draw[->,>=angle 60] (mess from) -- (mess to) node[midway, above]
+ {#3};
+
+ \node (#3 from) at (mess from) {};
+ \node (#3 to) at (mess to) {};
+}
+
+\newenvironment{messcall}[4][1]{
+ \stepcounter{seqlevel}
+ \stepcounter{callevel} % push
+ \path
+ (#2)+(0,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (cf\thecallevel) {}
+ (#4.\threadbias)+(0,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (ct\thecallevel) {};
+
+ \draw[->,>=angle 60] ({cf\thecallevel}) -- (ct\thecallevel)
+ node[midway, above] {#3};
+ \def\l\thecallevel{#1}
+ \def\f\thecallevel{#2}
+ \def\t\thecallevel{#4}
+ \tikzstyle{threadstyle}+=[instcolor#2]
+}
+{
+ \addtocounter{seqlevel}{\l\thecallevel}
+ \path
+ (\f\thecallevel)+(0,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (rf\thecallevel) {}
+ (\t\thecallevel.\threadbias)+(0,-\theseqlevel*\unitfactor-0.3*\unitfactor) node (rt\thecallevel) {};
+ \drawthread{ct\thecallevel}{rt\thecallevel}
+ \addtocounter{callevel}{-1} % pop
+}
+
+% In the situation of multi-threads, some objects are called at the
+% same time. Currently, we have to adjust the bias of thread line
+% manually. Possible parameters are: center, west, east
+\newcommand{\setthreadbias}[1]{\global\def\threadbias{#1}}
+
+% This function makes the call earlier.
+\newcommand{\prelevel}{\addtocounter{seqlevel}{-1}}
+
+% This function makes the call later.
+\newcommand{\postlevel}{\addtocounter{seqlevel}{+1}}
+
+% a block box with caption
+% \begin{sdblock}[caption background color]{caption}{comments}
+% \end{sdblock}
+\newenvironment{sdblock}[3][white]{
+ \stepcounter{seqlevel}
+ \stepcounter{blocklevel} % push
+ \coordinate (blockbeg\theblocklevel) at (0,-\theseqlevel*\unitfactor-\unitfactor);
+ \stepcounter{seqlevel}
+ \def\blockcolor\theblocklevel{#1}
+ \def\blockname\theblocklevel{#2}
+ \def\blockcomm\theblocklevel{#3}
+ \begin{pgfinterruptboundingbox}
+}{
+ \coordinate (blockend) at (0,-\theseqlevel*\unitfactor-2*\unitfactor);
+ \path (current bounding box.east)+(0.2,0) node (boxeast) {}
+ (current bounding box.west |- {blockbeg\theblocklevel}) + (-0.2,0)
+ node (nw) {};
+ \path (boxeast |- blockend) node (se) {};
+
+ % % title
+ \node[blockstyle] (blocktitle) at (nw) {\blockname\theblocklevel};
+ \path (blocktitle.south east) + (0,0.2) node (set) {}
+ (blocktitle.south east) + (-0.2,0) node (seb) {}
+ (blocktitle.north east) + (0.2,0) node (comm) {};
+ \draw[fill=\blockcolor\theblocklevel] (blocktitle.north west) -- (blocktitle.north east) --
+ (set.center) -- (seb.center) -- (blocktitle.south west) -- cycle;
+ \node[blockstyle] (blocktitle) at (nw) {\blockname\theblocklevel};
+ \node[blockcommentstyle] (blockcomment) at (comm) {\blockcomm\theblocklevel};
+
+ \coordinate (se) at (current bounding box.south east);
+ \end{pgfinterruptboundingbox}
+
+ \draw (se) rectangle (nw);
+
+ \addtocounter{blocklevel}{-1} % pop
+ \stepcounter{seqlevel}
+}
+
+% the environment of sequence diagram
+\newenvironment{sequencediagram}{
+ % declare layers
+ \pgfdeclarelayer{umlsd@background}
+ \pgfdeclarelayer{umlsd@threadlayer}
+ \pgfsetlayers{umlsd@background,umlsd@threadlayer,main}
+
+ \begin{tikzpicture}
+ \setlength{\unitlength}{1cm}
+ \tikzstyle{sequence}=[coordinate]
+ \tikzstyle{inststyle}=[rectangle, draw, anchor=west, minimum
+ height=0.8cm, minimum width=1.6cm, fill=white,
+ drop shadow={opacity=1,fill=black}]
+ \ifpgfumlsdroundedcorners
+ \tikzstyle{inststyle}+=[rounded corners=3mm]
+ \fi
+ \tikzstyle{blockstyle}=[anchor=north west]
+ \tikzstyle{blockcommentstyle}=[anchor=north west, font=\small]
+ \tikzstyle{dot}=[inner sep=0pt,fill=black,circle,minimum size=0.2pt]
+ \global\def\unitfactor{0.6}
+ \global\def\threadbias{center}
+ % reset counters
+ \setcounter{preinst}{0}
+ \setcounter{instnum}{0}
+ \setcounter{threadnum}{0}
+ \setcounter{seqlevel}{0}
+ \setcounter{callevel}{0}
+ \setcounter{callselflevel}{0}
+ \setcounter{blocklevel}{0}
+
+ % origin
+ \node[coordinate] (inst0) {};
+}
+{
+ \begin{pgfonlayer}{umlsd@background}
+ \ifnum\c@instnum > 0
+ \foreach \t [evaluate=\t] in {1,...,\theinstnum}{
+ \draw[dotted] (inst\t) -- ++(0,-\theseqlevel*\unitfactor-2.2*\unitfactor);
+ }
+ \fi
+ \ifnum\c@threadnum > 0
+ \foreach \t [evaluate=\t] in {1,...,\thethreadnum}{
+ \path (thread\t)+(0,-\theseqlevel*\unitfactor-0.1*\unitfactor) node (threadend) {};
+ \tikzstyle{threadstyle}+=[threadcolor\t]
+ \drawthread{thread\t}{threadend}
+ }
+ \fi
+ \end{pgfonlayer}
+\end{tikzpicture}}
+
+
+%%% End of pgf-umlsd.sty
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \ No newline at end of file
diff --git a/00-pflichtenheft/sections/2-produkteinsatz.tex b/00-pflichtenheft/sections/2-produkteinsatz.tex
new file mode 100644
index 0000000..2d98e82
--- /dev/null
+++ b/00-pflichtenheft/sections/2-produkteinsatz.tex
@@ -0,0 +1,73 @@
+\section{Produkteinsatz}
+
+Im Folgenden werden Anwendungsbereiche, Zielgruppen und Betriebsbedingungen des
+Produkts geschildert.
+
+\subsection{Anwendungsbereiche}
+
+Der \Gls{podcast}-Synchronisationsserver dient dazu,
+Betreibern von \Glspl{podcatcher} einen performanteren und schlankeren
+Synchronisationsdienst zur Verfügung zu stellen, als aktuell erhältliche Synchronisationsserver.
+Die Nutzer erhalten außerdem eine einfach zu bedienende und übersichtliche Möglichkeit,
+ihre abonnierten \Glspl{podcast} über mehrere Geräte hinweg synchronisieren zu können.
+
+Damit das Produkt seinen Ansprüchen in Sachen Performanz und Nutzerfreundlichkeit
+gerecht werden kann, wird ausdrücklich auf Features, die nicht zur Kernaufgabe gehören,
+was die Synchronisation von \Glspl{podcast} ist, verzichtet.
+Dazu gehören zum Beispiel Funktionalitäten, wie das Suchen von \Glspl{podcast} oder das
+Anhören von \Glspl{episode}, welche nicht bereitgestellt werden.
+Außerdem werden keine extra Konfigurationsmöglichkeiten für die Synchronisation angeboten.
+
+Es wird eine Schnittstelle in Form einer graphischen Weboberfläche
+bereitgestellt, mithilfe welcher der Nutzer seinen Account verwalten und
+synchronisierte \Glspl{podcast} einsehen kann.
+Für die Synchronisation wird der Account mit einer oder mehreren \Gls{podcatcher}-Applikationen
+verknüpft.
+Dadurch werden lokal gespeicherte \Glspl{abo} und Abhörfortschritte auf den
+Account und somit auf alle verknüpften \Gls{podcatcher} übertragen.
+
+
+\subsection{Zielgruppen}
+Zur Zielgruppe gehören Betreiber von \Gls{podcatcher}-Applikationen und deren Nutzer.
+Durch den Synchronisationsserver können die Betreiber ihren Nutzern eine
+schlanke und einfach bedienbare Möglichkeit zum Synchronisieren ihrer abonnierten
+\Glspl{podcast} bieten.
+
+\subsection{Betriebsbedingungen}
+Es müssen folgende Voraussetzungen auf Server- und Nutzerseite erfüllt sein.
+
+%\newcommand{\tabitem}{\vspace{.1cm}~~\llap{\textbullet}~~}
+%\begin{tabular}{l l}
+% Server: & Nutzer: \\
+% % \hline
+% \tabitem Internetanbindung &
+% \tabitem Internetanbindung \\
+% \tabitem Speicherplatz: mind. 12GB &
+% \tabitem Aktueller Webbrowser \\
+% \tabitem Arbeitsspeicher: mind. 2GB &
+% \tabitem \Gls{podcatcher} mit \Gls{gpodder} Unterstützung \\
+% \tabitem CPU: mind. 2 Kerne & \\
+% \tabitem JVM-Fähig (\Gls{java} 17) & \\
+% \tabitem MariaDB-Fähig (MariaDB Server 10.6) & \\
+%\end{tabular}
+
+\begin{multicols}{2}
+Server:
+\begin{itemize}
+ \item Speicherplatz: mind. 12GB
+ \item Arbeitsspeicher: mind. 2GB
+ \item CPU: mind. 2 Kerne
+ \item JVM-Fähig (\Gls{java} 17)
+ \item MariaDB-Fähig \\ (MariaDB Server 10.6)
+\end{itemize}
+\columnbreak
+Nutzer:
+\begin{itemize}
+ \item Internetanbindung
+ \item Aktueller Webbrowser
+ \item \Gls{podcatcher} mit \Gls{gpodder} Unterstützung
+ \item[]
+ \item[]
+\end{itemize}
+\end{multicols}
+
diff --git a/00-pflichtenheft/sections/TikzPictures/ActivityLogin.tex b/00-pflichtenheft/sections/TikzPictures/ActivityLogin.tex
new file mode 100644
index 0000000..701eeef
--- /dev/null
+++ b/00-pflichtenheft/sections/TikzPictures/ActivityLogin.tex
@@ -0,0 +1,56 @@
+\begin{tikzpicture}
+
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ % Nodeklassen für Aktivitätsdiagramm festlegen: %
+ %-------------------------------------------------------------------------------%
+ % start - Schwarzer ausgefüllter Kreis %
+ % activity - Abgerundetes Rechteck für Aktivitäten des Users %
+ % actBox - Rechteck für Reaktionen des Systems %
+ % decision - Karokästchen für Entscheidungen / Abzweigungen %
+ % end - Zielscheibe für das Ende der Aktivität %
+ %-------------------------------------------------------------------------------%
+ % Siehe: https://www-kseta.ttp.kit.edu/fellows/Tanja.Harbaum/tikz_tutorial.pdf %
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ \tikzset{start/.style={circle,minimum width=0.3cm,minimum height=0.3cm,draw,fill}}
+ \tikzset{activity/.style={rectangle,minimum width=1cm,minimum height=0.5cm,rounded corners=5pt,draw,align=center}}
+ \tikzset{actBox/.style={rectangle,minimum width=1cm,minimum height=0.5cm,draw,align=center}}
+ \tikzset{decision/.style={diamond,minimum width=1cm,minimum height=1cm,draw,align=center}}
+ \tikzset{end/.style={draw,double=white,circle,inner sep=1pt,minimum width=0.3cm,minimum height=0.3cm,draw,fill}}
+
+ % Nodes und deren Position (voneinander abhängig) angeben
+ \node[start] (Start) {};
+ \node[activity, right = of Start] (Aufruf) {Website aufrufen};
+ \node[actBox, right = of Aufruf] (Login) {Login page};
+ \node[decision, right = of Login] (Remembered) {Gemerkt?};
+ \node[decision, below left = of Remembered] (RemEnd1) {};
+ \node[activity, below = of RemEnd1] (Input) {E-Mail und\\ Passwort eingeben};
+ \node[activity, below = of Input] (RememberOpt) {Option \string"Passwort merken\string"\\ aus-/abwählen};
+ \node[activity, below = of RememberOpt] (LoginPress) {\string"Anmelden\string"-Button\\ drücken};
+ \node[actBox, left = of LoginPress] (ErrorBox) {Fehlermeldung};
+ \node[decision, below = of LoginPress] (CorrectEntry) {Korrekte\\ Eingabe?};
+ \node[actBox, right = of CorrectEntry] (DashboardShow) {Dashboard\\ der Website};
+ \path[name path=P1] (Remembered.south east) -| (DashboardShow);
+ \path[name path=P2] (RemEnd1.north east) -| (DashboardShow);
+ \node[end, below = of DashboardShow] (End) {};
+ \coordinate (jump1) at (DashboardShow |- RemEnd1){};
+ \draw($(Start.north west)+(-1,2)$) rectangle ($(End.south east)+(2,-1)$);
+ \path ($(Start.north west)+(-1,1.3)$) -- ($(Start -| End)+(2,1.3)$) node[midway]{\Large \textbf{Anmeldung}};
+
+ % Verbindungen zwischen den Nodes
+
+ \draw[-stealth, thick](Start) -- (Aufruf);
+ \draw[-stealth, thick](Aufruf) -- (Login);
+ \draw[-stealth, thick](Login) -- (Remembered);
+ \draw[-stealth, thick](Remembered) -- node[left = 2mm, very near start]{nein} (RemEnd1);
+ \draw[-stealth, thick](Remembered.south east) -- (jump1) node[right = 2mm, near start]{ja} -- (DashboardShow);
+ \draw[-stealth, thick](RemEnd1) -- (Input);
+ \draw[-stealth, thick](Input) -- (RememberOpt);
+ \draw[-stealth, thick](RememberOpt) -- (LoginPress);
+ \draw[-stealth, thick](LoginPress) -- (CorrectEntry);
+ \draw[-stealth, thick](CorrectEntry) -| node[above, very near start]{falsch} (ErrorBox);
+ \draw[-stealth, thick](ErrorBox) |- (RemEnd1);
+ \draw[-stealth, thick](CorrectEntry) -- node[above, midway]{wahr} (DashboardShow);
+ \draw[-stealth, thick](DashboardShow) -- (End);
+
+\end{tikzpicture} \ No newline at end of file
diff --git a/00-pflichtenheft/sections/TikzPictures/ActivityRegister.tex b/00-pflichtenheft/sections/TikzPictures/ActivityRegister.tex
new file mode 100644
index 0000000..b50bafe
--- /dev/null
+++ b/00-pflichtenheft/sections/TikzPictures/ActivityRegister.tex
@@ -0,0 +1,60 @@
+\begin{tikzpicture}
+
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ % Nodeklassen für Aktivitätsdiagramm festlegen: %
+ %-------------------------------------------------------------------------------%
+ % start - Schwarzer ausgefüllter Kreis %
+ % activity - Abgerundetes Rechteck für Aktivitäten des Users %
+ % actBox - Rechteck für Reaktionen des Systems %
+ % decision - Karokästchen für Entscheidungen / Abzweigungen %
+ % end - Zielscheibe für das Ende der Aktivität %
+ %-------------------------------------------------------------------------------%
+ % Siehe: https://www-kseta.ttp.kit.edu/fellows/Tanja.Harbaum/tikz_tutorial.pdf %
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ \tikzset{start/.style={circle,minimum width=0.3cm,minimum height=0.3cm,draw,fill}}
+ \tikzset{activity/.style={rectangle,minimum width=1cm,minimum height=0.5cm,rounded corners=5pt,draw,align=center}}
+ \tikzset{actBox/.style={rectangle,minimum width=1cm,minimum height=0.5cm,draw,align=center}}
+ \tikzset{decision/.style={diamond,minimum width=1cm,minimum height=1cm,draw,align=center}}
+ \tikzset{end/.style={draw,double=white,circle,inner sep=1pt,minimum width=0.3cm,minimum height=0.3cm,draw,fill}}
+
+ % Nodes und deren Position (voneinander abhängig) angeben
+ \node[start] (Start) {};
+ \node[activity, right = of Start] (Aufruf) {Website aufrufen};
+ \node[actBox, right = of Aufruf] (Login1) {Login page};
+ \node[activity, below = of Login1] (RegOpt) {\string"Registrieren\string"-Option\\ auswählen};
+ \node[actBox, below = of RegOpt] (Registrieren) {Registrierungsfenster};
+ \node[decision, below = of Registrieren] (EmailTakenEnd) {};
+ \node[activity, below = of EmailTakenEnd] (Input) {E-Mail-Adresse und\\ zweimal neues\\ Passwort eingeben};
+ \node[activity, below = of Input] (RegPress) {\string"Registrieren\string"-Button\\ drücken};
+ \node[decision, left = of RegPress] (EmailTaken) {E-Mail\\ vergeben?};
+ \node[actBox] (Error1) at (EmailTaken |- EmailTakenEnd) {Fehlermeldung};
+ \node[actBox, below = of EmailTaken] (Confirm) {E-Mail mit Link\\ zur Verifizierung};
+ \node[activity, below = of Confirm] (LinkClick) {Link\\ anklicken};
+ \node[decision, right = of LinkClick] (LinkTime) {Link älter\\ als 24h?};
+ \node[actBox, right = 2cm of LinkTime] (Error2) {Fehler};
+ \node[actBox, below = 1.5cm of LinkTime] (Login2) {Login Page};
+ \node[end] (End) at (Error2 |- Login2) {};
+ \draw ($(Start.north west)+(-2,2)$) rectangle ($(End.south east)+(2,-1)$);
+ \path ($(Start.north west)+(-2,1.4)$) -- ($(Start -| Error2)+(2,1.4)$) node[midway]{\Large \textbf{Registrieren}};
+
+ % Verbindungen zwischen den Nodes
+ \draw[-stealth, thick](Start) -- (Aufruf);
+ \draw[-stealth, thick](Aufruf) -- (Login1);
+ \draw[-stealth, thick](Login1) -- (RegOpt);
+ \draw[-stealth, thick](RegOpt) -- (Registrieren);
+ \draw[-stealth, thick](Registrieren) -- (EmailTakenEnd);
+ \draw[-stealth, thick](EmailTakenEnd) -- (Input);
+ \draw[-stealth, thick](Input) -- (RegPress);
+ \draw[-stealth, thick](RegPress) -- (EmailTaken);
+ \draw[-stealth, thick](EmailTaken) -- node[left, near start]{ja} (Error1);
+ \draw[-stealth, thick](Error1) -- (EmailTakenEnd);
+ \draw[-stealth, thick](EmailTaken) -- node[left, near start]{nein} (Confirm);
+ \draw[-stealth, thick](Confirm) -- (LinkClick);
+ \draw[-stealth, thick](LinkClick) -- (LinkTime);
+ \draw[-stealth, thick](LinkTime) -- node[above, near start]{ja} (Error2);
+ \draw[-stealth, thick](LinkTime) -- node[left, near start]{nein} (Login2);
+ \draw[-stealth, thick](Error2) -- (End);
+ \draw[-stealth, thick](Login2) -- (End);
+
+\end{tikzpicture} \ No newline at end of file
diff --git a/00-pflichtenheft/sections/TikzPictures/ActivityResetPass.tex b/00-pflichtenheft/sections/TikzPictures/ActivityResetPass.tex
new file mode 100644
index 0000000..28a065c
--- /dev/null
+++ b/00-pflichtenheft/sections/TikzPictures/ActivityResetPass.tex
@@ -0,0 +1,70 @@
+\begin{tikzpicture}
+
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ % Nodeklassen für Aktivitätsdiagramm festlegen: %
+ %-------------------------------------------------------------------------------%
+ % start - Schwarzer ausgefüllter Kreis %
+ % activity - Abgerundetes Rechteck für Aktivitäten des Users %
+ % actBox - Rechteck für Reaktionen des Systems %
+ % decision - Karokästchen für Entscheidungen / Abzweigungen %
+ % end - Zielscheibe für das Ende der Aktivität %
+ %-------------------------------------------------------------------------------%
+ % Siehe: https://www-kseta.ttp.kit.edu/fellows/Tanja.Harbaum/tikz_tutorial.pdf %
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ \tikzset{start/.style={circle,minimum width=0.3cm,minimum height=0.3cm,draw,fill}}
+ \tikzset{activity/.style={rectangle,minimum width=1cm,minimum height=0.5cm,rounded corners=5pt,draw,align=center}}
+ \tikzset{actBox/.style={rectangle,minimum width=1cm,minimum height=0.5cm,draw,align=center}}
+ \tikzset{decision/.style={diamond,minimum width=1cm,minimum height=1cm,draw,align=center}}
+ \tikzset{end/.style={draw,double=white,circle,inner sep=1pt,minimum width=0.3cm,minimum height=0.3cm,draw,fill}}
+
+ % Nodes und deren Position (voneinander abhängig) angeben
+ \node[start] (Start) {};
+ \node[activity, right = of Start] (Aufruf) {Website aufrufen};
+ \node[actBox, right = of Aufruf] (Login1) {Login page};
+ \node[activity, below = of Login1] (ForgetOpt) {\string"Passwort vergessen\string"\\ Option auswählen};
+ \node[actBox, below = of ForgetOpt] (Forget) {\string"Passwort vergessen\string"\\ Fenster};
+ \node[decision, below = of Forget] (EmailDecEnd) {};
+ \node[activity, below = of EmailDecEnd] (Input1) {E-Mail-Adresse\\ eingeben};
+ \node[decision, left = of Input1] (EmailDec) {E-Mail\\ registriert?};
+ \path (EmailDec) |- (EmailDecEnd) node[actBox, near end](Error2){Fehler};
+ \node[actBox, below = of EmailDec] (SendMail) {E-Mail mit Link\\ zum Zurücksetzen\\ des Passworts};
+ \node[activity, below = of SendMail] (LinkClick) {Empfangenen Link\\ öffnen};
+ \node[decision, right = of LinkClick] (LinkTime) {Link älter\\ als 24h?};
+ \node[actBox, above = of LinkTime] (Error) {Fehler};
+ \node[end, right = of Error] (End1) {};
+ \node[actBox, below = of LinkTime] (ResetWin) {\string"Passwort zurücksetzen\string"\\ Fenster};
+ \node[decision, left = of ResetWin] (PswCorEnd) {};
+ \node[activity, left = of PswCorEnd] (Input2) {neues Passwort\\ zweimal eingeben};
+ \node[activity, below = 2cm of Input2] (ResetPress) {\string"Passwort zurücksetzen\string"-\\ Button drücken};
+ \node[decision, right = of ResetPress] (PswCorrect) {Passwort\\ legal?};
+ \node[actBox, right = of PswCorrect] (Login2) {Login page};
+ \node[end, right = of Login2] (End2) {};
+ \draw ($(Start.north west)+(-3,2)$) rectangle ($(End2.south east)+(1,-2)$);
+ \path ($(Start.north west)+(-3,1.4)$) -- ($(Start -| End2)+(1,1.4)$) node[midway]{\Large \textbf{Passwort vergessen}};
+
+ % Verbindungen zwischen den Nodes
+ \draw[-stealth, thick](Start) -- (Aufruf);
+ \draw[-stealth, thick](Aufruf) -- (Login1);
+ \draw[-stealth, thick](Login1) -- (ForgetOpt);
+ \draw[-stealth, thick](ForgetOpt) -- (Forget);
+ \draw[-stealth, thick](Forget) -- (EmailDecEnd);
+ \draw[-stealth, thick](EmailDecEnd) -- (Input1);
+ \draw[-stealth, thick](Input1) -- (EmailDec);
+ \draw[-stealth, thick](EmailDec) |- node[left, near start]{nein} (Error2);
+ \draw[-stealth, thick](Error2) -- (EmailDecEnd);
+ \draw[-stealth, thick](EmailDec) -- node[left, near start]{ja} (SendMail);
+ \draw[-stealth, thick](SendMail) -- (LinkClick);
+ \draw[-stealth, thick](LinkClick) -- (LinkTime);
+ \draw[-stealth, thick](LinkTime) -- node[left, near start]{ja} (Error);
+ \draw[-stealth, thick](Error) -- (End1);
+ \draw[-stealth, thick](LinkTime) -- node[left, near start]{nein} (ResetWin);
+ \draw[-stealth, thick](ResetWin) -- (PswCorEnd);
+ \draw[-stealth, thick](PswCorEnd) -- (Input2);
+ \draw[-stealth, thick](Input2) -- (ResetPress);
+ \draw[-stealth, thick](ResetPress) -- (PswCorrect);
+ \draw[-stealth, thick](PswCorrect.north west) -| (PswCorEnd) node[above, near start]{nein};
+ \draw[-stealth, thick](PswCorrect) -- (Login2) node[above, near start]{ja};
+ \draw[-stealth, thick](Login2) -- (End2);
+
+\end{tikzpicture} \ No newline at end of file
diff --git a/00-pflichtenheft/sections/TikzPictures/SequenceSynchroniseSubscription.tex b/00-pflichtenheft/sections/TikzPictures/SequenceSynchroniseSubscription.tex
new file mode 100644
index 0000000..3e68555
--- /dev/null
+++ b/00-pflichtenheft/sections/TikzPictures/SequenceSynchroniseSubscription.tex
@@ -0,0 +1,79 @@
+%\begin{tikzpicture}
+%
+% \begin{umlseqdiag}
+%
+% \umlactor[no ddots]{Benutzer}
+% \umlobject[no ddots]{Podcatcher1}
+% \umlobject[no ddots]{Podcatcher2}
+% \umlobject[no ddots]{Webfrontend}
+% \umlobject[no ddots]{Server}
+%
+% \begin{umlcall}[dt=5, op=abonniere Podcast]{Benutzer}{Podcatcher1}
+% \begin{umlcallself}[dt=8, op=füge Podcast zu Abos hinzu, type=synchron]{Podcatcher1}
+% \end{umlcallself}
+% \begin{umlcall}[op=lade Änderungen hoch]{Podcatcher1}{Server}
+% \begin{umlcallself}[dt=8, op=speichere Änderungen]{Server}
+% \end{umlcallself}
+% \end{umlcall}
+% \end{umlcall}
+%
+% \begin{umlcall}[dt=10, op=Abos anzeigen]{Benutzer}{Webfrontend}
+% \begin{umlcall}[dt=5, op=hole Aboliste, return=Aboliste]{Webfrontend}{Server}
+% \end{umlcall}
+% \end{umlcall}
+%
+% \begin{umlcall}[dt=10, op=Abos anzeigen]{Benutzer}{Podcatcher2}
+% \begin{umlcall}[dt=5, op=hole Aboliste, return=Aboliste]{Podcatcher2}{Server}
+% \end{umlcall}
+% \end{umlcall}
+%
+% \end{umlseqdiag}
+%
+%\end{tikzpicture}
+
+\begin{sequencediagram}
+
+ \newthread{b}{Benutzer}
+ \newinst[2]{p1}{Podcatcher1}
+ \newinst{p2}{Podcatcher2}
+ \newinst[1]{w}{Webfrontend}
+ \newinst[1]{s}{Server}
+
+ \begin{call}{b}{abonniere Podcast}{p1}{}
+ \begin{callself}{p1}{füge Podcasts zu Abos hinzu}{}
+ \begin{call}{p1}{lade Änderungen hoch}{s}{}
+ \begin{callself}{s}{\shortstack{speichere\\Änderungen\\persistent}}{}
+ \end{callself}
+ \end{call}
+ \end{callself}
+ \end{call}
+
+ \begin{call}{b}{Abos anzeigen}{w}{}
+ \begin{call}{w}{hole Aboliste}{s}{Aboliste}
+ \end{call}
+ \end{call}
+
+ \begin{call}{b}{Abos anzeigen}{p2}{}
+ \begin{call}{p2}{hole Aboliste}{s}{Aboliste}
+ \end{call}
+ \end{call}
+
+\end{sequencediagram}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/00-pflichtenheft/sections/TikzPictures/UseCaseUML.tex b/00-pflichtenheft/sections/TikzPictures/UseCaseUML.tex
new file mode 100644
index 0000000..1bb2e2c
--- /dev/null
+++ b/00-pflichtenheft/sections/TikzPictures/UseCaseUML.tex
@@ -0,0 +1,46 @@
+\begin{tikzpicture}%[trim left = 1cm]
+
+ \begin{umlsystem}[x=5] {<<Website>> Podcast Sync Web}
+ \umlusecase[name=a,width=2.5cm] {Registrieren}
+ \umlusecase[name=c,y=-4,width=2.5cm] {Aktion ausführen}
+ \umlusecase[name=d,y=-6,width=2.5cm] {Anmelden}
+ \umlusecase[name=f,y=-2,width=2.5cm] {Sprache ändern (*)}
+ \umlusecase[name=g,x=6,y=-1,width=2.5cm] {Anleitung einsehen}
+ \umlusecase[name=h,x=6,y=-3,width=2.5cm] {Abonnierte Podcasts einsehen}
+ \umlusecase[name=i,x=6,y=-5,width=2.5cm] {Profil verwalten}
+ \umlusecase[name=r,x=6,y=-7.25,width=2.5cm] {Zuletzt angehörte\\ Episoden einsehen}
+ \umlusecase[name=j,x=6,y=-10.5,width=2.5cm] {Mit Google / anderen Anbietern anmelden (*)}
+ \umlusecase[name=k,x=4,y=-13,width=2.5cm] {Passwort vergessen}
+ \umlusecase[name=l,y=-15,width=2.5cm] {Admin Aktion ausführen (*)}
+ \umlusecase[name=m,x=8,y=-15,width=2.5cm] {Statistiken einsehen (*)}
+ \umlusecase[name=n,x=12,y=-4,width=2.5cm] {Passwort ändern}
+ \umlusecase[name=o,x=12,y=-2,width=2.5cm] {Gpodder verknüpfen (*)}
+ \umlusecase[name=p,x=12,y=-6,width=2.5cm] {Personenbezogene Daten abrufen (*)}
+ \umlusecase[name=q,x=12,y=-8,width=2.5cm] {Account löschen}
+ \end{umlsystem}
+
+ \umlactor[y=-3] {User}
+ \umlactor[y=-15] {Admin}
+
+ \umlinherit{Admin}{User}
+
+ \umlassoc{User}{a}
+ \umlassoc{User}{c}
+ \umlassoc{User}{d}
+ \umlassoc{User}{f}
+ \umlassoc{Admin}{l}
+
+ \umlextend{g}{c}
+ \umlextend{h}{c}
+ \umlextend{i}{c}
+ \umlextend{r}{c}
+ \umlextend{j}{d}
+ \umlextend{k}{d}
+ \umlextend{m}{l}
+ \umlinclude{c}{d}
+ \umlinclude{l}{d}
+ \umlextend{n}{i}
+ \umlextend{o}{i}
+ \umlextend{p}{i}
+ \umlextend{q}{i}
+\end{tikzpicture} \ No newline at end of file
diff --git a/00-pflichtenheft/sections/anforderungsanalyse.tex b/00-pflichtenheft/sections/anforderungsanalyse.tex
new file mode 100644
index 0000000..51be6c3
--- /dev/null
+++ b/00-pflichtenheft/sections/anforderungsanalyse.tex
@@ -0,0 +1,219 @@
+\newcommand{\newrequirementlist}[1]{
+ % https://www.overleaf.com/learn/latex/Lists#Creating_a_new_list_with_enumitem
+ \newlist{#1list}{enumerate}{1}
+ \setlist[#1list, 1]
+ {
+ before=\leavevmode,
+ label=\upshape\textlangle #1\arabic*\textrangle,
+ ref=\upshape\textlangle #1\arabic*\textrangle,
+ resume=#1list
+ }
+ }
+
+\newrequirementlist{RM}
+\newrequirementlist{RS}
+\newrequirementlist{RC}
+\newrequirementlist{RW}
+
+\section{Anforderungsanalyse}
+
+\subsection{ Musskriterien }
+
+Musskriterien: unabdingbare Leistungen der Software.
+
+\subsubsection*{ Funktionale Anforderungen }
+
+\begin{RMlist}
+ \item\label{r:login} Der Benutzer kann sich im Webfrontend mit einer
+ E-Mail-Adresse und einem Pass\-wort erstmalig registrieren und bei
+ abgeschlossener Registrierung fortan mit denselben Informationen
+ anmelden.
+ Für eine erfolgreiche Registrierung muss die angegebene
+ E-Mail-Adresse zuerst verifiziert werden.\\
+ \emph{Tests: \ref{t:register}, \ref{t:login}}
+ \item\label{r:store} Die Liste der \Glspl{abo} eines Benutzers sowie
+ der zeitliche Fortschritt beim Anhören(/Ansehen) von jeder begonnen
+ \Gls{episode} werden für jeden Benutzer gespeichert.
+ \item\label{r:sync} Die Liste der \Glspl{abo} eines Benutzers
+ sowie der zeitliche Fortschritt beim Anhören(/Ansehen) von jeder
+ begonnenen \Gls{episode} wird automatisch über alle von einem Benutzer
+ verknüpften \Gls{podcatcher}n aktualisiert.
+ Dabei sind der zu synchronisierende Stand der \Glspl{abo} und der
+ zeitliche Fortschritt jeweils definiert als derjenige Stand, der
+ zeitlich am kürzesten zurückliegt.\\
+ \emph{Tests: \ref{t:sync-sub}, \ref{t:sync-unsub}, \ref{t:sync-episode}}
+ \item\label{r:ui} Das Webfrontend bietet dem Benutzer eine graphische
+ Benutzeroberfläche zur Navigation und zur Ansteuerung einzelner
+ Funktionalitäten.\\
+ \emph{Implizit durch alle Testfälle geprüft.}
+ \item\label{r:reset-pw} Der Benutzer kann sein Passwort ändern und es
+ gibt eine ,,Passwort vergessen''-Funktion.
+ So kann ein angemeldeter Benutzer sein Passwort direkt im Webfrontend
+ ändern.
+ Im nicht angemeldeten Zustand kann der Benutzer sein Passwort über
+ die registrierte E-Mail-Adresse zurücksetzen.\\
+ \emph{Tests: \ref{t:change-pw}, \ref{t:forgot-pw}}
+ \item\label{r:show-podcasts} Das Webfrontend bietet dem Benutzer die
+ Möglichkeit, sich die Liste seiner \Glspl{abo} anzeigen zu
+ lassen.
+ Die dabei dargestellten Informationen beinhalten den Namen des
+ \Glspl{abo} und eine gerundete Angabe darüber, wie lange es her ist,
+ dass der Benutzer das letzte Mal eine \Gls{episode} dieses \Glspl{abo}
+ konsumiert hat.\\
+ \emph{Tests: \ref{t:sync-sub}, \ref{t:sync-unsub}}
+\end{RMlist}
+
+\subsubsection*{ Nicht-funktionale Anforderungen }
+
+\begin{RMlist}
+ \item\label{r:requests} Der Synchronisations-Server kann mindestens
+ 50 Anfragen pro Sekunde verarbeiten.\\
+ \emph{Test: \ref{t:lasttest}}
+ \item\label{r:desktop-first} Das Webfrontend ist primär für
+ Desktop-Benutzer ausgelegt.
+ \item\label{r:gpodder} Der Datenaustausch erfolgt über die Gpodder
+ \Gls{rest-api} unter Verwendung des Datenformats \Gls{json}.
+ \item\label{r:persistent-storage} Die Speicherung der Daten eines
+ Benutzers \ref{r:store} über den Synchronisations-Server erfolgt
+ persistent in einer \Gls{db}. Diese Daten des Benutzers sind die
+ Liste seiner \Glspl{abo} und der zeitliche Fortschritt beim Anhören
+ (/Ansehen) aller begonnenen \Glspl{episode}.
+ \item\label{r:api-extension} Die \Gls{gpodder} wird um Funktionalitäten
+ zur verbesserten Kommunikation zwischen Front- und Backend erweitert
+ (siehe \ref{r:login}).\\
+\end{RMlist}
+
+
+\subsection{ Sollkriterien }
+
+Sollkriterien: erstrebenswerte Leistungen.
+
+\subsubsection*{ Funktionale Anforderungen }
+
+\begin{RSlist}
+ \item\label{r:man} Das Webfrontend bietet die Möglichkeit eine nicht
+ ausgefüllte Benutzeranleitung für das Synchronisieren von \Glspl{podcast}
+ anzuzeigen (Abbildung \ref{fig:help-desktop}).\\
+ \emph{Test: \ref{t:man}}
+ \item\label{r:delete-acc} Der Benutzer kann seinen Account löschen.
+ Daraufhin werden alle auf diesen Benutzer bezogenen Daten gelöscht.\\
+ \emph{Test: \ref{t:delete-acc}}
+\end{RSlist}
+
+\subsubsection*{ Nicht-funktionale Anforderungen }
+
+\begin{RSlist}
+\item\label{r:backend-libs} Das Backend wird in \Gls{java} unter Verwendung des
+ quelloffenen Frameworks Spring implementiert. Weiter wird für die
+ \Gls{db} das relationale Open-Source Datenbankverwaltungssystem MariaDB
+ eingesetzt.
+ \item\label{r:ui-libs} Die Weboberfläche wird mithilfe der
+ \Gls{ui-lib} React oder des Webframeworks Vue in JavaScript und
+ mit dem Frontend-CSS-Framework Bootstrap entwickelt.
+ \item\label{r:ui-source}
+ Verwendete \Glspl{ui-lib} werden von einem \Gls{packagemanager}, wie dem Node
+ Package Manager (npm) bezogen. Ein \Gls{bundler}, wie vite oder Webpack,
+ stellt ein minimiertes Skript von den Teilen der Bibliotheken zusammen,
+ die vom Code verwendet werden. Das minimierte Skript wird dann auf einem
+ eigenen Server für die Weboberfläche bereitgestellt.
+ \item\label{r:spa} Die Weboberfläche wird als \Gls{spa}
+ entworfen und aktualisiert dynamisch ihren Inhalt, sobald es eine
+ Antwort auf eine Anfrage an die \Gls{gpodder} \ref{r:api-compat} erhält.
+ \item\label{r:parse-metadata} Das Backend kann die Metadaten von
+ \Gls{podcast} aus
+ deren \Gls{rss}-Feeds (XML-Dateien) für die Anzeige im Webfrontend
+ \ref{r:show-podcasts} parsen.
+ \item\label{r:pw-requirements} Verwendete Passwörter müssen mindestens 8 Zeichen,
+ ein Sonderzeichen, eine Zahl sowie einen Klein- und einen Großbuchstaben
+ enthalten.
+ Diese Anforderungen gelten also insbesondere für über die Funktionen
+ \ref{r:login} und \ref{r:reset-pw} neu gewählte Passwörter.\\
+ \emph{Test: \ref{t:pw-req}}
+ \item\label{r:save-pw} Passwörter werden sicher mittels \Gls{salt-hash}
+ gespeichert.
+ \item\label{r:session} Im Webfrontend angemeldete Benutzer bleiben dort
+ angemeldet. Hierfür wird ein \Gls{session-token} in einem \Gls{cookie} gespeichert.\\
+\end{RSlist}
+
+\subsection{ Kannkriterien }
+
+Kannkriterien: Leistungen, die enthalten sein können.
+
+\subsubsection*{ Funktionale Anforderungen }
+
+\begin{RClist}
+ \item\label{r:subscribe} Ein Benutzer kann über die Weboberfläche einen
+ abonnierten \Gls{podcast} über einen generierten Link teilen.
+ Öffnet nun ein anderer Nutzer den Link wird dieser zur Weboberfläche
+ weitergeleitet und mit einem Pop-up gefragt, ob dieser den
+ \Gls{podcast} abonnieren
+ möchte, falls noch nicht geschehen.
+ Akzeptiert der Nutzer, so wird der \Gls{podcast} zur Liste der
+ \Glspl{abo} des
+ Nutzers hinzugefügt.
+ Gegebenenfalls muss sich der Benutzer dafür zuerst anmelden.
+ Der Link setzt sich dabei unter anderem aus der URL des Webfrontends oder
+ einem \Gls{pseudoprotocol} und dem \Gls{podcast}-Link des Providers zusammen.
+ \item\label{r:unsubscribe} Das Webfrontend bietet dem Benutzer die Möglichkeit,
+ \Glspl{abo} zu entfernen beziehungsweise \Glspl{podcast} zu deabonnieren.
+ \item\label{r:import} Das Importieren und Exportieren aller benutzerbezogenen
+ Daten wird unterstützt (siehe \ref{r:dsgvo}).
+ \item\label{r:import-other} Das Umsiedeln von anderen Gpodder-Plattformen und
+ damit insbesondere der damit verbundene Datenimport wird unterstützt.
+ \item\label{r:api-compat} Die Weboberfläche ist kompatibel mit beliebigen
+ \Glspl{gpodder}.
+ \item\label{r:responsive} Die Weboberfläche ist \gls{responsive}.
+ \item\label{r:admin} Es gibt Administrator Benutzerkonten. Eine angestrebte
+ Funktionalität dieser privilegierten Konten ist das Einsehen von Statistiken,
+ wie der Anzahl von Benutzern, und dem Abruf der Metadaten eines
+ \Glspl{abo}.
+\end{RClist}
+
+\subsubsection*{ Nicht-funktionale Anforderungen }
+
+\begin{RClist}
+ \item\label{r:login-provider} Die Anmeldung im Webfrontend kann mit dem
+ offenen Protokoll \Gls{oauth} 2.0 über Google, Apple oder Facebook erfolgen.
+ Die bei der Verknüpfung eines \Gls{podcatcher}s mit dem Synchronisationsserver
+ geforderten Anmeldedaten werden dann automatisch für den betreffenden
+ Benutzer generiert.
+ Diese kann er im Webfrontend einsehen.
+ \item\label{r:live-update} Im Webfrontend angemeldete Benutzer bleiben dort
+ angemeldet, wenn das Backend ein Update bekommt.
+ \item\label{r:language} Die Benutzeroberfläche kann in mehreren Sprachen
+ angezeigt werden, wobei neben der standardmäßig deutschen
+ Benutzeroberfläche die zusätzliche Bereitstellung einer englischen
+ Version gegenüber anderen Fremdsprachen priorisiert angestrebt wird.
+ \item\label{r:dsgvo} Der Umgang mit personenbezogenen Daten ist konform mit
+ der \\\Gls{dsgvo} der Europäischen Union.
+ \item\label{r:docker} Die Benutzung von \Gls{docker} vereinfacht das Deployment auf
+ einen Server, da Abhängigkeiten bereits im \Gls{docker}-Image enthalten sind.
+ Außerdem bleibt bei einer Kompromittierung der Software das Host-System
+ durch Virtualisierung der Container sicher.\\
+\end{RClist}
+
+\subsection{ Abgrenzungskriterien }
+
+Abgrenzungskriterien: Leistungen, die explizit nicht umgesetzt werden.
+
+\begin{RWlist}
+ \item\label{r:playback} Das Webfrontend stellt explizit keine Funktionalität
+ zum Anhören von \Glspl{podcast} bereit und grenzt sich unter anderem dadurch
+ von \Gls{podcatcher}-Software ab.
+ \item\label{r:no-logs} Es werden explizit keine Logdateien für Benutzer-Aktionen
+ gespeichert. Stattdessen wird nur genau die Liste der \Glspl{abo} eines
+ Benutzers und der zeitliche Fortschritt jeder \Gls{episode} aktuell gehalten.
+ \item\label{r:no-devices} Die benutzerdefinierte Synchronisation über
+ verschiedene, für die Synchronisation differenzierte Geräte wird nicht
+ unterstützt.
+ Das heißt, die gespeicherten Daten eines Benutzers werden über alle
+ mit seinem Account verbundenen \Gls{podcatcher} unabhängig vom Gerät auf den
+ gleichen, letzten Stand synchronisiert.
+ \item\label{r:discovery} Das Webfrontend bietet keine Funktionalität zum
+ Suchen von \Glspl{podcast} (\Gls{discovery}) an.
+ \item\label{r:no-man} Im Webfrontend wird lediglich die Möglichkeit geboten,
+ eine zunächst leere Benutzeranleitung \ref{r:man} anzuzeigen. Eine
+ inhaltlich vollständig ausgeschriebene Benutzeranleitung wird
+ ausdrücklich nicht bereitgestellt.
+\end{RWlist}
+
diff --git a/00-pflichtenheft/sections/benutzeroberflaeche.tex b/00-pflichtenheft/sections/benutzeroberflaeche.tex
new file mode 100644
index 0000000..536ed04
--- /dev/null
+++ b/00-pflichtenheft/sections/benutzeroberflaeche.tex
@@ -0,0 +1,183 @@
+\section{Benutzeroberfläche}
+
+Die Synchronisation der \Glspl{podcast} soll über eine Weboberfläche verwalten werden.
+Dazu wird eine \Gls{spa} erstellt. Diese kann durch ein
+\Gls{responsive}-Design für Desktop- und Mobilgeräte nutzerfreundlich angezeigt
+werden.
+
+Die Navigation erfolgt über eine Navigationsleiste, welche auf jeder
+nutzerbezogenen Seite zu sehen ist. Über die Navigationsleiste können über
+Knöpfe alle anderen nutzerbezogenen Seiten aufgerufen werden. Über ein
+Dropdown-Menu werden Accounteinstellungen und ein Logout-Knopf sichtbar (siehe
+Abbildung \ref{fig:listening-progress-account-dropdown}). Ein weiters
+Dropdown-Menu erlaubt das Wechseln der Sprache (siehe Abbildung
+\ref{fig:podcast-desktop-change-language}). Der ,,Hilfe''-Eintrag öffnet ein
+Fenster mit Hilfestellungen (siehe Abbildung \ref{fig:help-desktop}). Durch das
+\Gls{responsive}-Design kann die Navigations-Leiste auf Mobilgeräten sich zu
+einem Burger-Menu zusammenklappen.
+
+Die Komponenten der Weboberfläche werden von einem Still-Framework, wie Bootstrap,
+benutzt.
+
+% Übersichtlichkeit wichtig?
+
+% Webanwendung
+% Single-Page-Application
+% Responsive
+% Navigationsleiste
+% Bootstrap
+
+\subsection{Login}
+
+Bei der erstmaligen Nutzung des Services wird der Nutzer aufgefordert, sich neu
+für die \Gls{podcast}-Synchronisation zu registrieren. Dabei gibt der Nutzer seine
+E-Mail und ein Passwort ein. Daraufhin wird dem Nutzer eine E-Mail mit einem
+Bestätigungslink an seine E-Mail-Adresse versandt. Erst wenn der Link angeklickt
+wird, ist der Account freigeschaltet und der Nutzer wird zur Anmeldeseite
+weitergeleitet (siehe Abbildung \ref{fig:login-mobile}).
+
+Alternativ kann der Nutzer sich auch mit einem Identifikationsbereitsteller, wie
+Google oder Facebook registrieren und anmelden.
+
+Zusätzlich kann der Nutzer beim Anmelden über eine Checkbox einstellen, dass
+dieser angemeldet bleiben möchte, sodass sich dieser beim nächsten Aufruf der
+Weboberfläche nicht erneut anmelden muss.
+
+Nach dem Anmelden wird der Nutzer zur \Gls{podcast}-Liste weitergeleitet.
+
+% Registrieren
+% E-Mail und Passwort, E-Mail bestätigung
+
+% anmelden mit E-Mail und Passwort oder es kann sich auch mit einem
+% Identifikations-Bereitsteller (wie Google, Facebook, GitHub) angemeldet
+% werden.
+
+% Angemeldet bleiben
+
+% Anschließlich auf der Startseite
+
+\subsection{Podcast-Liste}
+
+Die Seite der \Gls{podcast}-Liste zeigt eine Liste aller vom Nutzer abonnierten
+\Glspl{podcast}. Diese sind danach sortiert, welcher \Gls{podcast} zuletzt
+gehört wurde (siehe Abbildung \ref{fig:podcast-desktop-change-language}).
+
+\Glspl{podcast} können aufgeklappt werden, um \Glspl{episode} inklusive deren Hörfortschritt
+anzuzeigen. Die \Glspl{episode} werden nach Veröffentlichungszeitpunkt sortiert.
+
+% Navigatinsleiste
+% Zeigt eine Liste aller vom Nutzer abonnierten Podcasts sortiert nach welcher
+% Podcast zuletzt gehört wurde.
+% Podcasts können aufgeklappt werden, um Episoden inklusive deren Hörfortschritt
+% anzuzueigen. Die Episoden werden nach Veröffentlichungszeitpunkt sortiert.
+
+\subsection{Zuletzt gehört}
+
+Die Seite ,,Zuletzt gehört'' zeigt eine Liste der vom Nutzer gehörten
+\Glspl{episode} inklusive Hörfortschritt (siehe Abbildung
+\ref{fig:listening-progress-account-dropdown}). Die \Glspl{episode} sind danach
+sortiert wann sie zuletzt gehört wurden.
+
+Zusätzlich können die beendeten und angefangenen \Glspl{episode} über ein
+Dropdown-Menu auch auf- und absteigend lexikografisch oder nach Hörfortschritt
+sortiert werden.
+
+% \newpage
+
+\subsection{Einstellungen}
+
+Auf der Einstellungsseite darf der Nutzer sein Passwort ändern und seinen
+Account löschen (siehe Abbildung \ref{fig:settings-mobile-1}).
+
+Der Nutzer kann seine personenbezogenen Daten, wie abonnierte \Glspl{podcast} und
+Hörfortschritte, in eine Datei exportieren, welche der Nutzer herunterladen
+kann. Außerdem kann der Nutzer zuvor heruntergeladene Exports wieder
+importieren, um zum Beispiel alte abonnierte \Glspl{podcast} wiederherzustellen.
+
+Zusätzlich kann der Nutzer seine Daten von einer anderen \Gls{gpodder} importieren,
+indem er sich in den Einstellungen auf der anderen \Gls{gpodder} anmeldet.
+
+% Passwort ändern
+% Account löschen
+% Daten importieren/exportieren
+% Daten anderer Gpodder-API importieren
+
+% \vspace{1cm}
+
+%===================================================================================%
+% https://tex.stackexchange.com/questions/55337/how-to-use-figure-inside-a-minipage %
+%===================================================================================%
+\hspace{-.5cm}
+\begin{minipage}[H]{\linewidth}
+ %\centering
+ \begin{minipage}{0.32\linewidth}
+ \begin{figure}[H]
+ \fbox{\includegraphics[width=.9\linewidth]{assets/ui/login-mobile.png}}
+ \setcapindent*{1em}
+ \caption{Anmeldeseite mit Identitätsbereitsteller\\}
+ \label{fig:login-mobile}
+ \end{figure}
+ \end{minipage}
+% \hspace{0.05\linewidth}
+ \begin{minipage}{0.32\linewidth}
+ \begin{figure}[H]
+ \fbox{\includegraphics[width=.9\linewidth]{assets/ui/podcasts-mobile.png}}
+ \setcapindent*{1em}
+ \caption{Mobile \Glspl{podcast}-Seite mit Burger-Menu\\}
+ \label{fig:podcasts-mobile}
+ \end{figure}
+ \end{minipage}
+% \hspace{0.05\linewidth}
+ \begin{minipage}{0.32\linewidth}
+ \begin{figure}[H]
+ \fbox{\includegraphics[width=.9\linewidth]{assets/ui/listening-progress-mobile.png}}
+ \setcapindent*{1em}
+ \caption{Mobile ,,Zuletzt gehört''-Seite mit offenem Burger-Menu}
+ \label{fig:listening-progress-mobile}
+ \end{figure}
+ \end{minipage}
+\end{minipage}
+
+\begin{figure}[H]
+ \centering
+ \fbox{\includegraphics[width=.9\linewidth]{assets/ui/podcasts-desktop-change-language.png}}
+ \caption{\Glspl{podcast}-Seite mit \Glspl{episode} und Sprachauswahl}
+ \label{fig:podcast-desktop-change-language}
+\end{figure}
+
+\begin{figure}[H]
+ \centering
+ \fbox{\includegraphics[width=.9\linewidth]{assets/ui/listening-progess-account-dropdown.png}}
+ \caption{,,Zuletzt gehört''-Seite mit Fortschrittsbalken und Account-Dropdown}
+ \label{fig:listening-progress-account-dropdown}
+\end{figure}
+
+\begin{figure}[H]
+ \centering
+ \includegraphics[width=.87\linewidth]{assets/ui/help-desktop.png}
+ \caption{Hilfe-Fenster, welches mit dem Menu-Eintrag ,,Hilfe'' geöffnet wird}
+ \label{fig:help-desktop}
+\end{figure}
+
+\begin{minipage}[H]{.9\linewidth}
+ \centering
+ \begin{minipage}{.4\linewidth}
+ \begin{figure}[H]
+ \centering
+ \fbox{\includegraphics[width=.8\linewidth]{assets/ui/settings-mobile-1.png}}
+ \setcapindent*{1em}
+ \caption{Einstellungen mit Ändern des Passworts und Gpodder-Verknüpfung}
+ \label{fig:settings-mobile-1}
+ \end{figure}%
+ \end{minipage}
+ \hspace{.5cm}
+ \begin{minipage}{.4\linewidth}
+ \begin{figure}[H]
+ \fbox{\includegraphics[width=.8\linewidth]{assets/ui/settings-mobile-2.png}}
+ \setcapindent*{1em}
+ \caption{Einstellungen mit Datenexport und Accountlöschung\\}
+ \label{fig:settings-mobile-2}
+ \end{figure}
+ \end{minipage}
+\end{minipage}
+
diff --git a/00-pflichtenheft/sections/einleitung.tex b/00-pflichtenheft/sections/einleitung.tex
new file mode 100644
index 0000000..67b6208
--- /dev/null
+++ b/00-pflichtenheft/sections/einleitung.tex
@@ -0,0 +1,34 @@
+\section{Einleitung}
+
+Dieses Softwareprojekt setzt sich zum Ziel, einen im Vergleich zu anderen Synchronisationsservern
+möglichst schlanken und performanten Synchronisationsserver für \Glspl{podcast}
+bereitzustellen, welcher von sogenannten \Glspl{podcatcher} verwendet werden soll.
+
+Ein \Gls{podcatcher} ist eine Anwendung, mit der \Glspl{podcast} abonniert,
+heruntergeladen und angehört werden können.
+Durch diesen Synchronisationsserver ermöglichen Betreiber von \Glspl{podcatcher} den Nutzern
+eine einfache Möglichkeit zum Synchronisieren von \Glspl{podcast} über verschiedene
+Geräte hinweg.
+Im Gegensatz zu anderen Synchronisationsservern für \Glspl{podcast} versucht dieses Produkt
+möglichst einfach und unkompliziert in der Handhabung zu sein. Deshalb wird nur eine
+grundlegende Synchronisationsfunktion ohne weitere
+Anpassungsmöglichkeit bereitgestellt.
+Außerden werden Funktionalitäten die bereits von einem \Gls{podcatcher} ermöglicht werden, wie
+zum Beispiel das Anhören und Verwalten von \Glspl{podcast}, nicht bereitgestellt.
+Dies sorgt zusätzlich für ein schlankes Backend.
+
+Es werden hierbei sowohl die \Glspl{podcast} an sich, als auch die aktuellen
+Hörfortschritte synchronisiert.
+Das bedeutet, dass alle vorgenommenen Änderungen auf den Server gespiegelt
+werden.
+Die Änderungen werden danach von jedem mit dem Account verbundenen
+\Gls{podcatcher} heruntergeladen.
+Dazu werden die \Glspl{podcast} und die Hörfortschritte eines jeden Nutzers in einer
+\Gls{db} gespeichert.
+Auf die \Gls{db} können die \Gls{podcatcher} mit einer API in Verbindung eines
+Nutzeraccounts lesend und schreibend zugreifen.
+Um eine Kompatibilität mit bestehenden Podcatchern
+sicherzustellen, wird die weitverbreitete \Gls{gpodder} verwendet.
+Zusätzlich soll es Nutzern durch ein Webinterface ermöglicht werden, ihre
+synchronisierten \Glspl{podcast} einsehen zu können und ihren Nutzeraccount verwalten zu können.
+
diff --git a/00-pflichtenheft/sections/glossar.tex b/00-pflichtenheft/sections/glossar.tex
new file mode 100644
index 0000000..8dce712
--- /dev/null
+++ b/00-pflichtenheft/sections/glossar.tex
@@ -0,0 +1,272 @@
+\makeglossaries
+
+\newglossaryentry{spa}
+{
+ name=Single-Page-Application,
+ description={
+ ist ein Webseiten-Modell, bei welchem dem Nutzer nur ein Webdokument
+ bereitgestellt wird. Mit einem Skript wird der Inhalt der Seite
+ dynamisch mit Daten einer API befüllt. Außerdem verwaltet die Seite
+ (nicht der Server), welcher Inhalt bei welchem Pfad angezeigt wird. Dies
+ erzeugt geringere Serverlast und eine bessere Nutzererfahrung, da die
+ Seitenstruktur beim Laden von neuen Inhalten erhalten bleibt}
+}
+
+\newglossaryentry{packagemanager}
+{
+ name=Paketmanager,
+ description={
+ ist ein Programm, welches Pakete und dessen Abhängigkeiten verwaltet,
+ installiert, entfernt und aktualisiert. Pakete können andere Programme,
+ Plugins oder Software-Bibliotheken sein}
+}
+
+\newglossaryentry{bundler}
+{
+ name=Bundler,
+ description={
+ ist ein Programm, welches genutzte Teile von Abhängigkeiten eines
+ Software-Projekts in passender Reihenfolge zusammensucht und daraus
+ Dateien erstellt, die für den Nutzer bereitgestellt werden können. Dabei
+ kann der Bundler mit zusätzlichen Modulen Dateien erzeugen, die
+ rückwärtskompatibel oder für den Nutzer schwerer einsehbar sind}
+}
+
+\newglossaryentry{java}
+{
+ name=Java,
+ description={
+ ist eine objekt-orientierte interpretierte kompilierte
+ Programmiersprache, welche plattformunabhängig auf einer virtuellen
+ Maschine ausgeführt wird}
+}
+
+\newglossaryentry{db}
+{
+ name=Datenbank,
+ description={
+ ist ein System um Daten persistent zu speichern und effizient zu
+ verwalten. Am meisten verbreitet sind relationale Datenbanken, welche
+ Daten in Tabellen mit Referenzen zu Einträgen anderer Tabellen
+ speichern. Programme können dann über eine Anfragesprache (Structured
+ Query Language - SQL) komplexe Operationen auf den Daten ausführen}
+}
+
+\newglossaryentry{docker}
+{
+ name=Docker,
+ description={
+ ist ein Programm, das virtualisierte Container ausführt. Ein Programm in
+ so einem Container läuft in seiner eigenen virtuellen Umgebung, wodurch
+ das Host-System sicher bleibt. Zudem lassen sich die Container leicht
+ auf andere Systeme verteilen}
+}
+
+% RESTfull-API, JSON, RSS-Feed, Salting and Hasing, OAuth, Cookie, Garbage
+% Collection, DSGVO, Podcast, Podcatcher, Episode, Gpodder,
+
+\newglossaryentry{podcatcher}
+{
+ name=Podcatcher,
+ plural=Podcatchern,
+ description={
+ ist ein Programm, über welches man Podcasts entdecken, abonnieren und
+ Episoden von Podcasts hören kann. Mit einem Account auf einer Plattform,
+ welche eine Gpodder-API zur Verfügung stellt, können Ereignisse, die von
+ einem Nutzer ausgehen, auf anderen Podcatchern des Nutzers
+ synchronisiert werden}
+}
+
+\newglossaryentry{podcast}
+{
+ name=Podcast,
+ description={
+ ist ein RSS-Feed, dessen Einträge die Episoden darstellen}
+}
+
+\newglossaryentry{episode}
+{
+ name=Episode,
+ plural=Episoden,
+ description={
+ ist ein Eintrag in einem Podcast. Eine URL in dem Eintrag zeigt auf eine
+ Medien-Datei, welche vom Podcatcher abgespielt werden kann}
+}
+
+\newglossaryentry{rest-api}
+{
+ name=RESTful-API,
+ description={
+ ist ein Schnittstellenentwurf über das Hypertext Transfer Protocol
+ (HTTP), bei dem die Schnittstellen strukturiert als Pfad an einem
+ Endpunkt erreichbar sind. Mittels verschiedener HTTP-Methoden können an
+ der Schnittstelle Daten abgefragt (GET), gesendet (PUT), gelöscht
+ (DELETE) oder geändert (POST) werden. Die Daten, die über die
+ Schnittstelle gesendet werden liegen meist im JSON-Format vor}
+}
+
+
+\newglossaryentry{gpodder}
+{
+ name=Gpodder-API,
+ description={
+ wird von gpodder.net benutzt und entwickelt. Die API wird als
+ Schnittstelle zwischen Podcatchern und Podcast Synchronisationsservern
+ verwendet. Weitere Details sind unter
+ "https://gpoddernet.readthedocs.io/en/latest/api/" zu finden}
+}
+
+\newglossaryentry{json}
+{
+ name=JSON,
+ description={
+ (JavaScript Object Notation) ist ein Datenformat und wird zur
+ Übertragung von Strukturen und Daten eingesetzt. JSON besteht dabei aus
+ grundlegenden Datentypen sowie Objekten mit Schlüssel-Wert Paaren und
+ Listen}
+}
+
+\newglossaryentry{oauth}
+{
+ name=OAuth,
+ description={
+ (Open Authorization) ist ein offenes Protokoll, welches es Nutzern
+ ermöglicht, sich mit bereits bestehenden Accounts bei anderen Diensten
+ zu registrieren. Dabei werden benötigte Daten für die Registrierung über
+ die bereitgestellte Schnittstelle zur Verfügung gestellt}
+}
+
+\newglossaryentry{garbage-collection}
+{
+ name=Garbage Collection,
+ description={
+ ist eine automatische Speicherbereinigung, welche nicht mehr benötigten
+ Speicherplatz wieder freigibt. Die Bereinigung kann dabei in determinierten
+ Zeitintervallen erfolgen oder durch bestimmte Ereignisse ausgelöst
+ werden}
+}
+
+\newglossaryentry{salt-hash}
+{
+ name=Salting und Hashing,
+ description={
+ ist eine Methode um Passwörter so zu kodieren, dass sie nicht als
+ Klartext gespeichert werden und auch sicher vor Hash-Wörterbüchern sind.
+ Dafür wird dem Passwort ein bekanntes Wort, der Salt, angefügt, bevor
+ aus dem kompletten Wort eine Prüfsumme, ein Hash, generiert wird. Beim
+ Anmelden wird die Prüfsumme der Anmeldung mit der bekannten
+ Prüfsumme des Passworts verglichen}
+}
+
+\newglossaryentry{rss}
+{
+ name=RSS,
+ description={
+ (Really Simple Syndication) zeigt strukturiert Listen von Nachrichten
+ an. Die Änderungen werden im XML-Format in sogenannte RSS-Dateien
+ geschrieben, welche über einen Link abgerufen werden können}
+}
+
+\newglossaryentry{dsgvo}
+{
+ name=Datenschutz-Grundverordnung,
+ description={
+ (DSGVO) ist eine im europäischen Wirtschaftsraum
+ geltende Verordnung. Sie sorgt für eine Reglementierung bei der
+ Verarbeitung personenbezogener Daten. Unter anderem muss einsehbar sein,
+ welche Daten von Nutzern erhoben werden. Außerdem muss für einen Nutzer
+ die Möglichkeit bestehen, seine erhobenen Daten abrufen zu können}
+}
+
+\newglossaryentry{push-pull}
+{
+ name=Push und Pull,
+ description={
+ sind Methoden, um Daten auszutauschen. Bei der Pull-Methode
+ stellt Akteur A einem Akteur B eine Anfrage auf Daten und erhält diese
+ als Antwort. Damit Akteur A und B immer auf dem selben Stand sind, muss
+ Akteur A chronisch Anfragen an Akteur B stellen. Im Gegensatz dazu steht
+ die Push-Methode, bei der Akteur B den Akteuren mitteilt, dass er neue
+ Änderungen hat. Dafür muss Akteur B allerdings wissen mit welchen
+ anderen Akteuren er in Verbindung steht und diese Verbindung aufrecht
+ erhalten}
+}
+
+\newglossaryentry{ui-lib}
+{
+ name=UI-Bibliothek,
+ plural=UI-Bibliotheken,
+ description={
+ kümmert sich um das Layout einer Webseite. Dabei unterscheidet man
+ zwischen Design-Bibliotheken (wie Bootstrap), welche fertige
+ UI-Komponenten bereitstellen, und Layout-Bibliotheken (wie Vue oder
+ React.js), welche die Komponenten basierend auf Daten dynamisch
+ anzeigen}
+}
+
+\newglossaryentry{responsive}
+{
+ name=Responsive,
+ description={
+ Design ist ein Design-Prinzip für Webseiten, bei dem die selbe Webseite ihre
+ Komponenten dynamisch der Bildschirmbreite anpasst}
+}
+
+\newglossaryentry{pseudoprotocol}
+{
+ name=Pseudoprotokoll,
+ description={
+ ist ein URL-Schema, auf das Webseiten hören können, wenn sie sich das
+ URL-Schema im Browser anmelden. Bekannt Pseudoprotokolle sind:
+ ,,mailto:'', ,,tel:'' oder ,,irc:''}
+}
+
+\newglossaryentry{dashboard}
+{
+ name=Dashboard,
+ description={
+ ist die erste Seite auf der man landet, wenn man angemeldet ist}
+}
+
+\newglossaryentry{abo}
+{
+ name=Abonnement,
+ description={
+ ist ein abonnierter Podcast}
+}
+
+\newglossaryentry{discovery}
+{
+ name=Discovery,
+ description={
+ ist ein Feature der Gpodder-API, welches dem Nutzer eine Reihe von
+ Podcasts zum abonnieren anbietet}
+}
+
+\newglossaryentry{session-token}
+{
+ name=Session-Token,
+ description={
+ ist ein Wort, dass vom Client gespeichert wird solange der Nutzer
+ eingeloggt ist und bei jeder Anfrage an den Server mitgeschickt wird.
+ Der Server kann den Session-Token einem Nutzer zuordnen und so mit
+ nutzerspezifischen Daten antworten}
+}
+
+\newglossaryentry{cookie}
+{
+ name=Cookie,
+ description={
+ ist ein kleiner webseitenspezifischer Speicher im Browser, welcher vom
+ Server und von der Webseite gesetzt werden kann und bei jeder weiteren
+ Anfrage an den Server mitgesendet wird. Cookies bleiben entweder
+ temporär im Browserspeicher, bis der Browser geschlossen wird oder
+ permanent, bis ein optionales Verfallsdatum erreicht ist}
+}
+
+% UI-Framework (React.js/Vue/Bootstrap)
+% Responsive Design
+% Abonnement
+% Pseudoprotokoll
+% Dashboard
+
diff --git a/00-pflichtenheft/sections/produktdaten.tex b/00-pflichtenheft/sections/produktdaten.tex
new file mode 100644
index 0000000..c74e3fb
--- /dev/null
+++ b/00-pflichtenheft/sections/produktdaten.tex
@@ -0,0 +1,83 @@
+\section{Produktdaten}
+
+Das Projekt erhebt an unterschiedlichen Stellen Daten des Benutzers oder anderen
+Plattformen. Diese Daten können temporär gespeichert werden. Dabei bleiben die
+Daten nur für eine kurze Zeit gespeichert, zum Beispiel so lange wie der Nutzer
+eingeloggt ist. Andere Daten können auch persistent gespeichert werden. Dabei
+bleiben die Daten solange gespeichert, bis sie manuell oder durch
+\Gls{garbage-collection} gelöscht werden.
+
+\subsection{Weboberfläche}
+
+Die Weboberfläche bezieht direkt Daten vom Benutzer. Die Weboberfläche erhält
+E-Mail-Adresse und Passwort vom Benutzer, speichert diese aber nur solange, bis
+diese an das Backend zur Validierung geschickt werden. Daraufhin erhält die
+Weboberfläche einen \Gls{session-token} welcher entweder persistent oder temporär als
+\Gls{cookie} gespeichert bleibt, je nachdem, ob der Nutzer angemeldet bleiben möchte.
+
+Zusätzlich erhält die Weboberfläche die abonnierten \Glspl{podcast} und gehörten
+\Glspl{episode} inklusive Metadaten vom Backend. Diese Daten werden nur temporär,
+solange die Webseite offen ist, gespeichert.
+
+\subsubsection*{Persistent}
+
+\begin{itemize}
+ \item \Gls{session-token} (falls der Nutzer angemeldet bleiben möchte)
+\end{itemize}
+
+\subsubsection*{Temporär}
+
+\begin{itemize}
+ \item Abonnierte \Glspl{podcast}
+ \item Gehörte \Glspl{episode}
+ \item \Gls{session-token}
+\end{itemize}
+
+\subsection{Backend}
+
+Das Backend interagiert nicht direkt mit dem Benutzer, sondern bekommt Daten von
+der Weboberfläche und \Glspl{podcatcher}. Wenn sich ein Nutzer über die Weboberfläche
+oder im \Gls{podcatcher} anmeldet oder registriert speichert der Server temporär die E-Mail-Adresse und
+das Passwort des Nutzers im Klartext, bevor es die Daten gegen die gehashten und
+gesalzenen persistenten Daten der \Gls{db} abgleicht beziehungsweise speichert.
+
+Außerdem speichert das Backend abonnierte \Glspl{podcast} und gehörte
+\Glspl{episode}, welche
+es vom \Gls{podcatcher} bekommt, im persistenten Speicher. Diese Daten bleiben
+gespeichert bis sie durch neue Daten obsolet werden (\Gls{garbage-collection}),
+vom Nutzer manuell gelöscht werden oder der Account gelöscht wird.
+
+Wenn die Weboberfläche \Glspl{episode} über \Glspl{podcast} abfragt, welche noch nicht vom
+Nutzer gehört wurden, holt der Server Metadaten über den \Glspl{podcast} und speichert
+Informationen und Bilder des \Glspl{podcast} temporär, solange der Nutzer die
+Weboberfläche geöffnet hat.
+
+\subsubsection*{Persistent}
+\begin{itemize}
+% Email (gehasht und gesalzen) / Betreuer fragen weil evtl Mails gesendet werden
+% müssen, falls Datenschutzbedinungen geändert werden
+\item E-Mail-Adresse gehasht und gesalzen
+\item Passwort gehasht und gesalzen
+\item Abonnierte \Glspl{podcast}
+\item Gehörte \Glspl{episode} (Hörfortschritte)
+\end{itemize}
+
+\subsubsection*{Temporär}
+\begin{itemize}
+ \item Metadaten von Feeds (\Glspl{episode}, Bilder)
+\end{itemize}
+
+\subsection{Podcatcher}
+
+Der \Gls{podcatcher} speichert die E-Mail-Adresse, das Passwort und die URL der
+Gpodder-Instanz im persistenten Speicher. Zusätzlich speichert der
+\Gls{podcatcher}
+abonnierte \Glspl{podcast} und gehörte \Glspl{episode} im persistenten Speicher.
+
+\subsubsection*{Persistent}
+\begin{itemize}
+\item E-Mail-Adresse, Passwort und URL der Gpodder-Instanz
+\item Abonnierte \Glspl{podcast}
+\item Gehörte \Glspl{episode}
+\end{itemize}
+
diff --git a/00-pflichtenheft/sections/produktfunktionen.tex b/00-pflichtenheft/sections/produktfunktionen.tex
new file mode 100644
index 0000000..12c5b56
--- /dev/null
+++ b/00-pflichtenheft/sections/produktfunktionen.tex
@@ -0,0 +1,215 @@
+\section{ Produktfunktionen }
+
+\subsection{ Registrierung }
+\label{f:registrierung}
+
+\begin{description}
+ \item[Anwendungsfall:] Der Nutzer möchte sich registrieren.
+ \item[Anforderungen:] \ref{r:login}
+ \item[Test:] \ref{t:register}, \ref{t:pw-req}
+ \item[Ziel:] Der Nutzer hat einen funktionierenden Account.
+ \item[Vorbedingung:] -
+ \item[Nachbedingung Erfolg:] Erfolgreiche Registrierung.
+ \item[Nachbedingung Fehlschlag:] Registrierung/Verbindungsaufbau zum Server schlägt
+ fehl.
+ \item[Akteure:] Nutzer, Server
+ \item[Auslösendes Ereignis:] Drücken des \enquote{Registrieren}-Buttons.
+ \item[Beschreibung:] \mbox{}
+ \begin{enumerate}
+ \item Öffnen der Webseite.
+ \item Drücken auf \enquote{Registrieren}-Option.
+ \item E-Mail-Adresse und zwei Mal neues Passwort eingeben.
+ \item \enquote{Registrieren}-Button drücken.
+ \item Bestätigungs-E-Mail wird an angegebene E-Mail-Adresse gesendet.
+ \item Nutzer öffnet Bestätigungs-Link.
+ \item Nutzer wird auf Login-Seite weitergeleitet. Der Bestätigungs-Link verfällt.
+ \end{enumerate}
+ \item[Erweiterung:] Wenn der Link nach 24 Stunden noch nicht angeklickt wurde, verfällt \\
+ dieser.
+\end{description}
+
+\newpage
+
+\subsection{ Anmelden }
+\label{f:anmelden}
+
+\begin{description}
+ \item[Anwendungsfall:] Der Nutzer möchte sich anmelden
+ \item[Anforderungen:] \ref{r:login}, \ref{r:login-provider}
+ \item[Test:] \ref{t:login}
+ \item[Ziel:] Der Nutzer ist eingeloggt.
+ \item[Vorbedingung:] Der Nutzer hat einen funktionierenden Account.
+ \item[Nachbedingung Erfolg:] Erfolgreiche Anmeldung
+ \item[Nachbedingung Fehlschlag:] Anmeldung/Verbindungsaufbau zum Server schlägt
+ fehl.
+ \item[Akteure:] Nutzer, Server
+ \item[Auslösendes Ereignis:] Drücken des \enquote{Anmelden}-Buttons.
+ \item[Beschreibung:] \mbox{}
+ \begin{enumerate}
+ \item Öffnen der Webseite.
+ \item E-Mail-Adresse und Passwort eingeben.
+ \item Option \enquote{Passwort merken} aus-/abwählen.
+ \item \enquote{Anmelden}-Button drücken.
+ \item Nutzer wird zu seinem \Gls{dashboard} weitergeleitet.
+ \end{enumerate}
+ \item[Erweiterung:] Wenn die Option \enquote{Passwort merken} aktiviert ist, bleibt der Nutzer \\
+ sitzungsübergreifend in seinem Account eingeloggt.
+ \item[Alternativen:] \mbox{}
+ \begin{enumerate}
+ \item Falls sich der Browser einen vorherigen Login gemerkt hat,
+ wird der Nutzer beim Aufruf der Seite direkt zu seinem
+ \Gls{dashboard} weitergeleitet.
+ \item Der Nutzer meldet sich mit einem \Gls{oauth} Dienst an.
+ \end{enumerate}
+\end{description}
+
+\newpage
+
+\subsection{ Passwort vergessen }
+\label{f:pwreset}
+
+\begin{description}
+ \item[Anwendungsfall:] Der Nutzer hat sein Passwort vergessen und möchte es zurücksetzen.
+ \item[Anforderungen:] \ref{r:reset-pw}
+ \item[Test:] \ref{t:pw-req}, \ref{t:forgot-pw}
+ \item[Ziel:] Der Nutzer hat ein neues Passwort.
+ \item[Vorbedingung:] Der Nutzer hat einen bestehenden Account und Zugriff auf seine E-Mail-Adresse
+ \item[Nachbedingung Erfolg:] Erfolgreiche Passwort Zurücksetzung.
+ \item[Nachbedingung Fehlschlag:] Zurücksetzung des Passworts / Verbindungsaufbau zum Server
+ schlägt fehl.
+ \item[Akteure:] Nutzer, Server
+ \item[Auslösendes Ereignis:] Drücken der \enquote{Passwort-Vergessen} Option auf der Login-Seite.
+ \item[Beschreibung:] \mbox{}
+ \begin{enumerate}
+ \item Öffnen der Webseite.
+ \item \enquote{Passwort-Vergessen} Option auswählen.
+ \item Weiterleitung auf \enquote{Passwort zurücksetzen} Seite.
+ \item E-Mail-Adresse des Accounts eingeben. Falls kein Account mit dieser
+ Adresse existiert, wird dieser Schritt wiederholt.
+ \item Bestätigungs-E-Mail mit Zurücksetzungs-Link wird an die angegebene
+ E-Mail-Adresse gesendet.
+ \item Der Nutzer öffnet den Zurücksetzungs-Link.
+ \item Ein Neues Passwort zweimal eingeben.
+ \item Auf den \enquote{Passwort-Zurücksetzen}-Button klicken.
+ \item Weiterleitung auf Login-Seite.
+ \end{enumerate}
+\end{description}
+
+\newpage
+
+\subsection{ Passwort ändern }
+\label{f:pwchange}
+
+\begin{description}
+ \item[Anwendungsfall:] Der Nutzer möchte sein Passwort ändern.
+ \item[Anforderungen:] \ref{r:reset-pw}
+ \item[Test:] \ref{t:pw-req}, \ref{t:change-pw}
+ \item[Ziel:] Der Nutzer hat ein neues Passwort.
+ \item[Vorbedingung:] Der Nutzer ist in seinem Account angemeldet.
+ \item[Nachbedingung Erfolg:] Erfolgreiche Passwort Änderung.
+ \item[Nachbedingung Fehlschlag:] Änderung des Passworts / Verbindungsaufbau zum Server
+ schlägt fehl.
+ \item[Akteure:] Nutzer, Server
+ \item[Auslösendes Ereignis:] Betätigen des \enquote{Passwort-Ändern}-Buttons.
+ \item[Beschreibung:] \mbox{}
+ \begin{enumerate}
+ \item Öffnen der Webseite.
+ \item Anmelden
+ \item Auf Account-Einstellungen gehen.
+ \item Bisheriges Passwort und zweimal neues Passwort in dafür vorgesehene Felder
+ eintippen.
+ \item \enquote{Passwort-Ändern}-Button betätigen.
+ \end{enumerate}
+\end{description}
+
+\newpage
+
+\subsection{ Hörfortschritt synchronisieren }
+\label{f:hörfortschrittSync}
+
+\begin{description}
+ \item[Anwendungsfall:] Der Nutzer hört mit einem verknüpften
+ \Gls{podcatcher} eine \Gls{episode} bis zu
+ einem gewissen Zeitpunkt.
+ Der Hörfortschritt soll mit dem Server und allen anderen Geräten synchronisiert werden.
+ \item[Anforderungen:] \ref{r:sync}, \ref{r:store}, \ref{r:persistent-storage}, \ref{r:gpodder}
+ \item[Test:] \ref{t:sync-episode}
+ \item[Ziel:] Der Hörfortschritt wird auf den Server und alle verknüpften Geräte übertragen.
+ \item[Vorbedingung:] Der Nutzer hat seinen Account mit einem \Gls{podcatcher} verknüpft und verwendet
+ diesen im Folgenden.
+ \item[Nachbedingung Erfolg:] Erfolgreiche Synchronisation des Hörfortschritts.
+ \item[Nachbedingung Fehlschlag:] Verbindungsaufbau zum Server schlägt
+ fehl.
+\item[Akteure:] Nutzer, \Gls{podcatcher}, Server
+\item[Auslösendes Ereignis:] Anhören einer \Gls{episode} bis zu einem gewissen Zeitpunkt.
+ \item[Beschreibung:] \mbox{}
+ \begin{enumerate}
+ \item Der Nutzer hört innerhalb eines \Gls{podcatcher}s eine
+ \Gls{episode}.
+ \item Der Hörfortschritt wird dem Server über die \Gls{gpodder} mitgeteilt.
+ \item Der Server aktualisiert den Hörfortschritt im entsprechenden Datensatz
+ des Nutzeraccounts zur \Gls{episode}.
+ \end{enumerate}
+ \item[Erweiterung:] Wenn sich ein weiterer \Gls{podcatcher} aktualisiert, ruft dieser
+ die neuen Hörfortschritte des Nutzers vom Server über die \Gls{gpodder} ab und wendet diese an.
+\end{description}
+
+\newpage
+
+\subsection{ Abonnements synchronisieren}
+\label{f:abonnentsSync}
+
+\begin{description}
+ \item[Anwendungsfall:] Der Nutzer fügt auf einem verknüpften
+ \Gls{podcatcher} ein \Gls{abo} hinzu bzw. löscht ein \Gls{abo}.
+ Dieses soll mit dem Server und allen anderen Geräten synchronisiert werden.
+ \item[Anforderungen:] \ref{r:sync}, \ref{r:store}, \ref{r:persistent-storage}, \ref{r:gpodder}
+ \item[Test:] \ref{t:sync-sub}, \ref{t:sync-unsub}
+ \item[Ziel:] Das (De-)\Gls{abo} wird auf den Server und alle verknüpften Geräte übertragen.
+ \item[Vorbedingung:] Der Nutzer hat seinen Account mit einem \Gls{podcatcher} verknüpft und verwendet
+ diesen im Folgenden.
+\item[Nachbedingung Erfolg:] Erfolgreiche Synchronisation des \Glspl{abo}.
+ \item[Nachbedingung Fehlschlag:] Verbindungsaufbau zum Server schlägt
+ fehl.
+\item[Akteure:] Nutzer, \Gls{podcatcher}, Server
+\item[Auslösendes Ereignis:] (De-)Abonnieren eines \Glspl{podcast} innerhalb
+ eines \Gls{podcatcher}.
+ \item[Beschreibung:] \mbox{}
+ \begin{enumerate}
+ \item Der Nutzer (de-)abonniert innerhalb eines \Gls{podcatcher}s einen
+ \Gls{podcast}.
+ \item Die Änderung wird dem Server über die \Gls{gpodder} mitgeteilt.
+ \item Der Server fügt das neue \Gls{abo} persistent zum Datensatz des Nutzers
+ auf dem Server hinzu / löscht das \Gls{abo} vom Datensatz auf
+ dem Server.
+ \end{enumerate}
+ \item[Erweiterung:] Wenn sich ein weiterer \Gls{podcatcher} aktualisiert, holt dieser
+ die aktuelle Liste der \Glspl{abo} des Nutzers vom Server über die
+ \Gls{gpodder} (Client Pull).
+\end{description}
+
+\newpage
+
+\subsection{ Account löschen}
+\label{f:deleteAccount}
+
+\begin{description}
+ \item[Anwendungsfall:] Der Nutzer möchte seinen Account löschen.
+ \item[Anforderungen:] \ref{r:delete-acc}
+ \item[Test:] \ref{t:delete-acc}
+ \item[Ziel:] Der Account und alle Nutzerdaten werden vom Server gelöscht.
+ \item[Vorbedingung:] Der Nutzer ist angemeldet und befindet sich auf der Einstellungsseite.
+ \item[Nachbedingung Erfolg:] Der Account wurde gelöscht.
+ \item[Nachbedingung Fehlschlag:] Verbindungsaufbau zum Server schlägt
+ fehl.
+ \item[Akteure:] Nutzer, Server
+ \item[Auslösendes Ereignis:] Der Nutzer drückt auf den \enquote{Account löschen} Knopf.
+ \item[Beschreibung:] \mbox{}
+ \begin{enumerate}
+ \item Der Nutzer drückt auf den \enquote{Account löschen}-Knopf.
+ \item Der Nutzer wird dazu aufgefordert sein Passwort als Bestätigung der Löschung
+ einzugeben.
+ \item Der Server löscht den Account und alle dazugehörigen Daten.
+ \item Der Nutzer wird auf die Login-Seite weitergeleitet.
+ \end{enumerate}
+\end{description}
diff --git a/00-pflichtenheft/sections/produktuebersicht.tex b/00-pflichtenheft/sections/produktuebersicht.tex
new file mode 100644
index 0000000..37e0789
--- /dev/null
+++ b/00-pflichtenheft/sections/produktuebersicht.tex
@@ -0,0 +1,184 @@
+\section{Produktübersicht}
+
+In diesem Kapitel wird der Aufbau der Synchronisationsserver-Webseite in einem Use-Case-Diagramm, welches sich in Abbildung
+\ref{fig:UseCase} befindet, visualisiert.
+
+Hierbei wird in Aktivitätsdiagrammen näher auf die Aktionen \enquote{Anmelden} (Abbildung \ref{fig:ActLogin}),
+\enquote{Registrieren} (Abbildung \ref{fig:ActRegister}) und \enquote{Passwort vergessen} (Abbildung \ref{fig:ActResetPass})
+eingegangen.
+
+Weiter beschreibt ein abstrahiertes Sequenzdiagramm (Abbildung
+\ref{fig:SeqSynchSubs}) den Nachrichtenaustausch bei der Synchronisation der
+gespeicherten Daten eines Benutzers. Dies erfolgt am Beispiel der Tätigung eines
+neuen \Glspl{abo} über einen \Gls{podcatcher}.
+
+\subsection{Der Aufbau der Webseite}
+
+In dem Use-Case-Diagramm in Abbildung \ref{fig:UseCase} erkennt man den Aufbau der Webseite des Synchronisationsservers.
+Besucht man die Seite ohne eingeloggt zu sein, so hat man die Möglichkeit die Sprache zu ändern, sich anzumelden, sich zu registrieren oder sein Passwort über die \enquote{Passwort vergessen}-Funktion \ref{f:pwreset} zurückzusetzen.
+Dabei gibt es die Möglichkeit sich mit seinem Google-Konto oder dem Konto eines anderen Anbieters zu registrieren / anzumelden.
+
+Ist man angemeldet, wird man auf ein \Gls{dashboard} weitergeleitet.
+Dort hat man die Möglichkeit eine Anleitung einzusehen und die bisher
+abonnierten \Glspl{podcast} einzusehen.
+Dabei erhält man zu jedem \Gls{podcast} einen Überblick über dessen
+\Glspl{episode} und Details darüber, bis zu welchem Zeitpunkt man die
+\Gls{episode} angehört hat.
+Auch gibt es die Möglichkeit einen Verlauf und den korrespondierenden
+Fortschritt aller zuletzt gehörten \Glspl{episode} einzusehen.
+
+Des Weiteren kann man das eigene Profil verwalten.
+Dies beinhaltet das Ändern des eigenen Passworts, das Importieren der Daten einer Gpodder-Instanz über eine Anmeldung oder
+dem Importieren als Datei.
+Auch können in der Profilverwaltung personenbezogene Daten als Datei importiert und exportiert werden.
+Schließlich hat man in der Profilverwaltung die Möglichkeit den eigenen Account permanent zu löschen.
+
+Ist man ein Administrator, so hat man zusätzlich die Möglichkeit Statistiken einzusehen.
+
+\newpage
+
+% UML Use-Case Diagramm
+\begin{figure}[H]
+ \centering
+ \hspace*{-2.5cm}
+ \input{sections/TikzPictures/UseCaseUML}
+ \caption{Use-Case-Diagramm der Webseite\\(*) - Optionale Funktionen, deren Implementierung nicht feststeht}
+ \label{fig:UseCase}
+\end{figure}
+\newpage
+
+\subsection{Das Einloggen}
+
+Im Aktivitätsdiagramm \enquote{Anmeldung} in Abbildung \ref{fig:ActLogin} möchte der Nutzer sich auf der Webseite anmelden.
+Hierzu ruft der Nutzer zunächst die Webseite auf und landet auf der Login Seite.
+
+Hat der Nutzer sich bereits zuvor auf dem Computer auf der Seite angemeldet und dabei ausgewählt eingeloggt zu bleiben,
+so wird der Nutzer über Session-\Glspl{cookie} automatisch auf das \Gls{dashboard} weitergeleitet.
+Ist das nicht der Fall, so muss der Nutzer seine Anmeldedaten eingeben.
+
+Nach dem Eintragen der Daten hat der Nutzer die Möglichkeit für das nächste Mal, wenn der Nutzer die Webseite
+am selben Computer betritt, angemeldet zu bleiben.
+Daraufhin drückt der Nutzer den \enquote{Anmelden}-Button.
+
+Wurde die E-Mail oder das Passwort falsch eingegeben, so zeigt die Seite eine Fehlermeldung an und der Nutzer wird aufgefordert seine Eingabe zu korrigieren.
+Wurden die E-Mail und das Passwort korrekt eingegeben, so landet der Nutzer
+angemeldet auf dem \Gls{dashboard}, von wo aus er dann alle Aktionen ausführen kann, für die man angemeldet sein muss.
+
+\newpage
+
+% UML Activity Diagramm - Login
+\begin{figure}[H]
+ \centering
+ \input{sections/TikzPictures/ActivityLogin}
+ \caption{Aktivitätsdiagramm - Anmelden}
+ \label{fig:ActLogin}
+\end{figure}
+\newpage
+
+\subsection{Das Registrieren}
+
+Möchte sich der Nutzer einen neuen Account erstellen, so läuft dieser Vorgang
+entsprechend dem Aktivitätsdiagramm \enquote{Registrieren} in Abbildung \ref{fig:ActRegister} ab.
+Der Nutzer ruft zunächst die Webseite auf und landet auf der Login Seite.
+Dort wählt der Nutzer die \enquote{Registrieren}-Option aus und wird zur Registrierungsseite weitergeleitet.
+
+Auf der Registrierungsseite gibt der Nutzer in den jeweils dafür zugeordneten Eingabefeldern seine E-Mail-Adresse und zur Kontrolle
+zwei Mal das gleiche Passwort ein, welches dem Account zugeordnet werden soll.
+Daraufhin drückt der Nutzer zum Abschluss den \enquote{Registrieren}-Button.
+Der Server überprüft, ob die E-Mail-Adresse bereits vergeben ist und ob das Passwort die Passwortmindestanforderungen \ref{r:pw-requirements} erfüllt.
+
+Ist die E-Mail schon vergeben, so wird dem Nutzer eine entsprechende Meldung angezeigt und der Nutzer muss die eingegebene E-Mail-Adresse korrigieren.
+Erfüllt das Passwort nicht die Mindestvoraussetzungen, so wird dem Nutzer auch hier eine entsprechende Meldung angezeigt und der Nutzer muss die Eingabe korrigieren.
+
+Erfüllen die Eingaben die Voraussetzungen, so wird an die angegebene E-Mail-Adresse eine E-Mail mit einem Link zur Verifizierung
+der E-Mail-Adresse geschickt.
+Der Nutzer muss diesen Link innerhalb der nächsten 24 Stunden zur Aktivierung seines Kontos öffnen, da ansonsten der Link
+abläuft und der Nutzer den Prozess erneut beginnen muss.
+
+Wurde der Link innerhalb von 24 Stunden geöffnet, so wird der Account aktiviert und der Nutzer wird über den Link zur Login Seite
+weitergeleitet, von wo aus er sich mit seinem neu erstellten Account nun einloggen kann.
+
+\newpage
+
+% UML Activity Diagram - Register
+\begin{figure}[H]
+ \centering
+ \input{sections/TikzPictures/ActivityRegister}
+ \caption{Aktivitätsdiagramm - Registrieren}
+ \label{fig:ActRegister}
+\end{figure}
+\newpage
+
+\subsection{Das Vergessen des Passwortes}
+
+Hat der Nutzer einmal sein Passwort vergessen, so gibt es die Möglichkeit das Passwort zurückzusetzen.
+Wie dieser Vorgang aussieht, wird im Aktivitätsdiagramm \enquote{Passwort zurücksetzen} in Abbildung \ref{fig:ActResetPass}
+dargestellt.
+Zunächst ruft der Nutzer die Webseite auf und landet auf der Login Seite.
+Über die Option \enquote{Passwort vergessen} wird der Nutzer auf die \enquote{Passwort vergessen}-Seite weitergeleitet.
+
+Hier gibt der Nutzer in einem Eingabefeld die E-Mail-Adresse des Accounts an, dessen Passwort der Nutzer vergessen hat.
+Nach der Bestätigung der Eingabe überprüft der Server, ob unter der angegebenen E-Mail-Adresse ein Account angelegt ist.
+Ist dies nicht der Fall, so wird der Nutzer erneut darum gebeten die E-Mail-Adresse anzugeben.
+Existiert ein Account unter der angegeben E-Mail-Adresse, so wird eine E-Mail an die angegebene Adresse geschickt, die einen
+automatisch generierten Link enthält, der es dem Nutzer erlaubt das Passwort für den jeweiligen Account zurückzusetzen.
+
+Der Nutzer muss den Link innerhalb der nächsten 24 Stunden öffnen, da dieser ansonsten abläuft und zu einer entsprechenden
+Fehlermeldung führt.
+Öffnet der Nutzer den Link innerhalb von 24 Stunden, so wird der Nutzer auf eine Seite weitergeleitet auf der der Nutzer
+zwei Mal das neue Passwort eingeben muss.
+Das Passwort muss dabei die Passwortmindestanforderungen \ref{r:pw-requirements} erfüllen.
+
+Ist das neue Passwort eingegeben, so muss der Nutzer den \enquote{Passwort zurücksetzen}-Button drücken und das eingegebene Passwort wird überprüft.
+Erfüllt das Passwort die Mindestanforderungen nicht, so wird dem Nutzer eine entsprechende Fehlermeldung angezeigt und der Nutzer muss sich ein neues Passwort ausdenken und zwei Mal eingeben.
+Erfüllt das Passwort die Mindestanforderungen, so wird das neue Passwort für den Account gespeichert und der Nutzer wird auf die Login Seite weitergeleitet, von wo aus er sich mit dem neuen Passwort anmelden kann.
+
+\newpage
+
+% UML Activity Diagram - Reset Password
+\begin{figure}[H]
+ \centering
+ \input{sections/TikzPictures/ActivityResetPass}
+ \caption{Aktivitätsdiagramm - Passwort vergessen}
+ \label{fig:ActResetPass}
+\end{figure}
+\newpage
+
+\subsection{Das Synchronisieren am Beispiel eines Abonnements}
+
+Der Benutzer in Abbildung \ref{fig:SeqSynchSubs} hört \Glspl{podcast} über die
+verschiedenen \Gls{podcatcher}-Applika\-tionen \enquote{Podcatcher1} und \enquote{Podcatcher2}.
+Dabei spielt es im Folgenden keine Rolle ob er beide Applikationen auf demselben Gerät, beide auf jeweils unterschiedlichen Geräten oder die gleiche Applikation auf unterschiedlichen Geräten verwendet.
+
+Der Benutzer tätigt ein neues \Gls{abo} über die \Gls{podcatcher}-Applikation \enquote{Podcatcher1}.
+Dies bewirkt zunächst eine lokale Änderung der Liste der \Glspl{abo}.
+Im Zuge dessen wird auch der Server über die vorgenommene Änderung benachrichtigt.
+Dieser speichert dann die kommunizierte Änderung persistent in der \Gls{db}.
+
+Im Folgenden lässt sich der Benutzer die Liste seiner \Glspl{abo} im Webfrontend anzeigen.
+Dafür benachrichtigt das Webfrontend den Server darüber, dass es die Liste der
+\Glspl{abo} des entsprechenden Nutzers benötigt (\enquote{Client Pull}).
+Das Webfrontend erhält die aktuelle Liste, welche insbesondere das zuvor
+getätigte \Gls{abo} enthält, und zeigt diese dem Nutzer an.
+
+Der Benutzer lässt sich nun auch in der \Gls{podcatcher}-Applikation
+\enquote{Podcatcher2} die Liste seiner \Glspl{abo} anzeigen.
+Die Anwendung \enquote{Podcatcher2} benachrichtigt hierfür nach kurzer Zeit oder
+nach manueller Anforderung den Server darüber, dass sie die Liste der
+\Glspl{abo} des entsprechenden Nutzers benötigt.
+
+Die Anwendung erhält die aktuelle Liste, übernimmt diese lokal und zeigt sie dem Nutzer an.
+So wird der aktuelle Stand der Liste der \Glspl{abo} (analog der Fortschritt
+beim Anhören/Ansehen von \Glspl{episode}) über alle verbundenen \Gls{podcatcher} (und entsprechend alle verbundenen Geräte) synchronisiert.
+
+\newpage
+
+% UML Sequence Diagram - Synchronise Subscription
+\begin{figure}[H]
+ \centering
+ \raisebox{3cm}{
+ \input{sections/TikzPictures/SequenceSynchroniseSubscription}}
+ \caption{Sequenzdiagramm - Synchronisation am Beispiel Abonnieren}
+ \label{fig:SeqSynchSubs}
+\end{figure}
+\newpage
diff --git a/00-pflichtenheft/sections/tests.tex b/00-pflichtenheft/sections/tests.tex
new file mode 100644
index 0000000..9d29aa1
--- /dev/null
+++ b/00-pflichtenheft/sections/tests.tex
@@ -0,0 +1,605 @@
+
+\section{Tests}
+
+\subsection{Registrierung}\label{t:register}
+\vspace{0.3cm}
+
+\begin{enumerate}
+
+\item
+\begin{description}
+ \item [Stand] Ein Fenster ist im Browser geöffnet.
+ \item [Aktion] Der Benutzer gibt die URL der Weboberfläche in die Kopfzeile ein und drückt Enter.
+ \item [Reaktion] Der Browser wechselt zur Anmeldeseite der Weboberfläche.
+\end{description}
+
+\item
+\begin{description}
+ \item [Stand] Die Anmeldeseite ist im Browser geladen.
+ \item [Aktion] Der Benutzer klickt auf den Knopf \enquote{Registrieren}.
+ \item [Reaktion] Der Browser wechselt zur Registrierungsseite.
+\end{description}
+
+\item
+\begin{enumerate}
+
+\item
+\begin{description}
+ \item [Stand] Die Registrierungsseite mit Registrierungsmöglichkeit in der Mitte des Fensters ist geladen.
+ \item [Aktion] Der Benutzer gibt \enquote{pseIstToll@test.com} als E-Mail und \enquote{Test123!?} als Passwort ein. Weiter gibt er \enquote{test123!?} in das \enquote{Wiederholen} Feld ein. Dann klickt der Benutzer auf den Knopf \enquote{Registrieren}.
+ \item [Reaktion] Die Registrierungsseite bleibt geladen. Im E-Mail-Feld steht \enquote{pseIstToll@test.com}, im Feld \enquote{Passwort} steht \enquote{Test123!?} und im Feld \enquote{Wiederholen} steht \enquote{test123!?}. Der Benutzer wird aufgefordert in die Felder \enquote{Passwort} und \enquote{Wiederholen} das gleiche Passwort einzugeben.
+\end{description}
+
+\item
+\begin{description}
+ \item [Stand] Die Registrierungsseite ist geladen. Als E-Mail ist \enquote{pseIstToll@test\-.com}, als Passwort \enquote{Test123!?} und \enquote{test123!?} in das Feld \enquote{Wiederholen} eingetragen.
+ \item [Aktion] Der Benutzer gibt \enquote{Test123!?} in das Feld \enquote{Wiederholen} ein. Dann klickt der Benutzer auf den Knopf \enquote{Registrieren}.
+ \item [Reaktion] Dem Benutzer wird angezeigt, dass an die angegebene E-Mail-Adres\-se eine E-Mail mit einem Bestätigungslink versendet wurde. Der Benutzer wird aufgefordert diesen zu Bestätigen um die Registrierung abzuschließen.
+\end{description}
+
+\end{enumerate}
+
+\item
+\begin{description}
+ \item [Stand] Der Benutzer hat die Registrierung begonnen und die E-Mail mit dem Bestä\-tigungs-Link erhalten. Der Benutzer hat noch nicht auf den Bestätigungs-Link geklickt.
+ \item [Aktion] Der Benutzer klickt innerhalb von 24 Stunden nach Versendung auf den Bestätigungs-Link.
+ \item [Reaktion] Der Account wird erstellt und der Benutzer wird auf die Anmeldeseite weitergeleitet.
+\end{description}
+
+\item
+\begin{description}
+ \item [Stand] Der Benutzer hat die Registrierung bereits abgeschlossen.
+ \item [Aktion] Der Benutzer klickt auf den Bestätigungs-Link.
+ \item [Reaktion] Der Benutzer erhält eine Fehlermeldung, dass der Link abgelaufen ist.
+\end{description}
+
+\item
+\begin{description}
+ \item [Stand] Der Benutzer hat die Registrierung begonnen und die E-Mail mit dem Bestä\-tigungs-Link erhalten. Die E-Mail wurde vor mehr als 24 Stunden versendet. Der Benutzer hat den Bestätigungs-Link noch nicht angeklickt.
+ \item [Aktion] Der Benutzer klickt auf den Bestätigungs-Link.
+ \item [Reaktion] Der Benutzer erhält eine Fehlermeldung, dass der Link abgelaufen ist. Der Account wird nicht erstellt. Der Benutzer wird auf die Anmeldeseite weitergeleitet.
+\end{description}
+
+\item
+\begin{description}
+ \item [Stand] Die Registrierungsseite ist geladen. Es ist bereits ein Account mit der E-Mail-Adresse \enquote{pseIstToll@test.com} registriert.
+ \item [Aktion] Der Benutzer gibt \enquote{pseIstToll@test.com} als E-Mail-Adresse und \enquote{Test123!?} als Passwort ein. Weiter gibt er das gleiche Passwort in das Feld \enquote{Wiederholen} ein. Dann klickt der Benutzer auf den Knopf \enquote{Registrieren}.
+ \item [Reaktion] Die Registrierungsseite bleibt geladen. Es wird eine Fehlermeldung ausgegeben, dass diese E-Mail-Adresse bereits vergeben ist.\\
+\end{description}
+
+\end{enumerate}
+
+\newpage
+
+
+\subsection{Passwort Anforderungen}\label{t:pw-req}
+\vspace{0.3cm}
+
+\begin{description}
+ \item [Anmerkung] Die Testfälle sind beispielhaft für den Vorgang der Registrierung entworfen worden. Es wird analoges Verhalten bei den Vorgängen \enquote{Passwort ändern} \ref{t:change-pw} und \enquote{Passwort vergessen} \ref{t:forgot-pw} erwartet.
+\end{description}
+
+\begin{enumerate}
+
+\item
+\begin{description}
+ \item [Stand] Die Registrierungsseite ist geladen. Als E-Mail-Adresse ist \enquote{pseIstToll@test\-.com} eingetragen.
+ \item [Aktion] Der Benutzer gibt \enquote{test} in die Felder \enquote{Passwort} und \enquote{Wiederholen} ein. Dann klickt der Benutzer auf den Knopf \enquote{Registrieren}.
+ \item [Reaktion] Die Registrierungsseite bleibt geladen. Dem Benutzer wird angezeigt das sein Passwort nicht die Passwort-Mindestanforderungen erfüllt. Weiter wird farblich angezeigt, dass sein Passwort nicht:
+ \color{red}
+ \begin{itemize}
+ \item mindestens 8 Zeichen lang ist.
+ \item mindestens einen Großbuchstaben enthält.
+ \item mindestens eine Zahl enthält.
+ \item mindestens ein Sonderzeichen enthält.
+ \end{itemize}
+ \color{black}
+ Dem Benutzer wird farblich angezeigt dass sein Passwort:
+ \color{ForestGreen}
+ \begin{itemize}
+ \item mindestens einen Kleinbuchstaben enthält.
+ \end{itemize}
+ \color{black}
+\end{description}
+
+\item
+\begin{description}
+ \item [Stand] Die Registrierungsseite ist geladen. Als E-Mail ist \enquote{pseIstToll@test.com} eingetragen.
+ \item [Aktion] Der Benutzer gibt \enquote{Test123} in die Felder \enquote{Passwort} und \enquote{Wiederholen} ein. Dann klickt der Benutzer auf den Knopf \enquote{Registrieren}.
+ \item [Reaktion] Die Registrierungsseite bleibt geladen. Dem Benutzer wird angezeigt das sein Passwort nicht die Passwort-Mindestanforderungen erfüllt. Weiter wird farblich angezeigt, dass sein Passwort nicht:
+ \color{red}
+ \begin{itemize}
+ \item mindestens 8 Zeichen lang ist.
+ \item mindestens ein Sonderzeichen enthält.
+ \end{itemize}
+ \color{black}
+ Dem Benutzer wird farblich angezeigt dass sein Passwort:
+ \color{ForestGreen}
+ \begin{itemize}
+ \item mindestens einen Kleinbuchstaben enthält.
+ \item mindestens einen Großbuchstaben enthält.
+ \item mindestens eine Zahl enthält.
+ \end{itemize}
+ \color{black}
+\end{description}
+
+\newpage
+
+\item
+\begin{description}
+ \item [Stand] Die Registrierungsseite ist geladen. Als E-Mail-Adresse ist \enquote{pseIstToll@test\-.com} eingetragen.
+ \item [Aktion] Der Benutzer gibt \enquote{TEST123?} in die Felder \enquote{Passwort} und \enquote{Wiederholen} ein. Dann klickt der Benutzer auf den Knopf \enquote{Registrieren}.
+ \item [Reaktion] Die Registrierungsseite bleibt geladen. Dem Benutzer wird angezeigt das sein Passwort nicht die Passwort-Mindestanforderungen erfüllt. Weiter wird farblich angezeigt, dass sein Passwort nicht:
+ \color{red}
+ \begin{itemize}
+ \item mindestens einen Kleinbuchstaben enthält.
+ \end{itemize}
+ \color{black}
+ Dem Benutzer wird farblich angezeigt dass sein Passwort:
+ \color{ForestGreen}
+ \begin{itemize}
+ \item mindestens 8 Zeichen lang ist.
+ \item mindestens einen Großbuchstaben enthält.
+ \item mindestens eine Zahl enthält.
+ \item mindestens ein Sonderzeichen enthält.
+ \end{itemize}
+ \color{black}
+\end{description}
+
+\item
+\begin{description}
+ \item [Stand] Die Registrierungsseite ist geladen. Als E-Mail ist \enquote{pseIstToll@test.com} eingetragen.
+ \item [Aktion] Der Benutzer gibt \enquote{Test123!?} in die Felder \enquote{Passwort} und \enquote{Wiederholen} ein. Dann klickt der Benutzer auf den Knopf \enquote{Registrieren}.
+ \item [Reaktion] Dem Benutzer wird angezeigt, dass an die angegebene E-Mail-Adresse eine E-Mail mit einem Bestätigungslink versendet wurde. Der Benutzer wird aufgefordert diesen zu bestätigen um die Registrierung abzuschließen.\\
+\end{description}
+
+\end{enumerate}
+
+\newpage
+
+
+\subsection{Anmeldung}\label{t:login}
+\vspace{0.3cm}
+
+\begin{description}
+ \item [Vorbedingung] Es ist nur ein Benutzer registriert. Dieser hat die E-Mail \enquote{pseIstToll@test\-.com} und das Passwort \enquote{Test123!?}. Die Option \enquote{Angemeldet bleiben} wurde nicht verwendet.
+\end{description}
+
+\begin{enumerate}
+
+\item
+\begin{description}
+ \item [Stand] Ein Fenster ist im Browser geöffnet.
+ \item [Aktion] Der Benutzer gibt die URL der Weboberfläche in die Kopfzeile ein und drückt Enter.
+ \item [Reaktion] Der Browser wechselt zur Anmeldeseite der Weboberfläche.
+\end{description}
+
+\item
+\begin{description}
+ \item [Stand] Die Anmeldeseite mit Anmeldemöglichkeit in der Mitte des Fensters ist im Browser geladen.
+ \item [Aktion] Der Benutzer macht keine Eingaben und klickt auf den Knopf \enquote{Anmelden}.
+ \item [Reaktion] Die Anmeldeseite bleibt geladen. Der Benutzer wird aufgefordert die Felder \enquote{E-Mail-Adresse} und \enquote{Passwort} auszufüllen.
+\end{description}
+
+\item
+\begin{description}
+ \item [Stand] Die Anmeldeseite ist im Browser geladen.
+ \item [Aktion] Der Benutzer gibt als E-Mail-Adresse \enquote{pseIstToll@test.com} ein aber gibt kein Passwort ein. Dann klickt der Benutzer auf den Knopf \enquote{Anmelden}.
+ \item [Reaktion] Die Anmeldeseite bleibt geladen. Im E-Mail-Feld ist \enquote{pseIstToll@test\-.com} eingetragen. Der Benutzer wird aufgefordert das Passwort-Feld auszufüllen.
+\end{description}
+
+\item
+\begin{description}
+ \item [Stand] Die Anmeldeseite ist im Browser geladen.
+ \item [Aktion] Der Benutzer gibt in das \enquote{E-Mail}-Feld \enquote{pseIstSuperToll@test.com} ein und gibt \enquote{Test123!?} als Passwort ein. Dann klickt der Benutzer auf den Knopf \enquote{Anmelden}.
+ \item [Reaktion] Die Anmeldeseite bleibt geladen. Als E-Mail ist \enquote{pseIstSuperToll@test\-.com} und als Passwort \enquote{Test123!?} eingetragen. Dem Benutzer wird eine Fehlermeldung ausgegeben: \enquote{E-Mail-Adresse oder Passwort ist ungültig!}
+\end{description}
+
+\item
+\begin{description}
+ \item [Stand] Die Anmeldeseite ist im Browser geladen.
+ \item [Aktion] Der Benutzer gibt in das \enquote{E-Mail}-Feld \enquote{pseIstToll@test.com} ein und gibt \enquote{test} als Passwort ein. Der Benutzer wählt die Option \enquote{Angemeldet bleiben} aus. Dann klickt der Benutzer auf den Knopf \enquote{Anmelden}.
+ \item [Reaktion] Die Anmeldeseite bleibt geladen. Als E-Mail ist \enquote{pseIstToll@test.com} und als Passwort \enquote{test} eingetragen. Die Option \enquote{Angemeldet bleiben} ist ausgewählt. Dem Benutzer wird eine Fehlermeldung ausgegeben: \enquote{E-Mail-Adresse oder Passwort ist ungültig!}
+\end{description}
+
+\newpage
+
+\item
+\begin{description}
+ \item [Stand] Die Anmeldeseite ist im Browser geladen. Als E-Mail ist \enquote{pseIstToll@test\-.com} und als Passwort \enquote{test} eingetragen. Die Option \enquote{Angemeldet bleiben} ist ausgewählt.
+ \item [Aktion] Der Benutzer gibt \enquote{Test123!?} als Passwort ein. Dann klickt der Benutzer auf den Knopf \enquote{Anmelden}.
+ \item [Reaktion] Der Browser wechselt zum \Gls{dashboard}.
+\end{description}
+
+\item
+\begin{description}
+ \item [Stand] Der Benutzer hat sich erfolgreich angemeldet. Bei der Anmeldung wurde die Option \enquote{Angemeldet bleiben} ausgewählt.
+ \item [Aktion] Der Benutzer startet seinen Browser neu. Dann gibt er die URL der Weboberfläche in der Kopfzeile ein und drückt Enter.
+ \item [Reaktion] Der Benutzer wird automatisch angemeldet und das
+ \Gls{dashboard} geladen.
+\end{description}
+
+\item
+\begin{description}
+ \item [Stand] Der Benutzer hat sich erfolgreich angemeldet. Bei der Anmeldung wurde die nicht Option \enquote{Angemeldet bleiben} ausgewählt.
+ \item [Aktion] Der Benutzer startet seinen Browser neu. Dann gibt er die URL der Weboberfläche in der Kopfzeile ein und drückt Enter.
+ \item [Reaktion] Der Browser wechselt zur Anmeldeseite. Der Benutzer wird nicht automatisch angemeldet.\\
+\end{description}
+
+\end{enumerate}
+
+\newpage
+
+
+\subsection{Passwort ändern}\label{t:change-pw}
+\vspace{0.3cm}
+
+\begin{description}
+ \item [Vorbedingung] Es gibt einen Benutzer mit der E-Mail \enquote{pseIstToll@test.com} und dem Passwort \enquote{Test123!?}.
+\end{description}
+
+\begin{enumerate}
+
+\item
+\begin{description}
+ \item [Stand] Der Benutzer ist angemeldet. Das \Gls{dashboard} ist im Browser geladen.
+ \item [Aktion] Der Benutzer klickt auf den Profil-Knopf oben rechts (Pfeil nach unten neben dem Männchen). Dann klickt er in dem geöffneten Menu oben rechts auf den Knopf \enquote{Einstellungen}.
+ \item [Reaktion] Der Browser wechselt zur \enquote{Einstellungs}-Oberfläche.
+\end{description}
+
+\item
+\begin{description}
+ \item [Stand] Der Benutzer ist angemeldet. Die \enquote{Einstellungs}-Oberfläche ist im Browser geladen.
+ \item [Aktion] Der Benutzer macht keine Eingaben und klickt auf den Knopf \enquote{Passwort ändern}.
+ \item [Reaktion] Die \enquote{Einstellungs}-Oberfläche bleibt geladen. Der Benutzer wird aufgefordert die Felder \enquote{Altes Passwort}, \enquote{Neues Passwort} und \enquote{Wiederholen} auszufüllen.
+\end{description}
+
+\item
+\begin{description}
+ \item [Stand] Der Benutzer ist angemeldet. Die \enquote{Einstellungs}-Oberfläche ist im Browser geladen.
+ \item [Aktion] Der Benutzer gibt \enquote{test} als altes Passwort ein. Weiter gibt er in die Felder \enquote{Neues Passwort} und \enquote{Wiederholen} \enquote{NeuerTest123!?} ein. Dann klickt er auf den Knopf \enquote{Passwort ändern}.
+ \item [Reaktion] Die \enquote{Einstellungs}-Oberfläche bleibt geladen. Der Benutzer bekommt eine Fehlermeldung, dass das alte Passwort falsch ist. In den Feldern \enquote{Neues Passwort} und \enquote{Wiederholen} steht weiter \enquote{NeuerTest123!?}.
+\end{description}
+
+\item
+\begin{description}
+ \item [Stand] Der Benutzer ist angemeldet. Die \enquote{Einstellungs}-Oberfläche ist im Browser geladen.
+ \item [Aktion] Der Benutzer gibt \enquote{Test123!?} als altes Passwort ein. Weiter gibt er in die Felder \enquote{Neues Passwort} und \enquote{Wiederholen} \enquote{neuerTest} ein. Dann klickt er auf den Knopf \enquote{Passwort ändern}.
+ \item [Reaktion] Die \enquote{Einstellungs}-Oberfläche bleibt geladen. Dem Benutzer wird angezeigt das sein neues Passwort nicht die Passwort-Mindestanforderungen erfüllt. Weiter wird farblich angezeigt, dass sein Passwort nicht:
+ \color{red}
+ \begin{itemize}
+ \item mindestens eine Zahl enthält.
+ \item mindestens ein Sonderzeichen enthält.
+ \end{itemize}
+ \color{black}
+ Dem Benutzer wird farblich angezeigt, dass sein Passwort:
+ \color{ForestGreen}
+ \begin{itemize}
+ \item mindestens 8 Zeichen lang ist.
+ \item mindestens einen Kleinbuchstaben enthält.
+ \item mindestens einen Großbuchstaben enthält.
+ \end{itemize}
+ \color{black}
+\end{description}
+
+\item
+\begin{description}
+ \item [Stand] Der Benutzer ist angemeldet. Die \enquote{Einstellungs}-Oberfläche ist im Browser geladen.
+ \item [Aktion] Der Benutzer gibt in das \enquote{Altes Passwort}-Feld \enquote{Test123!?} ein. Er gibt in das \enquote{Neues Passwort}-Feld und in das \enquote{Wiederholen}-Feld \enquote{NeuerTest123!?} ein. Dann klickt er auf den Knopf \enquote{Passwort ändern}.
+ \item [Reaktion] Die \enquote{Einstellungs}-Oberfläche bleibt geladen. Die Felder \enquote{Altes Passwort}, \enquote{Neues Passwort} und \enquote{Wiederholen} werden geleert. Dem Benutzer wird angezeigt, dass das Passwort erfolgreich geändert wurde.
+\end{description}
+
+\item
+\begin{description}
+ \item [Stand] Der Benutzer ist angemeldet. Die \enquote{Einstellungs}-Oberfläche ist im Browser geladen. Sein Passwort wurde zu \enquote{NeuerTest123!?} geändert.
+ \item [Aktion] Der Benutzer meldet sich ab.
+ \item [Reaktion] Der Browser wechselt zur Anmeldeseite. Der Benutzer ist abgemeldet.
+\end{description}
+
+\item
+\begin{description}
+ \item [Stand] Der Benutzer ist abgemeldet. Die Anmeldeseite ist geladen.
+ \item [Aktion] Der Benutzer gibt als E-Mail \enquote{pseIstToll@test.com} und \enquote{Test123!?} als Passwort ein. Dann klickt der Benutzer auf den Knopf \enquote{Anmelden}.
+ \item [Reaktion] Die Anmeldeseite bleibt geladen. Als E-Mail ist \enquote{pseIstToll@test.com} eingetragen und als Passwort ist \enquote{Test123!?} eingetragen. Dem Benutzer wird per Fehlermeldung ausgegeben, dass E-Mail-Adresse oder Passwort ungültig sind.
+\end{description}
+
+\item
+\begin{description}
+ \item [Stand] Der Benutzer ist abgemeldet. Die Anmeldeseite ist geladen.
+ \item [Aktion] Der Benutzer gibt als E-Mail \enquote{pseIstToll@test.com} und \enquote{NeuerTest123!?} als Passwort ein. Dann klickt der Benutzer auf den Knopf \enquote{Anmelden}.
+ \item [Reaktion] Der Browser wechselt zum \Gls{dashboard}.\\
+\end{description}
+
+\end{enumerate}
+
+\newpage
+
+
+\subsection{Passwort vergessen}\label{t:forgot-pw}
+\vspace{0.3cm}
+
+\begin{description}
+ \item [Vorbedingung] Es gibt nur einen registrierten Benutzer. Dieser hat die E-Mail \enquote{pseIstToll@test.com} und \enquote{Test123!?} als Passwort.
+\end{description}
+
+\begin{enumerate}
+
+\item
+\begin{description}
+ \item [Stand] Die Anmeldeseite ist im Browser geladen.
+ \item [Aktion] Der Benutzer klickt auf den Knopf \enquote{Passwort vergessen?}.
+ \item [Reaktion] Der Browser wechselt zur \enquote{Passwort vergessen}-Seite.
+\end{description}
+
+\item
+\begin{description}
+ \item [Stand] Die Passwort-Vergessen-Seite ist im Browser geladen.
+ \item [Aktion] Der Benutzer gibt in das \enquote{E-Mail}-Feld \enquote{pseIstSuperToll@test.com} ein. Dann klickt der Benutzer auf den Knopf \enquote{Bestätigen}.
+ \item [Reaktion] Die \enquote{Passwort zurücksetzen}-Seite bleibt geladen. Dem Benutzer wird eine Fehlermeldung angezeigt, dass diese E-Mail-Adresse nicht vergeben ist.
+\end{description}
+
+\item
+\begin{description}
+ \item [Stand] Die Passwort-Vergessen-Seite ist im Browser geladen.
+ \item [Aktion] Der Benutzer gibt in das \enquote{E-Mail}-Feld \enquote{pseIstToll@test.com} ein. Der Benutzer klickt auf den Knopf \enquote{Bestätigen}.
+ \item [Reaktion] Der Benutzer wird darüber benachrichtigt, dass an die angegebene E-Mail-Adresse eine E-Mail mit einem Link zum Zurücksetzen des Passworts versendet wurde.
+\end{description}
+
+\item
+\begin{description}
+ \item [Stand] Der Benutzer hat die E-Mail mit dem Link zum Zurücksetzen des Passworts erhalten und sein Passwort noch nicht zurückgesetzt.
+ \item [Aktion] Der Benutzer klickt innerhalb von 24 Stunden nach Versendung auf den Link zum Passwort Zurücksetzen.
+ \item [Reaktion] Der Browser wechselt zur \enquote{Passwort zurücksetzen}-Seite.
+\end{description}
+
+\item
+\begin{description}
+ \item [Stand] Im Browser ist die \enquote{Passwort zurücksetzen}-Seite geladen.
+ \item [Aktion] Der Benutzer gibt in die Felder \enquote{Neues Passwort} und \enquote{Wiederholen} \enquote{neuerTest} ein. Dann klickt er auf den Knopf \enquote{Passwort zurücksetzen}.
+ \item [Reaktion] Die \enquote{Passwort zurücksetzen}-Seite bleibt geladen. Dem Benutzer wird angezeigt das sein neues Passwort nicht die Passwort-Mindestanforderungen erfüllt. Weiter wird farblich angezeigt, dass sein Passwort nicht:
+ \color{red}
+ \begin{itemize}
+ \item mindestens eine Zahl enthält.
+ \item mindestens ein Sonderzeichen enthält.
+ \end{itemize}
+ \color{black}
+ Dem Benutzer wird farblich angezeigt, dass sein Passwort:
+ \color{ForestGreen}
+ \begin{itemize}
+ \item mindestens 8 Zeichen lang ist.
+ \item mindestens einen Kleinbuchstaben enthält.
+ \item mindestens einen Großbuchstaben enthält.
+ \end{itemize}
+ \color{black}
+\end{description}
+
+\newpage
+
+\item
+\begin{description}
+ \item [Stand] Im Browser ist die \enquote{Passwort zurücksetzen}-Seite geladen.
+ \item [Aktion] Der Benutzer gibt in das \enquote{Neues Passwort}-Feld und in das \enquote{Wiederholen}-Feld \enquote{NeuerTest123!?} ein. Dann klickt der Benutzer auf den Knopf \enquote{Passwort zurücksetzen}.
+ \item [Reaktion] Der Browser wechselt zur Anmeldeseite. Der verwendete Link zum zurücksetzen des Passworts wird ungültig.
+\end{description}
+
+\item
+\begin{description}
+ \item [Stand] Im Browser ist die Anmeldeseite geladen.
+ \item [Aktion] Der Benutzer gibt in das \enquote{E-Mail}-Feld \enquote{pseIstToll@test.com} und \enquote{Test\-123!?} als Passwort ein.
+ \item [Reaktion] Die Anmeldeseite bleibt geladen. Der Benutzer bekommt eine Fehlermeldung, dass die E-Mail oder das Passwort ungültig ist.
+\end{description}
+
+\item
+\begin{description}
+ \item [Stand] Im Browser ist die Anmeldeseite geladen.
+ \item [Aktion] Der Benutzer gibt in das \enquote{E-Mail}-Feld \enquote{pseIstToll@test.com} und \enquote{NeuerTest123!?} als Passwort ein.
+ \item [Reaktion] Der Browser wechselt zum \Gls{dashboard}.
+\end{description}
+
+\item
+\begin{description}
+ \item [Stand] Der Benutzer hat die E-Mail mit dem Link zum Zurücksetzen des Passworts erhalten und sein Passwort noch nicht zurückgesetzt. Die E-Mail wurde vor mehr als 24 Stunden versendet.
+ \item [Aktion] Der Benutzer klickt auf den Link zum Passwort Zurücksetzen.
+ \item [Reaktion] Der Benutzer bekommt eine Fehlermeldung, dass der Link abgelaufen ist. Das Passwort wird nicht zurückgesetzt. Der Benutzer wird auf die Anmeldeseite weitergeleitet.
+\end{description}
+
+\item
+\begin{description}
+ \item [Stand] Der Benutzer hat die E-Mail mit dem Link zum Zurücksetzen des Passworts erhalten und sein Passwort bereits über diesen Link zurückgesetzt.
+ \item [Aktion] Der Benutzer klickt erneut auf den Link zum Passwort Zurücksetzen.
+ \item [Reaktion] Der Benutzer bekommt eine Fehlermeldung, dass der Link abgelaufen ist. Das Passwort wird nicht zurückgesetzt. Der Benutzer wird auf die Anmeldeseite weitergeleitet.\\
+\end{description}
+
+\end{enumerate}
+
+\newpage
+
+
+\subsection{Account Löschen}\label{t:delete-acc}
+\vspace{0.3cm}
+
+\begin{description}
+ \item [Vorbedingung] Es gibt den registrierten Benutzer mit der E-Mail \enquote{pseIstToll@test.com} und \enquote{Test123!?} als Passwort.
+\end{description}
+
+\begin{enumerate}
+
+\item
+\begin{description}
+ \item [Stand] Der Benutzer ist angemeldet. Im Browser ist die Einstellungsseite geladen. Möglichkeit zum Löschen des Accounts unten links.
+ \item [Aktion] Der Benutzer klickt auf den Knopf \enquote{Account löschen}.
+ \item [Reaktion] Der Browser wechselt zur Account-Löschen-Seite. Auf dieser wird der Benutzer aufgefordert sein Passwort einzugeben um den Vorgang des Löschens zu Bestätigen.
+\end{description}
+
+\item
+\begin{description}
+ \item [Stand] Die Account-Löschen-Seite ist im Browser geladen.
+ \item [Aktion] Der Benutzer macht keine Eingaben und klickt auf den Knopf \enquote{Account löschen bestätigen}.
+ \item [Reaktion] Die Account-Löschen-Seite bleibt geladen. Dem Benutzer wird eine Fehlermeldung angezeigt, dass er um die Account Löschung zu bestätigen sein Passwort eingeben muss.
+\end{description}
+
+\item
+\begin{description}
+ \item [Stand] Die Account-Löschen-Seite ist im Browser geladen.
+ \item [Aktion] Der Benutzer gibt \enquote{test123!?} als Passwort ein und klickt auf den Knopf \enquote{Account löschen bestätigen}.
+ \item [Reaktion] Es bleibt die Account-Löschen-Seite geladen. Dem Benutzer wird eine Fehlermeldung angezeigt, dass das Passwort falsch ist.
+\end{description}
+
+\item
+\begin{description}
+ \item [Stand] Die Account-Löschen-Seite ist im Browser geladen.
+ \item [Aktion] Der Benutzer gibt \enquote{Test123!?} als Passwort ein und klickt auf den Knopf \enquote{Account löschen bestätigen}.
+ \item [Reaktion] Der Account des Benutzers wird zusammen mit allen dazugehörigen gespeicherten Daten gelöscht. Der Browser wechselt zur Anmeldeseite.
+\end{description}
+
+\item
+\begin{description}
+ \item [Stand] Die Anmeldeseite ist im Browser geladen.
+ \item [Aktion] Der Benutzer gibt als E-Mail \enquote{pseIstToll@test.com} und \enquote{Test123!?} als Passwort ein. Dann klickt er auf den \enquote{Anmelden} Knopf.
+ \item [Reaktion] Die Anmeldeseite bleibt geladen und dem Benutzer wird eine Fehlermeldung angezeigt: \enquote{E-Mail-Adresse oder Passwort ist ungültig!}
+\end{description}
+
+\item
+\begin{description}
+ \item [Stand] Die Account-Löschen-Seite ist im Browser geladen.
+ \item [Aktion] Der Benutzer klickt auf den \enquote{Abbrechen} Knopf.
+ \item [Reaktion] Der Account wird nicht gelöscht. Der Browser wechselt zur Einstellungsseite.
+\end{description}
+
+\end{enumerate}
+
+\newpage
+
+
+\subsection{Synchronisation: Podcast abonnieren}\label{t:sync-sub}
+\vspace{0.3cm}
+
+\begin{enumerate}
+
+\item
+\begin{description}
+ \item [Stand] Der Benutzer ist in einem synchronisierten \Gls{podcatcher} angemeldet.
+ \item [Aktion] Der Benutzer fügt den \Gls{podcast} \enquote{Der tagesschau
+ Zukunfts-Podcast: mal angenommen} zu seinen \Glspl{abo} hinzu.
+ \item [Reaktion] Der \Gls{podcatcher} synchronisiert das neue \Gls{abo}.
+\end{description}
+
+\item
+\begin{description}
+ \item [Stand] Dem Benutzer wird die \enquote{Zuletzt gehört}-Oberfläche angezeigt.
+ \item [Aktion] Der Benutzer klickt auf den Reiter \enquote{Podcasts}.
+ \item [Reaktion] Der Browser wechselt zur \enquote{Podcasts}-Oberfläche.
+ Diese zeigt eine Liste aller abonnierten \Glspl{podcast}. Der oberste
+ Eintrag ist der \Gls{podcast} \enquote{Der tagesschau Zukunfts-Podcast:
+ mal angenommen}.
+\end{description}
+
+\item
+\begin{description}
+ \item [Stand] Der Benutzer meldet sich über ein anderes Gerät in einem
+ synchronisierten \Gls{podcatcher} an.
+ \item [Aktion] Der Benutzer lässt sich im \Gls{podcatcher} die Liste seiner
+ \Glspl{abo} anzeigen.
+ \item [Reaktion] Nach kurzer Zeit oder durch manuelles Synchronisieren wird
+ dem Benutzer dort ebenfalls die aktualisierte Liste der \Glspl{abo}
+ angezeigt. Diese enthält insbesondere den Eintrag mit dem \Gls{podcast} \enquote{Der tagesschau Zukunfts-Podcast: mal angenommen}.\\
+\end{description}
+
+\end{enumerate}
+
+
+\subsection{Synchronisation: Podcast deabonnieren}\label{t:sync-unsub}
+\vspace{0.3cm}
+
+\begin{description}
+ \item [Vorbedingung] Der Benutzer hat den \Gls{podcast} \enquote{Der tagesschau Zukunfts-Podcast: mal angenommen} abonniert.
+\end{description}
+
+\begin{enumerate}
+
+\item
+\begin{description}
+ \item [Stand] Der Benutzer ist in einem synchronisierten \Gls{podcatcher} angemeldet.
+ \item [Aktion] Der Benutzer deabonniert den \Gls{podcast} \enquote{Der tagesschau Zukunfts-Podcast: mal angenommen}.
+ \item [Reaktion] Der \Gls{podcatcher} synchronisiert die reduzierte Liste
+ der \Glspl{abo}.
+\end{description}
+
+\item
+\begin{description}
+ \item [Stand] Die \enquote{Zuletzt gehört}-Oberfläche ist im Browser geladen.
+ \item [Aktion] Der Benutzer klickt auf den Reiter \enquote{Podcasts}.
+ \item [Reaktion] Der Browser wechselt zur \enquote{Podcasts}-Oberfläche.
+ Diese zeigt die aktuelle Liste aller abonnierten \Glspl{podcast}. Der Eintrag \enquote{Der tagesschau Zukunfts-Podcast: mal angenommen} ist nicht mehr in der Liste enthalten.\\
+\end{description}
+
+\end{enumerate}
+
+\newpage
+
+\subsection{Synchronisation: \Gls{episode} anhören}\label{t:sync-episode}
+\vspace{0.3cm}
+
+\begin{enumerate}
+
+\item
+\begin{description}
+ \item [Stand] Der Benutzer ist in einem synchronisierten \Gls{podcatcher} angemeldet.
+ \item [Aktion] Der Benutzer hört sich die \Gls{episode} \enquote{Kein Handel mit
+ China? Was dann?} des \Glspl{podcast} \enquote{Der tagesschau Zukunfts-Podcast: mal angenommen} bis zum Zeitpunkt 7 Minuten 19 Sekunden an. Dann beendet er die Wiedergabe.
+ \item [Reaktion] Der \Gls{podcatcher} synchronisiert den Fortschritt beim
+ Anhören der \Gls{episode}.
+\end{description}
+
+\item
+\begin{description}
+ \item [Stand] Die \enquote{Podcasts}-Oberfläche ist im Browser geladen.
+ \item [Aktion] Der Benutzer klickt auf den Reiter \enquote{Zuletzt gehört}.
+ \item [Reaktion] Der Browser wechselt zur \enquote{Zuletzt
+ gehört}-Oberfläche. Diese zeigt eine Liste aller angefangenen, aber
+ nicht beendeten \Glspl{episode} mit korrespondierendem Hörfortschritt
+ an. Die Liste ist nach der Aktualität des Anhörens oder Ansehens einer
+ \Gls{episode} sortiert. Der oberste Eintrag ist die \Gls{episode} \enquote{Kein Handel mit China? Was dann?} mit dem Fortschritt 7 Minuten 19 Sekunden.
+\end{description}
+
+\item
+\begin{description}
+ \item [Stand] Der Benutzer meldet sich über ein anderes Gerät in einem
+ synchronisierten \Gls{podcatcher} an.
+ \item [Aktion] Der Benutzer hört sich die \Gls{episode} \enquote{Kein Handel mit
+ China? Was dann?} des \Glspl{podcast} \enquote{Der tagesschau Zukunfts-Podcast: mal angenommen} bis zum Zeitpunkt 4 Minuten 30 Sekunden an. Dann beendet er die Wiedergabe.
+ \item [Reaktion] Der \Gls{podcatcher} synchronisiert den Fortschritt beim
+ Anhören der \Gls{episode}.
+\end{description}
+
+\item
+\begin{description}
+ \item [Stand] Die \enquote{Podcasts}-Oberfläche ist im Browser geladen.
+ \item [Aktion] Der Benutzer klickt auf den Reiter \enquote{Zuletzt gehört}.
+ \item [Reaktion] Der Browser wechselt zur \enquote{Zuletzt
+ gehört}-Oberfläche. Der oberste Eintrag der \enquote{Zuletzt
+ gehört}-Liste ist die \Gls{episode} \enquote{Kein Handel mit China? Was dann?} mit dem Fortschritt 4 Minuten 30 Sekunden.\\
+\end{description}
+
+\end{enumerate}
+
+
+\subsection{Benutzeranleitung anzeigen}\label{t:man}
+\vspace{0.3cm}
+
+\begin{description}
+ \item [Stand] Der Benutzer ist im Webfrontend angemeldet.
+ \item [Aktion] Der Benutzer klickt auf den \enquote{Hilfe}-Button oben rechts (Abbildung \ref{fig:help-desktop}).
+ \item [Reaktion] Dem Benutzer wird ein leeres \enquote{Hilfe}-Fenster
+ angezeigt. (Dieses kann nachträglich um Hilfestellungen zum
+ Synchronisieren von \Glspl{podcast} ergänzt werden. \ref{r:no-man})\\
+\end{description}
+
+
+\subsection{Lasttest}\label{t:lasttest}
+\vspace{0.3cm}
+Es werden Lasttests zur Überprüfung der Leitungsfähigkeit des Synchronisa\-tions-Server Systems durchgeführt.
+Dabei müssen über einen längeren Zeitraum mindestens 50 Anfragen pro Sekunde verarbeitet werden.
+Die Antwortzeit pro Anfrage darf dabei nicht mehr als 500 Millisekunden betragen.
+Der Test gilt als bestanden, wenn diese Anforderungen erfüllt sind.
+
diff --git a/00-pflichtenheft/tikz-uml.sty b/00-pflichtenheft/tikz-uml.sty
new file mode 100644
index 0000000..c6e8e0d
--- /dev/null
+++ b/00-pflichtenheft/tikz-uml.sty
@@ -0,0 +1,5377 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Start of tikz-uml.sty
+%
+% Some macros for UML Diagrams.
+% Home page of project :
+% Author: Nicolas Kielbasiewicz
+% Style from :
+% Fixed by Nicolas Kielbasiewicz (nicolas.kielbasiewicz@ensta-paristech.fr) in march 2016 to compile with pgf 3.00
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+\NeedsTeXFormat{LaTeX2e}[1995/12/01]%
+\ProvidesPackage{tikz-uml}[2011/01/26]%
+%
+\RequirePackage{etoolbox}%
+\RequirePackage{ifthen}%
+\RequirePackage{tikz}%
+\RequirePackage{xstring}%
+\RequirePackage{calc}%
+\RequirePackage{pgfopts}%
+\usetikzlibrary{backgrounds,arrows,shapes,fit,shadows,decorations.markings}%
+%
+\def\tikzumlPackageLayersNum{3}%
+\pgfkeys{/tikzuml/options/.cd, packageLayers/.initial=3}%
+\pgfkeys{/tikzuml/options/.cd, packageLayers/.store in=\tikzumlPackageLayersNum}%
+\def\tikzumlStateLayersNum{3}%
+\pgfkeys{/tikzuml/options/.cd, stateLayers/.initial=3}%
+\pgfkeys{/tikzuml/options/.cd, stateLayers/.store in=\tikzumlStateLayersNum}%
+\def\tikzumlFragmentLayersNum{3}%
+\pgfkeys{/tikzuml/options/.cd, fragmentLayers/.initial=3}%
+\pgfkeys{/tikzuml/options/.cd, fragmentLayers/.store in=\tikzumlFragmentLayersNum}%
+\def\tikzumlComponentLayersNum{3}%
+\pgfkeys{/tikzuml/options/.cd, componentLayers/.initial=3}%
+\pgfkeys{/tikzuml/options/.cd, componentLayers/.store in=\tikzumlComponentLayersNum}%
+%
+\ProcessPgfOptions{/tikzuml/options}%
+%
+\def\pgfsetlayersArg{background}%
+\pgfdeclarelayer{background}%
+\newcounter{tikzumlPackageLayers}%
+\loop \pgfdeclarelayer{package\thetikzumlPackageLayers}%
+ \xdef\pgfsetlayersArg{\pgfsetlayersArg,package\thetikzumlPackageLayers}%
+ \ifnum\tikzumlPackageLayersNum>\thetikzumlPackageLayers%
+ \stepcounter{tikzumlPackageLayers}%
+\repeat%
+%
+\newcounter{tikzumlFragmentLayers}%
+\loop \pgfdeclarelayer{fragment\thetikzumlFragmentLayers}%
+ \xdef\pgfsetlayersArg{\pgfsetlayersArg,fragment\thetikzumlFragmentLayers}%
+ \ifnum\tikzumlFragmentLayersNum>\thetikzumlFragmentLayers%
+ \stepcounter{tikzumlFragmentLayers}%
+\repeat%
+%
+\newcounter{tikzumlStateLayers}%
+\loop \pgfdeclarelayer{state\thetikzumlStateLayers}%
+ \xdef\pgfsetlayersArg{\pgfsetlayersArg,state\thetikzumlStateLayers}%
+ \ifnum\tikzumlStateLayersNum>\thetikzumlStateLayers%
+ \stepcounter{tikzumlStateLayers}%
+\repeat%
+%
+\newcounter{tikzumlComponentLayers}%
+\loop \pgfdeclarelayer{component\thetikzumlComponentLayers}%
+ \xdef\pgfsetlayersArg{\pgfsetlayersArg,component\thetikzumlComponentLayers}%
+ \ifnum\tikzumlComponentLayersNum>\thetikzumlComponentLayers%
+ \stepcounter{tikzumlComponentLayers}%
+\repeat%
+%
+\pgfdeclarelayer{lifelines}%
+\pgfdeclarelayer{activity}%
+\pgfdeclarelayer{connections}%
+\xdef\pgfsetlayersArg{\pgfsetlayersArg,lifelines,activity,connections,main}%
+\pgfsetlayers{\pgfsetlayersArg}%
+%
+\pgfkeys{/tikzuml/.cd, text/.initial=black, draw/.initial=black, font/.initial=\small,%
+ x/.initial=0, y/.initial=0,%
+ package type/.initial=tikzumlEmpty, fill package/.initial=blue!20,%
+ class width/.initial=10ex, simple interface width/.initial=4ex, class type/.initial=class, fill class/.initial=yellow!20, fill template/.initial=yellow!2,%
+ narynode width/.initial=6ex,%
+ relation geometry/.initial=--, relation angle1/.initial=-30, relation angle2/.initial=30, relation loopsize/.initial=3em, relation weight/.initial=0.5, relation pos1/.initial=0.2, relation pos2/.initial=0.8, relation pos stereo/.initial=0.5,%
+ note width/.initial=3cm, fill note/.initial=green!20,%
+ fill system/.initial=white,%
+ fill usecase/.initial=blue!20,%
+ actor below/.initial=0.5cm,%
+ state join width/.initial=3ex,%
+ state decision width/.initial=3ex,%
+ state initial width/.initial=5ex,%
+ state final width/.initial=5.5ex,%
+ state enter width/.initial=5ex,%
+ state exit width/.initial=5ex,%
+ state end width/.initial=5ex,%
+ state history width/.initial=5ex,%
+ state deep history width/.initial=5ex,%
+ state width/.initial=8ex, fill state/.initial=yellow!20,%
+ object stereo/.initial=object, fill object/.initial=yellow!20,%
+ call dt/.initial=tikzumlEmpty, call padding/.initial=2, call type/.initial=synchron, fill call/.initial=white,%
+ fragment type/.initial=opt, fragment inner xsep/.initial=1, fragment inner ysep/.initial=1, fill fragment/.initial= none,%
+ create call dt/.initial=4,%
+ component width/.initial=8ex, fill component/.initial= yellow!20,%
+ required interface distance/.initial=2.5cm, required interface width/.initial=1em, required interface padding/.initial=1cm,%
+ provided interface distance/.initial=3cm, provided interface width/.initial=1em, provided interface padding/.initial=1cm,%
+ port width/.initial=1ex, fill port/.initial= yellow!20,%
+ fill assembly connector/.initial= white,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \errmessage{TIKZUML ERROR : in tikzuml global, invalid option \keyname}%
+ }%
+}%
+%
+\pgfkeys{/tikzuml/.cd, text/.get=\tikzumlDefaultTextColor, draw/.get=\tikzumlDefaultDrawColor, font/.get=\tikzumlDefaultFont,%
+ x/.get=\tikzumlDefaultX, y/.get=\tikzumlDefaultY,%
+ package type/.get=\tikzumlPackageDefaultType, fill package/.get=\tikzumlPackageDefaultFillColor,%
+ class width/.get=\tikzumlClassDefaultWidth, simple interface width/.get=\tikzumlSimpleInterfaceDefaultWidth, class type/.get=\tikzumlClassDefaultType, fill class/.get=\tikzumlClassDefaultFillColor, fill template/.get=\tikzumlClassTemplateFillColorDefaultFillColor,%
+ narynode width/.get=\tikzumlNaryNodeDefaultWidth,%
+ relation geometry/.get=\tikzumlRelationDefaultGeometry, relation angle1/.get=\tikzumlRelationDefaultAngleO, relation angle2/.get=\tikzumlRelationDefaultAngleT, relation loopsize/.get=\tikzumlRelationDefaultLoopSize, relation weight/.get=\tikzumlRelationDefaultWeight, relation pos1/.get=\tikzumlRelationDefaultPosO, relation pos2/.get=\tikzumlRelationDefaultPosT, relation pos stereo/.get=\tikzumlRelationDefaultPosStereo,%
+ note width/.get=\tikzumlNoteDefaultWidth, fill note/.get=\tikzumlNoteDefaultFillColor,%
+ fill system/.get=\tikzumlSystemDefaultFillColor,%
+ fill usecase/.get=\tikzumlUseCaseDefaultFillColor,%
+ actor below/.get=\tikzumlActorDefaultBelow,%
+ state join width/.get=\tikzumlStateJoinDefaultWidth,%
+ state decision width/.get=\tikzumlStateDecisionDefaultWidth,%
+ state initial width/.get=\tikzumlStateInitialDefaultWidth,%
+ state final width/.get=\tikzumlStateFinalDefaultWidth,%
+ state enter width/.get=\tikzumlStateEnterDefaultWidth,%
+ state exit width/.get=\tikzumlStateExitDefaultWidth,%
+ state end width/.get=\tikzumlStateEndDefaultWidth,%
+ state history width/.get=\tikzumlStateHistoryDefaultWidth,%
+ state deep history width/.get=\tikzumlStateDeepHistoryDefaultWidth,%
+ state width/.get=\tikzumlStateDefaultWidth, fill state/.get=\tikzumlStateDefaultFillColor,%
+ object stereo/.get=\tikzumlObjectDefaultStereo, fill object/.get=\tikzumlObjectDefaultFillColor,%
+ call dt/.get=\tikzumlCallDefaultDT, call padding/.get=\tikzumlCallDefaultPadding, call type/.get=\tikzumlCallDefaultType, fill call/.get=\tikzumlCallDefaultFillColor,%
+ fragment type/.get=\tikzumlFragmentDefaultType, fragment inner xsep/.get=\tikzumlFragmentDefaultXSep, fragment inner ysep/.get=\tikzumlFragmentDefaultYSep, fill fragment/.get=\tikzumlFragmentDefaultFillColor,%
+ create call dt/.get=\tikzumlCreateCallDefaultDT,%
+ component width/.get=\tikzumlComponentDefaultWidth, fill component/.get=\tikzumlComponentDefaultFillColor,%
+ required interface distance/.get=\tikzumlRequiredInterfaceDefaultDistance, required interface width/.get=\tikzumlRequiredInterfaceDefaultWidth, required interface padding/.get=\tikzumlRequiredInterfaceDefaultPadding,%
+ provided interface distance/.get=\tikzumlProvidedInterfaceDefaultDistance, provided interface width/.get=\tikzumlProvidedInterfaceDefaultWidth, provided interface padding/.get=\tikzumlProvidedInterfaceDefaultPadding,%
+ port width/.get=\tikzumlPortDefaultWidth, fill port/.get=\tikzumlPortDefaultFillColor,%
+ fill assembly connector/.get=\tikzumlAssemblyConnectorDefaultFillColor%
+}%
+%
+% utility : change default colors
+\newcommand{\tikzumlset}[1]{%
+ \pgfkeys{/tikzuml/.cd,#1}%
+ \pgfkeys{/tikzuml/.cd, text/.get=\tikzumlDefaultTextColor, draw/.get=\tikzumlDefaultDrawColor, font/.get=\tikzumlDefaultFont,%
+ x/.get=\tikzumlDefaultX, y/.get=\tikzumlDefaultY,%
+ package type/.get=\tikzumlPackageDefaultType, fill package/.get=\tikzumlPackageDefaultFillColor,%
+ class width/.get=\tikzumlClassDefaultWidth, simple interface width/.get=\tikzumlSimpleInterfaceDefaultWidth, class type/.get=\tikzumlClassDefaultType, fill class/.get=\tikzumlClassDefaultFillColor, fill template/.get=\tikzumlClassTemplateFillColorDefaultFillColor,%
+ narynode width/.get=\tikzumlNaryNodeWidth,%
+ relation geometry/.get=\tikzumlRelationDefaultGeometry, relation angle1/.get=\tikzumlRelationDefaultAngleO, relation angle2/.get=\tikzumlRelationDefaultAngleT, relation loopsize/.get=\tikzumlRelationDefaultLoopSize, relation weight/.get=\tikzumlRelationDefaultWeight, relation pos1/.get=\tikzumlRelationDefaultPosO, relation pos2/.get=\tikzumlRelationDefaultPosT, relation pos stereo/.get=\tikzumlRelationDefaultPosStereo,%
+ note width/.get=\tikzumlNoteDefaultWidth, fill note/.get=\tikzumlNoteDefaultFillColor,%
+ fill system/.get=\tikzumlSystemDefaultFillColor,%
+ fill usecase/.get=\tikzumlUseCaseDefaultFillColor,%
+ actor below/.get=\tikzumlActorDefaultBelow,%
+ state join width/.get=\tikzumlStateJoinDefaultWidth,%
+ state decision width/.get=\tikzumlStateDecisionDefaultWidth,%
+ state initial width/.get=\tikzumlStateInitialDefaultWidth,%
+ state final width/.get=\tikzumlStateFinalDefaultWidth,%
+ state enter width/.get=\tikzumlStateEnterDefaultWidth,%
+ state exit width/.get=\tikzumlStateExitDefaultWidth,%
+ state end width/.get=\tikzumlStateEndDefaultWidth,%
+ state history width/.get=\tikzumlStateHistoryDefaultWidth,%
+ state deep history width/.get=\tikzumlStateDeepHistoryDefaultWidth,%
+ state width/.get=\tikzumlStateDefaultWidth, fill state/.get=\tikzumlStateDefaultFillColor,%
+ object stereo/.get=\tikzumlObjectDefaultStereo, fill object/.get=\tikzumlObjectDefaultFillColor,%
+ call dt/.get=\tikzumlCallDefaultDT, call padding/.get=\tikzumlCallDefaultPadding, call type/.get=\tikzumlCallDefaultType, fill call/.get=\tikzumlCallDefaultFillColor,%
+ fragment type/.get=\tikzumlFragmentDefaultType, fragment inner xsep/.get=\tikzumlFragmentDefaultXSep, fragment inner ysep/.get=\tikzumlFragmentDefaultYSep, fill fragment/.get=\tikzumlFragmentDefaultFillColor,%
+ create call dt/.get=\tikzumlCreateCallDT,%
+ component width/.get=\tikzumlComponentDefaultWidth, fill component/.get=\tikzumlComponentDefaultFillColor,%
+ required interface distance/.get=\tikzumlRequiredInterfaceDefaultDistance, required interface width/.get=\tikzumlRequiredInterfaceDefaultWidth, required interface padding/.get=\tikzumlRequiredInterfaceDefaultPadding,%
+ provided interface distance/.get=\tikzumlProvidedInterfaceDefaultDistance, provided interface width/.get=\tikzumlProvidedInterfaceDefaultWidth, provided interface padding/.get=\tikzumlProvidedInterfaceDefaultPadding,%
+ port width/.get=\tikzumlPortDefaultWidth, fill port/.get=\tikzumlPortDefaultFillColor,%
+ fill assembly connector/.get=\tikzumlAssemblyConnectorDefaultFillColor%
+ }%
+}%
+%
+% define a point
+% arg : node/coordinates of the point
+\newcommand{\umlpoint}[1]{%
+ \begin{pgfonlayer}{connections}%
+ \node[tikzuml control nodes style] at (#1) {};%
+ \end{pgfonlayer}%
+}%
+%
+\newcommand{\tikzumlskipescape}[3][_]{%
+\begingroup%
+ \def\_{#1}\edef\x{\endgroup%
+ \def\noexpand\csname #3\endcsname{#2}}\x%
+}%
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% class diagrams %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+\pgfkeys{/tikzuml/relation/.cd, attr1/.style args={#1|#2}{arg1=#1, mult1=#2},%
+ attr2/.style args={#1|#2}{arg2=#1, mult2=#2},%
+ attr/.style args={#1|#2}{arg=#1, mult=#2},%
+ recursive/.style args={#1|#2|#3}{angle1=#1, angle2=#2, loopsize=#3},%
+ anchors/.style args={#1 and #2}{anchor1=#1, anchor2=#2},%
+ recursive direction/.style args={#1 to #2}{recursive direction start=#1, recursive direction end=#2}%
+}%
+%
+\pgfkeys{/tikzuml/note/.cd, anchors/.style args={#1 and #2}{anchor1=#1, anchor2=#2}}%
+%
+\tikzstyle{tikzuml simpleclass style}=[rectangle, minimum height=2em, node distance=2em]%
+\tikzstyle{tikzuml simpleinterface style}=[circle, minimum height=1em, node distance=1em]%
+\tikzstyle{tikzuml class style}=[rectangle split, rectangle split parts=3, rectangle split part align={center, left, left}, minimum height=2em, node distance=2em]%
+\tikzstyle{tikzuml narynode style}=[diamond]%
+\tikzstyle{tikzuml template style}=[dashed, inner ysep=0.5em, inner xsep=1ex]%
+\tikzstyle{tikzuml control nodes style}=[fill=black, inner sep=1.5pt, circle]%
+%
+\tikzstyle{tikzuml association style}=[color=\tikzumlDefaultDrawColor, -]%
+\tikzstyle{tikzuml bidirectional association style}=[color=\tikzumlDefaultDrawColor, angle45-angle45]%
+\tikzstyle{tikzuml unidirectional association style}=[color=\tikzumlDefaultDrawColor, -angle 45]%
+\tikzstyle{tikzuml aggregation style}=[color=\tikzumlDefaultDrawColor, open diamond-]%
+\tikzstyle{tikzuml unidirectional aggregation style}=[color=\tikzumlDefaultDrawColor, open diamond-angle 45]%
+\tikzstyle{tikzuml composition style}=[color=\tikzumlDefaultDrawColor, diamond-]%
+\tikzstyle{tikzuml unidirectional composition style}=[color=\tikzumlDefaultDrawColor, diamond-angle 45]%
+\tikzstyle{tikzuml nesting style}=[color=\tikzumlDefaultDrawColor]%
+\tikzstyle{tikzuml dependency style}=[color=\tikzumlDefaultDrawColor, -angle 45, dashed]%
+\tikzstyle{tikzuml import style}=[color=\tikzumlDefaultDrawColor, -angle 45, dashed]%
+\tikzstyle{tikzuml inherit style}=[color=\tikzumlDefaultDrawColor, -open triangle 45]%
+\tikzstyle{tikzuml implements style}=[color=\tikzumlDefaultDrawColor, -open triangle 45, dashed]%
+%
+\pgfkeys{/tikzuml/assemblyconnectorrelation/.cd, anchors/.style args={#1 and #2}{anchor1=#1, anchor2=#2}}%
+%
+\newcounter{tikzumlPackageClassNum}%
+\newcounter{tikzumlPackageSubPackageNum}%
+\newcounter{tikzumlRelationNum}%
+\setcounter{tikzumlRelationNum}{1}%
+\newcounter{tikzumlNoteNum}%
+\setcounter{tikzumlNoteNum}{1}%
+%
+\newcounter{pos}%
+\newcounter{posT}%
+\newcounter{posStereo}%
+%
+\newcounter{tikzumlPackageLevel}%
+\setcounter{tikzumlPackageLevel}{0}%
+%
+\newif\iftikzumlpackageSimpleStyle%
+\newif\iftikzumlclassSimpleStyle%
+\newif\iftikzumlclassCircleShape%
+\newif\iftikzumlpackageWithoutCoords%
+\newif\iftikzumlclassWithoutCoords%
+\newif\iftikzumlassocclassWithoutCoords%
+\newif\iftikzumlnoteWithoutCoords%
+%
+% define a uml package
+% arg : package name
+% optional : x, y: coordinates of the package
+% type: stereotype of the package
+% name: name of the package node
+% draw, fill, text: colors
+% style: to manage every default TikZ option
+% no coords: to tell that the package position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newenvironment{umlpackage}[2][]{%
+ \pgfkeys{/tikzuml/package/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, style/.style={},%
+ name/.initial=tikzumlEmpty, type/.initial=\tikzumlPackageDefaultType, draw/.initial=\tikzumlDefaultDrawColor,%
+ fill/.initial=\tikzumlPackageDefaultFillColor, text/.initial=\tikzumlDefaultTextColor,%
+ no coords/.is if=tikzumlpackageWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/package/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/package/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/package/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlpackage, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/package/.cd, #1}%
+ \pgfkeys{/tikzuml/package/.cd, x/.get=\tikzumlPackageXShift, y/.get=\tikzumlPackageYShift, name/.get=\tikzumlPackageName, type/.get=\tikzumlPackageTypeTmp,%
+ draw/.get=\tikzumlPackageDrawColor, fill/.get=\tikzumlPackageFillColor,%
+ text/.get=\tikzumlPackageTextColor%
+ }%
+ %
+
+ %
+ \ifthenelse{\equal{\tikzumlPackageTypeTmp}{tikzumlEmpty}}{%
+ \def\tikzumlPackageType{}%
+ }{%
+ \expandafter\def\expandafter\tikzumlPackageType\expandafter{$\ll$\tikzumlPackageTypeTmp$\gg$ \\}%
+ }%
+ %
+ \ifnum\thetikzumlPackageLevel>0%
+ \let\tikzumlPackage@nameold\tikzumlPackage@fitname%
+ \def\tikzumlPackage@name{#2}%
+ \begingroup%
+ \def\_{@}\edef\x{\endgroup%
+ \def\noexpand\tikzumlPackage@fitname{\tikzumlPackage@name}}\x%
+ \let\tikzumlPackage@parentold\tikzumlPackage@parent%
+ \edef\tikzumlPackage@parent{\tikzumlPackage@parentold @@\tikzumlPackage@nameold}%
+ \else%
+ \def\tikzumlPackage@parent{}%
+ \def\tikzumlPackage@name{#2}%
+ \begingroup%
+ \def\_{@}\edef\x{\endgroup%
+ \def\noexpand\tikzumlPackage@fitname{\tikzumlPackage@name}}\x%
+ \fi%
+ %
+ \let\tikzumlPackage@nodeNameold\tikzumlPackage@nodeName%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlPackage@nodeName{\tikzumlPackage@name}}\x%
+ %
+ \ifthenelse{\equal{\tikzumlPackageName}{tikzumlEmpty}}{}{%
+ \def\tikzumlPackage@nodeName{\tikzumlPackageName}%
+ }%
+ %
+ \StrSubstitute{\tikzumlPackage@nodeName}{.}{@POINT@}{\tikzumlPackage@nodeName}%
+ %
+ \expandafter\gdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{}%
+ %
+ \setcounter{tikzumlPackageClassNum}{0}%
+ \setcounter{tikzumlPackageSubPackageNum}{0}%
+ \stepcounter{tikzumlPackageLevel}%
+ %
+ \begin{scope}[xshift=\tikzumlPackageXShift cm, yshift=\tikzumlPackageYShift cm]%
+}{%
+ \addtocounter{tikzumlPackageLevel}{-1}%
+ \begin{pgfonlayer}{package\thetikzumlPackageLevel}%
+ %
+ % if contains no class, and not simple, one define a fictive node to enable the fit option
+ \ifnum\c@tikzumlPackageClassNum=0%
+ \ifnum\c@tikzumlPackageSubPackageNum=0%
+ \iftikzumlpackageWithoutCoords%
+ \node[inner sep=1.5ex, /tikzuml/package/style] (\tikzumlPackage@nodeName-root) {\phantom{\tikzumlPackage@nodeName}};%
+ \else%
+ \node[inner sep=1.5ex, /tikzuml/package/style] (\tikzumlPackage@nodeName-root) at (0,0) {\phantom{\tikzumlPackage@nodeName}};%
+ \fi%
+ \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{(\tikzumlPackage@nodeName-root)}%
+ \fi%
+ \fi%
+ %
+ \ifnum\c@tikzumlPackageLevel>0%
+ \def\tikzumlPackageFitTmp{\csname tikzumlPackageFit\tikzumlPackage@parent\endcsname}%
+ \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent\endcsname{\tikzumlPackageFitTmp (\tikzumlPackage@nodeName) (\tikzumlPackage@nodeName-caption)}%
+ \stepcounter{tikzumlPackageSubPackageNum}%
+ \fi%
+ %
+ \node[draw=\tikzumlPackageDrawColor, fill=\tikzumlPackageFillColor, text=\tikzumlPackageTextColor, font=\tikzumlDefaultFont, inner sep=1.5ex, /tikzuml/package/style, fit = \csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname] (\tikzumlPackage@nodeName) {};%
+ \node[draw=\tikzumlPackageDrawColor, fill=\tikzumlPackageFillColor, text=\tikzumlPackageTextColor, font=\tikzumlDefaultFont, minimum height=1.5em, outer ysep=-0.3, anchor=south west] (\tikzumlPackage@nodeName-caption) at (\tikzumlPackage@nodeName.north west) {\begin{tabular}{c} \tikzumlPackageType \textbf{\tikzumlPackage@name}\end{tabular}};%
+ \end{pgfonlayer}%
+ \end{scope}%
+}%
+%
+% shortcut to define an empty package
+\newcommand{\umlemptypackage}[2][]{\begin{umlpackage}[#1]{#2} \end{umlpackage}}%
+%
+% define a uml class
+% args : name of the class
+% attributes of the class
+% operations of the class
+% optional : x, y: coordinates of the class
+% width: of the class node
+% type: type of class (class, interface, typedef, enum)
+% tags: tagged values of class
+% template: template parameters
+% simple: if used, class is empty and drawn with a rectangle
+% circle: if used with simple, class is empty and drawn with a circle
+% draw, fill, fill template, and text: colors
+% style: to manage every default TikZ option
+% no coords: to tell that the class position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlclass}[4][]{%
+ \pgfkeys{/tikzuml/class/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlClassDefaultWidth, type/.initial=\tikzumlClassDefaultType,%
+ tags/.initial={}, style/.style={},%
+ template/.initial={}, name/.initial=tikzumlEmpty,%
+ draw/.initial=\tikzumlDefaultDrawColor,%
+ fill template/.initial=\tikzumlClassTemplateFillColorDefaultFillColor,%
+ fill/.initial=\tikzumlClassDefaultFillColor,%
+ text/.initial=\tikzumlDefaultTextColor,%
+ simple/.is if=tikzumlclassSimpleStyle, circle/.is if=tikzumlclassCircleShape, no coords/.is if=tikzumlclassWithoutCoords,%
+ simple=false, circle=false, no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/class/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/class/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/class/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlclass, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/class/.cd,#1}%
+ %
+ \iftikzumlclassSimpleStyle%
+ \iftikzumlclassCircleShape%
+ \pgfkeys{/tikzuml/class/.cd, width/.initial=\tikzumlSimpleInterfaceDefaultWidth}%
+ \fi%
+ \fi%
+ %
+ \pgfkeys{/tikzuml/class/.cd, x/.get=\tikzumlClassX, y/.get=\tikzumlClassY, width/.get=\tikzumlClassMinimumWidth,%
+ type/.get=\tikzumlClassTypeTmp, tags/.get=\tikzumlClassTagsTmp, template/.get=\tikzumlClassTemplateFillColorParam,%
+ name/.get=\tikzumlClassName,%
+ draw/.get=\tikzumlClassDrawColor, fill/.get=\tikzumlClassFillColor,%
+ text/.get=\tikzumlClassTextColor, fill template/.get=\tikzumlClassTemplateFillColor%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlClassTypeTmp}{class}\OR\equal{\tikzumlClassTypeTmp}{abstract}}{%
+ \def\tikzumlClassType{}%
+ }{%
+ \expandafter\def\expandafter\tikzumlClassType\expandafter{$\ll$\tikzumlClassTypeTmp$\gg$ \\}%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlClassTagsTmp}{}}{%
+ \def\tikzumlClassTags{}%
+ }{%
+ \def\tikzumlClassTags{\\ \{\tikzumlClassTagsTmp\}}%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlClassTemplateFillColorParam}{}}{%
+ \def\tikzumlClassVPadding{}%
+ \def\tikzumlClassHPadding{}%
+ }{%
+ \def\tikzumlClassVPadding{\vspace{0.1em} \\}%
+ \def\tikzumlClassHPadding{\hspace{0.5ex} $ $}%
+ }%
+ %
+ \def\tikzumlClassName{#2}%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlClassNodeName{\tikzumlClassName}}\x%
+ %
+ \ifthenelse{\equal{\tikzumlClassName}{tikzumlEmpty}}{}{%
+ \def\tikzumlClassNodeName{\tikzumlClassName}%
+ }%
+ %
+ \StrSubstitute{\tikzumlClassNodeName}{:}{@COLON@}[\tikzumlClassNodeName]%
+ \StrSubstitute{\tikzumlClassNodeName}{\_}{@UNDERSCORE@}[\tikzumlClassNodeName]%
+ %
+ \ifthenelse{\equal{\tikzumlClassTypeTmp}{abstract}}{%
+ \let\tikzumlClassNameOld\tikzumlClassName%
+ \def\tikzumlClassName{{\it \tikzumlClassNameOld}}%
+ }{}%
+ %
+ \def\tikzumlClassPos{\tikzumlClassX,\tikzumlClassY}%
+ \def\tikzumlClassAttributes{#3}%
+ \def\tikzumlClassOperations{#4}%
+ %
+ \iftikzumlclassSimpleStyle%
+ \iftikzumlclassWithoutCoords%
+ \iftikzumlclassCircleShape%
+ \node[tikzuml simpleinterface style, draw=\tikzumlClassDrawColor, fill=\tikzumlClassFillColor, text=\tikzumlClassTextColor, font=\tikzumlDefaultFont, minimum width=\tikzumlClassMinimumWidth, /tikzuml/class/style] (\tikzumlClassNodeName) {};%
+ \node[anchor=south] (\tikzumlClassNodeName-label) at (\tikzumlClassNodeName.north) {\begin{tabular}{c}\tikzumlClassVPadding \tikzumlClassType \tikzumlClassHPadding \textbf{\tikzumlClassName} \tikzumlClassHPadding \tikzumlClassTags \end{tabular}%
+ };%
+ \else%
+ \node[tikzuml simpleclass style, draw=\tikzumlClassDrawColor, fill=\tikzumlClassFillColor, text=\tikzumlClassTextColor, font=\tikzumlDefaultFont, minimum width=\tikzumlClassMinimumWidth, /tikzuml/class/style] (\tikzumlClassNodeName) {\begin{tabular}{c}\tikzumlClassVPadding \tikzumlClassType \tikzumlClassHPadding \textbf{\tikzumlClassName} \tikzumlClassHPadding \tikzumlClassTags \end{tabular}%
+ };%
+ \fi%
+ \else%
+ \iftikzumlclassCircleShape%
+ \node[tikzuml simpleinterface style, draw=\tikzumlClassDrawColor, fill=\tikzumlClassFillColor, text=\tikzumlClassTextColor, font=\tikzumlDefaultFont, minimum width=\tikzumlClassMinimumWidth, /tikzuml/class/style] (\tikzumlClassNodeName) at (\tikzumlClassPos) {};
+ \node[anchor=south] (\tikzumlClassNodeName-label) at (\tikzumlClassNodeName.north){\begin{tabular}{c}\tikzumlClassVPadding \tikzumlClassType \tikzumlClassHPadding \textbf{\tikzumlClassName} \tikzumlClassHPadding \tikzumlClassTags \end{tabular}%
+ };%
+ \else%
+ \node[tikzuml simpleclass style, draw=\tikzumlClassDrawColor, fill=\tikzumlClassFillColor, text=\tikzumlClassTextColor, font=\tikzumlDefaultFont, minimum width=\tikzumlClassMinimumWidth, /tikzuml/class/style] (\tikzumlClassNodeName) at (\tikzumlClassPos) {\begin{tabular}{c}\tikzumlClassVPadding \tikzumlClassType \tikzumlClassHPadding \textbf{\tikzumlClassName} \tikzumlClassHPadding \tikzumlClassTags \end{tabular}%
+ };%
+ \fi%
+ \fi%
+ \else%
+ \iftikzumlclassWithoutCoords%
+ \node[tikzuml class style, draw=\tikzumlClassDrawColor, fill=\tikzumlClassFillColor, text=\tikzumlClassTextColor, font=\tikzumlDefaultFont, minimum width=\tikzumlClassMinimumWidth, /tikzuml/class/style] (\tikzumlClassNodeName) {\begin{tabular}{c}\tikzumlClassVPadding \tikzumlClassType \tikzumlClassHPadding \textbf{\tikzumlClassName} \tikzumlClassHPadding \tikzumlClassTags \end{tabular}%
+ \nodepart{second}%
+ \begin{tabular}{l}%
+ \tikzumlClassAttributes%
+ \end{tabular}%
+ \nodepart{third}%
+ \begin{tabular}{l}%
+ \tikzumlClassOperations%
+ \end{tabular}%
+ };%
+ \else%
+ \node[tikzuml class style, draw=\tikzumlClassDrawColor, fill=\tikzumlClassFillColor, text=\tikzumlClassTextColor, font=\tikzumlDefaultFont, minimum width=\tikzumlClassMinimumWidth, /tikzuml/class/style] (\tikzumlClassNodeName) at (\tikzumlClassPos) {\begin{tabular}{c}\tikzumlClassVPadding \tikzumlClassType \tikzumlClassHPadding \textbf{\tikzumlClassName} \tikzumlClassHPadding \tikzumlClassTags \end{tabular}%
+ \nodepart{second}%
+ \begin{tabular}{l}%
+ \tikzumlClassAttributes%
+ \end{tabular}%
+ \nodepart{third}%
+ \begin{tabular}{l}%
+ \tikzumlClassOperations%
+ \end{tabular}%
+ };%
+ \fi%
+ \fi%
+ %
+ \ifthenelse{\equal{\tikzumlClassTemplateFillColorParam}{}}{}{%
+ \draw (\tikzumlClassNodeName.north east) node[tikzuml template style, name=\tikzumlClassNodeName-template, draw=\tikzumlClassDrawColor, fill=\tikzumlClassTemplateFillColor, text=\tikzumlClassTextColor, font=\tikzumlDefaultFont] {\tikzumlClassTemplateFillColorParam};%
+ }%
+ %
+ % add to fit
+ \ifnum\c@tikzumlPackageLevel>0%
+ \edef\tikzumlPackageFitOld{\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname}%
+ \ifthenelse{\equal{\tikzumlClassTemplateFillColorParam}{}}{%
+ \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{\tikzumlPackageFitOld (\tikzumlClassNodeName)}%
+ }{%
+ \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{\tikzumlPackageFitOld (\tikzumlClassNodeName) (\tikzumlClassNodeName-template)}%
+ }%
+ \stepcounter{tikzumlPackageClassNum}%
+ \fi%
+ \ifnum\c@tikzumlComponentLevel>0%
+ \def\tikzumlComponentFitTmp{\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname}%
+ \ifthenelse{\equal{\tikzumlClassTemplateFillColorParam}{}}{%
+ \expandafter\xdef\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname{\tikzumlComponentFitTmp (\tikzumlClassNodeName)}%
+ }{%
+ \expandafter\xdef\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname{\tikzumlComponentFitTmp (\tikzumlClassNodeName) (\tikzumlClassNodeName-template)}%
+ }%
+ \stepcounter{tikzumlComponentSubComponentNum}%
+ \fi%
+}%
+%
+% shortcuts for interface, enum and typedef environments
+\newcommand{\umlabstract}[4][]{%
+ \pgfkeys{/tikzuml/class/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{type}}{%
+ \errmessage{TIKZUML ERROR : in umlabstract, forbidden option type}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/class/.cd, #1}%
+ \umlclass[type=abstract,#1]{#2}{#3}{#4}%
+}%
+\newcommand{\umlinterface}[4][]{%
+ \pgfkeys{/tikzuml/class/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{type}}{%
+ \errmessage{TIKZUML ERROR : in umlinterface, forbidden option type}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/class/.cd, #1}%
+ \umlclass[type=interface,#1]{#2}{#3}{#4}%
+}%
+\newcommand{\umltypedef}[4][]{%
+ \pgfkeys{/tikzuml/class/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{type}}{%
+ \errmessage{TIKZUML ERROR : in umltypedef, forbidden option type}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/class/.cd, #1}%
+ \umlclass[type=typedef,#1]{#2}{#3}{#4}%
+}%
+\newcommand{\umlenum}[4][]{%
+ \pgfkeys{/tikzuml/class/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{type}}{%
+ \errmessage{TIKZUML ERROR : in umlenum, forbidden option type}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/class/.cd, #1}%
+ \umlclass[type=enum,#1]{#2}{#3}{#4}
+}%
+%
+% shortcut to define an empty class
+\newcommand{\umlemptyclass}[2][]{\umlclass[#1]{#2}{}{}}%
+\newcommand{\umlsimpleclass}[2][]{%
+ \pgfkeys{/tikzuml/class/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{simple}}{%
+ \errmessage{TIKZUML ERROR : in umlsimpleclass, forbidden option simple}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/class/.cd, #1}%
+ \umlemptyclass[simple, #1]{#2}%
+}%
+%
+\newcommand{\umlsimpleinterface}[2][]{%
+ \pgfkeys{/tikzuml/class/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{simple}}{%
+ \errmessage{TIKZUML ERROR : in umlsimpleinterface, forbidden option simple}%
+ }{%
+ \ifthenelse{\equal{\keyname}{circle}}{%
+ \errmessage{TIKZUML ERROR : in umlsimpleinterface, forbidden option circle}%
+ }{}%
+ }%
+ }%
+ }%
+ \pgfkeys{/tikzuml/class/.cd, #1}%
+ \umlsimpleclass[circle, #1]{#2}%
+}%
+% underline the text for static arg
+\newcommand{\umlstatic}[1]{\underline{#1}}%
+\newcommand{\umlvirt}[1]{\textit{#1}}%
+%
+% define node for n-ary association
+\newcommand{\umlNarynode}[2][]{%
+ \def\tikzumlNaryNodeAnchor{.north}
+ \def\tikzumlNaryNodeLabelPos{above}
+ \pgfkeys{/tikzuml/narynode/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlNaryNodeDefaultWidth, name/.initial=tikzumlEmpty,%
+ draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlClassDefaultFillColor,%
+ text/.initial=\tikzumlDefaultTextColor, style/.style={},%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}}{%
+ \def\tikzumlNaryNodeAnchor{.north}%
+ \def\tikzumlNaryNodeLabelPos{above}%
+ }{%
+ \ifthenelse{\equal{\keyname}{above left}}{%
+ \def\tikzumlNaryNodeAnchor{.north west}%
+ \def\tikzumlNaryNodeLabelPos{above left}%
+ }{%
+ \ifthenelse{\equal{\keyname}{left}}{%
+ \def\tikzumlNaryNodeAnchor{.west}%
+ \def\tikzumlNaryNodeLabelPos{left}%
+ }{%
+ \ifthenelse{\equal{\keyname}{below left}}{%
+ \def\tikzumlNaryNodeAnchor{.south west}%
+ \def\tikzumlNaryNodeLabelPos{below left}%
+ }{%
+ \ifthenelse{\equal{\keyname}{below}}{%
+ \def\tikzumlNaryNodeAnchor{.south}%
+ \def\tikzumlNaryNodeLabelPos{below}%
+ }{%
+ \ifthenelse{\equal{\keyname}{below right}}{%
+ \def\tikzumlNaryNodeAnchor{.south east}%
+ \def\tikzumlNaryNodeLabelPos{below right}%
+ }{%
+ \ifthenelse{\equal{\keyname}{right}}{%
+ \def\tikzumlNaryNodeAnchor{.east}%
+ \def\tikzumlNaryNodeLabelPos{right}%
+ }{%
+ \ifthenelse{\equal{\keyname}{above right}}{%
+ \def\tikzumlNaryNodeAnchor{.north east}%
+ \def\tikzumlNaryNodeLabelPos{above right}%
+ }{%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/narynode/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/narynode/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlNarynode, invalid option \keyname}%
+ }%
+ }%
+ }%
+ }%
+ }%
+ }%
+ }%
+ }%
+ }%
+ }%
+ \pgfkeys{/tikzuml/narynode/.cd,#1}%
+ \pgfkeys{/tikzuml/narynode/.cd, x/.get=\tikzumlNaryNodeX, y/.get=\tikzumlNaryNodeY, width/.get=\tikzumlNaryNodeMinimumWidth,%
+ name/.get=\tikzumlNaryNodeName,%
+ draw/.get=\tikzumlNaryNodeDrawColor, fill/.get=\tikzumlNaryNodeFillColor,%
+ text/.get=\tikzumlNaryNodeTextColor%
+ }%
+ %
+ \def\tikzumlNaryName{#2}%
+ %
+ \ifthenelse{\equal{\tikzumlNaryNodeName}{tikzumlEmpty}}{%
+ \edef\tikzumlNaryNodeName{\tikzumlNaryName}%
+ }{%
+ \edef\tikzumlNaryNodeName{\tikzumlNaryNodeName}%
+ }%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlNaryNode@nodeName{\tikzumlNaryNodeName}}\x%
+ %
+ \StrSubstitute{\tikzumlNaryNode@nodeName}{:}{@COLON@}[\tikzumlNaryNode@nodeName]%
+ \StrSubstitute{\tikzumlNaryNode@nodeName}{\_}{@UNDERSCORE@}[\tikzumlNaryNode@nodeName]%
+ %
+ \def\tikzumlNarynodePos{\tikzumlNaryNodeX,\tikzumlNaryNodeY}%
+ %
+ \node[tikzuml narynode style, draw=\tikzumlNaryNodeDrawColor, fill=\tikzumlNaryNodeFillColor, text=\tikzumlNaryNodeTextColor, font=\tikzumlDefaultFont, minimum width=\tikzumlNaryNodeMinimumWidth, minimum height=\tikzumlNaryNodeMinimumWidth, /tikzuml/narynode/style] (\tikzumlNaryNode@nodeName) at (\tikzumlNarynodePos) {};%
+ \draw (\tikzumlNaryNode@nodeName\tikzumlNaryNodeAnchor) node[\tikzumlNaryNodeLabelPos] {\tikzumlNaryName};%
+ %
+ % add to fit
+ \ifnum\c@tikzumlPackageLevel>0%
+ \edef\tikzumlPackageFitOld{\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{\tikzumlPackageFitOld (\tikzumlNaryNode@nodeName)}%
+ \stepcounter{tikzumlPackageClassNum}%
+ \fi%
+}%
+%
+\newdimen\tikzumlNestingSymbolSize%
+%
+% main command to define a relation between two classes
+% args : src class
+% dest class
+% optional : geometry: geometry of the line
+% weight: barycentric weight of the middle part when geometry is a 3-line
+% arm1, arm2: lengths of first or last part when geometry id a 3-line
+% arg1, arg2, arg: name of the src/dest/dest side class type attribute defined by the relation
+% mult1, mult2, mult: multiplicity of the src/dest/dest side class type attribute defined by the relation
+% pos1, pos2, pos: position of the src/dest/dest side class type attribute defined by the relation
+% align1, align2, align: text justification of the src/dest/dest side class type attribute defined by the relation
+% anchor1, anchor2: src/dest anchors on linked classes
+% angle1, angle2, loopsize: start angle, end angle and size of the relation (only if recursive)
+% stereo: stereotype of the relation
+% pos stereo: position of the stereotype on the relation
+% style: style of the relation (association, aggregation, composition, inherit, ...)
+% name: rootname used for naming nodes of the relation
+% recursive mode: type of recursive arrow (transition for state diagrams, or default)
+% recursive direction start/end: when transition relation, start/end directions of the relation arrow
+\newcommand{\umlrelation}[3][]{%
+ \pgfkeys{/tikzuml/relation/.cd, geometry/.initial=\tikzumlRelationDefaultGeometry, weight/.initial=\tikzumlRelationDefaultWeight,%
+ arm1/.initial=auto, arm2/.initial=auto,%
+ arg1/.initial={}, arg2/.initial={}, arg/.initial={},%
+ mult1/.initial={}, mult2/.initial={}, mult/.initial={},%
+ pos1/.initial=\tikzumlRelationDefaultPosO, pos2/.initial=\tikzumlRelationDefaultPosT, pos/.initial=tikzumlEmpty,%
+ align1/.initial={}, align2/.initial={}, align/.initial={},%
+ anchor1/.initial=tikzumlEmpty, anchor2/.initial=tikzumlEmpty,%
+ angle1/.initial=\tikzumlRelationDefaultAngleO, angle2/.initial=\tikzumlRelationDefaultAngleT, loopsize/.initial=\tikzumlRelationDefaultLoopSize,%
+ stereo/.initial={}, pos stereo/.initial=\tikzumlRelationDefaultPosStereo,%
+ style/.initial=->, style2/.style={}, name/.initial=relation-\thetikzumlRelationNum,%
+ recursive mode/.initial=default, recursive direction start/.initial=right,%
+ recursive direction end/.initial=bottom,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{with port}%
+ \OR\equal{\keyname}{interface}%
+ \OR\equal{\keyname}{padding}%
+ \OR\equal{\keyname}{width}%
+ \OR\equal{\keyname}{first arm}%
+ \OR\equal{\keyname}{second arm}%
+ \OR\equal{\keyname}{middle arm}%
+ \OR\equal{\keyname}{last arm}%
+ \OR\equal{\keyname}{distance}}{}{%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/relation/.cd, style2/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/relation/.cd, style2/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlrelation, invalid option \keyname}%
+ }%
+ }%
+ }%
+ \pgfkeys{/tikzuml/relation/.cd,#1}%
+ \pgfkeys{/tikzuml/relation/.cd, geometry/.get=\tikzumlRelationGeometry, weight/.get=\tikzumlRelationWeight,%
+ arm1/.get=\tikzumlRelationArmO, arm2/.get=\tikzumlRelationArmT,%
+ arg1/.get=\tikzumlRelationAttrName, arg2/.get=\tikzumlRelationAttrNameTO, arg/.get=\tikzumlRelationAttrNameTT,%
+ mult1/.get=\tikzumlRelationMultiplicity, mult2/.get=\tikzumlRelationMultiplicityTO, mult/.get=\tikzumlRelationMultiplicityTT,%
+ pos1/.get=\tikzumlRelationPosition, pos2/.get=\tikzumlRelationPositionTO, pos/.get=\tikzumlRelationPositionTT,%
+ align1/.get=\tikzumlRelationAlign, align2/.get=\tikzumlRelationAlignTO, align/.get=\tikzumlRelationAlignTT,%
+ anchor1/.get=\tikzumlRelationSrcAnchor, anchor2/.get=\tikzumlRelationDestAnchor,%
+ angle1/.get=\tikzumlRelationStartAngle, angle2/.get=\tikzumlRelationEndAngle, loopsize/.get=\tikzumlRelationLoopSize,%
+ stereo/.get=\tikzumlRelationStereoType, pos stereo/.get=\tikzumlRelationPositionStereotype,%
+ style/.get=\tikzumlRelationStyle, name/.get=\tikzumlRelationName,%
+ recursive mode/.get=\tikzumlRelationRecursiveMode,%
+ recursive direction start/.get=\tikzumlRelationRecursiveDirectionStart,%
+ recursive direction end/.get=\tikzumlRelationRecursiveDirectionEnd%
+ }%
+ %
+ \def\tikzumlSrcClassName{#2}%
+ %
+ % managing \_ in class names for node names
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlSrcClassNodeName{\tikzumlSrcClassName}}\x%
+ %
+ \StrSubstitute{\tikzumlSrcClassNodeName}{:}{@COLON@}[\tikzumlSrcClassNodeName]%
+ \StrSubstitute{\tikzumlSrcClassNodeName}{\_}{@UNDERSCORE@}[\tikzumlSrcClassNodeName]%
+ %
+ \def\tikzumlDestClassName{#3}%
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlDestClassNodeName{\tikzumlDestClassName}}\x%
+ %
+ \StrSubstitute{\tikzumlDestClassNodeName}{:}{@COLON@}[\tikzumlDestClassNodeName]%
+ \StrSubstitute{\tikzumlDestClassNodeName}{\_}{@UNDERSCORE@}[\tikzumlDestClassNodeName]%
+ %
+ % managing alias keys
+ \def\tikzumlRelationAttrNameT{\tikzumlRelationAttrNameTO\tikzumlRelationAttrNameTT}%
+ \def\tikzumlRelationMultiplicityT{\tikzumlRelationMultiplicityTO\tikzumlRelationMultiplicityTT}%
+ \def\tikzumlRelationAlignT{\tikzumlRelationAlignTO\tikzumlRelationAlignTT}%
+ \def\posAttrName{}%
+ \def\posMultiplicity{}%
+ \def\posAttrNameT{}%
+ \def\posMultiplicityT{}%
+ %
+ \ifthenelse{\equal{\tikzumlRelationPositionTT}{tikzumlEmpty}}{%
+ \def\tikzumlRelationPositionT{\tikzumlRelationPositionTO}%
+ }{%
+ \def\tikzumlRelationPositionT{\tikzumlRelationPositionTT}%
+ }%
+ %
+ \def\attrAlign{}%
+ \def\multAlign{}%
+ \def\attrAlignT{}%
+ \def\multAlignT{}%
+ %
+ \ifthenelse{\equal{\tikzumlRelationAlign}{left}}{%
+ \def\attrAlign{above right}%
+ \def\multAlign{below right}%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationAlign}{right}}{%
+ \def\attrAlign{above left}%
+ \def\multAlign{below left}%
+ }{}%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlRelationAlignT}{left}}{%
+ \def\attrAlignT{above right}%
+ \def\multAlignT{below right}%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationAlignT}{right}}{%
+ \def\attrAlignT{above left}%
+ \def\multAlignT{below left}%
+ }{}%
+ }%
+ %
+ % def stereotype
+ \ifthenelse{\equal{\tikzumlRelationStereoType}{}}{%
+ \def\stereotype{}%
+ }{%
+ \def\stereotype{$\ll$\tikzumlRelationStereoType$\gg$}%
+ }%
+
+ % def anchors macros
+ \ifthenelse{\equal{\tikzumlRelationSrcAnchor}{tikzumlEmpty}}{%
+ \def\tikzumlRelationSrcAnchor{}%
+ }{%
+ \let\tikzumlRelationSrcAnchorold\tikzumlRelationSrcAnchor%
+ \def\tikzumlRelationSrcAnchor{.\tikzumlRelationSrcAnchorold}%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlRelationDestAnchor}{tikzumlEmpty}}{%
+ \def\tikzumlRelationDestAnchor{}%
+ }{%
+ \let\tikzumlRelationDestAnchorold\tikzumlRelationDestAnchor%
+ \def\tikzumlRelationDestAnchor{.\tikzumlRelationDestAnchorold}%
+ }%
+ %
+ \setcounter{pos}{100*\real{\tikzumlRelationPosition}}%
+ \setcounter{posT}{100*\real{\tikzumlRelationPositionT}}%
+ \setcounter{posStereo}{100*\real{\tikzumlRelationPositionStereotype}}%
+ %
+ \pgfmathsetmacro{\tikzumlRelationWeightT}{1.0-\tikzumlRelationWeight}%
+ %
+ %\newcounter{tikzumlControlNodesNum}%
+ %\setcounter{tikzumlControlNodesNum}{0}%
+ %
+ \node[inner sep=0] (\tikzumlRelationName-middle) at (barycentric cs:\tikzumlSrcClassNodeName=\tikzumlRelationWeightT,\tikzumlDestClassNodeName=\tikzumlRelationWeight) {};%
+ %
+ % straight line
+ \ifthenelse{\equal{\tikzumlRelationGeometry}{--}}%
+ {%
+ \ifthenelse{\equal{\tikzumlSrcClassNodeName}{\tikzumlDestClassNodeName}}{%
+ \def\arcNum{1}%
+ \def\arcNumT{1}%
+ %
+ \ifthenelse{\equal{\tikzumlRelationRecursiveMode}{default}}{%
+ \xdef\tikzumlLastArc{node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity}%
+ node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT}%
+ node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \xdef\tikzumlPath{(\tikzumlSrcClassNodeName) edge[in=\tikzumlRelationEndAngle, out=\tikzumlRelationStartAngle, distance=\tikzumlRelationLoopSize] \tikzumlLastArc%
+ node[midway, inner sep=0, name=\tikzumlRelationName-1, anchor=center] {} (\tikzumlDestClassNodeName) }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveMode}{transition}}{%
+ \xdef\tikzumlFirstArc{node[midway, inner sep=0, name=\tikzumlRelationName-1, anchor=center] {}}%
+ \xdef\tikzumlMidOneArc{node[midway, inner sep=0, name=\tikzumlRelationName-3, anchor=center] {}}%
+ %
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{\tikzumlRelationRecursiveDirectionEnd}}{%
+ \def\numArcs{3}%
+ \xdef\tikzumlLastArc{node[midway, inner sep=0, name=\tikzumlRelationName-5, anchor=center] {}}%
+ %
+ \begin{pgfonlayer}{connections}%
+ \draw (\tikzumlSrcClassNodeName) edge[in=\tikzumlRelationEndAngle, out=\tikzumlRelationStartAngle, distance=\tikzumlRelationLoopSize, draw=none] %
+ node[midway, inner sep=0, name=\tikzumlRelationName-tmp, anchor=center] {} (\tikzumlDestClassNodeName);%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}\OR\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{%
+ \node[inner sep=0, name=\tikzumlRelationName-2] at (\tikzumlSrcClassNodeName.\tikzumlRelationStartAngle -| \tikzumlRelationName-tmp) {};%
+ \node[inner sep=0, name=\tikzumlRelationName-4] at (\tikzumlDestClassNodeName.\tikzumlRelationEndAngle -| \tikzumlRelationName-tmp) {};%
+ }{%
+ \node[inner sep=0, name=\tikzumlRelationName-2] at (\tikzumlSrcClassNodeName.\tikzumlRelationStartAngle |- \tikzumlRelationName-tmp) {};%
+ \node[inner sep=0, name=\tikzumlRelationName-4] at (\tikzumlDestClassNodeName.\tikzumlRelationEndAngle |- \tikzumlRelationName-tmp) {};%
+ }%
+ \end{pgfonlayer}%
+ }{%
+ \def\numArcs{4}%
+ \xdef\tikzumlMidTwoArc{node[midway, inner sep=0, name=\tikzumlRelationName-5, anchor=center] {}}%
+ \xdef\tikzumlLastArc{node[midway, inner sep=0, name=\tikzumlRelationName-7, anchor=center] {}}%
+ %
+ \begin{pgfonlayer}{connections}%
+ \draw (\tikzumlSrcClassNodeName) edge[in=\tikzumlRelationEndAngle, out=\tikzumlRelationStartAngle, distance=\tikzumlRelationLoopSize, draw=none] %
+ node[midway, name=\tikzumlRelationName-4, anchor=center] {} (\tikzumlDestClassNodeName);%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}\OR\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{%
+ \node[inner sep=0, name=\tikzumlRelationName-2] at (\tikzumlSrcClassNodeName.\tikzumlRelationStartAngle -| \tikzumlRelationName-4) {};%
+ \node[inner sep=0, name=\tikzumlRelationName-6] at (\tikzumlDestClassNodeName.\tikzumlRelationEndAngle |- \tikzumlRelationName-4) {};%
+ }{%
+ \node[inner sep=0, name=\tikzumlRelationName-2] at (\tikzumlSrcClassNodeName.\tikzumlRelationStartAngle |- \tikzumlRelationName-4) {};%
+ \node[inner sep=0, name=\tikzumlRelationName-6] at (\tikzumlDestClassNodeName.\tikzumlRelationEndAngle -| \tikzumlRelationName-4) {};%
+ }%
+ \end{pgfonlayer}%
+ }%
+ %
+ \ifnum\numArcs=4%
+ \ifnum\theposStereo>300%
+ \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-300)/100}%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype}}%
+ \else%
+ \ifnum\theposStereo<100%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype}}%
+ \else%
+ \ifnum\theposStereo>200%
+ \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-200)/100}%
+ \xdef\tikzumlMidTwoArc{\tikzumlMidTwoArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype}}%
+ \else%
+ \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-100)/100}%
+ \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype}}%
+ \fi%
+ \fi%
+ \fi%
+ %
+ \ifthenelse{\thepos=300\OR\thepos=100}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{bottom}}{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{bottom}}{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{top}}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{left}}{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{left}}{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }%
+ }%
+ }%
+ }%
+ }{}%
+ %
+ \ifthenelse{\thepos=200}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{bottom}}{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{bottom}}{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{top}}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{left}}{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{left}}{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }%
+ }%
+ }%
+ }%
+ }{}%
+ %
+ \ifnum\thepos>300%
+ \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-300)/100}%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity}%
+ }%
+ \else%
+ \ifnum\thepos<100%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity}%
+ }%
+ \else%
+ \ifnum\thepos>200%
+ \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-200)/100}%
+ \xdef\tikzumlMidTwoArc{\tikzumlMidTwoArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity}%
+ }%
+ \else%
+ \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-100)/100}%
+ \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity}%
+ }%
+ \fi%
+ \fi%
+ \fi%
+ %
+ \ifthenelse{\theposT=300\OR\theposT=100}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{bottom}}{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{bottom}}{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{top}}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{left}}{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{left}}{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }%
+ }%
+ }%
+ }%
+ }{}%
+ \ifthenelse{\theposT=200}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{bottom}}{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicity{below right}%
+ }{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{bottom}}{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{top}}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{left}}{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{left}}{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }%
+ }%
+ }%
+ }%
+ }{}%
+ %
+ \ifnum\theposT>300%
+ \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-300)/100}%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT}%
+ }%
+ \else%
+ \ifnum\theposT<100%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT}%
+ }%
+ \else%
+ \ifnum\theposT>200%
+ \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-200)/100}%
+ \xdef\tikzumlMidTwoArc{\tikzumlMidTwoArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT}%
+ }%
+ \else%
+ \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-100)/100}%
+ \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT}%
+ }%
+ \fi%
+ \fi%
+ \fi%
+ \else%
+ \ifnum\theposStereo>200%
+ \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-200)/100}%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \else%
+ \ifnum\theposStereo<100%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \else%
+ \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-100)/100}%
+ \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \fi%
+ \fi%
+ %
+ \ifthenelse{\thepos=100}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}}{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{top}}{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }%
+ }{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }%
+ }%
+ }%
+ }%
+ }{}%
+ %
+ \ifthenelse{\thepos=200}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}}{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{top}}{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }%
+ }{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }%
+ }%
+ }%
+ }%
+ }{}%
+ %
+ \ifnum\thepos>200%
+ \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-200)/100}%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity}%
+ }%
+ \else%
+ \ifnum\thepos<100%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity}%
+ }%
+ \else%
+ \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-100)/100}%
+ \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity}%
+ }%
+ \fi%
+ \fi%
+ %
+ \ifthenelse{\theposT=100}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}}{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{top}}{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }%
+ }{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }%
+ }%
+ }%
+ }%
+ }{}%
+ %
+ \ifthenelse{\theposT=200}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}}{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{top}}{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }%
+ }{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }%
+ }%
+ }%
+ }%
+ }{}%
+ %
+ \ifnum\theposT>200%
+ \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-200)/100}%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT}%
+ }%
+ \else%
+ \ifnum\theposT<100%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT}%
+ }%
+ \else%
+ \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-100)/100}%
+ \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT}%
+ }%
+ \fi%
+ \fi%
+ \fi%
+ %
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{\tikzumlRelationRecursiveDirectionEnd}}{%
+ \xdef\tikzumlPath{(\tikzumlSrcClassNodeName.\tikzumlRelationStartAngle) -- \tikzumlFirstArc (\tikzumlRelationName-2.center) -- \tikzumlMidOneArc (\tikzumlRelationName-4.center) -- \tikzumlLastArc (\tikzumlDestClassNodeName.\tikzumlRelationEndAngle) }%
+ \ifnum\thetikzumlStateLevel>0%
+ \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitTmp (\tikzumlRelationName-1) (\tikzumlRelationName-2) (\tikzumlRelationName-3) (\tikzumlRelationName-4) (\tikzumlRelationName-5)}%
+ \fi%
+ }{%
+ \xdef\tikzumlPath{(\tikzumlSrcClassNodeName.\tikzumlRelationStartAngle) -- \tikzumlFirstArc (\tikzumlRelationName-2.center) -- \tikzumlMidOneArc (\tikzumlRelationName-4.center) -- \tikzumlMidTwoArc (\tikzumlRelationName-6.center) -- \tikzumlLastArc (\tikzumlDestClassNodeName.\tikzumlRelationEndAngle) }%
+ \ifnum\thetikzumlStateLevel>0%
+ \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitTmp (\tikzumlRelationName-1) (\tikzumlRelationName-2) (\tikzumlRelationName-3) (\tikzumlRelationName-4) (\tikzumlRelationName-5) (\tikzumlRelationName-6) (\tikzumlRelationName-7)}%
+ \fi%
+ }%
+ }{}%
+ }%
+ }{%
+ \def\arcNum{1}%
+ \def\arcNumT{1}%
+ %
+ \node[inner sep=0] (\tikzumlRelationName-1) at (\tikzumlRelationName-middle) {};%
+ \xdef\tikzumlLastArc{node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity}%
+ node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT}%
+ node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \xdef\tikzumlPath{(\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor) -- \tikzumlLastArc (\tikzumlDestClassNodeName\tikzumlRelationDestAnchor) }%
+ \ifnum\thetikzumlStateLevel>0%
+ \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitTmp (\tikzumlRelationName-1) }%
+ \fi%
+ }%
+ }{%
+ % first vertical then horizontal line
+ \ifthenelse{\equal{\tikzumlRelationGeometry}{|-}}%
+ {%
+ %\setcounter{tikzumlControlNodesNum}{1}%
+ %
+ \def\tikzumlFirstArc{node[midway, inner sep=0, name=\tikzumlRelationName-1, anchor=center] {} }%
+ \def\tikzumlLastArc{node[midway, inner sep=0, name=\tikzumlRelationName-3, anchor=center]{} }%
+ %
+ \begin{pgfonlayer}{connections}%
+ \node[inner sep=0] (\tikzumlRelationName-2) at (\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor |- \tikzumlDestClassNodeName\tikzumlRelationDestAnchor) {};%
+ \end{pgfonlayer}%
+ %
+ \ifnum\theposStereo>100%
+ \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-100)/100}%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \else%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \fi%
+ %
+ \ifnum\thepos>100%
+ \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-100)/100}%
+ \def\arcNum{2}%
+ \else%
+ \def\arcNum{1}%
+ \ifnum\thepos=100%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ \fi%
+ \fi%
+ %
+ \ifnum\arcNum=1%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }%
+ \fi%
+ \ifnum\arcNum=2%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }%
+ \fi%
+ %
+ \ifnum\theposT>100%
+ \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-100)/100}%
+ \def\arcNumT{2}%
+ \else%
+ \def\arcNumT{1}%
+ \ifnum\theposT=100%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ \fi%
+ \fi%
+ %
+ \ifnum\arcNumT=1%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }%
+ \fi%
+ \ifnum\arcNumT=2%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }%
+ \fi%
+ %
+ \xdef\tikzumlPath{(\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor) -- \tikzumlFirstArc (\tikzumlRelationName-2.base) -- \tikzumlLastArc (\tikzumlDestClassNodeName\tikzumlRelationDestAnchor) }%
+ \ifnum\thetikzumlStateLevel>0%
+ \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitTmp (\tikzumlRelationName-1) (\tikzumlRelationName-2) (\tikzumlRelationName-3) }%
+ \fi%
+ }{%
+ % first horizontal then vertical line
+ \ifthenelse{\equal{\tikzumlRelationGeometry}{-|}}%
+ {%
+ %\setcounter{tikzumlControlNodesNum}{1}%
+ %
+ \def\tikzumlFirstArc{node[midway, inner sep=0, name=\tikzumlRelationName-1, anchor=center]{} }%
+ \def\tikzumlLastArc{node[midway, inner sep=0, name=\tikzumlRelationName-3, anchor=center] {} }%
+ %
+ \begin{pgfonlayer}{connections}%
+ \node[inner sep=0] (\tikzumlRelationName-2) at (\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor -| \tikzumlDestClassNodeName\tikzumlRelationDestAnchor) {};%
+ \end{pgfonlayer}%
+ %
+ \ifnum\theposStereo>100%
+ \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-100)/100}%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \else%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \fi%
+ %
+ \ifnum\thepos>100%
+ \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-100)/100}%
+ \def\arcNum{2}%
+ \else%
+ \def\arcNum{1}%
+ \ifnum\thepos=100%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ \fi%
+ \fi%
+ %
+ \ifnum\arcNum=1%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }%
+ \fi%
+ \ifnum\arcNum=2%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }%
+ \fi%
+ %
+ \ifnum\theposT>100%
+ \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-100)/100}%
+ \def\arcNumT{2}%
+ \else%
+ \def\arcNumT{1}%
+ \ifnum\theposT=100%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ \fi%
+ \fi%
+ %
+ \ifnum\arcNumT=1%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }%
+ \fi%
+ \ifnum\arcNumT=2%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }%
+ \fi%
+ %
+ \xdef\tikzumlPath{(\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor) -- \tikzumlFirstArc (\tikzumlRelationName-2.base) -- \tikzumlLastArc (\tikzumlDestClassNodeName\tikzumlRelationDestAnchor) }%
+ \ifnum\thetikzumlStateLevel>0%
+ \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitTmp (\tikzumlRelationName-1) (\tikzumlRelationName-2) (\tikzumlRelationName-3) }%
+ \fi%
+ }{%
+ % first vertical, then horizontal, finally vertical line
+ \ifthenelse{\equal{\tikzumlRelationGeometry}{|-|}}%
+ {%
+ %\setcounter{tikzumlControlNodesNum}{2}%
+ %
+ \def\tikzumlFirstArc{node[midway, inner sep=0, name=\tikzumlRelationName-1, anchor=center] {} }%
+ \def\tikzumlLastArc{node[midway, inner sep=0, name=\tikzumlRelationName-5, anchor=center] {} }%
+ \def\tikzumlMidOneArc{ }%
+ %
+ \begin{pgfonlayer}{connections}%
+ %
+ \ifthenelse{\equal{\tikzumlRelationArmO}{auto}}{%
+ \ifthenelse{\equal{\tikzumlRelationArmT}{auto}}{%
+ \node[inner sep=0] (\tikzumlRelationName-3) at (\tikzumlRelationName-middle) {};%
+ \node[inner sep=0] (\tikzumlRelationName-2) at (\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor |- \tikzumlRelationName-3) {};%
+ \node[inner sep=0] (\tikzumlRelationName-4) at (\tikzumlRelationName-3 -| \tikzumlDestClassNodeName\tikzumlRelationDestAnchor) {};%
+ }{%
+ \draw (\tikzumlDestClassNodeName\tikzumlRelationDestAnchor)+(0,\tikzumlRelationArmT) node[inner sep=0, name=\tikzumlRelationName-4] {};%
+ \node[inner sep=0] (\tikzumlRelationName-2) at (\tikzumlRelationName-4 -| \tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor) {};%
+ \node[inner sep=0] (\tikzumlRelationName-3) at (barycentric cs:\tikzumlRelationName-2=0.5,\tikzumlRelationName-4=0.5) {};%
+ }%
+ }{%
+ \draw (\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor)+(0,\tikzumlRelationArmO) node[inner sep=0, name=\tikzumlRelationName-2] {};%
+ \node[inner sep=0] (\tikzumlRelationName-4) at (\tikzumlRelationName-2 -| \tikzumlDestClassNodeName\tikzumlRelationDestAnchor) {};%
+ \node[inner sep=0] (\tikzumlRelationName-3) at (barycentric cs:\tikzumlRelationName-2=0.5,\tikzumlRelationName-4=0.5) {};%
+ }%
+ \end{pgfonlayer}%
+ %
+ \ifnum\theposStereo>200%
+ \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-200)/100}%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \else%
+ \ifnum\theposStereo<100%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \else%
+ \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-100)/100}%
+ \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \fi%
+ \fi%
+ %
+ \ifthenelse{\thepos=200\OR\thepos=100}{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }{}%
+ %
+ \ifthenelse{\thepos>200}{%
+ \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-200)/100}%
+ \def\arcNum{3}%
+ }{%
+ \ifthenelse{\thepos<100}{%
+ \def\arcNum{1}%
+ }{%
+ \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-100)/100}%
+ \def\arcNum{2}%
+ }%
+ }%
+ %
+ \ifnum\arcNum=1%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }%
+ \fi%
+ \ifnum\arcNum=2%
+ \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }%
+ \fi%
+ \ifnum\arcNum=3%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }%
+ \fi%
+ %
+ \ifthenelse{\theposT=200\OR\theposT=100}{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }{}%
+ %
+ \ifthenelse{\theposT>200}{%
+ \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-200)/100}%
+ \def\arcNumT{3}%
+ }{%
+ \ifthenelse{\theposT<100}{%
+ \def\arcNumT{1}%
+ }{%
+ \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-100)/100}%
+ \def\arcNumT{2}%
+ }%
+ }%
+ %
+ \ifnum\arcNumT=1%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }%
+ \fi%
+ \ifnum\arcNumT=2%
+ \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }%
+ \fi%
+ \ifnum\arcNumT=3%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }%
+ \fi%
+ %
+ \xdef\tikzumlPath{(\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor) -- \tikzumlFirstArc (\tikzumlRelationName-2.base) -- \tikzumlMidOneArc (\tikzumlRelationName-4.base) -- \tikzumlLastArc (\tikzumlDestClassNodeName\tikzumlRelationDestAnchor) }%
+ \ifnum\thetikzumlStateLevel>0%
+ \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitTmp (\tikzumlRelationName-1) (\tikzumlRelationName-2) (\tikzumlRelationName-3) (\tikzumlRelationName-4) (\tikzumlRelationName-5) }%
+ \fi%
+ }{%
+ % first horizontal, then vertical, finally horizontal line
+ \ifthenelse{\equal{\tikzumlRelationGeometry}{-|-}}%
+ {%
+ %\setcounter{tikzumlControlNodesNum}{2}%
+ %
+ \def\tikzumlFirstArc{node[midway, inner sep=0, name=\tikzumlRelationName-1, anchor=center] {} }%
+ \def\tikzumlLastArc{node[midway, inner sep=0, name=\tikzumlRelationName-5, anchor=center] {} }%
+ \def\tikzumlMidOneArc{}%
+ %
+ \begin{pgfonlayer}{connections}%
+ %
+ \ifthenelse{\equal{\tikzumlRelationArmO}{auto}}{%
+ \ifthenelse{\equal{\tikzumlRelationArmT}{auto}}{%
+ \node[inner sep=0] (\tikzumlRelationName-3) at (\tikzumlRelationName-middle) {};%
+ \node[inner sep=0] (\tikzumlRelationName-2) at (\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor -| \tikzumlRelationName-3) {};%
+ \node[inner sep=0] (\tikzumlRelationName-4) at (\tikzumlRelationName-3 |- \tikzumlDestClassNodeName\tikzumlRelationDestAnchor) {};%
+ }{%
+ \draw (\tikzumlDestClassNodeName\tikzumlRelationDestAnchor)+(\tikzumlRelationArmT,0) node[inner sep=0, name=\tikzumlRelationName-4] {};%
+ \node[inner sep=0] (\tikzumlRelationName-2) at (\tikzumlRelationName-4 |- \tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor) {};%
+ \node[inner sep=0] (\tikzumlRelationName-3) at (barycentric cs:\tikzumlRelationName-2=0.5,\tikzumlRelationName-4=0.5) {};%
+ }%
+ }{%
+ \draw (\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor)+(\tikzumlRelationArmO,0) node[inner sep=0, name=\tikzumlRelationName-2] {};%
+ \node[inner sep=0] (\tikzumlRelationName-4) at (\tikzumlRelationName-2 |- \tikzumlDestClassNodeName\tikzumlRelationDestAnchor) {};%
+ \node[inner sep=0] (\tikzumlRelationName-3) at (barycentric cs:\tikzumlRelationName-2=0.5,\tikzumlRelationName-4=0.5) {};%
+ }%
+ \end{pgfonlayer}%
+ %
+ \ifnum\theposStereo>200%
+ \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-200)/100}%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \else%
+ \ifnum\theposStereo<100%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \else%
+ \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-100)/100}%
+ \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \fi%
+ \fi%
+ %
+ \ifthenelse{\thepos=200\OR\thepos=100}{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }{}%
+ %
+ \ifthenelse{\thepos>200}{%
+ \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-200)/100}%
+ \def\arcNum{3}%
+ }{%
+ \ifthenelse{\thepos<100}{%
+ \def\arcNum{1}%
+ }{%
+ \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-100)/100}%
+ \def\arcNum{2}%
+ }%
+ }%
+ %
+ \ifnum\arcNum=1%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }%
+ \fi%
+ \ifnum\arcNum=2%
+ \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }%
+ \fi%
+ \ifnum\arcNum=3%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }%
+ \fi%
+ %
+ \ifthenelse{\theposT=200\OR\theposT=100}{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }{}%
+ %
+ \ifthenelse{\theposT>200}{%
+ \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-200)/100}%
+ \def\arcNumT{3}%
+ }{%
+ \ifthenelse{\theposT<100}{%
+ \def\arcNumT{1}%
+ }{%
+ \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-100)/100}%
+ \def\arcNumT{2}%
+ }%
+ }%
+ %
+ \ifnum\arcNumT=1%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }%
+ \fi%
+ \ifnum\arcNumT=2%
+ \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }%
+ \fi%
+ \ifnum\arcNumT=3%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }%
+ \fi%
+ %
+ \xdef\tikzumlPath{(\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor) -- \tikzumlFirstArc (\tikzumlRelationName-2.base) -- \tikzumlMidOneArc (\tikzumlRelationName-4.base) -- \tikzumlLastArc (\tikzumlDestClassNodeName\tikzumlRelationDestAnchor) }%
+ \ifnum\thetikzumlStateLevel>0%
+ \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitTmp (\tikzumlRelationName-1) (\tikzumlRelationName-2) (\tikzumlRelationName-3) (\tikzumlRelationName-4) (\tikzumlRelationName-5) }%
+ \fi%
+ }{%
+ \errmessage{TIKZUML ERROR : Unknown geometry value !!! It should be in the following list : --, |-, -|, |-|, -|-}%
+ }%
+ }%
+ }%
+ }%
+ }%
+ %
+ \begin{pgfonlayer}{connections}%
+ \ifthenelse{\equal{\tikzumlRelationStyle}{tikzuml nesting style}}{%
+ \pgfarrowsdeclare{nested}{nested}{...}
+ {
+ \tikzumlNestingSymbolSize=0.2pt%
+ \advance\tikzumlNestingSymbolSize by .5\pgflinewidth%
+ \pgfsetdash{}{0pt} % do not dash
+ \pgfsetroundjoin % fix join
+ \pgfsetroundcap % fix cap
+ \pgfpathmoveto{\pgfpoint{-16*\tikzumlNestingSymbolSize}{0pt}}%
+ \pgfpatharc{180}{90}{8*\tikzumlNestingSymbolSize}%
+ \pgfpatharc{90}{0}{8*\tikzumlNestingSymbolSize}%
+ \pgfpatharc{0}{-90}{8*\tikzumlNestingSymbolSize}%
+ \pgfpatharc{-90}{-180}{8*\tikzumlNestingSymbolSize}%
+ \pgfpathmoveto{\pgfpoint{-8*\tikzumlNestingSymbolSize}{8*\tikzumlNestingSymbolSize}}%
+ \pgfpathlineto{\pgfpoint{-8*\tikzumlNestingSymbolSize}{-8*\tikzumlNestingSymbolSize}}%
+ \pgfusepathqstroke%
+ }%
+ \draw[auto, nested-, font=\tikzumlDefaultFont, \tikzumlRelationStyle, /tikzuml/relation/style2] \tikzumlPath ;%
+ }{
+ \draw[auto, font=\tikzumlDefaultFont, \tikzumlRelationStyle, /tikzuml/relation/style2] \tikzumlPath ;%
+ }
+ \end{pgfonlayer}%
+ %
+ \stepcounter{tikzumlRelationNum}%
+}%
+%
+% shortcuts of \umlrelation
+\newcommand{\umlHVrelation}[3][]{%
+ \pgfkeys{/tikzuml/HVrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlHVrelation, forbidden option geometry}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/HVrelation/.cd, #1}%
+ \umlrelation[geometry=-|, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlVHrelation}[3][]{%
+ \pgfkeys{/tikzuml/VHrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlVHrelation, forbidden option geometry}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/VHrelation/.cd, #1}%
+ \umlrelation[geometry=|-, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlHVHrelation}[3][]{%
+ \pgfkeys{/tikzuml/HVHrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlHVHrelation, forbidden option geometry}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/HVHrelation/.cd, #1}%
+ \umlrelation[geometry=-|-, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlVHVrelation}[3][]{%
+ \pgfkeys{/tikzuml/VHVrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlVHVrelation, forbidden option geometry}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/VHVrelation/.cd, #1}%
+ \umlrelation[geometry=|-|, #1]{#2}{#3}%
+}%
+%
+%
+% shortcuts for relations
+\newcommand{\umlinherit}[3][]{\umlrelation[style={tikzuml inherit style}, #1]{#2}{#3}}%
+\newcommand{\umlimpl}[3][]{\umlrelation[style={tikzuml implements style}, #1]{#2}{#3}}%
+\newcommand{\umlreal}[3][]{\umlrelation[style={tikzuml implements style}, #1]{#2}{#3}}%
+\newcommand{\umlassoc}[3][]{\umlrelation[style={tikzuml association style}, #1]{#2}{#3}}%
+\newcommand{\umlbiassoc}[3][]{\umlrelation[style={tikzuml bidirectional association style}, #1]{#2}{#3}}%
+\newcommand{\umluniassoc}[3][]{\umlrelation[style={tikzuml unidirectional association style}, #1]{#2}{#3}}%
+\newcommand{\umlaggreg}[3][]{\umlrelation[style={tikzuml aggregation style}, #1]{#2}{#3}}%
+\newcommand{\umluniaggreg}[3][]{\umlrelation[style={tikzuml unidirectional aggregation style}, #1]{#2}{#3}}%
+\newcommand{\umlcompo}[3][]{\umlrelation[style={tikzuml composition style}, #1]{#2}{#3}}%
+\newcommand{\umlunicompo}[3][]{\umlrelation[style={tikzuml unidirectional composition style}, #1]{#2}{#3}}%
+\newcommand{\umlimport}[3][]{\umlrelation[style={tikzuml import style}, #1]{#2}{#3}}%
+\newcommand{\umlnest}[3][]{\umlrelation[style={tikzuml nesting style}, #1]{#2}{#3}}%
+\newcommand{\umldep}[3][]{\umlrelation[style={tikzuml dependency style}, #1]{#2}{#3}}%
+\newcommand{\umlfriend}[3][]{%
+ \pgfkeys{/tikzuml/friendrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlfriend, forbidden option stereo}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/friendrelation/.cd, #1}%
+ \umlrelation[stereo=friend, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlHVinherit}[3][]{\umlHVrelation[style={tikzuml inherit style}, #1]{#2}{#3}}%
+\newcommand{\umlHVimpl}[3][]{\umlHVrelation[style={tikzuml implements style}, #1]{#2}{#3}}%
+\newcommand{\umlHVreal}[3][]{\umlHVrelation[style={tikzuml implements style}, #1]{#2}{#3}}%
+\newcommand{\umlHVassoc}[3][]{\umlHVrelation[style={tikzuml association style}, #1]{#2}{#3}}%
+\newcommand{\umlHVuniassoc}[3][]{\umlHVrelation[style={tikzuml unidirectional association style}, #1]{#2}{#3}}%
+\newcommand{\umlHVaggreg}[3][]{\umlHVrelation[style={tikzuml aggregation style}, #1]{#2}{#3}}%
+\newcommand{\umlHVuniaggreg}[3][]{\umlHVrelation[style={tikzuml unidirectional aggregation style}, #1]{#2}{#3}}%
+\newcommand{\umlHVcompo}[3][]{\umlHVrelation[style={tikzuml composition style}, #1]{#2}{#3}}%
+\newcommand{\umlHVunicompo}[3][]{\umlHVrelation[style={tikzuml unidirectional composition style}, #1]{#2}{#3}}%
+\newcommand{\umlHVimport}[3][]{\umlHVrelation[style={tikzuml import style}, #1]{#2}{#3}}%
+\newcommand{\umlHVnest}[3][]{\umlHVrelation[style={tikzuml nesting style}, #1]{#2}{#3}}%
+\newcommand{\umlHVdep}[3][]{\umlHVrelation[style={tikzuml dependency style}, #1]{#2}{#3}}%
+\newcommand{\umlHVfriend}[3][]{%
+ \pgfkeys{/tikzuml/friendrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlHVfriend, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlHVfriend, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/friendrelation/.cd, #1}%
+ \umlrelation[geometry=-|, stereo=friend, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlVHinherit}[3][]{\umlVHrelation[style={tikzuml inherit style}, #1]{#2}{#3}}%
+\newcommand{\umlVHimpl}[3][]{\umlVHrelation[style={tikzuml implements style}, #1]{#2}{#3}}%
+\newcommand{\umlVHreal}[3][]{\umlVHrelation[style={tikzuml implements style}, #1]{#2}{#3}}%
+\newcommand{\umlVHassoc}[3][]{\umlVHrelation[style={tikzuml association style}, #1]{#2}{#3}}%
+\newcommand{\umlVHuniassoc}[3][]{\umlVHrelation[style={tikzuml unidirectional association style}, #1]{#2}{#3}}%
+\newcommand{\umlVHaggreg}[3][]{\umlVHrelation[style={tikzuml aggregation style}, #1]{#2}{#3}}%
+\newcommand{\umlVHuniaggreg}[3][]{\umlVHrelation[style={tikzuml unidirectional aggregation style}, #1]{#2}{#3}}%
+\newcommand{\umlVHcompo}[3][]{\umlVHrelation[style={tikzuml composition style}, #1]{#2}{#3}}%
+\newcommand{\umlVHunicompo}[3][]{\umlVHrelation[style={tikzuml unidirectional composition style}, #1]{#2}{#3}}%
+\newcommand{\umlVHimport}[3][]{\umlVHrelation[style={tikzuml import style}, #1]{#2}{#3}}%
+\newcommand{\umlVHnest}[3][]{\umlVHrelation[style={tikzuml nesting style}, #1]{#2}{#3}}%
+\newcommand{\umlVHdep}[3][]{\umlVHrelation[style={tikzuml dependency style}, #1]{#2}{#3}}%
+\newcommand{\umlVHfriend}[3][]{%
+ \pgfkeys{/tikzuml/friendrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlVHfriend, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlVHfriend, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/friendrelation/.cd, #1}%
+ \umlrelation[geometry=|-, stereo=friend, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlHVHinherit}[3][]{\umlHVHrelation[style={tikzuml inherit style}, #1]{#2}{#3}}%
+\newcommand{\umlHVHimpl}[3][]{\umlHVHrelation[style={tikzuml implements style}, #1]{#2}{#3}}%
+\newcommand{\umlHVHreal}[3][]{\umlHVHrelation[style={tikzuml implements style}, #1]{#2}{#3}}%
+\newcommand{\umlHVHassoc}[3][]{\umlHVHrelation[style={tikzuml association style}, #1]{#2}{#3}}%
+\newcommand{\umlHVHuniassoc}[3][]{\umlHVHrelation[style={tikzuml unidirectional association style}, #1]{#2}{#3}}%
+\newcommand{\umlHVHaggreg}[3][]{\umlHVHrelation[style={tikzuml aggregation style}, #1]{#2}{#3}}%
+\newcommand{\umlHVHuniaggreg}[3][]{\umlHVHrelation[style={tikzuml unidirectional aggregation style}, #1]{#2}{#3}}%
+\newcommand{\umlHVHcompo}[3][]{\umlHVHrelation[style={tikzuml composition style}, #1]{#2}{#3}}%
+\newcommand{\umlHVHunicompo}[3][]{\umlHVHrelation[style={tikzuml unidirectional composition style}, #1]{#2}{#3}}%
+\newcommand{\umlHVHimport}[3][]{\umlHVHrelation[style={tikzuml import style}, #1]{#2}{#3}}%
+\newcommand{\umlHVHnest}[3][]{\umlHVHrelation[style={tikzuml nesting style}, #1]{#2}{#3}}%
+\newcommand{\umlHVHdep}[3][]{\umlHVHrelation[style={tikzuml dependency style}, #1]{#2}{#3}}%
+\newcommand{\umlHVHfriend}[3][]{%
+ \pgfkeys{/tikzuml/friendrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlHVHfriend, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlHVHfriend, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/friendrelation/.cd, #1}%
+ \umlrelation[geometry=-|-, stereo=friend, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlVHVinherit}[3][]{\umlVHVrelation[style={tikzuml inherit style}, #1]{#2}{#3}}%
+\newcommand{\umlVHVimpl}[3][]{\umlVHVrelation[style={tikzuml implements style}, #1]{#2}{#3}}%
+\newcommand{\umlVHVreal}[3][]{\umlVHVrelation[style={tikzuml implements style}, #1]{#2}{#3}}%
+\newcommand{\umlVHVassoc}[3][]{\umlVHVrelation[style={tikzuml association style}, #1]{#2}{#3}}%
+\newcommand{\umlVHVuniassoc}[3][]{\umlVHVrelation[style={tikzuml unidirectional association style}, #1]{#2}{#3}}%
+\newcommand{\umlVHVaggreg}[3][]{\umlVHVrelation[style={tikzuml aggregation style}, #1]{#2}{#3}}%
+\newcommand{\umlVHVuniaggreg}[3][]{\umlVHVrelation[style={tikzuml unidirectional aggregation style}, #1]{#2}{#3}}%
+\newcommand{\umlVHVcompo}[3][]{\umlVHVrelation[style={tikzuml composition style}, #1]{#2}{#3}}%
+\newcommand{\umlVHVunicompo}[3][]{\umlVHVrelation[style={tikzuml unidirectional composition style}, #1]{#2}{#3}}%
+\newcommand{\umlVHVimport}[3][]{\umlVHVrelation[style={tikzuml import style}, #1]{#2}{#3}}%
+\newcommand{\umlVHVnest}[3][]{\umlVHVrelation[style={tikzuml nesting style}, #1]{#2}{#3}}%
+\newcommand{\umlVHVdep}[3][]{\umlVHVrelation[style={tikzuml dependency style}, #1]{#2}{#3}}%
+\newcommand{\umlVHVfriend}[3][]{%
+ \pgfkeys{/tikzuml/friendrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlVHVfriend, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlVHVfriend, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/friendrelation/.cd, #1}%
+ \umlrelation[geometry=|-|, stereo=friend, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+%
+% define a node
+\newcommand{\umlnode}[2]{%
+ \node (#2) at (#1) {};%
+}%
+%
+% main command to define a relation between two classes through a control node
+% args : src class
+% control node
+% dest class
+% optional : arg1, arg2, arg: name of the src/dest/dest side class type attribute defined by the relation
+% mult1, mult2, mult: multiplicity of the src/dest/dest side class type attribute defined by the relation
+% pos1, pos2, pos: position of the src/dest/dest side class type attribute defined by the relation
+% align1, align2, align: text justification of the src/dest/dest side class type attribute defined by the relation
+% anchor1, anchor2: src/dest anchors on linked classes
+% stereo: stereotype of the relation
+% pos stereo: position of the stereotype on the relation
+% style: style of the relation (association, aggregation, composition, inherit, ...)
+% name: rootname used for naming nodes of the relation
+\newcommand{\umlCNrelation}[4][]{%
+ \pgfkeys{/tikzuml/relation/.cd, arg1/.initial={}, arg2/.initial={}, arg/.initial={},%
+ mult1/.initial={}, mult2/.initial={}, mult/.initial={},%
+ pos1/.initial=0.2, pos2/.initial=0.8, pos/.initial=tikzumlEmpty,%
+ align1/.initial={}, align2/.initial={}, align/.initial={},%
+ anchor1/.initial=tikzumlEmpty, anchor2/.initial=tikzumlEmpty,%
+ stereo/.initial={}, pos stereo/.initial=1,%
+ style/.initial=->, name/.initial=relation-\thetikzumlRelationNum,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \errmessage{TIKZUML ERROR : in umlCNrelation, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/relation/.cd,#1}%
+ \pgfkeys{/tikzuml/relation/.cd, arg1/.get=\tikzumlCNRelationAttrName, arg2/.get=\tikzumlCNRelationAttrNameTO, arg/.get=\tikzumlCNRelationAttrNameTT,%
+ mult1/.get=\tikzumlCNRelationMultiplicity, mult2/.get=\tikzumlCNRelationMultiplicityTO, mult/.get=\tikzumlCNRelationMultiplicityTT,%
+ pos1/.get=\tikzumlCNRelationPosition, pos2/.get=\tikzumlCNRelationPositionTO, pos/.get=\tikzumlCNRelationPositionTT,%
+ align1/.get=\tikzumlCNRelationAlign, align2/.get=\tikzumlCNRelationAlignTO, align/.get=\tikzumlCNRelationAlignTT,%
+ anchor1/.get=\tikzumlCNRelationSrcAnchor, anchor2/.get=\tikzumlCNRelationDestAnchor,%
+ stereo/.get=\tikzumlCNRelationStereoType, pos stereo/.get=\tikzumlCNRelationPositionStereotype,%
+ style/.get=\tikzumlCNRelationStyle, name/.get=\tikzumlCNRelationName%
+ }%
+ %
+ % managing \_ in class names for node names
+ \def\tikzumlSrcClassName{#2}%
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlSrcClassNodeName{\tikzumlSrcClassName}}\x%
+ %
+ \StrSubstitute{\tikzumlSrcClassNodeName}{:}{@COLON@}[\tikzumlSrcClassNodeName]%
+ \StrSubstitute{\tikzumlSrcClassNodeName}{\_}{@UNDERSCORE@}[\tikzumlSrcClassNodeName]%
+ %
+ \def\tikzumlDestClassName{#4}%
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlDestClassNodeName{\tikzumlDestClassName}}\x%
+ %
+ \StrSubstitute{\tikzumlDestClassNodeName}{:}{@COLON@}[\tikzumlDestClassNodeName]%
+ \StrSubstitute{\tikzumlDestClassNodeName}{\_}{@UNDERSCORE@}[\tikzumlDestClassNodeName]%
+ %
+ % managing alias keys
+ \def\tikzumlCNRelationAttrNameT{\tikzumlCNRelationAttrNameTO\tikzumlCNRelationAttrNameTT}%
+ \def\tikzumlCNRelationMultiplicityT{\tikzumlCNRelationMultiplicityTO\tikzumlCNRelationMultiplicityTT}%
+ \def\tikzumlCNRelationAlignT{\tikzumlCNRelationAlignTO\tikzumlCNRelationAlignTT}%
+ \def\orientationT{\orientationTO\orientationTT}%
+ %
+ \ifthenelse{\equal{\tikzumlCNRelationPositionTT}{tikzumlEmpty}}{%
+ \def\tikzumlCNRelationPositionT{\tikzumlCNRelationPositionTO}%
+ }{%
+ \def\tikzumlCNRelationPositionT{\tikzumlCNRelationPositionTT}%
+ }%
+ %
+ \def\attrAlign{}%
+ \def\multAlign{}%
+ \def\attrAlignT{}%
+ \def\multAlignT{}%
+ %
+ \ifthenelse{\equal{\tikzumlCNRelationAlign}{left}}{%
+ \def\attrAlign{above right}%
+ \def\multAlign{below right}%
+ }{%
+ \ifthenelse{\equal{\tikzumlCNRelationAlign}{right}}{%
+ \def\attrAlign{above left}%
+ \def\multAlign{below left}%
+ }{}%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlCNRelationAlignT}{left}}{%
+ \def\attrAlignT{above right}%
+ \def\multAlignT{below right}%
+ }{%
+ \ifthenelse{\equal{\tikzumlCNRelationAlignT}{right}}{%
+ \def\attrAlignT{above left}%
+ \def\multAlignT{below left}%
+ }{}%
+ }%
+ %
+ % def stereotype
+ \ifthenelse{\equal{\tikzumlCNRelationStereoType}{}}{%
+ \def\stereotype{}%
+ }{%
+ \def\stereotype{$\ll$\tikzumlCNRelationStereoType$\gg$}%
+ }%
+ %
+ % def anchors macros
+ \ifthenelse{\equal{\tikzumlCNRelationSrcAnchor}{tikzumlEmpty}}{%
+ \def\tikzumlCNRelationSrcAnchor{}%
+ }{%
+ \let\tikzumlCNRelationSrcAnchorold\tikzumlCNRelationSrcAnchor%
+ \def\tikzumlCNRelationSrcAnchor{.\tikzumlCNRelationSrcAnchorold}%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlCNRelationDestAnchor}{tikzumlEmpty}}{%
+ \def\tikzumlCNRelationDestAnchor{}%
+ }{%
+ \let\tikzumlCNRelationDestAnchorold\tikzumlCNRelationDestAnchor%
+ \def\tikzumlCNRelationDestAnchor{.\tikzumlCNRelationDestAnchorold}%
+ }%
+ %
+ \setcounter{pos}{100*\real{\tikzumlCNRelationPosition}}%
+ \setcounter{posT}{100*\real{\tikzumlCNRelationPositionT}}%
+ \setcounter{posStereo}{100*\real{\tikzumlCNRelationPositionStereotype}}%
+ %
+ % straight line
+ %\setcounter{tikzumlControlNodesNum}{1}%
+ %
+ \def\tikzumlFirstArc{node[midway, name=\tikzumlCNRelationName-1, anchor=center] {} }%
+ \def\tikzumlLastArc{node[midway, name=\tikzumlCNRelationName-3, anchor=center]{} }%
+ \def\posAttrName{}%
+ \def\posMultiplicity{}%
+ \def\posAttrNameT{}%
+ \def\posMultiplicityT{}%
+ %
+ \begin{pgfonlayer}{connections}%
+ \node (\tikzumlCNRelationName-2) at (#3) {};%
+ \end{pgfonlayer}%
+ %
+ \ifnum\theposStereo>100%
+ \pgfmathsetmacro{\tikzumlCNRelationPositionStereotype}{(\theposStereo-100)/100}%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlCNRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \else%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlCNRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \fi%
+ %
+ \ifnum\thepos>100%
+ \pgfmathsetmacro{\tikzumlCNRelationPosition}{(\thepos-100)/100}%
+ \def\arcNum{2}%
+ \else%
+ \def\arcNum{1}%
+ \ifnum\thepos=100%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ \fi%
+ \fi%
+ %
+ \ifnum\arcNum=1%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlCNRelationPosition, \posAttrName, \attrAlign] {\tikzumlCNRelationAttrName}%
+ node[pos=\tikzumlCNRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlCNRelationMultiplicity} }%
+ \fi%
+ \ifnum\arcNum=2%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlCNRelationPosition, \posAttrName, \attrAlign] {\tikzumlCNRelationAttrName}%
+ node[pos=\tikzumlCNRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlCNRelationMultiplicity} }%
+ \fi%
+ %
+ \ifnum\theposT>100%
+ \pgfmathsetmacro{\tikzumlCNRelationPositionT}{(\theposT-100)/100}%
+ \def\arcNumT{2}%
+ \else%
+ \def\arcNumT{1}%
+ \ifnum\theposT=100%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ \fi%
+ \fi%
+ %
+ \ifnum\arcNumT=1%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlCNRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlCNRelationAttrNameT}%
+ node[pos=\tikzumlCNRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlCNRelationMultiplicityT} }%
+ \fi%
+ \ifnum\arcNumT=2%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlCNRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlCNRelationAttrNameT}%
+ node[pos=\tikzumlCNRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlCNRelationMultiplicityT} }%
+ \fi%
+ %
+ \xdef\tikzumlPath{(\tikzumlSrcClassNodeName\tikzumlCNRelationSrcAnchor) -- \tikzumlFirstArc (\tikzumlCNRelationName-2.base) -- \tikzumlLastArc (\tikzumlDestClassNodeName\tikzumlCNRelationDestAnchor) }%
+
+ \begin{pgfonlayer}{connections}%
+ \ifthenelse{\equal{\tikzumlCNRelationStyle}{tikzuml nesting style}}{%
+ \pgfarrowsdeclare{nested}{nested}{...}
+ {
+ \tikzumlNestingSymbolSize=0.2pt%
+ \advance\tikzumlNestingSymbolSize by .5\pgflinewidth%
+ \pgfsetdash{}{0pt} % do not dash
+ \pgfsetroundjoin % fix join
+ \pgfsetroundcap % fix cap
+ \pgfpathmoveto{\pgfpoint{-16*\tikzumlNestingSymbolSize}{0pt}}%
+ \pgfpatharc{180}{90}{8*\tikzumlNestingSymbolSize}%
+ \pgfpatharc{90}{0}{8*\tikzumlNestingSymbolSize}%
+ \pgfpatharc{0}{-90}{8*\tikzumlNestingSymbolSize}%
+ \pgfpatharc{-90}{-180}{8*\tikzumlNestingSymbolSize}%
+ \pgfpathmoveto{\pgfpoint{-8*\tikzumlNestingSymbolSize}{8*\tikzumlNestingSymbolSize}}%
+ \pgfpathlineto{\pgfpoint{-8*\tikzumlNestingSymbolSize}{-8*\tikzumlNestingSymbolSize}}%
+ \pgfusepathqstroke%
+ }%
+ \draw[auto, \tikzumlCNRelationStyle, nested-, font=\tikzumlDefaultFont] \tikzumlPath ;%
+ }{
+ \draw[auto, \tikzumlCNRelationStyle, font=\tikzumlDefaultFont] \tikzumlPath ;%
+ }
+ \end{pgfonlayer}%
+ %
+ \stepcounter{tikzumlRelationNum}%
+}%
+%
+% shortcuts for cnrelations
+\newcommand{\umlCNinherit}[4][]{\umlCNrelation[style={tikzuml inherit style}, #1]{#2}{#3}{#4}}%
+\newcommand{\umlCNimpl}[4][]{\umlCNrelation[style={tikzuml implements style}, #1]{#2}{#3}{#4}}%
+\newcommand{\umlCNreal}[4][]{\umlCNrelation[style={tikzuml implements style}, #1]{#2}{#3}{#4}}%
+\newcommand{\umlCNassoc}[4][]{\umlCNrelation[style={tikzuml association style}, #1]{#2}{#3}{#4}}%
+\newcommand{\umlCNuniassoc}[4][]{\umlCNrelation[style={tikzuml unidirectional association style}, #1]{#2}{#3}{#4}}%
+\newcommand{\umlCNaggreg}[4][]{\umlCNrelation[style={tikzuml aggregation style}, #1]{#2}{#3}{#4}}%
+\newcommand{\umlCNuniaggreg}[4][]{\umlCNrelation[style={tikzuml unidirectional aggregation style}, #1]{#2}{#3}{#4}}%
+\newcommand{\umlCNcompo}[4][]{\umlCNrelation[style={tikzuml composition style}, #1]{#2}{#3}{#4}}%
+\newcommand{\umlCNunicompo}[4][]{\umlCNrelation[style={tikzuml unidirectional composition style}, #1]{#2}{#3}{#4}}%
+\newcommand{\umlCNimport}[4][]{\umlCNrelation[style={tikzuml import style}, #1]{#2}{#3}{#4}}%
+\newcommand{\umlCNnest}[4][]{\umlCNrelation[style={tikzuml nesting style}, #1]{#2}{#3}{#4}}%
+\newcommand{\umlCNdep}[4][]{\umlCNrelation[style={tikzuml dependency style}, #1]{#2}{#3}{#4}}%
+\newcommand{\umlCNfriend}[4][]{%
+ \pgfkeys{/tikzuml/friendrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlCNfriend, forbidden option stereo}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/friendrelation/.cd, #1}%
+ \umlCNrelation[stereo=friend, style={tikzuml dependency style}, #1]{#2}{#3}{#4}%
+}%
+%
+% define a note
+% arg : attached class
+% label of the note
+% optional : x,y: coordinates of the note
+% width: width of the note
+% geometry: geometry of the relation between the note and what it is about
+% weight: barycentric weight for a 3-line relation
+% arm: length of the first arm
+% anchor1, anchor2: anchors of the relation
+% draw, fill, text: colors
+% style: to manage every default TikZ option
+% no coords: to tell that the note position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlnote}[3][]{%
+ \pgfkeys{/tikzuml/note/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlNoteDefaultWidth,%
+ geometry/.initial=\tikzumlRelationDefaultGeometry,%
+ weight/.initial=\tikzumlRelationDefaultWeight, arm/.initial=auto, style/.style={},%
+ anchor1/.initial=tikzumlEmpty, anchor2/.initial=tikzumlEmpty,%
+ draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlNoteDefaultFillColor,%
+ text/.initial=\tikzumlDefaultTextColor,%
+ no coords/.is if=tikzumlnoteWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/note/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/note/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/note/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlnote, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/note/.cd, #1}%
+ \pgfkeys{/tikzuml/note/.cd, x/.get=\tikzumlNoteX, y/.get=\tikzumlNoteY, width/.get=\tikzumlNoteTextWidth,%
+ geometry/.get=\tikzumlNoteGeometry,%
+ weight/.get=\tikzumlNoteWeight, arm/.get=\tikzumlNoteArm,%
+ anchor1/.get=\tikzumlNoteSrcAnchor, anchor2/.get=\tikzumlNoteDestAnchor,%
+ draw/.get=\tikzumlNoteDrawColor, fill/.get=\tikzumlNoteFillColor,%
+ text/.get=\tikzumlNoteTextColor%
+ }%
+ %
+ \def\tikzumlClassName{#2}%
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlClassNodeName{\tikzumlClassName}}\x%
+ %
+ % def anchors macros
+ \ifthenelse{\equal{\tikzumlNoteSrcAnchor}{tikzumlEmpty}}{%
+ \def\tikzumlNoteSrcAnchor{}%
+ }{%
+ \let\tikzumlNoteSrcAnchorold\tikzumlNoteSrcAnchor%
+ \def\tikzumlNoteSrcAnchor{.\tikzumlNoteSrcAnchorold}%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlNoteDestAnchor}{tikzumlEmpty}}{%
+ \def\tikzumlNoteDestAnchor{}%
+ }{%
+ \let\tikzumlNoteDestAnchorold\tikzumlNoteDestAnchor%
+ \def\tikzumlNoteDestAnchor{.\tikzumlNoteDestAnchorold}%
+ }%
+ %
+ \iftikzumlnoteWithoutCoords%
+ \node[text=\tikzumlNoteTextColor, text width=\tikzumlNoteTextWidth, font=\tikzumlDefaultFont, outer sep=0, inner xsep=1ex, inner ysep=3ex, /tikzuml/note/style] (note-\thetikzumlNoteNum-coord) {#3};%
+ \else%
+ \node[text=\tikzumlNoteTextColor, text width=\tikzumlNoteTextWidth, font=\tikzumlDefaultFont, outer sep=0, inner xsep=1ex, inner ysep=3ex, /tikzuml/note/style] (note-\thetikzumlNoteNum-coord) at (\tikzumlNoteX, \tikzumlNoteY) {#3};%
+ \fi%
+ \draw (note-\thetikzumlNoteNum-coord.north east) node[name=note-\thetikzumlNoteNum-right-top, below=2ex, coordinate] {};%
+ \draw (note-\thetikzumlNoteNum-coord.north east) node[name=note-\thetikzumlNoteNum-top-right, left=2ex, coordinate] {};%
+ \draw[draw=\tikzumlNoteDrawColor, fill=\tikzumlNoteFillColor] (note-\thetikzumlNoteNum-coord.south west) -- (note-\thetikzumlNoteNum-coord.south east) -- (note-\thetikzumlNoteNum-right-top.base) -- (note-\thetikzumlNoteNum-top-right.base) -- (note-\thetikzumlNoteNum-coord.north west) -- cycle;%
+ \node[text=\tikzumlNoteTextColor, text width=\tikzumlNoteTextWidth, outer sep=0, inner xsep=1ex, inner ysep=3ex, font=\tikzumlDefaultFont] (note-\thetikzumlNoteNum) at (note-\thetikzumlNoteNum-coord) {#3};%
+ \draw[draw=\tikzumlNoteDrawColor] (note-\thetikzumlNoteNum-right-top) -| (note-\thetikzumlNoteNum-top-right);%
+ %
+ \pgfmathsetmacro{\tikzumlNoteWeightT}{1.0-\tikzumlNoteWeight}%
+ \node (note-\thetikzumlNoteNum-middle) at (barycentric cs:note-\thetikzumlNoteNum-coord=\tikzumlNoteWeight,\tikzumlClassNodeName=\tikzumlNoteWeightT) {};%
+ %
+ \ifthenelse{\equal{\tikzumlNoteGeometry}{--}%
+ \OR\equal{\tikzumlNoteGeometry}{-|}%
+ \OR\equal{\tikzumlNoteGeometry}{|-}}{%
+ \edef\tikzumlnotepath{\tikzumlNoteGeometry}
+ }{%
+ \ifthenelse{\equal{\tikzumlNoteGeometry}{-|-}}{%
+ \ifthenelse{\equal{\tikzumlNoteArm}{auto}}{%
+ \edef\tikzumlnotepath{-- (note-\thetikzumlNoteNum-coord\tikzumlNoteSrcAnchor -| note-\thetikzumlNoteNum-middle.center) -- (note-\thetikzumlNoteNum-middle.center) -- (note-\thetikzumlNoteNum-middle.center |- \tikzumlClassNodeName\tikzumlNoteDestAnchor) --}%
+ }{%
+ \draw (note-\thetikzumlNoteNum-coord\tikzumlNoteSrcAnchor)+(\tikzumlNoteArm,0) node[name=note-\thetikzumlNoteNum-tmp] {};
+ \edef\tikzumlnotepath{-- (note-\thetikzumlNoteNum-tmp.center) |-}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlNoteGeometry}{|-|}}{%
+ \ifthenelse{\equal{\tikzumlNoteArm}{auto}}{%
+ \edef\tikzumlnotepath{-- (note-\thetikzumlNoteNum-coord\tikzumlNoteSrcAnchor |- note-\thetikzumlNoteNum-middle.center) -- (note-\thetikzumlNoteNum-middle.center) -- (note-\thetikzumlNoteNum-middle.center -| \tikzumlClassNodeName\tikzumlNoteDestAnchor) --}%
+ }{%
+ \draw (note-\thetikzumlNoteNum-coord\tikzumlNoteSrcAnchor)+(0,\tikzumlNoteArm) node[name=note-\thetikzumlNoteNum-tmp] {};
+ \edef\tikzumlnotepath{-- (note-\thetikzumlNoteNum-tmp.center) -|}%
+ }%
+
+ }{%
+ \errmessage{TIKZUML ERROR : Unknown geometry value !!! It should be in the following list : --, |-, -|, |-|, -|-}%
+ }%
+ }%
+ }%
+ %
+ \begin{pgfonlayer}{connections}%
+ \draw[dashed] (note-\thetikzumlNoteNum-coord\tikzumlNoteSrcAnchor) \tikzumlnotepath (\tikzumlClassNodeName\tikzumlNoteDestAnchor);%
+ \end{pgfonlayer}%
+ %
+ \stepcounter{tikzumlNoteNum}%
+}%
+%
+% shortcuts for note with geometry
+\newcommand{\umlHVnote}[3][]{%
+ \pgfkeys{/tikzuml/note/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlHVnote, forbidden option geometry}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/note/.cd, #1}%
+ \umlnote[geometry=-|, #1]{#2}{#3}%
+}%
+\newcommand{\umlVHnote}[3][]{%
+ \pgfkeys{/tikzuml/note/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlVHnote, forbidden option geometry}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/note/.cd, #1}%
+ \umlnote[geometry=|-, #1]{#2}{#3}%
+}%
+\newcommand{\umlVHVnote}[3][]{%
+ \pgfkeys{/tikzuml/note/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlVHVnote, forbidden option geometry}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/note/.cd, #1}%
+ \umlnote[geometry=|-|, #1]{#2}{#3}%
+}%
+\newcommand{\umlHVHnote}[3][]{%
+ \pgfkeys{/tikzuml/note/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlHVHnote, forbidden option geometry}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/note/.cd, #1}%
+ \umlnote[geometry=-|-, #1]{#2}{#3}%
+}%
+%
+% define a uml association class (command)
+% args : name of the class
+% attributes of the class
+% operations of the class
+% optional : x,y: coordinates of the class
+% width: width of the class node
+% type: type of of class (class, interface, typedef, enum)
+% template: template parameters
+% name: name of the class node
+% geometry: geometry of the line
+% weight: barycentric weight of the middle part when geometry is a 3-line
+% arm: length of first part when geometry id a 3-line
+% anchor1, anchor2: src/dest anchors on linked classes
+% style: style of the association class (association, aggregation, composition, inherit, ...)
+% draw, fill, fill template, text: colors
+% style: to manage every default TikZ option
+% no coords: to tell that the class position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlassocclass}[5][]{%
+ \pgfkeys{/tikzuml/assocclass/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX,
+ width/.initial=\tikzumlClassDefaultWidth, type/.initial=\tikzumlClassDefaultType, style/.style={},%
+ template/.initial={}, name/.initial=tikzumlEmpty, geometry/.initial=\tikzumlRelationDefaultGeometry,%
+ weight/.initial=\tikzumlRelationDefaultWeight, arm/.initial=auto,%
+ anchor1/.initial=tikzumlEmpty, anchor2/.initial=tikzumlEmpty,%
+ draw/.initial=\tikzumlDefaultDrawColor,%
+ fill template/.initial=\tikzumlClassTemplateFillColorDefaultFillColor,%
+ fill/.initial=\tikzumlClassDefaultFillColor,%
+ text/.initial=\tikzumlDefaultTextColor,%
+ no coords/.is if=tikzumlassocclassWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/assocclass/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/assocclass/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/assocclass/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlassocclass, invalid option \keyname}%
+ }%
+ }%
+ %
+ \pgfkeys{/tikzuml/assocclass/.cd,#1}%
+ \pgfkeys{/tikzuml/assocclass/.cd, x/.get=\tikzumlAssocClassX, y/.get=\tikzumlAssocClassY,%
+ width/.get=\tikzumlAssocClassMinimumWidth, type/.get=\tikzumlAssocClassTypeTmp,%
+ template/.get=\tikzumlAssocClassTemplateParam,%
+ name/.get=\tikzumlAssocClassName, geometry/.get=\tikzumlAssocClassGeometry,%
+ weight/.get=\tikzumlAssocClassWeight, arm/.get=\tikzumlAssocClassArm,%
+ anchor1/.get=\tikzumlAssocClassSrcAnchor,%
+ anchor2/.get=\tikzumlAssocClassDestAnchor,%
+ draw/.get=\tikzumlAssocClassDrawColor, fill/.get=\tikzumlAssocClassFillColor,%
+ text/.get=\tikzumlAssocClassTextColor, fill template/.get=\tikzumlAssocClassTemplateFillColor%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlAssocClassTypeTmp}{class}\OR\equal{\tikzumlAssocClassTypeTmp}{abstract}}{%
+ \def\tikzumlAssocClassType{}%
+ }{%
+ \def\tikzumlAssocClassType{$\ll$\tikzumlAssocClassTypeTmp$\gg$ \\}%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlAssocClassTemplateParam}{}}{%
+ \def\tikzumlAssocClassVPadding{}%
+ \def\tikzumlAssocClassHPadding{}%
+ }{%
+ \def\tikzumlAssocClassVPadding{\vspace{0.1em} \\}%
+ \def\tikzumlAssocClassHPadding{\hspace{0.5ex} $ $}%
+ }%
+ %
+ \def\tikzumlAssocClassName{#2}%
+ \def\tikzumlAssocClassRelationName{#3}%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlAssocClassNodeName{\tikzumlAssocClassName}}\x%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlAssocClassRelationNodeName{\tikzumlAssocClassRelationName}}\x%
+ %
+ \ifthenelse{\equal{\tikzumlAssocClassName}{tikzumlEmpty}}{}{%
+ \def\tikzumlAssocClassNodeName{\tikzumlAssocClassName}%
+ }%
+ %
+ \StrSubstitute{\tikzumlAssocClassNodeName}{:}{@COLON@}[\tikzumlAssocClassNodeName]%
+ \StrSubstitute{\tikzumlAssocClassNodeName}{\_}{@UNDERSCORE@}[\tikzumlAssocClassNodeName]%
+ %
+ \ifthenelse{\equal{\tikzumlAssocClassTypeTmp}{abstract}}{%
+ \let\tikzumlAssocClassNameOld\tikzumlAssocClassName%
+ \def\tikzumlAssocClassName{{\it \tikzumlAssocClassNameOld}}%
+ }{}%
+ %
+ \def\tikzumlAssocClassPos{\tikzumlAssocClassX,\tikzumlAssocClassY}%
+ \def\tikzumlAssocClassAttributes{#4}%
+ \def\tikzumlAssocClassOperations{#5}%
+ %
+ % def anchors macros
+ \ifthenelse{\equal{\tikzumlAssocClassSrcAnchor}{tikzumlEmpty}}{%
+ \def\tikzumlAssocClassSrcAnchor{}%
+ }{%
+ \let\tikzumlAssocClassSrcAnchorold\tikzumlAssocClassSrcAnchor%
+ \def\tikzumlAssocClassSrcAnchor{.\tikzumlAssocClassSrcAnchorold}%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlAssocClassDestAnchor}{tikzumlEmpty}}{%
+ \def\tikzumlAssocClassDestAnchor{}%
+ }{%
+ \let\tikzumlAssocClassDestAnchorold\tikzumlAssocClassDestAnchor%
+ \def\tikzumlAssocClassDestAnchor{.\tikzumlAssocClassDestAnchorold}%
+ }%
+ %
+ \iftikzumlassocclassWithoutCoords%
+ \node[tikzuml class style, draw=\tikzumlAssocClassDrawColor, fill=\tikzumlAssocClassFillColor, text=\tikzumlAssocClassTextColor, font=\tikzumlDefaultFont, minimum width=\tikzumlAssocClassMinimumWidth, /tikzuml/assocclass/style] (\tikzumlAssocClassNodeName) {\begin{tabular}{c}\tikzumlAssocClassVPadding \tikzumlAssocClassType \tikzumlAssocClassHPadding \textbf{\tikzumlAssocClassName} \tikzumlAssocClassHPadding \end{tabular}%
+ \nodepart{second}%
+ \begin{tabular}{l}%
+ \tikzumlAssocClassAttributes%
+ \end{tabular}%
+ \nodepart{third}%
+ \begin{tabular}{l}%
+ \tikzumlAssocClassOperations%
+ \end{tabular}%
+ };%
+ \else%
+ \node[tikzuml class style, draw=\tikzumlAssocClassDrawColor, fill=\tikzumlAssocClassFillColor, text=\tikzumlAssocClassTextColor, font=\tikzumlDefaultFont, minimum width=\tikzumlAssocClassMinimumWidth, /tikzuml/assocclass/style] (\tikzumlAssocClassNodeName) at (\tikzumlAssocClassPos) {\begin{tabular}{c}\tikzumlAssocClassVPadding \tikzumlAssocClassType \tikzumlAssocClassHPadding \textbf{\tikzumlAssocClassName} \tikzumlAssocClassHPadding \end{tabular}%
+ \nodepart{second}%
+ \begin{tabular}{l}%
+ \tikzumlAssocClassAttributes%
+ \end{tabular}%
+ \nodepart{third}%
+ \begin{tabular}{l}%
+ \tikzumlAssocClassOperations%
+ \end{tabular}%
+ };%
+ \fi%
+ %
+ \ifthenelse{\equal{\tikzumlAssocClassTemplateParam}{}}{}{%
+ \draw (\tikzumlAssocClassNodeName.north east) node[tikzuml template style, name=\tikzumlAssocClassNodeName-template, draw=\tikzumlAssocClassDrawColor, fill=\tikzumlAssocClassTemplateFillColor, text=\tikzumlAssocClassTextColor, font=\tikzumlDefaultFont] {\tikzumlAssocClassTemplateParam};%
+ }%
+ %
+ \pgfmathsetmacro{\tikzumlAssocClassWeightT}{1.0-\tikzumlAssocClassWeight}
+ \node (\tikzumlAssocClassNodeName-middle) at (barycentric cs:\tikzumlAssocClassNodeName=\tikzumlAssocClassWeight,\tikzumlAssocClassRelationNodeName=\tikzumlAssocClassWeightT) {};%
+ %
+ \ifthenelse{\equal{\tikzumlAssocClassGeometry}{--}\OR\equal{\tikzumlAssocClassGeometry}{-|}\OR\equal{\tikzumlAssocClassGeometry}{|-}}{%
+ \edef\tikzumlassocclasspath{\tikzumlAssocClassGeometry}
+ }{%
+ \ifthenelse{\equal{\tikzumlAssocClassGeometry}{-|-}}{%
+ \ifthenelse{\equal{\tikzumlAssocClassArm}{auto}}{%
+ \edef\tikzumlassocclasspath{-- (\tikzumlAssocClassNodeName\tikzumlAssocClassSrcAnchor -| \tikzumlAssocClassNodeName-middle.center) -- (\tikzumlAssocClassNodeName-middle.center) -- (\tikzumlAssocClassNodeName-middle.center |- \tikzumlAssocClassRelationNodeName\tikzumlAssocClassDestAnchor) --}%
+ }{%
+ \draw (\tikzumlAssocClassNodeName\tikzumlAssocClassSrcAnchor)+(\tikzumlAssocClassArm,0) node[name=\tikzumlAssocClassNodeName-tmp] {};
+ \edef\tikzumlnotepath{-- (\tikzumlAssocClassNodeName-tmp.center) |-}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlAssocClassGeometry}{|-|}}{%
+ \ifthenelse{\equal{\tikzumlAssocClassArm}{auto}}{%
+ \edef\tikzumlassocclasspath{-- (\tikzumlAssocClassNodeName\tikzumlAssocClassSrcAnchor |- \tikzumlAssocClassNodeName-middle.center) -- (\tikzumlAssocClassNodeName-middle.center) -- (\tikzumlAssocClassNodeName-middle.center -| \tikzumlAssocClassRelationNodeName\tikzumlAssocClassDestAnchor) --}%
+ }{%
+ \draw (\tikzumlAssocClassNodeName\tikzumlAssocClassSrcAnchor)+(0,\tikzumlAssocClassArm) node[name=\tikzumlAssocClassNodeName-tmp] {};
+ \edef\tikzumlassocclasspath{-- (\thetikzumlAssocClassNodeName-tmp.center) -|}%
+ }%
+
+ }{%
+ \errmessage{TIKZUML ERROR : Unknown geometry value !!! It should be in the following list : --, |-, -|, |-|, -|-}%
+ }%
+ }%
+ }%
+ %
+ \begin{pgfonlayer}{connections}%
+ \draw[dashed] (\tikzumlAssocClassNodeName\tikzumlAssocClassSrcAnchor) \tikzumlassocclasspath (\tikzumlAssocClassRelationNodeName\tikzumlAssocClassDestAnchor);%
+ \end{pgfonlayer}%
+ %
+ % add to fit
+ \ifnum\c@tikzumlPackageLevel>0%
+ \edef\tikzumlPackageFitOld{\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname}%
+ \ifthenelse{\equal{\tikzumlAssocClassTemplateParam}{}}{%
+ \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{\tikzumlPackageFitOld (\tikzumlAssocClassNodeName)(\tikzumlAssocClassNodeName-middle)}%
+ }{%
+ \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{\tikzumlPackageFitOld (\tikzumlAssocClassNodeName) (\tikzumlAssocClassNodeName-template)(\tikzumlAssocClassNodeName-middle)}%
+ }%
+ \stepcounter{tikzumlPackageClassNum}%
+ \fi%
+}%
+%
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% use case diagrams %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+\tikzstyle{tikzuml usecase style}=[ellipse, text centered]%
+\tikzstyle{tikzuml actor style}=[ellipse, inner sep=0, outer sep=0]%
+%
+\newcounter{tikzumlSystemUseCaseNum}%
+\newcounter{tikzumlSystemLevel}%
+\newcounter{tikzumlUseCaseNum}%
+\newcounter{tikzumlActorNum}%
+%
+\newif\iftikzumlusecaseWithoutCoords%
+\newif\iftikzumlactorWithoutCoords%
+%
+% define a system
+% arg : name
+% optional : x, y: coordinates of the system
+% draw, fill, text: colors
+\newenvironment{umlsystem}[2][]{%
+ \gdef\tikzumlSystemFit{}%
+ \def\tikzumlSystemName{#2}%
+ \setcounter{tikzumlSystemUseCaseNum}{0}%
+ %
+ \pgfkeys{/tikzuml/system/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX,%
+ draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlSystemDefaultFillColor,%
+ text/.initial=\tikzumlDefaultTextColor,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \errmessage{TIKZUML ERROR : in umlsystem, invalid option \keyname}%
+ }%
+ }%
+ %
+ \pgfkeys{/tikzuml/system/.cd, #1}%
+ \pgfkeys{/tikzuml/system/.cd, x/.get=\tikzumlSystemXShift, y/.get=\tikzumlSystemYShift,%
+ draw/.get=\tikzumlSystemDrawColor, fill/.get=\tikzumlSystemFillColor,%
+ text/.get=\tikzumlSystemTextColor}%
+ %
+ \stepcounter{tikzumlSystemLevel}%
+ %
+ \begin{scope}[xshift=\tikzumlSystemXShift cm, yshift=\tikzumlSystemYShift cm]%
+}{%
+ \addtocounter{tikzumlSystemLevel}{-1}%
+ % if contains no usecase, one define a fictive node to enable the fit option
+ \ifnum\c@tikzumlSystemUseCaseNum=0%
+ \node[inner xsep=10ex, inner ysep=1em] (\tikzumlSystemName-root) at (0,0) {};%
+ \xdef\tikzumlSystemFit{(\tikzumlSystemName-root)}%
+ \fi%
+ %
+ \begin{pgfonlayer}{background}%
+ \node[inner ysep=1em, inner xsep=2ex, fit = \tikzumlSystemFit] (\tikzumlSystemName-tmp) {};%
+ \node[text=\tikzumlSystemTextColor, font=\tikzumlDefaultFont] (\tikzumlSystemName-caption-tmp) at (\tikzumlSystemName-tmp.north) {\tikzumlSystemName};%
+ \node[draw=\tikzumlSystemDrawColor, fill=\tikzumlSystemFillColor, text=\tikzumlSystemTextColor, font=\tikzumlDefaultFont, inner ysep=1em, inner xsep=2ex, fit = (\tikzumlSystemName-tmp) (\tikzumlSystemName-caption-tmp)] (\tikzumlSystemName) {};%
+ \node[text=\tikzumlSystemTextColor, font=\tikzumlDefaultFont] (\tikzumlSystemName-caption) at (\tikzumlSystemName-caption-tmp.north) {\tikzumlSystemName};%
+ \end{pgfonlayer}%
+ \end{scope}%
+ %
+}%
+%
+% define a use case
+% arg : label of the use case
+% optional : x, y: coordinates of the use case
+% name: name of the node
+% width: node width
+% draw, fill, text: colors
+% style: to manage every default TikZ option
+% no coords: to tell that the use case position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlusecase}[2][]{%
+ \stepcounter{tikzumlUseCaseNum}%
+ \pgfkeys{/tikzuml/usecase/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=auto,%
+ name/.initial=usecase-\thetikzumlUseCaseNum,%
+ draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlUseCaseDefaultFillColor,%
+ text/.initial=\tikzumlDefaultTextColor, style/.style={},%
+ no coords/.is if=tikzumlusecaseWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/usecase/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/usecase/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/usecase/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlusecase, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/usecase/.cd, #1}%
+ \pgfkeys{/tikzuml/usecase/.cd, x/.get=\tikzumlUseCaseX, y/.get=\tikzumlUseCaseY, width/.get=\tikzumlUseCaseTextWidth,%
+ name/.get=\tikzumlUseCaseName,%
+ draw/.get=\tikzumlUseCaseDrawColor, fill/.get=\tikzumlUseCaseFillColor,%
+ text/.get=\tikzumlUseCaseTextColor%
+ }%
+ %
+ \def\tikzumlUseCaseText{#2}%
+ %
+ \def\tikzumlUseCasePos{\tikzumlUseCaseX,\tikzumlUseCaseY}%
+ %
+ \ifthenelse{\equal{\tikzumlUseCaseTextWidth}{auto}}{%
+ \iftikzumlusecaseWithoutCoords%
+ \node[tikzuml usecase style, draw=\tikzumlUseCaseDrawColor, fill=\tikzumlUseCaseFillColor, text=\tikzumlUseCaseTextColor, font=\tikzumlDefaultFont, /tikzuml/usecase/style] (\tikzumlUseCaseName) {\tikzumlUseCaseText};%
+ \else%
+ \node[tikzuml usecase style, draw=\tikzumlUseCaseDrawColor, fill=\tikzumlUseCaseFillColor, text=\tikzumlUseCaseTextColor, font=\tikzumlDefaultFont, /tikzuml/usecase/style] (\tikzumlUseCaseName) at (\tikzumlUseCasePos) {\tikzumlUseCaseText};%
+ \fi%
+ }{%
+ \iftikzumlusecaseWithoutCoords%
+ \node[tikzuml usecase style, draw=\tikzumlUseCaseDrawColor, fill=\tikzumlUseCaseFillColor, text=\tikzumlUseCaseTextColor, font=\tikzumlDefaultFont, text width=\tikzumlUseCaseTextWidth, /tikzuml/usecase/style] (\tikzumlUseCaseName) {\tikzumlUseCaseText};%
+ \else%
+ \node[tikzuml usecase style, draw=\tikzumlUseCaseDrawColor, fill=\tikzumlUseCaseFillColor, text=\tikzumlUseCaseTextColor, font=\tikzumlDefaultFont, text width=\tikzumlUseCaseTextWidth, /tikzuml/usecase/style] (\tikzumlUseCaseName) at (\tikzumlUseCasePos) {\tikzumlUseCaseText};%
+ \fi%
+ }%
+ %
+ % add to fit
+ \ifnum\c@tikzumlSystemLevel>0%
+ \let\tikzumlSystemFitOld\tikzumlSystemFit%
+ \xdef\tikzumlSystemFit{\tikzumlSystemFitOld (\tikzumlUseCaseName)}%
+ \stepcounter{tikzumlSystemUseCaseNum}%
+ \fi%
+}%
+%
+% define the actor symbol
+% optional : global tikzpicture styles
+\newcommand{\picturedactor}[1]{%
+ \pgfkeys{/tikzuml/picactor/.cd, scale/.initial=1, .unknown/.code={}}%
+ \pgfkeys{/tikzuml/picactor/.cd,#1}%
+ \pgfkeys{/tikzuml/picactor/.cd, scale/.get=\tikzumlPicturedActorScale}%
+ %
+ \begin{tikzpicture}[#1]%
+ \coordinate (head) at (0,4ex);%
+ \coordinate (left-hand) at (-2ex,2ex);%
+ \coordinate (right-hand) at (2ex,2ex);%
+ \coordinate (left-foot) at (-2ex,-2ex);%
+ \coordinate (right-foot) at (2ex,-2ex);%
+ \coordinate (empty) at (0,-3ex);%
+ \draw (empty) (0,0) -- (head);%
+ \draw (left-hand) -- (right-hand);%
+ \draw (0,0) -- (left-foot) (0,0) -- (right-foot);%
+ \node[fill, draw, circle, inner sep=\tikzumlPicturedActorScale*0.3333ex, minimum size=\tikzumlPicturedActorScale*2ex, anchor=base] at (head) {};%
+ \end{tikzpicture}%
+}%
+%
+% define an actor
+% arg : var name
+% optional : x, y: coordinates of the actor
+% scale: scale factor of the actor symbol
+% below: distance between the actor symbol and its name below
+% draw, text: colors
+% style: to manage every default TikZ option
+% no coords: to tell that the actor position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlactor}[2][]{%
+ \stepcounter{tikzumlActorNum}%
+ \pgfkeys{/tikzuml/actor/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, scale/.initial=1, below/.initial=\tikzumlActorDefaultBelow,%
+ draw/.initial=\tikzumlDefaultDrawColor, text/.initial=\tikzumlDefaultTextColor,%
+ style/.style={},%
+ no coords/.is if=tikzumlactorWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/actor/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/actor/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/actor/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlactor, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/actor/.cd, #1}%
+ \pgfkeys{/tikzuml/actor/.cd,%
+ x/.get=\tikzumlActorX, y/.get=\tikzumlActorY, scale/.get=\tikzumlActorScale,%
+ below/.get=\tikzumlActorBelow,%
+ draw/.get=\tikzumlActorDrawColor, text/.get=\tikzumlActorTextColor}%
+ %
+ \def\tikzumlActorName{#2}%
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlActorNodeName{\tikzumlActorName}}\x%
+ %
+ \def\tikzumlActorPos{\tikzumlActorX,\tikzumlActorY}%
+ %
+ \iftikzumlactorWithoutCoords%
+ \node[tikzuml actor style, text=\tikzumlActorTextColor, font=\tikzumlDefaultFont, /tikzuml/actor/style] (\tikzumlActorNodeName) {\picturedactor{scale=\tikzumlActorScale, fill=white, draw=\tikzumlActorDrawColor, thick}};%
+ \else%
+ \node[tikzuml actor style, text=\tikzumlActorTextColor, font=\tikzumlDefaultFont, /tikzuml/actor/style] (\tikzumlActorNodeName) at (\tikzumlActorPos) {\picturedactor{scale=\tikzumlActorScale, fill=white, draw=\tikzumlActorDrawColor, thick}};%
+ \fi%
+ \node[text=\tikzumlActorTextColor, font=\tikzumlDefaultFont, below=\tikzumlActorScale*\tikzumlActorBelow] at (\tikzumlActorNodeName) {\tikzumlActorName};%
+ %
+}%
+
+% shortcuts for include and extend relation
+\newcommand{\umlinclude}[3][]{%
+ \pgfkeys{/tikzuml/includerelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlinclude, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlinclude, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/includerelation/.cd, #1}%
+ \umlrelation[stereo=include, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+\newcommand{\umlextend}[3][]{%
+ \pgfkeys{/tikzuml/extendrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlextend, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlextend, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/extendrelation/.cd, #1}%
+ \umlrelation[stereo=extend, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlHVinclude}[3][]{%
+ \pgfkeys{/tikzuml/includerelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlHVinclude, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlHVinclude, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/includerelation/.cd, #1}%
+ \umlrelation[geometry=-|, stereo=include, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+\newcommand{\umlHVextend}[3][]{%
+ \pgfkeys{/tikzuml/extendrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlHVextend, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlHVextend, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/extendrelation/.cd, #1}%
+ \umlrelation[geometry=-|, stereo=extend, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlVHinclude}[3][]{%
+ \pgfkeys{/tikzuml/includerelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlVHinclude, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlVHinclude, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/includerelation/.cd, #1}%
+ \umlrelation[geometry=|-, stereo=include, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+\newcommand{\umlVHextend}[3][]{%
+ \pgfkeys{/tikzuml/extendrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR :in umlVHextend, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlVHextend, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/extendrelation/.cd, #1}%
+ \umlrelation[geometry=|-, stereo=extend, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlHVHinclude}[3][]{%
+ \pgfkeys{/tikzuml/includerelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlHVHinclude, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlHVHinclude, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/includerelation/.cd, #1}%
+ \umlrelation[geometry=-|-, stereo=include, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+\newcommand{\umlHVHextend}[3][]{%
+ \pgfkeys{/tikzuml/extendrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlHVHextend, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlHVHextend, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/extendrelation/.cd, #1}%
+ \umlrelation[geometry=-|-, stereo=extend, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlVHVinclude}[3][]{%
+ \pgfkeys{/tikzuml/includerelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlVHVinclude, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlVHVinclude, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/includerelation/.cd, #1}%
+ \umlrelation[geometry=|-|, stereo=include, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+\newcommand{\umlVHVextend}[3][]{%
+ \pgfkeys{/tikzuml/extendrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlVHVextend, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlVHVextend, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/extendrelation/.cd, #1}%
+ \umlrelation[geometry=|-|, stereo=extend, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlCNinclude}[4][]{%
+ \pgfkeys{/tikzuml/includerelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlCNinclude, forbidden option stereo}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/includerelation/.cd, #1}%
+ \umlCNrelation[stereo=include, style={tikzuml dependency style}, #1]{#2}{#3}{#4}%
+}%
+\newcommand{\umlCNextend}[4][]{%
+ \pgfkeys{/tikzuml/extendrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlCNextend, forbidden option stereo}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/extendrelation/.cd, #1}%
+ \umlCNrelation[stereo=extend, style={tikzuml dependency style}, #1]{#2}{#3}{#4}%
+}%
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% state diagrams %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+\tikzstyle{tikzuml state style}=[rectangle split, rectangle split parts=2, rounded corners, inner xsep=1.5ex]%
+\tikzstyle{tikzuml transition style}=[color=\tikzumlDefaultDrawColor, rounded corners, -angle 45]%
+%
+\newcounter{tikzumlStateJoinNum}%
+\newcounter{tikzumlStateDecisionNum}%
+\newcounter{tikzumlStateInitialNum}%
+\newcounter{tikzumlStateFinalNum}%
+\newcounter{tikzumlStateEnterNum}%
+\newcounter{tikzumlStateExitNum}%
+\newcounter{tikzumlStateEndNum}%
+\newcounter{tikzumlStateHistoryNum}%
+\newcounter{tikzumlStateDeepHistoryNum}%
+\newcounter{tikzumlStateLevel}%
+\newcounter{tikzumlStateSubStateNum}%
+\newcounter{tikzumlStateText}%
+%
+\newif\iftikzumlstatejoinWithoutCoords%
+\newif\iftikzumlstatedecisionWithoutCoords%
+\newif\iftikzumlstateinitialWithoutCoords%
+\newif\iftikzumlstatefinalWithoutCoords%
+\newif\iftikzumlstateenterWithoutCoords%
+\newif\iftikzumlstateexitWithoutCoords%
+\newif\iftikzumlstateendWithoutCoords%
+\newif\iftikzumlstatehistoryWithoutCoords%
+\newif\iftikzumlstatedeephistoryWithoutCoords%
+\newif\iftikzumlstateWithoutCoords%
+%
+% define a uml join state
+% args : name of the state
+% optional : x,y: coordinates of the state
+% width: width of the state node
+% name: name of the state node
+% color: color of the join symbol
+% style: to manage every default TikZ option
+% no coords: to tell that the state position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlstatejoin}[1][]{%
+ \pgfkeys{/tikzuml/statejoin/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateJoinDefaultWidth,%
+ name/.initial=statejoin-\thetikzumlStateJoinNum,%
+ color/.initial=\tikzumlDefaultDrawColor, style/.style={},%
+ no coords/.is if=tikzumlstatejoinWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/statejoin/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/statejoin/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/statejoin/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlstatejoin, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/statejoin/.cd, #1}%
+ \pgfkeys{/tikzuml/statejoin/.cd, x/.get=\tikzumlStateJoinX, y/.get=\tikzumlStateJoinY, width/.get=\tikzumlStateJoinMinimumWidth,%
+ name/.get=\tikzumlStateJoinName, color/.get=\tikzumlStateJoinColor%
+ }%
+ %
+ \def\tikzumlStateJoinPos{\tikzumlStateJoinX,\tikzumlStateJoinY}%
+ %
+ \iftikzumlstatejoinWithoutCoords%
+ \node[circle, minimum size=\tikzumlStateJoinMinimumWidth, draw=\tikzumlStateJoinColor, fill=\tikzumlStateJoinColor, /tikzuml/statejoin/style] (\tikzumlStateJoinName) {};%
+ \else%
+ \node[circle, minimum size=\tikzumlStateJoinMinimumWidth, draw=\tikzumlStateJoinColor, fill=\tikzumlStateJoinColor, /tikzuml/statejoin/style] (\tikzumlStateJoinName) at (\tikzumlStateJoinPos) {};%
+ \fi%
+ %
+ % add to fit
+ \ifnum\c@tikzumlStateLevel>0%
+ \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlStateJoinName)}%
+ \stepcounter{tikzumlStateSubStateNum}%
+ \fi%
+ \stepcounter{tikzumlStateJoinNum}%
+}%
+%
+% define a uml decision state
+% args : name of the state
+% optional : x,y: coordinates of the state
+% width: width of the state node
+% name: name of the state node
+% color: color of the join symbol
+% style: to manage every default TikZ option
+% no coords: to tell that the state position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlstatedecision}[1][]{%
+ \pgfkeys{/tikzuml/statedecision/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateDecisionDefaultWidth,%
+ name/.initial=statedecision-\thetikzumlStateDecisionNum,%
+ color/.initial=\tikzumlDefaultDrawColor, style/.style={},%
+ no coords/.is if=tikzumlstatedecisionWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/statedecision/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/statedecision/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/statedecision/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlstatedecision, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/statedecision/.cd, #1}%
+ \pgfkeys{/tikzuml/statedecision/.cd, x/.get=\tikzumlStateDecisionX, y/.get=\tikzumlStateDecisionY, width/.get=\tikzumlStateDecisionMinimumWidth,%
+ name/.get=\tikzumlStateDecisionName, color/.get=\tikzumlStateDecisionColor%
+ }%
+ %
+ \def\tikzumlStateDecisionPos{\tikzumlStateDecisionX,\tikzumlStateDecisionY}%
+ %
+ \iftikzumlstatedecisionWithoutCoords%
+ \node[rectangle, rotate=45, minimum size=\tikzumlStateDecisionMinimumWidth, draw=\tikzumlStateDecisionColor, /tikzuml/statedecision/style] (\tikzumlStateDecisionName) {};%
+ \else%
+ \node[rectangle, rotate=45, minimum size=\tikzumlStateDecisionMinimumWidth, draw=\tikzumlStateDecisionColor, /tikzuml/statedecision/style] (\tikzumlStateDecisionName) at (\tikzumlStateDecisionPos) {};%
+ \fi%
+ %
+ % add to fit
+ \ifnum\c@tikzumlStateLevel>0%
+ \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlStateDecisionName)}%
+ \stepcounter{tikzumlStateSubStateNum}%
+ \fi%
+ \stepcounter{tikzumlStateDecisionNum}%
+}%
+%
+% define a uml initial state
+% args : name of the state
+% optional : x,y: coordinates of the state
+% width: width of the state node
+% name: name of the state node
+% entry, do, exit: entry/do/exit action of the state
+% color: color of the join symbol
+% style: to manage every default TikZ option
+% no coords: to tell that the state position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlstateinitial}[1][]{%
+ \pgfkeys{/tikzuml/stateinitial/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateInitialDefaultWidth,%
+ name/.initial=stateinitial-\thetikzumlStateInitialNum,%
+ color/.initial=\tikzumlDefaultDrawColor, style/.style={},%
+ no coords/.is if=tikzumlstateinitialWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/stateinitial/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/stateinitial/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/stateinitial/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlstateinitial, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/stateinitial/.cd, #1}%
+ \pgfkeys{/tikzuml/stateinitial/.cd, x/.get=\tikzumlStateInitialX, y/.get=\tikzumlStateInitialY, width/.get=\tikzumlStateInitialMinimumWidth,%
+ name/.get=\tikzumlStateInitialName, color/.get=\tikzumlStateInitialColor%
+ }%
+ %
+ \def\tikzumlStateInitialPos{\tikzumlStateInitialX,\tikzumlStateInitialY}%
+ %
+ \iftikzumlstateinitialWithoutCoords%
+ \node[circle, minimum size=\tikzumlStateInitialMinimumWidth, fill=\tikzumlStateInitialColor, /tikzuml/stateinitial/style] (\tikzumlStateInitialName) {};%
+ \else%
+ \node[circle, minimum size=\tikzumlStateInitialMinimumWidth, fill=\tikzumlStateInitialColor, /tikzuml/stateinitial/style] (\tikzumlStateInitialName) at (\tikzumlStateInitialPos) {};%
+ \fi%
+ %
+ % add to fit
+ \ifnum\c@tikzumlStateLevel>0%
+ \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlStateInitialName)}%
+ \stepcounter{tikzumlStateSubStateNum}%
+ \fi%
+ \stepcounter{tikzumlStateInitialNum}%
+}%
+%
+% define a uml final state
+% args : name of the state
+% optional : x,y: coordinates of the state
+% width: width of the state node
+% name: name of the state node
+% color: color of the join symbol
+% style: to manage every default TikZ option
+% no coords: to tell that the state position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlstatefinal}[1][]{%
+ \pgfkeys{/tikzuml/statefinal/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateFinalDefaultWidth,%
+ name/.initial=statefinal-\thetikzumlStateFinalNum,%
+ color/.initial=\tikzumlDefaultDrawColor, style/.style={},%
+ no coords/.is if=tikzumlstatefinalWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/statefinal/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/statefinal/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/statefinal/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlstatefinal, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/statefinal/.cd, #1}%
+ \pgfkeys{/tikzuml/statefinal/.cd, x/.get=\tikzumlStateFinalX, y/.get=\tikzumlStateFinalY, width/.get=\tikzumlStateFinalMinimumWidth,%
+ name/.get=\tikzumlStateFinalName, color/.get=\tikzumlStateFinalColor%
+ }%
+ %
+ \def\tikzumlStateFinalPos{\tikzumlStateFinalX,\tikzumlStateFinalY}%
+ %
+ \iftikzumlstatefinalWithoutCoords%
+ \node[circle, minimum size=\tikzumlStateFinalMinimumWidth, draw=\tikzumlStateFinalColor, fill=\tikzumlStateFinalColor, double, double distance=0.1cm, /tikzuml/statefinal/style] (\tikzumlStateFinalName) {};%
+ \else%
+ \node[circle, minimum size=\tikzumlStateFinalMinimumWidth, draw=\tikzumlStateFinalColor, fill=\tikzumlStateFinalColor, double, double distance=0.1cm, /tikzuml/statefinal/style] (\tikzumlStateFinalName) at (\tikzumlStateFinalPos) {};%
+ \fi%
+ %
+ % add to fit
+ \ifnum\c@tikzumlStateLevel>0%
+ \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlStateFinalName)}%
+ \stepcounter{tikzumlStateSubStateNum}%
+ \fi%
+ \stepcounter{tikzumlStateFinalNum}%
+}%
+%
+% define a uml enter state
+% args : name of the state
+% optional : x,y: coordinates of the state
+% width: width of the state node
+% name: name of the state node
+% color: color of the join symbol
+% style: to manage every default TikZ option
+% no coords: to tell that the state position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlstateenter}[1][]{%
+ \pgfkeys{/tikzuml/stateenter/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateEnterDefaultWidth,%
+ name/.initial=stateenter-\thetikzumlStateEnterNum,%
+ color/.initial=\tikzumlDefaultDrawColor, style/.style={},%
+ no coords/.is if=tikzumlstateenterWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/stateenter/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/stateenter/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/stateenter/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlstateenter, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/stateenter/.cd, #1}%
+ \pgfkeys{/tikzuml/stateenter/.cd, x/.get=\tikzumlStateEnterX, y/.get=\tikzumlStateEnterY, width/.get=\tikzumlStateEnterMinimumWidth,%
+ name/.get=\tikzumlStateEnterName, color/.get=\tikzumlStateEnterColor%
+ }%
+ %
+ \def\tikzumlStateEnterPos{\tikzumlStateEnterX,\tikzumlStateEnterY}%
+ %
+ \iftikzumlstateenterWithoutCoords%
+ \node[circle, minimum size=\tikzumlStateEnterMinimumWidth, draw=\tikzumlStateEnterColor, /tikzuml/stateenter/style] (\tikzumlStateEnterName) {};%
+ \else%
+ \node[circle, minimum size=\tikzumlStateEnterMinimumWidth, draw=\tikzumlStateEnterColor, /tikzuml/stateenter/style] (\tikzumlStateEnterName) at (\tikzumlStateEnterPos) {};%
+ \fi%
+ %
+ % add to fit
+ \ifnum\c@tikzumlStateLevel>0%
+ \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlStateEnterName)}%
+ \stepcounter{tikzumlStateSubStateNum}%
+ \fi%
+ \stepcounter{tikzumlStateEnterNum}%
+}%
+%
+% define a uml exit state
+% args : name of the state
+% optional : x,y: coordinates of the state
+% width: width of the state node
+% name: name of the state node
+% color: color of the join symbol
+% style: to manage every default TikZ option
+% no coords: to tell that the state position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlstateexit}[1][]{%
+ \pgfkeys{/tikzuml/stateexit/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateExitDefaultWidth,%
+ name/.initial=stateexit-\thetikzumlStateExitNum,%
+ color/.initial=\tikzumlDefaultDrawColor, style/.style={},%
+ no coords/.is if=tikzumlstateexitWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/stateexit/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/stateexit/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/stateexit/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlstateexit, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/stateexit/.cd, #1}%
+ \pgfkeys{/tikzuml/stateexit/.cd, x/.get=\tikzumlStateExitX, y/.get=\tikzumlStateExitY, width/.get=\tikzumlStateExitMinimumWidth,%
+ name/.get=\tikzumlStateExitName, color/.get=\tikzumlStateExitColor%
+ }%
+ %
+ \def\tikzumlStateExitPos{\tikzumlStateExitX,\tikzumlStateExitY}%
+ %
+ \iftikzumlstateexitWithoutCoords%
+ \node[circle, minimum size=\tikzumlStateExitMinimumWidth, draw=\tikzumlStateExitColor, /tikzuml/stateexit/style] (\tikzumlStateExitName) {};%
+ \else%
+ \node[circle, minimum size=\tikzumlStateExitMinimumWidth, draw=\tikzumlStateExitColor, /tikzuml/stateexit/style] (\tikzumlStateExitName) at (\tikzumlStateExitPos) {};%
+ \fi%
+ \draw[draw=\tikzumlStateExitColor] (\tikzumlStateExitName.north east) -- (\tikzumlStateExitName.south west) (\tikzumlStateExitName.north west) -- (\tikzumlStateExitName.south east);
+ %
+ % add to fit
+ \ifnum\c@tikzumlStateLevel>0%
+ \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlStateExitName)}%
+ \stepcounter{tikzumlStateSubStateNum}%
+ \fi%
+ \stepcounter{tikzumlStateExitNum}%
+}%
+%
+% define a uml end state
+% args : name of the state
+% optional : x,y: coordinates of the state
+% width: width of the state node
+% name: name of the state node
+% color: color of the join symbol
+% style: to manage every default TikZ option
+% no coords: to tell that the state position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlstateend}[1][]{%
+ \pgfkeys{/tikzuml/stateend/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateEndDefaultWidth,%
+ name/.initial=stateend-\thetikzumlStateEndNum,%
+ color/.initial=\tikzumlDefaultDrawColor, style/.style={},%
+ no coords/.is if=tikzumlstateendWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/stateend/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/stateend/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/stateend/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlstateend, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/stateend/.cd, #1}%
+ \pgfkeys{/tikzuml/stateend/.cd, x/.get=\tikzumlStateEndX, y/.get=\tikzumlStateEndY, width/.get=\tikzumlStateEndMinimumWidth,%
+ name/.get=\tikzumlStateEndName, color/.get=\tikzumlStateEndColor%
+ }%
+ %
+ \def\tikzumlStateEndPos{\tikzumlStateEndX,\tikzumlStateEndY}%
+ %
+ \iftikzumlstateendWithoutCoords%
+ \node[circle, minimum size=\tikzumlStateEndMinimumWidth, /tikzuml/stateend/style] (\tikzumlStateEndName) {};%
+ \else%
+ \node[circle, minimum size=\tikzumlStateEndMinimumWidth, /tikzuml/stateend/style] (\tikzumlStateEndName) at (\tikzumlStateEndPos) {};%
+ \fi%
+ \draw[draw=\tikzumlStateEndColor] (\tikzumlStateEndName.north east) -- (\tikzumlStateEndName.south west) (\tikzumlStateEndName.north west) -- (\tikzumlStateEndName.south east);
+ %
+ % add to fit
+ \ifnum\c@tikzumlStateLevel>0%
+ \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlStateEndName)}%
+ \stepcounter{tikzumlStateSubStateNum}%
+ \fi%
+ \stepcounter{tikzumlStateEndNum}%
+}%
+%
+\newcommand{\picturedhistory}[1]{%
+ \begin{tikzpicture}[#1]%
+ \draw[thick] (-0.1cm,-0.15cm) -- (-0.1cm,0.15cm)
+ (-0.1cm,0) -- (0.1cm,0)
+ (0.1cm,-0.15cm) -- (0.1cm,0.15cm);%
+ \end{tikzpicture}%
+}%
+%
+% define a uml history state
+% args : name of the state
+% optional : x,y: coordinates of the state
+% width: width of the state node
+% name: name of the state node
+% color: color of the join symbol
+% style: to manage every default TikZ option
+% no coords: to tell that the state position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlstatehistory}[1][]{%
+ \pgfkeys{/tikzuml/statehistory/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateHistoryDefaultWidth,%
+ name/.initial=statehistory-\thetikzumlStateHistoryNum,%
+ color/.initial=\tikzumlDefaultDrawColor, style/.style={},%
+ no coords/.is if=tikzumlstatehistoryWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/statehistory/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/statehistory/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/statehistory/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlstatehistory, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/statehistory/.cd, #1}%
+ \pgfkeys{/tikzuml/statehistory/.cd, x/.get=\tikzumlStateHistoryX, y/.get=\tikzumlStateHistoryY, width/.get=\tikzumlStateHistoryMinimumWidth,%
+ name/.get=\tikzumlStateHistoryName, color/.get=\tikzumlStateHistoryColor%
+ }%
+ %
+ \def\tikzumlStateHistoryPos{\tikzumlStateHistoryX,\tikzumlStateHistoryY}%
+ %
+ \iftikzumlstatehistoryWithoutCoords%
+ \node[circle, minimum size=\tikzumlStateHistoryMinimumWidth, draw=\tikzumlStateHistoryColor, /tikzuml/statehistory/style] (\tikzumlStateHistoryName) {\picturedhistory{draw=\tikzumlStateHistoryColor}};%
+ \else%
+ \node[circle, minimum size=\tikzumlStateHistoryMinimumWidth, draw=\tikzumlStateHistoryColor, /tikzuml/statehistory/style] (\tikzumlStateHistoryName) at (\tikzumlStateHistoryPos) {\picturedhistory{draw=\tikzumlStateHistoryColor}};%
+ \fi%
+ %
+ % add to fit
+ \ifnum\c@tikzumlStateLevel>0%
+ \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlStateHistoryName)}%
+ \stepcounter{tikzumlStateSubStateNum}%
+ \fi%
+ \stepcounter{tikzumlStateHistoryNum}%
+}%
+%
+\newcommand{\pictureddeephistory}[1]{%
+ \begin{tikzpicture}[#1]%
+ \draw[thick] (-0.1cm,-0.15cm) -- (-0.1cm,0.15cm)
+ (-0.1cm,0) -- (0.1cm,0)
+ (0.1cm,-0.15cm) -- (0.1cm,0.15cm)
+ (0.23cm,0.19cm) -- (0.23cm,0.11cm)
+ (0.20cm,0.17cm) -- (0.26cm,0.13cm)
+ (0.20cm,0.13cm) -- (0.26cm,0.17cm);%
+ \end{tikzpicture}%
+}%
+%
+% define a uml deep-history state
+% args : name of the state
+% optional : x,y: coordinates of the state
+% width: width of the state node
+% name: name of the state node
+% color: color of the join symbol
+% style: to manage every default TikZ option
+% no coords: to tell that the state position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlstatedeephistory}[1][]{%
+ \pgfkeys{/tikzuml/statedeephistory/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateDeepHistoryDefaultWidth,%
+ name/.initial=statedeephistory-\thetikzumlStateDeepHistoryNum,%
+ color/.initial=\tikzumlDefaultDrawColor, style/.style={},%
+ no coords/.is if=tikzumlstatedeephistoryWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/statedeephistory/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/statedeephistory/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/statedeephistory/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlstatedeephistory, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/statedeephistory/.cd, #1}%
+ \pgfkeys{/tikzuml/statedeephistory/.cd, x/.get=\tikzumlStateDeepHistoryX, y/.get=\tikzumlStateDeepHistoryY, width/.get=\tikzumlStateDeepHistoryMinimumWidth,%
+ name/.get=\tikzumlStateDeepHistoryName, color/.get=\tikzumlStateDeepHistoryColor%
+ }%
+ %
+ \def\tikzumlStateDeepHistoryPos{\tikzumlStateDeepHistoryX,\tikzumlStateDeepHistoryY}%
+ %
+ \iftikzumlstatedeephistoryWithoutCoords%
+ \node[circle, minimum size=\tikzumlStateDeepHistoryMinimumWidth, draw=\tikzumlStateDeepHistoryColor, /tikzuml/statedeephistory/style] (\tikzumlStateDeepHistoryName) {\pictureddeephistory{draw=\tikzumlStateDeepHistoryColor}};%
+ \else%
+ \node[circle, minimum size=\tikzumlStateDeepHistoryMinimumWidth, draw=\tikzumlStateDeepHistoryColor, /tikzuml/statedeephistory/style] (\tikzumlStateDeepHistoryName) at (\tikzumlStateDeepHistoryPos) {\pictureddeephistory{draw=\tikzumlStateDeepHistoryColor}};%
+ \fi%
+ %
+ % add to fit
+ \ifnum\c@tikzumlStateLevel>0%
+ \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlStateDeepHistoryName)}%
+ \stepcounter{tikzumlStateSubStateNum}%
+ \fi%
+ \stepcounter{tikzumlStateDeepHistoryNum}%
+}%
+%
+% define a uml state
+% args : name of the state
+% content of the state
+% optional : x,y: coordinates of the state
+% width: width of the state node
+% name: name of the state node
+% entry, do, exit: entry/do/exit action of the state
+% draw, fill, text: colors
+% style: to manage every default TikZ option
+% no coords: to tell that the state position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newenvironment{umlstate}[2][]{%
+ \ifnum\thetikzumlStateLevel>0%
+ \let\tikzumlState@nameold\tikzumlState@fitname%
+ \let\tikzumlState@parentold\tikzumlState@parent%
+ \edef\tikzumlState@parent{\tikzumlState@parentold @@\tikzumlState@nameold}%
+ \else%
+ \def\tikzumlState@parent{}%
+ \fi%
+ %
+ \stepcounter{tikzumlStateLevel}%
+ %
+ \pgfkeys{/tikzuml/state/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateDefaultWidth,%
+ name/.initial={},%
+ entry/.initial={}, do/.initial={}, exit/.initial={},%
+ draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlStateDefaultFillColor,%
+ text/.initial=\tikzumlDefaultTextColor, style/.style={},%
+ no coords/.is if=tikzumlstateWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/state/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/state/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/state/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ % \errmessage{TIKZUML ERROR : in umlstate, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/state/.cd, #1}%
+ \pgfkeys{/tikzuml/state/.cd, x/.get=\tikzumlStateXShift, y/.get=\tikzumlStateYShift, width/.get=\tikzumlStateMinimumWidth, name/.get=\tikzumlStateName,%
+ entry/.get=\tikzumlStateEntry, do/.get=\tikzumlStateDo, exit/.get=\tikzumlStateExit,%
+ draw/.get=\tikzumlStateDrawColor, fill/.get=\tikzumlStateFillColor,%
+ text/.get=\tikzumlStateTextColor%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlStateName}{}}{%
+ \edef\tikzumlState@name{#2}%
+ }{%
+ \edef\tikzumlState@name{\tikzumlStateName}%
+ }%
+ %
+ \begingroup%
+ \def\_{@}\edef\x{\endgroup%
+ \def\noexpand\tikzumlState@fitname{\tikzumlState@name}}\x%
+ %
+ \let\tikzumlState@nodeNameold\tikzumlState@nodeName%
+ \def\tikzumlState@caption{#2}%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlState@nodeName{\tikzumlState@name}}\x%
+ %
+ \expandafter\gdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{}%
+ %
+ \setcounter{tikzumlStateSubStateNum}{0}%
+ \setcounter{tikzumlStateText}{0}%
+ %
+ \def\tikzumlStateText{tikzumlEmpty}%
+ \begin{scope}[xshift=\tikzumlStateXShift cm, yshift=\tikzumlStateYShift cm]%
+}{%
+ %
+ \def\tikzumlstaterootlabel{\phantom{\tikzumlState@nodeName}}%
+ %
+ \def\tikzumlstaterootinnerysep{0.5ex}%
+ \def\tikzumlstatebodyinnerysep{2ex}%
+ %
+ \ifthenelse{\equal{\tikzumlStateEntry}{}}{}{%
+ \ifnum\c@tikzumlStateText=0%
+ \def\tikzumlStateText{entry/\tikzumlStateEntry}%
+ \else%
+ \let\tikzumlStateTextOld\tikzumlStateText%
+ \ifthenelse{\equal{\tikzumlStateText}{tikzumlEmpty}}{%
+ \def\tikzumlStateText{entry/\tikzumlStateEntry}%
+ }{%
+ \expandafter\def\expandafter\tikzumlStateText\expandafter{\tikzumlStateTextOld \\ entry/\tikzumlStateEntry}%
+ }%
+ \fi%
+ \setcounter{tikzumlStateText}{1}%
+ \ifnum\c@tikzumlStateSubStateNum=0%
+ \def\tikzumlstatebodyinnerysep{0}%
+ \def\tikzumlstaterootinnerysep{0}%
+ \fi%
+ }%
+ \ifthenelse{\equal{\tikzumlStateDo}{}}{}{%
+ \ifnum\c@tikzumlStateText=0%
+ \def\tikzumlStateText{do/\tikzumlStateDo}%
+ \else%
+ \let\tikzumlStateTextOld\tikzumlStateText%
+ \ifthenelse{\equal{\tikzumlStateText}{tikzumlEmpty}}{%
+ \def\tikzumlStateText{do/\tikzumlStateDo}%
+ }{%
+ \expandafter\def\expandafter\tikzumlStateText\expandafter{\tikzumlStateTextOld \\ do/\tikzumlStateDo}%
+ }%
+ \fi%
+ \setcounter{tikzumlStateText}{1}%
+ \ifnum\c@tikzumlStateSubStateNum=0%
+ \def\tikzumlstatebodyinnerysep{0}%
+ \def\tikzumlstaterootinnerysep{0}%
+ \fi%
+ }%
+ \ifthenelse{\equal{\tikzumlStateExit}{}}{}{%
+ \ifnum\c@tikzumlStateText=0%
+ \def\tikzumlStateText{exit/\tikzumlStateExit}%
+ \else%
+ \let\tikzumlStateTextOld\tikzumlStateText%
+ \ifthenelse{\equal{\tikzumlStateText}{tikzumlEmpty}}{%
+ \def\tikzumlStateText{exit/\tikzumlStateExit}%
+ }{%
+ \expandafter\def\expandafter\tikzumlStateText\expandafter{\tikzumlStateTextOld \\ exit/\tikzumlStateExit}%
+ }%
+ \fi%
+ \setcounter{tikzumlStateText}{1}%
+ \ifnum\c@tikzumlStateSubStateNum=0%
+ \def\tikzumlstatebodyinnerysep{0}%
+ \def\tikzumlstaterootinnerysep{0}%
+ \fi%
+ }%
+ %
+ \addtocounter{tikzumlStateLevel}{-1}%
+ \begin{pgfonlayer}{state\thetikzumlStateLevel}%
+ %
+ % if contains nothing, one define a fictive node to enable the fit option
+ \ifnum\c@tikzumlStateSubStateNum=0%
+ \iftikzumlstateWithoutCoords%
+ \node[inner ysep=\tikzumlstaterootinnerysep, minimum width=\tikzumlStateMinimumWidth, /tikzuml/state/style] (\tikzumlState@nodeName-root) {\tikzumlstaterootlabel};%
+ \else%
+ \node[inner ysep=\tikzumlstaterootinnerysep, minimum width=\tikzumlStateMinimumWidth, /tikzuml/state/style] (\tikzumlState@nodeName-root) at (0,0) {\tikzumlstaterootlabel};%
+ \fi%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{(\tikzumlState@nodeName-root)}%
+ \fi%
+ %
+ \ifnum\c@tikzumlStateLevel>0%
+ \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent\endcsname{\tikzumlStateFitTmp (\tikzumlState@nodeName-body) (\tikzumlState@nodeName-caption)}%
+ \stepcounter{tikzumlStateSubStateNum}%
+ \fi%
+ %
+ \node[inner xsep=2ex, inner ysep=\tikzumlstatebodyinnerysep, fit = \csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname, /tikzuml/state/style ] (\tikzumlState@nodeName-body) {};%
+ \def\tikzumlState@orig{body}%
+ \ifnum\c@tikzumlStateText=1%
+ \node[above=0] (\tikzumlState@nodeName-texttmp) at (\tikzumlState@nodeName-\tikzumlState@orig.north) {\begin{tabular}{l}\tikzumlStateText \end{tabular}};%
+ \def\tikzumlState@orig{texttmp}%
+ \fi%
+ \node[above] (\tikzumlState@nodeName-captiontmp) at (\tikzumlState@nodeName-\tikzumlState@orig.north) {\tikzumlState@caption};%
+ \ifnum\c@tikzumlStateText=1%
+ \node[rounded corners, draw=\tikzumlStateDrawColor, fill=\tikzumlStateFillColor, name=\tikzumlState@nodeName, fit=(\tikzumlState@nodeName-body) (\tikzumlState@nodeName-texttmp) (\tikzumlState@nodeName-captiontmp)] {};%
+ \else%
+ \node[rounded corners, draw=\tikzumlStateDrawColor, fill=\tikzumlStateFillColor, name=\tikzumlState@nodeName, fit=(\tikzumlState@nodeName-body) (\tikzumlState@nodeName-captiontmp)] {};%
+ \fi%
+ \ifnum\c@tikzumlStateText=1%
+ \node (\tikzumlState@nodeName-text) at (\tikzumlState@nodeName-texttmp) {\begin{tabular}{l}\tikzumlStateText \end{tabular}};%
+ \fi%
+ \node (\tikzumlState@nodeName-caption) at (\tikzumlState@nodeName-captiontmp) {\tikzumlState@caption};%
+ \draw (\tikzumlState@nodeName-caption.south -| \tikzumlState@nodeName.north west) -- (\tikzumlState@nodeName-caption.south -| \tikzumlState@nodeName.north east);%
+ \end{pgfonlayer}%
+ \end{scope}%
+}%
+%
+% shortcut for empty state
+\newcommand{\umlbasicstate}[2][]{\begin{umlstate}[#1]{#2}\end{umlstate}}%
+%
+% command to add text in a state, to be used inside umlstate environment
+\newcommand{\umlstatetext}[1]{%
+ \def\tikzumlStateText{#1}%
+ \setcounter{tikzumlStateText}{1}%
+}%
+%
+% shortcuts for state transitions macros
+\newcommand{\umltrans}[3][]{%
+ \ifthenelse{\equal{#2}{#3}}{%
+ \umlrelation[style={tikzuml transition style}, recursive mode=transition, #1]{#2}{#3}%
+ }{%
+ \umlrelation[style={tikzuml transition style}, #1]{#2}{#3}%
+ }%
+}%
+\newcommand{\umlHVtrans}[3][]{\umlHVrelation[style={tikzuml transition style}, #1]{#2}{#3}}%
+\newcommand{\umlVHtrans}[3][]{\umlVHrelation[style={tikzuml transition style}, #1]{#2}{#3}}%
+\newcommand{\umlVHVtrans}[3][]{\umlVHVrelation[style={tikzuml transition style}, #1]{#2}{#3}}%
+\newcommand{\umlHVHtrans}[3][]{\umlHVHrelation[style={tikzuml transition style}, #1]{#2}{#3}}%
+\newcommand{\umlCNtrans}[4][]{\umlCNrelation[style={tikzuml transition style}, #1]{#2}{#3}{#4}}%
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% sequence diagrams %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+\tikzstyle{tikzuml synchron-msg style}=[color=\tikzumlDefaultDrawColor, -triangle 45]%
+\tikzstyle{tikzuml asynchron-msg style}=[color=\tikzumlDefaultDrawColor, -angle 45]%
+\tikzstyle{tikzuml return-msg style}=[color=\tikzumlDefaultDrawColor, dashed, -angle 45]%
+\tikzstyle{tikzuml call return style}=[color=\tikzumlDefaultDrawColor, dashed, -angle 45]%
+\tikzstyle{tikzuml activity style}=[inner xsep=1ex, inner ysep=1ex]%
+%
+\newcounter{tikzumlObjectNum}%
+\newcounter{tikzumlCallLevel}%
+\newcounter{tikzumlCallNum}%
+\newcounter{tikzumlFragmentLevel}%
+\newcounter{tikzumlFragmentLevelNum}%
+\newcounter{tikzumlFragmentNum}%
+\newcounter{tikzumlFragmentPartNum}%
+\newcounter{tikzumlCallStartFragmentNum}%
+\newcounter{tikzumlCallEndFragmentNum}%
+%
+\newif\iftikzumlobjectNoDDots%
+\newif\iftikzumlcreatecallNoDDots%
+%
+% define a sequence diagram
+%
+\newenvironment{umlseqdiag}{%
+ \gdef\tikzumlInCreateCall{0}%
+ \setcounter{tikzumlObjectNum}{0}%
+ \setcounter{tikzumlCallLevel}{0}%
+ \setcounter{tikzumlCallNum}{0}%
+ \setcounter{tikzumlFragmentLevel}{0}%
+ \setcounter{tikzumlFragmentLevelNum}{0}%
+ \setcounter{tikzumlFragmentNum}{0}%
+ \setcounter{tikzumlFragmentPartNum}{0}%
+ \setcounter{tikzumlCallStartFragmentNum}{0}%
+ \setcounter{tikzumlCallEndFragmentNum}{0}%
+ %
+ \ifx \@umlactor \@empty
+ \newcommand{\umlactor}[2][]{%
+ \pgfkeys{/tikzuml/actorobj/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlactor, forbidden option stereo}%
+ }{}%
+ }%
+ }%
+ %
+ \pgfkeys{/tikzuml/actorobj/.cd, ##1}%
+ \umlobject[stereo=actor, ##1]{##2}%
+ }%
+ \else%
+ \renewcommand{\umlactor}[2][]{%
+ \pgfkeys{/tikzuml/actorobj/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlactor, forbidden option stereo}%
+ }{}%
+ }%
+ }%
+ %
+ \pgfkeys{/tikzuml/actorobj/.cd, ##1}%
+ \umlobject[stereo=actor, ##1]{##2}%
+ }%
+ \fi%
+ \begin{scope}[font=\tikzumlDefaultFont]%
+}{%
+ % draw lifelines of each object
+ \begin{pgfonlayer}{lifelines}%
+ \foreach \id in \tikzumlIdList {%
+ \draw (\csname tikzumlLastChild@\id \endcsname)+(0,-2.5ex) node[inner sep=0, name=end-\id] {};%
+ \draw[dotted] (\id) -- (end-\id);%
+ }%
+ \end{pgfonlayer}%
+ \end{scope}%
+}%
+%
+% define the database symbol
+% optional : global tikzpicture styles
+\newcommand{\pictureddatabase}[1]{%
+ \pgfkeys{/tikzuml/database/.cd, scale/.initial=1, .unknown/.code={}}%
+ \pgfkeys{/tikzuml/database/.cd,#1}%
+ \pgfkeys{/tikzuml/database/.cd, scale/.get=\tikzumlDatabaseScale}%
+ %
+ \begin{tikzpicture}[#1]%
+ \node[fill, draw, ellipse, minimum width=\tikzumlDatabaseScale*4ex, minimum height=\tikzumlDatabaseScale*2ex, inner sep=0] (bottom) at (0,-2ex) {};%
+ \node[fill, draw, ellipse, minimum width=\tikzumlDatabaseScale*4ex, minimum height=\tikzumlDatabaseScale*2ex, inner sep=0] (top) at (0,4ex) {};%
+ \fill (bottom.west) rectangle (top.east);%
+ \begin{scope}%
+ \clip (-3.5ex,-0.5ex) rectangle (3.5ex,2.5ex);%
+ \node[draw, dashed, ellipse, minimum width=\tikzumlDatabaseScale*4ex, minimum height=\tikzumlDatabaseScale*2ex, inner sep=0] (bottom2) at (0,-2ex) {};%
+ \end{scope}%
+ \node[draw, ellipse, minimum width=\tikzumlDatabaseScale*4ex, minimum height=\tikzumlDatabaseScale*2ex, inner sep=0] (top2) at (0,4ex) {};%
+ \draw (bottom.west) -- (top.west) (bottom.east) -- (top.east);%
+ \end{tikzpicture}%
+}%
+%
+% define the entity symbol
+% optional : global tikzpicture styles
+\newcommand{\picturedentity}[1]{%
+ \pgfkeys{/tikzuml/entity/.cd, scale/.initial=1, .unknown/.code={}}%
+ \pgfkeys{/tikzuml/entity/.cd,#1}%
+ \pgfkeys{/tikzuml/entity/.cd, scale/.get=\tikzumlEntityScale}%
+ %
+ \begin{tikzpicture}[#1]%
+ \node[fill, draw, circle, inner sep=0, minimum size=\tikzumlEntityScale*5ex] (center) at (0,0) {};%
+ \draw (center.south) node[coordinate, name=bottom] {};%
+ \draw (bottom)+(-2ex,0) node[coordinate, name=bottom-left] {};%
+ \draw (bottom)+(2ex,0) node[coordinate, name=bottom-right] {};%
+ \draw (center) -- (bottom);%
+ \draw (bottom-left) -- (bottom-right);%
+ \end{tikzpicture}%
+}%
+%
+% define the boundary symbol
+% optional : global tikzpicture styles
+\newcommand{\picturedboundary}[1]{%
+ \pgfkeys{/tikzuml/boundary/.cd, scale/.initial=1, .unknown/.code={}}%
+ \pgfkeys{/tikzuml/boundary/.cd,#1}%
+ \pgfkeys{/tikzuml/boundary/.cd, scale/.get=\tikzumlBoundaryScale}%
+ %
+ \begin{tikzpicture}[#1]
+ \node[fill, draw, circle, inner sep=0, minimum size=\tikzumlBoundaryScale*5ex] (center) at (0,0) {};
+ \draw (center.west)+(-0.8ex,0) node[coordinate, name=left] {};
+ \draw (left)+(0,0.2ex) node[coordinate, name=left-top] {};
+ \draw (left)+(0,-0.2ex) node[coordinate, name=left-bottom] {};
+ \draw (center) -- (left);
+ \draw (left-top) -- (left-bottom);
+ \end{tikzpicture}
+}%
+%
+% define the control symbol
+% optional : global tikzpicture styles
+\newcommand{\picturedcontrol}[1]{%
+ \pgfkeys{/tikzuml/control/.cd, scale/.initial=1, .unknown/.code={}}%
+ \pgfkeys{/tikzuml/control/.cd,#1}%
+ \pgfkeys{/tikzuml/control/.cd, scale/.get=\tikzumlControlScale}%
+ %
+ \begin{tikzpicture}[#1, decoration={markings, mark=at position 0.25 with {\arrow{>}}}]
+ \node[fill, draw, circle, inner sep=0, minimum size=\tikzumlControlScale*5ex, postaction={decorate}] (center) at (0,0) {};
+ \end{tikzpicture}
+}%
+%
+% define a uml object for a sequence diagram
+% args : name of the object
+% optional : x, y: coordinates of the object
+% stereo: stereotype of the object (object, actor, database, boundary, control, entity, multiobject)
+% class: class of the object
+% scale: scale factor of the object symbol
+% draw, fill, text; colors
+% no ddots: when used, disable printing of double dots
+\newcommand{\umlobject}[2][]{
+ \stepcounter{tikzumlObjectNum}%
+ %
+ \edef\tikzumlobject@ddot{:}%
+ \pgfkeys{/tikzuml/obj/.cd, x/.initial=tikzumlEmpty, y/.initial=\tikzumlDefaultX, stereo/.initial=\tikzumlObjectDefaultStereo,%
+ class/.initial={}, scale/.initial=1,%
+ draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlObjectDefaultFillColor,%
+ text/.initial=\tikzumlDefaultTextColor,%
+ no ddots/.is if=tikzumlobjectNoDDots,%
+ no ddots=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \errmessage{TIKZUML ERROR : in umlobject, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/obj/.cd, #1}%
+ \pgfkeys{/tikzuml/obj/.cd, x/.get=\tikzumlObjectX, y/.get=\tikzumlObjectY,%
+ stereo/.get=\tikzumlObjectStereo, class/.get=\tikzumlObjectClass,%
+ scale/.get=\tikzumlObjectScale,%
+ draw/.get=\tikzumlObjectDrawColor, fill/.get=\tikzumlObjectFillColor,%
+ text/.get=\tikzumlObjectTextColor%
+ }%
+ %
+ \iftikzumlobjectNoDDots%
+ \edef\tikzumlobject@ddot{}%
+ \fi%
+ %
+ \ifthenelse{\equal{\tikzumlObjectX}{tikzumlEmpty}}{%
+ \pgfmathsetmacro{\tikzumlObjectX}{4*(\thetikzumlObjectNum-1)}%
+ }{}%
+ %
+ \def\tikzumlObjectName{#2}%
+ \expandafter\xdef\csname tikzumlLastChild@\tikzumlObjectName \endcsname{\tikzumlObjectName}%
+ %
+ \ifnum\thetikzumlObjectNum=1%
+ \xdef\tikzumlIdList{\tikzumlObjectName}%
+ \else%
+ \let\tikzumlIdListOld\tikzumlIdList%
+ \expandafter\xdef\expandafter\tikzumlIdList\expandafter{\tikzumlIdListOld,\tikzumlObjectName}%
+ \fi%
+ %
+ \tikzstyle{tikzuml object box style}=[rectangle, text=\tikzumlObjectTextColor, font=\tikzumlDefaultFont]%
+ %
+ \ifthenelse{\equal{\tikzumlObjectStereo}{object}}{%
+ \tikzstyle{tikzuml object box style}+=[draw=\tikzumlObjectDrawColor, fill=\tikzumlObjectFillColor]%
+ }{%
+ \ifthenelse{\equal{\tikzumlObjectStereo}{multi}}{%
+ \tikzstyle{tikzuml object box style}+=[fill=\tikzumlObjectFillColor]%
+ }{}%
+ }%
+ %
+ \ifnum\tikzumlInCreateCall=1%
+ \draw (\tikzumlCreateCallObjectSrc -| \tikzumlObjectX,0) node[tikzuml object box style] (\tikzumlObjectName) {\tikzumlObjectName\tikzumlobject@ddot\tikzumlObjectClass};%
+ \else%
+ \node[tikzuml object box style] (\tikzumlObjectName) at (\tikzumlObjectX,\tikzumlObjectY) {\tikzumlObjectName\tikzumlobject@ddot\tikzumlObjectClass};%
+ \fi%
+ %
+ \ifthenelse{\equal{\tikzumlObjectStereo}{multi}}{%
+ \draw (\tikzumlObjectName.north east)+(0.4ex,0.4ex) node[name=\tikzumlObjectName-tr, coordinate] {};
+ \draw (\tikzumlObjectName.north west)+(0.4ex,0.4ex) node[name=\tikzumlObjectName-tl, coordinate] {};
+ \draw (\tikzumlObjectName.south east)+(0.4ex,0.4ex) node[name=\tikzumlObjectName-br, coordinate] {};
+ \draw (\tikzumlObjectName-tr)+(0.4ex,0.4ex) node[name=\tikzumlObjectName-ttr, coordinate] {};
+ \draw (\tikzumlObjectName-tl)+(0.4ex,0.4ex) node[name=\tikzumlObjectName-ttl, coordinate] {};
+ \draw (\tikzumlObjectName-br)+(0.4ex,0.4ex) node[name=\tikzumlObjectName-tbr, coordinate] {};
+ \fill[fill=\tikzumlObjectFillColor] (\tikzumlObjectName-ttl |- \tikzumlObjectName.north) -- (\tikzumlObjectName-ttl) -- (\tikzumlObjectName-ttr) -- (\tikzumlObjectName-tbr) -- (\tikzumlObjectName-tbr -| \tikzumlObjectName.east) -- (\tikzumlObjectName.north east) -- (\tikzumlObjectName-ttl |- \tikzumlObjectName.north);
+ \draw[draw=\tikzumlObjectDrawColor] (\tikzumlObjectName-ttl |- \tikzumlObjectName.north) -- (\tikzumlObjectName-ttl) -- (\tikzumlObjectName-ttr) -- (\tikzumlObjectName-tbr) -- (\tikzumlObjectName-tbr -| \tikzumlObjectName.east);
+ \fill[fill=\tikzumlObjectFillColor] (\tikzumlObjectName-tl |- \tikzumlObjectName.north) -- (\tikzumlObjectName-tl) -- (\tikzumlObjectName-tr) -- (\tikzumlObjectName-br) -- (\tikzumlObjectName-br -| \tikzumlObjectName.east) -- (\tikzumlObjectName.north east) -- (\tikzumlObjectName-tl |- \tikzumlObjectName.north);
+ \draw[draw=\tikzumlObjectDrawColor] (\tikzumlObjectName-tl |- \tikzumlObjectName.north) -- (\tikzumlObjectName-tl) -- (\tikzumlObjectName-tr) -- (\tikzumlObjectName-br) -- (\tikzumlObjectName-br -| \tikzumlObjectName.east);
+ \draw[draw=\tikzumlObjectDrawColor] (\tikzumlObjectName.north west) rectangle (\tikzumlObjectName.south east);
+ }{%
+ \ifthenelse{\equal{\tikzumlObjectStereo}{object}}{}{%
+ \node[above=1ex, name=\tikzumlObjectName-picture] at (\tikzumlObjectName) {\csname pictured\tikzumlObjectStereo \endcsname{draw=\tikzumlObjectDrawColor, fill=\tikzumlObjectFillColor, scale=\tikzumlObjectScale}};
+ }%
+ }%
+}%
+%
+% shortcuts for objects
+\newcommand{\umlbasicobject}[2][]{%
+ \pgfkeys{/tikzuml/basicobj/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{no ddots}}{%
+ \errmessage{TIKZUML ERROR : in umlbasicobject, forbidden option no ddots}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/basicobj/.cd, #1}%
+ \umlobject[no ddots, #1]{#2}%
+}%
+%
+\newcommand{\umldatabase}[2][]{%
+ \pgfkeys{/tikzuml/databaseobj/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umldatabase, forbidden option stereo}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/databaseobj/.cd, #1}%
+ \umlobject[stereo=database, #1]{#2}%
+}%
+\newcommand{\umlentity}[2][]{%
+ \pgfkeys{/tikzuml/entityobj/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlentity, forbidden option stereo}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/entityobj/.cd, #1}%
+ \umlobject[stereo=entity, #1]{#2}%
+}%
+\newcommand{\umlcontrol}[2][]{%
+ \pgfkeys{/tikzuml/controlobj/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlcontrol, forbidden option stereo}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/controlobj/.cd, #1}%
+ \umlobject[stereo=control, #1]{#2}%
+}%
+\newcommand{\umlboundary}[2][]{%
+ \pgfkeys{/tikzuml/boundaryobj/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlboundary, forbidden option stereo}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/boundaryobj/.cd, #1}%
+ \umlobject[stereo=boundary, #1]{#2}%
+}%
+\newcommand{\umlmulti}[2][]{%
+ \pgfkeys{/tikzuml/multiobj/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlmulti, forbidden option stereo}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/multiobj/.cd, #1}%
+ \umlobject[stereo=multi, #1]{#2}%
+}%
+%
+\newcounter{tikzumlSDNodeNum}%
+%
+% define a hidden node to lengthen lifeline of a object
+% args : object node
+% optional : dt: distance between the sdnode and the last call defined on the lifeline of the object
+% name: name of the sdnode
+\newcommand{\umlsdnode}[2][]{%
+ \pgfkeys{/tikzuml/sdnode/.cd, dt/.initial=0, name/.initial=tikzumlEmpty}%
+ \pgfkeys{/tikzuml/sdnode/.cd, #1}%
+ \pgfkeys{/tikzuml/sdnode/.cd, dt/.get=\tikzumlSDNodeDT, name/.get=\tikzumlSDNodeName}%
+ %
+ \ifthenelse{\equal{\tikzumlSDNodeName}{tikzumlEmpty}}{%
+ \expandafter\def\expandafter\tikzumlSDNode@nodeName{sdnode-\thetikzumlSDNodeNum}%
+ }{%
+ \expandafter\def\expandafter\tikzumlSDNode@nodeName{\tikzumlSDNodeName}%
+ }%
+ %
+ \stepcounter{tikzumlSDNodeNum}%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlSDNode@objnodeName{#2}}\x%
+ %
+ \draw (\expandafter\csname tikzumlLastChild@\tikzumlSDNode@objnodeName \endcsname)+(0,-\tikzumlSDNodeDT ex) node[name=\tikzumlSDNode@nodeName,coordinate] {};%
+ %
+ % update last node drawn on sender lifeline
+ \expandafter\xdef\csname tikzumlLastChild@\tikzumlSDNode@objnodeName \endcsname{\tikzumlSDNode@nodeName}%
+}%
+%
+\newlength{\tikzumlCall@xa}%
+\newlength{\tikzumlCall@xb}%
+%
+% define a uml operation call for sequence diagrams
+% args : call sender
+% call receiver
+% optional : dt: time delay from precedent event end
+% name: name of the call
+% op: operation name and input args
+% return: return value
+% type: type of the call (synchron, asynchron)
+% draw, fill, text: colors
+% padding: time padding from call start and to call end
+\newenvironment{umlcall}[3][]{%
+ \stepcounter{tikzumlCallNum}%
+ \def\tikzumlCallWithReturn{tikzumlFalse}%
+ \edef\tikzumlCall@lastchildNum{\thetikzumlCallNum}% for testing presence of sub-calls
+ \gdef\tikzumlCallBottom{0}%
+ %
+ \pgfkeys{/tikzuml/call/.cd, dt/.initial=\tikzumlCallDefaultDT, name/.initial={call-\thetikzumlCallNum},%
+ op/.initial={}, return/.initial={}, type/.initial=\tikzumlCallDefaultType,%
+ draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlCallDefaultFillColor,%
+ text/.initial=\tikzumlDefaultTextColor,%
+ padding/.initial=\tikzumlCallDefaultPadding,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{with return}}{%
+ \def\tikzumlCallWithReturn{tikzumlTrue}%
+ }{%
+ \errmessage{TIKZUML ERROR : in umlcall, invalid option \keyname}%
+ }%
+ }%
+ }%
+ \pgfkeys{/tikzuml/call/.cd, #1}%
+ \pgfkeys{/tikzuml/call/.cd, dt/.get=\tikzumlCallDT, name/.get=\tikzumlCallName, op/.get=\tikzumlCallOp,%
+ return/.get=\tikzumlCallReturn, type/.get=\tikzumlCallType,%
+ padding/.get=\tikzumlCallPadding,%
+ draw/.get=\tikzumlCallDrawColor, fill/.get=\tikzumlCallFillColor,%
+ text/.get=\tikzumlCallTextColor%
+ }%
+ %
+ \edef\tikzumlfillcall{\tikzumlCallFillColor}%
+ \edef\tikzumldrawcall{\tikzumlCallDrawColor}%
+ \edef\tikzumltextcall{\tikzumlCallTextColor}%
+ \edef\tikzumltypecall{\tikzumlCallType}%
+ %
+ \ifthenelse{\equal{\tikzumlCallDT}{tikzumlEmpty}}{%
+ \ifnum\thetikzumlCallNum=1%
+ \def\tikzumlCallDT{2}%
+ \def\tikzumlcallSrc{2}%
+ \else%
+ \def\tikzumlCallDT{2}%
+ \def\tikzumlcallSrc{1}%
+ \fi%
+ }{%
+ \def\tikzumlcallSrc{0}%
+ }%
+ %
+ \let\tikzumlCallStartNodeNameold\tikzumlCallStartNodeName%
+ \def\tikzumlCallStartNodeName{#2}%
+ \let\tikzumlCallEndNodeNameold\tikzumlCallEndNodeName%
+ \def\tikzumlCallEndNodeName{#3}%
+ \def\tikzumlcallheight{\tikzumlCallPadding}%
+ %
+ % managing time delays from previous/parent fragments
+ \ifnum\thetikzumlCallStartFragmentNum>0%
+ \let\tikzumlCallDTold\tikzumlCallDT%
+ \pgfmathparse{0.5*\tikzumlFragment@paddingy+\tikzumlCallDTold}%
+ \edef\tikzumlCallDT{\pgfmathresult}%
+ \addtocounter{tikzumlCallStartFragmentNum}{-1}
+ \fi%
+ \ifnum\thetikzumlCallEndFragmentNum>0%
+ \let\tikzumlCallDTold\tikzumlCallDT%
+ \pgfmathparse{0.5*\tikzumlFragment@paddingy+\tikzumlCallDTold}%
+ \edef\tikzumlCallDT{\pgfmathresult}%
+ \addtocounter{tikzumlCallEndFragmentNum}{-1}
+ \fi%
+ \ifnum\thetikzumlFragmentPartNum>0%
+ \let\tikzumlCallDTold\tikzumlCallDT%
+ \pgfmathparse{0.5*\tikzumlFragment@paddingy+\tikzumlCallDTold}%
+ \edef\tikzumlCallDT{\pgfmathresult}%
+ \fi%
+ %
+ % managing parent-child structure
+ \ifnum\thetikzumlCallLevel>0%
+ \let\tikzumlCall@nameold\tikzumlCall@name%
+ \edef\tikzumlCall@name{\tikzumlCallName}%
+ \let\tikzumlCall@parentold\tikzumlCall@parent%
+ \edef\tikzumlCall@parent{\tikzumlCall@parentold @@\tikzumlCall@nameold}%
+ \else%
+ \edef\tikzumlCall@parent{}%
+ \edef\tikzumlCall@parentold{}%
+ \edef\tikzumlCall@nameold{}
+ \edef\tikzumlCall@name{\tikzumlCallName}%
+ \fi%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlCall@nodeName{\tikzumlCall@name}}\x%
+ %
+ \let\tikzumlCall@nodeNameold\tikzumlCall@nodeName%
+ %
+ \def\tikzumlcallstyle{tikzuml \tikzumlCallType-msg style}%
+ %
+ % top node of activity period of call sender
+ \begin{pgfonlayer}{connections}%
+ \pgfmathparse{\tikzumlCallDT+\tikzumlcallSrc}%
+ \draw (\csname tikzumlLastChild@\tikzumlCallStartNodeName \endcsname)+(0,-\pgfmathresult ex) node[coordinate, name=tikzumlTmpNode] {};%
+ \node[tikzuml activity style] (st-\tikzumlCall@nodeName) at (\tikzumlCallStartNodeName |- tikzumlTmpNode) {};%
+ %
+ % update last node drawn on sender lifeline
+ \expandafter\xdef\csname tikzumlLastChild@\tikzumlCallStartNodeName \endcsname{st-\tikzumlCall@nodeName}%
+ %
+ % top node of activity period of call receiver
+ \ifstrequal{\tikzumlCallStartNodeName}{\tikzumlCallEndNodeName}{%
+ \draw (st-\tikzumlCall@nodeName)+(0,-0.75*\tikzumlCallPadding ex) node[coordinate, name=tikzumlTmpNode] {};%
+ \node[tikzuml activity style] (et-\tikzumlCall@nodeName) at (\tikzumlCallStartNodeName |- tikzumlTmpNode) {};%
+ }{%
+ \node[tikzuml activity style] (et-\tikzumlCall@nodeName) at (\tikzumlCallEndNodeName |- st-\tikzumlCall@nodeName) {};%
+ }%
+ %
+ % update last node drawn on receiver lifeline
+ \expandafter\xdef\csname tikzumlLastChild@\tikzumlCallEndNodeName \endcsname{et-\tikzumlCall@nodeName}%
+ \xdef\tikzumlCallBottomSrc{et-\tikzumlCall@nodeName}%
+ \end{pgfonlayer}%
+ %
+ \stepcounter{tikzumlCallLevel}%
+}{%
+ \addtocounter{tikzumlCallLevel}{-1}%
+ %
+ % bottom nodes of activity periods of call sender and receiver
+ \begin{pgfonlayer}{connections}%
+ \ifnum\tikzumlCall@lastchildNum=\thetikzumlCallNum%
+ %
+ % this test occurs a bug with latex package preview
+ \ifstrequal{\tikzumlCallStartNodeName}{\tikzumlCallEndNodeName}{%
+ \draw (\tikzumlCallBottomSrc)+(0,-\tikzumlCallPadding ex) node[coordinate, name=tikzumlTmpNode] {};%
+ \node[tikzuml activity style] (eb-\tikzumlCall@nodeName) at (\tikzumlCallEndNodeName |- tikzumlTmpNode) {};%
+ \draw (eb-\tikzumlCall@nodeName)+(0,-0.75*\tikzumlCallPadding ex) node[coordinate, name=tikzumlTmpNode] {};%
+ \node[tikzuml activity style] (sb-\tikzumlCall@nodeName) at (\tikzumlCallStartNodeName |- tikzumlTmpNode) {};%
+ }{%
+ \ifthenelse{\equal{\tikzumlCallReturn}{tikzumlEmpty}}{%
+ \pgfmathsetmacro{\tikzumlCallPaddingd}{0.5*\tikzumlCallPadding}%
+ }{%
+ \pgfmathsetmacro{\tikzumlCallPaddingd}{1.2*\tikzumlCallPadding}%
+ }%
+ \draw (\tikzumlCallBottomSrc)+(0,-\tikzumlCallPaddingd ex) node[coordinate, name=tikzumlTmpNode] {};%
+ \node[tikzuml activity style] (eb-\tikzumlCall@nodeName) at (\tikzumlCallEndNodeName |- tikzumlTmpNode) {};%
+ \node[tikzuml activity style] (sb-\tikzumlCall@nodeName) at (\tikzumlCallStartNodeName |- eb-\tikzumlCall@nodeName) {};%
+ }%
+ \xdef\tikzumlCallBottomSrc{sb-\tikzumlCall@nodeName}%
+ \else%
+ %
+ % managing time delays from previous/parent fragments
+ \ifnum\thetikzumlCallStartFragmentNum>0%
+ \let\tikzumlcallheightold\tikzumlCallPadding%
+ \pgfmathparse{\tikzumlcallheightold+0.5*\tikzumlFragment@paddingy}%
+ \edef\tikzumlcallheight{\pgfmathresult}%
+ \addtocounter{tikzumlCallStartFragmentNum}{-1}%
+ \fi%
+ \ifnum\thetikzumlCallEndFragmentNum>0%
+ \let\tikzumlcallheightold\tikzumlCallPadding%
+ \pgfmathparse{\tikzumlcallheightold+0.5*\tikzumlFragment@paddingy}%
+ \edef\tikzumlcallheight{\pgfmathresult}%
+ \addtocounter{tikzumlCallEndFragmentNum}{-1}%
+ \fi%
+ %
+ \ifstrequal{\tikzumlCallStartNodeName}{\tikzumlCallEndNodeName}{%
+ \draw (\tikzumlCallBottomSrc)+(0,-\tikzumlcallheight ex) node[coordinate, name=tikzumlTmpNode] {};%
+ \node[tikzuml activity style] (eb-\tikzumlCall@nodeName) at (\tikzumlCallEndNodeName |- tikzumlTmpNode) {};%
+ \draw (eb-\tikzumlCall@nodeName)+(0,-0.75*\tikzumlCallPadding ex) node[coordinate, name=tikzumlTmpNode] {};%
+ \node[tikzuml activity style] (sb-\tikzumlCall@nodeName) at (\tikzumlCallStartNodeName |- tikzumlTmpNode) {};%
+ }{%
+ \draw (\tikzumlCallBottomSrc)+(0,-\tikzumlcallheight ex) node[coordinate, name=tikzumlTmpNode] {};%
+ \node[tikzuml activity style] (eb-\tikzumlCall@nodeName) at (\tikzumlCallEndNodeName |- tikzumlTmpNode) {};%
+ \node[tikzuml activity style] (sb-\tikzumlCall@nodeName) at (\tikzumlCallStartNodeName |- eb-\tikzumlCall@nodeName) {};%
+ }%
+ %
+ \xdef\tikzumlCallBottomSrc{sb-\tikzumlCall@nodeName}%
+ \fi%
+ \end{pgfonlayer}%
+ %
+ % draw activity periods
+ \begin{pgfonlayer}{activity}%
+ \ifstrequal{\tikzumlCallStartNodeName}{\tikzumlCallEndNodeName}{%
+ % draw root activity period only
+ \ifnum\thetikzumlCallLevel=0%
+ \draw[draw=\tikzumldrawcall, fill=\tikzumlfillcall] (st-\tikzumlCall@nodeName.north west) rectangle (sb-\tikzumlCall@nodeName.south east);%
+ \else%
+ % draw root activity from inner call
+ \ifthenelse{\equal{\tikzumlCallStartNodeName}{\tikzumlCallEndNodeNameold}}{}{%
+ \draw[draw=\tikzumldrawcall, fill=\tikzumlfillcall] (st-\tikzumlCall@nodeName.north west) rectangle (sb-\tikzumlCall@nodeName.south east);%
+ }%
+ \fi%
+ }{%
+ % draw root activity period
+ \ifnum\thetikzumlCallLevel=0%
+ \draw[draw=\tikzumldrawcall, fill=\tikzumlfillcall] (st-\tikzumlCall@nodeName.north west) rectangle (sb-\tikzumlCall@nodeName.south east);%
+ \else%
+ % draw root activity from inner call
+ \ifthenelse{\equal{\tikzumlCallStartNodeName}{\tikzumlCallEndNodeNameold}}{}{%
+ \draw[draw=\tikzumldrawcall, fill=\tikzumlfillcall] (st-\tikzumlCall@nodeName.north west) rectangle (sb-\tikzumlCall@nodeName.south east);%
+ }%
+ \fi%
+ % draw receiver activity period
+ \draw[draw=\tikzumldrawcall, fill=\tikzumlfillcall] (et-\tikzumlCall@nodeName.north west) rectangle (eb-\tikzumlCall@nodeName.south east);%
+ }%
+ \end{pgfonlayer}%
+ \ifthenelse{\equal{\tikzumlCallDefaultFillColor}{\tikzumlCallFillColor}}{}{%
+ \fill[\tikzumlfillcall] (st-\tikzumlCall@nodeName.north west) rectangle (sb-\tikzumlCall@nodeName.south east);%
+ \draw[\tikzumldrawcall] (st-\tikzumlCall@nodeName.north west) rectangle (sb-\tikzumlCall@nodeName.south west) (st-\tikzumlCall@nodeName.north east) rectangle (sb-\tikzumlCall@nodeName.south east);%
+ }%
+ %
+ % update last nodes drawn on sender and receiver lifelines
+ \expandafter\xdef\csname tikzumlLastChild@\tikzumlCallEndNodeName \endcsname{eb-\tikzumlCall@nodeName}%
+ \expandafter\xdef\csname tikzumlLastChild@\tikzumlCallStartNodeName \endcsname{sb-\tikzumlCall@nodeName}%
+ %
+ % draw call arrows
+ \begin{pgfonlayer}{connections}%
+ \ifstrequal{\tikzumlCallStartNodeName}{\tikzumlCallEndNodeName}{%
+ \draw[\tikzumlcallstyle, \tikzumldrawcall] (st-\tikzumlCall@nodeName.east) -- ++(2.5*\tikzumlCallPadding ex,0) %
+ -- ++(0,-0.75*\tikzumlCallPadding ex) %
+ node[font=\tikzumlDefaultFont, text=\tikzumltextcall, midway, right, name=\tikzumlCall@nodeName-op] {\tikzumlCallOp} %
+ -- (et-\tikzumlCall@nodeName.east);%
+ %
+ % draw return arrow and update fit for parent fragment
+ \ifthenelse{\equal{\tikzumltypecall}{synchron}}{%
+ \ifthenelse{\NOT\equal{\tikzumlCallReturn}{}\OR\equal{\tikzumlCallWithReturn}{tikzumlTrue}}{%
+ \ifnum\c@tikzumlFragmentLevel>0%
+ \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname}%
+ \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{\tikzumlFragmentFitOld (st-\tikzumlCall@nodeName) (et-\tikzumlCall@nodeName) (eb-\tikzumlCall@nodeName) (sb-\tikzumlCall@nodeName) (\tikzumlCall@nodeName-op) (\tikzumlCall@nodeName-return)}%
+ \fi%
+ %
+ \draw[tikzuml call return style, \tikzumldrawcall] (eb-\tikzumlCall@nodeName.east) -- ++(2.5*\tikzumlCallPadding ex,0)
+ -- ++(0,-0.75*\tikzumlCallPadding ex) %
+ node[font=\tikzumlDefaultFont, text=\tikzumltextcall, midway, right, name=\tikzumlCall@nodeName-return] {\tikzumlCallReturn} %
+ -- (sb-\tikzumlCall@nodeName.east);%
+ }{%
+ \ifnum\c@tikzumlFragmentLevel>0%
+ \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname}%
+ \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{\tikzumlFragmentFitOld (st-\tikzumlCall@nodeName) (et-\tikzumlCall@nodeName) (eb-\tikzumlCall@nodeName) (sb-\tikzumlCall@nodeName) (\tikzumlCall@nodeName-op)}%
+ \fi%
+ }%
+ }{%
+ \ifnum\c@tikzumlFragmentLevel>0%
+ \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname}%
+ \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{\tikzumlFragmentFitOld (st-\tikzumlCall@nodeName) (et-\tikzumlCall@nodeName) (eb-\tikzumlCall@nodeName) (sb-\tikzumlCall@nodeName) (\tikzumlCall@nodeName-op)}%
+ \fi%
+ }%
+ }{%
+ % draw call arrows
+ \pgfextractx{\tikzumlCall@xa}{\pgfpointanchor{\tikzumlCallStartNodeName}{center}}%
+ \pgfextractx{\tikzumlCall@xb}{\pgfpointanchor{\tikzumlCallEndNodeName}{center}}%
+ %
+ \ifthenelse{\tikzumlCall@xb>\tikzumlCall@xa}{%
+ \draw[\tikzumlcallstyle, \tikzumldrawcall] (st-\tikzumlCall@nodeName.east) -- (et-\tikzumlCall@nodeName.west) %
+ node[font=\tikzumlDefaultFont, text=\tikzumltextcall, midway, above=-0.4ex, name=\tikzumlCall@nodeName-op] {\tikzumlCallOp};%
+ }{%
+ \draw[\tikzumlcallstyle, \tikzumldrawcall] (st-\tikzumlCall@nodeName.west) -- (et-\tikzumlCall@nodeName.east) %
+ node[font=\tikzumlDefaultFont, text=\tikzumltextcall, midway, above=-0.4ex, name=\tikzumlCall@nodeName-op] {\tikzumlCallOp};%
+ }%
+ %
+ % draw return arrow and update fit for parent fragment
+ \ifthenelse{\equal{\tikzumltypecall}{synchron}}{%
+ \ifthenelse{\NOT\equal{\tikzumlCallReturn}{}\OR\equal{\tikzumlCallWithReturn}{tikzumlTrue}}{%
+ \ifnum\c@tikzumlFragmentLevel>0%
+ \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname}%
+ \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{\tikzumlFragmentFitOld (st-\tikzumlCall@nodeName) (et-\tikzumlCall@nodeName) (eb-\tikzumlCall@nodeName) (sb-\tikzumlCall@nodeName) (\tikzumlCall@nodeName-op) (\tikzumlCall@nodeName-return)}%
+ \fi%
+ %
+ \ifthenelse{\tikzumlCall@xb>\tikzumlCall@xa}{%
+ \draw[tikzuml call return style, \tikzumldrawcall] (eb-\tikzumlCall@nodeName.west) -- (sb-\tikzumlCall@nodeName.east) %
+ node[font=\tikzumlDefaultFont, text=\tikzumltextcall, midway, above=-0.4ex, name=\tikzumlCall@nodeName-return] {\tikzumlCallReturn};%
+ }{%
+ \draw[tikzuml call return style, \tikzumldrawcall] (eb-\tikzumlCall@nodeName.east) -- (sb-\tikzumlCall@nodeName.west) %
+ node[font=\tikzumlDefaultFont, text=\tikzumltextcall, midway, above=-0.4ex, name=\tikzumlCall@nodeName-return] {\tikzumlCallReturn};%
+ }%
+ }{%
+ \ifnum\c@tikzumlFragmentLevel>0%
+ \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname}%
+ \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{\tikzumlFragmentFitOld (st-\tikzumlCall@nodeName) (et-\tikzumlCall@nodeName) (eb-\tikzumlCall@nodeName) (sb-\tikzumlCall@nodeName) (\tikzumlCall@nodeName-op)}%
+ \fi%
+ }%
+ }{%
+ \ifnum\c@tikzumlFragmentLevel>0%
+ \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname}%
+ \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{\tikzumlFragmentFitOld (st-\tikzumlCall@nodeName) (et-\tikzumlCall@nodeName) (eb-\tikzumlCall@nodeName) (sb-\tikzumlCall@nodeName) (\tikzumlCall@nodeName-op)}%
+ \fi%
+ }%
+ }%
+ \end{pgfonlayer}%
+}%
+%
+% alias for function self call
+\newenvironment{umlcallself}[2][]{\begin{umlcall}[#1]{#2}{#2} }{\end{umlcall}}%
+%
+% define a combined fragment
+% optional : name: name of fragment
+% type: type of fragment (opt, alt, break, loop, par, critical, ignore, consider, assert, neg, weak, strict, ref)
+% label: label of fragment (ex : condition for opt, iterator for loop, ...)
+% inner xsep, inner ysep: padding of the fragment box
+% draw, fill, text: colors
+\newenvironment{umlfragment}[1][]{%
+ % define a fragment separator
+ % optional : label of the fragment part (ex : else for alt)
+ \providecommand{\umlfpart}[1][]{%
+ \stepcounter{tikzumlFragmentPartNum}%
+ %
+ \node[outer sep=0, inner xsep=\tikzumlFragmentXSep ex, inner ysep=\tikzumlFragmentYSep ex, fit=\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname, name=\tikzumlFragment@name-Part-tmp] {};%
+ \node[anchor=east, name=\tikzumlFragment@name-PartType-\thetikzumlFragmentPartNum] at (\tikzumlFragment@name-Part-tmp.north west |- \tikzumlCallBottomSrc) {\phantom{\tikzumlFragmentType}};%
+ \draw (\tikzumlFragment@name-PartType-\thetikzumlFragmentPartNum.north west |- \tikzumlCallBottomSrc)+(0,-0.4*\tikzumlFragment@paddingy ex) node[name=\tikzumlFragment@name-PartWest-\thetikzumlFragmentPartNum] {};%
+ \draw (\tikzumlFragment@name-Part-tmp.north east |- \tikzumlCallBottomSrc)+(0,-0.4*\tikzumlFragment@paddingy ex) node[name=\tikzumlFragment@name-PartEast-\thetikzumlFragmentPartNum] {};%
+ \draw[dashed] (\tikzumlFragment@name-PartWest-\thetikzumlFragmentPartNum) -- (\tikzumlFragment@name-PartEast-\thetikzumlFragmentPartNum);
+ \draw (\tikzumlFragment@name-PartType-\thetikzumlFragmentPartNum)+(0,-0.4*\tikzumlFragment@paddingy ex) node[name=tikzumlTmpNode] {\phantom{\tikzumlFragmentType}};%
+ \node[anchor=north west] at (tikzumlTmpNode.south west) {[##1]};%
+ }%
+ %
+ \stepcounter{tikzumlFragmentNum}%
+ %
+ \pgfkeys{/tikzuml/fragment/.cd, name/.initial=fragment@\alph{tikzumlFragmentNum}, type/.initial=\tikzumlFragmentDefaultType,%
+ label/.initial=tikzumlEmpty,%
+ inner xsep/.initial=\tikzumlFragmentDefaultXSep, inner ysep/.initial=\tikzumlFragmentDefaultYSep,%
+ draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlFragmentDefaultFillColor,%
+ text/.initial=\tikzumlDefaultTextColor,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \errmessage{TIKZUML ERROR : in umlfragment, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/fragment/.cd, #1}%
+ \pgfkeys{/tikzuml/fragment/.cd, name/.get=\tikzumlFragmentName, type/.get=\tikzumlFragmentType,%
+ label/.get=\tikzumlFragmentLabel,%
+ inner xsep/.get=\tikzumlFragmentXSep, inner ysep/.get=\tikzumlFragmentYSep,%
+ draw/.get=\tikzumlFragmentDrawColor, fill/.get=\tikzumlFragmentFillColor,%
+ text/.get=\tikzumlFragmentTextColor%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlFragmentLabel}{tikzumlEmpty}}{%
+ \def\tikzumlFragmentLabel{}%
+ }{%
+ \let\tikzumlFragmentLabelold\tikzumlFragmentLabel%
+ \def\tikzumlFragmentLabel{[\tikzumlFragmentLabelold]}%
+ }%
+ %
+ \ifnum\thetikzumlFragmentLevel>0%
+ \let\tikzumlFragment@parentold\tikzumlFragment@parent%
+ \let\tikzumlFragment@nameold\tikzumlFragment@name%
+ \edef\tikzumlFragment@parent{\tikzumlFragment@nameold}%
+ \else%
+ \setcounter{tikzumlFragmentPartNum}{0}%
+ \edef\tikzumlFragment@parent{}%
+ \edef\tikzumlFragment@parentold{}%
+ \edef\tikzumlFragment@nameold{}%
+ \fi%
+ %
+ \edef\tikzumlFragment@name{\tikzumlFragmentName}%
+ \expandafter\gdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{}%
+ %
+ \stepcounter{tikzumlFragmentLevel}%
+ %
+ \ifnum\thetikzumlCallLevel>0%
+ \stepcounter{tikzumlCallStartFragmentNum}%
+ \fi%
+ %
+ \pgfmathparse{6*\tikzumlFragmentYSep}%
+ \xdef\tikzumlFragment@paddingy{\pgfmathresult}%
+ \if\c@tikzumlFragmentLevelNum=0%
+ \setcounter{tikzumlFragmentLevelNum}{\thetikzumlFragmentLevel}%
+ \fi%
+ %
+ % time delay adjustment for two consecutive fragments
+ \ifnum\thetikzumlCallEndFragmentNum>0%
+ \addtocounter{tikzumlCallEndFragmentNum}{-1}
+ \fi%
+}{%
+ %
+ \addtocounter{tikzumlFragmentLevel}{-1}%
+ %
+ \ifnum\thetikzumlFragmentLevel>0%
+ \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@parent \endcsname}%
+ \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@parent \endcsname{\tikzumlFragmentFitOld (\tikzumlFragment@name)}%
+ \fi%
+ %
+ % draw working fragment box
+ \begin{pgfonlayer}{fragment\thetikzumlFragmentLevel}%
+ \node[outer sep=0, inner xsep=\tikzumlFragmentXSep ex, inner ysep=\tikzumlFragmentYSep ex, fit=\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname, name=\tikzumlFragment@name-back] {};%
+ \end{pgfonlayer}%
+ %
+ % draw type and label
+ \node[text=\tikzumlFragmentTextColor, font=\tikzumlDefaultFont, anchor=north east, name=\tikzumlFragment@name-type] %
+ at (\tikzumlFragment@name-back.north west) {\tikzumlFragmentType};%
+ \node[text=\tikzumlFragmentTextColor, font=\tikzumlDefaultFont, anchor=north west, name=\tikzumlFragment@name-label] %
+ at (\tikzumlFragment@name-type.south west) {\tikzumlFragmentLabel};%
+ %
+ % draw final fragment box
+ \begin{pgfonlayer}{fragment\thetikzumlFragmentLevel}%
+ \node[draw=\tikzumlFragmentDrawColor, fill=\tikzumlFragmentFillColor, outer sep=0, inner sep=0, font=\tikzumlDefaultFont, fit=(\tikzumlFragment@name-back) (\tikzumlFragment@name-type) (\tikzumlFragment@name-label), name=\tikzumlFragment@name] {};%
+ \end{pgfonlayer}%
+ %
+ \draw[draw=\tikzumlFragmentDrawColor] (\tikzumlFragment@name.north west) rectangle (\tikzumlFragment@name.south east);%
+ \draw (\tikzumlFragment@name-type.south east)+(0,1ex) node[name=\tikzumlFragment@name-typetop, inner sep=0] {};%
+ \draw (\tikzumlFragment@name-type.south east)+(-1ex,0) node[name=\tikzumlFragment@name-typeleft, inner sep=0] {};%
+ \draw (\tikzumlFragment@name.north west) -| (\tikzumlFragment@name-typetop.center) -- (\tikzumlFragment@name-typeleft.center) -| (\tikzumlFragment@name.north west);%
+ %
+ \ifnum\thetikzumlCallLevel>0%
+ \stepcounter{tikzumlCallEndFragmentNum}%
+ \fi%
+}%
+%
+% define a constructor call
+% arg : call sender
+% name of constructed object
+% optional : x: coordinate of the new object
+% stereo: stereotype of the new object
+% class: class type of the new object
+% dt: time delay from last event
+% name: name of the call
+% draw, fill, text: colors
+% no ddots: when used, disable printing of double dots
+\newcommand{\umlcreatecall}[3][]{%
+ \stepcounter{tikzumlCallNum}%
+ \edef\tikzumlCall@lastchildNum{\thetikzumlCallNum}% for testing presence of sub-calls
+ \gdef\tikzumlInCreateCall{1}%
+ \pgfkeys{/tikzuml/createcall/.cd, x/.initial=tikzumlEmpty, stereo/.initial=\tikzumlObjectDefaultStereo, class/.initial={},%
+ dt/.initial=\tikzumlCreateCallDefaultDT, name/.initial=call-\thetikzumlCallNum,%
+ draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlCallDefaultFillColor,%
+ text/.initial=\tikzumlDefaultTextColor,%
+ draw obj/.initial=\tikzumlDefaultDrawColor, fill obj/.initial=\tikzumlObjectDefaultFillColor,%
+ text obj/.initial=\tikzumlDefaultTextColor,%
+ no ddots/.is if=tikzumlcreatecallNoDDots,%
+ no ddots=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \errmessage{TIKZUML ERROR : in umlcreatecall, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/createcall/.cd, #1}%
+ \pgfkeys{/tikzuml/createcall/.cd, x/.get=\tikzumlCreateCallX, stereo/.get=\tikzumlCreateCallStereo,%
+ class/.get=\tikzumlCreateCallClass,%
+ dt/.get=\tikzumlCreateCallDT, name/.get=\tikzumlCreateCallName,%
+ draw/.get=\tikzumlCreateCallDrawColor, fill/.get=\tikzumlCreateCallFillColor,%
+ text/.get=\tikzumlCreateCallTextColor,%
+ draw obj/.get=\tikzumlCreateCallObjectDrawColor, fill obj/.get=\tikzumlCreateCallObjectFillColor,%
+ text obj/.get=\tikzumlCreateCallObjectTextColor%
+ }%
+ %
+ \def\tikzumlCreateCallSrc@name{#2}%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlCreateCallSrc@nodeName{\tikzumlCreateCallSrc@name}}\x%
+ %
+ % managing time delays from previous/parent fragments
+ \ifnum\thetikzumlCallStartFragmentNum>0%
+ \let\tikzumlCreateCallDTold\tikzumlCreateCallDT%
+ \pgfmathparse{0.5*\tikzumlFragment@paddingy+\tikzumlCreateCallDTold}%
+ \edef\tikzumlCreateCallDT{\pgfmathresult}%
+ \addtocounter{tikzumlCallStartFragmentNum}{-1}
+ \fi%
+ \ifnum\thetikzumlCallEndFragmentNum>0%
+ \let\tikzumlCreateCallDTold\tikzumlCreateCallDT%
+ \pgfmathparse{0.5*\tikzumlFragment@paddingy+\tikzumlCreateCallDTold}%
+ \edef\tikzumlCreateCallDT{\pgfmathresult}%
+ \addtocounter{tikzumlCallEndFragmentNum}{-1}
+ \fi%
+ \ifnum\thetikzumlFragmentPartNum>0%
+ \let\tikzumlCreateCallDTold\tikzumlCreateCallDT%
+ \pgfmathparse{0.5*\tikzumlFragment@paddingy+\tikzumlCreateCallDTold}%
+ \edef\tikzumlCreateCallDT{\pgfmathresult}%
+ \fi%
+ %
+ % managing parent-child structure
+ \ifnum\thetikzumlCallLevel>0%
+ \let\tikzumlCall@nameold\tikzumlCall@name%
+ \def\tikzumlCall@name{\tikzumlCreateCallName}%
+ \let\tikzumlCall@parentold\tikzumlCall@parent%
+ \edef\tikzumlCall@parent{\tikzumlCall@parentold @@\tikzumlCall@nameold}%
+ \else%
+ \edef\tikzumlCall@parent{}%
+ \edef\tikzumlCall@parentold{}%
+ \edef\tikzumlCall@nameold{}
+ \edef\tikzumlCall@name{\tikzumlCreateCallName}%
+ \fi%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlCreateCall@nodeName{\tikzumlCall@name}}\x%
+ %
+ \draw (\csname tikzumlLastChild@\tikzumlCreateCallSrc@nodeName \endcsname)+(0,-\tikzumlCreateCallDT ex) node[name=st-\tikzumlCreateCall@nodeName, tikzuml activity style] {};%
+ %
+ \xdef\tikzumlCreateCallObjectSrc{st-\tikzumlCreateCall@nodeName}%
+ %
+ \iftikzumlcreatecallNoDDots%
+ \umlobject[x=\tikzumlCreateCallX, stereo=\tikzumlCreateCallStereo, class=\tikzumlCreateCallClass, draw=\tikzumlCreateCallObjectDrawColor, fill=\tikzumlCreateCallObjectFillColor, text=\tikzumlCreateCallObjectTextColor, no ddots]{#3}%
+ \else
+ \umlobject[x=\tikzumlCreateCallX, stereo=\tikzumlCreateCallStereo, class=\tikzumlCreateCallClass, draw=\tikzumlCreateCallObjectDrawColor, fill=\tikzumlCreateCallObjectFillColor, text=\tikzumlCreateCallObjectTextColor]{#3}%
+ \fi
+ %
+ \draw (\csname tikzumlLastChild@\tikzumlCreateCallSrc@nodeName \endcsname |- #3)+(0,-0.5*\tikzumlCreateCallDT ex) node[name=sb-\tikzumlCreateCall@nodeName, tikzuml activity style] {};%
+ %
+ \expandafter\xdef\csname tikzumlLastChild@\tikzumlCreateCallSrc@nodeName \endcsname{sb-\tikzumlCreateCall@nodeName}%
+ \xdef\tikzumlCallBottomSrc{sb-\tikzumlCreateCall@nodeName}%
+ %
+ \begin{pgfonlayer}{connections}%
+ \draw[tikzuml synchron-msg style, \tikzumlCreateCallDrawColor] (st-\tikzumlCreateCall@nodeName) -- (#3) node[midway, above, font=\tikzumlDefaultFont, text=\tikzumlCreateCallTextColor, name=\tikzumlCreateCall@nodeName-op] {create};%
+ \end{pgfonlayer}%
+ %
+ \ifnum\thetikzumlCallLevel=0%
+ \begin{pgfonlayer}{activity}%
+ \draw[draw=\tikzumlCreateCallDrawColor, fill=\tikzumlCreateCallFillColor] (st-\tikzumlCreateCall@nodeName.north west) rectangle (sb-\tikzumlCreateCall@nodeName.south east);%
+ \end{pgfonlayer}%
+ \fi%
+ % add to fit fragment
+ \ifnum\c@tikzumlFragmentLevel>0%
+ \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname}%
+ \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{\tikzumlFragmentFitOld (st-\tikzumlCreateCall@nodeName) (sb-\tikzumlCreateCall@nodeName) (\tikzumlCreateCall@nodeName-op) (#3) }%
+ \fi%
+}
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% component diagrams %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+\tikzstyle{tikzuml connector style}=[color=\tikzumlDefaultDrawColor, -]%
+%
+\newcounter{tikzumlComponentLevel}%
+\newcounter{tikzumlComponentSubComponentNum}%
+\newcounter{tikzumlConnectorNum}%
+\setcounter{tikzumlConnectorNum}{1}%
+%
+\newif\iftikzumlcomponentWithoutCoords%
+%
+\newcommand{\picturedcomponent}[1]{%
+ \pgfkeys{/tikzuml/component/picture/.cd, scale/.initial=1, .unknown/.code={}}%
+ \pgfkeys{/tikzuml/component/picture/.cd,#1}%
+ \pgfkeys{/tikzuml/component/picture/.cd, scale/.get=\tikzumlComponentScale}%
+ \begin{tikzpicture}[#1]%
+ \filldraw (0,0) rectangle (1ex,1.5ex);%
+ \filldraw (-0.2ex,0.4ex) rectangle (0.2ex,0.6ex);%
+ \filldraw (-0.2ex,0.9ex) rectangle (0.2ex,1.1ex);%
+ \end{tikzpicture}%
+}%
+%
+% define a uml component
+% args : name of the component
+% content of the component
+% optional args : x,y coordinates of the component
+% width of the component node
+\newenvironment{umlcomponent}[2][]{%
+ \ifnum\thetikzumlComponentLevel>0%
+ \let\tikzumlComponent@nameold\tikzumlComponent@fitname%
+ \let\tikzumlComponent@parentold\tikzumlComponent@parent%
+ \edef\tikzumlComponent@parent{\tikzumlComponent@parentold @@\tikzumlComponent@nameold}%
+ \else%
+ \def\tikzumlComponent@parent{}%
+ \fi%
+ %
+ \stepcounter{tikzumlComponentLevel}%
+ %
+ \pgfkeys{/tikzuml/component/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlComponentDefaultWidth, name/.initial={},%
+ draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlComponentDefaultFillColor,%
+ text/.initial=\tikzumlDefaultTextColor, style/.style={},%
+ no coords/.is if=tikzumlcomponentWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/component/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/component/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/component/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlcomponent, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/component/.cd, #1}%
+ \pgfkeys{/tikzuml/component/.cd, x/.get=\tikzumlComponentXShift, y/.get=\tikzumlComponentYShift,%
+ width/.get=\tikzumlComponentMinimumWidth, name/.get=\tikzumlComponentName,%
+ draw/.get=\tikzumlComponentDrawColor, fill/.get=\tikzumlComponentFillColor,%
+ text/.get=\tikzumlComponentTextColor%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlComponentName}{}}{%
+ \edef\tikzumlComponent@name{#2}%
+ }{%
+ \edef\tikzumlComponent@name{\tikzumlComponentName}%
+ }%
+ %
+ \begingroup%
+ \def\_{@}\edef\x{\endgroup%
+ \def\noexpand\tikzumlComponent@fitname{\tikzumlComponent@name}}\x%
+ %
+ \let\tikzumlComponent@nodeNameold\tikzumlComponent@nodeName%
+ \def\tikzumlComponent@caption{#2}%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlComponent@nodeName{\tikzumlComponent@name}}\x%
+ %
+ \expandafter\gdef\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname{}%
+ %
+ \setcounter{tikzumlComponentSubComponentNum}{0}%
+ %
+ \begin{scope}[xshift=\tikzumlComponentXShift cm, yshift=\tikzumlComponentYShift cm]%
+}{%
+ \addtocounter{tikzumlComponentLevel}{-1}%
+ \begin{pgfonlayer}{component\thetikzumlComponentLevel}%
+ %
+ % if contains nothing, one define a fictive node to enable the fit option
+ \ifnum\c@tikzumlComponentSubComponentNum=0%
+ \iftikzumlcomponentWithoutCoords%
+ \node[inner ysep=0.5ex, minimum width=\tikzumlComponentMinimumWidth, font=\tikzumlDefaultFont, /tikzuml/component/style] (\tikzumlComponent@nodeName-root) {\phantom{\tikzumlComponent@nodeName}};%
+ \else%
+ \node[inner ysep=0.5ex, minimum width=\tikzumlComponentMinimumWidth, font=\tikzumlDefaultFont, /tikzuml/component/style] (\tikzumlComponent@nodeName-root) at (0,0) {\phantom{\tikzumlComponent@nodeName}};%
+ \fi%
+ \expandafter\xdef\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname{(\tikzumlComponent@nodeName-root)}%
+ \fi%
+ %
+ \ifnum\c@tikzumlComponentLevel>0%
+ \def\tikzumlComponentFitTmp{\csname tikzumlComponentFit\tikzumlComponent@parent\endcsname}%
+ \expandafter\xdef\csname tikzumlComponentFit\tikzumlComponent@parent\endcsname{\tikzumlComponentFitTmp (\tikzumlComponent@nodeName-body) (\tikzumlComponent@nodeName-caption)}%
+ \stepcounter{tikzumlComponentSubComponentNum}%
+ \fi%
+ %
+ \node[inner sep=2ex, font=\tikzumlDefaultFont, fit = \csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname] (\tikzumlComponent@nodeName-body) {};%
+ \node[above, font=\tikzumlDefaultFont] (\tikzumlComponent@nodeName-captiontmp) at (\tikzumlComponent@nodeName-body.north) {\tikzumlComponent@caption};%
+ \node (\tikzumlComponent@nodeName-logotmp) at (\tikzumlComponent@nodeName-captiontmp.north -| \tikzumlComponent@nodeName-body.east) {\picturedcomponent{draw=\tikzumlComponentDrawColor, fill=\tikzumlComponentFillColor, font=\tikzumlDefaultFont} };%
+ \node[draw=\tikzumlComponentDrawColor, fill=\tikzumlComponentFillColor, name=\tikzumlComponent@nodeName, /tikzuml/component/style, fit=(\tikzumlComponent@nodeName-body) (\tikzumlComponent@nodeName-captiontmp)] {};%
+ \node[font=\tikzumlDefaultFont] (\tikzumlComponent@nodeName-caption) at (\tikzumlComponent@nodeName-captiontmp) {\tikzumlComponent@caption};%
+ \draw (\tikzumlComponent@nodeName-caption.north -| \tikzumlComponent@nodeName.east) node[font=\tikzumlDefaultFont, xshift=-1ex, below=-1ex, name=\tikzumlComponent@nodeName-logo] {\picturedcomponent{draw=\tikzumlComponentDrawColor, fill=\tikzumlComponentFillColor, font=\tikzumlDefaultFont} };%
+ \draw (\tikzumlComponent@nodeName-caption.south -| \tikzumlComponent@nodeName.north west) -- (\tikzumlComponent@nodeName-caption.south -| \tikzumlComponent@nodeName.north east);%
+ \coordinate (\tikzumlComponent@nodeName-west-port) at (\tikzumlComponent@nodeName.west);
+ \coordinate (\tikzumlComponent@nodeName-east-port) at (\tikzumlComponent@nodeName.east);
+ \coordinate (\tikzumlComponent@nodeName-south-port) at (\tikzumlComponent@nodeName.south);
+ \coordinate (\tikzumlComponent@nodeName-north-port) at (\tikzumlComponent@nodeName.north);
+ \end{pgfonlayer}%
+ \end{scope}%
+ %
+ % add to fit
+ \ifnum\c@tikzumlPackageLevel>0%
+ \edef\tikzumlPackageFitOld{\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{\tikzumlPackageFitOld (\tikzumlComponent@nodeName)}%
+ \stepcounter{tikzumlPackageClassNum}%
+ \fi%
+}%
+%
+% shortcut for empty component
+\newcommand{\umlbasiccomponent}[2][]{\begin{umlcomponent}[#1]{#2} \end{umlcomponent}}%
+%
+\newcommand{\umlrequiredinterface}[2][]{%
+ \def\tikzumlInterfaceWithPort{tikzumlFalse}%
+ \pgfkeys{/tikzuml/requiredinterfacerelation/.cd, interface/.initial={}, distance/.initial=\tikzumlRequiredInterfaceDefaultDistance,%
+ name/.initial=tikzumlEmpty, width/.initial=\tikzumlRequiredInterfaceDefaultWidth,%
+ padding/.initial=\tikzumlRequiredInterfaceDefaultPadding,%
+ draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlComponentDefaultFillColor,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{with port}}{%
+ \def\tikzumlInterfaceWithPort{tikzumlTrue}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/requiredinterfacerelation/.cd, #1}%
+ \pgfkeys{/tikzuml/requiredinterfacerelation/.cd, interface/.get=\tikzumlRequiredInterfaceLabel,%
+ distance/.get=\tikzumlRequiredInterfaceDistance,%
+ name/.get=\tikzumlRequiredInterfaceName,%
+ width/.get=\tikzumlRequiredInterfaceWidth,%
+ padding/.get=\tikzumlRequiredInterfacePadding,%
+ draw/.get=\tikzumlRequiredInterfaceDrawColor,%
+ fill/.get=\tikzumlRequiredInterfaceFillColor%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlRequiredInterfaceName}{tikzumlEmpty}}{%
+ \edef\tikzumlRequiredInterface@interfacename{#2-east-interface}%
+ \edef\tikzumlRequiredInterface@portname{#2-east-port}%
+ \edef\tikzumlRequiredInterface@paddingname{#2-east-padding}%
+ }{%
+ \edef\tikzumlRequiredInterface@interfacename{\tikzumlRequiredInterfaceName}%
+ \edef\tikzumlRequiredInterface@portname{\tikzumlRequiredInterfaceName-port}%
+ \edef\tikzumlRequiredInterface@paddingname{\tikzumlRequiredInterfaceName-padding}%
+ }%
+ %
+ \edef\tikzumlRequiredInterface@name{#2}%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlRequiredInterface@nodeName{\tikzumlRequiredInterface@name}}\x%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlRequiredInterface@interfacenodeName{\tikzumlRequiredInterface@interfacename}}\x%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlRequiredInterface@portnodeName{\tikzumlRequiredInterface@portname}}\x%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlRequiredInterface@paddingnodeName{\tikzumlRequiredInterface@paddingname}}\x%
+ %
+ \ifthenelse{\equal{\tikzumlInterfaceWithPort}{tikzumlTrue}}{%
+ \node[inner sep=0.5*\tikzumlRequiredInterfaceWidth, rectangle, draw=\tikzumlRequiredInterfaceDrawColor, fill=\tikzumlRequiredInterfaceFillColor] (\tikzumlRequiredInterface@portnodeName) at (\tikzumlRequiredInterface@nodeName.east) {};%
+ }{%
+ \node[inner sep=0] (\tikzumlRequiredInterface@nodeName-east-port) at (\tikzumlRequiredInterface@nodeName.east) {};%
+ }%
+ \begin{scope}%
+ \draw (\tikzumlRequiredInterface@nodeName)+(\tikzumlRequiredInterfaceDistance,0) node[inner sep=0, text width=\tikzumlRequiredInterfaceWidth, circle, name=\tikzumlRequiredInterface@interfacenodeName-tmp] {};%
+ \clip (\tikzumlRequiredInterface@interfacenodeName-tmp.north) rectangle (\tikzumlRequiredInterface@interfacenodeName-tmp.south -| \tikzumlRequiredInterface@interfacenodeName-tmp.west);%
+ \node[inner sep=0, text width=\tikzumlRequiredInterfaceWidth, circle, draw=\tikzumlRequiredInterfaceDrawColor] (\tikzumlRequiredInterface@interfacenodeName) at (\tikzumlRequiredInterface@interfacenodeName-tmp) {};%
+ \end{scope}%
+ \node[above] at (\tikzumlRequiredInterface@interfacenodeName.north) {\tikzumlRequiredInterfaceLabel};%
+ %
+ \umlrelation[style={tikzuml connector style}, #1]{\tikzumlRequiredInterface@portnodeName}{\tikzumlRequiredInterface@interfacenodeName}%
+ %
+ \draw (\tikzumlRequiredInterface@interfacenodeName)+(\tikzumlRequiredInterfacePadding,0) node[name=\tikzumlRequiredInterface@paddingnodeName] {};%
+ %
+ % add to fit
+ \ifnum\c@tikzumlComponentLevel>0%
+ \def\tikzumlComponentFitTmp{\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname{\tikzumlComponentFitTmp (\tikzumlRequiredInterface@paddingnodeName) (\tikzumlRequiredInterface@portnodeName) }%
+ \fi%
+}%
+%
+\newcommand{\umlprovidedinterface}[2][]{%
+ \def\tikzumlInterfaceWithPort{tikzumlFalse}%
+ \pgfkeys{/tikzuml/providedinterfacerelation/.cd, interface/.initial={}, distance/.initial=\tikzumlProvidedInterfaceDefaultDistance,%
+ name/.initial=tikzumlEmpty, width/.initial=\tikzumlProvidedInterfaceDefaultWidth,%
+ padding/.initial=\tikzumlProvidedInterfaceDefaultPadding,%
+ draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlComponentDefaultFillColor,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{with port}}{%
+ \def\tikzumlInterfaceWithPort{tikzumlTrue}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/providedinterfacerelation/.cd, #1}%
+ \pgfkeys{/tikzuml/providedinterfacerelation/.cd, interface/.get=\tikzumlProvidedInterfaceLabel,%
+ distance/.get=\tikzumlProvidedInterfaceDistance,%
+ name/.get=\tikzumlProvidedInterfaceName,%
+ width/.get=\tikzumlProvidedInterfaceWidth,%
+ padding/.get=\tikzumlProvidedInterfacePadding,%
+ draw/.get=\tikzumlProvidedInterfaceDrawColor,%
+ fill/.get=\tikzumlProvidedInterfaceFillColor%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlProvidedInterfaceName}{tikzumlEmpty}}{%
+ \edef\tikzumlProvidedInterface@interfacename{#2-west-interface}%
+ \edef\tikzumlProvidedInterface@portname{#2-west-port}%
+ \edef\tikzumlProvidedInterface@paddingname{#2-west-padding}%
+ }{%
+ \edef\tikzumlProvidedInterface@interfacename{\tikzumlProvidedInterfaceName}%
+ \edef\tikzumlProvidedInterface@portname{\tikzumlProvidedInterfaceName-port}%
+ \edef\tikzumlProvidedInterface@paddingname{\tikzumlProvidedInterfaceName-padding}%
+ }%
+ %
+ \edef\tikzumlProvidedInterface@name{#2}%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlProvidedInterface@nodeName{\tikzumlProvidedInterface@name}}\x%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlProvidedInterface@interfacenodeName{\tikzumlProvidedInterface@interfacename}}\x%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlProvidedInterface@portnodeName{\tikzumlProvidedInterface@portname}}\x%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlProvidedInterface@paddingnodeName{\tikzumlProvidedInterface@paddingname}}\x%
+ %
+ \ifthenelse{\equal{\tikzumlInterfaceWithPort}{tikzumlTrue}}{%
+ \node[inner sep=0.5*\tikzumlProvidedInterfaceWidth, rectangle, draw=\tikzumlProvidedInterfaceDrawColor, fill=\tikzumlProvidedInterfaceFillColor] (\tikzumlProvidedInterface@portnodeName) at (\tikzumlProvidedInterface@nodeName.west) {};%
+ }{%
+ \node[inner sep=0] (\tikzumlProvidedInterface@portnodeName) at (\tikzumlProvidedInterface@nodeName.west) {};%
+ }%
+ \draw (\tikzumlProvidedInterface@nodeName)+(-\tikzumlProvidedInterfaceDistance,0) node[inner sep=0, text width=\tikzumlProvidedInterfaceWidth, circle, draw=\tikzumlProvidedInterfaceDrawColor, fill=\tikzumlProvidedInterfaceFillColor, name=\tikzumlProvidedInterface@interfacenodeName] {};%
+ \node[above] at (\tikzumlProvidedInterface@interfacenodeName.north)
+ {\tikzumlProvidedInterfaceLabel};%
+ %
+ \umlrelation[style={tikzuml connector style}, #1]{\tikzumlProvidedInterface@portnodeName}{\tikzumlProvidedInterface@interfacenodeName}%
+ %
+ \draw (\tikzumlProvidedInterface@interfacenodeName)+(-\tikzumlProvidedInterfacePadding,0) node[name=\tikzumlProvidedInterface@paddingnodeName] {};%
+ %
+ % add to fit
+ \ifnum\thetikzumlComponentLevel>0%
+ \def\tikzumlComponentFitTmp{\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname{\tikzumlComponentFitTmp (\tikzumlProvidedInterface@paddingnodeName) (\tikzumlProvidedInterface@portnodeName) }%
+ \fi%
+}%
+%
+\newlength{\tikzuml@AC@xa}%
+\newlength{\tikzuml@AC@ya}%
+\newlength{\tikzuml@AC@xb}%
+\newlength{\tikzuml@AC@yb}%
+\newlength{\tikzuml@AC@xi}%
+\newlength{\tikzuml@AC@yi}%
+\newlength{\tikzuml@AC@xic}%
+\newlength{\tikzuml@AC@yic}%
+\newlength{\tikzuml@AC@xio}%
+\newlength{\tikzuml@AC@yio}%
+\newlength{\tikzuml@AC@AB}%
+\newlength{\tikzuml@AC@lambda}%
+\newlength{\tikzuml@AC@xtrc}%
+\newlength{\tikzuml@AC@ytrc}%
+\newlength{\tikzuml@AC@xtlc}%
+\newlength{\tikzuml@AC@ytlc}%
+\newlength{\tikzuml@AC@xblc}%
+\newlength{\tikzuml@AC@yblc}%
+\newlength{\tikzuml@AC@xbrc}%
+\newlength{\tikzuml@AC@ybrc}%
+\newlength{\tikzuml@AC@middleArm}%
+%
+\newcommand{\umlassemblyconnectorsymbol}[2]{%
+ \ifthenelse{\NOT\equal{\tikzumlAssemblyConnectorLabel}{}}{%
+ \edef\tikzuml@ACStart@name{#1}%
+ \edef\tikzuml@ACEnd@name{#2}%
+ \edef\tikzuml@AC@width{\tikzumlAssemblyConnectorWidth}%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzuml@ACStart@nodeName{\tikzuml@ACStart@name}}\x%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzuml@ACEnd@nodeName{\tikzuml@ACEnd@name}}\x%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzuml@ACInterface@nodeName{\tikzumlAssemblyConnectorSymbolName}}\x%
+ %
+ \pgfextractx{\tikzuml@AC@xa}{\pgfpointanchor{\tikzuml@ACStart@nodeName}{\tikzumlAssemblyConnectorStartAnchor}}%
+ \pgfextracty{\tikzuml@AC@ya}{\pgfpointanchor{\tikzuml@ACStart@nodeName}{\tikzumlAssemblyConnectorStartAnchor}}%
+ \pgfextractx{\tikzuml@AC@xb}{\pgfpointanchor{\tikzuml@ACEnd@nodeName}{\tikzumlAssemblyConnectorEndAnchor}}%
+ \pgfextracty{\tikzuml@AC@yb}{\pgfpointanchor{\tikzuml@ACEnd@nodeName}{\tikzumlAssemblyConnectorEndAnchor}}%
+ \pgfmathsetlength{\tikzuml@AC@xi}{0.5*\tikzuml@AC@xa+0.5*\tikzuml@AC@xb}%
+ \pgfmathsetlength{\tikzuml@AC@yi}{0.5*\tikzuml@AC@ya+0.5*\tikzuml@AC@yb}%
+ \pgfmathsetlength{\tikzuml@AC@AB}{veclen(\tikzuml@AC@xa-\tikzuml@AC@xb,\tikzuml@AC@ya-\tikzuml@AC@yb)}%
+ \pgfmathsetlength{\tikzuml@AC@lambda}{0.25*\tikzuml@AC@width/\tikzuml@AC@AB}%
+ \pgfmathsetlength{\tikzuml@AC@xic}{\tikzuml@AC@xi-\tikzuml@AC@lambda*(\tikzuml@AC@xb-\tikzuml@AC@xa)}%
+ \pgfmathsetlength{\tikzuml@AC@yic}{\tikzuml@AC@yi-\tikzuml@AC@lambda*(\tikzuml@AC@yb-\tikzuml@AC@ya)}%
+ \pgfmathsetlength{\tikzuml@AC@xio}{\tikzuml@AC@xi+\tikzuml@AC@lambda*(\tikzuml@AC@xb-\tikzuml@AC@xa)}%
+ \pgfmathsetlength{\tikzuml@AC@yio}{\tikzuml@AC@yi+\tikzuml@AC@lambda*(\tikzuml@AC@yb-\tikzuml@AC@ya)}%
+ \node[inner sep=0.5*\tikzuml@AC@width] (\tikzuml@ACInterface@nodeName-interface) at (\tikzuml@AC@xi,\tikzuml@AC@yi) {};%
+ \node[inner sep=0, text width=\tikzuml@AC@width, circle, draw=\tikzumlAssemblyConnectorDrawColor, fill=\tikzumlAssemblyConnectorFillColor] (\tikzuml@ACInterface@nodeName-io) at (\tikzuml@AC@xio,\tikzuml@AC@yio) {};%
+ \begin{scope}%
+ \pgfmathsetlength{\tikzuml@AC@xtrc}{\tikzuml@AC@xic-2*\tikzuml@AC@lambda*(\tikzuml@AC@yb-\tikzuml@AC@ya)}%
+ \pgfmathsetlength{\tikzuml@AC@ytrc}{\tikzuml@AC@yic+2*\tikzuml@AC@lambda*(\tikzuml@AC@xb-\tikzuml@AC@xa)}%
+ \pgfmathsetlength{\tikzuml@AC@xbrc}{\tikzuml@AC@xic+2*\tikzuml@AC@lambda*(\tikzuml@AC@yb-\tikzuml@AC@ya)}%
+ \pgfmathsetlength{\tikzuml@AC@ybrc}{\tikzuml@AC@yic-2*\tikzuml@AC@lambda*(\tikzuml@AC@xb-\tikzuml@AC@xa)}%
+ \pgfmathsetlength{\tikzuml@AC@xtlc}{\tikzuml@AC@xic-3*\tikzuml@AC@lambda*(\tikzuml@AC@yb-\tikzuml@AC@ya+\tikzuml@AC@xb-\tikzuml@AC@xa)}%
+ \pgfmathsetlength{\tikzuml@AC@ytlc}{\tikzuml@AC@yic+3*\tikzuml@AC@lambda*(\tikzuml@AC@xb-\tikzuml@AC@xa+\tikzuml@AC@ya-\tikzuml@AC@yb)}%
+ \pgfmathsetlength{\tikzuml@AC@xblc}{\tikzuml@AC@xic+3*\tikzuml@AC@lambda*(\tikzuml@AC@yb-\tikzuml@AC@ya+\tikzuml@AC@xa-\tikzuml@AC@xb)}%
+ \pgfmathsetlength{\tikzuml@AC@yblc}{\tikzuml@AC@yic-3*\tikzuml@AC@lambda*(\tikzuml@AC@xb-\tikzuml@AC@xa+\tikzuml@AC@yb-\tikzuml@AC@ya)}%
+ \coordinate (\tikzuml@ACInterface@nodeName-trc) at (\tikzuml@AC@xtrc,\tikzuml@AC@ytrc);%
+ \coordinate (\tikzuml@ACInterface@nodeName-brc) at (\tikzuml@AC@xbrc,\tikzuml@AC@ybrc);%
+ \coordinate (\tikzuml@ACInterface@nodeName-tlc) at (\tikzuml@AC@xtlc,\tikzuml@AC@ytlc);%
+ \coordinate (\tikzuml@ACInterface@nodeName-blc) at (\tikzuml@AC@xblc,\tikzuml@AC@yblc);%
+ \clip (\tikzuml@ACInterface@nodeName-trc) -- (\tikzuml@ACInterface@nodeName-tlc) -- (\tikzuml@ACInterface@nodeName-blc) -- (\tikzuml@ACInterface@nodeName-brc) -- cycle;%
+ \node[inner sep=0, text width=\tikzuml@AC@width, circle, draw=\tikzumlAssemblyConnectorDrawColor, fill=\tikzumlAssemblyConnectorFillColor] (\tikzuml@ACInterface@nodeName-ic) at (\tikzuml@AC@xic,\tikzuml@AC@yic) {};%
+ \end{scope}%
+ \node[above, font=\tikzumlDefaultFont] at (\tikzuml@ACInterface@nodeName-interface.north)
+ {\tikzumlAssemblyConnectorLabel};%
+ }{}%
+}%
+%
+\newcommand{\umlassemblyconnector}[3][]{%
+ \def\tikzumlAssemblyConnectorWithPort{tikzumlFalse}%
+ \def\tikzumlAssemblyConnectorFirstArm{tikzumlFalse}%
+ \def\tikzumlAssemblyConnectorSecondArm{tikzumlFalse}%
+ \def\tikzumlAssemblyConnectorMiddleArm{tikzumlFalse}%
+ \def\tikzumlAssemblyConnectorLastArm{tikzumlFalse}%
+ \pgfkeys{/tikzuml/assemblyconnectorrelation/.cd, geometry/.initial=--, interface/.initial={},%
+ arm1/.initial={auto}, arm2/.initial={auto},%
+ name/.initial=connector-\thetikzumlConnectorNum, width/.initial=1em,%
+ anchor1/.initial={}, anchor2/.initial={},%
+ draw/.initial=\tikzumlDefaultDrawColor,%
+ fill assembly connector/.initial=\tikzumlAssemblyConnectorDefaultFillColor,%
+ fill port/.initial=\tikzumlPortDefaultFillColor,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{with port}}{%
+ \def\tikzumlAssemblyConnectorWithPort{tikzumlTrue}%
+ }{%
+ \ifthenelse{\equal{\keyname}{first arm}}{%
+ \def\tikzumlAssemblyConnectorFirstArm{tikzumlTrue}%
+ }{%
+ \ifthenelse{\equal{\keyname}{second arm}}{%
+ \def\tikzumlAssemblyConnectorSecondArm{tikzumlTrue}%
+ }{%
+ \ifthenelse{\equal{\keyname}{middle arm}}{%
+ \def\tikzumlAssemblyConnectorMiddleArm{tikzumlTrue}%
+ }{%
+ \ifthenelse{\equal{\keyname}{last arm}}{%
+ \def\tikzumlAssemblyConnectorLastArm{tikzumlTrue}%
+ }{%
+ }%
+ }%
+ }%
+ }%
+ }%
+ }%
+ }%
+ \pgfkeys{/tikzuml/assemblyconnectorrelation/.cd, #1}%
+ \pgfkeys{/tikzuml/assemblyconnectorrelation/.cd, geometry/.get=\tikzumlAssemblyConnectorGeometry,%
+ name/.get=\tikzumlAssemblyConnectorName,%
+ interface/.get=\tikzumlAssemblyConnectorLabel,%
+ width/.get=\tikzumlAssemblyConnectorWidth,%
+ arm1/.get=\tikzumlAssemblyConnectorStartArm,%
+ arm2/.get=\tikzumlAssemblyConnectorEndArm,%
+ anchor1/.get=\tikzumlAssemblyConnectorStartAnchorTmp,%
+ anchor2/.get=\tikzumlAssemblyConnectorEndAnchorTmp,%
+ draw/.get=\tikzumlAssemblyConnectorDrawColor,%
+ fill assembly connector/.get=\tikzumlAssemblyConnectorFillColor,%
+ fill port/.get=\tikzumlAssemblyConnectorPortFillColor%
+ }%
+ %
+ \edef\tikzumlAssemblyConnectorStart@name{#2}%
+ \edef\tikzumlAssemblyConnectorEnd@name{#3}%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlAssemblyConnectorStart@nodeName{\tikzumlAssemblyConnectorStart@name}}\x%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlAssemblyConnectorEnd@nodeName{\tikzumlAssemblyConnectorEnd@name}}\x%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlAssemblyConnectorLabel@nodeName{\tikzumlAssemblyConnectorLabel}}\x%
+ %
+ \pgfextractx{\tikzuml@AC@xa}{\pgfpointanchor{\tikzumlAssemblyConnectorStart@nodeName}{center}}%
+ \pgfextracty{\tikzuml@AC@ya}{\pgfpointanchor{\tikzumlAssemblyConnectorStart@nodeName}{center}}%
+ \pgfextractx{\tikzuml@AC@xb}{\pgfpointanchor{\tikzumlAssemblyConnectorEnd@nodeName}{center}}%
+ \pgfextracty{\tikzuml@AC@yb}{\pgfpointanchor{\tikzumlAssemblyConnectorEnd@nodeName}{center}}%
+ %
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{--}}{%
+ \ifthenelse{\tikzuml@AC@xb>\tikzuml@AC@xa}{%
+ \def\tikzumlAssemblyConnectorStartAnchor{east}%
+ \def\tikzumlAssemblyConnectorEndAnchor{west}%
+ }{%
+ \def\tikzumlAssemblyConnectorStartAnchor{west}%
+ \def\tikzumlAssemblyConnectorEndAnchor{east}%
+ }
+ }{}%
+ %
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{-|}}{%
+ \ifthenelse{\tikzuml@AC@xb>\tikzuml@AC@xa}{%
+ \def\tikzumlAssemblyConnectorStartAnchor{east}%
+ }{%
+ \def\tikzumlAssemblyConnectorStartAnchor{west}%
+ }
+ \ifthenelse{\tikzuml@AC@yb>\tikzuml@AC@ya}{%
+ \def\tikzumlAssemblyConnectorEndAnchor{south}%
+ }{%
+ \def\tikzumlAssemblyConnectorEndAnchor{north}%
+ }
+ }{}%
+ %
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{|-}}{%
+ \ifthenelse{\tikzuml@AC@xb>\tikzuml@AC@xa}{%
+ \def\tikzumlAssemblyConnectorEndAnchor{west}%
+ }{%
+ \def\tikzumlAssemblyConnectorEndAnchor{east}%
+ }
+ \ifthenelse{\tikzuml@AC@yb>\tikzuml@AC@ya}{%
+ \def\tikzumlAssemblyConnectorStartAnchor{north}%
+ }{%
+ \def\tikzumlAssemblyConnectorStartAnchor{south}%
+ }
+ }{}%
+ %
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{-|-}}{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorStartArm}{auto}}{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorEndArm}{auto}}{%
+ \pgfmathsetlength{\tikzuml@AC@middleArm}{0.5 * \tikzuml@AC@xa + 0.5 * \tikzuml@AC@xb}%
+ }{%
+ \pgfmathsetlength{\tikzuml@AC@middleArm}{\tikzuml@AC@xb+\tikzumlAssemblyConnectorEndArm}%
+ }%
+ }{%
+ \pgfmathsetlength{\tikzuml@AC@middleArm}{\tikzuml@AC@xa+\tikzumlAssemblyConnectorStartArm}%
+ }%
+ \pgfmathparse{\tikzuml@AC@middleArm>\tikzuml@AC@xa}
+ \pgfmathparse{\tikzuml@AC@middleArm>\tikzuml@AC@xb}
+ \ifthenelse{\lengthtest{\tikzuml@AC@middleArm>\tikzuml@AC@xa}}{%
+ \def\tikzumlAssemblyConnectorStartAnchor{east}%
+ }{%
+ \def\tikzumlAssemblyConnectorStartAnchor{west}%
+ }
+ \ifthenelse{\lengthtest{\tikzuml@AC@middleArm>\tikzuml@AC@xb}}{%
+ \def\tikzumlAssemblyConnectorEndAnchor{east}%
+ }{%
+ \def\tikzumlAssemblyConnectorEndAnchor{west}%
+ }
+ }{}%
+ %
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{|-|}}{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorStartArm}{auto}}{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorEndArm}{auto}}{%
+ \pgfmathsetlength{\tikzuml@AC@middleArm}{0.5 * \tikzuml@AC@ya + 0.5 * \tikzuml@AC@yb}%
+ }{%
+ \pgfmathsetlength{\tikzuml@AC@middleArm}{\tikzuml@AC@yb+\tikzumlAssemblyConnectorEndArm}%
+ }%
+ }{%
+ \pgfmathsetlength{\tikzuml@AC@middleArm}{\tikzuml@AC@ya+\tikzumlAssemblyConnectorStartArm}%
+ }%
+ \ifthenelse{\tikzuml@AC@middleArm>\tikzuml@AC@ya}{%
+ \def\tikzumlAssemblyConnectorStartAnchor{north}%
+ }{%
+ \def\tikzumlAssemblyConnectorStartAnchor{south}%
+ }
+ \ifthenelse{\tikzuml@AC@middleArm>\tikzuml@AC@yb}{%
+ \def\tikzumlAssemblyConnectorEndAnchor{north}%
+ }{%
+ \def\tikzumlAssemblyConnectorEndAnchor{south}%
+ }
+ }{}%
+ %
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorStartAnchorTmp}{}}{%
+ }{%
+ \def\tikzumlAssemblyConnectorStartAnchor{\tikzumlAssemblyConnectorStartAnchorTmp}%
+ }%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorEndAnchorTmp}{}}{%
+ }{%
+ \def\tikzumlAssemblyConnectorEndAnchor{\tikzumlAssemblyConnectorEndAnchorTmp}%
+ }%
+ %
+ \node[inner sep=0] (\tikzumlAssemblyConnectorStart@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port-tmp) at (\tikzumlAssemblyConnectorStart@nodeName.\tikzumlAssemblyConnectorStartAnchor) {};%
+ \node[inner sep=0] (\tikzumlAssemblyConnectorEnd@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port-tmp) at (\tikzumlAssemblyConnectorEnd@nodeName.\tikzumlAssemblyConnectorEndAnchor) {};%
+ %
+ \umlrelation[style={tikzuml connector style}, #1]{\tikzumlAssemblyConnectorStart@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port-tmp}{\tikzumlAssemblyConnectorEnd@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port-tmp}%
+ %
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorWithPort}{tikzumlTrue}}{%
+ \node[inner sep=0.5*\tikzumlAssemblyConnectorWidth, rectangle, draw=\tikzumlAssemblyConnectorDrawColor, fill=\tikzumlAssemblyConnectorPortFillColor] (\tikzumlAssemblyConnectorStart@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port) at (\tikzumlAssemblyConnectorStart@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port-tmp) {};%
+ \node[inner sep=0.5*\tikzumlAssemblyConnectorWidth, rectangle, draw=\tikzumlAssemblyConnectorDrawColor, fill=\tikzumlAssemblyConnectorPortFillColor] (\tikzumlAssemblyConnectorEnd@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port) at (\tikzumlAssemblyConnectorEnd@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port-tmp) {};%
+ }{%
+ \node[inner sep=0] (\tikzumlAssemblyConnectorStart@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port) at (\tikzumlAssemblyConnectorStart@nodeName.\tikzumlAssemblyConnectorStartAnchor) {};%
+ \node[inner sep=0] (\tikzumlAssemblyConnectorEnd@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port) at (\tikzumlAssemblyConnectorEnd@nodeName.\tikzumlAssemblyConnectorEndAnchor) {};%
+ }%
+ %
+ \addtocounter{tikzumlRelationNum}{-1}%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorName}{connector-\thetikzumlConnectorNum}}{%
+ \edef\tikzumlAssemblyConnectorName{relation-\thetikzumlRelationNum}%
+ \edef\tikzumlAssemblyConnectorSymbolName{\tikzumlAssemblyConnectorLabel@nodeName}%
+ }{%
+ \edef\tikzumlAssemblyConnectorSymbolName{\tikzumlAssemblyConnectorName}%
+ }%
+ %
+ \stepcounter{tikzumlRelationNum}%
+ %
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{--}}{%
+ \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorStart@nodeName}{\tikzumlAssemblyConnectorEnd@nodeName}%
+ }{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{-|}}{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorFirstArm}{tikzumlTrue}}{%
+ \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorStart@nodeName}{\tikzumlAssemblyConnectorName-2}%
+ }{%
+ \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorName-2}{\tikzumlAssemblyConnectorEnd@nodeName}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{|-}}{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorFirstArm}{tikzumlTrue}}{%
+ \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorStart@nodeName}{\tikzumlAssemblyConnectorName-2}%
+ }{%
+ \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorName-2}{\tikzumlAssemblyConnectorEnd@nodeName}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{-|-}}{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorFirstArm}{tikzumlTrue}}{%
+ \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorStart@nodeName}{\tikzumlAssemblyConnectorName-2}%
+ }{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorLastArm}{tikzumlTrue}}{%
+ \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorName-4}{\tikzumlAssemblyConnectorEnd@nodeName}%
+ }{%
+ \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorName-2}{\tikzumlAssemblyConnectorName-4}%
+ }%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{|-|}}{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorFirstArm}{tikzumlTrue}}{%
+ \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorStart@nodeName}{\tikzumlAssemblyConnectorName-2}%
+ }{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorLastArm}{tikzumlTrue}}{%
+ \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorName-4}{\tikzumlAssemblyConnectorEnd@nodeName}%
+ }{%
+ \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorName-2}{\tikzumlAssemblyConnectorName-4}%
+ }%
+ }%
+ }{}%
+ }%
+ }%
+ }%
+ }%
+ \stepcounter{tikzumlConnectorNum}%
+}%
+%
+% shortcuts of \umlassemblyconnector
+\newcommand{\umlHVassemblyconnector}[3][]{%
+ \pgfkeys{/tikzuml/HVassemblyconnector/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlHVassemblyconnector, forbidden option geometry}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/HVassemblyconnector/.cd, #1}%
+ \umlassemblyconnector[geometry=-|, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlVHassemblyconnector}[3][]{%
+ \pgfkeys{/tikzuml/VHassemblyconnector/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlVHassemblyconnector, forbidden option geometry}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/VHassemblyconnector/.cd, #1}%
+ \umlassemblyconnector[geometry=|-, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlHVHassemblyconnector}[3][]{%
+ \pgfkeys{/tikzuml/HVHassemblyconnector/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlHVHassemblyconnector, forbidden option geometry}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/HVHassemblyconnector/.cd, #1}%
+ \umlassemblyconnector[geometry=-|-, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlVHVassemblyconnector}[3][]{%
+ \pgfkeys{/tikzuml/VHVassemblyconnector/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlVHVassemblyconnector, forbidden option geometry}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/VHVassemblyconnector/.cd, #1}%
+ \umlassemblyconnector[geometry=|-|, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlport}[3][]{%
+ \pgfkeys{/tikzuml/port/.cd, draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlPortDefaultFillColor,%
+ width/.initial=\tikzumlPortDefaultWidth,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \errmessage{TIKZUML ERROR : in umlport forbidden option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/port/.cd, #1}%
+ \pgfkeys{/tikzuml/port/.cd, width/.get=\tikzumlPortWidth,%
+ draw/.get=\tikzumlPortDrawColor, fill/.get=\tikzumlPortFillColor}%
+ \edef\tikzumlPort@name{#2}%
+ \edef\tikzumlPort@anchor{#3}%
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlPort@nodeName{\tikzumlPort@name}}\x%
+ %
+ \node[inner sep=0.5*\tikzumlPortWidth, rectangle, draw=\tikzumlPortDrawColor, fill=\tikzumlPortFillColor] (\tikzumlPort@nodeName-\tikzumlPort@anchor-port) at (\tikzumlPort@nodeName.\tikzumlPort@anchor) {};%
+}%
+%
+\newcommand{\umldelegateconnector}[3][]{%
+ \def\tikzumlDelegateConnectorWithStartPort{tikzumlFalse}%
+ \def\tikzumlDelegateConnectorWithEndPort{tikzumlFalse}%
+ \pgfkeys{/tikzuml/delegateconnector/.cd,
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umldelegateconnector, forbidden option stereo}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/delegateconnector/.cd, #1}%
+ \umlrelation[style={tikzuml connector style}, stereo=delegate, #1]{#2}{#3}%
+}%
+%
+% shortcuts of \umldelegateconnector
+\newcommand{\umlHVdelegateconnector}[3][]{%
+ \pgfkeys{/tikzuml/HVdelegateconnector/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}\OR\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlHVdelegateconnector, forbidden option \keyname}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/HVdelegateconnector/.cd, #1}%
+ \umldelegateconnector[geometry=-|, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlVHdelegateconnector}[3][]{%
+ \pgfkeys{/tikzuml/VHdelegateconnector/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}\OR\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlVHdelegateconnector, forbidden option \keyname}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/VHdelegateconnector/.cd, #1}%
+ \umldelegateconnector[geometry=|-, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlHVHdelegateconnector}[3][]{%
+ \pgfkeys{/tikzuml/HVHdelegateconnector/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}\OR\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlHVHdelegateconnector, forbidden option \keyname}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/HVHdelegateconnector/.cd, #1}%
+ \umldelegateconnector[geometry=-|-, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlVHVdelegateconnector}[3][]{%
+ \pgfkeys{/tikzuml/VHVdelegateconnector/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}\OR\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlVHVdelegateconnector, forbidden option \keyname}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/VHVdelegateconnector/.cd, #1}%
+ \umldelegateconnector[geometry=|-|, #1]{#2}{#3}%
+}%
+%%% End of tikz-uml.sty
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \ No newline at end of file
diff --git a/00-pflichtenheft/titlepage.tex b/00-pflichtenheft/titlepage.tex
new file mode 100644
index 0000000..a1ddb42
--- /dev/null
+++ b/00-pflichtenheft/titlepage.tex
@@ -0,0 +1,75 @@
+%% Encoding: UTF-8 %%
+
+%% titlepage.tex
+
+\def\usesf{}
+\let\usesf\sffamily % diese Zeile auskommentieren für normalen TeX Font
+
+\begin{titlepage}
+
+\setlength{\unitlength}{1pt}
+\begin{picture}(00,0)(70,770)
+ \includegraphics[width=\paperwidth]{assets/KIT_Deckblatt.pdf}
+\end{picture}
+
+\thispagestyle{empty}
+
+\begin{center}
+\hbox{}
+\vfill
+\includegraphics[width=.5\textwidth]{assets/logo.pdf}
+\vskip 1cm
+{\usesf
+ {\huge\bfseries PSE\textsuperscript{2} - Podcast Synchronisation \\
+ made Efficient\\
+ Pflichtenheft \par}
+\vskip 1.8cm
+{\Large Wintersemester 2022/2023\\}
+%von\\[2mm]
+\vskip 1.5cm
+
+% {\large\bfseries Vorname Nachname\\}
+% \vskip 1.2cm
+Praxis der Softwareentwicklung \\
+Prof. Dr.-Ing. Gregor Snelting \\
+Fakultät für Informatik\\
+Karlsruher Institut für Technologie\\
+\vskip 1.5cm
+\begin{tabular}{p{20mm}l}
+Autoren:
+& Daniel Hönlinger \\
+& Gero Beckmann \\
+& Immanuel Reitz \\
+& Julius Friesen \\
+& Lukas Schmidheissler \\
+\\
+Betreuer: & M.Sc. Hans-Peter Lehmann \\
+ & M.Sc. Daniel Seemaier
+\end{tabular}
+}
+\end{center}
+\vfill
+
+%\begin{textblock}{10}[0,0](4,15)
+% \includegraphics[width=.3\textwidth]{logos/logo.pdf}
+%\end{textblock}
+
+% \begin{textblock}{8}[0,0](14,14)
+% \includegraphics[width=.3\textwidth]{logos/KASTEL_logo.pdf}
+% \end{textblock}
+
+\end{titlepage}
+
+% \thispagestyle{empty}
+% \ \vfill
+% \begin{flushleft}
+% Copyright $\copyright$ ITI und Verfasser 201?\\
+% \ \\
+% Institut für Theoretische Informatik
+% Fakultät für Informatik\\
+% Karlsruher Institut für Technologie\\
+% Am Fasanengarten 5\\
+% 76131 Karlsruhe
+% \end{flushleft}
+% \newpage
+
diff --git a/01-pflichtenheft-kolloquium/.gitignore b/01-pflichtenheft-kolloquium/.gitignore
new file mode 100644
index 0000000..87ec682
--- /dev/null
+++ b/01-pflichtenheft-kolloquium/.gitignore
@@ -0,0 +1,302 @@
+## Core latex/pdflatex auxiliary files:
+*.aux
+*.lof
+*.log
+*.lot
+*.fls
+*.out
+*.toc
+*.fmt
+*.fot
+*.cb
+*.cb2
+.*.lb
+
+## Intermediate documents:
+*.dvi
+*.xdv
+*-converted-to.*
+# these rules might exclude image files for figures etc.
+# *.ps
+# *.eps
+*.pdf
+!assets/*.pdf
+
+## Generated if empty string is given at "Please type another file name for output:"
+.pdf
+
+## Bibliography auxiliary files (bibtex/biblatex/biber):
+*.bbl
+*.bcf
+*.blg
+*-blx.aux
+*-blx.bib
+*.run.xml
+
+## Build tool auxiliary files:
+*.fdb_latexmk
+*.synctex
+*.synctex(busy)
+*.synctex.gz
+*.synctex.gz(busy)
+*.pdfsync
+
+## Build tool directories for auxiliary files
+# latexrun
+latex.out/
+
+## Auxiliary and intermediate files from other packages:
+# algorithms
+*.alg
+*.loa
+
+# achemso
+acs-*.bib
+
+# amsthm
+*.thm
+
+# beamer
+*.nav
+*.pre
+*.snm
+*.vrb
+
+# changes
+*.soc
+
+# comment
+*.cut
+
+# cprotect
+*.cpt
+
+# elsarticle (documentclass of Elsevier journals)
+*.spl
+
+# endnotes
+*.ent
+
+# fixme
+*.lox
+
+# feynmf/feynmp
+*.mf
+*.mp
+*.t[1-9]
+*.t[1-9][0-9]
+*.tfm
+
+#(r)(e)ledmac/(r)(e)ledpar
+*.end
+*.?end
+*.[1-9]
+*.[1-9][0-9]
+*.[1-9][0-9][0-9]
+*.[1-9]R
+*.[1-9][0-9]R
+*.[1-9][0-9][0-9]R
+*.eledsec[1-9]
+*.eledsec[1-9]R
+*.eledsec[1-9][0-9]
+*.eledsec[1-9][0-9]R
+*.eledsec[1-9][0-9][0-9]
+*.eledsec[1-9][0-9][0-9]R
+
+# glossaries
+*.acn
+*.acr
+*.glg
+*.glo
+*.gls
+*.glsdefs
+*.lzo
+*.lzs
+*.slg
+*.slo
+*.sls
+
+# uncomment this for glossaries-extra (will ignore makeindex's style files!)
+*.ist
+
+# gnuplot
+*.gnuplot
+*.table
+
+# gnuplottex
+*-gnuplottex-*
+
+# gregoriotex
+*.gaux
+*.glog
+*.gtex
+
+# htlatex
+*.4ct
+*.4tc
+*.idv
+*.lg
+*.trc
+*.xref
+
+# hyperref
+*.brf
+
+# knitr
+*-concordance.tex
+# TODO Uncomment the next line if you use knitr and want to ignore its generated tikz files
+# *.tikz
+*-tikzDictionary
+
+# listings
+*.lol
+
+# luatexja-ruby
+*.ltjruby
+
+# makeidx
+*.idx
+*.ilg
+*.ind
+
+# minitoc
+*.maf
+*.mlf
+*.mlt
+*.mtc[0-9]*
+*.slf[0-9]*
+*.slt[0-9]*
+*.stc[0-9]*
+
+# minted
+_minted*
+*.pyg
+
+# morewrites
+*.mw
+
+# newpax
+*.newpax
+
+# nomencl
+*.nlg
+*.nlo
+*.nls
+
+# pax
+*.pax
+
+# pdfpcnotes
+*.pdfpc
+
+# sagetex
+*.sagetex.sage
+*.sagetex.py
+*.sagetex.scmd
+
+# scrwfile
+*.wrt
+
+# svg
+svg-inkscape/
+
+# sympy
+*.sout
+*.sympy
+sympy-plots-for-*.tex/
+
+# pdfcomment
+*.upa
+*.upb
+
+# pythontex
+*.pytxcode
+pythontex-files-*/
+
+# tcolorbox
+*.listing
+
+# thmtools
+*.loe
+
+# TikZ & PGF
+*.dpth
+*.md5
+*.auxlock
+
+# titletoc
+*.ptc
+
+# todonotes
+*.tdo
+
+# vhistory
+*.hst
+*.ver
+
+# easy-todo
+*.lod
+
+# xcolor
+*.xcp
+
+# xmpincl
+*.xmpi
+
+# xindy
+*.xdy
+
+# xypic precompiled matrices and outlines
+*.xyc
+*.xyd
+
+# endfloat
+*.ttt
+*.fff
+
+# Latexian
+TSWLatexianTemp*
+
+## Editors:
+# WinEdt
+*.bak
+*.sav
+
+# Texpad
+.texpadtmp
+
+# LyX
+*.lyx~
+
+# Kile
+*.backup
+
+# gummi
+.*.swp
+
+# KBibTeX
+*~[0-9]*
+
+# TeXnicCenter
+*.tps
+
+# auto folder when using emacs and auctex
+./auto/*
+*.el
+
+# expex forward references with \gathertags
+*-tags.tex
+
+# standalone packages
+*.sta
+
+# Makeindex log files
+*.lpz
+
+# xwatermark package
+*.xwm
+
+# REVTeX puts footnotes in the bibliography by default, unless the nofootinbib
+# option is specified. Footnotes are the stored in a file with suffix Notes.bib.
+# Uncomment the next line to have this generated file ignored.
+#*Notes.bib
diff --git a/01-pflichtenheft-kolloquium/.gitlab-ci.yml b/01-pflichtenheft-kolloquium/.gitlab-ci.yml
new file mode 100644
index 0000000..427b043
--- /dev/null
+++ b/01-pflichtenheft-kolloquium/.gitlab-ci.yml
@@ -0,0 +1,15 @@
+image: texlive/texlive
+
+pages:
+ script:
+ - mkdir public
+ - make
+ - mv *.pdf public
+ artifacts:
+ paths:
+ - public
+ rules:
+ - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
+
+
+
diff --git a/01-pflichtenheft-kolloquium/CHANGELOG.md b/01-pflichtenheft-kolloquium/CHANGELOG.md
new file mode 100644
index 0000000..7671a41
--- /dev/null
+++ b/01-pflichtenheft-kolloquium/CHANGELOG.md
@@ -0,0 +1,34 @@
+# Changelog
+Alle Änderungen an diesem Projekt werden in dieser Datei dokumentiert.
+Die Versionsnummern folgt der Syntax in `sdqbeamer.cls`.
+
+## [2022-05-03 v3.1.3]
+- Die Breite des Gruppennamens in der Fußzeile kann nun über `\groupnamewidth{}` gesteuert werden
+- FIX: zweizeilige Fußzeilen haben nun gleichmäßigen vertikalen Abstand (Issue #16 in Gitlab)
+
+## [2021-08-10 v3.1.2]
+- FIX: framesubtitle wird nun angezeigt (Issue #6 in Gitlab)
+
+## [2020-12-08 v3.1.1]
+- FIX: Titelbild (Issue #4 in Gitlab)
+
+## [2020-12-07 v3.1]
+- Umgebung ``contentblock`` (farbloser Block mit fetter Überschrift) hinzugefügt
+- Farbboxen (``greenblock``, ``blueblock``, …) hinzugefügt
+- Abstufungen der KIT-Farben in 10er-Schritten entsprechend der Gestaltungsrichtlinien eingeführt
+- FIX: Navigationspunkte für Subsections in eine Zeile gesetzt, um vertikal Platz zu sparen
+- FIX: ``inputenc`` an den Anfang von ``sdqbeamer.cls`` verschoben
+
+## [2020-11-16 v3.0]
+- Seitenformat 16:10 hinzugefügt
+- Umstellung auf KIT-Design vom 1. August 2020
+ - Anpassung auf neues Farbschema und Maße
+ - neues Titelbild aus der KIT-Bildwelt
+- Neue Optionen:
+ - durch `smallfoot` und `bigfoot` kann die Schriftgröße der Fußzeile gesteuert werden
+ - durch `navbarkit` kann eine Fußzeile nach KIT-Vorgaben erzwungen werden
+- Deutsch (`de`) ist nun die Standard-Option
+- Ordner `templates` wurde gelöscht und die Inhalte in `sdqbeamer.cls` integriert
+- Globale Größe auf 10 pt verringert (vorher: 11 pt), da der beschreibbare Bereich im Vergleich zur 2009er Version kleiner geworden ist
+- SDQ-spezifische Logos und Titelbilder entfernt. Diese sind ab sofort im Branch »sdq« verfügbar.
+- Fix: Zeilenumbruch bei Titel in der Fußzeile repariert \ No newline at end of file
diff --git a/01-pflichtenheft-kolloquium/Makefile b/01-pflichtenheft-kolloquium/Makefile
new file mode 100644
index 0000000..65ba963
--- /dev/null
+++ b/01-pflichtenheft-kolloquium/Makefile
@@ -0,0 +1,10 @@
+MAIN = presentation.tex
+FLAGS = -pdf
+
+all:
+ latexmk $(FLAGS) $(MAIN)
+dev:
+ latexmk $(FLAGS) -pvc $(MAIN)
+clean:
+ latexmk -C
+
diff --git a/01-pflichtenheft-kolloquium/README.md b/01-pflichtenheft-kolloquium/README.md
new file mode 100644
index 0000000..6a5e9ea
--- /dev/null
+++ b/01-pflichtenheft-kolloquium/README.md
@@ -0,0 +1,118 @@
+LaTeX-Vorlage für Präsentationen
+================================
+
+Das vorliegende Paket dient als Vorlage für Präsentationen im [Corporate Design des KIT](https://intranet.kit.edu/gestaltungsrichtlinien.php) (Fassung vom 1. August 2020).
+
+Es wird an der Forschungsgruppe [DSiS](https://dsis.kastel.kit.edu) an der KIT-Fakultät für Informatik entwickelt und basiert auf [LaTeX Beamer](https://ctan.org/pkg/beamer).
+
+Autor: [Dr.-Ing. Erik Burger](https://dsis.kastel.kit.edu/staff_erik_burger.php)
+mit Beiträgen von Christian Hammer, Klaus Krogmann und Maximilian Schambach
+
+Siehe https://sdqweb.ipd.kit.edu/wiki/Dokumentvorlagen
+
+Hinweise, Verbesserungsvorschläge
+=================================
+
+Bitte verwenden Sie das [Issue-Tracking-System von Gitlab](https://git.scc.kit.edu/i43/dokumentvorlagen/praesentationen/beamer/-/issues), um auf Probleme mit der Vorlage hinzuweisen oder Erweiterungswünsche zu äußern. Sie können gerne auch eine Änderung per Merge-Request vorschlagen.
+
+Verwendung
+==========
+
+Optionen der Dokumentklasse `sdqbeamer`
+-----------------------------------------
+Durch die folgenden Optionen kann das Seitenverhältnis der Folien bestimmt werden:
+
+| Seitenverhältnis | Option |
+| ---------------- | ------------------- |
+| 16:9 | `16:9` (Standard) |
+| 16:10 | `16:10` |
+| 4:3 | `4:3` |
+
+Die Schriftgröße in der Fußzeile ist standardmäßig größer gewählt, als in den Gestaltungsrichtlinien vorgegeben. Diese Vorgabe kann durch die Option `smallfoot` erzwungen werden.
+
+| Schriftgröße Fußzeile | Option |
+| ----------------------| -------------------- |
+| etwas größer (12pt) | `bigfoot` (Standard) |
+| KIT-Vorgabe (9pt) | `smallfoot` |
+
+Die Plazierung der Navigationsleiste kann durch folgende Optionen beeinflußt werden:
+
+| Position | Option | Bemerkung |
+| ------------------------ | ---------------- | ------------------------------------------ |
+| oberhalb der Trennlinie | `navbarinline` | Standard |
+| unterhalb der Trennlinie | `navbarinfooter` | keine Subsection-Punkte, Größe `smallfoot` |
+| Seitenleiste links | `navbarside` | keine Subsection-Punkte |
+| keine Navigationsleiste | `navbaroff` | |
+| KIT-Vorgabe | `navbarkit` | entspricht `navbaroff` und `smallfoot` |
+
+Als Sprache sind Deutsch und Englisch verfügbar. Durch die Sprachwahl werden automatisch die passenden Logos und Formate (z.B. Datum) gewählt.
+
+| Sprache | |
+| -------- |---------------- |
+| Deutsch | `de` (Standard) |
+| Englisch | `en` |
+
+Beispiel: `\documentclass[de,16:9,navbarinline]{sdqbeamer}`
+
+Titelbild
+---------
+
+Das Bild auf der Titelfolie kann mit dem Befehl
+
+`\titleimage{myimage}` (ohne Dateiendung)
+
+gesetzt werden. Um ein eigenes Bild zu verwenden, bitte die Datei (z.B. `myimage.jpg`) ins `logos/`-Verzeichnis legen und den Befehl anpassen. Mitgeliefert wird ein generisches Bild aus der KIT-Bildwelt (https://intranet.kit.edu/gestaltungsrichtlinien.php) in der Datei `logos/banner_2020_kit.jpg`. Falls kein Titelbild eingefügt werden soll, bitte `\titleimage{}` setzen.
+
+Für 16:9-Folien sollte das Verhältnis des Bildes 160:37 betragen, für 4:3-Folien 63:20. Es können auch breitere Bilder verwendet werden, da das Titelbild auf die Höhe des Rahmens skaliert und zentriert wird.
+
+Logo und Name Abteilung/KIT-Fakultät/Institut
+---------------------------------------------
+
+Das Logo rechts oben auf der Titelfolie kann mit dem folgenden Befehl gesetzt werden:
+
+`\grouplogo{mylogo}` (ohne Dateiendung)
+
+Um ein eigenes Logo zu verwenden, bitte die Datei (z.B. `mylogo.pdf`) in das Verzeichnis `logos/` legen und den Befehl anpassen. Falls kein Logo eingefügt werden soll, bitte `\grouplogo{}` setzen.
+
+Der Gruppenname kann mit folgendem Befehl gesetzt werden:
+
+`\groupname{Software Design and Quality}`
+
+Der Gruppenname erscheint in der Fußzeile rechts unten. Lange Namen werden in zwei Zeilen umgebrochen. Falls der Gruppenname leer gelassen wird (`\groupname{}`), wird die volle Breite der Fußzeile für Autornamen und Titel verwendet.
+
+Die Standardbreite des Gruppennamens sind 50 mm. Sie kann mit
+
+`\groupnamewidth{80mm}`
+
+verändert werden, wodurch sich auch die Breite des Textfeldes mit Autor und Titel entsprechend ändert. Umbrüche sind mit `\\` möglich. Statt zweizeiliger Fußzeilen empfiehlt sich eventuell die Option `smallfoot`.
+
+LaTeX allgemein
+---------------
+Siehe https://sdqweb.ipd.kit.edu/wiki/LaTeX
+
+Dateistruktur
+============
+`presentation.tex`
+------------------
+Hauptdatei des LaTeX-Dokuments.
+
+`presentation.bib`
+-------------
+Beispieldatei für BibTeX-Referenzen
+https://sdqweb.ipd.kit.edu/wiki/BibTeX-Literaturlisten
+
+`sdqbeamer.cls`
+-----------------
+Dokumentklasse für Präsentationen im KIT-Design.
+
+`logos/`
+--------
+In diesem Verzeichnis befinden das KIT-Logo als PDF sowie das Hintergrundbild der Titelfolie als JPG.
+
+`CHANGELOG.md`
+--------------
+Dokumentation der Änderungen in den jeweiligen Versionen.
+
+`README.md`
+-----------
+Dieser Text.
diff --git a/01-pflichtenheft-kolloquium/logos/banner_2020_kit.jpg b/01-pflichtenheft-kolloquium/logos/banner_2020_kit.jpg
new file mode 100644
index 0000000..70ae1d0
--- /dev/null
+++ b/01-pflichtenheft-kolloquium/logos/banner_2020_kit.jpg
Binary files differ
diff --git a/01-pflichtenheft-kolloquium/notizen b/01-pflichtenheft-kolloquium/notizen
new file mode 100644
index 0000000..70ac63b
--- /dev/null
+++ b/01-pflichtenheft-kolloquium/notizen
@@ -0,0 +1,40 @@
+Titelseite:
+- Begrüßung
+
+Einführung:
+- Podcast: RSS-Feed, Episoden, Audio/Video
+- Podcatcher: lokale Verwaltung von Podcasts, API Unterstützung,
+Abspielen von Episoden
+- Synchronisationsserver (das soll unser Produkt werden): Hörfortschritte,
+Abonnements, Discovery (bei AntennaPod z.B. iTunes)
+
+Zielsetzung:
+
+Synchronisation (die Art, die wir bei uns anwenden):
+- alle Aktionen werden auf den Server und infolge dessen auf alle Podcatcher
+übertragen
+
+Features:
+- Synchronisation: Abos, Hörfortschritt
+- Weboberfläche: Aboliste, Zuletzt gehört
+- Account-Verwaltung: Registrieren, Anmelden, Passwort ändern/zurücksetzen,
+Account löschen, Daten importieren/exportieren
+
+UI-Journey:
+- login.html:
+ - Sprache ändern
+ - OAuth (kann)
+ - Registrieren (muss): neues Fenster, E-Mail + 2-mal Passwort (sicher?),
+ vergeben? -> Fehler / Bestätigungslink per E-Mail (gültig 24h)
+ - Anmelden (muss): E-Mail + Passwort eingeben, Login merken,
+ login, Fehlermeldung oder Dashboard
+ - Passwort vergessen: neues Fenster, E-Mail eingeben, falls Account wird
+ Link versendet, 24h gültig, nach betätigen PW zweimal eingeben & bestätigen
+ (Anforderungen)
+
+- podcasts.html: Abonnements, Eisoden, Hörfortschritte
+
+- listening.html: Zuletzt gehörte Episoden, Hörfortschritt, Wann gehört
+
+- settings.html: PW ändern, Gpodder Import, pers. Daten imp./exp.,
+ Account löschen
diff --git a/01-pflichtenheft-kolloquium/presentation.tex b/01-pflichtenheft-kolloquium/presentation.tex
new file mode 100644
index 0000000..2f65a95
--- /dev/null
+++ b/01-pflichtenheft-kolloquium/presentation.tex
@@ -0,0 +1,60 @@
+%% Beispiel-Präsentation mit LaTeX Beamer im KIT-Design
+%% entsprechend den Gestaltungsrichtlinien vom 1. August 2020
+%%
+%% Siehe https://sdqweb.ipd.kit.edu/wiki/Dokumentvorlagen
+
+%% Beispiel-Präsentation
+\documentclass{sdqbeamer}
+
+\usepackage{tikz}
+\usetikzlibrary{positioning}
+\usetikzlibrary{calc}
+\usetikzlibrary{arrows}
+\usepackage{multicol}
+\usepackage{fontawesome5}
+\usepackage{tikz}
+\usepackage{tikz-uml}
+\usetikzlibrary{positioning, arrows, chains}
+\usetikzlibrary[calc]
+
+
+%% Titelbild
+\titleimage{banner_2020_kit}
+
+%% Gruppenlogo
+\grouplogo{kitlogo_de_rgb}
+
+%% Gruppenname und Breite (Standard: 50 mm)
+\groupname{Praxis der Softwareentwicklung}
+%\groupnamewidth{50mm}
+
+% Beginn der Präsentation
+
+\title[Kolloquium Pflichtenheft]{
+ PSE\textsuperscript{2} - Podcast Synchronisation made Efficient
+}
+\subtitle{Kolloquium Pflichtenheft}
+\author[Julius Friesen]{Julius Friesen}
+
+\date[06.\,12.\,2022]{06. Dezember 2022}
+
+\begin{document}
+
+%Titelseite
+\KITtitleframe
+
+% Folie Einführung
+\include{slides/einführung}
+
+% Folie Zielsetzung
+\include{slides/zielsetzung}
+
+% TODO: Folie Synchronisation
+\include{slides/synchronisation}
+
+% TODO: Folie Features
+\include{slides/features}
+
+% TODO: User-Journey
+
+\end{document}
diff --git a/01-pflichtenheft-kolloquium/sdqbeamer.cls b/01-pflichtenheft-kolloquium/sdqbeamer.cls
new file mode 100644
index 0000000..8f0433b
--- /dev/null
+++ b/01-pflichtenheft-kolloquium/sdqbeamer.cls
@@ -0,0 +1,954 @@
+%% Vorlage für Präsentationen mit LaTeX Beamer im KIT-Design
+%% entsprechend den Gestaltungsrichtlinien vom 1. August 2020
+%%
+%% Siehe https://sdqweb.ipd.kit.edu/wiki/Dokumentvorlagen
+
+
+\NeedsTeXFormat{LaTeX2e}
+\ProvidesClass{sdqbeamer}[2022-05-03 v3.1.3 SDQ Beamer class]
+
+\RequirePackage[utf8]{inputenc}
+\RequirePackage[T1]{fontenc}
+
+\newif\ifsectionnavigation
+\newif\ifnavbarinfoot
+\newif\ifnavbarinline
+\newif\ifnavbarside
+\newif\iffourtothree
+\newif\ifsixteentonine
+\newif\ifsixteentoten
+\newif\ifgerman
+\newif\ifsmallfooterfont
+
+\def\kitslogan#1{\def\@kitslogan{#1}}
+\def\kitlogo#1{\def\@kitlogo{#1}}
+\def\groupname#1{\def\@groupname{#1}}
+\def\groupnamewidth#1{\def\@groupnamewidth{#1}}
+
+% siehe README.md
+\DeclareOption{de}{
+ \kitslogan{KIT -- Die Forschungsuniversität in der Helmholtz-Gemeinschaft}
+ \kitlogo{pse_logo}
+ \germantrue
+ \PassOptionsToPackage{autostyle}{csquotes}
+ }
+\DeclareOption{en}{
+ \kitslogan{KIT -- The Research University in the Helmholtz Association}
+ \kitlogo{kitlogo_en_rgb}
+ \germanfalse
+ }
+\DeclareOption{4:3}{
+ \fourtothreetrue
+ \sixteentoninefalse
+ \sixteentotenfalse
+}
+\DeclareOption{16:9}{
+ \fourtothreefalse
+ \sixteentoninetrue
+ \sixteentotenfalse
+}
+\DeclareOption{16:10}{
+ \fourtothreefalse
+ \sixteentoninefalse
+ \sixteentotentrue
+}
+\DeclareOption{navbarside}{
+ \sectionnavigationtrue
+ \navbarsidetrue
+ \navbarinlinefalse
+ \navbarinfootfalse
+}
+\DeclareOption{navbarinline}{
+ \sectionnavigationtrue
+ \navbarsidefalse
+ \navbarinlinetrue
+ \navbarinfootfalse
+}
+\DeclareOption{navbarinfooter}{
+ \sectionnavigationtrue
+ \navbarsidefalse
+ \navbarinlinefalse
+ \navbarinfoottrue
+}
+\DeclareOption{navbaroff}{
+ \sectionnavigationfalse
+}
+\DeclareOption{navbarkit}{
+ \sectionnavigationfalse
+ \smallfooterfonttrue
+}
+\DeclareOption{smallfoot}{
+ \smallfooterfonttrue
+}
+\DeclareOption{bigfoot}{
+ \smallfooterfontfalse
+}
+
+\ExecuteOptions{de,16:9,navbarinline,bigfoot}
+
+\DeclareOption*{\PassOptionsToClass{\CurrentOption}{beamer}}
+
+\ProcessOptions\relax
+
+\LoadClass[10pt,utf8]{beamer}
+
+% Babel-Paket wird nur bei deutscher Sprache benötigt
+\ifgerman
+ \RequirePackage[ngerman]{babel}
+\fi
+\RequirePackage{csquotes}
+\RequirePackage{hyperref}
+\RequirePackage[absolute,overlay]{textpos}
+
+%% ---------------
+%% | Typographie |
+%% ---------------
+
+\RequirePackage{microtype}
+
+\RequirePackage[scaled=.92]{helvet}
+\RequirePackage[scaled=.78]{beramono}
+\RequirePackage{libertineRoman}
+
+\setbeamerfont{title}{series=\bfseries,size=\Large}
+\setbeamerfont{frametitle}{series=\bfseries,size=\Large}
+\setbeamerfont{framesubtitle}{series=\bfseries,size=\normalsize}
+
+%% -----------------
+%% | Folien-Layout |
+%% -----------------
+
+% Seitenverhältnis
+%
+% Die Folien sind auf die Standardhöhe in LaTeX Beamer (9,6 cm) normiert.
+% Die Maße der KIT-Gestaltungsrichtlinien (Folienhöhe 14,3 cm) wurden durch
+% den Quotienten 1,5 geteilt.
+
+\RequirePackage{geometry}
+\iffourtothree
+ \geometry{papersize={12.8cm,9.6cm}}
+\fi
+\ifsixteentoten
+ \geometry{papersize={15.36cm,9.6cm}}
+\fi
+\ifsixteentonine
+ \geometry{papersize={17.07cm,9.6cm}}
+\fi
+
+% Ränder laut Gestaltungsrichtlinen; 3 mm -> 2 mm, 11 mm -> 7,3 mm
+\newlength{\kitoutermargin}
+\setlength{\kitoutermargin}{2mm}
+\newlength{\kitinnermargin}
+\setlength{\kitinnermargin}{7.3mm}
+\newlength{\kitbottommargin}
+\setlength{\kitbottommargin}{\kitinnermargin}
+
+% Ränder außen
+\setbeamersize{text margin left=\kitinnermargin,text margin right=\kitinnermargin}
+
+% keine Navigationssymbole
+\setbeamertemplate{navigation symbols}{}
+\setbeamercovered{invisible}
+\useinnertheme{rounded}
+\beamer@compresstrue % Miniframes (Navigations-Punkte) für Subsections immer in einer Zeile, ohne Umbrüche
+
+% Folientitel
+\setbeamertemplate{frametitle}{
+ \ifbeamer@plainframe\else%
+ % Unterkante Titeltext: 22,5 mm -> 15 mm von Seitenkopf
+ \begin{textblock*}{\dimexpr\paperwidth-30mm-2\kitinnermargin}[0,1](\kitinnermargin,15mm)%
+ \usebeamerfont{frametitle}\insertframetitle%
+ \ifx\insertframesubtitle\@empty\else\\[.1em]\fi
+ \usebeamerfont{framesubtitle}\insertframesubtitle%
+ \end{textblock*}%
+ \begin{textblock*}{20mm}[1,1](\dimexpr\paperwidth-\kitinnermargin\relax,15mm)%j
+ \includegraphics[width=20mm]{logos/\@kitlogo}%
+ \end{textblock*}%
+ \fi
+% Rand oben (ergibt Beginn des Textes bei 34 mm -> 22,7 mm)
+ \vspace {18mm}
+}
+
+%% Fußzeile
+\newlength{\kitbottom}
+ % Navbar in Footer: Schmale Fußzeile
+\ifnavbarinfoot
+ % Bei Navbar in Footer immer kleiner Font in der Fußzeile
+ \setbeamerfont{footer}{size=\fontsize{6pt}{7.2pt}\selectfont}
+ \setlength{\kitbottom}{4mm}
+\else
+ % Ansonsten kleiner Text nur, wenn "smallfoot" gewählt
+ \ifsmallfooterfont
+ \setbeamerfont{footer}{size=\fontsize{6pt}{7.2pt}\selectfont}
+ \else
+ \setbeamerfont{footer}{size=\scriptsize}
+ \fi
+ \setlength{\kitbottom}{\kitbottommargin}
+\fi
+\setbeamerfont{page number in head/foot}{series=\bfseries}
+
+\newlength{\kitbottomdepth}
+\newlength{\kitbottomheight}
+\newlength{\kitfootergroupwidth}
+
+\setbeamertemplate{footline}{%
+\setlength{\kitbottomdepth}{\dimexpr.5\kitbottom-.5em\relax}%
+\setlength{\kitbottomheight}{\dimexpr.5\kitbottom+.5em\relax}%
+ %% die "%" am Ende sind nötig, damit keine Abstände eingefügt werden
+ %
+ % Falls kein Gruppenname angegeben, die ganze Breite der Fußzeile für den Titel nutzen.
+ \ifdefined\@groupname%
+ \ifx\@groupname\empty%
+ \setlength{\kitfootergroupwidth}{0mm}%
+ \else%
+ % Falls die Breite des Gruppenlogos definiert ist, diese nehmen, sonst 50 mm
+ \ifdefined\@groupnamewidth%
+ \setlength{\kitfootergroupwidth}{\@groupnamewidth}%
+ \else%
+ \setlength{\kitfootergroupwidth}{50mm}%
+ \fi%
+ \fi%
+ \else
+ \setlength{\kitfootergroupwidth}{0mm}%
+ \fi
+ \usebeamerfont{footer}%
+ \ifsectionnavigation%
+ % Option "navbarinline"
+ \ifnavbarinline%
+ \begin{beamercolorbox}[wd=\paperwidth, leftskip=2mm, rightskip=2mm]{}
+ \insertnavigation{\dimexpr\paperwidth-4mm\relax}
+ \vspace{1mm}
+ \end{beamercolorbox}%
+ \fi%
+ % Option "navbarinfooter"
+ \ifnavbarinfoot%
+ % Punkte für Subsections deaktivieren
+ \setbeamertemplate{mini frames}{}%
+ \begin{beamercolorbox}[wd=\paperwidth, leftskip=1mm, rightskip=1mm]{}%
+ \insertsectionnavigationhorizontal{\dimexpr\paperwidth-\kitoutermargin\relax}{}{}
+ \end{beamercolorbox}%
+ \fi%
+ \fi%
+ \leavevmode%
+ \begin{beamercolorbox}[wd=13mm, ht=\kitbottomheight, dp=\kitbottomdepth, leftskip=4mm]{}
+ \usebeamerfont{page number in head/foot}%
+ \strut\insertframenumber{}/\inserttotalframenumber%
+ \end{beamercolorbox}%
+ \begin{beamercolorbox}[wd=20mm, ht=\kitbottomheight, dp=\kitbottomdepth]{}
+ \usebeamerfont{date in head/foot}%
+ \strut\insertshortdate%
+ \end{beamercolorbox}%
+ % Die Boxen mit dem Titel und dem Gruppennamen sind vertikal zentriert, damit auch zweizeilige Texte schön aussehen
+ % Daher müssen sie um \kitbottomdepth nach unten verschoben werden
+ \raisebox{-\kitbottomdepth}{
+ % Die Box hat daher auch Höhe \kitbottom und Tiefe 0mm
+ \begin{beamercolorbox}[wd=\dimexpr\paperwidth-37mm-\kitfootergroupwidth, ht=\kitbottom, dp=0mm]{}%
+ % Inhalt vertikal zentrieren; Anpassung um 1.5 pt, damit bei einzeiligem Inhalt genau die Baseline der Blöcke mit Seitenzahl und Datum getroffen wird
+ \vbox to\kitbottom{\vfill\vskip1.5pt%
+ \beamer@shortauthor\ifx\beamer@shortauthor\empty\else: \fi\beamer@shorttitle%
+ \vfill}%
+ \end{beamercolorbox}%
+ \ifdefined\@groupname%
+ \begin{beamercolorbox}[wd=\kitfootergroupwidth, ht=\kitbottom, dp=0mm, rightskip=\kitinnermargin]{}
+ \vbox to\kitbottom{\vfill\vskip1.5pt%
+ \raggedleft\@groupname%
+ \vfill}%
+ \end{beamercolorbox}%
+ \fi%
+ }%
+}
+
+%% Option "navbarside"
+\ifnavbarside
+\useoutertheme[height=0cm,width=3.5cm,left]{sidebar}
+
+\setbeamerfont{title in sidebar}{family=\sffamily,series=\mdseries,size={\fontsize{10pt}{11pt}}}
+\setbeamerfont{section in sidebar}{family=\sffamily,series=\mdseries,size={\fontsize{9pt}{9.9pt}}}
+\setbeamerfont{subsection in sidebar}{family=\sffamily,series=\mdseries,size={\fontsize{8pt}{8.8pt}}}
+
+\setbeamertemplate{sidebar \beamer@sidebarside}
+ {\vskip1.5cm%
+ \hskip6.5mm%
+ \advance\beamer@sidebarwidth by -5mm%
+ \insertverticalnavigation{\beamer@sidebarwidth}%
+ }%
+\fi
+
+%% Hintergrund
+\usebackgroundtemplate{
+ % Trennlinie nicht bei "plain"-Frames
+ \ifbeamer@plainframe\else\kitseparationline\fi
+}
+
+% Trennlinie
+\newcommand{\kitseparationline}{
+ \begin{pgfpicture}{0mm}{0mm}{\paperwidth}{\paperheight}
+ \pgfsetstrokecolor{black!15}
+ \pgfsetlinewidth{.5pt}
+ \pgfpathmoveto{\pgfpoint{\kitoutermargin}{\kitinnermargin}}
+ \pgfpathlineto{\pgfpoint{\paperwidth-\kitoutermargin}{\kitinnermargin}}
+ \pgfusepath{stroke}
+ \end{pgfpicture}%
+}
+
+
+%% --------------
+%% | Titelseite |
+%% --------------
+
+\def\titleimage#1{\def\@titleimage{#1}}
+\def\grouplogo#1{\def\@grouplogo{#1}}
+
+\newcommand{\KITtitleframe}{
+ \begin{frame}[plain]
+ \titlepage
+ \end{frame}
+}
+
+\newlength{\kittitleimageheight}
+\setbeamertemplate{title page}{
+ % From textpos documentation (https://ctan.org/pkg/textpos)
+ %
+ % \begin{textblock}{<hsize>}[<ho>,<vo>](<hpos>,<vpos>)
+ % The coordinates <ho> and <vo> are fractions of the width and height of the text
+ % box, respectively, and state that the box is to be placed so that the reference point
+ % (<ho>,<vo>) within the box is to be placed at the point (<hpos>,<vpos>) on the page.
+
+ % KIT-Logo
+ \begin{textblock*}{30mm}(\kitinnermargin,6.7mm)
+ \includegraphics[width=30mm]{logos/\@kitlogo}
+ \end{textblock*}
+
+ % Gruppenlogo
+ \ifdefined\@grouplogo
+ \ifx\@grouplogo\empty \else
+ \begin{textblock*}{20mm}(\dimexpr\paperwidth-24mm\relax,6.7mm)
+ \includegraphics[width=20mm,height=20mm,keepaspectratio]{logos/\@grouplogo}
+ \end{textblock*}
+ \fi % falls \grouplogo{} aufgerufen wird, kein Gruppenlogo einbinden
+ \else
+ \begin{textblock*}{20mm}(\dimexpr\paperwidth-24mm\relax,6.7mm)
+ \colorbox{kit-purple100!20}{\parbox[t][12mm][c]{19mm}{\color{kit-purple100}\scriptsize\centering
+ \ifgerman
+ Bitte Logo über \texttt{\textbackslash grouplogo\{\}} festlegen.
+ \else
+ Please set a logo using \texttt{\textbackslash grouplogo\{\}}.
+ \fi
+ }}
+ \end{textblock*}
+ \fi
+
+ % Titel
+ \begin{textblock*}{\dimexpr\paperwidth-8mm\relax}[0,.5](\kitinnermargin,28mm)
+ \usebeamerfont*{title}\inserttitle
+ \end{textblock*}
+
+ % Untertitel
+ \begin{textblock*}{\dimexpr\paperwidth-8mm\relax}(\kitinnermargin,36mm)
+ \small\textbf{\insertsubtitle}
+ \end{textblock*}
+
+ % Autor
+ \begin{textblock*}{\dimexpr\paperwidth-8mm\relax}(\kitinnermargin,41mm)
+ \small\insertauthor~\textbar~\insertdate
+ \end{textblock*}
+
+ % Titelbild
+ \setlength{\kittitleimageheight}{40mm}
+ \begin{textblock*}{\paperwidth}(\kitoutermargin,\dimexpr\paperheight-\kitbottommargin-\kittitleimageheight)
+ \begin{pgfpicture}{0mm}{0mm}{\paperwidth}{\kittitleimageheight}
+ % Clipping-Pfad um titelbild
+ \pgfsetstrokecolor{black!15}
+ \pgfsetlinewidth{1pt}
+ \pgfsetcornersarced{\pgfpoint{3mm}{3mm}}
+ \pgfpathmoveto{\pgfpoint{\paperwidth-2\kitoutermargin}{0mm}}
+ \pgfpathlineto{\pgfpoint{\paperwidth-2\kitoutermargin}{\kittitleimageheight}}
+ \pgfsetcornersarced{\pgfpointorigin}
+ \pgfpathlineto{\pgfpoint{0mm}{\kittitleimageheight}}
+ \pgfsetcornersarced{\pgfpoint{3mm}{3mm}}
+ \pgfpathlineto{\pgfpointorigin}
+ \pgfsetcornersarced{\pgfpointorigin}
+ \pgfpathclose
+ \pgfusepath{stroke,clip}
+ \pgfsetstrokecolor{black}
+
+ % Titelbild
+ \ifdefined\@titleimage
+ \ifx\@titleimage\empty \else%
+ \pgftext[at=\pgfpoint{.5\paperwidth}{0mm},center,bottom]{%
+ \includegraphics[height=40mm]{logos/\@titleimage}
+ }
+ \fi % Bei Aufruf von \titleimage{} leeren Rahmen anzeigen.
+ \else
+ \pgftext[at=\pgfpoint{.5\paperwidth}{.5\kittitleimageheight},center,base]{%
+ \colorbox{kit-purple100!20}{\parbox[c][\kittitleimageheight][c]{\paperwidth}{\color{kit-purple100}\centering Bitte Titelbild über \texttt{\textbackslash titleimage\{\}} festlegen.
+ }}%
+ }
+ \fi
+
+
+ \end{pgfpicture}%
+ \end{textblock*}
+
+
+ % KIT slogan
+ \begin{textblock*}{80mm}[0,.5](\kitoutermargin,\dimexpr\paperheight-.5\kitbottommargin)
+ \fontsize{5.5pt}{5.5pt}\selectfont\@kitslogan
+ \end{textblock*}
+
+ \begin{textblock*}{30mm}[1,.5](\dimexpr\paperwidth-\kitoutermargin\relax,\dimexpr\paperheight-.5\kitbottommargin)
+ \fontsize{11pt}{11pt}\selectfont\bfseries\raggedleft%
+ {\href{https://www.kit.edu}{www.kit.edu}}
+ \end{textblock*}
+
+}
+%% ---------------
+%% | /Titelseite |
+%% ---------------
+
+%% ----------
+%% | Farben |
+%% ----------
+%% KIT-Farbschema
+
+% KIT color green :
+\definecolor{kit-green}{RGB}{0, 150, 130}
+\definecolor{kit-green100}{RGB}{0, 150, 130}
+\definecolor{kit-green90}{rgb}{0.1, 0.6294, 0.5588}
+\definecolor{kit-green80}{rgb}{0.2, 0.6706, 0.6078}
+\definecolor{kit-green75}{rgb}{0.25, 0.6912, 0.6324}
+\definecolor{kit-green70}{rgb}{0.3, 0.7118, 0.6569}
+\definecolor{kit-green60}{rgb}{0.4, 0.7529, 0.7059}
+\definecolor{kit-green50}{rgb}{0.5, 0.7941, 0.7549}
+\definecolor{kit-green40}{rgb}{0.6, 0.8353, 0.8039}
+\definecolor{kit-green30}{rgb}{0.7, 0.8765, 0.8529}
+\definecolor{kit-green25}{rgb}{0.75, 0.8971, 0.8775}
+\definecolor{kit-green20}{rgb}{0.8, 0.9176, 0.902}
+\definecolor{kit-green15}{rgb}{0.85, 0.9382, 0.9265}
+\definecolor{kit-green10}{rgb}{0.9, 0.9588, 0.951}
+\definecolor{kit-green5}{rgb}{0.95, 0.9794, 0.9755}
+
+% KIT color blue:
+\definecolor{kit-blue}{RGB}{70, 100, 170}
+\definecolor{kit-blue100}{RGB}{70, 100, 170}
+\definecolor{kit-blue90}{rgb}{0.3471, 0.4529, 0.7}
+\definecolor{kit-blue80}{rgb}{0.4196, 0.5137, 0.7333}
+\definecolor{kit-blue75}{rgb}{0.4559, 0.5441, 0.75}
+\definecolor{kit-blue70}{rgb}{0.4922, 0.5745, 0.7667}
+\definecolor{kit-blue60}{rgb}{0.5647, 0.6353, 0.8}
+\definecolor{kit-blue50}{rgb}{0.6373, 0.6961, 0.8333}
+\definecolor{kit-blue40}{rgb}{0.7098, 0.7569, 0.8667}
+\definecolor{kit-blue30}{rgb}{0.7824, 0.8176, 0.9}
+\definecolor{kit-blue25}{rgb}{0.8186, 0.848, 0.9167}
+\definecolor{kit-blue20}{rgb}{0.8549, 0.8784, 0.9333}
+\definecolor{kit-blue15}{rgb}{0.8912, 0.9088, 0.95}
+\definecolor{kit-blue10}{rgb}{0.9275, 0.9392, 0.9667}
+\definecolor{kit-blue5}{rgb}{0.9637, 0.9696, 0.9833}
+
+% KIT color red :
+\definecolor{kit-red}{RGB}{162, 34, 35}
+\definecolor{kit-red100}{RGB}{162, 34, 35}
+\definecolor{kit-red90}{rgb}{0.6718, 0.22, 0.2235}
+\definecolor{kit-red80}{rgb}{0.7082, 0.3067, 0.3098}
+\definecolor{kit-red75}{rgb}{0.7265, 0.35, 0.3529}
+\definecolor{kit-red70}{rgb}{0.7447, 0.3933, 0.3961}
+\definecolor{kit-red60}{rgb}{0.7812, 0.48, 0.4824}
+\definecolor{kit-red50}{rgb}{0.8176, 0.5667, 0.5686}
+\definecolor{kit-red40}{rgb}{0.8541, 0.6533, 0.6549}
+\definecolor{kit-red30}{rgb}{0.8906, 0.74, 0.7412}
+\definecolor{kit-red25}{rgb}{0.9088, 0.7833, 0.7843}
+\definecolor{kit-red20}{rgb}{0.9271, 0.8267, 0.8275}
+\definecolor{kit-red15}{rgb}{0.9453, 0.87, 0.8706}
+\definecolor{kit-red10}{rgb}{0.9635, 0.9133, 0.9137}
+\definecolor{kit-red5}{rgb}{0.9818, 0.9567, 0.9569}
+
+% KIT color yellow :
+\definecolor{kit-yellow}{RGB}{252, 229, 0}
+\definecolor{kit-yellow100}{RGB}{252, 229, 0}
+\definecolor{kit-yellow90}{rgb}{0.9894, 0.9082, 0.1}
+\definecolor{kit-yellow80}{rgb}{0.9906, 0.9184, 0.2}
+\definecolor{kit-yellow75}{rgb}{0.9912, 0.9235, 0.25}
+\definecolor{kit-yellow70}{rgb}{0.9918, 0.9286, 0.3}
+\definecolor{kit-yellow60}{rgb}{0.9929, 0.9388, 0.4}
+\definecolor{kit-yellow50}{rgb}{0.9941, 0.949, 0.5}
+\definecolor{kit-yellow40}{rgb}{0.9953, 0.9592, 0.6}
+\definecolor{kit-yellow30}{rgb}{0.9965, 0.9694, 0.7}
+\definecolor{kit-yellow25}{rgb}{0.9971, 0.9745, 0.75}
+\definecolor{kit-yellow20}{rgb}{0.9976, 0.9796, 0.8}
+\definecolor{kit-yellow15}{rgb}{0.9982, 0.9847, 0.85}
+\definecolor{kit-yellow10}{rgb}{0.9988, 0.9898, 0.9}
+\definecolor{kit-yellow5}{rgb}{0.9994, 0.9949, 0.95}
+
+% KIT color orange :
+\definecolor{kit-orange}{RGB}{223, 155, 27}
+\definecolor{kit-orange100}{RGB}{223, 155, 27}
+\definecolor{kit-orange90}{rgb}{0.8871, 0.6471, 0.1953}
+\definecolor{kit-orange80}{rgb}{0.8996, 0.6863, 0.2847}
+\definecolor{kit-orange75}{rgb}{0.9059, 0.7059, 0.3294}
+\definecolor{kit-orange70}{rgb}{0.9122, 0.7255, 0.3741}
+\definecolor{kit-orange60}{rgb}{0.9247, 0.7647, 0.4635}
+\definecolor{kit-orange50}{rgb}{0.9373, 0.8039, 0.5529}
+\definecolor{kit-orange40}{rgb}{0.9498, 0.8431, 0.6424}
+\definecolor{kit-orange30}{rgb}{0.9624, 0.8824, 0.7318}
+\definecolor{kit-orange25}{rgb}{0.9686, 0.902, 0.7765}
+\definecolor{kit-orange20}{rgb}{0.9749, 0.9216, 0.8212}
+\definecolor{kit-orange15}{rgb}{0.9812, 0.9412, 0.8659}
+\definecolor{kit-orange10}{rgb}{0.9875, 0.9608, 0.9106}
+\definecolor{kit-orange5}{rgb}{0.9937, 0.9804, 0.9553}
+
+% KIT color lightgreen :
+\definecolor{kit-lightgreen}{RGB}{140, 182, 60}
+\definecolor{kit-lightgreen100}{RGB}{140, 182, 60}
+\definecolor{kit-lightgreen90}{rgb}{0.5941, 0.7424, 0.3118}
+\definecolor{kit-lightgreen80}{rgb}{0.6392, 0.771, 0.3882}
+\definecolor{kit-lightgreen75}{rgb}{0.6618, 0.7853, 0.4265}
+\definecolor{kit-lightgreen70}{rgb}{0.6843, 0.7996, 0.4647}
+\definecolor{kit-lightgreen60}{rgb}{0.7294, 0.8282, 0.5412}
+\definecolor{kit-lightgreen50}{rgb}{0.7745, 0.8569, 0.6176}
+\definecolor{kit-lightgreen40}{rgb}{0.8196, 0.8855, 0.6941}
+\definecolor{kit-lightgreen30}{rgb}{0.8647, 0.9141, 0.7706}
+\definecolor{kit-lightgreen25}{rgb}{0.8873, 0.9284, 0.8088}
+\definecolor{kit-lightgreen20}{rgb}{0.9098, 0.9427, 0.8471}
+\definecolor{kit-lightgreen15}{rgb}{0.9324, 0.9571, 0.8853}
+\definecolor{kit-lightgreen10}{rgb}{0.9549, 0.9714, 0.9235}
+\definecolor{kit-lightgreen5}{rgb}{0.9775, 0.9857, 0.9618}
+
+
+% KIT color purple :
+\definecolor{kit-purple}{RGB}{163, 16, 124}
+\definecolor{kit-purple100}{RGB}{163, 16, 124}
+\definecolor{kit-purple90}{rgb}{0.6753, 0.1565, 0.5376}
+\definecolor{kit-purple80}{rgb}{0.7114, 0.2502, 0.589}
+\definecolor{kit-purple75}{rgb}{0.7294, 0.2971, 0.6147}
+\definecolor{kit-purple70}{rgb}{0.7475, 0.3439, 0.6404}
+\definecolor{kit-purple60}{rgb}{0.7835, 0.4376, 0.6918}
+\definecolor{kit-purple50}{rgb}{0.8196, 0.5314, 0.7431}
+\definecolor{kit-purple40}{rgb}{0.8557, 0.6251, 0.7945}
+\definecolor{kit-purple30}{rgb}{0.8918, 0.7188, 0.8459}
+\definecolor{kit-purple25}{rgb}{0.9098, 0.7657, 0.8716}
+\definecolor{kit-purple20}{rgb}{0.9278, 0.8125, 0.8973}
+\definecolor{kit-purple15}{rgb}{0.9459, 0.8594, 0.9229}
+\definecolor{kit-purple10}{rgb}{0.9639, 0.9063, 0.9486}
+\definecolor{kit-purple5}{rgb}{0.982, 0.9531, 0.9743}
+
+% KIT color brown :
+\definecolor{kit-brown}{RGB}{167, 130, 46}
+\definecolor{kit-brown100}{RGB}{167, 130, 46}
+\definecolor{kit-brown90}{rgb}{0.6894, 0.5588, 0.2624}
+\definecolor{kit-brown80}{rgb}{0.7239, 0.6078, 0.3443}
+\definecolor{kit-brown75}{rgb}{0.7412, 0.6324, 0.3853}
+\definecolor{kit-brown70}{rgb}{0.7584, 0.6569, 0.4263}
+\definecolor{kit-brown60}{rgb}{0.7929, 0.7059, 0.5082}
+\definecolor{kit-brown50}{rgb}{0.8275, 0.7549, 0.5902}
+\definecolor{kit-brown40}{rgb}{0.862, 0.8039, 0.6722}
+\definecolor{kit-brown30}{rgb}{0.8965, 0.8529, 0.7541}
+\definecolor{kit-brown25}{rgb}{0.9137, 0.8775, 0.7951}
+\definecolor{kit-brown20}{rgb}{0.931, 0.902, 0.8361}
+\definecolor{kit-brown15}{rgb}{0.9482, 0.9265, 0.8771}
+\definecolor{kit-brown10}{rgb}{0.9655, 0.951, 0.918}
+\definecolor{kit-brown5}{rgb}{0.9827, 0.9755, 0.959}
+
+% KIT color cyan :
+\definecolor{kit-cyan}{RGB}{35, 161, 224}
+\definecolor{kit-cyan100}{RGB}{35, 161, 224}
+\definecolor{kit-cyan90}{rgb}{0.2235, 0.6682, 0.8906}
+\definecolor{kit-cyan80}{rgb}{0.3098, 0.7051, 0.9027}
+\definecolor{kit-cyan75}{rgb}{0.3529, 0.7235, 0.9088}
+\definecolor{kit-cyan70}{rgb}{0.3961, 0.742, 0.9149}
+\definecolor{kit-cyan60}{rgb}{0.4824, 0.7788, 0.9271}
+\definecolor{kit-cyan50}{rgb}{0.5686, 0.8157, 0.9392}
+\definecolor{kit-cyan40}{rgb}{0.6549, 0.8525, 0.9514}
+\definecolor{kit-cyan30}{rgb}{0.7412, 0.8894, 0.9635}
+\definecolor{kit-cyan25}{rgb}{0.7843, 0.9078, 0.9696}
+\definecolor{kit-cyan20}{rgb}{0.8275, 0.9263, 0.9757}
+\definecolor{kit-cyan15}{rgb}{0.8706, 0.9447, 0.9818}
+\definecolor{kit-cyan10}{rgb}{0.9137, 0.9631, 0.9878}
+\definecolor{kit-cyan5}{rgb}{0.9569, 0.9816, 0.9939}
+
+% KIT color gray :
+\definecolor{kit-gray}{RGB}{0, 0, 0}
+\definecolor{kit-gray100}{RGB}{0, 0, 0}
+\definecolor{kit-gray90}{rgb}{0.1, 0.1, 0.1}
+\definecolor{kit-gray80}{rgb}{0.2, 0.2, 0.2}
+\definecolor{kit-gray75}{rgb}{0.25, 0.25, 0.25}
+\definecolor{kit-gray70}{rgb}{0.3, 0.3, 0.3}
+\definecolor{kit-gray60}{rgb}{0.4, 0.4, 0.4}
+\definecolor{kit-gray50}{rgb}{0.5, 0.5, 0.5}
+\definecolor{kit-gray40}{rgb}{0.6, 0.6, 0.6}
+\definecolor{kit-gray30}{rgb}{0.7, 0.7, 0.7}
+\definecolor{kit-gray25}{rgb}{0.75, 0.75, 0.75}
+\definecolor{kit-gray20}{rgb}{0.8, 0.8, 0.8}
+\definecolor{kit-gray15}{rgb}{0.85, 0.85, 0.85}
+\definecolor{kit-gray10}{rgb}{0.9, 0.9, 0.9}
+\definecolor{kit-gray5}{rgb}{0.95, 0.95, 0.95}
+
+
+
+\setbeamercolor*{normal text}{fg=black}
+\setbeamercolor*{alerted text}{fg=kit-red100}
+\setbeamercolor*{example text}{fg=black}
+\setbeamercolor*{structure}{fg=black}
+
+\setbeamercolor*{palette primary}{fg=black,bg=black!15}
+\setbeamercolor*{palette secondary}{fg=black,bg=black!15}
+\setbeamercolor*{palette tertiary}{fg=black,bg=black!15}
+\setbeamercolor*{palette quaternary}{fg=black,bg=black!15}
+
+\setbeamercolor*{palette sidebar primary}{fg=black!75}
+\setbeamercolor*{palette sidebar secondary}{fg=black!75}
+\setbeamercolor*{palette sidebar tertiary}{fg=black!75}
+\setbeamercolor*{palette sidebar quaternary}{fg=black!75}
+
+\setbeamercolor*{item projected}{fg=white,bg=kit-green100}
+
+\setbeamercolor*{block title}{fg=white,bg=kit-green100}
+\setbeamercolor*{block title alerted}{use=alerted text,fg=white,bg=alerted text.fg!75!black}
+\setbeamercolor*{block title example}{fg=white,bg=kit-blue100}
+
+\setbeamercolor*{block body}{fg=black,bg=kit-green15}
+\setbeamercolor*{block body alerted}{parent=normal text,use=block title alerted,bg=block title alerted.bg!10!bg}
+\setbeamercolor*{block body example}{fg=black,bg=kit-blue15}
+
+\setbeamercolor*{separation line}{}
+\setbeamercolor*{fine separation line}{}
+
+\setbeamercolor*{background canvas}{bg=white}
+
+%% -----------
+%% | /Farben |
+%% -----------
+
+%% -----------------------------------
+%% | halbgerundete Aufzählungspunkte |
+%% -----------------------------------
+
+% KIT-Aufzählungszeichen
+\newcommand{\KITmark}{%
+ \begin{pgfpicture}{0mm}{0mm}{1ex}{1ex}
+ {\pgfsetcornersarced{\pgfpoint{.3ex}{.3ex}}
+ \pgfpathmoveto{\pgfpoint{0cm}{1ex}}
+ \pgfpathlineto{\pgfpoint{1ex}{1ex}}
+ \pgfpathlineto{\pgfpoint{1ex}{0cm}}}
+ {\pgfsetcornersarced{\pgfpoint{.3ex}{.3ex}}
+ \pgfpathmoveto{\pgfpoint{1ex}{0cm}}
+ \pgfpathlineto{\pgfpointorigin}
+ \pgfpathlineto{\pgfpoint{0cm}{1ex}}}
+ \color{kit-green100}
+ \pgfusepath{fill}
+ \end{pgfpicture}%
+}
+
+\setbeamertemplate{itemize items}{\raisebox{.2ex}{\KITmark}}
+
+%% ----------------------
+%% | Inhaltsverzeichnis |
+%% ----------------------
+
+\setbeamertemplate{section in toc}{\normalsize\textbf{\textcolor{kit-blue}{\inserttocsectionnumber.~\inserttocsection}}\par}
+\setbeamertemplate{subsection in toc}{\small\hspace{1.2em}\raisebox{.2ex}{\KITmark}\hspace{\labelsep}\inserttocsubsection\par}
+
+%% ------------------------------
+%% | halbgerundete Beamer-Boxen |
+%% ------------------------------
+
+\renewcommand\beamerboxesrounded[2][]{%
+ \global\let\beamer@firstlineitemizeunskip=\relax%
+ \vbox\bgroup%
+ \setkeys{beamerboxes}{upper=block title,lower=block body,width=\textwidth,shadow=false}%
+ \setkeys{beamerboxes}{#1}%
+ {%
+ \usebeamercolor{\bmb@lower}%
+ \globalcolorstrue%
+ \colorlet{lower.bg}{bg}%
+ }%
+ {%
+ \usebeamercolor{\bmb@upper}%
+ \globalcolorstrue%
+ \colorlet{upper.bg}{bg}%
+ }%
+ %
+ % Typeset head
+ %
+ \vskip4bp
+ \setbox\bmb@box=\hbox{%
+ \begin{minipage}[b]{\bmb@width}%
+ \usebeamercolor[fg]{\bmb@upper}%
+ #2%
+ \end{minipage}}%
+ \ifdim\wd\bmb@box=0pt%
+ \setbox\bmb@box=\hbox{}%
+ \ht\bmb@box=1.5pt%
+ \bmb@prevheight=-4.5pt%
+ \else%
+ \wd\bmb@box=\bmb@width%
+ \bmb@temp=\dp\bmb@box%
+ \ifdim\bmb@temp<1.5pt%
+ \bmb@temp=1.5pt%
+ \fi%
+ \setbox\bmb@box=\hbox{\raise\bmb@temp\hbox{\box\bmb@box}}%
+ \dp\bmb@box=0pt%
+ \bmb@prevheight=\ht\bmb@box%
+ \fi%
+ \bmb@temp=\bmb@width%
+ \bmb@dima=\bmb@temp\advance\bmb@dima by2.2bp%
+ \bmb@dimb=\bmb@temp\advance\bmb@dimb by4bp%
+ \hbox{%
+ \begin{pgfpicture}{0bp}{+-\ht\bmb@box}{0bp}{+-\ht\bmb@box}
+ \ifdim\wd\bmb@box=0pt%
+ \color{lower.bg}%
+ \else%
+ \color{upper.bg}%
+ \fi%
+ \pgfpathqmoveto{-4bp}{-1bp}
+ % Adaption for "KIT-Design"
+ \pgfpathlineto{\pgfpoint{-4bp}{3bp}}
+ %\pgfpathqcurveto{-4bp}{1.2bp}{-2.2bp}{3bp}{0bp}{3bp}
+ \pgfpathlineto{\pgfpoint{\bmb@temp}{3bp}}
+ \pgfpathcurveto%
+ {\pgfpoint{\bmb@dima}{3bp}}%
+ {\pgfpoint{\bmb@dimb}{1.2bp}}%
+ {\pgfpoint{\bmb@dimb}{-1bp}}%
+ \bmb@dima=-\ht\bmb@box%
+ \advance\bmb@dima by-2pt%
+ \pgfpathlineto{\pgfpoint{\bmb@dimb}{\bmb@dima}}
+ \pgfpathlineto{\pgfpoint{-4bp}{\bmb@dima}}
+ \pgfusepath{fill}
+ \end{pgfpicture}%
+ \copy\bmb@box%
+ }%
+ \nointerlineskip%
+ \vskip-1pt%
+ \ifdim\wd\bmb@box=0pt%
+ \else%
+ \hbox{%
+ \begin{pgfpicture}{0pt}{0pt}{\bmb@width}{6pt}
+ \bmb@dima=\bmb@width%
+ \advance\bmb@dima by8bp%
+ \pgfpathrectangle{\pgfpoint{-4bp}{-1bp}}{\pgfpoint{\bmb@dima}{8bp}}
+ \pgfusepath{clip}
+ {\pgftransformshift{\pgfpoint{-4bp}{0bp}}\pgftext[left,base]{\pgfuseshading{bmb@transition}}}%
+ \end{pgfpicture}%
+ }%
+ \nointerlineskip%
+ \vskip-0.5pt%
+ \fi%
+ \ifbmb@shadow%
+ \setbox\bmb@boxshadow=\hbox{\pgfuseshading{bmb@shadow}}%
+ \setbox\bmb@boxshadowball=\hbox{\pgfuseshading{bmb@shadowball}}%
+ \setbox\bmb@boxshadowballlarge=\hbox{\pgfuseshading{bmb@shadowballlarge}}%
+ \fi%
+ \setbox\bmb@colorbox=\hbox{{\pgfpicturetrue\pgfsetcolor{lower.bg}}}%
+ \setbox\bmb@box=\hbox\bgroup\begin{minipage}[b]{\bmb@width}%
+ \vskip2pt%
+ \usebeamercolor[fg]{\bmb@lower}%
+ \colorlet{beamerstructure}{upper.bg}%
+ \colorlet{structure}{upper.bg}%
+ %\color{.}%
+ }
+
+\def\endbeamerboxesrounded{%
+ \end{minipage}\egroup%
+ \wd\bmb@box=\bmb@width%
+ \bmb@temp=\dp\bmb@box%
+ \advance\bmb@temp by.5pt%
+ \setbox\bmb@box=\hbox{\raise\bmb@temp\hbox{\box\bmb@box}}%
+ \dp\bmb@box=0pt%
+ \bmb@temp=\wd\bmb@box%
+ \bmb@dima=\bmb@temp\advance\bmb@dima by2.2bp%
+ \bmb@dimb=\bmb@temp\advance\bmb@dimb by4bp%
+ \hbox{%
+ \begin{pgfpicture}{0bp}{0bp}{0bp}{0bp}
+ \ifbmb@shadow%
+ {\pgftransformshift{\pgfpoint{4bp}{-3bp}}\pgftext{\copy\bmb@boxshadowball}}
+ \begin{pgfscope}
+ {%
+ \advance\bmb@temp by-1bp%
+ \pgfpathrectangle{\pgfpoint{\bmb@temp}{-7bp}}{\pgfpoint{9bp}{9bp}}%
+ \pgfusepath{clip}
+ }%
+ {\pgftransformshift{\pgfpoint{\bmb@temp}{1bp}}\pgftext{\box\bmb@boxshadowballlarge}}
+ \end{pgfscope}
+ \begin{pgfscope}
+ \advance\bmb@temp by-4bp%
+ \pgfpathrectangle{\pgfpoint{4bp}{-7bp}}{\pgfpoint{\bmb@temp}{5bp}}
+ \pgfusepath{clip}
+ {\pgftransformshift{\pgfpoint{4bp}{-7bp}}\pgftext[left,base]{\copy\bmb@boxshadow}}%
+ \end{pgfscope}
+ \begin{pgfscope}
+ \advance\bmb@temp by 4bp%
+ \bmb@dima=\ht\bmb@box%
+ \advance\bmb@dima by\bmb@prevheight%
+ \advance\bmb@dima by 4bp%
+ \pgfpathrectangle{\pgfpoint{\bmb@temp}{1bp}}{\pgfpoint{4bp}{\bmb@dima}}
+ \pgfusepath{clip}
+ \advance\bmb@dima by-4bp%
+ {\pgftransformshift{\pgfpoint{\bmb@temp}{\bmb@dima}}\pgftext{\box\bmb@boxshadowball}}
+ \advance\bmb@dima by-1bp%
+ \pgfpathrectangle{\pgfpoint{\bmb@temp}{1bp}}{\pgfpoint{4bp}{\bmb@dima}}
+ \pgfusepath{clip}
+ \advance\bmb@temp by4bp%
+ {\pgftransformshift{\pgfpoint{\bmb@temp}{-3bp}}%
+ \pgftransformrotate{90}%
+ \pgftext[left,base]{\box\bmb@boxshadow}}%
+ \end{pgfscope}
+ \fi%
+ \unhbox\bmb@colorbox%
+ \pgfpathqmoveto{-4bp}{1bp}
+ \pgfpathqcurveto{-4bp}{-1.2bp}{-2.2bp}{-3bp}{0bp}{-3bp}
+ \pgfpathlineto{\pgfpoint{\the\bmb@dimb}{-3bp}}
+ {
+ \bmb@dima=\ht\bmb@box%
+ \pgfpathlineto{\pgfpoint{\bmb@dimb}{\bmb@dima}}
+ \pgfpathlineto{\pgfpoint{-4bp}{\bmb@dima}}
+ \pgfusepath{fill}
+ }
+ \ifbmb@shadow%
+ {
+ \color{black!50!bg}
+ \pgfsetlinewidth{0pt}
+ \pgfpathmoveto{\pgfpoint{\bmb@dimb}{-.5bp}}
+ \bmb@dima=\ht\bmb@box%
+ \advance\bmb@dima by\bmb@prevheight%
+ \advance\bmb@dima by 1bp%
+ \pgfpathlineto{\pgfpoint{\bmb@dimb}{\bmb@dima}}
+ \pgfusepath{stroke}
+ \bmb@temp=\bmb@dima
+ \advance\bmb@dima by 1bp%
+ \color{black!31!bg}
+ \pgfpathmoveto{\pgfpoint{\bmb@dimb}{\bmb@temp}}
+ \pgfpathlineto{\pgfpoint{\bmb@dimb}{\bmb@dima}}
+ \pgfusepath{stroke}
+ \advance\bmb@dima by 1bp%
+ \advance\bmb@temp by 1bp%
+ \color{black!19!bg}
+ \pgfpathmoveto{\pgfpoint{\bmb@dimb}{\bmb@temp}}
+ \pgfpathlineto{\pgfpoint{\bmb@dimb}{\bmb@dima}}
+ \pgfusepath{stroke}
+ \advance\bmb@dima by 1bp%
+ \advance\bmb@temp by 1bp%
+ \color{black!6!bg}
+ \pgfpathmoveto{\pgfpoint{\bmb@dimb}{\bmb@temp}}
+ \pgfpathlineto{\pgfpoint{\bmb@dimb}{\bmb@dima}}
+ \pgfusepath{stroke}
+ \advance\bmb@dima by 1.5bp%
+ \advance\bmb@temp by 1bp%
+ \color{bg}
+ \pgfpathmoveto{\pgfpoint{\bmb@dimb}{\bmb@temp}}
+ \pgfpathlineto{\pgfpoint{\bmb@dimb}{\bmb@dima}}
+ \pgfusepath{stroke}
+ }
+ \fi
+ \end{pgfpicture}%
+ \box\bmb@box%
+ }%
+ \ifbmb@shadow%
+ \vskip4bp minus 2bp%
+ \else%
+ \vskip2bp%
+ \fi%
+ \egroup% of \vbox\bgroup
+}
+
+
+%% -------------------------------
+%% | /halbgerundete Beamer-Boxen |
+%% -------------------------------
+
+
+%% ----------------------
+%% | Block-Definitionen |
+%% ----------------------
+
+% Content environment for structuring. Basically a headline followed by text
+\newenvironment<>{contentblock}[1]{\begingroup%
+ \setbeamertemplate{blocks}[default]
+ \setbeamercolor{block body}{fg=black,bg=}%
+ \setbeamercolor{block title}{fg=black,bg=}%
+ \setbeamerfont*{block title}{family=\sffamily,series=\bfseries,size=\large}
+ \begin{block}#2{#1}%
+ }{\end{block}%
+\endgroup}
+
+
+\newenvironment<>{greenblock}[1]{\begingroup%
+ \setbeamercolor{block body}{fg=black,bg=kit-green15}%
+ \setbeamercolor{block title}{fg=white,bg=kit-green100}%
+ \begin{block}#2{#1}%
+ }{\end{block}
+\endgroup}
+
+\newenvironment<>{blueblock}[1]{\begingroup%
+ \setbeamercolor{block body}{fg=black,bg=kit-blue15}%
+ \setbeamercolor{block title}{fg=white,bg=kit-blue100}%
+ \begin{block}#2{#1}%
+ }{\end{block}
+\endgroup}
+
+\newenvironment<>{redblock}[1]{\begingroup%
+ \setbeamercolor{block body}{fg=black,bg=kit-red15}%
+ \setbeamercolor{block title}{fg=white,bg=kit-red100}%
+ \begin{block}#2{#1}%
+ }{\end{block}%
+\endgroup}
+
+\newenvironment<>{brownblock}[1]{\begingroup%
+ \setbeamercolor{block body}{fg=black,bg=kit-brown15}%
+ \setbeamercolor{block title}{fg=white,bg=kit-brown100}%
+ \begin{block}#2{#1}%
+ }{\end{block}%
+\endgroup}
+
+\newenvironment<>{purpleblock}[1]{\begingroup%
+ \setbeamercolor{block body}{fg=black,bg=kit-purple15}%
+ \setbeamercolor{block title}{fg=white,bg=kit-purple100}%
+ \begin{block}#2{#1}%
+ }{\end{block}%
+\endgroup}
+
+\newenvironment<>{grayblock}[1]{\begingroup%
+ \setbeamercolor{block body}{fg=black,bg=kit-gray15}%
+ \setbeamercolor{block title}{fg=white,bg=kit-gray70}%
+ \begin{block}#2{#1}%
+ }{\end{block}%
+\endgroup}
+
+\newenvironment<>{yellowblock}[1]{\begingroup%
+ \setbeamercolor{block body}{fg=black,bg=kit-yellow30}%
+ \setbeamercolor{block title}{fg=black,bg=kit-yellow100}%
+ \begin{block}#2{#1}%
+ }{\end{block}%
+\endgroup}
+
+\newenvironment<>{lightgreenblock}[1]{\begingroup%
+ \setbeamercolor{block body}{fg=black,bg=kit-lightgreen15}%
+ \setbeamercolor{block title}{fg=white,bg=kit-lightgreen100}%
+ \begin{block}#2{#1}%
+ }{\end{block}%
+\endgroup}
+
+\newenvironment<>{orangeblock}[1]{\begingroup%
+ \setbeamercolor{block body}{fg=black,bg=kit-orange15}%
+ \setbeamercolor{block title}{fg=white,bg=kit-orange100}%
+ \begin{block}#2{#1}%
+ }{\end{block}%
+\endgroup}
+
+\newenvironment<>{cyanblock}[1]{\begingroup%
+ \setbeamercolor{block body}{fg=black,bg=kit-cyan15}%
+ \setbeamercolor{block title}{fg=white,bg=kit-cyan100}%
+ \begin{block}#2{#1}%
+ }{\end{block}%
+\endgroup}
+%% ------------------------------
+%% | /Block-Definitionen |
+%% ------------------------------
+
+%% use this for setting the total page number
+\newcommand{\beginbackup}{
+ \newcounter{framenumbervorappendix}
+ \setcounter{framenumbervorappendix}{\value{framenumber}}
+}
+\newcommand{\backupend}{
+ \addtocounter{framenumbervorappendix}{-\value{framenumber}}
+ \addtocounter{framenumber}{\value{framenumbervorappendix}}
+}
diff --git a/01-pflichtenheft-kolloquium/slides/einführung.tex b/01-pflichtenheft-kolloquium/slides/einführung.tex
new file mode 100644
index 0000000..d818cd3
--- /dev/null
+++ b/01-pflichtenheft-kolloquium/slides/einführung.tex
@@ -0,0 +1,40 @@
+\begin{frame}[t]{Einführung}
+
+
+ \begin{columns}[t]
+ \begin{column}{.3\textwidth}
+ \centering{\fontsize{30pt}{36pt}\selectfont\faPodcast}
+ \vspace{.2cm}
+ \begin{block}{Podcast}
+ \begin{itemize}
+ \item RSS-Feed
+ \item Episoden
+ \item Audio/Video
+ \end{itemize}
+ \end{block}
+ \end{column}
+ \begin{column}{.3\textwidth}
+ \centering{\fontsize{30pt}{36pt}\selectfont\faArrowCircleDown}
+ \vspace{.2cm}
+ \begin{block}{Podcatcher}
+ \begin{itemize}
+ \item lokale Verwaltung von Podcasts
+ \item API Unterstützung
+ \item Abspielen von Episoden
+ \end{itemize}
+ \end{block}
+ \end{column}
+ \begin{column}{.3\textwidth}
+ \centering{\fontsize{30pt}{36pt}\selectfont\faSync}
+ \vspace{.2cm}
+ \begin{block}{Synchronisationsserver}
+ \begin{itemize}
+ \item Hörfortschritte
+ \item Abonnements
+ \item Discovery
+ \end{itemize}
+ \end{block}
+ \end{column}
+ \end{columns}
+
+\end{frame} \ No newline at end of file
diff --git a/01-pflichtenheft-kolloquium/slides/features.tex b/01-pflichtenheft-kolloquium/slides/features.tex
new file mode 100644
index 0000000..6ec435b
--- /dev/null
+++ b/01-pflichtenheft-kolloquium/slides/features.tex
@@ -0,0 +1,37 @@
+\begin{frame}{Features}
+\begin{columns}[t]
+\begin{column}{.3\textwidth}
+\centering{\fontsize{30pt}{36pt}\selectfont\faSync}
+\vspace{.2cm}
+\begin{block}{Synchronisation}
+\begin{itemize}
+ \item Abos
+ \item Hörfortschritt
+\end{itemize}
+\end{block}
+\end{column}
+\begin{column}{.3\textwidth}
+\centering{\fontsize{30pt}{36pt}\selectfont\faGlobe}
+\vspace{.2cm}
+\begin{block}{Weboberfläche}
+\begin{itemize}
+ \item Aboliste
+ \item Zuletzt gehört
+\end{itemize}
+\end{block}
+\end{column}
+\begin{column}{.3\textwidth}
+\centering{\fontsize{30pt}{36pt}\selectfont\faUser}
+\vspace{.2cm}
+\begin{block}{Account-Verwaltung}
+\begin{itemize}
+ \item Registrieren und Anmelden
+ \item Passwort ändern und zurücksetzen
+ \item Account löschen
+ \item Daten importieren/exportieren
+\end{itemize}
+\end{block}
+\end{column}
+\end{columns}
+\end{frame}
+
diff --git a/01-pflichtenheft-kolloquium/slides/synchronisation.tex b/01-pflichtenheft-kolloquium/slides/synchronisation.tex
new file mode 100644
index 0000000..0849279
--- /dev/null
+++ b/01-pflichtenheft-kolloquium/slides/synchronisation.tex
@@ -0,0 +1,36 @@
+\begin{frame}{Synchronisation}
+
+ \tikzstyle{line} = [draw, -latex']
+
+ \begin{figure}[H]
+
+ \begin{tikzpicture}
+
+ \tikzset{focus/.style={rectangle, minimum width = 1cm, minimum height = 0.5cm, rounded corners, draw}};
+ \tikzset{hyperfocus/.style={rectangle, minimum width = 1cm, minimum height = 0.5cm, draw}};
+
+ \node[hyperfocus, text width = 2.6cm, fill = green!25](s){Synchronisations-\\\quad \quad Server};
+ \node[focus, left = 3cm of s, text width = 3.1cm, orange](p1){\quad \underline{p1:Podcatcher}
+ \begin{itemize}
+ \vspace{0.2cm}
+ \item Abonnements
+ \item Hörfortschritt
+ \vspace{0.1cm}
+ \end{itemize}};
+ \node[focus, above = 1.8cm of s, orange](p2){p2};
+ \node[focus, right = 2.5cm of s, orange](p3){p3};
+ \node[below = 1.7cm of s](p4){\textbf{...}};
+ \umlactor[left = 2.7cm of p2, blue!60]{Benutzer};
+
+ \draw[] (p1) -- (s);
+ \draw[] (p2) -- (s);
+ \draw[] (s) -- (p3);
+ \draw[] (s) -- (p4);
+ \path [line, thick, blue!60] (Benutzer) -- node [text width=2.5cm, midway, above=0.1cm, align=center] {Podcast abonnieren} (p2);
+ \path [line, thick, blue!60] (Benutzer) -| node [text width=2.5cm, midway, above=0.1cm, align=center] {Episode anhören} (p1);
+
+ \end{tikzpicture}
+
+ \end{figure}
+
+\end{frame} \ No newline at end of file
diff --git a/01-pflichtenheft-kolloquium/slides/zielsetzung.tex b/01-pflichtenheft-kolloquium/slides/zielsetzung.tex
new file mode 100644
index 0000000..84e1064
--- /dev/null
+++ b/01-pflichtenheft-kolloquium/slides/zielsetzung.tex
@@ -0,0 +1,39 @@
+\begin{frame}{Zielsetzung}
+
+\begin{figure}[H]
+
+\raggedright
+
+\begin{tikzpicture}
+
+\tikzset{focus/.style={rectangle, minimum width=1cm, minimum height=0.5cm, rounded corners=7pt, draw}};
+
+\tikzset{hyperfocus/.style={rectangle, minimum width=1cm, minimum height=0.5cm, draw}};
+
+\node[hyperfocus] (main) {gPodder};
+\node[focus, right = 2cm of main] (sync) {Synchronisation};
+\node[above = of sync] (share) {Inhalt teilen};
+\node[above = 0.5cm of share] (discover) {Podcasts entdecken};
+\node[text width = 3cm, below = of sync] (create) {Listen erstellen und teilen};
+\node[text width = 3cm, below = 0.5cm of create] (popular) {Publisher:\\ Was ist beliebt?};
+
+\node[hyperfocus, right = 3cm of sync, text width = 4cm] (PSE) {\underline{PSE\textsuperscript{2}}\begin{itemize}
+ \item Schlankes Design
+ \item Effizient
+ \item Intuitiv
+\end{itemize}
+};
+
+\draw[] (main) -- (sync);
+\draw[] (main) -- (share);
+\draw[] (main) |- (discover);
+\draw[] (main) -- (create);
+\draw[] (main) |- (popular);
+\draw[stealth-, thick] (sync.east) -- ($(PSE.north west) + (0, -0.3)$);
+
+
+\end{tikzpicture}
+
+\end{figure}
+
+\end{frame} \ No newline at end of file
diff --git a/01-pflichtenheft-kolloquium/tikz-uml.sty b/01-pflichtenheft-kolloquium/tikz-uml.sty
new file mode 100644
index 0000000..c6e8e0d
--- /dev/null
+++ b/01-pflichtenheft-kolloquium/tikz-uml.sty
@@ -0,0 +1,5377 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Start of tikz-uml.sty
+%
+% Some macros for UML Diagrams.
+% Home page of project :
+% Author: Nicolas Kielbasiewicz
+% Style from :
+% Fixed by Nicolas Kielbasiewicz (nicolas.kielbasiewicz@ensta-paristech.fr) in march 2016 to compile with pgf 3.00
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+\NeedsTeXFormat{LaTeX2e}[1995/12/01]%
+\ProvidesPackage{tikz-uml}[2011/01/26]%
+%
+\RequirePackage{etoolbox}%
+\RequirePackage{ifthen}%
+\RequirePackage{tikz}%
+\RequirePackage{xstring}%
+\RequirePackage{calc}%
+\RequirePackage{pgfopts}%
+\usetikzlibrary{backgrounds,arrows,shapes,fit,shadows,decorations.markings}%
+%
+\def\tikzumlPackageLayersNum{3}%
+\pgfkeys{/tikzuml/options/.cd, packageLayers/.initial=3}%
+\pgfkeys{/tikzuml/options/.cd, packageLayers/.store in=\tikzumlPackageLayersNum}%
+\def\tikzumlStateLayersNum{3}%
+\pgfkeys{/tikzuml/options/.cd, stateLayers/.initial=3}%
+\pgfkeys{/tikzuml/options/.cd, stateLayers/.store in=\tikzumlStateLayersNum}%
+\def\tikzumlFragmentLayersNum{3}%
+\pgfkeys{/tikzuml/options/.cd, fragmentLayers/.initial=3}%
+\pgfkeys{/tikzuml/options/.cd, fragmentLayers/.store in=\tikzumlFragmentLayersNum}%
+\def\tikzumlComponentLayersNum{3}%
+\pgfkeys{/tikzuml/options/.cd, componentLayers/.initial=3}%
+\pgfkeys{/tikzuml/options/.cd, componentLayers/.store in=\tikzumlComponentLayersNum}%
+%
+\ProcessPgfOptions{/tikzuml/options}%
+%
+\def\pgfsetlayersArg{background}%
+\pgfdeclarelayer{background}%
+\newcounter{tikzumlPackageLayers}%
+\loop \pgfdeclarelayer{package\thetikzumlPackageLayers}%
+ \xdef\pgfsetlayersArg{\pgfsetlayersArg,package\thetikzumlPackageLayers}%
+ \ifnum\tikzumlPackageLayersNum>\thetikzumlPackageLayers%
+ \stepcounter{tikzumlPackageLayers}%
+\repeat%
+%
+\newcounter{tikzumlFragmentLayers}%
+\loop \pgfdeclarelayer{fragment\thetikzumlFragmentLayers}%
+ \xdef\pgfsetlayersArg{\pgfsetlayersArg,fragment\thetikzumlFragmentLayers}%
+ \ifnum\tikzumlFragmentLayersNum>\thetikzumlFragmentLayers%
+ \stepcounter{tikzumlFragmentLayers}%
+\repeat%
+%
+\newcounter{tikzumlStateLayers}%
+\loop \pgfdeclarelayer{state\thetikzumlStateLayers}%
+ \xdef\pgfsetlayersArg{\pgfsetlayersArg,state\thetikzumlStateLayers}%
+ \ifnum\tikzumlStateLayersNum>\thetikzumlStateLayers%
+ \stepcounter{tikzumlStateLayers}%
+\repeat%
+%
+\newcounter{tikzumlComponentLayers}%
+\loop \pgfdeclarelayer{component\thetikzumlComponentLayers}%
+ \xdef\pgfsetlayersArg{\pgfsetlayersArg,component\thetikzumlComponentLayers}%
+ \ifnum\tikzumlComponentLayersNum>\thetikzumlComponentLayers%
+ \stepcounter{tikzumlComponentLayers}%
+\repeat%
+%
+\pgfdeclarelayer{lifelines}%
+\pgfdeclarelayer{activity}%
+\pgfdeclarelayer{connections}%
+\xdef\pgfsetlayersArg{\pgfsetlayersArg,lifelines,activity,connections,main}%
+\pgfsetlayers{\pgfsetlayersArg}%
+%
+\pgfkeys{/tikzuml/.cd, text/.initial=black, draw/.initial=black, font/.initial=\small,%
+ x/.initial=0, y/.initial=0,%
+ package type/.initial=tikzumlEmpty, fill package/.initial=blue!20,%
+ class width/.initial=10ex, simple interface width/.initial=4ex, class type/.initial=class, fill class/.initial=yellow!20, fill template/.initial=yellow!2,%
+ narynode width/.initial=6ex,%
+ relation geometry/.initial=--, relation angle1/.initial=-30, relation angle2/.initial=30, relation loopsize/.initial=3em, relation weight/.initial=0.5, relation pos1/.initial=0.2, relation pos2/.initial=0.8, relation pos stereo/.initial=0.5,%
+ note width/.initial=3cm, fill note/.initial=green!20,%
+ fill system/.initial=white,%
+ fill usecase/.initial=blue!20,%
+ actor below/.initial=0.5cm,%
+ state join width/.initial=3ex,%
+ state decision width/.initial=3ex,%
+ state initial width/.initial=5ex,%
+ state final width/.initial=5.5ex,%
+ state enter width/.initial=5ex,%
+ state exit width/.initial=5ex,%
+ state end width/.initial=5ex,%
+ state history width/.initial=5ex,%
+ state deep history width/.initial=5ex,%
+ state width/.initial=8ex, fill state/.initial=yellow!20,%
+ object stereo/.initial=object, fill object/.initial=yellow!20,%
+ call dt/.initial=tikzumlEmpty, call padding/.initial=2, call type/.initial=synchron, fill call/.initial=white,%
+ fragment type/.initial=opt, fragment inner xsep/.initial=1, fragment inner ysep/.initial=1, fill fragment/.initial= none,%
+ create call dt/.initial=4,%
+ component width/.initial=8ex, fill component/.initial= yellow!20,%
+ required interface distance/.initial=2.5cm, required interface width/.initial=1em, required interface padding/.initial=1cm,%
+ provided interface distance/.initial=3cm, provided interface width/.initial=1em, provided interface padding/.initial=1cm,%
+ port width/.initial=1ex, fill port/.initial= yellow!20,%
+ fill assembly connector/.initial= white,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \errmessage{TIKZUML ERROR : in tikzuml global, invalid option \keyname}%
+ }%
+}%
+%
+\pgfkeys{/tikzuml/.cd, text/.get=\tikzumlDefaultTextColor, draw/.get=\tikzumlDefaultDrawColor, font/.get=\tikzumlDefaultFont,%
+ x/.get=\tikzumlDefaultX, y/.get=\tikzumlDefaultY,%
+ package type/.get=\tikzumlPackageDefaultType, fill package/.get=\tikzumlPackageDefaultFillColor,%
+ class width/.get=\tikzumlClassDefaultWidth, simple interface width/.get=\tikzumlSimpleInterfaceDefaultWidth, class type/.get=\tikzumlClassDefaultType, fill class/.get=\tikzumlClassDefaultFillColor, fill template/.get=\tikzumlClassTemplateFillColorDefaultFillColor,%
+ narynode width/.get=\tikzumlNaryNodeDefaultWidth,%
+ relation geometry/.get=\tikzumlRelationDefaultGeometry, relation angle1/.get=\tikzumlRelationDefaultAngleO, relation angle2/.get=\tikzumlRelationDefaultAngleT, relation loopsize/.get=\tikzumlRelationDefaultLoopSize, relation weight/.get=\tikzumlRelationDefaultWeight, relation pos1/.get=\tikzumlRelationDefaultPosO, relation pos2/.get=\tikzumlRelationDefaultPosT, relation pos stereo/.get=\tikzumlRelationDefaultPosStereo,%
+ note width/.get=\tikzumlNoteDefaultWidth, fill note/.get=\tikzumlNoteDefaultFillColor,%
+ fill system/.get=\tikzumlSystemDefaultFillColor,%
+ fill usecase/.get=\tikzumlUseCaseDefaultFillColor,%
+ actor below/.get=\tikzumlActorDefaultBelow,%
+ state join width/.get=\tikzumlStateJoinDefaultWidth,%
+ state decision width/.get=\tikzumlStateDecisionDefaultWidth,%
+ state initial width/.get=\tikzumlStateInitialDefaultWidth,%
+ state final width/.get=\tikzumlStateFinalDefaultWidth,%
+ state enter width/.get=\tikzumlStateEnterDefaultWidth,%
+ state exit width/.get=\tikzumlStateExitDefaultWidth,%
+ state end width/.get=\tikzumlStateEndDefaultWidth,%
+ state history width/.get=\tikzumlStateHistoryDefaultWidth,%
+ state deep history width/.get=\tikzumlStateDeepHistoryDefaultWidth,%
+ state width/.get=\tikzumlStateDefaultWidth, fill state/.get=\tikzumlStateDefaultFillColor,%
+ object stereo/.get=\tikzumlObjectDefaultStereo, fill object/.get=\tikzumlObjectDefaultFillColor,%
+ call dt/.get=\tikzumlCallDefaultDT, call padding/.get=\tikzumlCallDefaultPadding, call type/.get=\tikzumlCallDefaultType, fill call/.get=\tikzumlCallDefaultFillColor,%
+ fragment type/.get=\tikzumlFragmentDefaultType, fragment inner xsep/.get=\tikzumlFragmentDefaultXSep, fragment inner ysep/.get=\tikzumlFragmentDefaultYSep, fill fragment/.get=\tikzumlFragmentDefaultFillColor,%
+ create call dt/.get=\tikzumlCreateCallDefaultDT,%
+ component width/.get=\tikzumlComponentDefaultWidth, fill component/.get=\tikzumlComponentDefaultFillColor,%
+ required interface distance/.get=\tikzumlRequiredInterfaceDefaultDistance, required interface width/.get=\tikzumlRequiredInterfaceDefaultWidth, required interface padding/.get=\tikzumlRequiredInterfaceDefaultPadding,%
+ provided interface distance/.get=\tikzumlProvidedInterfaceDefaultDistance, provided interface width/.get=\tikzumlProvidedInterfaceDefaultWidth, provided interface padding/.get=\tikzumlProvidedInterfaceDefaultPadding,%
+ port width/.get=\tikzumlPortDefaultWidth, fill port/.get=\tikzumlPortDefaultFillColor,%
+ fill assembly connector/.get=\tikzumlAssemblyConnectorDefaultFillColor%
+}%
+%
+% utility : change default colors
+\newcommand{\tikzumlset}[1]{%
+ \pgfkeys{/tikzuml/.cd,#1}%
+ \pgfkeys{/tikzuml/.cd, text/.get=\tikzumlDefaultTextColor, draw/.get=\tikzumlDefaultDrawColor, font/.get=\tikzumlDefaultFont,%
+ x/.get=\tikzumlDefaultX, y/.get=\tikzumlDefaultY,%
+ package type/.get=\tikzumlPackageDefaultType, fill package/.get=\tikzumlPackageDefaultFillColor,%
+ class width/.get=\tikzumlClassDefaultWidth, simple interface width/.get=\tikzumlSimpleInterfaceDefaultWidth, class type/.get=\tikzumlClassDefaultType, fill class/.get=\tikzumlClassDefaultFillColor, fill template/.get=\tikzumlClassTemplateFillColorDefaultFillColor,%
+ narynode width/.get=\tikzumlNaryNodeWidth,%
+ relation geometry/.get=\tikzumlRelationDefaultGeometry, relation angle1/.get=\tikzumlRelationDefaultAngleO, relation angle2/.get=\tikzumlRelationDefaultAngleT, relation loopsize/.get=\tikzumlRelationDefaultLoopSize, relation weight/.get=\tikzumlRelationDefaultWeight, relation pos1/.get=\tikzumlRelationDefaultPosO, relation pos2/.get=\tikzumlRelationDefaultPosT, relation pos stereo/.get=\tikzumlRelationDefaultPosStereo,%
+ note width/.get=\tikzumlNoteDefaultWidth, fill note/.get=\tikzumlNoteDefaultFillColor,%
+ fill system/.get=\tikzumlSystemDefaultFillColor,%
+ fill usecase/.get=\tikzumlUseCaseDefaultFillColor,%
+ actor below/.get=\tikzumlActorDefaultBelow,%
+ state join width/.get=\tikzumlStateJoinDefaultWidth,%
+ state decision width/.get=\tikzumlStateDecisionDefaultWidth,%
+ state initial width/.get=\tikzumlStateInitialDefaultWidth,%
+ state final width/.get=\tikzumlStateFinalDefaultWidth,%
+ state enter width/.get=\tikzumlStateEnterDefaultWidth,%
+ state exit width/.get=\tikzumlStateExitDefaultWidth,%
+ state end width/.get=\tikzumlStateEndDefaultWidth,%
+ state history width/.get=\tikzumlStateHistoryDefaultWidth,%
+ state deep history width/.get=\tikzumlStateDeepHistoryDefaultWidth,%
+ state width/.get=\tikzumlStateDefaultWidth, fill state/.get=\tikzumlStateDefaultFillColor,%
+ object stereo/.get=\tikzumlObjectDefaultStereo, fill object/.get=\tikzumlObjectDefaultFillColor,%
+ call dt/.get=\tikzumlCallDefaultDT, call padding/.get=\tikzumlCallDefaultPadding, call type/.get=\tikzumlCallDefaultType, fill call/.get=\tikzumlCallDefaultFillColor,%
+ fragment type/.get=\tikzumlFragmentDefaultType, fragment inner xsep/.get=\tikzumlFragmentDefaultXSep, fragment inner ysep/.get=\tikzumlFragmentDefaultYSep, fill fragment/.get=\tikzumlFragmentDefaultFillColor,%
+ create call dt/.get=\tikzumlCreateCallDT,%
+ component width/.get=\tikzumlComponentDefaultWidth, fill component/.get=\tikzumlComponentDefaultFillColor,%
+ required interface distance/.get=\tikzumlRequiredInterfaceDefaultDistance, required interface width/.get=\tikzumlRequiredInterfaceDefaultWidth, required interface padding/.get=\tikzumlRequiredInterfaceDefaultPadding,%
+ provided interface distance/.get=\tikzumlProvidedInterfaceDefaultDistance, provided interface width/.get=\tikzumlProvidedInterfaceDefaultWidth, provided interface padding/.get=\tikzumlProvidedInterfaceDefaultPadding,%
+ port width/.get=\tikzumlPortDefaultWidth, fill port/.get=\tikzumlPortDefaultFillColor,%
+ fill assembly connector/.get=\tikzumlAssemblyConnectorDefaultFillColor%
+ }%
+}%
+%
+% define a point
+% arg : node/coordinates of the point
+\newcommand{\umlpoint}[1]{%
+ \begin{pgfonlayer}{connections}%
+ \node[tikzuml control nodes style] at (#1) {};%
+ \end{pgfonlayer}%
+}%
+%
+\newcommand{\tikzumlskipescape}[3][_]{%
+\begingroup%
+ \def\_{#1}\edef\x{\endgroup%
+ \def\noexpand\csname #3\endcsname{#2}}\x%
+}%
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% class diagrams %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+\pgfkeys{/tikzuml/relation/.cd, attr1/.style args={#1|#2}{arg1=#1, mult1=#2},%
+ attr2/.style args={#1|#2}{arg2=#1, mult2=#2},%
+ attr/.style args={#1|#2}{arg=#1, mult=#2},%
+ recursive/.style args={#1|#2|#3}{angle1=#1, angle2=#2, loopsize=#3},%
+ anchors/.style args={#1 and #2}{anchor1=#1, anchor2=#2},%
+ recursive direction/.style args={#1 to #2}{recursive direction start=#1, recursive direction end=#2}%
+}%
+%
+\pgfkeys{/tikzuml/note/.cd, anchors/.style args={#1 and #2}{anchor1=#1, anchor2=#2}}%
+%
+\tikzstyle{tikzuml simpleclass style}=[rectangle, minimum height=2em, node distance=2em]%
+\tikzstyle{tikzuml simpleinterface style}=[circle, minimum height=1em, node distance=1em]%
+\tikzstyle{tikzuml class style}=[rectangle split, rectangle split parts=3, rectangle split part align={center, left, left}, minimum height=2em, node distance=2em]%
+\tikzstyle{tikzuml narynode style}=[diamond]%
+\tikzstyle{tikzuml template style}=[dashed, inner ysep=0.5em, inner xsep=1ex]%
+\tikzstyle{tikzuml control nodes style}=[fill=black, inner sep=1.5pt, circle]%
+%
+\tikzstyle{tikzuml association style}=[color=\tikzumlDefaultDrawColor, -]%
+\tikzstyle{tikzuml bidirectional association style}=[color=\tikzumlDefaultDrawColor, angle45-angle45]%
+\tikzstyle{tikzuml unidirectional association style}=[color=\tikzumlDefaultDrawColor, -angle 45]%
+\tikzstyle{tikzuml aggregation style}=[color=\tikzumlDefaultDrawColor, open diamond-]%
+\tikzstyle{tikzuml unidirectional aggregation style}=[color=\tikzumlDefaultDrawColor, open diamond-angle 45]%
+\tikzstyle{tikzuml composition style}=[color=\tikzumlDefaultDrawColor, diamond-]%
+\tikzstyle{tikzuml unidirectional composition style}=[color=\tikzumlDefaultDrawColor, diamond-angle 45]%
+\tikzstyle{tikzuml nesting style}=[color=\tikzumlDefaultDrawColor]%
+\tikzstyle{tikzuml dependency style}=[color=\tikzumlDefaultDrawColor, -angle 45, dashed]%
+\tikzstyle{tikzuml import style}=[color=\tikzumlDefaultDrawColor, -angle 45, dashed]%
+\tikzstyle{tikzuml inherit style}=[color=\tikzumlDefaultDrawColor, -open triangle 45]%
+\tikzstyle{tikzuml implements style}=[color=\tikzumlDefaultDrawColor, -open triangle 45, dashed]%
+%
+\pgfkeys{/tikzuml/assemblyconnectorrelation/.cd, anchors/.style args={#1 and #2}{anchor1=#1, anchor2=#2}}%
+%
+\newcounter{tikzumlPackageClassNum}%
+\newcounter{tikzumlPackageSubPackageNum}%
+\newcounter{tikzumlRelationNum}%
+\setcounter{tikzumlRelationNum}{1}%
+\newcounter{tikzumlNoteNum}%
+\setcounter{tikzumlNoteNum}{1}%
+%
+\newcounter{pos}%
+\newcounter{posT}%
+\newcounter{posStereo}%
+%
+\newcounter{tikzumlPackageLevel}%
+\setcounter{tikzumlPackageLevel}{0}%
+%
+\newif\iftikzumlpackageSimpleStyle%
+\newif\iftikzumlclassSimpleStyle%
+\newif\iftikzumlclassCircleShape%
+\newif\iftikzumlpackageWithoutCoords%
+\newif\iftikzumlclassWithoutCoords%
+\newif\iftikzumlassocclassWithoutCoords%
+\newif\iftikzumlnoteWithoutCoords%
+%
+% define a uml package
+% arg : package name
+% optional : x, y: coordinates of the package
+% type: stereotype of the package
+% name: name of the package node
+% draw, fill, text: colors
+% style: to manage every default TikZ option
+% no coords: to tell that the package position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newenvironment{umlpackage}[2][]{%
+ \pgfkeys{/tikzuml/package/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, style/.style={},%
+ name/.initial=tikzumlEmpty, type/.initial=\tikzumlPackageDefaultType, draw/.initial=\tikzumlDefaultDrawColor,%
+ fill/.initial=\tikzumlPackageDefaultFillColor, text/.initial=\tikzumlDefaultTextColor,%
+ no coords/.is if=tikzumlpackageWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/package/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/package/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/package/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlpackage, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/package/.cd, #1}%
+ \pgfkeys{/tikzuml/package/.cd, x/.get=\tikzumlPackageXShift, y/.get=\tikzumlPackageYShift, name/.get=\tikzumlPackageName, type/.get=\tikzumlPackageTypeTmp,%
+ draw/.get=\tikzumlPackageDrawColor, fill/.get=\tikzumlPackageFillColor,%
+ text/.get=\tikzumlPackageTextColor%
+ }%
+ %
+
+ %
+ \ifthenelse{\equal{\tikzumlPackageTypeTmp}{tikzumlEmpty}}{%
+ \def\tikzumlPackageType{}%
+ }{%
+ \expandafter\def\expandafter\tikzumlPackageType\expandafter{$\ll$\tikzumlPackageTypeTmp$\gg$ \\}%
+ }%
+ %
+ \ifnum\thetikzumlPackageLevel>0%
+ \let\tikzumlPackage@nameold\tikzumlPackage@fitname%
+ \def\tikzumlPackage@name{#2}%
+ \begingroup%
+ \def\_{@}\edef\x{\endgroup%
+ \def\noexpand\tikzumlPackage@fitname{\tikzumlPackage@name}}\x%
+ \let\tikzumlPackage@parentold\tikzumlPackage@parent%
+ \edef\tikzumlPackage@parent{\tikzumlPackage@parentold @@\tikzumlPackage@nameold}%
+ \else%
+ \def\tikzumlPackage@parent{}%
+ \def\tikzumlPackage@name{#2}%
+ \begingroup%
+ \def\_{@}\edef\x{\endgroup%
+ \def\noexpand\tikzumlPackage@fitname{\tikzumlPackage@name}}\x%
+ \fi%
+ %
+ \let\tikzumlPackage@nodeNameold\tikzumlPackage@nodeName%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlPackage@nodeName{\tikzumlPackage@name}}\x%
+ %
+ \ifthenelse{\equal{\tikzumlPackageName}{tikzumlEmpty}}{}{%
+ \def\tikzumlPackage@nodeName{\tikzumlPackageName}%
+ }%
+ %
+ \StrSubstitute{\tikzumlPackage@nodeName}{.}{@POINT@}{\tikzumlPackage@nodeName}%
+ %
+ \expandafter\gdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{}%
+ %
+ \setcounter{tikzumlPackageClassNum}{0}%
+ \setcounter{tikzumlPackageSubPackageNum}{0}%
+ \stepcounter{tikzumlPackageLevel}%
+ %
+ \begin{scope}[xshift=\tikzumlPackageXShift cm, yshift=\tikzumlPackageYShift cm]%
+}{%
+ \addtocounter{tikzumlPackageLevel}{-1}%
+ \begin{pgfonlayer}{package\thetikzumlPackageLevel}%
+ %
+ % if contains no class, and not simple, one define a fictive node to enable the fit option
+ \ifnum\c@tikzumlPackageClassNum=0%
+ \ifnum\c@tikzumlPackageSubPackageNum=0%
+ \iftikzumlpackageWithoutCoords%
+ \node[inner sep=1.5ex, /tikzuml/package/style] (\tikzumlPackage@nodeName-root) {\phantom{\tikzumlPackage@nodeName}};%
+ \else%
+ \node[inner sep=1.5ex, /tikzuml/package/style] (\tikzumlPackage@nodeName-root) at (0,0) {\phantom{\tikzumlPackage@nodeName}};%
+ \fi%
+ \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{(\tikzumlPackage@nodeName-root)}%
+ \fi%
+ \fi%
+ %
+ \ifnum\c@tikzumlPackageLevel>0%
+ \def\tikzumlPackageFitTmp{\csname tikzumlPackageFit\tikzumlPackage@parent\endcsname}%
+ \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent\endcsname{\tikzumlPackageFitTmp (\tikzumlPackage@nodeName) (\tikzumlPackage@nodeName-caption)}%
+ \stepcounter{tikzumlPackageSubPackageNum}%
+ \fi%
+ %
+ \node[draw=\tikzumlPackageDrawColor, fill=\tikzumlPackageFillColor, text=\tikzumlPackageTextColor, font=\tikzumlDefaultFont, inner sep=1.5ex, /tikzuml/package/style, fit = \csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname] (\tikzumlPackage@nodeName) {};%
+ \node[draw=\tikzumlPackageDrawColor, fill=\tikzumlPackageFillColor, text=\tikzumlPackageTextColor, font=\tikzumlDefaultFont, minimum height=1.5em, outer ysep=-0.3, anchor=south west] (\tikzumlPackage@nodeName-caption) at (\tikzumlPackage@nodeName.north west) {\begin{tabular}{c} \tikzumlPackageType \textbf{\tikzumlPackage@name}\end{tabular}};%
+ \end{pgfonlayer}%
+ \end{scope}%
+}%
+%
+% shortcut to define an empty package
+\newcommand{\umlemptypackage}[2][]{\begin{umlpackage}[#1]{#2} \end{umlpackage}}%
+%
+% define a uml class
+% args : name of the class
+% attributes of the class
+% operations of the class
+% optional : x, y: coordinates of the class
+% width: of the class node
+% type: type of class (class, interface, typedef, enum)
+% tags: tagged values of class
+% template: template parameters
+% simple: if used, class is empty and drawn with a rectangle
+% circle: if used with simple, class is empty and drawn with a circle
+% draw, fill, fill template, and text: colors
+% style: to manage every default TikZ option
+% no coords: to tell that the class position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlclass}[4][]{%
+ \pgfkeys{/tikzuml/class/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlClassDefaultWidth, type/.initial=\tikzumlClassDefaultType,%
+ tags/.initial={}, style/.style={},%
+ template/.initial={}, name/.initial=tikzumlEmpty,%
+ draw/.initial=\tikzumlDefaultDrawColor,%
+ fill template/.initial=\tikzumlClassTemplateFillColorDefaultFillColor,%
+ fill/.initial=\tikzumlClassDefaultFillColor,%
+ text/.initial=\tikzumlDefaultTextColor,%
+ simple/.is if=tikzumlclassSimpleStyle, circle/.is if=tikzumlclassCircleShape, no coords/.is if=tikzumlclassWithoutCoords,%
+ simple=false, circle=false, no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/class/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/class/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/class/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlclass, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/class/.cd,#1}%
+ %
+ \iftikzumlclassSimpleStyle%
+ \iftikzumlclassCircleShape%
+ \pgfkeys{/tikzuml/class/.cd, width/.initial=\tikzumlSimpleInterfaceDefaultWidth}%
+ \fi%
+ \fi%
+ %
+ \pgfkeys{/tikzuml/class/.cd, x/.get=\tikzumlClassX, y/.get=\tikzumlClassY, width/.get=\tikzumlClassMinimumWidth,%
+ type/.get=\tikzumlClassTypeTmp, tags/.get=\tikzumlClassTagsTmp, template/.get=\tikzumlClassTemplateFillColorParam,%
+ name/.get=\tikzumlClassName,%
+ draw/.get=\tikzumlClassDrawColor, fill/.get=\tikzumlClassFillColor,%
+ text/.get=\tikzumlClassTextColor, fill template/.get=\tikzumlClassTemplateFillColor%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlClassTypeTmp}{class}\OR\equal{\tikzumlClassTypeTmp}{abstract}}{%
+ \def\tikzumlClassType{}%
+ }{%
+ \expandafter\def\expandafter\tikzumlClassType\expandafter{$\ll$\tikzumlClassTypeTmp$\gg$ \\}%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlClassTagsTmp}{}}{%
+ \def\tikzumlClassTags{}%
+ }{%
+ \def\tikzumlClassTags{\\ \{\tikzumlClassTagsTmp\}}%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlClassTemplateFillColorParam}{}}{%
+ \def\tikzumlClassVPadding{}%
+ \def\tikzumlClassHPadding{}%
+ }{%
+ \def\tikzumlClassVPadding{\vspace{0.1em} \\}%
+ \def\tikzumlClassHPadding{\hspace{0.5ex} $ $}%
+ }%
+ %
+ \def\tikzumlClassName{#2}%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlClassNodeName{\tikzumlClassName}}\x%
+ %
+ \ifthenelse{\equal{\tikzumlClassName}{tikzumlEmpty}}{}{%
+ \def\tikzumlClassNodeName{\tikzumlClassName}%
+ }%
+ %
+ \StrSubstitute{\tikzumlClassNodeName}{:}{@COLON@}[\tikzumlClassNodeName]%
+ \StrSubstitute{\tikzumlClassNodeName}{\_}{@UNDERSCORE@}[\tikzumlClassNodeName]%
+ %
+ \ifthenelse{\equal{\tikzumlClassTypeTmp}{abstract}}{%
+ \let\tikzumlClassNameOld\tikzumlClassName%
+ \def\tikzumlClassName{{\it \tikzumlClassNameOld}}%
+ }{}%
+ %
+ \def\tikzumlClassPos{\tikzumlClassX,\tikzumlClassY}%
+ \def\tikzumlClassAttributes{#3}%
+ \def\tikzumlClassOperations{#4}%
+ %
+ \iftikzumlclassSimpleStyle%
+ \iftikzumlclassWithoutCoords%
+ \iftikzumlclassCircleShape%
+ \node[tikzuml simpleinterface style, draw=\tikzumlClassDrawColor, fill=\tikzumlClassFillColor, text=\tikzumlClassTextColor, font=\tikzumlDefaultFont, minimum width=\tikzumlClassMinimumWidth, /tikzuml/class/style] (\tikzumlClassNodeName) {};%
+ \node[anchor=south] (\tikzumlClassNodeName-label) at (\tikzumlClassNodeName.north) {\begin{tabular}{c}\tikzumlClassVPadding \tikzumlClassType \tikzumlClassHPadding \textbf{\tikzumlClassName} \tikzumlClassHPadding \tikzumlClassTags \end{tabular}%
+ };%
+ \else%
+ \node[tikzuml simpleclass style, draw=\tikzumlClassDrawColor, fill=\tikzumlClassFillColor, text=\tikzumlClassTextColor, font=\tikzumlDefaultFont, minimum width=\tikzumlClassMinimumWidth, /tikzuml/class/style] (\tikzumlClassNodeName) {\begin{tabular}{c}\tikzumlClassVPadding \tikzumlClassType \tikzumlClassHPadding \textbf{\tikzumlClassName} \tikzumlClassHPadding \tikzumlClassTags \end{tabular}%
+ };%
+ \fi%
+ \else%
+ \iftikzumlclassCircleShape%
+ \node[tikzuml simpleinterface style, draw=\tikzumlClassDrawColor, fill=\tikzumlClassFillColor, text=\tikzumlClassTextColor, font=\tikzumlDefaultFont, minimum width=\tikzumlClassMinimumWidth, /tikzuml/class/style] (\tikzumlClassNodeName) at (\tikzumlClassPos) {};
+ \node[anchor=south] (\tikzumlClassNodeName-label) at (\tikzumlClassNodeName.north){\begin{tabular}{c}\tikzumlClassVPadding \tikzumlClassType \tikzumlClassHPadding \textbf{\tikzumlClassName} \tikzumlClassHPadding \tikzumlClassTags \end{tabular}%
+ };%
+ \else%
+ \node[tikzuml simpleclass style, draw=\tikzumlClassDrawColor, fill=\tikzumlClassFillColor, text=\tikzumlClassTextColor, font=\tikzumlDefaultFont, minimum width=\tikzumlClassMinimumWidth, /tikzuml/class/style] (\tikzumlClassNodeName) at (\tikzumlClassPos) {\begin{tabular}{c}\tikzumlClassVPadding \tikzumlClassType \tikzumlClassHPadding \textbf{\tikzumlClassName} \tikzumlClassHPadding \tikzumlClassTags \end{tabular}%
+ };%
+ \fi%
+ \fi%
+ \else%
+ \iftikzumlclassWithoutCoords%
+ \node[tikzuml class style, draw=\tikzumlClassDrawColor, fill=\tikzumlClassFillColor, text=\tikzumlClassTextColor, font=\tikzumlDefaultFont, minimum width=\tikzumlClassMinimumWidth, /tikzuml/class/style] (\tikzumlClassNodeName) {\begin{tabular}{c}\tikzumlClassVPadding \tikzumlClassType \tikzumlClassHPadding \textbf{\tikzumlClassName} \tikzumlClassHPadding \tikzumlClassTags \end{tabular}%
+ \nodepart{second}%
+ \begin{tabular}{l}%
+ \tikzumlClassAttributes%
+ \end{tabular}%
+ \nodepart{third}%
+ \begin{tabular}{l}%
+ \tikzumlClassOperations%
+ \end{tabular}%
+ };%
+ \else%
+ \node[tikzuml class style, draw=\tikzumlClassDrawColor, fill=\tikzumlClassFillColor, text=\tikzumlClassTextColor, font=\tikzumlDefaultFont, minimum width=\tikzumlClassMinimumWidth, /tikzuml/class/style] (\tikzumlClassNodeName) at (\tikzumlClassPos) {\begin{tabular}{c}\tikzumlClassVPadding \tikzumlClassType \tikzumlClassHPadding \textbf{\tikzumlClassName} \tikzumlClassHPadding \tikzumlClassTags \end{tabular}%
+ \nodepart{second}%
+ \begin{tabular}{l}%
+ \tikzumlClassAttributes%
+ \end{tabular}%
+ \nodepart{third}%
+ \begin{tabular}{l}%
+ \tikzumlClassOperations%
+ \end{tabular}%
+ };%
+ \fi%
+ \fi%
+ %
+ \ifthenelse{\equal{\tikzumlClassTemplateFillColorParam}{}}{}{%
+ \draw (\tikzumlClassNodeName.north east) node[tikzuml template style, name=\tikzumlClassNodeName-template, draw=\tikzumlClassDrawColor, fill=\tikzumlClassTemplateFillColor, text=\tikzumlClassTextColor, font=\tikzumlDefaultFont] {\tikzumlClassTemplateFillColorParam};%
+ }%
+ %
+ % add to fit
+ \ifnum\c@tikzumlPackageLevel>0%
+ \edef\tikzumlPackageFitOld{\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname}%
+ \ifthenelse{\equal{\tikzumlClassTemplateFillColorParam}{}}{%
+ \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{\tikzumlPackageFitOld (\tikzumlClassNodeName)}%
+ }{%
+ \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{\tikzumlPackageFitOld (\tikzumlClassNodeName) (\tikzumlClassNodeName-template)}%
+ }%
+ \stepcounter{tikzumlPackageClassNum}%
+ \fi%
+ \ifnum\c@tikzumlComponentLevel>0%
+ \def\tikzumlComponentFitTmp{\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname}%
+ \ifthenelse{\equal{\tikzumlClassTemplateFillColorParam}{}}{%
+ \expandafter\xdef\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname{\tikzumlComponentFitTmp (\tikzumlClassNodeName)}%
+ }{%
+ \expandafter\xdef\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname{\tikzumlComponentFitTmp (\tikzumlClassNodeName) (\tikzumlClassNodeName-template)}%
+ }%
+ \stepcounter{tikzumlComponentSubComponentNum}%
+ \fi%
+}%
+%
+% shortcuts for interface, enum and typedef environments
+\newcommand{\umlabstract}[4][]{%
+ \pgfkeys{/tikzuml/class/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{type}}{%
+ \errmessage{TIKZUML ERROR : in umlabstract, forbidden option type}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/class/.cd, #1}%
+ \umlclass[type=abstract,#1]{#2}{#3}{#4}%
+}%
+\newcommand{\umlinterface}[4][]{%
+ \pgfkeys{/tikzuml/class/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{type}}{%
+ \errmessage{TIKZUML ERROR : in umlinterface, forbidden option type}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/class/.cd, #1}%
+ \umlclass[type=interface,#1]{#2}{#3}{#4}%
+}%
+\newcommand{\umltypedef}[4][]{%
+ \pgfkeys{/tikzuml/class/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{type}}{%
+ \errmessage{TIKZUML ERROR : in umltypedef, forbidden option type}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/class/.cd, #1}%
+ \umlclass[type=typedef,#1]{#2}{#3}{#4}%
+}%
+\newcommand{\umlenum}[4][]{%
+ \pgfkeys{/tikzuml/class/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{type}}{%
+ \errmessage{TIKZUML ERROR : in umlenum, forbidden option type}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/class/.cd, #1}%
+ \umlclass[type=enum,#1]{#2}{#3}{#4}
+}%
+%
+% shortcut to define an empty class
+\newcommand{\umlemptyclass}[2][]{\umlclass[#1]{#2}{}{}}%
+\newcommand{\umlsimpleclass}[2][]{%
+ \pgfkeys{/tikzuml/class/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{simple}}{%
+ \errmessage{TIKZUML ERROR : in umlsimpleclass, forbidden option simple}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/class/.cd, #1}%
+ \umlemptyclass[simple, #1]{#2}%
+}%
+%
+\newcommand{\umlsimpleinterface}[2][]{%
+ \pgfkeys{/tikzuml/class/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{simple}}{%
+ \errmessage{TIKZUML ERROR : in umlsimpleinterface, forbidden option simple}%
+ }{%
+ \ifthenelse{\equal{\keyname}{circle}}{%
+ \errmessage{TIKZUML ERROR : in umlsimpleinterface, forbidden option circle}%
+ }{}%
+ }%
+ }%
+ }%
+ \pgfkeys{/tikzuml/class/.cd, #1}%
+ \umlsimpleclass[circle, #1]{#2}%
+}%
+% underline the text for static arg
+\newcommand{\umlstatic}[1]{\underline{#1}}%
+\newcommand{\umlvirt}[1]{\textit{#1}}%
+%
+% define node for n-ary association
+\newcommand{\umlNarynode}[2][]{%
+ \def\tikzumlNaryNodeAnchor{.north}
+ \def\tikzumlNaryNodeLabelPos{above}
+ \pgfkeys{/tikzuml/narynode/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlNaryNodeDefaultWidth, name/.initial=tikzumlEmpty,%
+ draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlClassDefaultFillColor,%
+ text/.initial=\tikzumlDefaultTextColor, style/.style={},%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}}{%
+ \def\tikzumlNaryNodeAnchor{.north}%
+ \def\tikzumlNaryNodeLabelPos{above}%
+ }{%
+ \ifthenelse{\equal{\keyname}{above left}}{%
+ \def\tikzumlNaryNodeAnchor{.north west}%
+ \def\tikzumlNaryNodeLabelPos{above left}%
+ }{%
+ \ifthenelse{\equal{\keyname}{left}}{%
+ \def\tikzumlNaryNodeAnchor{.west}%
+ \def\tikzumlNaryNodeLabelPos{left}%
+ }{%
+ \ifthenelse{\equal{\keyname}{below left}}{%
+ \def\tikzumlNaryNodeAnchor{.south west}%
+ \def\tikzumlNaryNodeLabelPos{below left}%
+ }{%
+ \ifthenelse{\equal{\keyname}{below}}{%
+ \def\tikzumlNaryNodeAnchor{.south}%
+ \def\tikzumlNaryNodeLabelPos{below}%
+ }{%
+ \ifthenelse{\equal{\keyname}{below right}}{%
+ \def\tikzumlNaryNodeAnchor{.south east}%
+ \def\tikzumlNaryNodeLabelPos{below right}%
+ }{%
+ \ifthenelse{\equal{\keyname}{right}}{%
+ \def\tikzumlNaryNodeAnchor{.east}%
+ \def\tikzumlNaryNodeLabelPos{right}%
+ }{%
+ \ifthenelse{\equal{\keyname}{above right}}{%
+ \def\tikzumlNaryNodeAnchor{.north east}%
+ \def\tikzumlNaryNodeLabelPos{above right}%
+ }{%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/narynode/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/narynode/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlNarynode, invalid option \keyname}%
+ }%
+ }%
+ }%
+ }%
+ }%
+ }%
+ }%
+ }%
+ }%
+ }%
+ \pgfkeys{/tikzuml/narynode/.cd,#1}%
+ \pgfkeys{/tikzuml/narynode/.cd, x/.get=\tikzumlNaryNodeX, y/.get=\tikzumlNaryNodeY, width/.get=\tikzumlNaryNodeMinimumWidth,%
+ name/.get=\tikzumlNaryNodeName,%
+ draw/.get=\tikzumlNaryNodeDrawColor, fill/.get=\tikzumlNaryNodeFillColor,%
+ text/.get=\tikzumlNaryNodeTextColor%
+ }%
+ %
+ \def\tikzumlNaryName{#2}%
+ %
+ \ifthenelse{\equal{\tikzumlNaryNodeName}{tikzumlEmpty}}{%
+ \edef\tikzumlNaryNodeName{\tikzumlNaryName}%
+ }{%
+ \edef\tikzumlNaryNodeName{\tikzumlNaryNodeName}%
+ }%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlNaryNode@nodeName{\tikzumlNaryNodeName}}\x%
+ %
+ \StrSubstitute{\tikzumlNaryNode@nodeName}{:}{@COLON@}[\tikzumlNaryNode@nodeName]%
+ \StrSubstitute{\tikzumlNaryNode@nodeName}{\_}{@UNDERSCORE@}[\tikzumlNaryNode@nodeName]%
+ %
+ \def\tikzumlNarynodePos{\tikzumlNaryNodeX,\tikzumlNaryNodeY}%
+ %
+ \node[tikzuml narynode style, draw=\tikzumlNaryNodeDrawColor, fill=\tikzumlNaryNodeFillColor, text=\tikzumlNaryNodeTextColor, font=\tikzumlDefaultFont, minimum width=\tikzumlNaryNodeMinimumWidth, minimum height=\tikzumlNaryNodeMinimumWidth, /tikzuml/narynode/style] (\tikzumlNaryNode@nodeName) at (\tikzumlNarynodePos) {};%
+ \draw (\tikzumlNaryNode@nodeName\tikzumlNaryNodeAnchor) node[\tikzumlNaryNodeLabelPos] {\tikzumlNaryName};%
+ %
+ % add to fit
+ \ifnum\c@tikzumlPackageLevel>0%
+ \edef\tikzumlPackageFitOld{\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{\tikzumlPackageFitOld (\tikzumlNaryNode@nodeName)}%
+ \stepcounter{tikzumlPackageClassNum}%
+ \fi%
+}%
+%
+\newdimen\tikzumlNestingSymbolSize%
+%
+% main command to define a relation between two classes
+% args : src class
+% dest class
+% optional : geometry: geometry of the line
+% weight: barycentric weight of the middle part when geometry is a 3-line
+% arm1, arm2: lengths of first or last part when geometry id a 3-line
+% arg1, arg2, arg: name of the src/dest/dest side class type attribute defined by the relation
+% mult1, mult2, mult: multiplicity of the src/dest/dest side class type attribute defined by the relation
+% pos1, pos2, pos: position of the src/dest/dest side class type attribute defined by the relation
+% align1, align2, align: text justification of the src/dest/dest side class type attribute defined by the relation
+% anchor1, anchor2: src/dest anchors on linked classes
+% angle1, angle2, loopsize: start angle, end angle and size of the relation (only if recursive)
+% stereo: stereotype of the relation
+% pos stereo: position of the stereotype on the relation
+% style: style of the relation (association, aggregation, composition, inherit, ...)
+% name: rootname used for naming nodes of the relation
+% recursive mode: type of recursive arrow (transition for state diagrams, or default)
+% recursive direction start/end: when transition relation, start/end directions of the relation arrow
+\newcommand{\umlrelation}[3][]{%
+ \pgfkeys{/tikzuml/relation/.cd, geometry/.initial=\tikzumlRelationDefaultGeometry, weight/.initial=\tikzumlRelationDefaultWeight,%
+ arm1/.initial=auto, arm2/.initial=auto,%
+ arg1/.initial={}, arg2/.initial={}, arg/.initial={},%
+ mult1/.initial={}, mult2/.initial={}, mult/.initial={},%
+ pos1/.initial=\tikzumlRelationDefaultPosO, pos2/.initial=\tikzumlRelationDefaultPosT, pos/.initial=tikzumlEmpty,%
+ align1/.initial={}, align2/.initial={}, align/.initial={},%
+ anchor1/.initial=tikzumlEmpty, anchor2/.initial=tikzumlEmpty,%
+ angle1/.initial=\tikzumlRelationDefaultAngleO, angle2/.initial=\tikzumlRelationDefaultAngleT, loopsize/.initial=\tikzumlRelationDefaultLoopSize,%
+ stereo/.initial={}, pos stereo/.initial=\tikzumlRelationDefaultPosStereo,%
+ style/.initial=->, style2/.style={}, name/.initial=relation-\thetikzumlRelationNum,%
+ recursive mode/.initial=default, recursive direction start/.initial=right,%
+ recursive direction end/.initial=bottom,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{with port}%
+ \OR\equal{\keyname}{interface}%
+ \OR\equal{\keyname}{padding}%
+ \OR\equal{\keyname}{width}%
+ \OR\equal{\keyname}{first arm}%
+ \OR\equal{\keyname}{second arm}%
+ \OR\equal{\keyname}{middle arm}%
+ \OR\equal{\keyname}{last arm}%
+ \OR\equal{\keyname}{distance}}{}{%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/relation/.cd, style2/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/relation/.cd, style2/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlrelation, invalid option \keyname}%
+ }%
+ }%
+ }%
+ \pgfkeys{/tikzuml/relation/.cd,#1}%
+ \pgfkeys{/tikzuml/relation/.cd, geometry/.get=\tikzumlRelationGeometry, weight/.get=\tikzumlRelationWeight,%
+ arm1/.get=\tikzumlRelationArmO, arm2/.get=\tikzumlRelationArmT,%
+ arg1/.get=\tikzumlRelationAttrName, arg2/.get=\tikzumlRelationAttrNameTO, arg/.get=\tikzumlRelationAttrNameTT,%
+ mult1/.get=\tikzumlRelationMultiplicity, mult2/.get=\tikzumlRelationMultiplicityTO, mult/.get=\tikzumlRelationMultiplicityTT,%
+ pos1/.get=\tikzumlRelationPosition, pos2/.get=\tikzumlRelationPositionTO, pos/.get=\tikzumlRelationPositionTT,%
+ align1/.get=\tikzumlRelationAlign, align2/.get=\tikzumlRelationAlignTO, align/.get=\tikzumlRelationAlignTT,%
+ anchor1/.get=\tikzumlRelationSrcAnchor, anchor2/.get=\tikzumlRelationDestAnchor,%
+ angle1/.get=\tikzumlRelationStartAngle, angle2/.get=\tikzumlRelationEndAngle, loopsize/.get=\tikzumlRelationLoopSize,%
+ stereo/.get=\tikzumlRelationStereoType, pos stereo/.get=\tikzumlRelationPositionStereotype,%
+ style/.get=\tikzumlRelationStyle, name/.get=\tikzumlRelationName,%
+ recursive mode/.get=\tikzumlRelationRecursiveMode,%
+ recursive direction start/.get=\tikzumlRelationRecursiveDirectionStart,%
+ recursive direction end/.get=\tikzumlRelationRecursiveDirectionEnd%
+ }%
+ %
+ \def\tikzumlSrcClassName{#2}%
+ %
+ % managing \_ in class names for node names
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlSrcClassNodeName{\tikzumlSrcClassName}}\x%
+ %
+ \StrSubstitute{\tikzumlSrcClassNodeName}{:}{@COLON@}[\tikzumlSrcClassNodeName]%
+ \StrSubstitute{\tikzumlSrcClassNodeName}{\_}{@UNDERSCORE@}[\tikzumlSrcClassNodeName]%
+ %
+ \def\tikzumlDestClassName{#3}%
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlDestClassNodeName{\tikzumlDestClassName}}\x%
+ %
+ \StrSubstitute{\tikzumlDestClassNodeName}{:}{@COLON@}[\tikzumlDestClassNodeName]%
+ \StrSubstitute{\tikzumlDestClassNodeName}{\_}{@UNDERSCORE@}[\tikzumlDestClassNodeName]%
+ %
+ % managing alias keys
+ \def\tikzumlRelationAttrNameT{\tikzumlRelationAttrNameTO\tikzumlRelationAttrNameTT}%
+ \def\tikzumlRelationMultiplicityT{\tikzumlRelationMultiplicityTO\tikzumlRelationMultiplicityTT}%
+ \def\tikzumlRelationAlignT{\tikzumlRelationAlignTO\tikzumlRelationAlignTT}%
+ \def\posAttrName{}%
+ \def\posMultiplicity{}%
+ \def\posAttrNameT{}%
+ \def\posMultiplicityT{}%
+ %
+ \ifthenelse{\equal{\tikzumlRelationPositionTT}{tikzumlEmpty}}{%
+ \def\tikzumlRelationPositionT{\tikzumlRelationPositionTO}%
+ }{%
+ \def\tikzumlRelationPositionT{\tikzumlRelationPositionTT}%
+ }%
+ %
+ \def\attrAlign{}%
+ \def\multAlign{}%
+ \def\attrAlignT{}%
+ \def\multAlignT{}%
+ %
+ \ifthenelse{\equal{\tikzumlRelationAlign}{left}}{%
+ \def\attrAlign{above right}%
+ \def\multAlign{below right}%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationAlign}{right}}{%
+ \def\attrAlign{above left}%
+ \def\multAlign{below left}%
+ }{}%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlRelationAlignT}{left}}{%
+ \def\attrAlignT{above right}%
+ \def\multAlignT{below right}%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationAlignT}{right}}{%
+ \def\attrAlignT{above left}%
+ \def\multAlignT{below left}%
+ }{}%
+ }%
+ %
+ % def stereotype
+ \ifthenelse{\equal{\tikzumlRelationStereoType}{}}{%
+ \def\stereotype{}%
+ }{%
+ \def\stereotype{$\ll$\tikzumlRelationStereoType$\gg$}%
+ }%
+
+ % def anchors macros
+ \ifthenelse{\equal{\tikzumlRelationSrcAnchor}{tikzumlEmpty}}{%
+ \def\tikzumlRelationSrcAnchor{}%
+ }{%
+ \let\tikzumlRelationSrcAnchorold\tikzumlRelationSrcAnchor%
+ \def\tikzumlRelationSrcAnchor{.\tikzumlRelationSrcAnchorold}%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlRelationDestAnchor}{tikzumlEmpty}}{%
+ \def\tikzumlRelationDestAnchor{}%
+ }{%
+ \let\tikzumlRelationDestAnchorold\tikzumlRelationDestAnchor%
+ \def\tikzumlRelationDestAnchor{.\tikzumlRelationDestAnchorold}%
+ }%
+ %
+ \setcounter{pos}{100*\real{\tikzumlRelationPosition}}%
+ \setcounter{posT}{100*\real{\tikzumlRelationPositionT}}%
+ \setcounter{posStereo}{100*\real{\tikzumlRelationPositionStereotype}}%
+ %
+ \pgfmathsetmacro{\tikzumlRelationWeightT}{1.0-\tikzumlRelationWeight}%
+ %
+ %\newcounter{tikzumlControlNodesNum}%
+ %\setcounter{tikzumlControlNodesNum}{0}%
+ %
+ \node[inner sep=0] (\tikzumlRelationName-middle) at (barycentric cs:\tikzumlSrcClassNodeName=\tikzumlRelationWeightT,\tikzumlDestClassNodeName=\tikzumlRelationWeight) {};%
+ %
+ % straight line
+ \ifthenelse{\equal{\tikzumlRelationGeometry}{--}}%
+ {%
+ \ifthenelse{\equal{\tikzumlSrcClassNodeName}{\tikzumlDestClassNodeName}}{%
+ \def\arcNum{1}%
+ \def\arcNumT{1}%
+ %
+ \ifthenelse{\equal{\tikzumlRelationRecursiveMode}{default}}{%
+ \xdef\tikzumlLastArc{node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity}%
+ node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT}%
+ node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \xdef\tikzumlPath{(\tikzumlSrcClassNodeName) edge[in=\tikzumlRelationEndAngle, out=\tikzumlRelationStartAngle, distance=\tikzumlRelationLoopSize] \tikzumlLastArc%
+ node[midway, inner sep=0, name=\tikzumlRelationName-1, anchor=center] {} (\tikzumlDestClassNodeName) }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveMode}{transition}}{%
+ \xdef\tikzumlFirstArc{node[midway, inner sep=0, name=\tikzumlRelationName-1, anchor=center] {}}%
+ \xdef\tikzumlMidOneArc{node[midway, inner sep=0, name=\tikzumlRelationName-3, anchor=center] {}}%
+ %
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{\tikzumlRelationRecursiveDirectionEnd}}{%
+ \def\numArcs{3}%
+ \xdef\tikzumlLastArc{node[midway, inner sep=0, name=\tikzumlRelationName-5, anchor=center] {}}%
+ %
+ \begin{pgfonlayer}{connections}%
+ \draw (\tikzumlSrcClassNodeName) edge[in=\tikzumlRelationEndAngle, out=\tikzumlRelationStartAngle, distance=\tikzumlRelationLoopSize, draw=none] %
+ node[midway, inner sep=0, name=\tikzumlRelationName-tmp, anchor=center] {} (\tikzumlDestClassNodeName);%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}\OR\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{%
+ \node[inner sep=0, name=\tikzumlRelationName-2] at (\tikzumlSrcClassNodeName.\tikzumlRelationStartAngle -| \tikzumlRelationName-tmp) {};%
+ \node[inner sep=0, name=\tikzumlRelationName-4] at (\tikzumlDestClassNodeName.\tikzumlRelationEndAngle -| \tikzumlRelationName-tmp) {};%
+ }{%
+ \node[inner sep=0, name=\tikzumlRelationName-2] at (\tikzumlSrcClassNodeName.\tikzumlRelationStartAngle |- \tikzumlRelationName-tmp) {};%
+ \node[inner sep=0, name=\tikzumlRelationName-4] at (\tikzumlDestClassNodeName.\tikzumlRelationEndAngle |- \tikzumlRelationName-tmp) {};%
+ }%
+ \end{pgfonlayer}%
+ }{%
+ \def\numArcs{4}%
+ \xdef\tikzumlMidTwoArc{node[midway, inner sep=0, name=\tikzumlRelationName-5, anchor=center] {}}%
+ \xdef\tikzumlLastArc{node[midway, inner sep=0, name=\tikzumlRelationName-7, anchor=center] {}}%
+ %
+ \begin{pgfonlayer}{connections}%
+ \draw (\tikzumlSrcClassNodeName) edge[in=\tikzumlRelationEndAngle, out=\tikzumlRelationStartAngle, distance=\tikzumlRelationLoopSize, draw=none] %
+ node[midway, name=\tikzumlRelationName-4, anchor=center] {} (\tikzumlDestClassNodeName);%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}\OR\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{%
+ \node[inner sep=0, name=\tikzumlRelationName-2] at (\tikzumlSrcClassNodeName.\tikzumlRelationStartAngle -| \tikzumlRelationName-4) {};%
+ \node[inner sep=0, name=\tikzumlRelationName-6] at (\tikzumlDestClassNodeName.\tikzumlRelationEndAngle |- \tikzumlRelationName-4) {};%
+ }{%
+ \node[inner sep=0, name=\tikzumlRelationName-2] at (\tikzumlSrcClassNodeName.\tikzumlRelationStartAngle |- \tikzumlRelationName-4) {};%
+ \node[inner sep=0, name=\tikzumlRelationName-6] at (\tikzumlDestClassNodeName.\tikzumlRelationEndAngle -| \tikzumlRelationName-4) {};%
+ }%
+ \end{pgfonlayer}%
+ }%
+ %
+ \ifnum\numArcs=4%
+ \ifnum\theposStereo>300%
+ \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-300)/100}%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype}}%
+ \else%
+ \ifnum\theposStereo<100%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype}}%
+ \else%
+ \ifnum\theposStereo>200%
+ \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-200)/100}%
+ \xdef\tikzumlMidTwoArc{\tikzumlMidTwoArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype}}%
+ \else%
+ \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-100)/100}%
+ \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype}}%
+ \fi%
+ \fi%
+ \fi%
+ %
+ \ifthenelse{\thepos=300\OR\thepos=100}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{bottom}}{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{bottom}}{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{top}}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{left}}{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{left}}{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }%
+ }%
+ }%
+ }%
+ }{}%
+ %
+ \ifthenelse{\thepos=200}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{bottom}}{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{bottom}}{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{top}}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{left}}{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{left}}{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }%
+ }%
+ }%
+ }%
+ }{}%
+ %
+ \ifnum\thepos>300%
+ \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-300)/100}%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity}%
+ }%
+ \else%
+ \ifnum\thepos<100%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity}%
+ }%
+ \else%
+ \ifnum\thepos>200%
+ \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-200)/100}%
+ \xdef\tikzumlMidTwoArc{\tikzumlMidTwoArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity}%
+ }%
+ \else%
+ \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-100)/100}%
+ \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity}%
+ }%
+ \fi%
+ \fi%
+ \fi%
+ %
+ \ifthenelse{\theposT=300\OR\theposT=100}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{bottom}}{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{bottom}}{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{top}}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{left}}{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{left}}{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }%
+ }%
+ }%
+ }%
+ }{}%
+ \ifthenelse{\theposT=200}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{bottom}}{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicity{below right}%
+ }{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{bottom}}{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{top}}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{left}}{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{left}}{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }%
+ }%
+ }%
+ }%
+ }{}%
+ %
+ \ifnum\theposT>300%
+ \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-300)/100}%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT}%
+ }%
+ \else%
+ \ifnum\theposT<100%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT}%
+ }%
+ \else%
+ \ifnum\theposT>200%
+ \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-200)/100}%
+ \xdef\tikzumlMidTwoArc{\tikzumlMidTwoArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT}%
+ }%
+ \else%
+ \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-100)/100}%
+ \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT}%
+ }%
+ \fi%
+ \fi%
+ \fi%
+ \else%
+ \ifnum\theposStereo>200%
+ \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-200)/100}%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \else%
+ \ifnum\theposStereo<100%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \else%
+ \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-100)/100}%
+ \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \fi%
+ \fi%
+ %
+ \ifthenelse{\thepos=100}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}}{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{top}}{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }%
+ }{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }%
+ }%
+ }%
+ }%
+ }{}%
+ %
+ \ifthenelse{\thepos=200}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}}{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{top}}{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }%
+ }{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }%
+ }%
+ }%
+ }%
+ }{}%
+ %
+ \ifnum\thepos>200%
+ \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-200)/100}%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity}%
+ }%
+ \else%
+ \ifnum\thepos<100%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity}%
+ }%
+ \else%
+ \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-100)/100}%
+ \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity}%
+ }%
+ \fi%
+ \fi%
+ %
+ \ifthenelse{\theposT=100}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}}{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{top}}{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }%
+ }{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }%
+ }%
+ }%
+ }%
+ }{}%
+ %
+ \ifthenelse{\theposT=200}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}}{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{top}}{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }%
+ }{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }%
+ }%
+ }%
+ }%
+ }{}%
+ %
+ \ifnum\theposT>200%
+ \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-200)/100}%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT}%
+ }%
+ \else%
+ \ifnum\theposT<100%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT}%
+ }%
+ \else%
+ \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-100)/100}%
+ \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT}%
+ }%
+ \fi%
+ \fi%
+ \fi%
+ %
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{\tikzumlRelationRecursiveDirectionEnd}}{%
+ \xdef\tikzumlPath{(\tikzumlSrcClassNodeName.\tikzumlRelationStartAngle) -- \tikzumlFirstArc (\tikzumlRelationName-2.center) -- \tikzumlMidOneArc (\tikzumlRelationName-4.center) -- \tikzumlLastArc (\tikzumlDestClassNodeName.\tikzumlRelationEndAngle) }%
+ \ifnum\thetikzumlStateLevel>0%
+ \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitTmp (\tikzumlRelationName-1) (\tikzumlRelationName-2) (\tikzumlRelationName-3) (\tikzumlRelationName-4) (\tikzumlRelationName-5)}%
+ \fi%
+ }{%
+ \xdef\tikzumlPath{(\tikzumlSrcClassNodeName.\tikzumlRelationStartAngle) -- \tikzumlFirstArc (\tikzumlRelationName-2.center) -- \tikzumlMidOneArc (\tikzumlRelationName-4.center) -- \tikzumlMidTwoArc (\tikzumlRelationName-6.center) -- \tikzumlLastArc (\tikzumlDestClassNodeName.\tikzumlRelationEndAngle) }%
+ \ifnum\thetikzumlStateLevel>0%
+ \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitTmp (\tikzumlRelationName-1) (\tikzumlRelationName-2) (\tikzumlRelationName-3) (\tikzumlRelationName-4) (\tikzumlRelationName-5) (\tikzumlRelationName-6) (\tikzumlRelationName-7)}%
+ \fi%
+ }%
+ }{}%
+ }%
+ }{%
+ \def\arcNum{1}%
+ \def\arcNumT{1}%
+ %
+ \node[inner sep=0] (\tikzumlRelationName-1) at (\tikzumlRelationName-middle) {};%
+ \xdef\tikzumlLastArc{node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity}%
+ node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT}%
+ node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \xdef\tikzumlPath{(\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor) -- \tikzumlLastArc (\tikzumlDestClassNodeName\tikzumlRelationDestAnchor) }%
+ \ifnum\thetikzumlStateLevel>0%
+ \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitTmp (\tikzumlRelationName-1) }%
+ \fi%
+ }%
+ }{%
+ % first vertical then horizontal line
+ \ifthenelse{\equal{\tikzumlRelationGeometry}{|-}}%
+ {%
+ %\setcounter{tikzumlControlNodesNum}{1}%
+ %
+ \def\tikzumlFirstArc{node[midway, inner sep=0, name=\tikzumlRelationName-1, anchor=center] {} }%
+ \def\tikzumlLastArc{node[midway, inner sep=0, name=\tikzumlRelationName-3, anchor=center]{} }%
+ %
+ \begin{pgfonlayer}{connections}%
+ \node[inner sep=0] (\tikzumlRelationName-2) at (\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor |- \tikzumlDestClassNodeName\tikzumlRelationDestAnchor) {};%
+ \end{pgfonlayer}%
+ %
+ \ifnum\theposStereo>100%
+ \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-100)/100}%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \else%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \fi%
+ %
+ \ifnum\thepos>100%
+ \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-100)/100}%
+ \def\arcNum{2}%
+ \else%
+ \def\arcNum{1}%
+ \ifnum\thepos=100%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ \fi%
+ \fi%
+ %
+ \ifnum\arcNum=1%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }%
+ \fi%
+ \ifnum\arcNum=2%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }%
+ \fi%
+ %
+ \ifnum\theposT>100%
+ \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-100)/100}%
+ \def\arcNumT{2}%
+ \else%
+ \def\arcNumT{1}%
+ \ifnum\theposT=100%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ \fi%
+ \fi%
+ %
+ \ifnum\arcNumT=1%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }%
+ \fi%
+ \ifnum\arcNumT=2%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }%
+ \fi%
+ %
+ \xdef\tikzumlPath{(\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor) -- \tikzumlFirstArc (\tikzumlRelationName-2.base) -- \tikzumlLastArc (\tikzumlDestClassNodeName\tikzumlRelationDestAnchor) }%
+ \ifnum\thetikzumlStateLevel>0%
+ \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitTmp (\tikzumlRelationName-1) (\tikzumlRelationName-2) (\tikzumlRelationName-3) }%
+ \fi%
+ }{%
+ % first horizontal then vertical line
+ \ifthenelse{\equal{\tikzumlRelationGeometry}{-|}}%
+ {%
+ %\setcounter{tikzumlControlNodesNum}{1}%
+ %
+ \def\tikzumlFirstArc{node[midway, inner sep=0, name=\tikzumlRelationName-1, anchor=center]{} }%
+ \def\tikzumlLastArc{node[midway, inner sep=0, name=\tikzumlRelationName-3, anchor=center] {} }%
+ %
+ \begin{pgfonlayer}{connections}%
+ \node[inner sep=0] (\tikzumlRelationName-2) at (\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor -| \tikzumlDestClassNodeName\tikzumlRelationDestAnchor) {};%
+ \end{pgfonlayer}%
+ %
+ \ifnum\theposStereo>100%
+ \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-100)/100}%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \else%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \fi%
+ %
+ \ifnum\thepos>100%
+ \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-100)/100}%
+ \def\arcNum{2}%
+ \else%
+ \def\arcNum{1}%
+ \ifnum\thepos=100%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ \fi%
+ \fi%
+ %
+ \ifnum\arcNum=1%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }%
+ \fi%
+ \ifnum\arcNum=2%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }%
+ \fi%
+ %
+ \ifnum\theposT>100%
+ \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-100)/100}%
+ \def\arcNumT{2}%
+ \else%
+ \def\arcNumT{1}%
+ \ifnum\theposT=100%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ \fi%
+ \fi%
+ %
+ \ifnum\arcNumT=1%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }%
+ \fi%
+ \ifnum\arcNumT=2%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }%
+ \fi%
+ %
+ \xdef\tikzumlPath{(\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor) -- \tikzumlFirstArc (\tikzumlRelationName-2.base) -- \tikzumlLastArc (\tikzumlDestClassNodeName\tikzumlRelationDestAnchor) }%
+ \ifnum\thetikzumlStateLevel>0%
+ \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitTmp (\tikzumlRelationName-1) (\tikzumlRelationName-2) (\tikzumlRelationName-3) }%
+ \fi%
+ }{%
+ % first vertical, then horizontal, finally vertical line
+ \ifthenelse{\equal{\tikzumlRelationGeometry}{|-|}}%
+ {%
+ %\setcounter{tikzumlControlNodesNum}{2}%
+ %
+ \def\tikzumlFirstArc{node[midway, inner sep=0, name=\tikzumlRelationName-1, anchor=center] {} }%
+ \def\tikzumlLastArc{node[midway, inner sep=0, name=\tikzumlRelationName-5, anchor=center] {} }%
+ \def\tikzumlMidOneArc{ }%
+ %
+ \begin{pgfonlayer}{connections}%
+ %
+ \ifthenelse{\equal{\tikzumlRelationArmO}{auto}}{%
+ \ifthenelse{\equal{\tikzumlRelationArmT}{auto}}{%
+ \node[inner sep=0] (\tikzumlRelationName-3) at (\tikzumlRelationName-middle) {};%
+ \node[inner sep=0] (\tikzumlRelationName-2) at (\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor |- \tikzumlRelationName-3) {};%
+ \node[inner sep=0] (\tikzumlRelationName-4) at (\tikzumlRelationName-3 -| \tikzumlDestClassNodeName\tikzumlRelationDestAnchor) {};%
+ }{%
+ \draw (\tikzumlDestClassNodeName\tikzumlRelationDestAnchor)+(0,\tikzumlRelationArmT) node[inner sep=0, name=\tikzumlRelationName-4] {};%
+ \node[inner sep=0] (\tikzumlRelationName-2) at (\tikzumlRelationName-4 -| \tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor) {};%
+ \node[inner sep=0] (\tikzumlRelationName-3) at (barycentric cs:\tikzumlRelationName-2=0.5,\tikzumlRelationName-4=0.5) {};%
+ }%
+ }{%
+ \draw (\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor)+(0,\tikzumlRelationArmO) node[inner sep=0, name=\tikzumlRelationName-2] {};%
+ \node[inner sep=0] (\tikzumlRelationName-4) at (\tikzumlRelationName-2 -| \tikzumlDestClassNodeName\tikzumlRelationDestAnchor) {};%
+ \node[inner sep=0] (\tikzumlRelationName-3) at (barycentric cs:\tikzumlRelationName-2=0.5,\tikzumlRelationName-4=0.5) {};%
+ }%
+ \end{pgfonlayer}%
+ %
+ \ifnum\theposStereo>200%
+ \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-200)/100}%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \else%
+ \ifnum\theposStereo<100%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \else%
+ \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-100)/100}%
+ \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \fi%
+ \fi%
+ %
+ \ifthenelse{\thepos=200\OR\thepos=100}{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }{}%
+ %
+ \ifthenelse{\thepos>200}{%
+ \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-200)/100}%
+ \def\arcNum{3}%
+ }{%
+ \ifthenelse{\thepos<100}{%
+ \def\arcNum{1}%
+ }{%
+ \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-100)/100}%
+ \def\arcNum{2}%
+ }%
+ }%
+ %
+ \ifnum\arcNum=1%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }%
+ \fi%
+ \ifnum\arcNum=2%
+ \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }%
+ \fi%
+ \ifnum\arcNum=3%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }%
+ \fi%
+ %
+ \ifthenelse{\theposT=200\OR\theposT=100}{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }{}%
+ %
+ \ifthenelse{\theposT>200}{%
+ \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-200)/100}%
+ \def\arcNumT{3}%
+ }{%
+ \ifthenelse{\theposT<100}{%
+ \def\arcNumT{1}%
+ }{%
+ \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-100)/100}%
+ \def\arcNumT{2}%
+ }%
+ }%
+ %
+ \ifnum\arcNumT=1%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }%
+ \fi%
+ \ifnum\arcNumT=2%
+ \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }%
+ \fi%
+ \ifnum\arcNumT=3%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }%
+ \fi%
+ %
+ \xdef\tikzumlPath{(\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor) -- \tikzumlFirstArc (\tikzumlRelationName-2.base) -- \tikzumlMidOneArc (\tikzumlRelationName-4.base) -- \tikzumlLastArc (\tikzumlDestClassNodeName\tikzumlRelationDestAnchor) }%
+ \ifnum\thetikzumlStateLevel>0%
+ \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitTmp (\tikzumlRelationName-1) (\tikzumlRelationName-2) (\tikzumlRelationName-3) (\tikzumlRelationName-4) (\tikzumlRelationName-5) }%
+ \fi%
+ }{%
+ % first horizontal, then vertical, finally horizontal line
+ \ifthenelse{\equal{\tikzumlRelationGeometry}{-|-}}%
+ {%
+ %\setcounter{tikzumlControlNodesNum}{2}%
+ %
+ \def\tikzumlFirstArc{node[midway, inner sep=0, name=\tikzumlRelationName-1, anchor=center] {} }%
+ \def\tikzumlLastArc{node[midway, inner sep=0, name=\tikzumlRelationName-5, anchor=center] {} }%
+ \def\tikzumlMidOneArc{}%
+ %
+ \begin{pgfonlayer}{connections}%
+ %
+ \ifthenelse{\equal{\tikzumlRelationArmO}{auto}}{%
+ \ifthenelse{\equal{\tikzumlRelationArmT}{auto}}{%
+ \node[inner sep=0] (\tikzumlRelationName-3) at (\tikzumlRelationName-middle) {};%
+ \node[inner sep=0] (\tikzumlRelationName-2) at (\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor -| \tikzumlRelationName-3) {};%
+ \node[inner sep=0] (\tikzumlRelationName-4) at (\tikzumlRelationName-3 |- \tikzumlDestClassNodeName\tikzumlRelationDestAnchor) {};%
+ }{%
+ \draw (\tikzumlDestClassNodeName\tikzumlRelationDestAnchor)+(\tikzumlRelationArmT,0) node[inner sep=0, name=\tikzumlRelationName-4] {};%
+ \node[inner sep=0] (\tikzumlRelationName-2) at (\tikzumlRelationName-4 |- \tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor) {};%
+ \node[inner sep=0] (\tikzumlRelationName-3) at (barycentric cs:\tikzumlRelationName-2=0.5,\tikzumlRelationName-4=0.5) {};%
+ }%
+ }{%
+ \draw (\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor)+(\tikzumlRelationArmO,0) node[inner sep=0, name=\tikzumlRelationName-2] {};%
+ \node[inner sep=0] (\tikzumlRelationName-4) at (\tikzumlRelationName-2 |- \tikzumlDestClassNodeName\tikzumlRelationDestAnchor) {};%
+ \node[inner sep=0] (\tikzumlRelationName-3) at (barycentric cs:\tikzumlRelationName-2=0.5,\tikzumlRelationName-4=0.5) {};%
+ }%
+ \end{pgfonlayer}%
+ %
+ \ifnum\theposStereo>200%
+ \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-200)/100}%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \else%
+ \ifnum\theposStereo<100%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \else%
+ \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-100)/100}%
+ \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \fi%
+ \fi%
+ %
+ \ifthenelse{\thepos=200\OR\thepos=100}{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }{}%
+ %
+ \ifthenelse{\thepos>200}{%
+ \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-200)/100}%
+ \def\arcNum{3}%
+ }{%
+ \ifthenelse{\thepos<100}{%
+ \def\arcNum{1}%
+ }{%
+ \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-100)/100}%
+ \def\arcNum{2}%
+ }%
+ }%
+ %
+ \ifnum\arcNum=1%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }%
+ \fi%
+ \ifnum\arcNum=2%
+ \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }%
+ \fi%
+ \ifnum\arcNum=3%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }%
+ \fi%
+ %
+ \ifthenelse{\theposT=200\OR\theposT=100}{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }{}%
+ %
+ \ifthenelse{\theposT>200}{%
+ \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-200)/100}%
+ \def\arcNumT{3}%
+ }{%
+ \ifthenelse{\theposT<100}{%
+ \def\arcNumT{1}%
+ }{%
+ \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-100)/100}%
+ \def\arcNumT{2}%
+ }%
+ }%
+ %
+ \ifnum\arcNumT=1%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }%
+ \fi%
+ \ifnum\arcNumT=2%
+ \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }%
+ \fi%
+ \ifnum\arcNumT=3%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }%
+ \fi%
+ %
+ \xdef\tikzumlPath{(\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor) -- \tikzumlFirstArc (\tikzumlRelationName-2.base) -- \tikzumlMidOneArc (\tikzumlRelationName-4.base) -- \tikzumlLastArc (\tikzumlDestClassNodeName\tikzumlRelationDestAnchor) }%
+ \ifnum\thetikzumlStateLevel>0%
+ \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitTmp (\tikzumlRelationName-1) (\tikzumlRelationName-2) (\tikzumlRelationName-3) (\tikzumlRelationName-4) (\tikzumlRelationName-5) }%
+ \fi%
+ }{%
+ \errmessage{TIKZUML ERROR : Unknown geometry value !!! It should be in the following list : --, |-, -|, |-|, -|-}%
+ }%
+ }%
+ }%
+ }%
+ }%
+ %
+ \begin{pgfonlayer}{connections}%
+ \ifthenelse{\equal{\tikzumlRelationStyle}{tikzuml nesting style}}{%
+ \pgfarrowsdeclare{nested}{nested}{...}
+ {
+ \tikzumlNestingSymbolSize=0.2pt%
+ \advance\tikzumlNestingSymbolSize by .5\pgflinewidth%
+ \pgfsetdash{}{0pt} % do not dash
+ \pgfsetroundjoin % fix join
+ \pgfsetroundcap % fix cap
+ \pgfpathmoveto{\pgfpoint{-16*\tikzumlNestingSymbolSize}{0pt}}%
+ \pgfpatharc{180}{90}{8*\tikzumlNestingSymbolSize}%
+ \pgfpatharc{90}{0}{8*\tikzumlNestingSymbolSize}%
+ \pgfpatharc{0}{-90}{8*\tikzumlNestingSymbolSize}%
+ \pgfpatharc{-90}{-180}{8*\tikzumlNestingSymbolSize}%
+ \pgfpathmoveto{\pgfpoint{-8*\tikzumlNestingSymbolSize}{8*\tikzumlNestingSymbolSize}}%
+ \pgfpathlineto{\pgfpoint{-8*\tikzumlNestingSymbolSize}{-8*\tikzumlNestingSymbolSize}}%
+ \pgfusepathqstroke%
+ }%
+ \draw[auto, nested-, font=\tikzumlDefaultFont, \tikzumlRelationStyle, /tikzuml/relation/style2] \tikzumlPath ;%
+ }{
+ \draw[auto, font=\tikzumlDefaultFont, \tikzumlRelationStyle, /tikzuml/relation/style2] \tikzumlPath ;%
+ }
+ \end{pgfonlayer}%
+ %
+ \stepcounter{tikzumlRelationNum}%
+}%
+%
+% shortcuts of \umlrelation
+\newcommand{\umlHVrelation}[3][]{%
+ \pgfkeys{/tikzuml/HVrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlHVrelation, forbidden option geometry}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/HVrelation/.cd, #1}%
+ \umlrelation[geometry=-|, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlVHrelation}[3][]{%
+ \pgfkeys{/tikzuml/VHrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlVHrelation, forbidden option geometry}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/VHrelation/.cd, #1}%
+ \umlrelation[geometry=|-, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlHVHrelation}[3][]{%
+ \pgfkeys{/tikzuml/HVHrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlHVHrelation, forbidden option geometry}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/HVHrelation/.cd, #1}%
+ \umlrelation[geometry=-|-, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlVHVrelation}[3][]{%
+ \pgfkeys{/tikzuml/VHVrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlVHVrelation, forbidden option geometry}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/VHVrelation/.cd, #1}%
+ \umlrelation[geometry=|-|, #1]{#2}{#3}%
+}%
+%
+%
+% shortcuts for relations
+\newcommand{\umlinherit}[3][]{\umlrelation[style={tikzuml inherit style}, #1]{#2}{#3}}%
+\newcommand{\umlimpl}[3][]{\umlrelation[style={tikzuml implements style}, #1]{#2}{#3}}%
+\newcommand{\umlreal}[3][]{\umlrelation[style={tikzuml implements style}, #1]{#2}{#3}}%
+\newcommand{\umlassoc}[3][]{\umlrelation[style={tikzuml association style}, #1]{#2}{#3}}%
+\newcommand{\umlbiassoc}[3][]{\umlrelation[style={tikzuml bidirectional association style}, #1]{#2}{#3}}%
+\newcommand{\umluniassoc}[3][]{\umlrelation[style={tikzuml unidirectional association style}, #1]{#2}{#3}}%
+\newcommand{\umlaggreg}[3][]{\umlrelation[style={tikzuml aggregation style}, #1]{#2}{#3}}%
+\newcommand{\umluniaggreg}[3][]{\umlrelation[style={tikzuml unidirectional aggregation style}, #1]{#2}{#3}}%
+\newcommand{\umlcompo}[3][]{\umlrelation[style={tikzuml composition style}, #1]{#2}{#3}}%
+\newcommand{\umlunicompo}[3][]{\umlrelation[style={tikzuml unidirectional composition style}, #1]{#2}{#3}}%
+\newcommand{\umlimport}[3][]{\umlrelation[style={tikzuml import style}, #1]{#2}{#3}}%
+\newcommand{\umlnest}[3][]{\umlrelation[style={tikzuml nesting style}, #1]{#2}{#3}}%
+\newcommand{\umldep}[3][]{\umlrelation[style={tikzuml dependency style}, #1]{#2}{#3}}%
+\newcommand{\umlfriend}[3][]{%
+ \pgfkeys{/tikzuml/friendrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlfriend, forbidden option stereo}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/friendrelation/.cd, #1}%
+ \umlrelation[stereo=friend, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlHVinherit}[3][]{\umlHVrelation[style={tikzuml inherit style}, #1]{#2}{#3}}%
+\newcommand{\umlHVimpl}[3][]{\umlHVrelation[style={tikzuml implements style}, #1]{#2}{#3}}%
+\newcommand{\umlHVreal}[3][]{\umlHVrelation[style={tikzuml implements style}, #1]{#2}{#3}}%
+\newcommand{\umlHVassoc}[3][]{\umlHVrelation[style={tikzuml association style}, #1]{#2}{#3}}%
+\newcommand{\umlHVuniassoc}[3][]{\umlHVrelation[style={tikzuml unidirectional association style}, #1]{#2}{#3}}%
+\newcommand{\umlHVaggreg}[3][]{\umlHVrelation[style={tikzuml aggregation style}, #1]{#2}{#3}}%
+\newcommand{\umlHVuniaggreg}[3][]{\umlHVrelation[style={tikzuml unidirectional aggregation style}, #1]{#2}{#3}}%
+\newcommand{\umlHVcompo}[3][]{\umlHVrelation[style={tikzuml composition style}, #1]{#2}{#3}}%
+\newcommand{\umlHVunicompo}[3][]{\umlHVrelation[style={tikzuml unidirectional composition style}, #1]{#2}{#3}}%
+\newcommand{\umlHVimport}[3][]{\umlHVrelation[style={tikzuml import style}, #1]{#2}{#3}}%
+\newcommand{\umlHVnest}[3][]{\umlHVrelation[style={tikzuml nesting style}, #1]{#2}{#3}}%
+\newcommand{\umlHVdep}[3][]{\umlHVrelation[style={tikzuml dependency style}, #1]{#2}{#3}}%
+\newcommand{\umlHVfriend}[3][]{%
+ \pgfkeys{/tikzuml/friendrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlHVfriend, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlHVfriend, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/friendrelation/.cd, #1}%
+ \umlrelation[geometry=-|, stereo=friend, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlVHinherit}[3][]{\umlVHrelation[style={tikzuml inherit style}, #1]{#2}{#3}}%
+\newcommand{\umlVHimpl}[3][]{\umlVHrelation[style={tikzuml implements style}, #1]{#2}{#3}}%
+\newcommand{\umlVHreal}[3][]{\umlVHrelation[style={tikzuml implements style}, #1]{#2}{#3}}%
+\newcommand{\umlVHassoc}[3][]{\umlVHrelation[style={tikzuml association style}, #1]{#2}{#3}}%
+\newcommand{\umlVHuniassoc}[3][]{\umlVHrelation[style={tikzuml unidirectional association style}, #1]{#2}{#3}}%
+\newcommand{\umlVHaggreg}[3][]{\umlVHrelation[style={tikzuml aggregation style}, #1]{#2}{#3}}%
+\newcommand{\umlVHuniaggreg}[3][]{\umlVHrelation[style={tikzuml unidirectional aggregation style}, #1]{#2}{#3}}%
+\newcommand{\umlVHcompo}[3][]{\umlVHrelation[style={tikzuml composition style}, #1]{#2}{#3}}%
+\newcommand{\umlVHunicompo}[3][]{\umlVHrelation[style={tikzuml unidirectional composition style}, #1]{#2}{#3}}%
+\newcommand{\umlVHimport}[3][]{\umlVHrelation[style={tikzuml import style}, #1]{#2}{#3}}%
+\newcommand{\umlVHnest}[3][]{\umlVHrelation[style={tikzuml nesting style}, #1]{#2}{#3}}%
+\newcommand{\umlVHdep}[3][]{\umlVHrelation[style={tikzuml dependency style}, #1]{#2}{#3}}%
+\newcommand{\umlVHfriend}[3][]{%
+ \pgfkeys{/tikzuml/friendrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlVHfriend, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlVHfriend, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/friendrelation/.cd, #1}%
+ \umlrelation[geometry=|-, stereo=friend, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlHVHinherit}[3][]{\umlHVHrelation[style={tikzuml inherit style}, #1]{#2}{#3}}%
+\newcommand{\umlHVHimpl}[3][]{\umlHVHrelation[style={tikzuml implements style}, #1]{#2}{#3}}%
+\newcommand{\umlHVHreal}[3][]{\umlHVHrelation[style={tikzuml implements style}, #1]{#2}{#3}}%
+\newcommand{\umlHVHassoc}[3][]{\umlHVHrelation[style={tikzuml association style}, #1]{#2}{#3}}%
+\newcommand{\umlHVHuniassoc}[3][]{\umlHVHrelation[style={tikzuml unidirectional association style}, #1]{#2}{#3}}%
+\newcommand{\umlHVHaggreg}[3][]{\umlHVHrelation[style={tikzuml aggregation style}, #1]{#2}{#3}}%
+\newcommand{\umlHVHuniaggreg}[3][]{\umlHVHrelation[style={tikzuml unidirectional aggregation style}, #1]{#2}{#3}}%
+\newcommand{\umlHVHcompo}[3][]{\umlHVHrelation[style={tikzuml composition style}, #1]{#2}{#3}}%
+\newcommand{\umlHVHunicompo}[3][]{\umlHVHrelation[style={tikzuml unidirectional composition style}, #1]{#2}{#3}}%
+\newcommand{\umlHVHimport}[3][]{\umlHVHrelation[style={tikzuml import style}, #1]{#2}{#3}}%
+\newcommand{\umlHVHnest}[3][]{\umlHVHrelation[style={tikzuml nesting style}, #1]{#2}{#3}}%
+\newcommand{\umlHVHdep}[3][]{\umlHVHrelation[style={tikzuml dependency style}, #1]{#2}{#3}}%
+\newcommand{\umlHVHfriend}[3][]{%
+ \pgfkeys{/tikzuml/friendrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlHVHfriend, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlHVHfriend, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/friendrelation/.cd, #1}%
+ \umlrelation[geometry=-|-, stereo=friend, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlVHVinherit}[3][]{\umlVHVrelation[style={tikzuml inherit style}, #1]{#2}{#3}}%
+\newcommand{\umlVHVimpl}[3][]{\umlVHVrelation[style={tikzuml implements style}, #1]{#2}{#3}}%
+\newcommand{\umlVHVreal}[3][]{\umlVHVrelation[style={tikzuml implements style}, #1]{#2}{#3}}%
+\newcommand{\umlVHVassoc}[3][]{\umlVHVrelation[style={tikzuml association style}, #1]{#2}{#3}}%
+\newcommand{\umlVHVuniassoc}[3][]{\umlVHVrelation[style={tikzuml unidirectional association style}, #1]{#2}{#3}}%
+\newcommand{\umlVHVaggreg}[3][]{\umlVHVrelation[style={tikzuml aggregation style}, #1]{#2}{#3}}%
+\newcommand{\umlVHVuniaggreg}[3][]{\umlVHVrelation[style={tikzuml unidirectional aggregation style}, #1]{#2}{#3}}%
+\newcommand{\umlVHVcompo}[3][]{\umlVHVrelation[style={tikzuml composition style}, #1]{#2}{#3}}%
+\newcommand{\umlVHVunicompo}[3][]{\umlVHVrelation[style={tikzuml unidirectional composition style}, #1]{#2}{#3}}%
+\newcommand{\umlVHVimport}[3][]{\umlVHVrelation[style={tikzuml import style}, #1]{#2}{#3}}%
+\newcommand{\umlVHVnest}[3][]{\umlVHVrelation[style={tikzuml nesting style}, #1]{#2}{#3}}%
+\newcommand{\umlVHVdep}[3][]{\umlVHVrelation[style={tikzuml dependency style}, #1]{#2}{#3}}%
+\newcommand{\umlVHVfriend}[3][]{%
+ \pgfkeys{/tikzuml/friendrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlVHVfriend, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlVHVfriend, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/friendrelation/.cd, #1}%
+ \umlrelation[geometry=|-|, stereo=friend, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+%
+% define a node
+\newcommand{\umlnode}[2]{%
+ \node (#2) at (#1) {};%
+}%
+%
+% main command to define a relation between two classes through a control node
+% args : src class
+% control node
+% dest class
+% optional : arg1, arg2, arg: name of the src/dest/dest side class type attribute defined by the relation
+% mult1, mult2, mult: multiplicity of the src/dest/dest side class type attribute defined by the relation
+% pos1, pos2, pos: position of the src/dest/dest side class type attribute defined by the relation
+% align1, align2, align: text justification of the src/dest/dest side class type attribute defined by the relation
+% anchor1, anchor2: src/dest anchors on linked classes
+% stereo: stereotype of the relation
+% pos stereo: position of the stereotype on the relation
+% style: style of the relation (association, aggregation, composition, inherit, ...)
+% name: rootname used for naming nodes of the relation
+\newcommand{\umlCNrelation}[4][]{%
+ \pgfkeys{/tikzuml/relation/.cd, arg1/.initial={}, arg2/.initial={}, arg/.initial={},%
+ mult1/.initial={}, mult2/.initial={}, mult/.initial={},%
+ pos1/.initial=0.2, pos2/.initial=0.8, pos/.initial=tikzumlEmpty,%
+ align1/.initial={}, align2/.initial={}, align/.initial={},%
+ anchor1/.initial=tikzumlEmpty, anchor2/.initial=tikzumlEmpty,%
+ stereo/.initial={}, pos stereo/.initial=1,%
+ style/.initial=->, name/.initial=relation-\thetikzumlRelationNum,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \errmessage{TIKZUML ERROR : in umlCNrelation, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/relation/.cd,#1}%
+ \pgfkeys{/tikzuml/relation/.cd, arg1/.get=\tikzumlCNRelationAttrName, arg2/.get=\tikzumlCNRelationAttrNameTO, arg/.get=\tikzumlCNRelationAttrNameTT,%
+ mult1/.get=\tikzumlCNRelationMultiplicity, mult2/.get=\tikzumlCNRelationMultiplicityTO, mult/.get=\tikzumlCNRelationMultiplicityTT,%
+ pos1/.get=\tikzumlCNRelationPosition, pos2/.get=\tikzumlCNRelationPositionTO, pos/.get=\tikzumlCNRelationPositionTT,%
+ align1/.get=\tikzumlCNRelationAlign, align2/.get=\tikzumlCNRelationAlignTO, align/.get=\tikzumlCNRelationAlignTT,%
+ anchor1/.get=\tikzumlCNRelationSrcAnchor, anchor2/.get=\tikzumlCNRelationDestAnchor,%
+ stereo/.get=\tikzumlCNRelationStereoType, pos stereo/.get=\tikzumlCNRelationPositionStereotype,%
+ style/.get=\tikzumlCNRelationStyle, name/.get=\tikzumlCNRelationName%
+ }%
+ %
+ % managing \_ in class names for node names
+ \def\tikzumlSrcClassName{#2}%
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlSrcClassNodeName{\tikzumlSrcClassName}}\x%
+ %
+ \StrSubstitute{\tikzumlSrcClassNodeName}{:}{@COLON@}[\tikzumlSrcClassNodeName]%
+ \StrSubstitute{\tikzumlSrcClassNodeName}{\_}{@UNDERSCORE@}[\tikzumlSrcClassNodeName]%
+ %
+ \def\tikzumlDestClassName{#4}%
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlDestClassNodeName{\tikzumlDestClassName}}\x%
+ %
+ \StrSubstitute{\tikzumlDestClassNodeName}{:}{@COLON@}[\tikzumlDestClassNodeName]%
+ \StrSubstitute{\tikzumlDestClassNodeName}{\_}{@UNDERSCORE@}[\tikzumlDestClassNodeName]%
+ %
+ % managing alias keys
+ \def\tikzumlCNRelationAttrNameT{\tikzumlCNRelationAttrNameTO\tikzumlCNRelationAttrNameTT}%
+ \def\tikzumlCNRelationMultiplicityT{\tikzumlCNRelationMultiplicityTO\tikzumlCNRelationMultiplicityTT}%
+ \def\tikzumlCNRelationAlignT{\tikzumlCNRelationAlignTO\tikzumlCNRelationAlignTT}%
+ \def\orientationT{\orientationTO\orientationTT}%
+ %
+ \ifthenelse{\equal{\tikzumlCNRelationPositionTT}{tikzumlEmpty}}{%
+ \def\tikzumlCNRelationPositionT{\tikzumlCNRelationPositionTO}%
+ }{%
+ \def\tikzumlCNRelationPositionT{\tikzumlCNRelationPositionTT}%
+ }%
+ %
+ \def\attrAlign{}%
+ \def\multAlign{}%
+ \def\attrAlignT{}%
+ \def\multAlignT{}%
+ %
+ \ifthenelse{\equal{\tikzumlCNRelationAlign}{left}}{%
+ \def\attrAlign{above right}%
+ \def\multAlign{below right}%
+ }{%
+ \ifthenelse{\equal{\tikzumlCNRelationAlign}{right}}{%
+ \def\attrAlign{above left}%
+ \def\multAlign{below left}%
+ }{}%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlCNRelationAlignT}{left}}{%
+ \def\attrAlignT{above right}%
+ \def\multAlignT{below right}%
+ }{%
+ \ifthenelse{\equal{\tikzumlCNRelationAlignT}{right}}{%
+ \def\attrAlignT{above left}%
+ \def\multAlignT{below left}%
+ }{}%
+ }%
+ %
+ % def stereotype
+ \ifthenelse{\equal{\tikzumlCNRelationStereoType}{}}{%
+ \def\stereotype{}%
+ }{%
+ \def\stereotype{$\ll$\tikzumlCNRelationStereoType$\gg$}%
+ }%
+ %
+ % def anchors macros
+ \ifthenelse{\equal{\tikzumlCNRelationSrcAnchor}{tikzumlEmpty}}{%
+ \def\tikzumlCNRelationSrcAnchor{}%
+ }{%
+ \let\tikzumlCNRelationSrcAnchorold\tikzumlCNRelationSrcAnchor%
+ \def\tikzumlCNRelationSrcAnchor{.\tikzumlCNRelationSrcAnchorold}%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlCNRelationDestAnchor}{tikzumlEmpty}}{%
+ \def\tikzumlCNRelationDestAnchor{}%
+ }{%
+ \let\tikzumlCNRelationDestAnchorold\tikzumlCNRelationDestAnchor%
+ \def\tikzumlCNRelationDestAnchor{.\tikzumlCNRelationDestAnchorold}%
+ }%
+ %
+ \setcounter{pos}{100*\real{\tikzumlCNRelationPosition}}%
+ \setcounter{posT}{100*\real{\tikzumlCNRelationPositionT}}%
+ \setcounter{posStereo}{100*\real{\tikzumlCNRelationPositionStereotype}}%
+ %
+ % straight line
+ %\setcounter{tikzumlControlNodesNum}{1}%
+ %
+ \def\tikzumlFirstArc{node[midway, name=\tikzumlCNRelationName-1, anchor=center] {} }%
+ \def\tikzumlLastArc{node[midway, name=\tikzumlCNRelationName-3, anchor=center]{} }%
+ \def\posAttrName{}%
+ \def\posMultiplicity{}%
+ \def\posAttrNameT{}%
+ \def\posMultiplicityT{}%
+ %
+ \begin{pgfonlayer}{connections}%
+ \node (\tikzumlCNRelationName-2) at (#3) {};%
+ \end{pgfonlayer}%
+ %
+ \ifnum\theposStereo>100%
+ \pgfmathsetmacro{\tikzumlCNRelationPositionStereotype}{(\theposStereo-100)/100}%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlCNRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \else%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlCNRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \fi%
+ %
+ \ifnum\thepos>100%
+ \pgfmathsetmacro{\tikzumlCNRelationPosition}{(\thepos-100)/100}%
+ \def\arcNum{2}%
+ \else%
+ \def\arcNum{1}%
+ \ifnum\thepos=100%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ \fi%
+ \fi%
+ %
+ \ifnum\arcNum=1%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlCNRelationPosition, \posAttrName, \attrAlign] {\tikzumlCNRelationAttrName}%
+ node[pos=\tikzumlCNRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlCNRelationMultiplicity} }%
+ \fi%
+ \ifnum\arcNum=2%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlCNRelationPosition, \posAttrName, \attrAlign] {\tikzumlCNRelationAttrName}%
+ node[pos=\tikzumlCNRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlCNRelationMultiplicity} }%
+ \fi%
+ %
+ \ifnum\theposT>100%
+ \pgfmathsetmacro{\tikzumlCNRelationPositionT}{(\theposT-100)/100}%
+ \def\arcNumT{2}%
+ \else%
+ \def\arcNumT{1}%
+ \ifnum\theposT=100%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ \fi%
+ \fi%
+ %
+ \ifnum\arcNumT=1%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlCNRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlCNRelationAttrNameT}%
+ node[pos=\tikzumlCNRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlCNRelationMultiplicityT} }%
+ \fi%
+ \ifnum\arcNumT=2%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlCNRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlCNRelationAttrNameT}%
+ node[pos=\tikzumlCNRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlCNRelationMultiplicityT} }%
+ \fi%
+ %
+ \xdef\tikzumlPath{(\tikzumlSrcClassNodeName\tikzumlCNRelationSrcAnchor) -- \tikzumlFirstArc (\tikzumlCNRelationName-2.base) -- \tikzumlLastArc (\tikzumlDestClassNodeName\tikzumlCNRelationDestAnchor) }%
+
+ \begin{pgfonlayer}{connections}%
+ \ifthenelse{\equal{\tikzumlCNRelationStyle}{tikzuml nesting style}}{%
+ \pgfarrowsdeclare{nested}{nested}{...}
+ {
+ \tikzumlNestingSymbolSize=0.2pt%
+ \advance\tikzumlNestingSymbolSize by .5\pgflinewidth%
+ \pgfsetdash{}{0pt} % do not dash
+ \pgfsetroundjoin % fix join
+ \pgfsetroundcap % fix cap
+ \pgfpathmoveto{\pgfpoint{-16*\tikzumlNestingSymbolSize}{0pt}}%
+ \pgfpatharc{180}{90}{8*\tikzumlNestingSymbolSize}%
+ \pgfpatharc{90}{0}{8*\tikzumlNestingSymbolSize}%
+ \pgfpatharc{0}{-90}{8*\tikzumlNestingSymbolSize}%
+ \pgfpatharc{-90}{-180}{8*\tikzumlNestingSymbolSize}%
+ \pgfpathmoveto{\pgfpoint{-8*\tikzumlNestingSymbolSize}{8*\tikzumlNestingSymbolSize}}%
+ \pgfpathlineto{\pgfpoint{-8*\tikzumlNestingSymbolSize}{-8*\tikzumlNestingSymbolSize}}%
+ \pgfusepathqstroke%
+ }%
+ \draw[auto, \tikzumlCNRelationStyle, nested-, font=\tikzumlDefaultFont] \tikzumlPath ;%
+ }{
+ \draw[auto, \tikzumlCNRelationStyle, font=\tikzumlDefaultFont] \tikzumlPath ;%
+ }
+ \end{pgfonlayer}%
+ %
+ \stepcounter{tikzumlRelationNum}%
+}%
+%
+% shortcuts for cnrelations
+\newcommand{\umlCNinherit}[4][]{\umlCNrelation[style={tikzuml inherit style}, #1]{#2}{#3}{#4}}%
+\newcommand{\umlCNimpl}[4][]{\umlCNrelation[style={tikzuml implements style}, #1]{#2}{#3}{#4}}%
+\newcommand{\umlCNreal}[4][]{\umlCNrelation[style={tikzuml implements style}, #1]{#2}{#3}{#4}}%
+\newcommand{\umlCNassoc}[4][]{\umlCNrelation[style={tikzuml association style}, #1]{#2}{#3}{#4}}%
+\newcommand{\umlCNuniassoc}[4][]{\umlCNrelation[style={tikzuml unidirectional association style}, #1]{#2}{#3}{#4}}%
+\newcommand{\umlCNaggreg}[4][]{\umlCNrelation[style={tikzuml aggregation style}, #1]{#2}{#3}{#4}}%
+\newcommand{\umlCNuniaggreg}[4][]{\umlCNrelation[style={tikzuml unidirectional aggregation style}, #1]{#2}{#3}{#4}}%
+\newcommand{\umlCNcompo}[4][]{\umlCNrelation[style={tikzuml composition style}, #1]{#2}{#3}{#4}}%
+\newcommand{\umlCNunicompo}[4][]{\umlCNrelation[style={tikzuml unidirectional composition style}, #1]{#2}{#3}{#4}}%
+\newcommand{\umlCNimport}[4][]{\umlCNrelation[style={tikzuml import style}, #1]{#2}{#3}{#4}}%
+\newcommand{\umlCNnest}[4][]{\umlCNrelation[style={tikzuml nesting style}, #1]{#2}{#3}{#4}}%
+\newcommand{\umlCNdep}[4][]{\umlCNrelation[style={tikzuml dependency style}, #1]{#2}{#3}{#4}}%
+\newcommand{\umlCNfriend}[4][]{%
+ \pgfkeys{/tikzuml/friendrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlCNfriend, forbidden option stereo}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/friendrelation/.cd, #1}%
+ \umlCNrelation[stereo=friend, style={tikzuml dependency style}, #1]{#2}{#3}{#4}%
+}%
+%
+% define a note
+% arg : attached class
+% label of the note
+% optional : x,y: coordinates of the note
+% width: width of the note
+% geometry: geometry of the relation between the note and what it is about
+% weight: barycentric weight for a 3-line relation
+% arm: length of the first arm
+% anchor1, anchor2: anchors of the relation
+% draw, fill, text: colors
+% style: to manage every default TikZ option
+% no coords: to tell that the note position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlnote}[3][]{%
+ \pgfkeys{/tikzuml/note/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlNoteDefaultWidth,%
+ geometry/.initial=\tikzumlRelationDefaultGeometry,%
+ weight/.initial=\tikzumlRelationDefaultWeight, arm/.initial=auto, style/.style={},%
+ anchor1/.initial=tikzumlEmpty, anchor2/.initial=tikzumlEmpty,%
+ draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlNoteDefaultFillColor,%
+ text/.initial=\tikzumlDefaultTextColor,%
+ no coords/.is if=tikzumlnoteWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/note/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/note/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/note/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlnote, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/note/.cd, #1}%
+ \pgfkeys{/tikzuml/note/.cd, x/.get=\tikzumlNoteX, y/.get=\tikzumlNoteY, width/.get=\tikzumlNoteTextWidth,%
+ geometry/.get=\tikzumlNoteGeometry,%
+ weight/.get=\tikzumlNoteWeight, arm/.get=\tikzumlNoteArm,%
+ anchor1/.get=\tikzumlNoteSrcAnchor, anchor2/.get=\tikzumlNoteDestAnchor,%
+ draw/.get=\tikzumlNoteDrawColor, fill/.get=\tikzumlNoteFillColor,%
+ text/.get=\tikzumlNoteTextColor%
+ }%
+ %
+ \def\tikzumlClassName{#2}%
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlClassNodeName{\tikzumlClassName}}\x%
+ %
+ % def anchors macros
+ \ifthenelse{\equal{\tikzumlNoteSrcAnchor}{tikzumlEmpty}}{%
+ \def\tikzumlNoteSrcAnchor{}%
+ }{%
+ \let\tikzumlNoteSrcAnchorold\tikzumlNoteSrcAnchor%
+ \def\tikzumlNoteSrcAnchor{.\tikzumlNoteSrcAnchorold}%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlNoteDestAnchor}{tikzumlEmpty}}{%
+ \def\tikzumlNoteDestAnchor{}%
+ }{%
+ \let\tikzumlNoteDestAnchorold\tikzumlNoteDestAnchor%
+ \def\tikzumlNoteDestAnchor{.\tikzumlNoteDestAnchorold}%
+ }%
+ %
+ \iftikzumlnoteWithoutCoords%
+ \node[text=\tikzumlNoteTextColor, text width=\tikzumlNoteTextWidth, font=\tikzumlDefaultFont, outer sep=0, inner xsep=1ex, inner ysep=3ex, /tikzuml/note/style] (note-\thetikzumlNoteNum-coord) {#3};%
+ \else%
+ \node[text=\tikzumlNoteTextColor, text width=\tikzumlNoteTextWidth, font=\tikzumlDefaultFont, outer sep=0, inner xsep=1ex, inner ysep=3ex, /tikzuml/note/style] (note-\thetikzumlNoteNum-coord) at (\tikzumlNoteX, \tikzumlNoteY) {#3};%
+ \fi%
+ \draw (note-\thetikzumlNoteNum-coord.north east) node[name=note-\thetikzumlNoteNum-right-top, below=2ex, coordinate] {};%
+ \draw (note-\thetikzumlNoteNum-coord.north east) node[name=note-\thetikzumlNoteNum-top-right, left=2ex, coordinate] {};%
+ \draw[draw=\tikzumlNoteDrawColor, fill=\tikzumlNoteFillColor] (note-\thetikzumlNoteNum-coord.south west) -- (note-\thetikzumlNoteNum-coord.south east) -- (note-\thetikzumlNoteNum-right-top.base) -- (note-\thetikzumlNoteNum-top-right.base) -- (note-\thetikzumlNoteNum-coord.north west) -- cycle;%
+ \node[text=\tikzumlNoteTextColor, text width=\tikzumlNoteTextWidth, outer sep=0, inner xsep=1ex, inner ysep=3ex, font=\tikzumlDefaultFont] (note-\thetikzumlNoteNum) at (note-\thetikzumlNoteNum-coord) {#3};%
+ \draw[draw=\tikzumlNoteDrawColor] (note-\thetikzumlNoteNum-right-top) -| (note-\thetikzumlNoteNum-top-right);%
+ %
+ \pgfmathsetmacro{\tikzumlNoteWeightT}{1.0-\tikzumlNoteWeight}%
+ \node (note-\thetikzumlNoteNum-middle) at (barycentric cs:note-\thetikzumlNoteNum-coord=\tikzumlNoteWeight,\tikzumlClassNodeName=\tikzumlNoteWeightT) {};%
+ %
+ \ifthenelse{\equal{\tikzumlNoteGeometry}{--}%
+ \OR\equal{\tikzumlNoteGeometry}{-|}%
+ \OR\equal{\tikzumlNoteGeometry}{|-}}{%
+ \edef\tikzumlnotepath{\tikzumlNoteGeometry}
+ }{%
+ \ifthenelse{\equal{\tikzumlNoteGeometry}{-|-}}{%
+ \ifthenelse{\equal{\tikzumlNoteArm}{auto}}{%
+ \edef\tikzumlnotepath{-- (note-\thetikzumlNoteNum-coord\tikzumlNoteSrcAnchor -| note-\thetikzumlNoteNum-middle.center) -- (note-\thetikzumlNoteNum-middle.center) -- (note-\thetikzumlNoteNum-middle.center |- \tikzumlClassNodeName\tikzumlNoteDestAnchor) --}%
+ }{%
+ \draw (note-\thetikzumlNoteNum-coord\tikzumlNoteSrcAnchor)+(\tikzumlNoteArm,0) node[name=note-\thetikzumlNoteNum-tmp] {};
+ \edef\tikzumlnotepath{-- (note-\thetikzumlNoteNum-tmp.center) |-}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlNoteGeometry}{|-|}}{%
+ \ifthenelse{\equal{\tikzumlNoteArm}{auto}}{%
+ \edef\tikzumlnotepath{-- (note-\thetikzumlNoteNum-coord\tikzumlNoteSrcAnchor |- note-\thetikzumlNoteNum-middle.center) -- (note-\thetikzumlNoteNum-middle.center) -- (note-\thetikzumlNoteNum-middle.center -| \tikzumlClassNodeName\tikzumlNoteDestAnchor) --}%
+ }{%
+ \draw (note-\thetikzumlNoteNum-coord\tikzumlNoteSrcAnchor)+(0,\tikzumlNoteArm) node[name=note-\thetikzumlNoteNum-tmp] {};
+ \edef\tikzumlnotepath{-- (note-\thetikzumlNoteNum-tmp.center) -|}%
+ }%
+
+ }{%
+ \errmessage{TIKZUML ERROR : Unknown geometry value !!! It should be in the following list : --, |-, -|, |-|, -|-}%
+ }%
+ }%
+ }%
+ %
+ \begin{pgfonlayer}{connections}%
+ \draw[dashed] (note-\thetikzumlNoteNum-coord\tikzumlNoteSrcAnchor) \tikzumlnotepath (\tikzumlClassNodeName\tikzumlNoteDestAnchor);%
+ \end{pgfonlayer}%
+ %
+ \stepcounter{tikzumlNoteNum}%
+}%
+%
+% shortcuts for note with geometry
+\newcommand{\umlHVnote}[3][]{%
+ \pgfkeys{/tikzuml/note/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlHVnote, forbidden option geometry}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/note/.cd, #1}%
+ \umlnote[geometry=-|, #1]{#2}{#3}%
+}%
+\newcommand{\umlVHnote}[3][]{%
+ \pgfkeys{/tikzuml/note/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlVHnote, forbidden option geometry}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/note/.cd, #1}%
+ \umlnote[geometry=|-, #1]{#2}{#3}%
+}%
+\newcommand{\umlVHVnote}[3][]{%
+ \pgfkeys{/tikzuml/note/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlVHVnote, forbidden option geometry}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/note/.cd, #1}%
+ \umlnote[geometry=|-|, #1]{#2}{#3}%
+}%
+\newcommand{\umlHVHnote}[3][]{%
+ \pgfkeys{/tikzuml/note/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlHVHnote, forbidden option geometry}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/note/.cd, #1}%
+ \umlnote[geometry=-|-, #1]{#2}{#3}%
+}%
+%
+% define a uml association class (command)
+% args : name of the class
+% attributes of the class
+% operations of the class
+% optional : x,y: coordinates of the class
+% width: width of the class node
+% type: type of of class (class, interface, typedef, enum)
+% template: template parameters
+% name: name of the class node
+% geometry: geometry of the line
+% weight: barycentric weight of the middle part when geometry is a 3-line
+% arm: length of first part when geometry id a 3-line
+% anchor1, anchor2: src/dest anchors on linked classes
+% style: style of the association class (association, aggregation, composition, inherit, ...)
+% draw, fill, fill template, text: colors
+% style: to manage every default TikZ option
+% no coords: to tell that the class position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlassocclass}[5][]{%
+ \pgfkeys{/tikzuml/assocclass/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX,
+ width/.initial=\tikzumlClassDefaultWidth, type/.initial=\tikzumlClassDefaultType, style/.style={},%
+ template/.initial={}, name/.initial=tikzumlEmpty, geometry/.initial=\tikzumlRelationDefaultGeometry,%
+ weight/.initial=\tikzumlRelationDefaultWeight, arm/.initial=auto,%
+ anchor1/.initial=tikzumlEmpty, anchor2/.initial=tikzumlEmpty,%
+ draw/.initial=\tikzumlDefaultDrawColor,%
+ fill template/.initial=\tikzumlClassTemplateFillColorDefaultFillColor,%
+ fill/.initial=\tikzumlClassDefaultFillColor,%
+ text/.initial=\tikzumlDefaultTextColor,%
+ no coords/.is if=tikzumlassocclassWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/assocclass/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/assocclass/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/assocclass/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlassocclass, invalid option \keyname}%
+ }%
+ }%
+ %
+ \pgfkeys{/tikzuml/assocclass/.cd,#1}%
+ \pgfkeys{/tikzuml/assocclass/.cd, x/.get=\tikzumlAssocClassX, y/.get=\tikzumlAssocClassY,%
+ width/.get=\tikzumlAssocClassMinimumWidth, type/.get=\tikzumlAssocClassTypeTmp,%
+ template/.get=\tikzumlAssocClassTemplateParam,%
+ name/.get=\tikzumlAssocClassName, geometry/.get=\tikzumlAssocClassGeometry,%
+ weight/.get=\tikzumlAssocClassWeight, arm/.get=\tikzumlAssocClassArm,%
+ anchor1/.get=\tikzumlAssocClassSrcAnchor,%
+ anchor2/.get=\tikzumlAssocClassDestAnchor,%
+ draw/.get=\tikzumlAssocClassDrawColor, fill/.get=\tikzumlAssocClassFillColor,%
+ text/.get=\tikzumlAssocClassTextColor, fill template/.get=\tikzumlAssocClassTemplateFillColor%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlAssocClassTypeTmp}{class}\OR\equal{\tikzumlAssocClassTypeTmp}{abstract}}{%
+ \def\tikzumlAssocClassType{}%
+ }{%
+ \def\tikzumlAssocClassType{$\ll$\tikzumlAssocClassTypeTmp$\gg$ \\}%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlAssocClassTemplateParam}{}}{%
+ \def\tikzumlAssocClassVPadding{}%
+ \def\tikzumlAssocClassHPadding{}%
+ }{%
+ \def\tikzumlAssocClassVPadding{\vspace{0.1em} \\}%
+ \def\tikzumlAssocClassHPadding{\hspace{0.5ex} $ $}%
+ }%
+ %
+ \def\tikzumlAssocClassName{#2}%
+ \def\tikzumlAssocClassRelationName{#3}%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlAssocClassNodeName{\tikzumlAssocClassName}}\x%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlAssocClassRelationNodeName{\tikzumlAssocClassRelationName}}\x%
+ %
+ \ifthenelse{\equal{\tikzumlAssocClassName}{tikzumlEmpty}}{}{%
+ \def\tikzumlAssocClassNodeName{\tikzumlAssocClassName}%
+ }%
+ %
+ \StrSubstitute{\tikzumlAssocClassNodeName}{:}{@COLON@}[\tikzumlAssocClassNodeName]%
+ \StrSubstitute{\tikzumlAssocClassNodeName}{\_}{@UNDERSCORE@}[\tikzumlAssocClassNodeName]%
+ %
+ \ifthenelse{\equal{\tikzumlAssocClassTypeTmp}{abstract}}{%
+ \let\tikzumlAssocClassNameOld\tikzumlAssocClassName%
+ \def\tikzumlAssocClassName{{\it \tikzumlAssocClassNameOld}}%
+ }{}%
+ %
+ \def\tikzumlAssocClassPos{\tikzumlAssocClassX,\tikzumlAssocClassY}%
+ \def\tikzumlAssocClassAttributes{#4}%
+ \def\tikzumlAssocClassOperations{#5}%
+ %
+ % def anchors macros
+ \ifthenelse{\equal{\tikzumlAssocClassSrcAnchor}{tikzumlEmpty}}{%
+ \def\tikzumlAssocClassSrcAnchor{}%
+ }{%
+ \let\tikzumlAssocClassSrcAnchorold\tikzumlAssocClassSrcAnchor%
+ \def\tikzumlAssocClassSrcAnchor{.\tikzumlAssocClassSrcAnchorold}%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlAssocClassDestAnchor}{tikzumlEmpty}}{%
+ \def\tikzumlAssocClassDestAnchor{}%
+ }{%
+ \let\tikzumlAssocClassDestAnchorold\tikzumlAssocClassDestAnchor%
+ \def\tikzumlAssocClassDestAnchor{.\tikzumlAssocClassDestAnchorold}%
+ }%
+ %
+ \iftikzumlassocclassWithoutCoords%
+ \node[tikzuml class style, draw=\tikzumlAssocClassDrawColor, fill=\tikzumlAssocClassFillColor, text=\tikzumlAssocClassTextColor, font=\tikzumlDefaultFont, minimum width=\tikzumlAssocClassMinimumWidth, /tikzuml/assocclass/style] (\tikzumlAssocClassNodeName) {\begin{tabular}{c}\tikzumlAssocClassVPadding \tikzumlAssocClassType \tikzumlAssocClassHPadding \textbf{\tikzumlAssocClassName} \tikzumlAssocClassHPadding \end{tabular}%
+ \nodepart{second}%
+ \begin{tabular}{l}%
+ \tikzumlAssocClassAttributes%
+ \end{tabular}%
+ \nodepart{third}%
+ \begin{tabular}{l}%
+ \tikzumlAssocClassOperations%
+ \end{tabular}%
+ };%
+ \else%
+ \node[tikzuml class style, draw=\tikzumlAssocClassDrawColor, fill=\tikzumlAssocClassFillColor, text=\tikzumlAssocClassTextColor, font=\tikzumlDefaultFont, minimum width=\tikzumlAssocClassMinimumWidth, /tikzuml/assocclass/style] (\tikzumlAssocClassNodeName) at (\tikzumlAssocClassPos) {\begin{tabular}{c}\tikzumlAssocClassVPadding \tikzumlAssocClassType \tikzumlAssocClassHPadding \textbf{\tikzumlAssocClassName} \tikzumlAssocClassHPadding \end{tabular}%
+ \nodepart{second}%
+ \begin{tabular}{l}%
+ \tikzumlAssocClassAttributes%
+ \end{tabular}%
+ \nodepart{third}%
+ \begin{tabular}{l}%
+ \tikzumlAssocClassOperations%
+ \end{tabular}%
+ };%
+ \fi%
+ %
+ \ifthenelse{\equal{\tikzumlAssocClassTemplateParam}{}}{}{%
+ \draw (\tikzumlAssocClassNodeName.north east) node[tikzuml template style, name=\tikzumlAssocClassNodeName-template, draw=\tikzumlAssocClassDrawColor, fill=\tikzumlAssocClassTemplateFillColor, text=\tikzumlAssocClassTextColor, font=\tikzumlDefaultFont] {\tikzumlAssocClassTemplateParam};%
+ }%
+ %
+ \pgfmathsetmacro{\tikzumlAssocClassWeightT}{1.0-\tikzumlAssocClassWeight}
+ \node (\tikzumlAssocClassNodeName-middle) at (barycentric cs:\tikzumlAssocClassNodeName=\tikzumlAssocClassWeight,\tikzumlAssocClassRelationNodeName=\tikzumlAssocClassWeightT) {};%
+ %
+ \ifthenelse{\equal{\tikzumlAssocClassGeometry}{--}\OR\equal{\tikzumlAssocClassGeometry}{-|}\OR\equal{\tikzumlAssocClassGeometry}{|-}}{%
+ \edef\tikzumlassocclasspath{\tikzumlAssocClassGeometry}
+ }{%
+ \ifthenelse{\equal{\tikzumlAssocClassGeometry}{-|-}}{%
+ \ifthenelse{\equal{\tikzumlAssocClassArm}{auto}}{%
+ \edef\tikzumlassocclasspath{-- (\tikzumlAssocClassNodeName\tikzumlAssocClassSrcAnchor -| \tikzumlAssocClassNodeName-middle.center) -- (\tikzumlAssocClassNodeName-middle.center) -- (\tikzumlAssocClassNodeName-middle.center |- \tikzumlAssocClassRelationNodeName\tikzumlAssocClassDestAnchor) --}%
+ }{%
+ \draw (\tikzumlAssocClassNodeName\tikzumlAssocClassSrcAnchor)+(\tikzumlAssocClassArm,0) node[name=\tikzumlAssocClassNodeName-tmp] {};
+ \edef\tikzumlnotepath{-- (\tikzumlAssocClassNodeName-tmp.center) |-}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlAssocClassGeometry}{|-|}}{%
+ \ifthenelse{\equal{\tikzumlAssocClassArm}{auto}}{%
+ \edef\tikzumlassocclasspath{-- (\tikzumlAssocClassNodeName\tikzumlAssocClassSrcAnchor |- \tikzumlAssocClassNodeName-middle.center) -- (\tikzumlAssocClassNodeName-middle.center) -- (\tikzumlAssocClassNodeName-middle.center -| \tikzumlAssocClassRelationNodeName\tikzumlAssocClassDestAnchor) --}%
+ }{%
+ \draw (\tikzumlAssocClassNodeName\tikzumlAssocClassSrcAnchor)+(0,\tikzumlAssocClassArm) node[name=\tikzumlAssocClassNodeName-tmp] {};
+ \edef\tikzumlassocclasspath{-- (\thetikzumlAssocClassNodeName-tmp.center) -|}%
+ }%
+
+ }{%
+ \errmessage{TIKZUML ERROR : Unknown geometry value !!! It should be in the following list : --, |-, -|, |-|, -|-}%
+ }%
+ }%
+ }%
+ %
+ \begin{pgfonlayer}{connections}%
+ \draw[dashed] (\tikzumlAssocClassNodeName\tikzumlAssocClassSrcAnchor) \tikzumlassocclasspath (\tikzumlAssocClassRelationNodeName\tikzumlAssocClassDestAnchor);%
+ \end{pgfonlayer}%
+ %
+ % add to fit
+ \ifnum\c@tikzumlPackageLevel>0%
+ \edef\tikzumlPackageFitOld{\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname}%
+ \ifthenelse{\equal{\tikzumlAssocClassTemplateParam}{}}{%
+ \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{\tikzumlPackageFitOld (\tikzumlAssocClassNodeName)(\tikzumlAssocClassNodeName-middle)}%
+ }{%
+ \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{\tikzumlPackageFitOld (\tikzumlAssocClassNodeName) (\tikzumlAssocClassNodeName-template)(\tikzumlAssocClassNodeName-middle)}%
+ }%
+ \stepcounter{tikzumlPackageClassNum}%
+ \fi%
+}%
+%
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% use case diagrams %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+\tikzstyle{tikzuml usecase style}=[ellipse, text centered]%
+\tikzstyle{tikzuml actor style}=[ellipse, inner sep=0, outer sep=0]%
+%
+\newcounter{tikzumlSystemUseCaseNum}%
+\newcounter{tikzumlSystemLevel}%
+\newcounter{tikzumlUseCaseNum}%
+\newcounter{tikzumlActorNum}%
+%
+\newif\iftikzumlusecaseWithoutCoords%
+\newif\iftikzumlactorWithoutCoords%
+%
+% define a system
+% arg : name
+% optional : x, y: coordinates of the system
+% draw, fill, text: colors
+\newenvironment{umlsystem}[2][]{%
+ \gdef\tikzumlSystemFit{}%
+ \def\tikzumlSystemName{#2}%
+ \setcounter{tikzumlSystemUseCaseNum}{0}%
+ %
+ \pgfkeys{/tikzuml/system/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX,%
+ draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlSystemDefaultFillColor,%
+ text/.initial=\tikzumlDefaultTextColor,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \errmessage{TIKZUML ERROR : in umlsystem, invalid option \keyname}%
+ }%
+ }%
+ %
+ \pgfkeys{/tikzuml/system/.cd, #1}%
+ \pgfkeys{/tikzuml/system/.cd, x/.get=\tikzumlSystemXShift, y/.get=\tikzumlSystemYShift,%
+ draw/.get=\tikzumlSystemDrawColor, fill/.get=\tikzumlSystemFillColor,%
+ text/.get=\tikzumlSystemTextColor}%
+ %
+ \stepcounter{tikzumlSystemLevel}%
+ %
+ \begin{scope}[xshift=\tikzumlSystemXShift cm, yshift=\tikzumlSystemYShift cm]%
+}{%
+ \addtocounter{tikzumlSystemLevel}{-1}%
+ % if contains no usecase, one define a fictive node to enable the fit option
+ \ifnum\c@tikzumlSystemUseCaseNum=0%
+ \node[inner xsep=10ex, inner ysep=1em] (\tikzumlSystemName-root) at (0,0) {};%
+ \xdef\tikzumlSystemFit{(\tikzumlSystemName-root)}%
+ \fi%
+ %
+ \begin{pgfonlayer}{background}%
+ \node[inner ysep=1em, inner xsep=2ex, fit = \tikzumlSystemFit] (\tikzumlSystemName-tmp) {};%
+ \node[text=\tikzumlSystemTextColor, font=\tikzumlDefaultFont] (\tikzumlSystemName-caption-tmp) at (\tikzumlSystemName-tmp.north) {\tikzumlSystemName};%
+ \node[draw=\tikzumlSystemDrawColor, fill=\tikzumlSystemFillColor, text=\tikzumlSystemTextColor, font=\tikzumlDefaultFont, inner ysep=1em, inner xsep=2ex, fit = (\tikzumlSystemName-tmp) (\tikzumlSystemName-caption-tmp)] (\tikzumlSystemName) {};%
+ \node[text=\tikzumlSystemTextColor, font=\tikzumlDefaultFont] (\tikzumlSystemName-caption) at (\tikzumlSystemName-caption-tmp.north) {\tikzumlSystemName};%
+ \end{pgfonlayer}%
+ \end{scope}%
+ %
+}%
+%
+% define a use case
+% arg : label of the use case
+% optional : x, y: coordinates of the use case
+% name: name of the node
+% width: node width
+% draw, fill, text: colors
+% style: to manage every default TikZ option
+% no coords: to tell that the use case position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlusecase}[2][]{%
+ \stepcounter{tikzumlUseCaseNum}%
+ \pgfkeys{/tikzuml/usecase/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=auto,%
+ name/.initial=usecase-\thetikzumlUseCaseNum,%
+ draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlUseCaseDefaultFillColor,%
+ text/.initial=\tikzumlDefaultTextColor, style/.style={},%
+ no coords/.is if=tikzumlusecaseWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/usecase/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/usecase/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/usecase/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlusecase, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/usecase/.cd, #1}%
+ \pgfkeys{/tikzuml/usecase/.cd, x/.get=\tikzumlUseCaseX, y/.get=\tikzumlUseCaseY, width/.get=\tikzumlUseCaseTextWidth,%
+ name/.get=\tikzumlUseCaseName,%
+ draw/.get=\tikzumlUseCaseDrawColor, fill/.get=\tikzumlUseCaseFillColor,%
+ text/.get=\tikzumlUseCaseTextColor%
+ }%
+ %
+ \def\tikzumlUseCaseText{#2}%
+ %
+ \def\tikzumlUseCasePos{\tikzumlUseCaseX,\tikzumlUseCaseY}%
+ %
+ \ifthenelse{\equal{\tikzumlUseCaseTextWidth}{auto}}{%
+ \iftikzumlusecaseWithoutCoords%
+ \node[tikzuml usecase style, draw=\tikzumlUseCaseDrawColor, fill=\tikzumlUseCaseFillColor, text=\tikzumlUseCaseTextColor, font=\tikzumlDefaultFont, /tikzuml/usecase/style] (\tikzumlUseCaseName) {\tikzumlUseCaseText};%
+ \else%
+ \node[tikzuml usecase style, draw=\tikzumlUseCaseDrawColor, fill=\tikzumlUseCaseFillColor, text=\tikzumlUseCaseTextColor, font=\tikzumlDefaultFont, /tikzuml/usecase/style] (\tikzumlUseCaseName) at (\tikzumlUseCasePos) {\tikzumlUseCaseText};%
+ \fi%
+ }{%
+ \iftikzumlusecaseWithoutCoords%
+ \node[tikzuml usecase style, draw=\tikzumlUseCaseDrawColor, fill=\tikzumlUseCaseFillColor, text=\tikzumlUseCaseTextColor, font=\tikzumlDefaultFont, text width=\tikzumlUseCaseTextWidth, /tikzuml/usecase/style] (\tikzumlUseCaseName) {\tikzumlUseCaseText};%
+ \else%
+ \node[tikzuml usecase style, draw=\tikzumlUseCaseDrawColor, fill=\tikzumlUseCaseFillColor, text=\tikzumlUseCaseTextColor, font=\tikzumlDefaultFont, text width=\tikzumlUseCaseTextWidth, /tikzuml/usecase/style] (\tikzumlUseCaseName) at (\tikzumlUseCasePos) {\tikzumlUseCaseText};%
+ \fi%
+ }%
+ %
+ % add to fit
+ \ifnum\c@tikzumlSystemLevel>0%
+ \let\tikzumlSystemFitOld\tikzumlSystemFit%
+ \xdef\tikzumlSystemFit{\tikzumlSystemFitOld (\tikzumlUseCaseName)}%
+ \stepcounter{tikzumlSystemUseCaseNum}%
+ \fi%
+}%
+%
+% define the actor symbol
+% optional : global tikzpicture styles
+\newcommand{\picturedactor}[1]{%
+ \pgfkeys{/tikzuml/picactor/.cd, scale/.initial=1, .unknown/.code={}}%
+ \pgfkeys{/tikzuml/picactor/.cd,#1}%
+ \pgfkeys{/tikzuml/picactor/.cd, scale/.get=\tikzumlPicturedActorScale}%
+ %
+ \begin{tikzpicture}[#1]%
+ \coordinate (head) at (0,4ex);%
+ \coordinate (left-hand) at (-2ex,2ex);%
+ \coordinate (right-hand) at (2ex,2ex);%
+ \coordinate (left-foot) at (-2ex,-2ex);%
+ \coordinate (right-foot) at (2ex,-2ex);%
+ \coordinate (empty) at (0,-3ex);%
+ \draw (empty) (0,0) -- (head);%
+ \draw (left-hand) -- (right-hand);%
+ \draw (0,0) -- (left-foot) (0,0) -- (right-foot);%
+ \node[fill, draw, circle, inner sep=\tikzumlPicturedActorScale*0.3333ex, minimum size=\tikzumlPicturedActorScale*2ex, anchor=base] at (head) {};%
+ \end{tikzpicture}%
+}%
+%
+% define an actor
+% arg : var name
+% optional : x, y: coordinates of the actor
+% scale: scale factor of the actor symbol
+% below: distance between the actor symbol and its name below
+% draw, text: colors
+% style: to manage every default TikZ option
+% no coords: to tell that the actor position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlactor}[2][]{%
+ \stepcounter{tikzumlActorNum}%
+ \pgfkeys{/tikzuml/actor/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, scale/.initial=1, below/.initial=\tikzumlActorDefaultBelow,%
+ draw/.initial=\tikzumlDefaultDrawColor, text/.initial=\tikzumlDefaultTextColor,%
+ style/.style={},%
+ no coords/.is if=tikzumlactorWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/actor/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/actor/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/actor/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlactor, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/actor/.cd, #1}%
+ \pgfkeys{/tikzuml/actor/.cd,%
+ x/.get=\tikzumlActorX, y/.get=\tikzumlActorY, scale/.get=\tikzumlActorScale,%
+ below/.get=\tikzumlActorBelow,%
+ draw/.get=\tikzumlActorDrawColor, text/.get=\tikzumlActorTextColor}%
+ %
+ \def\tikzumlActorName{#2}%
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlActorNodeName{\tikzumlActorName}}\x%
+ %
+ \def\tikzumlActorPos{\tikzumlActorX,\tikzumlActorY}%
+ %
+ \iftikzumlactorWithoutCoords%
+ \node[tikzuml actor style, text=\tikzumlActorTextColor, font=\tikzumlDefaultFont, /tikzuml/actor/style] (\tikzumlActorNodeName) {\picturedactor{scale=\tikzumlActorScale, fill=white, draw=\tikzumlActorDrawColor, thick}};%
+ \else%
+ \node[tikzuml actor style, text=\tikzumlActorTextColor, font=\tikzumlDefaultFont, /tikzuml/actor/style] (\tikzumlActorNodeName) at (\tikzumlActorPos) {\picturedactor{scale=\tikzumlActorScale, fill=white, draw=\tikzumlActorDrawColor, thick}};%
+ \fi%
+ \node[text=\tikzumlActorTextColor, font=\tikzumlDefaultFont, below=\tikzumlActorScale*\tikzumlActorBelow] at (\tikzumlActorNodeName) {\tikzumlActorName};%
+ %
+}%
+
+% shortcuts for include and extend relation
+\newcommand{\umlinclude}[3][]{%
+ \pgfkeys{/tikzuml/includerelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlinclude, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlinclude, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/includerelation/.cd, #1}%
+ \umlrelation[stereo=include, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+\newcommand{\umlextend}[3][]{%
+ \pgfkeys{/tikzuml/extendrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlextend, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlextend, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/extendrelation/.cd, #1}%
+ \umlrelation[stereo=extend, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlHVinclude}[3][]{%
+ \pgfkeys{/tikzuml/includerelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlHVinclude, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlHVinclude, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/includerelation/.cd, #1}%
+ \umlrelation[geometry=-|, stereo=include, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+\newcommand{\umlHVextend}[3][]{%
+ \pgfkeys{/tikzuml/extendrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlHVextend, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlHVextend, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/extendrelation/.cd, #1}%
+ \umlrelation[geometry=-|, stereo=extend, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlVHinclude}[3][]{%
+ \pgfkeys{/tikzuml/includerelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlVHinclude, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlVHinclude, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/includerelation/.cd, #1}%
+ \umlrelation[geometry=|-, stereo=include, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+\newcommand{\umlVHextend}[3][]{%
+ \pgfkeys{/tikzuml/extendrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR :in umlVHextend, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlVHextend, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/extendrelation/.cd, #1}%
+ \umlrelation[geometry=|-, stereo=extend, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlHVHinclude}[3][]{%
+ \pgfkeys{/tikzuml/includerelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlHVHinclude, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlHVHinclude, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/includerelation/.cd, #1}%
+ \umlrelation[geometry=-|-, stereo=include, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+\newcommand{\umlHVHextend}[3][]{%
+ \pgfkeys{/tikzuml/extendrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlHVHextend, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlHVHextend, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/extendrelation/.cd, #1}%
+ \umlrelation[geometry=-|-, stereo=extend, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlVHVinclude}[3][]{%
+ \pgfkeys{/tikzuml/includerelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlVHVinclude, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlVHVinclude, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/includerelation/.cd, #1}%
+ \umlrelation[geometry=|-|, stereo=include, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+\newcommand{\umlVHVextend}[3][]{%
+ \pgfkeys{/tikzuml/extendrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlVHVextend, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlVHVextend, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/extendrelation/.cd, #1}%
+ \umlrelation[geometry=|-|, stereo=extend, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlCNinclude}[4][]{%
+ \pgfkeys{/tikzuml/includerelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlCNinclude, forbidden option stereo}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/includerelation/.cd, #1}%
+ \umlCNrelation[stereo=include, style={tikzuml dependency style}, #1]{#2}{#3}{#4}%
+}%
+\newcommand{\umlCNextend}[4][]{%
+ \pgfkeys{/tikzuml/extendrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlCNextend, forbidden option stereo}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/extendrelation/.cd, #1}%
+ \umlCNrelation[stereo=extend, style={tikzuml dependency style}, #1]{#2}{#3}{#4}%
+}%
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% state diagrams %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+\tikzstyle{tikzuml state style}=[rectangle split, rectangle split parts=2, rounded corners, inner xsep=1.5ex]%
+\tikzstyle{tikzuml transition style}=[color=\tikzumlDefaultDrawColor, rounded corners, -angle 45]%
+%
+\newcounter{tikzumlStateJoinNum}%
+\newcounter{tikzumlStateDecisionNum}%
+\newcounter{tikzumlStateInitialNum}%
+\newcounter{tikzumlStateFinalNum}%
+\newcounter{tikzumlStateEnterNum}%
+\newcounter{tikzumlStateExitNum}%
+\newcounter{tikzumlStateEndNum}%
+\newcounter{tikzumlStateHistoryNum}%
+\newcounter{tikzumlStateDeepHistoryNum}%
+\newcounter{tikzumlStateLevel}%
+\newcounter{tikzumlStateSubStateNum}%
+\newcounter{tikzumlStateText}%
+%
+\newif\iftikzumlstatejoinWithoutCoords%
+\newif\iftikzumlstatedecisionWithoutCoords%
+\newif\iftikzumlstateinitialWithoutCoords%
+\newif\iftikzumlstatefinalWithoutCoords%
+\newif\iftikzumlstateenterWithoutCoords%
+\newif\iftikzumlstateexitWithoutCoords%
+\newif\iftikzumlstateendWithoutCoords%
+\newif\iftikzumlstatehistoryWithoutCoords%
+\newif\iftikzumlstatedeephistoryWithoutCoords%
+\newif\iftikzumlstateWithoutCoords%
+%
+% define a uml join state
+% args : name of the state
+% optional : x,y: coordinates of the state
+% width: width of the state node
+% name: name of the state node
+% color: color of the join symbol
+% style: to manage every default TikZ option
+% no coords: to tell that the state position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlstatejoin}[1][]{%
+ \pgfkeys{/tikzuml/statejoin/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateJoinDefaultWidth,%
+ name/.initial=statejoin-\thetikzumlStateJoinNum,%
+ color/.initial=\tikzumlDefaultDrawColor, style/.style={},%
+ no coords/.is if=tikzumlstatejoinWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/statejoin/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/statejoin/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/statejoin/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlstatejoin, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/statejoin/.cd, #1}%
+ \pgfkeys{/tikzuml/statejoin/.cd, x/.get=\tikzumlStateJoinX, y/.get=\tikzumlStateJoinY, width/.get=\tikzumlStateJoinMinimumWidth,%
+ name/.get=\tikzumlStateJoinName, color/.get=\tikzumlStateJoinColor%
+ }%
+ %
+ \def\tikzumlStateJoinPos{\tikzumlStateJoinX,\tikzumlStateJoinY}%
+ %
+ \iftikzumlstatejoinWithoutCoords%
+ \node[circle, minimum size=\tikzumlStateJoinMinimumWidth, draw=\tikzumlStateJoinColor, fill=\tikzumlStateJoinColor, /tikzuml/statejoin/style] (\tikzumlStateJoinName) {};%
+ \else%
+ \node[circle, minimum size=\tikzumlStateJoinMinimumWidth, draw=\tikzumlStateJoinColor, fill=\tikzumlStateJoinColor, /tikzuml/statejoin/style] (\tikzumlStateJoinName) at (\tikzumlStateJoinPos) {};%
+ \fi%
+ %
+ % add to fit
+ \ifnum\c@tikzumlStateLevel>0%
+ \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlStateJoinName)}%
+ \stepcounter{tikzumlStateSubStateNum}%
+ \fi%
+ \stepcounter{tikzumlStateJoinNum}%
+}%
+%
+% define a uml decision state
+% args : name of the state
+% optional : x,y: coordinates of the state
+% width: width of the state node
+% name: name of the state node
+% color: color of the join symbol
+% style: to manage every default TikZ option
+% no coords: to tell that the state position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlstatedecision}[1][]{%
+ \pgfkeys{/tikzuml/statedecision/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateDecisionDefaultWidth,%
+ name/.initial=statedecision-\thetikzumlStateDecisionNum,%
+ color/.initial=\tikzumlDefaultDrawColor, style/.style={},%
+ no coords/.is if=tikzumlstatedecisionWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/statedecision/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/statedecision/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/statedecision/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlstatedecision, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/statedecision/.cd, #1}%
+ \pgfkeys{/tikzuml/statedecision/.cd, x/.get=\tikzumlStateDecisionX, y/.get=\tikzumlStateDecisionY, width/.get=\tikzumlStateDecisionMinimumWidth,%
+ name/.get=\tikzumlStateDecisionName, color/.get=\tikzumlStateDecisionColor%
+ }%
+ %
+ \def\tikzumlStateDecisionPos{\tikzumlStateDecisionX,\tikzumlStateDecisionY}%
+ %
+ \iftikzumlstatedecisionWithoutCoords%
+ \node[rectangle, rotate=45, minimum size=\tikzumlStateDecisionMinimumWidth, draw=\tikzumlStateDecisionColor, /tikzuml/statedecision/style] (\tikzumlStateDecisionName) {};%
+ \else%
+ \node[rectangle, rotate=45, minimum size=\tikzumlStateDecisionMinimumWidth, draw=\tikzumlStateDecisionColor, /tikzuml/statedecision/style] (\tikzumlStateDecisionName) at (\tikzumlStateDecisionPos) {};%
+ \fi%
+ %
+ % add to fit
+ \ifnum\c@tikzumlStateLevel>0%
+ \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlStateDecisionName)}%
+ \stepcounter{tikzumlStateSubStateNum}%
+ \fi%
+ \stepcounter{tikzumlStateDecisionNum}%
+}%
+%
+% define a uml initial state
+% args : name of the state
+% optional : x,y: coordinates of the state
+% width: width of the state node
+% name: name of the state node
+% entry, do, exit: entry/do/exit action of the state
+% color: color of the join symbol
+% style: to manage every default TikZ option
+% no coords: to tell that the state position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlstateinitial}[1][]{%
+ \pgfkeys{/tikzuml/stateinitial/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateInitialDefaultWidth,%
+ name/.initial=stateinitial-\thetikzumlStateInitialNum,%
+ color/.initial=\tikzumlDefaultDrawColor, style/.style={},%
+ no coords/.is if=tikzumlstateinitialWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/stateinitial/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/stateinitial/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/stateinitial/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlstateinitial, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/stateinitial/.cd, #1}%
+ \pgfkeys{/tikzuml/stateinitial/.cd, x/.get=\tikzumlStateInitialX, y/.get=\tikzumlStateInitialY, width/.get=\tikzumlStateInitialMinimumWidth,%
+ name/.get=\tikzumlStateInitialName, color/.get=\tikzumlStateInitialColor%
+ }%
+ %
+ \def\tikzumlStateInitialPos{\tikzumlStateInitialX,\tikzumlStateInitialY}%
+ %
+ \iftikzumlstateinitialWithoutCoords%
+ \node[circle, minimum size=\tikzumlStateInitialMinimumWidth, fill=\tikzumlStateInitialColor, /tikzuml/stateinitial/style] (\tikzumlStateInitialName) {};%
+ \else%
+ \node[circle, minimum size=\tikzumlStateInitialMinimumWidth, fill=\tikzumlStateInitialColor, /tikzuml/stateinitial/style] (\tikzumlStateInitialName) at (\tikzumlStateInitialPos) {};%
+ \fi%
+ %
+ % add to fit
+ \ifnum\c@tikzumlStateLevel>0%
+ \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlStateInitialName)}%
+ \stepcounter{tikzumlStateSubStateNum}%
+ \fi%
+ \stepcounter{tikzumlStateInitialNum}%
+}%
+%
+% define a uml final state
+% args : name of the state
+% optional : x,y: coordinates of the state
+% width: width of the state node
+% name: name of the state node
+% color: color of the join symbol
+% style: to manage every default TikZ option
+% no coords: to tell that the state position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlstatefinal}[1][]{%
+ \pgfkeys{/tikzuml/statefinal/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateFinalDefaultWidth,%
+ name/.initial=statefinal-\thetikzumlStateFinalNum,%
+ color/.initial=\tikzumlDefaultDrawColor, style/.style={},%
+ no coords/.is if=tikzumlstatefinalWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/statefinal/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/statefinal/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/statefinal/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlstatefinal, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/statefinal/.cd, #1}%
+ \pgfkeys{/tikzuml/statefinal/.cd, x/.get=\tikzumlStateFinalX, y/.get=\tikzumlStateFinalY, width/.get=\tikzumlStateFinalMinimumWidth,%
+ name/.get=\tikzumlStateFinalName, color/.get=\tikzumlStateFinalColor%
+ }%
+ %
+ \def\tikzumlStateFinalPos{\tikzumlStateFinalX,\tikzumlStateFinalY}%
+ %
+ \iftikzumlstatefinalWithoutCoords%
+ \node[circle, minimum size=\tikzumlStateFinalMinimumWidth, draw=\tikzumlStateFinalColor, fill=\tikzumlStateFinalColor, double, double distance=0.1cm, /tikzuml/statefinal/style] (\tikzumlStateFinalName) {};%
+ \else%
+ \node[circle, minimum size=\tikzumlStateFinalMinimumWidth, draw=\tikzumlStateFinalColor, fill=\tikzumlStateFinalColor, double, double distance=0.1cm, /tikzuml/statefinal/style] (\tikzumlStateFinalName) at (\tikzumlStateFinalPos) {};%
+ \fi%
+ %
+ % add to fit
+ \ifnum\c@tikzumlStateLevel>0%
+ \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlStateFinalName)}%
+ \stepcounter{tikzumlStateSubStateNum}%
+ \fi%
+ \stepcounter{tikzumlStateFinalNum}%
+}%
+%
+% define a uml enter state
+% args : name of the state
+% optional : x,y: coordinates of the state
+% width: width of the state node
+% name: name of the state node
+% color: color of the join symbol
+% style: to manage every default TikZ option
+% no coords: to tell that the state position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlstateenter}[1][]{%
+ \pgfkeys{/tikzuml/stateenter/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateEnterDefaultWidth,%
+ name/.initial=stateenter-\thetikzumlStateEnterNum,%
+ color/.initial=\tikzumlDefaultDrawColor, style/.style={},%
+ no coords/.is if=tikzumlstateenterWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/stateenter/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/stateenter/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/stateenter/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlstateenter, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/stateenter/.cd, #1}%
+ \pgfkeys{/tikzuml/stateenter/.cd, x/.get=\tikzumlStateEnterX, y/.get=\tikzumlStateEnterY, width/.get=\tikzumlStateEnterMinimumWidth,%
+ name/.get=\tikzumlStateEnterName, color/.get=\tikzumlStateEnterColor%
+ }%
+ %
+ \def\tikzumlStateEnterPos{\tikzumlStateEnterX,\tikzumlStateEnterY}%
+ %
+ \iftikzumlstateenterWithoutCoords%
+ \node[circle, minimum size=\tikzumlStateEnterMinimumWidth, draw=\tikzumlStateEnterColor, /tikzuml/stateenter/style] (\tikzumlStateEnterName) {};%
+ \else%
+ \node[circle, minimum size=\tikzumlStateEnterMinimumWidth, draw=\tikzumlStateEnterColor, /tikzuml/stateenter/style] (\tikzumlStateEnterName) at (\tikzumlStateEnterPos) {};%
+ \fi%
+ %
+ % add to fit
+ \ifnum\c@tikzumlStateLevel>0%
+ \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlStateEnterName)}%
+ \stepcounter{tikzumlStateSubStateNum}%
+ \fi%
+ \stepcounter{tikzumlStateEnterNum}%
+}%
+%
+% define a uml exit state
+% args : name of the state
+% optional : x,y: coordinates of the state
+% width: width of the state node
+% name: name of the state node
+% color: color of the join symbol
+% style: to manage every default TikZ option
+% no coords: to tell that the state position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlstateexit}[1][]{%
+ \pgfkeys{/tikzuml/stateexit/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateExitDefaultWidth,%
+ name/.initial=stateexit-\thetikzumlStateExitNum,%
+ color/.initial=\tikzumlDefaultDrawColor, style/.style={},%
+ no coords/.is if=tikzumlstateexitWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/stateexit/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/stateexit/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/stateexit/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlstateexit, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/stateexit/.cd, #1}%
+ \pgfkeys{/tikzuml/stateexit/.cd, x/.get=\tikzumlStateExitX, y/.get=\tikzumlStateExitY, width/.get=\tikzumlStateExitMinimumWidth,%
+ name/.get=\tikzumlStateExitName, color/.get=\tikzumlStateExitColor%
+ }%
+ %
+ \def\tikzumlStateExitPos{\tikzumlStateExitX,\tikzumlStateExitY}%
+ %
+ \iftikzumlstateexitWithoutCoords%
+ \node[circle, minimum size=\tikzumlStateExitMinimumWidth, draw=\tikzumlStateExitColor, /tikzuml/stateexit/style] (\tikzumlStateExitName) {};%
+ \else%
+ \node[circle, minimum size=\tikzumlStateExitMinimumWidth, draw=\tikzumlStateExitColor, /tikzuml/stateexit/style] (\tikzumlStateExitName) at (\tikzumlStateExitPos) {};%
+ \fi%
+ \draw[draw=\tikzumlStateExitColor] (\tikzumlStateExitName.north east) -- (\tikzumlStateExitName.south west) (\tikzumlStateExitName.north west) -- (\tikzumlStateExitName.south east);
+ %
+ % add to fit
+ \ifnum\c@tikzumlStateLevel>0%
+ \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlStateExitName)}%
+ \stepcounter{tikzumlStateSubStateNum}%
+ \fi%
+ \stepcounter{tikzumlStateExitNum}%
+}%
+%
+% define a uml end state
+% args : name of the state
+% optional : x,y: coordinates of the state
+% width: width of the state node
+% name: name of the state node
+% color: color of the join symbol
+% style: to manage every default TikZ option
+% no coords: to tell that the state position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlstateend}[1][]{%
+ \pgfkeys{/tikzuml/stateend/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateEndDefaultWidth,%
+ name/.initial=stateend-\thetikzumlStateEndNum,%
+ color/.initial=\tikzumlDefaultDrawColor, style/.style={},%
+ no coords/.is if=tikzumlstateendWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/stateend/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/stateend/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/stateend/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlstateend, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/stateend/.cd, #1}%
+ \pgfkeys{/tikzuml/stateend/.cd, x/.get=\tikzumlStateEndX, y/.get=\tikzumlStateEndY, width/.get=\tikzumlStateEndMinimumWidth,%
+ name/.get=\tikzumlStateEndName, color/.get=\tikzumlStateEndColor%
+ }%
+ %
+ \def\tikzumlStateEndPos{\tikzumlStateEndX,\tikzumlStateEndY}%
+ %
+ \iftikzumlstateendWithoutCoords%
+ \node[circle, minimum size=\tikzumlStateEndMinimumWidth, /tikzuml/stateend/style] (\tikzumlStateEndName) {};%
+ \else%
+ \node[circle, minimum size=\tikzumlStateEndMinimumWidth, /tikzuml/stateend/style] (\tikzumlStateEndName) at (\tikzumlStateEndPos) {};%
+ \fi%
+ \draw[draw=\tikzumlStateEndColor] (\tikzumlStateEndName.north east) -- (\tikzumlStateEndName.south west) (\tikzumlStateEndName.north west) -- (\tikzumlStateEndName.south east);
+ %
+ % add to fit
+ \ifnum\c@tikzumlStateLevel>0%
+ \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlStateEndName)}%
+ \stepcounter{tikzumlStateSubStateNum}%
+ \fi%
+ \stepcounter{tikzumlStateEndNum}%
+}%
+%
+\newcommand{\picturedhistory}[1]{%
+ \begin{tikzpicture}[#1]%
+ \draw[thick] (-0.1cm,-0.15cm) -- (-0.1cm,0.15cm)
+ (-0.1cm,0) -- (0.1cm,0)
+ (0.1cm,-0.15cm) -- (0.1cm,0.15cm);%
+ \end{tikzpicture}%
+}%
+%
+% define a uml history state
+% args : name of the state
+% optional : x,y: coordinates of the state
+% width: width of the state node
+% name: name of the state node
+% color: color of the join symbol
+% style: to manage every default TikZ option
+% no coords: to tell that the state position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlstatehistory}[1][]{%
+ \pgfkeys{/tikzuml/statehistory/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateHistoryDefaultWidth,%
+ name/.initial=statehistory-\thetikzumlStateHistoryNum,%
+ color/.initial=\tikzumlDefaultDrawColor, style/.style={},%
+ no coords/.is if=tikzumlstatehistoryWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/statehistory/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/statehistory/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/statehistory/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlstatehistory, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/statehistory/.cd, #1}%
+ \pgfkeys{/tikzuml/statehistory/.cd, x/.get=\tikzumlStateHistoryX, y/.get=\tikzumlStateHistoryY, width/.get=\tikzumlStateHistoryMinimumWidth,%
+ name/.get=\tikzumlStateHistoryName, color/.get=\tikzumlStateHistoryColor%
+ }%
+ %
+ \def\tikzumlStateHistoryPos{\tikzumlStateHistoryX,\tikzumlStateHistoryY}%
+ %
+ \iftikzumlstatehistoryWithoutCoords%
+ \node[circle, minimum size=\tikzumlStateHistoryMinimumWidth, draw=\tikzumlStateHistoryColor, /tikzuml/statehistory/style] (\tikzumlStateHistoryName) {\picturedhistory{draw=\tikzumlStateHistoryColor}};%
+ \else%
+ \node[circle, minimum size=\tikzumlStateHistoryMinimumWidth, draw=\tikzumlStateHistoryColor, /tikzuml/statehistory/style] (\tikzumlStateHistoryName) at (\tikzumlStateHistoryPos) {\picturedhistory{draw=\tikzumlStateHistoryColor}};%
+ \fi%
+ %
+ % add to fit
+ \ifnum\c@tikzumlStateLevel>0%
+ \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlStateHistoryName)}%
+ \stepcounter{tikzumlStateSubStateNum}%
+ \fi%
+ \stepcounter{tikzumlStateHistoryNum}%
+}%
+%
+\newcommand{\pictureddeephistory}[1]{%
+ \begin{tikzpicture}[#1]%
+ \draw[thick] (-0.1cm,-0.15cm) -- (-0.1cm,0.15cm)
+ (-0.1cm,0) -- (0.1cm,0)
+ (0.1cm,-0.15cm) -- (0.1cm,0.15cm)
+ (0.23cm,0.19cm) -- (0.23cm,0.11cm)
+ (0.20cm,0.17cm) -- (0.26cm,0.13cm)
+ (0.20cm,0.13cm) -- (0.26cm,0.17cm);%
+ \end{tikzpicture}%
+}%
+%
+% define a uml deep-history state
+% args : name of the state
+% optional : x,y: coordinates of the state
+% width: width of the state node
+% name: name of the state node
+% color: color of the join symbol
+% style: to manage every default TikZ option
+% no coords: to tell that the state position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlstatedeephistory}[1][]{%
+ \pgfkeys{/tikzuml/statedeephistory/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateDeepHistoryDefaultWidth,%
+ name/.initial=statedeephistory-\thetikzumlStateDeepHistoryNum,%
+ color/.initial=\tikzumlDefaultDrawColor, style/.style={},%
+ no coords/.is if=tikzumlstatedeephistoryWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/statedeephistory/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/statedeephistory/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/statedeephistory/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlstatedeephistory, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/statedeephistory/.cd, #1}%
+ \pgfkeys{/tikzuml/statedeephistory/.cd, x/.get=\tikzumlStateDeepHistoryX, y/.get=\tikzumlStateDeepHistoryY, width/.get=\tikzumlStateDeepHistoryMinimumWidth,%
+ name/.get=\tikzumlStateDeepHistoryName, color/.get=\tikzumlStateDeepHistoryColor%
+ }%
+ %
+ \def\tikzumlStateDeepHistoryPos{\tikzumlStateDeepHistoryX,\tikzumlStateDeepHistoryY}%
+ %
+ \iftikzumlstatedeephistoryWithoutCoords%
+ \node[circle, minimum size=\tikzumlStateDeepHistoryMinimumWidth, draw=\tikzumlStateDeepHistoryColor, /tikzuml/statedeephistory/style] (\tikzumlStateDeepHistoryName) {\pictureddeephistory{draw=\tikzumlStateDeepHistoryColor}};%
+ \else%
+ \node[circle, minimum size=\tikzumlStateDeepHistoryMinimumWidth, draw=\tikzumlStateDeepHistoryColor, /tikzuml/statedeephistory/style] (\tikzumlStateDeepHistoryName) at (\tikzumlStateDeepHistoryPos) {\pictureddeephistory{draw=\tikzumlStateDeepHistoryColor}};%
+ \fi%
+ %
+ % add to fit
+ \ifnum\c@tikzumlStateLevel>0%
+ \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlStateDeepHistoryName)}%
+ \stepcounter{tikzumlStateSubStateNum}%
+ \fi%
+ \stepcounter{tikzumlStateDeepHistoryNum}%
+}%
+%
+% define a uml state
+% args : name of the state
+% content of the state
+% optional : x,y: coordinates of the state
+% width: width of the state node
+% name: name of the state node
+% entry, do, exit: entry/do/exit action of the state
+% draw, fill, text: colors
+% style: to manage every default TikZ option
+% no coords: to tell that the state position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newenvironment{umlstate}[2][]{%
+ \ifnum\thetikzumlStateLevel>0%
+ \let\tikzumlState@nameold\tikzumlState@fitname%
+ \let\tikzumlState@parentold\tikzumlState@parent%
+ \edef\tikzumlState@parent{\tikzumlState@parentold @@\tikzumlState@nameold}%
+ \else%
+ \def\tikzumlState@parent{}%
+ \fi%
+ %
+ \stepcounter{tikzumlStateLevel}%
+ %
+ \pgfkeys{/tikzuml/state/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateDefaultWidth,%
+ name/.initial={},%
+ entry/.initial={}, do/.initial={}, exit/.initial={},%
+ draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlStateDefaultFillColor,%
+ text/.initial=\tikzumlDefaultTextColor, style/.style={},%
+ no coords/.is if=tikzumlstateWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/state/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/state/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/state/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ % \errmessage{TIKZUML ERROR : in umlstate, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/state/.cd, #1}%
+ \pgfkeys{/tikzuml/state/.cd, x/.get=\tikzumlStateXShift, y/.get=\tikzumlStateYShift, width/.get=\tikzumlStateMinimumWidth, name/.get=\tikzumlStateName,%
+ entry/.get=\tikzumlStateEntry, do/.get=\tikzumlStateDo, exit/.get=\tikzumlStateExit,%
+ draw/.get=\tikzumlStateDrawColor, fill/.get=\tikzumlStateFillColor,%
+ text/.get=\tikzumlStateTextColor%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlStateName}{}}{%
+ \edef\tikzumlState@name{#2}%
+ }{%
+ \edef\tikzumlState@name{\tikzumlStateName}%
+ }%
+ %
+ \begingroup%
+ \def\_{@}\edef\x{\endgroup%
+ \def\noexpand\tikzumlState@fitname{\tikzumlState@name}}\x%
+ %
+ \let\tikzumlState@nodeNameold\tikzumlState@nodeName%
+ \def\tikzumlState@caption{#2}%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlState@nodeName{\tikzumlState@name}}\x%
+ %
+ \expandafter\gdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{}%
+ %
+ \setcounter{tikzumlStateSubStateNum}{0}%
+ \setcounter{tikzumlStateText}{0}%
+ %
+ \def\tikzumlStateText{tikzumlEmpty}%
+ \begin{scope}[xshift=\tikzumlStateXShift cm, yshift=\tikzumlStateYShift cm]%
+}{%
+ %
+ \def\tikzumlstaterootlabel{\phantom{\tikzumlState@nodeName}}%
+ %
+ \def\tikzumlstaterootinnerysep{0.5ex}%
+ \def\tikzumlstatebodyinnerysep{2ex}%
+ %
+ \ifthenelse{\equal{\tikzumlStateEntry}{}}{}{%
+ \ifnum\c@tikzumlStateText=0%
+ \def\tikzumlStateText{entry/\tikzumlStateEntry}%
+ \else%
+ \let\tikzumlStateTextOld\tikzumlStateText%
+ \ifthenelse{\equal{\tikzumlStateText}{tikzumlEmpty}}{%
+ \def\tikzumlStateText{entry/\tikzumlStateEntry}%
+ }{%
+ \expandafter\def\expandafter\tikzumlStateText\expandafter{\tikzumlStateTextOld \\ entry/\tikzumlStateEntry}%
+ }%
+ \fi%
+ \setcounter{tikzumlStateText}{1}%
+ \ifnum\c@tikzumlStateSubStateNum=0%
+ \def\tikzumlstatebodyinnerysep{0}%
+ \def\tikzumlstaterootinnerysep{0}%
+ \fi%
+ }%
+ \ifthenelse{\equal{\tikzumlStateDo}{}}{}{%
+ \ifnum\c@tikzumlStateText=0%
+ \def\tikzumlStateText{do/\tikzumlStateDo}%
+ \else%
+ \let\tikzumlStateTextOld\tikzumlStateText%
+ \ifthenelse{\equal{\tikzumlStateText}{tikzumlEmpty}}{%
+ \def\tikzumlStateText{do/\tikzumlStateDo}%
+ }{%
+ \expandafter\def\expandafter\tikzumlStateText\expandafter{\tikzumlStateTextOld \\ do/\tikzumlStateDo}%
+ }%
+ \fi%
+ \setcounter{tikzumlStateText}{1}%
+ \ifnum\c@tikzumlStateSubStateNum=0%
+ \def\tikzumlstatebodyinnerysep{0}%
+ \def\tikzumlstaterootinnerysep{0}%
+ \fi%
+ }%
+ \ifthenelse{\equal{\tikzumlStateExit}{}}{}{%
+ \ifnum\c@tikzumlStateText=0%
+ \def\tikzumlStateText{exit/\tikzumlStateExit}%
+ \else%
+ \let\tikzumlStateTextOld\tikzumlStateText%
+ \ifthenelse{\equal{\tikzumlStateText}{tikzumlEmpty}}{%
+ \def\tikzumlStateText{exit/\tikzumlStateExit}%
+ }{%
+ \expandafter\def\expandafter\tikzumlStateText\expandafter{\tikzumlStateTextOld \\ exit/\tikzumlStateExit}%
+ }%
+ \fi%
+ \setcounter{tikzumlStateText}{1}%
+ \ifnum\c@tikzumlStateSubStateNum=0%
+ \def\tikzumlstatebodyinnerysep{0}%
+ \def\tikzumlstaterootinnerysep{0}%
+ \fi%
+ }%
+ %
+ \addtocounter{tikzumlStateLevel}{-1}%
+ \begin{pgfonlayer}{state\thetikzumlStateLevel}%
+ %
+ % if contains nothing, one define a fictive node to enable the fit option
+ \ifnum\c@tikzumlStateSubStateNum=0%
+ \iftikzumlstateWithoutCoords%
+ \node[inner ysep=\tikzumlstaterootinnerysep, minimum width=\tikzumlStateMinimumWidth, /tikzuml/state/style] (\tikzumlState@nodeName-root) {\tikzumlstaterootlabel};%
+ \else%
+ \node[inner ysep=\tikzumlstaterootinnerysep, minimum width=\tikzumlStateMinimumWidth, /tikzuml/state/style] (\tikzumlState@nodeName-root) at (0,0) {\tikzumlstaterootlabel};%
+ \fi%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{(\tikzumlState@nodeName-root)}%
+ \fi%
+ %
+ \ifnum\c@tikzumlStateLevel>0%
+ \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent\endcsname{\tikzumlStateFitTmp (\tikzumlState@nodeName-body) (\tikzumlState@nodeName-caption)}%
+ \stepcounter{tikzumlStateSubStateNum}%
+ \fi%
+ %
+ \node[inner xsep=2ex, inner ysep=\tikzumlstatebodyinnerysep, fit = \csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname, /tikzuml/state/style ] (\tikzumlState@nodeName-body) {};%
+ \def\tikzumlState@orig{body}%
+ \ifnum\c@tikzumlStateText=1%
+ \node[above=0] (\tikzumlState@nodeName-texttmp) at (\tikzumlState@nodeName-\tikzumlState@orig.north) {\begin{tabular}{l}\tikzumlStateText \end{tabular}};%
+ \def\tikzumlState@orig{texttmp}%
+ \fi%
+ \node[above] (\tikzumlState@nodeName-captiontmp) at (\tikzumlState@nodeName-\tikzumlState@orig.north) {\tikzumlState@caption};%
+ \ifnum\c@tikzumlStateText=1%
+ \node[rounded corners, draw=\tikzumlStateDrawColor, fill=\tikzumlStateFillColor, name=\tikzumlState@nodeName, fit=(\tikzumlState@nodeName-body) (\tikzumlState@nodeName-texttmp) (\tikzumlState@nodeName-captiontmp)] {};%
+ \else%
+ \node[rounded corners, draw=\tikzumlStateDrawColor, fill=\tikzumlStateFillColor, name=\tikzumlState@nodeName, fit=(\tikzumlState@nodeName-body) (\tikzumlState@nodeName-captiontmp)] {};%
+ \fi%
+ \ifnum\c@tikzumlStateText=1%
+ \node (\tikzumlState@nodeName-text) at (\tikzumlState@nodeName-texttmp) {\begin{tabular}{l}\tikzumlStateText \end{tabular}};%
+ \fi%
+ \node (\tikzumlState@nodeName-caption) at (\tikzumlState@nodeName-captiontmp) {\tikzumlState@caption};%
+ \draw (\tikzumlState@nodeName-caption.south -| \tikzumlState@nodeName.north west) -- (\tikzumlState@nodeName-caption.south -| \tikzumlState@nodeName.north east);%
+ \end{pgfonlayer}%
+ \end{scope}%
+}%
+%
+% shortcut for empty state
+\newcommand{\umlbasicstate}[2][]{\begin{umlstate}[#1]{#2}\end{umlstate}}%
+%
+% command to add text in a state, to be used inside umlstate environment
+\newcommand{\umlstatetext}[1]{%
+ \def\tikzumlStateText{#1}%
+ \setcounter{tikzumlStateText}{1}%
+}%
+%
+% shortcuts for state transitions macros
+\newcommand{\umltrans}[3][]{%
+ \ifthenelse{\equal{#2}{#3}}{%
+ \umlrelation[style={tikzuml transition style}, recursive mode=transition, #1]{#2}{#3}%
+ }{%
+ \umlrelation[style={tikzuml transition style}, #1]{#2}{#3}%
+ }%
+}%
+\newcommand{\umlHVtrans}[3][]{\umlHVrelation[style={tikzuml transition style}, #1]{#2}{#3}}%
+\newcommand{\umlVHtrans}[3][]{\umlVHrelation[style={tikzuml transition style}, #1]{#2}{#3}}%
+\newcommand{\umlVHVtrans}[3][]{\umlVHVrelation[style={tikzuml transition style}, #1]{#2}{#3}}%
+\newcommand{\umlHVHtrans}[3][]{\umlHVHrelation[style={tikzuml transition style}, #1]{#2}{#3}}%
+\newcommand{\umlCNtrans}[4][]{\umlCNrelation[style={tikzuml transition style}, #1]{#2}{#3}{#4}}%
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% sequence diagrams %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+\tikzstyle{tikzuml synchron-msg style}=[color=\tikzumlDefaultDrawColor, -triangle 45]%
+\tikzstyle{tikzuml asynchron-msg style}=[color=\tikzumlDefaultDrawColor, -angle 45]%
+\tikzstyle{tikzuml return-msg style}=[color=\tikzumlDefaultDrawColor, dashed, -angle 45]%
+\tikzstyle{tikzuml call return style}=[color=\tikzumlDefaultDrawColor, dashed, -angle 45]%
+\tikzstyle{tikzuml activity style}=[inner xsep=1ex, inner ysep=1ex]%
+%
+\newcounter{tikzumlObjectNum}%
+\newcounter{tikzumlCallLevel}%
+\newcounter{tikzumlCallNum}%
+\newcounter{tikzumlFragmentLevel}%
+\newcounter{tikzumlFragmentLevelNum}%
+\newcounter{tikzumlFragmentNum}%
+\newcounter{tikzumlFragmentPartNum}%
+\newcounter{tikzumlCallStartFragmentNum}%
+\newcounter{tikzumlCallEndFragmentNum}%
+%
+\newif\iftikzumlobjectNoDDots%
+\newif\iftikzumlcreatecallNoDDots%
+%
+% define a sequence diagram
+%
+\newenvironment{umlseqdiag}{%
+ \gdef\tikzumlInCreateCall{0}%
+ \setcounter{tikzumlObjectNum}{0}%
+ \setcounter{tikzumlCallLevel}{0}%
+ \setcounter{tikzumlCallNum}{0}%
+ \setcounter{tikzumlFragmentLevel}{0}%
+ \setcounter{tikzumlFragmentLevelNum}{0}%
+ \setcounter{tikzumlFragmentNum}{0}%
+ \setcounter{tikzumlFragmentPartNum}{0}%
+ \setcounter{tikzumlCallStartFragmentNum}{0}%
+ \setcounter{tikzumlCallEndFragmentNum}{0}%
+ %
+ \ifx \@umlactor \@empty
+ \newcommand{\umlactor}[2][]{%
+ \pgfkeys{/tikzuml/actorobj/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlactor, forbidden option stereo}%
+ }{}%
+ }%
+ }%
+ %
+ \pgfkeys{/tikzuml/actorobj/.cd, ##1}%
+ \umlobject[stereo=actor, ##1]{##2}%
+ }%
+ \else%
+ \renewcommand{\umlactor}[2][]{%
+ \pgfkeys{/tikzuml/actorobj/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlactor, forbidden option stereo}%
+ }{}%
+ }%
+ }%
+ %
+ \pgfkeys{/tikzuml/actorobj/.cd, ##1}%
+ \umlobject[stereo=actor, ##1]{##2}%
+ }%
+ \fi%
+ \begin{scope}[font=\tikzumlDefaultFont]%
+}{%
+ % draw lifelines of each object
+ \begin{pgfonlayer}{lifelines}%
+ \foreach \id in \tikzumlIdList {%
+ \draw (\csname tikzumlLastChild@\id \endcsname)+(0,-2.5ex) node[inner sep=0, name=end-\id] {};%
+ \draw[dotted] (\id) -- (end-\id);%
+ }%
+ \end{pgfonlayer}%
+ \end{scope}%
+}%
+%
+% define the database symbol
+% optional : global tikzpicture styles
+\newcommand{\pictureddatabase}[1]{%
+ \pgfkeys{/tikzuml/database/.cd, scale/.initial=1, .unknown/.code={}}%
+ \pgfkeys{/tikzuml/database/.cd,#1}%
+ \pgfkeys{/tikzuml/database/.cd, scale/.get=\tikzumlDatabaseScale}%
+ %
+ \begin{tikzpicture}[#1]%
+ \node[fill, draw, ellipse, minimum width=\tikzumlDatabaseScale*4ex, minimum height=\tikzumlDatabaseScale*2ex, inner sep=0] (bottom) at (0,-2ex) {};%
+ \node[fill, draw, ellipse, minimum width=\tikzumlDatabaseScale*4ex, minimum height=\tikzumlDatabaseScale*2ex, inner sep=0] (top) at (0,4ex) {};%
+ \fill (bottom.west) rectangle (top.east);%
+ \begin{scope}%
+ \clip (-3.5ex,-0.5ex) rectangle (3.5ex,2.5ex);%
+ \node[draw, dashed, ellipse, minimum width=\tikzumlDatabaseScale*4ex, minimum height=\tikzumlDatabaseScale*2ex, inner sep=0] (bottom2) at (0,-2ex) {};%
+ \end{scope}%
+ \node[draw, ellipse, minimum width=\tikzumlDatabaseScale*4ex, minimum height=\tikzumlDatabaseScale*2ex, inner sep=0] (top2) at (0,4ex) {};%
+ \draw (bottom.west) -- (top.west) (bottom.east) -- (top.east);%
+ \end{tikzpicture}%
+}%
+%
+% define the entity symbol
+% optional : global tikzpicture styles
+\newcommand{\picturedentity}[1]{%
+ \pgfkeys{/tikzuml/entity/.cd, scale/.initial=1, .unknown/.code={}}%
+ \pgfkeys{/tikzuml/entity/.cd,#1}%
+ \pgfkeys{/tikzuml/entity/.cd, scale/.get=\tikzumlEntityScale}%
+ %
+ \begin{tikzpicture}[#1]%
+ \node[fill, draw, circle, inner sep=0, minimum size=\tikzumlEntityScale*5ex] (center) at (0,0) {};%
+ \draw (center.south) node[coordinate, name=bottom] {};%
+ \draw (bottom)+(-2ex,0) node[coordinate, name=bottom-left] {};%
+ \draw (bottom)+(2ex,0) node[coordinate, name=bottom-right] {};%
+ \draw (center) -- (bottom);%
+ \draw (bottom-left) -- (bottom-right);%
+ \end{tikzpicture}%
+}%
+%
+% define the boundary symbol
+% optional : global tikzpicture styles
+\newcommand{\picturedboundary}[1]{%
+ \pgfkeys{/tikzuml/boundary/.cd, scale/.initial=1, .unknown/.code={}}%
+ \pgfkeys{/tikzuml/boundary/.cd,#1}%
+ \pgfkeys{/tikzuml/boundary/.cd, scale/.get=\tikzumlBoundaryScale}%
+ %
+ \begin{tikzpicture}[#1]
+ \node[fill, draw, circle, inner sep=0, minimum size=\tikzumlBoundaryScale*5ex] (center) at (0,0) {};
+ \draw (center.west)+(-0.8ex,0) node[coordinate, name=left] {};
+ \draw (left)+(0,0.2ex) node[coordinate, name=left-top] {};
+ \draw (left)+(0,-0.2ex) node[coordinate, name=left-bottom] {};
+ \draw (center) -- (left);
+ \draw (left-top) -- (left-bottom);
+ \end{tikzpicture}
+}%
+%
+% define the control symbol
+% optional : global tikzpicture styles
+\newcommand{\picturedcontrol}[1]{%
+ \pgfkeys{/tikzuml/control/.cd, scale/.initial=1, .unknown/.code={}}%
+ \pgfkeys{/tikzuml/control/.cd,#1}%
+ \pgfkeys{/tikzuml/control/.cd, scale/.get=\tikzumlControlScale}%
+ %
+ \begin{tikzpicture}[#1, decoration={markings, mark=at position 0.25 with {\arrow{>}}}]
+ \node[fill, draw, circle, inner sep=0, minimum size=\tikzumlControlScale*5ex, postaction={decorate}] (center) at (0,0) {};
+ \end{tikzpicture}
+}%
+%
+% define a uml object for a sequence diagram
+% args : name of the object
+% optional : x, y: coordinates of the object
+% stereo: stereotype of the object (object, actor, database, boundary, control, entity, multiobject)
+% class: class of the object
+% scale: scale factor of the object symbol
+% draw, fill, text; colors
+% no ddots: when used, disable printing of double dots
+\newcommand{\umlobject}[2][]{
+ \stepcounter{tikzumlObjectNum}%
+ %
+ \edef\tikzumlobject@ddot{:}%
+ \pgfkeys{/tikzuml/obj/.cd, x/.initial=tikzumlEmpty, y/.initial=\tikzumlDefaultX, stereo/.initial=\tikzumlObjectDefaultStereo,%
+ class/.initial={}, scale/.initial=1,%
+ draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlObjectDefaultFillColor,%
+ text/.initial=\tikzumlDefaultTextColor,%
+ no ddots/.is if=tikzumlobjectNoDDots,%
+ no ddots=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \errmessage{TIKZUML ERROR : in umlobject, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/obj/.cd, #1}%
+ \pgfkeys{/tikzuml/obj/.cd, x/.get=\tikzumlObjectX, y/.get=\tikzumlObjectY,%
+ stereo/.get=\tikzumlObjectStereo, class/.get=\tikzumlObjectClass,%
+ scale/.get=\tikzumlObjectScale,%
+ draw/.get=\tikzumlObjectDrawColor, fill/.get=\tikzumlObjectFillColor,%
+ text/.get=\tikzumlObjectTextColor%
+ }%
+ %
+ \iftikzumlobjectNoDDots%
+ \edef\tikzumlobject@ddot{}%
+ \fi%
+ %
+ \ifthenelse{\equal{\tikzumlObjectX}{tikzumlEmpty}}{%
+ \pgfmathsetmacro{\tikzumlObjectX}{4*(\thetikzumlObjectNum-1)}%
+ }{}%
+ %
+ \def\tikzumlObjectName{#2}%
+ \expandafter\xdef\csname tikzumlLastChild@\tikzumlObjectName \endcsname{\tikzumlObjectName}%
+ %
+ \ifnum\thetikzumlObjectNum=1%
+ \xdef\tikzumlIdList{\tikzumlObjectName}%
+ \else%
+ \let\tikzumlIdListOld\tikzumlIdList%
+ \expandafter\xdef\expandafter\tikzumlIdList\expandafter{\tikzumlIdListOld,\tikzumlObjectName}%
+ \fi%
+ %
+ \tikzstyle{tikzuml object box style}=[rectangle, text=\tikzumlObjectTextColor, font=\tikzumlDefaultFont]%
+ %
+ \ifthenelse{\equal{\tikzumlObjectStereo}{object}}{%
+ \tikzstyle{tikzuml object box style}+=[draw=\tikzumlObjectDrawColor, fill=\tikzumlObjectFillColor]%
+ }{%
+ \ifthenelse{\equal{\tikzumlObjectStereo}{multi}}{%
+ \tikzstyle{tikzuml object box style}+=[fill=\tikzumlObjectFillColor]%
+ }{}%
+ }%
+ %
+ \ifnum\tikzumlInCreateCall=1%
+ \draw (\tikzumlCreateCallObjectSrc -| \tikzumlObjectX,0) node[tikzuml object box style] (\tikzumlObjectName) {\tikzumlObjectName\tikzumlobject@ddot\tikzumlObjectClass};%
+ \else%
+ \node[tikzuml object box style] (\tikzumlObjectName) at (\tikzumlObjectX,\tikzumlObjectY) {\tikzumlObjectName\tikzumlobject@ddot\tikzumlObjectClass};%
+ \fi%
+ %
+ \ifthenelse{\equal{\tikzumlObjectStereo}{multi}}{%
+ \draw (\tikzumlObjectName.north east)+(0.4ex,0.4ex) node[name=\tikzumlObjectName-tr, coordinate] {};
+ \draw (\tikzumlObjectName.north west)+(0.4ex,0.4ex) node[name=\tikzumlObjectName-tl, coordinate] {};
+ \draw (\tikzumlObjectName.south east)+(0.4ex,0.4ex) node[name=\tikzumlObjectName-br, coordinate] {};
+ \draw (\tikzumlObjectName-tr)+(0.4ex,0.4ex) node[name=\tikzumlObjectName-ttr, coordinate] {};
+ \draw (\tikzumlObjectName-tl)+(0.4ex,0.4ex) node[name=\tikzumlObjectName-ttl, coordinate] {};
+ \draw (\tikzumlObjectName-br)+(0.4ex,0.4ex) node[name=\tikzumlObjectName-tbr, coordinate] {};
+ \fill[fill=\tikzumlObjectFillColor] (\tikzumlObjectName-ttl |- \tikzumlObjectName.north) -- (\tikzumlObjectName-ttl) -- (\tikzumlObjectName-ttr) -- (\tikzumlObjectName-tbr) -- (\tikzumlObjectName-tbr -| \tikzumlObjectName.east) -- (\tikzumlObjectName.north east) -- (\tikzumlObjectName-ttl |- \tikzumlObjectName.north);
+ \draw[draw=\tikzumlObjectDrawColor] (\tikzumlObjectName-ttl |- \tikzumlObjectName.north) -- (\tikzumlObjectName-ttl) -- (\tikzumlObjectName-ttr) -- (\tikzumlObjectName-tbr) -- (\tikzumlObjectName-tbr -| \tikzumlObjectName.east);
+ \fill[fill=\tikzumlObjectFillColor] (\tikzumlObjectName-tl |- \tikzumlObjectName.north) -- (\tikzumlObjectName-tl) -- (\tikzumlObjectName-tr) -- (\tikzumlObjectName-br) -- (\tikzumlObjectName-br -| \tikzumlObjectName.east) -- (\tikzumlObjectName.north east) -- (\tikzumlObjectName-tl |- \tikzumlObjectName.north);
+ \draw[draw=\tikzumlObjectDrawColor] (\tikzumlObjectName-tl |- \tikzumlObjectName.north) -- (\tikzumlObjectName-tl) -- (\tikzumlObjectName-tr) -- (\tikzumlObjectName-br) -- (\tikzumlObjectName-br -| \tikzumlObjectName.east);
+ \draw[draw=\tikzumlObjectDrawColor] (\tikzumlObjectName.north west) rectangle (\tikzumlObjectName.south east);
+ }{%
+ \ifthenelse{\equal{\tikzumlObjectStereo}{object}}{}{%
+ \node[above=1ex, name=\tikzumlObjectName-picture] at (\tikzumlObjectName) {\csname pictured\tikzumlObjectStereo \endcsname{draw=\tikzumlObjectDrawColor, fill=\tikzumlObjectFillColor, scale=\tikzumlObjectScale}};
+ }%
+ }%
+}%
+%
+% shortcuts for objects
+\newcommand{\umlbasicobject}[2][]{%
+ \pgfkeys{/tikzuml/basicobj/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{no ddots}}{%
+ \errmessage{TIKZUML ERROR : in umlbasicobject, forbidden option no ddots}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/basicobj/.cd, #1}%
+ \umlobject[no ddots, #1]{#2}%
+}%
+%
+\newcommand{\umldatabase}[2][]{%
+ \pgfkeys{/tikzuml/databaseobj/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umldatabase, forbidden option stereo}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/databaseobj/.cd, #1}%
+ \umlobject[stereo=database, #1]{#2}%
+}%
+\newcommand{\umlentity}[2][]{%
+ \pgfkeys{/tikzuml/entityobj/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlentity, forbidden option stereo}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/entityobj/.cd, #1}%
+ \umlobject[stereo=entity, #1]{#2}%
+}%
+\newcommand{\umlcontrol}[2][]{%
+ \pgfkeys{/tikzuml/controlobj/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlcontrol, forbidden option stereo}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/controlobj/.cd, #1}%
+ \umlobject[stereo=control, #1]{#2}%
+}%
+\newcommand{\umlboundary}[2][]{%
+ \pgfkeys{/tikzuml/boundaryobj/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlboundary, forbidden option stereo}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/boundaryobj/.cd, #1}%
+ \umlobject[stereo=boundary, #1]{#2}%
+}%
+\newcommand{\umlmulti}[2][]{%
+ \pgfkeys{/tikzuml/multiobj/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlmulti, forbidden option stereo}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/multiobj/.cd, #1}%
+ \umlobject[stereo=multi, #1]{#2}%
+}%
+%
+\newcounter{tikzumlSDNodeNum}%
+%
+% define a hidden node to lengthen lifeline of a object
+% args : object node
+% optional : dt: distance between the sdnode and the last call defined on the lifeline of the object
+% name: name of the sdnode
+\newcommand{\umlsdnode}[2][]{%
+ \pgfkeys{/tikzuml/sdnode/.cd, dt/.initial=0, name/.initial=tikzumlEmpty}%
+ \pgfkeys{/tikzuml/sdnode/.cd, #1}%
+ \pgfkeys{/tikzuml/sdnode/.cd, dt/.get=\tikzumlSDNodeDT, name/.get=\tikzumlSDNodeName}%
+ %
+ \ifthenelse{\equal{\tikzumlSDNodeName}{tikzumlEmpty}}{%
+ \expandafter\def\expandafter\tikzumlSDNode@nodeName{sdnode-\thetikzumlSDNodeNum}%
+ }{%
+ \expandafter\def\expandafter\tikzumlSDNode@nodeName{\tikzumlSDNodeName}%
+ }%
+ %
+ \stepcounter{tikzumlSDNodeNum}%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlSDNode@objnodeName{#2}}\x%
+ %
+ \draw (\expandafter\csname tikzumlLastChild@\tikzumlSDNode@objnodeName \endcsname)+(0,-\tikzumlSDNodeDT ex) node[name=\tikzumlSDNode@nodeName,coordinate] {};%
+ %
+ % update last node drawn on sender lifeline
+ \expandafter\xdef\csname tikzumlLastChild@\tikzumlSDNode@objnodeName \endcsname{\tikzumlSDNode@nodeName}%
+}%
+%
+\newlength{\tikzumlCall@xa}%
+\newlength{\tikzumlCall@xb}%
+%
+% define a uml operation call for sequence diagrams
+% args : call sender
+% call receiver
+% optional : dt: time delay from precedent event end
+% name: name of the call
+% op: operation name and input args
+% return: return value
+% type: type of the call (synchron, asynchron)
+% draw, fill, text: colors
+% padding: time padding from call start and to call end
+\newenvironment{umlcall}[3][]{%
+ \stepcounter{tikzumlCallNum}%
+ \def\tikzumlCallWithReturn{tikzumlFalse}%
+ \edef\tikzumlCall@lastchildNum{\thetikzumlCallNum}% for testing presence of sub-calls
+ \gdef\tikzumlCallBottom{0}%
+ %
+ \pgfkeys{/tikzuml/call/.cd, dt/.initial=\tikzumlCallDefaultDT, name/.initial={call-\thetikzumlCallNum},%
+ op/.initial={}, return/.initial={}, type/.initial=\tikzumlCallDefaultType,%
+ draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlCallDefaultFillColor,%
+ text/.initial=\tikzumlDefaultTextColor,%
+ padding/.initial=\tikzumlCallDefaultPadding,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{with return}}{%
+ \def\tikzumlCallWithReturn{tikzumlTrue}%
+ }{%
+ \errmessage{TIKZUML ERROR : in umlcall, invalid option \keyname}%
+ }%
+ }%
+ }%
+ \pgfkeys{/tikzuml/call/.cd, #1}%
+ \pgfkeys{/tikzuml/call/.cd, dt/.get=\tikzumlCallDT, name/.get=\tikzumlCallName, op/.get=\tikzumlCallOp,%
+ return/.get=\tikzumlCallReturn, type/.get=\tikzumlCallType,%
+ padding/.get=\tikzumlCallPadding,%
+ draw/.get=\tikzumlCallDrawColor, fill/.get=\tikzumlCallFillColor,%
+ text/.get=\tikzumlCallTextColor%
+ }%
+ %
+ \edef\tikzumlfillcall{\tikzumlCallFillColor}%
+ \edef\tikzumldrawcall{\tikzumlCallDrawColor}%
+ \edef\tikzumltextcall{\tikzumlCallTextColor}%
+ \edef\tikzumltypecall{\tikzumlCallType}%
+ %
+ \ifthenelse{\equal{\tikzumlCallDT}{tikzumlEmpty}}{%
+ \ifnum\thetikzumlCallNum=1%
+ \def\tikzumlCallDT{2}%
+ \def\tikzumlcallSrc{2}%
+ \else%
+ \def\tikzumlCallDT{2}%
+ \def\tikzumlcallSrc{1}%
+ \fi%
+ }{%
+ \def\tikzumlcallSrc{0}%
+ }%
+ %
+ \let\tikzumlCallStartNodeNameold\tikzumlCallStartNodeName%
+ \def\tikzumlCallStartNodeName{#2}%
+ \let\tikzumlCallEndNodeNameold\tikzumlCallEndNodeName%
+ \def\tikzumlCallEndNodeName{#3}%
+ \def\tikzumlcallheight{\tikzumlCallPadding}%
+ %
+ % managing time delays from previous/parent fragments
+ \ifnum\thetikzumlCallStartFragmentNum>0%
+ \let\tikzumlCallDTold\tikzumlCallDT%
+ \pgfmathparse{0.5*\tikzumlFragment@paddingy+\tikzumlCallDTold}%
+ \edef\tikzumlCallDT{\pgfmathresult}%
+ \addtocounter{tikzumlCallStartFragmentNum}{-1}
+ \fi%
+ \ifnum\thetikzumlCallEndFragmentNum>0%
+ \let\tikzumlCallDTold\tikzumlCallDT%
+ \pgfmathparse{0.5*\tikzumlFragment@paddingy+\tikzumlCallDTold}%
+ \edef\tikzumlCallDT{\pgfmathresult}%
+ \addtocounter{tikzumlCallEndFragmentNum}{-1}
+ \fi%
+ \ifnum\thetikzumlFragmentPartNum>0%
+ \let\tikzumlCallDTold\tikzumlCallDT%
+ \pgfmathparse{0.5*\tikzumlFragment@paddingy+\tikzumlCallDTold}%
+ \edef\tikzumlCallDT{\pgfmathresult}%
+ \fi%
+ %
+ % managing parent-child structure
+ \ifnum\thetikzumlCallLevel>0%
+ \let\tikzumlCall@nameold\tikzumlCall@name%
+ \edef\tikzumlCall@name{\tikzumlCallName}%
+ \let\tikzumlCall@parentold\tikzumlCall@parent%
+ \edef\tikzumlCall@parent{\tikzumlCall@parentold @@\tikzumlCall@nameold}%
+ \else%
+ \edef\tikzumlCall@parent{}%
+ \edef\tikzumlCall@parentold{}%
+ \edef\tikzumlCall@nameold{}
+ \edef\tikzumlCall@name{\tikzumlCallName}%
+ \fi%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlCall@nodeName{\tikzumlCall@name}}\x%
+ %
+ \let\tikzumlCall@nodeNameold\tikzumlCall@nodeName%
+ %
+ \def\tikzumlcallstyle{tikzuml \tikzumlCallType-msg style}%
+ %
+ % top node of activity period of call sender
+ \begin{pgfonlayer}{connections}%
+ \pgfmathparse{\tikzumlCallDT+\tikzumlcallSrc}%
+ \draw (\csname tikzumlLastChild@\tikzumlCallStartNodeName \endcsname)+(0,-\pgfmathresult ex) node[coordinate, name=tikzumlTmpNode] {};%
+ \node[tikzuml activity style] (st-\tikzumlCall@nodeName) at (\tikzumlCallStartNodeName |- tikzumlTmpNode) {};%
+ %
+ % update last node drawn on sender lifeline
+ \expandafter\xdef\csname tikzumlLastChild@\tikzumlCallStartNodeName \endcsname{st-\tikzumlCall@nodeName}%
+ %
+ % top node of activity period of call receiver
+ \ifstrequal{\tikzumlCallStartNodeName}{\tikzumlCallEndNodeName}{%
+ \draw (st-\tikzumlCall@nodeName)+(0,-0.75*\tikzumlCallPadding ex) node[coordinate, name=tikzumlTmpNode] {};%
+ \node[tikzuml activity style] (et-\tikzumlCall@nodeName) at (\tikzumlCallStartNodeName |- tikzumlTmpNode) {};%
+ }{%
+ \node[tikzuml activity style] (et-\tikzumlCall@nodeName) at (\tikzumlCallEndNodeName |- st-\tikzumlCall@nodeName) {};%
+ }%
+ %
+ % update last node drawn on receiver lifeline
+ \expandafter\xdef\csname tikzumlLastChild@\tikzumlCallEndNodeName \endcsname{et-\tikzumlCall@nodeName}%
+ \xdef\tikzumlCallBottomSrc{et-\tikzumlCall@nodeName}%
+ \end{pgfonlayer}%
+ %
+ \stepcounter{tikzumlCallLevel}%
+}{%
+ \addtocounter{tikzumlCallLevel}{-1}%
+ %
+ % bottom nodes of activity periods of call sender and receiver
+ \begin{pgfonlayer}{connections}%
+ \ifnum\tikzumlCall@lastchildNum=\thetikzumlCallNum%
+ %
+ % this test occurs a bug with latex package preview
+ \ifstrequal{\tikzumlCallStartNodeName}{\tikzumlCallEndNodeName}{%
+ \draw (\tikzumlCallBottomSrc)+(0,-\tikzumlCallPadding ex) node[coordinate, name=tikzumlTmpNode] {};%
+ \node[tikzuml activity style] (eb-\tikzumlCall@nodeName) at (\tikzumlCallEndNodeName |- tikzumlTmpNode) {};%
+ \draw (eb-\tikzumlCall@nodeName)+(0,-0.75*\tikzumlCallPadding ex) node[coordinate, name=tikzumlTmpNode] {};%
+ \node[tikzuml activity style] (sb-\tikzumlCall@nodeName) at (\tikzumlCallStartNodeName |- tikzumlTmpNode) {};%
+ }{%
+ \ifthenelse{\equal{\tikzumlCallReturn}{tikzumlEmpty}}{%
+ \pgfmathsetmacro{\tikzumlCallPaddingd}{0.5*\tikzumlCallPadding}%
+ }{%
+ \pgfmathsetmacro{\tikzumlCallPaddingd}{1.2*\tikzumlCallPadding}%
+ }%
+ \draw (\tikzumlCallBottomSrc)+(0,-\tikzumlCallPaddingd ex) node[coordinate, name=tikzumlTmpNode] {};%
+ \node[tikzuml activity style] (eb-\tikzumlCall@nodeName) at (\tikzumlCallEndNodeName |- tikzumlTmpNode) {};%
+ \node[tikzuml activity style] (sb-\tikzumlCall@nodeName) at (\tikzumlCallStartNodeName |- eb-\tikzumlCall@nodeName) {};%
+ }%
+ \xdef\tikzumlCallBottomSrc{sb-\tikzumlCall@nodeName}%
+ \else%
+ %
+ % managing time delays from previous/parent fragments
+ \ifnum\thetikzumlCallStartFragmentNum>0%
+ \let\tikzumlcallheightold\tikzumlCallPadding%
+ \pgfmathparse{\tikzumlcallheightold+0.5*\tikzumlFragment@paddingy}%
+ \edef\tikzumlcallheight{\pgfmathresult}%
+ \addtocounter{tikzumlCallStartFragmentNum}{-1}%
+ \fi%
+ \ifnum\thetikzumlCallEndFragmentNum>0%
+ \let\tikzumlcallheightold\tikzumlCallPadding%
+ \pgfmathparse{\tikzumlcallheightold+0.5*\tikzumlFragment@paddingy}%
+ \edef\tikzumlcallheight{\pgfmathresult}%
+ \addtocounter{tikzumlCallEndFragmentNum}{-1}%
+ \fi%
+ %
+ \ifstrequal{\tikzumlCallStartNodeName}{\tikzumlCallEndNodeName}{%
+ \draw (\tikzumlCallBottomSrc)+(0,-\tikzumlcallheight ex) node[coordinate, name=tikzumlTmpNode] {};%
+ \node[tikzuml activity style] (eb-\tikzumlCall@nodeName) at (\tikzumlCallEndNodeName |- tikzumlTmpNode) {};%
+ \draw (eb-\tikzumlCall@nodeName)+(0,-0.75*\tikzumlCallPadding ex) node[coordinate, name=tikzumlTmpNode] {};%
+ \node[tikzuml activity style] (sb-\tikzumlCall@nodeName) at (\tikzumlCallStartNodeName |- tikzumlTmpNode) {};%
+ }{%
+ \draw (\tikzumlCallBottomSrc)+(0,-\tikzumlcallheight ex) node[coordinate, name=tikzumlTmpNode] {};%
+ \node[tikzuml activity style] (eb-\tikzumlCall@nodeName) at (\tikzumlCallEndNodeName |- tikzumlTmpNode) {};%
+ \node[tikzuml activity style] (sb-\tikzumlCall@nodeName) at (\tikzumlCallStartNodeName |- eb-\tikzumlCall@nodeName) {};%
+ }%
+ %
+ \xdef\tikzumlCallBottomSrc{sb-\tikzumlCall@nodeName}%
+ \fi%
+ \end{pgfonlayer}%
+ %
+ % draw activity periods
+ \begin{pgfonlayer}{activity}%
+ \ifstrequal{\tikzumlCallStartNodeName}{\tikzumlCallEndNodeName}{%
+ % draw root activity period only
+ \ifnum\thetikzumlCallLevel=0%
+ \draw[draw=\tikzumldrawcall, fill=\tikzumlfillcall] (st-\tikzumlCall@nodeName.north west) rectangle (sb-\tikzumlCall@nodeName.south east);%
+ \else%
+ % draw root activity from inner call
+ \ifthenelse{\equal{\tikzumlCallStartNodeName}{\tikzumlCallEndNodeNameold}}{}{%
+ \draw[draw=\tikzumldrawcall, fill=\tikzumlfillcall] (st-\tikzumlCall@nodeName.north west) rectangle (sb-\tikzumlCall@nodeName.south east);%
+ }%
+ \fi%
+ }{%
+ % draw root activity period
+ \ifnum\thetikzumlCallLevel=0%
+ \draw[draw=\tikzumldrawcall, fill=\tikzumlfillcall] (st-\tikzumlCall@nodeName.north west) rectangle (sb-\tikzumlCall@nodeName.south east);%
+ \else%
+ % draw root activity from inner call
+ \ifthenelse{\equal{\tikzumlCallStartNodeName}{\tikzumlCallEndNodeNameold}}{}{%
+ \draw[draw=\tikzumldrawcall, fill=\tikzumlfillcall] (st-\tikzumlCall@nodeName.north west) rectangle (sb-\tikzumlCall@nodeName.south east);%
+ }%
+ \fi%
+ % draw receiver activity period
+ \draw[draw=\tikzumldrawcall, fill=\tikzumlfillcall] (et-\tikzumlCall@nodeName.north west) rectangle (eb-\tikzumlCall@nodeName.south east);%
+ }%
+ \end{pgfonlayer}%
+ \ifthenelse{\equal{\tikzumlCallDefaultFillColor}{\tikzumlCallFillColor}}{}{%
+ \fill[\tikzumlfillcall] (st-\tikzumlCall@nodeName.north west) rectangle (sb-\tikzumlCall@nodeName.south east);%
+ \draw[\tikzumldrawcall] (st-\tikzumlCall@nodeName.north west) rectangle (sb-\tikzumlCall@nodeName.south west) (st-\tikzumlCall@nodeName.north east) rectangle (sb-\tikzumlCall@nodeName.south east);%
+ }%
+ %
+ % update last nodes drawn on sender and receiver lifelines
+ \expandafter\xdef\csname tikzumlLastChild@\tikzumlCallEndNodeName \endcsname{eb-\tikzumlCall@nodeName}%
+ \expandafter\xdef\csname tikzumlLastChild@\tikzumlCallStartNodeName \endcsname{sb-\tikzumlCall@nodeName}%
+ %
+ % draw call arrows
+ \begin{pgfonlayer}{connections}%
+ \ifstrequal{\tikzumlCallStartNodeName}{\tikzumlCallEndNodeName}{%
+ \draw[\tikzumlcallstyle, \tikzumldrawcall] (st-\tikzumlCall@nodeName.east) -- ++(2.5*\tikzumlCallPadding ex,0) %
+ -- ++(0,-0.75*\tikzumlCallPadding ex) %
+ node[font=\tikzumlDefaultFont, text=\tikzumltextcall, midway, right, name=\tikzumlCall@nodeName-op] {\tikzumlCallOp} %
+ -- (et-\tikzumlCall@nodeName.east);%
+ %
+ % draw return arrow and update fit for parent fragment
+ \ifthenelse{\equal{\tikzumltypecall}{synchron}}{%
+ \ifthenelse{\NOT\equal{\tikzumlCallReturn}{}\OR\equal{\tikzumlCallWithReturn}{tikzumlTrue}}{%
+ \ifnum\c@tikzumlFragmentLevel>0%
+ \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname}%
+ \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{\tikzumlFragmentFitOld (st-\tikzumlCall@nodeName) (et-\tikzumlCall@nodeName) (eb-\tikzumlCall@nodeName) (sb-\tikzumlCall@nodeName) (\tikzumlCall@nodeName-op) (\tikzumlCall@nodeName-return)}%
+ \fi%
+ %
+ \draw[tikzuml call return style, \tikzumldrawcall] (eb-\tikzumlCall@nodeName.east) -- ++(2.5*\tikzumlCallPadding ex,0)
+ -- ++(0,-0.75*\tikzumlCallPadding ex) %
+ node[font=\tikzumlDefaultFont, text=\tikzumltextcall, midway, right, name=\tikzumlCall@nodeName-return] {\tikzumlCallReturn} %
+ -- (sb-\tikzumlCall@nodeName.east);%
+ }{%
+ \ifnum\c@tikzumlFragmentLevel>0%
+ \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname}%
+ \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{\tikzumlFragmentFitOld (st-\tikzumlCall@nodeName) (et-\tikzumlCall@nodeName) (eb-\tikzumlCall@nodeName) (sb-\tikzumlCall@nodeName) (\tikzumlCall@nodeName-op)}%
+ \fi%
+ }%
+ }{%
+ \ifnum\c@tikzumlFragmentLevel>0%
+ \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname}%
+ \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{\tikzumlFragmentFitOld (st-\tikzumlCall@nodeName) (et-\tikzumlCall@nodeName) (eb-\tikzumlCall@nodeName) (sb-\tikzumlCall@nodeName) (\tikzumlCall@nodeName-op)}%
+ \fi%
+ }%
+ }{%
+ % draw call arrows
+ \pgfextractx{\tikzumlCall@xa}{\pgfpointanchor{\tikzumlCallStartNodeName}{center}}%
+ \pgfextractx{\tikzumlCall@xb}{\pgfpointanchor{\tikzumlCallEndNodeName}{center}}%
+ %
+ \ifthenelse{\tikzumlCall@xb>\tikzumlCall@xa}{%
+ \draw[\tikzumlcallstyle, \tikzumldrawcall] (st-\tikzumlCall@nodeName.east) -- (et-\tikzumlCall@nodeName.west) %
+ node[font=\tikzumlDefaultFont, text=\tikzumltextcall, midway, above=-0.4ex, name=\tikzumlCall@nodeName-op] {\tikzumlCallOp};%
+ }{%
+ \draw[\tikzumlcallstyle, \tikzumldrawcall] (st-\tikzumlCall@nodeName.west) -- (et-\tikzumlCall@nodeName.east) %
+ node[font=\tikzumlDefaultFont, text=\tikzumltextcall, midway, above=-0.4ex, name=\tikzumlCall@nodeName-op] {\tikzumlCallOp};%
+ }%
+ %
+ % draw return arrow and update fit for parent fragment
+ \ifthenelse{\equal{\tikzumltypecall}{synchron}}{%
+ \ifthenelse{\NOT\equal{\tikzumlCallReturn}{}\OR\equal{\tikzumlCallWithReturn}{tikzumlTrue}}{%
+ \ifnum\c@tikzumlFragmentLevel>0%
+ \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname}%
+ \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{\tikzumlFragmentFitOld (st-\tikzumlCall@nodeName) (et-\tikzumlCall@nodeName) (eb-\tikzumlCall@nodeName) (sb-\tikzumlCall@nodeName) (\tikzumlCall@nodeName-op) (\tikzumlCall@nodeName-return)}%
+ \fi%
+ %
+ \ifthenelse{\tikzumlCall@xb>\tikzumlCall@xa}{%
+ \draw[tikzuml call return style, \tikzumldrawcall] (eb-\tikzumlCall@nodeName.west) -- (sb-\tikzumlCall@nodeName.east) %
+ node[font=\tikzumlDefaultFont, text=\tikzumltextcall, midway, above=-0.4ex, name=\tikzumlCall@nodeName-return] {\tikzumlCallReturn};%
+ }{%
+ \draw[tikzuml call return style, \tikzumldrawcall] (eb-\tikzumlCall@nodeName.east) -- (sb-\tikzumlCall@nodeName.west) %
+ node[font=\tikzumlDefaultFont, text=\tikzumltextcall, midway, above=-0.4ex, name=\tikzumlCall@nodeName-return] {\tikzumlCallReturn};%
+ }%
+ }{%
+ \ifnum\c@tikzumlFragmentLevel>0%
+ \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname}%
+ \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{\tikzumlFragmentFitOld (st-\tikzumlCall@nodeName) (et-\tikzumlCall@nodeName) (eb-\tikzumlCall@nodeName) (sb-\tikzumlCall@nodeName) (\tikzumlCall@nodeName-op)}%
+ \fi%
+ }%
+ }{%
+ \ifnum\c@tikzumlFragmentLevel>0%
+ \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname}%
+ \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{\tikzumlFragmentFitOld (st-\tikzumlCall@nodeName) (et-\tikzumlCall@nodeName) (eb-\tikzumlCall@nodeName) (sb-\tikzumlCall@nodeName) (\tikzumlCall@nodeName-op)}%
+ \fi%
+ }%
+ }%
+ \end{pgfonlayer}%
+}%
+%
+% alias for function self call
+\newenvironment{umlcallself}[2][]{\begin{umlcall}[#1]{#2}{#2} }{\end{umlcall}}%
+%
+% define a combined fragment
+% optional : name: name of fragment
+% type: type of fragment (opt, alt, break, loop, par, critical, ignore, consider, assert, neg, weak, strict, ref)
+% label: label of fragment (ex : condition for opt, iterator for loop, ...)
+% inner xsep, inner ysep: padding of the fragment box
+% draw, fill, text: colors
+\newenvironment{umlfragment}[1][]{%
+ % define a fragment separator
+ % optional : label of the fragment part (ex : else for alt)
+ \providecommand{\umlfpart}[1][]{%
+ \stepcounter{tikzumlFragmentPartNum}%
+ %
+ \node[outer sep=0, inner xsep=\tikzumlFragmentXSep ex, inner ysep=\tikzumlFragmentYSep ex, fit=\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname, name=\tikzumlFragment@name-Part-tmp] {};%
+ \node[anchor=east, name=\tikzumlFragment@name-PartType-\thetikzumlFragmentPartNum] at (\tikzumlFragment@name-Part-tmp.north west |- \tikzumlCallBottomSrc) {\phantom{\tikzumlFragmentType}};%
+ \draw (\tikzumlFragment@name-PartType-\thetikzumlFragmentPartNum.north west |- \tikzumlCallBottomSrc)+(0,-0.4*\tikzumlFragment@paddingy ex) node[name=\tikzumlFragment@name-PartWest-\thetikzumlFragmentPartNum] {};%
+ \draw (\tikzumlFragment@name-Part-tmp.north east |- \tikzumlCallBottomSrc)+(0,-0.4*\tikzumlFragment@paddingy ex) node[name=\tikzumlFragment@name-PartEast-\thetikzumlFragmentPartNum] {};%
+ \draw[dashed] (\tikzumlFragment@name-PartWest-\thetikzumlFragmentPartNum) -- (\tikzumlFragment@name-PartEast-\thetikzumlFragmentPartNum);
+ \draw (\tikzumlFragment@name-PartType-\thetikzumlFragmentPartNum)+(0,-0.4*\tikzumlFragment@paddingy ex) node[name=tikzumlTmpNode] {\phantom{\tikzumlFragmentType}};%
+ \node[anchor=north west] at (tikzumlTmpNode.south west) {[##1]};%
+ }%
+ %
+ \stepcounter{tikzumlFragmentNum}%
+ %
+ \pgfkeys{/tikzuml/fragment/.cd, name/.initial=fragment@\alph{tikzumlFragmentNum}, type/.initial=\tikzumlFragmentDefaultType,%
+ label/.initial=tikzumlEmpty,%
+ inner xsep/.initial=\tikzumlFragmentDefaultXSep, inner ysep/.initial=\tikzumlFragmentDefaultYSep,%
+ draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlFragmentDefaultFillColor,%
+ text/.initial=\tikzumlDefaultTextColor,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \errmessage{TIKZUML ERROR : in umlfragment, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/fragment/.cd, #1}%
+ \pgfkeys{/tikzuml/fragment/.cd, name/.get=\tikzumlFragmentName, type/.get=\tikzumlFragmentType,%
+ label/.get=\tikzumlFragmentLabel,%
+ inner xsep/.get=\tikzumlFragmentXSep, inner ysep/.get=\tikzumlFragmentYSep,%
+ draw/.get=\tikzumlFragmentDrawColor, fill/.get=\tikzumlFragmentFillColor,%
+ text/.get=\tikzumlFragmentTextColor%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlFragmentLabel}{tikzumlEmpty}}{%
+ \def\tikzumlFragmentLabel{}%
+ }{%
+ \let\tikzumlFragmentLabelold\tikzumlFragmentLabel%
+ \def\tikzumlFragmentLabel{[\tikzumlFragmentLabelold]}%
+ }%
+ %
+ \ifnum\thetikzumlFragmentLevel>0%
+ \let\tikzumlFragment@parentold\tikzumlFragment@parent%
+ \let\tikzumlFragment@nameold\tikzumlFragment@name%
+ \edef\tikzumlFragment@parent{\tikzumlFragment@nameold}%
+ \else%
+ \setcounter{tikzumlFragmentPartNum}{0}%
+ \edef\tikzumlFragment@parent{}%
+ \edef\tikzumlFragment@parentold{}%
+ \edef\tikzumlFragment@nameold{}%
+ \fi%
+ %
+ \edef\tikzumlFragment@name{\tikzumlFragmentName}%
+ \expandafter\gdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{}%
+ %
+ \stepcounter{tikzumlFragmentLevel}%
+ %
+ \ifnum\thetikzumlCallLevel>0%
+ \stepcounter{tikzumlCallStartFragmentNum}%
+ \fi%
+ %
+ \pgfmathparse{6*\tikzumlFragmentYSep}%
+ \xdef\tikzumlFragment@paddingy{\pgfmathresult}%
+ \if\c@tikzumlFragmentLevelNum=0%
+ \setcounter{tikzumlFragmentLevelNum}{\thetikzumlFragmentLevel}%
+ \fi%
+ %
+ % time delay adjustment for two consecutive fragments
+ \ifnum\thetikzumlCallEndFragmentNum>0%
+ \addtocounter{tikzumlCallEndFragmentNum}{-1}
+ \fi%
+}{%
+ %
+ \addtocounter{tikzumlFragmentLevel}{-1}%
+ %
+ \ifnum\thetikzumlFragmentLevel>0%
+ \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@parent \endcsname}%
+ \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@parent \endcsname{\tikzumlFragmentFitOld (\tikzumlFragment@name)}%
+ \fi%
+ %
+ % draw working fragment box
+ \begin{pgfonlayer}{fragment\thetikzumlFragmentLevel}%
+ \node[outer sep=0, inner xsep=\tikzumlFragmentXSep ex, inner ysep=\tikzumlFragmentYSep ex, fit=\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname, name=\tikzumlFragment@name-back] {};%
+ \end{pgfonlayer}%
+ %
+ % draw type and label
+ \node[text=\tikzumlFragmentTextColor, font=\tikzumlDefaultFont, anchor=north east, name=\tikzumlFragment@name-type] %
+ at (\tikzumlFragment@name-back.north west) {\tikzumlFragmentType};%
+ \node[text=\tikzumlFragmentTextColor, font=\tikzumlDefaultFont, anchor=north west, name=\tikzumlFragment@name-label] %
+ at (\tikzumlFragment@name-type.south west) {\tikzumlFragmentLabel};%
+ %
+ % draw final fragment box
+ \begin{pgfonlayer}{fragment\thetikzumlFragmentLevel}%
+ \node[draw=\tikzumlFragmentDrawColor, fill=\tikzumlFragmentFillColor, outer sep=0, inner sep=0, font=\tikzumlDefaultFont, fit=(\tikzumlFragment@name-back) (\tikzumlFragment@name-type) (\tikzumlFragment@name-label), name=\tikzumlFragment@name] {};%
+ \end{pgfonlayer}%
+ %
+ \draw[draw=\tikzumlFragmentDrawColor] (\tikzumlFragment@name.north west) rectangle (\tikzumlFragment@name.south east);%
+ \draw (\tikzumlFragment@name-type.south east)+(0,1ex) node[name=\tikzumlFragment@name-typetop, inner sep=0] {};%
+ \draw (\tikzumlFragment@name-type.south east)+(-1ex,0) node[name=\tikzumlFragment@name-typeleft, inner sep=0] {};%
+ \draw (\tikzumlFragment@name.north west) -| (\tikzumlFragment@name-typetop.center) -- (\tikzumlFragment@name-typeleft.center) -| (\tikzumlFragment@name.north west);%
+ %
+ \ifnum\thetikzumlCallLevel>0%
+ \stepcounter{tikzumlCallEndFragmentNum}%
+ \fi%
+}%
+%
+% define a constructor call
+% arg : call sender
+% name of constructed object
+% optional : x: coordinate of the new object
+% stereo: stereotype of the new object
+% class: class type of the new object
+% dt: time delay from last event
+% name: name of the call
+% draw, fill, text: colors
+% no ddots: when used, disable printing of double dots
+\newcommand{\umlcreatecall}[3][]{%
+ \stepcounter{tikzumlCallNum}%
+ \edef\tikzumlCall@lastchildNum{\thetikzumlCallNum}% for testing presence of sub-calls
+ \gdef\tikzumlInCreateCall{1}%
+ \pgfkeys{/tikzuml/createcall/.cd, x/.initial=tikzumlEmpty, stereo/.initial=\tikzumlObjectDefaultStereo, class/.initial={},%
+ dt/.initial=\tikzumlCreateCallDefaultDT, name/.initial=call-\thetikzumlCallNum,%
+ draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlCallDefaultFillColor,%
+ text/.initial=\tikzumlDefaultTextColor,%
+ draw obj/.initial=\tikzumlDefaultDrawColor, fill obj/.initial=\tikzumlObjectDefaultFillColor,%
+ text obj/.initial=\tikzumlDefaultTextColor,%
+ no ddots/.is if=tikzumlcreatecallNoDDots,%
+ no ddots=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \errmessage{TIKZUML ERROR : in umlcreatecall, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/createcall/.cd, #1}%
+ \pgfkeys{/tikzuml/createcall/.cd, x/.get=\tikzumlCreateCallX, stereo/.get=\tikzumlCreateCallStereo,%
+ class/.get=\tikzumlCreateCallClass,%
+ dt/.get=\tikzumlCreateCallDT, name/.get=\tikzumlCreateCallName,%
+ draw/.get=\tikzumlCreateCallDrawColor, fill/.get=\tikzumlCreateCallFillColor,%
+ text/.get=\tikzumlCreateCallTextColor,%
+ draw obj/.get=\tikzumlCreateCallObjectDrawColor, fill obj/.get=\tikzumlCreateCallObjectFillColor,%
+ text obj/.get=\tikzumlCreateCallObjectTextColor%
+ }%
+ %
+ \def\tikzumlCreateCallSrc@name{#2}%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlCreateCallSrc@nodeName{\tikzumlCreateCallSrc@name}}\x%
+ %
+ % managing time delays from previous/parent fragments
+ \ifnum\thetikzumlCallStartFragmentNum>0%
+ \let\tikzumlCreateCallDTold\tikzumlCreateCallDT%
+ \pgfmathparse{0.5*\tikzumlFragment@paddingy+\tikzumlCreateCallDTold}%
+ \edef\tikzumlCreateCallDT{\pgfmathresult}%
+ \addtocounter{tikzumlCallStartFragmentNum}{-1}
+ \fi%
+ \ifnum\thetikzumlCallEndFragmentNum>0%
+ \let\tikzumlCreateCallDTold\tikzumlCreateCallDT%
+ \pgfmathparse{0.5*\tikzumlFragment@paddingy+\tikzumlCreateCallDTold}%
+ \edef\tikzumlCreateCallDT{\pgfmathresult}%
+ \addtocounter{tikzumlCallEndFragmentNum}{-1}
+ \fi%
+ \ifnum\thetikzumlFragmentPartNum>0%
+ \let\tikzumlCreateCallDTold\tikzumlCreateCallDT%
+ \pgfmathparse{0.5*\tikzumlFragment@paddingy+\tikzumlCreateCallDTold}%
+ \edef\tikzumlCreateCallDT{\pgfmathresult}%
+ \fi%
+ %
+ % managing parent-child structure
+ \ifnum\thetikzumlCallLevel>0%
+ \let\tikzumlCall@nameold\tikzumlCall@name%
+ \def\tikzumlCall@name{\tikzumlCreateCallName}%
+ \let\tikzumlCall@parentold\tikzumlCall@parent%
+ \edef\tikzumlCall@parent{\tikzumlCall@parentold @@\tikzumlCall@nameold}%
+ \else%
+ \edef\tikzumlCall@parent{}%
+ \edef\tikzumlCall@parentold{}%
+ \edef\tikzumlCall@nameold{}
+ \edef\tikzumlCall@name{\tikzumlCreateCallName}%
+ \fi%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlCreateCall@nodeName{\tikzumlCall@name}}\x%
+ %
+ \draw (\csname tikzumlLastChild@\tikzumlCreateCallSrc@nodeName \endcsname)+(0,-\tikzumlCreateCallDT ex) node[name=st-\tikzumlCreateCall@nodeName, tikzuml activity style] {};%
+ %
+ \xdef\tikzumlCreateCallObjectSrc{st-\tikzumlCreateCall@nodeName}%
+ %
+ \iftikzumlcreatecallNoDDots%
+ \umlobject[x=\tikzumlCreateCallX, stereo=\tikzumlCreateCallStereo, class=\tikzumlCreateCallClass, draw=\tikzumlCreateCallObjectDrawColor, fill=\tikzumlCreateCallObjectFillColor, text=\tikzumlCreateCallObjectTextColor, no ddots]{#3}%
+ \else
+ \umlobject[x=\tikzumlCreateCallX, stereo=\tikzumlCreateCallStereo, class=\tikzumlCreateCallClass, draw=\tikzumlCreateCallObjectDrawColor, fill=\tikzumlCreateCallObjectFillColor, text=\tikzumlCreateCallObjectTextColor]{#3}%
+ \fi
+ %
+ \draw (\csname tikzumlLastChild@\tikzumlCreateCallSrc@nodeName \endcsname |- #3)+(0,-0.5*\tikzumlCreateCallDT ex) node[name=sb-\tikzumlCreateCall@nodeName, tikzuml activity style] {};%
+ %
+ \expandafter\xdef\csname tikzumlLastChild@\tikzumlCreateCallSrc@nodeName \endcsname{sb-\tikzumlCreateCall@nodeName}%
+ \xdef\tikzumlCallBottomSrc{sb-\tikzumlCreateCall@nodeName}%
+ %
+ \begin{pgfonlayer}{connections}%
+ \draw[tikzuml synchron-msg style, \tikzumlCreateCallDrawColor] (st-\tikzumlCreateCall@nodeName) -- (#3) node[midway, above, font=\tikzumlDefaultFont, text=\tikzumlCreateCallTextColor, name=\tikzumlCreateCall@nodeName-op] {create};%
+ \end{pgfonlayer}%
+ %
+ \ifnum\thetikzumlCallLevel=0%
+ \begin{pgfonlayer}{activity}%
+ \draw[draw=\tikzumlCreateCallDrawColor, fill=\tikzumlCreateCallFillColor] (st-\tikzumlCreateCall@nodeName.north west) rectangle (sb-\tikzumlCreateCall@nodeName.south east);%
+ \end{pgfonlayer}%
+ \fi%
+ % add to fit fragment
+ \ifnum\c@tikzumlFragmentLevel>0%
+ \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname}%
+ \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{\tikzumlFragmentFitOld (st-\tikzumlCreateCall@nodeName) (sb-\tikzumlCreateCall@nodeName) (\tikzumlCreateCall@nodeName-op) (#3) }%
+ \fi%
+}
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% component diagrams %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+\tikzstyle{tikzuml connector style}=[color=\tikzumlDefaultDrawColor, -]%
+%
+\newcounter{tikzumlComponentLevel}%
+\newcounter{tikzumlComponentSubComponentNum}%
+\newcounter{tikzumlConnectorNum}%
+\setcounter{tikzumlConnectorNum}{1}%
+%
+\newif\iftikzumlcomponentWithoutCoords%
+%
+\newcommand{\picturedcomponent}[1]{%
+ \pgfkeys{/tikzuml/component/picture/.cd, scale/.initial=1, .unknown/.code={}}%
+ \pgfkeys{/tikzuml/component/picture/.cd,#1}%
+ \pgfkeys{/tikzuml/component/picture/.cd, scale/.get=\tikzumlComponentScale}%
+ \begin{tikzpicture}[#1]%
+ \filldraw (0,0) rectangle (1ex,1.5ex);%
+ \filldraw (-0.2ex,0.4ex) rectangle (0.2ex,0.6ex);%
+ \filldraw (-0.2ex,0.9ex) rectangle (0.2ex,1.1ex);%
+ \end{tikzpicture}%
+}%
+%
+% define a uml component
+% args : name of the component
+% content of the component
+% optional args : x,y coordinates of the component
+% width of the component node
+\newenvironment{umlcomponent}[2][]{%
+ \ifnum\thetikzumlComponentLevel>0%
+ \let\tikzumlComponent@nameold\tikzumlComponent@fitname%
+ \let\tikzumlComponent@parentold\tikzumlComponent@parent%
+ \edef\tikzumlComponent@parent{\tikzumlComponent@parentold @@\tikzumlComponent@nameold}%
+ \else%
+ \def\tikzumlComponent@parent{}%
+ \fi%
+ %
+ \stepcounter{tikzumlComponentLevel}%
+ %
+ \pgfkeys{/tikzuml/component/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlComponentDefaultWidth, name/.initial={},%
+ draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlComponentDefaultFillColor,%
+ text/.initial=\tikzumlDefaultTextColor, style/.style={},%
+ no coords/.is if=tikzumlcomponentWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/component/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/component/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/component/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlcomponent, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/component/.cd, #1}%
+ \pgfkeys{/tikzuml/component/.cd, x/.get=\tikzumlComponentXShift, y/.get=\tikzumlComponentYShift,%
+ width/.get=\tikzumlComponentMinimumWidth, name/.get=\tikzumlComponentName,%
+ draw/.get=\tikzumlComponentDrawColor, fill/.get=\tikzumlComponentFillColor,%
+ text/.get=\tikzumlComponentTextColor%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlComponentName}{}}{%
+ \edef\tikzumlComponent@name{#2}%
+ }{%
+ \edef\tikzumlComponent@name{\tikzumlComponentName}%
+ }%
+ %
+ \begingroup%
+ \def\_{@}\edef\x{\endgroup%
+ \def\noexpand\tikzumlComponent@fitname{\tikzumlComponent@name}}\x%
+ %
+ \let\tikzumlComponent@nodeNameold\tikzumlComponent@nodeName%
+ \def\tikzumlComponent@caption{#2}%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlComponent@nodeName{\tikzumlComponent@name}}\x%
+ %
+ \expandafter\gdef\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname{}%
+ %
+ \setcounter{tikzumlComponentSubComponentNum}{0}%
+ %
+ \begin{scope}[xshift=\tikzumlComponentXShift cm, yshift=\tikzumlComponentYShift cm]%
+}{%
+ \addtocounter{tikzumlComponentLevel}{-1}%
+ \begin{pgfonlayer}{component\thetikzumlComponentLevel}%
+ %
+ % if contains nothing, one define a fictive node to enable the fit option
+ \ifnum\c@tikzumlComponentSubComponentNum=0%
+ \iftikzumlcomponentWithoutCoords%
+ \node[inner ysep=0.5ex, minimum width=\tikzumlComponentMinimumWidth, font=\tikzumlDefaultFont, /tikzuml/component/style] (\tikzumlComponent@nodeName-root) {\phantom{\tikzumlComponent@nodeName}};%
+ \else%
+ \node[inner ysep=0.5ex, minimum width=\tikzumlComponentMinimumWidth, font=\tikzumlDefaultFont, /tikzuml/component/style] (\tikzumlComponent@nodeName-root) at (0,0) {\phantom{\tikzumlComponent@nodeName}};%
+ \fi%
+ \expandafter\xdef\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname{(\tikzumlComponent@nodeName-root)}%
+ \fi%
+ %
+ \ifnum\c@tikzumlComponentLevel>0%
+ \def\tikzumlComponentFitTmp{\csname tikzumlComponentFit\tikzumlComponent@parent\endcsname}%
+ \expandafter\xdef\csname tikzumlComponentFit\tikzumlComponent@parent\endcsname{\tikzumlComponentFitTmp (\tikzumlComponent@nodeName-body) (\tikzumlComponent@nodeName-caption)}%
+ \stepcounter{tikzumlComponentSubComponentNum}%
+ \fi%
+ %
+ \node[inner sep=2ex, font=\tikzumlDefaultFont, fit = \csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname] (\tikzumlComponent@nodeName-body) {};%
+ \node[above, font=\tikzumlDefaultFont] (\tikzumlComponent@nodeName-captiontmp) at (\tikzumlComponent@nodeName-body.north) {\tikzumlComponent@caption};%
+ \node (\tikzumlComponent@nodeName-logotmp) at (\tikzumlComponent@nodeName-captiontmp.north -| \tikzumlComponent@nodeName-body.east) {\picturedcomponent{draw=\tikzumlComponentDrawColor, fill=\tikzumlComponentFillColor, font=\tikzumlDefaultFont} };%
+ \node[draw=\tikzumlComponentDrawColor, fill=\tikzumlComponentFillColor, name=\tikzumlComponent@nodeName, /tikzuml/component/style, fit=(\tikzumlComponent@nodeName-body) (\tikzumlComponent@nodeName-captiontmp)] {};%
+ \node[font=\tikzumlDefaultFont] (\tikzumlComponent@nodeName-caption) at (\tikzumlComponent@nodeName-captiontmp) {\tikzumlComponent@caption};%
+ \draw (\tikzumlComponent@nodeName-caption.north -| \tikzumlComponent@nodeName.east) node[font=\tikzumlDefaultFont, xshift=-1ex, below=-1ex, name=\tikzumlComponent@nodeName-logo] {\picturedcomponent{draw=\tikzumlComponentDrawColor, fill=\tikzumlComponentFillColor, font=\tikzumlDefaultFont} };%
+ \draw (\tikzumlComponent@nodeName-caption.south -| \tikzumlComponent@nodeName.north west) -- (\tikzumlComponent@nodeName-caption.south -| \tikzumlComponent@nodeName.north east);%
+ \coordinate (\tikzumlComponent@nodeName-west-port) at (\tikzumlComponent@nodeName.west);
+ \coordinate (\tikzumlComponent@nodeName-east-port) at (\tikzumlComponent@nodeName.east);
+ \coordinate (\tikzumlComponent@nodeName-south-port) at (\tikzumlComponent@nodeName.south);
+ \coordinate (\tikzumlComponent@nodeName-north-port) at (\tikzumlComponent@nodeName.north);
+ \end{pgfonlayer}%
+ \end{scope}%
+ %
+ % add to fit
+ \ifnum\c@tikzumlPackageLevel>0%
+ \edef\tikzumlPackageFitOld{\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{\tikzumlPackageFitOld (\tikzumlComponent@nodeName)}%
+ \stepcounter{tikzumlPackageClassNum}%
+ \fi%
+}%
+%
+% shortcut for empty component
+\newcommand{\umlbasiccomponent}[2][]{\begin{umlcomponent}[#1]{#2} \end{umlcomponent}}%
+%
+\newcommand{\umlrequiredinterface}[2][]{%
+ \def\tikzumlInterfaceWithPort{tikzumlFalse}%
+ \pgfkeys{/tikzuml/requiredinterfacerelation/.cd, interface/.initial={}, distance/.initial=\tikzumlRequiredInterfaceDefaultDistance,%
+ name/.initial=tikzumlEmpty, width/.initial=\tikzumlRequiredInterfaceDefaultWidth,%
+ padding/.initial=\tikzumlRequiredInterfaceDefaultPadding,%
+ draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlComponentDefaultFillColor,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{with port}}{%
+ \def\tikzumlInterfaceWithPort{tikzumlTrue}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/requiredinterfacerelation/.cd, #1}%
+ \pgfkeys{/tikzuml/requiredinterfacerelation/.cd, interface/.get=\tikzumlRequiredInterfaceLabel,%
+ distance/.get=\tikzumlRequiredInterfaceDistance,%
+ name/.get=\tikzumlRequiredInterfaceName,%
+ width/.get=\tikzumlRequiredInterfaceWidth,%
+ padding/.get=\tikzumlRequiredInterfacePadding,%
+ draw/.get=\tikzumlRequiredInterfaceDrawColor,%
+ fill/.get=\tikzumlRequiredInterfaceFillColor%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlRequiredInterfaceName}{tikzumlEmpty}}{%
+ \edef\tikzumlRequiredInterface@interfacename{#2-east-interface}%
+ \edef\tikzumlRequiredInterface@portname{#2-east-port}%
+ \edef\tikzumlRequiredInterface@paddingname{#2-east-padding}%
+ }{%
+ \edef\tikzumlRequiredInterface@interfacename{\tikzumlRequiredInterfaceName}%
+ \edef\tikzumlRequiredInterface@portname{\tikzumlRequiredInterfaceName-port}%
+ \edef\tikzumlRequiredInterface@paddingname{\tikzumlRequiredInterfaceName-padding}%
+ }%
+ %
+ \edef\tikzumlRequiredInterface@name{#2}%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlRequiredInterface@nodeName{\tikzumlRequiredInterface@name}}\x%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlRequiredInterface@interfacenodeName{\tikzumlRequiredInterface@interfacename}}\x%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlRequiredInterface@portnodeName{\tikzumlRequiredInterface@portname}}\x%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlRequiredInterface@paddingnodeName{\tikzumlRequiredInterface@paddingname}}\x%
+ %
+ \ifthenelse{\equal{\tikzumlInterfaceWithPort}{tikzumlTrue}}{%
+ \node[inner sep=0.5*\tikzumlRequiredInterfaceWidth, rectangle, draw=\tikzumlRequiredInterfaceDrawColor, fill=\tikzumlRequiredInterfaceFillColor] (\tikzumlRequiredInterface@portnodeName) at (\tikzumlRequiredInterface@nodeName.east) {};%
+ }{%
+ \node[inner sep=0] (\tikzumlRequiredInterface@nodeName-east-port) at (\tikzumlRequiredInterface@nodeName.east) {};%
+ }%
+ \begin{scope}%
+ \draw (\tikzumlRequiredInterface@nodeName)+(\tikzumlRequiredInterfaceDistance,0) node[inner sep=0, text width=\tikzumlRequiredInterfaceWidth, circle, name=\tikzumlRequiredInterface@interfacenodeName-tmp] {};%
+ \clip (\tikzumlRequiredInterface@interfacenodeName-tmp.north) rectangle (\tikzumlRequiredInterface@interfacenodeName-tmp.south -| \tikzumlRequiredInterface@interfacenodeName-tmp.west);%
+ \node[inner sep=0, text width=\tikzumlRequiredInterfaceWidth, circle, draw=\tikzumlRequiredInterfaceDrawColor] (\tikzumlRequiredInterface@interfacenodeName) at (\tikzumlRequiredInterface@interfacenodeName-tmp) {};%
+ \end{scope}%
+ \node[above] at (\tikzumlRequiredInterface@interfacenodeName.north) {\tikzumlRequiredInterfaceLabel};%
+ %
+ \umlrelation[style={tikzuml connector style}, #1]{\tikzumlRequiredInterface@portnodeName}{\tikzumlRequiredInterface@interfacenodeName}%
+ %
+ \draw (\tikzumlRequiredInterface@interfacenodeName)+(\tikzumlRequiredInterfacePadding,0) node[name=\tikzumlRequiredInterface@paddingnodeName] {};%
+ %
+ % add to fit
+ \ifnum\c@tikzumlComponentLevel>0%
+ \def\tikzumlComponentFitTmp{\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname{\tikzumlComponentFitTmp (\tikzumlRequiredInterface@paddingnodeName) (\tikzumlRequiredInterface@portnodeName) }%
+ \fi%
+}%
+%
+\newcommand{\umlprovidedinterface}[2][]{%
+ \def\tikzumlInterfaceWithPort{tikzumlFalse}%
+ \pgfkeys{/tikzuml/providedinterfacerelation/.cd, interface/.initial={}, distance/.initial=\tikzumlProvidedInterfaceDefaultDistance,%
+ name/.initial=tikzumlEmpty, width/.initial=\tikzumlProvidedInterfaceDefaultWidth,%
+ padding/.initial=\tikzumlProvidedInterfaceDefaultPadding,%
+ draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlComponentDefaultFillColor,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{with port}}{%
+ \def\tikzumlInterfaceWithPort{tikzumlTrue}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/providedinterfacerelation/.cd, #1}%
+ \pgfkeys{/tikzuml/providedinterfacerelation/.cd, interface/.get=\tikzumlProvidedInterfaceLabel,%
+ distance/.get=\tikzumlProvidedInterfaceDistance,%
+ name/.get=\tikzumlProvidedInterfaceName,%
+ width/.get=\tikzumlProvidedInterfaceWidth,%
+ padding/.get=\tikzumlProvidedInterfacePadding,%
+ draw/.get=\tikzumlProvidedInterfaceDrawColor,%
+ fill/.get=\tikzumlProvidedInterfaceFillColor%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlProvidedInterfaceName}{tikzumlEmpty}}{%
+ \edef\tikzumlProvidedInterface@interfacename{#2-west-interface}%
+ \edef\tikzumlProvidedInterface@portname{#2-west-port}%
+ \edef\tikzumlProvidedInterface@paddingname{#2-west-padding}%
+ }{%
+ \edef\tikzumlProvidedInterface@interfacename{\tikzumlProvidedInterfaceName}%
+ \edef\tikzumlProvidedInterface@portname{\tikzumlProvidedInterfaceName-port}%
+ \edef\tikzumlProvidedInterface@paddingname{\tikzumlProvidedInterfaceName-padding}%
+ }%
+ %
+ \edef\tikzumlProvidedInterface@name{#2}%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlProvidedInterface@nodeName{\tikzumlProvidedInterface@name}}\x%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlProvidedInterface@interfacenodeName{\tikzumlProvidedInterface@interfacename}}\x%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlProvidedInterface@portnodeName{\tikzumlProvidedInterface@portname}}\x%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlProvidedInterface@paddingnodeName{\tikzumlProvidedInterface@paddingname}}\x%
+ %
+ \ifthenelse{\equal{\tikzumlInterfaceWithPort}{tikzumlTrue}}{%
+ \node[inner sep=0.5*\tikzumlProvidedInterfaceWidth, rectangle, draw=\tikzumlProvidedInterfaceDrawColor, fill=\tikzumlProvidedInterfaceFillColor] (\tikzumlProvidedInterface@portnodeName) at (\tikzumlProvidedInterface@nodeName.west) {};%
+ }{%
+ \node[inner sep=0] (\tikzumlProvidedInterface@portnodeName) at (\tikzumlProvidedInterface@nodeName.west) {};%
+ }%
+ \draw (\tikzumlProvidedInterface@nodeName)+(-\tikzumlProvidedInterfaceDistance,0) node[inner sep=0, text width=\tikzumlProvidedInterfaceWidth, circle, draw=\tikzumlProvidedInterfaceDrawColor, fill=\tikzumlProvidedInterfaceFillColor, name=\tikzumlProvidedInterface@interfacenodeName] {};%
+ \node[above] at (\tikzumlProvidedInterface@interfacenodeName.north)
+ {\tikzumlProvidedInterfaceLabel};%
+ %
+ \umlrelation[style={tikzuml connector style}, #1]{\tikzumlProvidedInterface@portnodeName}{\tikzumlProvidedInterface@interfacenodeName}%
+ %
+ \draw (\tikzumlProvidedInterface@interfacenodeName)+(-\tikzumlProvidedInterfacePadding,0) node[name=\tikzumlProvidedInterface@paddingnodeName] {};%
+ %
+ % add to fit
+ \ifnum\thetikzumlComponentLevel>0%
+ \def\tikzumlComponentFitTmp{\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname{\tikzumlComponentFitTmp (\tikzumlProvidedInterface@paddingnodeName) (\tikzumlProvidedInterface@portnodeName) }%
+ \fi%
+}%
+%
+\newlength{\tikzuml@AC@xa}%
+\newlength{\tikzuml@AC@ya}%
+\newlength{\tikzuml@AC@xb}%
+\newlength{\tikzuml@AC@yb}%
+\newlength{\tikzuml@AC@xi}%
+\newlength{\tikzuml@AC@yi}%
+\newlength{\tikzuml@AC@xic}%
+\newlength{\tikzuml@AC@yic}%
+\newlength{\tikzuml@AC@xio}%
+\newlength{\tikzuml@AC@yio}%
+\newlength{\tikzuml@AC@AB}%
+\newlength{\tikzuml@AC@lambda}%
+\newlength{\tikzuml@AC@xtrc}%
+\newlength{\tikzuml@AC@ytrc}%
+\newlength{\tikzuml@AC@xtlc}%
+\newlength{\tikzuml@AC@ytlc}%
+\newlength{\tikzuml@AC@xblc}%
+\newlength{\tikzuml@AC@yblc}%
+\newlength{\tikzuml@AC@xbrc}%
+\newlength{\tikzuml@AC@ybrc}%
+\newlength{\tikzuml@AC@middleArm}%
+%
+\newcommand{\umlassemblyconnectorsymbol}[2]{%
+ \ifthenelse{\NOT\equal{\tikzumlAssemblyConnectorLabel}{}}{%
+ \edef\tikzuml@ACStart@name{#1}%
+ \edef\tikzuml@ACEnd@name{#2}%
+ \edef\tikzuml@AC@width{\tikzumlAssemblyConnectorWidth}%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzuml@ACStart@nodeName{\tikzuml@ACStart@name}}\x%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzuml@ACEnd@nodeName{\tikzuml@ACEnd@name}}\x%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzuml@ACInterface@nodeName{\tikzumlAssemblyConnectorSymbolName}}\x%
+ %
+ \pgfextractx{\tikzuml@AC@xa}{\pgfpointanchor{\tikzuml@ACStart@nodeName}{\tikzumlAssemblyConnectorStartAnchor}}%
+ \pgfextracty{\tikzuml@AC@ya}{\pgfpointanchor{\tikzuml@ACStart@nodeName}{\tikzumlAssemblyConnectorStartAnchor}}%
+ \pgfextractx{\tikzuml@AC@xb}{\pgfpointanchor{\tikzuml@ACEnd@nodeName}{\tikzumlAssemblyConnectorEndAnchor}}%
+ \pgfextracty{\tikzuml@AC@yb}{\pgfpointanchor{\tikzuml@ACEnd@nodeName}{\tikzumlAssemblyConnectorEndAnchor}}%
+ \pgfmathsetlength{\tikzuml@AC@xi}{0.5*\tikzuml@AC@xa+0.5*\tikzuml@AC@xb}%
+ \pgfmathsetlength{\tikzuml@AC@yi}{0.5*\tikzuml@AC@ya+0.5*\tikzuml@AC@yb}%
+ \pgfmathsetlength{\tikzuml@AC@AB}{veclen(\tikzuml@AC@xa-\tikzuml@AC@xb,\tikzuml@AC@ya-\tikzuml@AC@yb)}%
+ \pgfmathsetlength{\tikzuml@AC@lambda}{0.25*\tikzuml@AC@width/\tikzuml@AC@AB}%
+ \pgfmathsetlength{\tikzuml@AC@xic}{\tikzuml@AC@xi-\tikzuml@AC@lambda*(\tikzuml@AC@xb-\tikzuml@AC@xa)}%
+ \pgfmathsetlength{\tikzuml@AC@yic}{\tikzuml@AC@yi-\tikzuml@AC@lambda*(\tikzuml@AC@yb-\tikzuml@AC@ya)}%
+ \pgfmathsetlength{\tikzuml@AC@xio}{\tikzuml@AC@xi+\tikzuml@AC@lambda*(\tikzuml@AC@xb-\tikzuml@AC@xa)}%
+ \pgfmathsetlength{\tikzuml@AC@yio}{\tikzuml@AC@yi+\tikzuml@AC@lambda*(\tikzuml@AC@yb-\tikzuml@AC@ya)}%
+ \node[inner sep=0.5*\tikzuml@AC@width] (\tikzuml@ACInterface@nodeName-interface) at (\tikzuml@AC@xi,\tikzuml@AC@yi) {};%
+ \node[inner sep=0, text width=\tikzuml@AC@width, circle, draw=\tikzumlAssemblyConnectorDrawColor, fill=\tikzumlAssemblyConnectorFillColor] (\tikzuml@ACInterface@nodeName-io) at (\tikzuml@AC@xio,\tikzuml@AC@yio) {};%
+ \begin{scope}%
+ \pgfmathsetlength{\tikzuml@AC@xtrc}{\tikzuml@AC@xic-2*\tikzuml@AC@lambda*(\tikzuml@AC@yb-\tikzuml@AC@ya)}%
+ \pgfmathsetlength{\tikzuml@AC@ytrc}{\tikzuml@AC@yic+2*\tikzuml@AC@lambda*(\tikzuml@AC@xb-\tikzuml@AC@xa)}%
+ \pgfmathsetlength{\tikzuml@AC@xbrc}{\tikzuml@AC@xic+2*\tikzuml@AC@lambda*(\tikzuml@AC@yb-\tikzuml@AC@ya)}%
+ \pgfmathsetlength{\tikzuml@AC@ybrc}{\tikzuml@AC@yic-2*\tikzuml@AC@lambda*(\tikzuml@AC@xb-\tikzuml@AC@xa)}%
+ \pgfmathsetlength{\tikzuml@AC@xtlc}{\tikzuml@AC@xic-3*\tikzuml@AC@lambda*(\tikzuml@AC@yb-\tikzuml@AC@ya+\tikzuml@AC@xb-\tikzuml@AC@xa)}%
+ \pgfmathsetlength{\tikzuml@AC@ytlc}{\tikzuml@AC@yic+3*\tikzuml@AC@lambda*(\tikzuml@AC@xb-\tikzuml@AC@xa+\tikzuml@AC@ya-\tikzuml@AC@yb)}%
+ \pgfmathsetlength{\tikzuml@AC@xblc}{\tikzuml@AC@xic+3*\tikzuml@AC@lambda*(\tikzuml@AC@yb-\tikzuml@AC@ya+\tikzuml@AC@xa-\tikzuml@AC@xb)}%
+ \pgfmathsetlength{\tikzuml@AC@yblc}{\tikzuml@AC@yic-3*\tikzuml@AC@lambda*(\tikzuml@AC@xb-\tikzuml@AC@xa+\tikzuml@AC@yb-\tikzuml@AC@ya)}%
+ \coordinate (\tikzuml@ACInterface@nodeName-trc) at (\tikzuml@AC@xtrc,\tikzuml@AC@ytrc);%
+ \coordinate (\tikzuml@ACInterface@nodeName-brc) at (\tikzuml@AC@xbrc,\tikzuml@AC@ybrc);%
+ \coordinate (\tikzuml@ACInterface@nodeName-tlc) at (\tikzuml@AC@xtlc,\tikzuml@AC@ytlc);%
+ \coordinate (\tikzuml@ACInterface@nodeName-blc) at (\tikzuml@AC@xblc,\tikzuml@AC@yblc);%
+ \clip (\tikzuml@ACInterface@nodeName-trc) -- (\tikzuml@ACInterface@nodeName-tlc) -- (\tikzuml@ACInterface@nodeName-blc) -- (\tikzuml@ACInterface@nodeName-brc) -- cycle;%
+ \node[inner sep=0, text width=\tikzuml@AC@width, circle, draw=\tikzumlAssemblyConnectorDrawColor, fill=\tikzumlAssemblyConnectorFillColor] (\tikzuml@ACInterface@nodeName-ic) at (\tikzuml@AC@xic,\tikzuml@AC@yic) {};%
+ \end{scope}%
+ \node[above, font=\tikzumlDefaultFont] at (\tikzuml@ACInterface@nodeName-interface.north)
+ {\tikzumlAssemblyConnectorLabel};%
+ }{}%
+}%
+%
+\newcommand{\umlassemblyconnector}[3][]{%
+ \def\tikzumlAssemblyConnectorWithPort{tikzumlFalse}%
+ \def\tikzumlAssemblyConnectorFirstArm{tikzumlFalse}%
+ \def\tikzumlAssemblyConnectorSecondArm{tikzumlFalse}%
+ \def\tikzumlAssemblyConnectorMiddleArm{tikzumlFalse}%
+ \def\tikzumlAssemblyConnectorLastArm{tikzumlFalse}%
+ \pgfkeys{/tikzuml/assemblyconnectorrelation/.cd, geometry/.initial=--, interface/.initial={},%
+ arm1/.initial={auto}, arm2/.initial={auto},%
+ name/.initial=connector-\thetikzumlConnectorNum, width/.initial=1em,%
+ anchor1/.initial={}, anchor2/.initial={},%
+ draw/.initial=\tikzumlDefaultDrawColor,%
+ fill assembly connector/.initial=\tikzumlAssemblyConnectorDefaultFillColor,%
+ fill port/.initial=\tikzumlPortDefaultFillColor,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{with port}}{%
+ \def\tikzumlAssemblyConnectorWithPort{tikzumlTrue}%
+ }{%
+ \ifthenelse{\equal{\keyname}{first arm}}{%
+ \def\tikzumlAssemblyConnectorFirstArm{tikzumlTrue}%
+ }{%
+ \ifthenelse{\equal{\keyname}{second arm}}{%
+ \def\tikzumlAssemblyConnectorSecondArm{tikzumlTrue}%
+ }{%
+ \ifthenelse{\equal{\keyname}{middle arm}}{%
+ \def\tikzumlAssemblyConnectorMiddleArm{tikzumlTrue}%
+ }{%
+ \ifthenelse{\equal{\keyname}{last arm}}{%
+ \def\tikzumlAssemblyConnectorLastArm{tikzumlTrue}%
+ }{%
+ }%
+ }%
+ }%
+ }%
+ }%
+ }%
+ }%
+ \pgfkeys{/tikzuml/assemblyconnectorrelation/.cd, #1}%
+ \pgfkeys{/tikzuml/assemblyconnectorrelation/.cd, geometry/.get=\tikzumlAssemblyConnectorGeometry,%
+ name/.get=\tikzumlAssemblyConnectorName,%
+ interface/.get=\tikzumlAssemblyConnectorLabel,%
+ width/.get=\tikzumlAssemblyConnectorWidth,%
+ arm1/.get=\tikzumlAssemblyConnectorStartArm,%
+ arm2/.get=\tikzumlAssemblyConnectorEndArm,%
+ anchor1/.get=\tikzumlAssemblyConnectorStartAnchorTmp,%
+ anchor2/.get=\tikzumlAssemblyConnectorEndAnchorTmp,%
+ draw/.get=\tikzumlAssemblyConnectorDrawColor,%
+ fill assembly connector/.get=\tikzumlAssemblyConnectorFillColor,%
+ fill port/.get=\tikzumlAssemblyConnectorPortFillColor%
+ }%
+ %
+ \edef\tikzumlAssemblyConnectorStart@name{#2}%
+ \edef\tikzumlAssemblyConnectorEnd@name{#3}%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlAssemblyConnectorStart@nodeName{\tikzumlAssemblyConnectorStart@name}}\x%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlAssemblyConnectorEnd@nodeName{\tikzumlAssemblyConnectorEnd@name}}\x%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlAssemblyConnectorLabel@nodeName{\tikzumlAssemblyConnectorLabel}}\x%
+ %
+ \pgfextractx{\tikzuml@AC@xa}{\pgfpointanchor{\tikzumlAssemblyConnectorStart@nodeName}{center}}%
+ \pgfextracty{\tikzuml@AC@ya}{\pgfpointanchor{\tikzumlAssemblyConnectorStart@nodeName}{center}}%
+ \pgfextractx{\tikzuml@AC@xb}{\pgfpointanchor{\tikzumlAssemblyConnectorEnd@nodeName}{center}}%
+ \pgfextracty{\tikzuml@AC@yb}{\pgfpointanchor{\tikzumlAssemblyConnectorEnd@nodeName}{center}}%
+ %
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{--}}{%
+ \ifthenelse{\tikzuml@AC@xb>\tikzuml@AC@xa}{%
+ \def\tikzumlAssemblyConnectorStartAnchor{east}%
+ \def\tikzumlAssemblyConnectorEndAnchor{west}%
+ }{%
+ \def\tikzumlAssemblyConnectorStartAnchor{west}%
+ \def\tikzumlAssemblyConnectorEndAnchor{east}%
+ }
+ }{}%
+ %
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{-|}}{%
+ \ifthenelse{\tikzuml@AC@xb>\tikzuml@AC@xa}{%
+ \def\tikzumlAssemblyConnectorStartAnchor{east}%
+ }{%
+ \def\tikzumlAssemblyConnectorStartAnchor{west}%
+ }
+ \ifthenelse{\tikzuml@AC@yb>\tikzuml@AC@ya}{%
+ \def\tikzumlAssemblyConnectorEndAnchor{south}%
+ }{%
+ \def\tikzumlAssemblyConnectorEndAnchor{north}%
+ }
+ }{}%
+ %
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{|-}}{%
+ \ifthenelse{\tikzuml@AC@xb>\tikzuml@AC@xa}{%
+ \def\tikzumlAssemblyConnectorEndAnchor{west}%
+ }{%
+ \def\tikzumlAssemblyConnectorEndAnchor{east}%
+ }
+ \ifthenelse{\tikzuml@AC@yb>\tikzuml@AC@ya}{%
+ \def\tikzumlAssemblyConnectorStartAnchor{north}%
+ }{%
+ \def\tikzumlAssemblyConnectorStartAnchor{south}%
+ }
+ }{}%
+ %
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{-|-}}{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorStartArm}{auto}}{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorEndArm}{auto}}{%
+ \pgfmathsetlength{\tikzuml@AC@middleArm}{0.5 * \tikzuml@AC@xa + 0.5 * \tikzuml@AC@xb}%
+ }{%
+ \pgfmathsetlength{\tikzuml@AC@middleArm}{\tikzuml@AC@xb+\tikzumlAssemblyConnectorEndArm}%
+ }%
+ }{%
+ \pgfmathsetlength{\tikzuml@AC@middleArm}{\tikzuml@AC@xa+\tikzumlAssemblyConnectorStartArm}%
+ }%
+ \pgfmathparse{\tikzuml@AC@middleArm>\tikzuml@AC@xa}
+ \pgfmathparse{\tikzuml@AC@middleArm>\tikzuml@AC@xb}
+ \ifthenelse{\lengthtest{\tikzuml@AC@middleArm>\tikzuml@AC@xa}}{%
+ \def\tikzumlAssemblyConnectorStartAnchor{east}%
+ }{%
+ \def\tikzumlAssemblyConnectorStartAnchor{west}%
+ }
+ \ifthenelse{\lengthtest{\tikzuml@AC@middleArm>\tikzuml@AC@xb}}{%
+ \def\tikzumlAssemblyConnectorEndAnchor{east}%
+ }{%
+ \def\tikzumlAssemblyConnectorEndAnchor{west}%
+ }
+ }{}%
+ %
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{|-|}}{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorStartArm}{auto}}{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorEndArm}{auto}}{%
+ \pgfmathsetlength{\tikzuml@AC@middleArm}{0.5 * \tikzuml@AC@ya + 0.5 * \tikzuml@AC@yb}%
+ }{%
+ \pgfmathsetlength{\tikzuml@AC@middleArm}{\tikzuml@AC@yb+\tikzumlAssemblyConnectorEndArm}%
+ }%
+ }{%
+ \pgfmathsetlength{\tikzuml@AC@middleArm}{\tikzuml@AC@ya+\tikzumlAssemblyConnectorStartArm}%
+ }%
+ \ifthenelse{\tikzuml@AC@middleArm>\tikzuml@AC@ya}{%
+ \def\tikzumlAssemblyConnectorStartAnchor{north}%
+ }{%
+ \def\tikzumlAssemblyConnectorStartAnchor{south}%
+ }
+ \ifthenelse{\tikzuml@AC@middleArm>\tikzuml@AC@yb}{%
+ \def\tikzumlAssemblyConnectorEndAnchor{north}%
+ }{%
+ \def\tikzumlAssemblyConnectorEndAnchor{south}%
+ }
+ }{}%
+ %
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorStartAnchorTmp}{}}{%
+ }{%
+ \def\tikzumlAssemblyConnectorStartAnchor{\tikzumlAssemblyConnectorStartAnchorTmp}%
+ }%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorEndAnchorTmp}{}}{%
+ }{%
+ \def\tikzumlAssemblyConnectorEndAnchor{\tikzumlAssemblyConnectorEndAnchorTmp}%
+ }%
+ %
+ \node[inner sep=0] (\tikzumlAssemblyConnectorStart@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port-tmp) at (\tikzumlAssemblyConnectorStart@nodeName.\tikzumlAssemblyConnectorStartAnchor) {};%
+ \node[inner sep=0] (\tikzumlAssemblyConnectorEnd@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port-tmp) at (\tikzumlAssemblyConnectorEnd@nodeName.\tikzumlAssemblyConnectorEndAnchor) {};%
+ %
+ \umlrelation[style={tikzuml connector style}, #1]{\tikzumlAssemblyConnectorStart@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port-tmp}{\tikzumlAssemblyConnectorEnd@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port-tmp}%
+ %
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorWithPort}{tikzumlTrue}}{%
+ \node[inner sep=0.5*\tikzumlAssemblyConnectorWidth, rectangle, draw=\tikzumlAssemblyConnectorDrawColor, fill=\tikzumlAssemblyConnectorPortFillColor] (\tikzumlAssemblyConnectorStart@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port) at (\tikzumlAssemblyConnectorStart@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port-tmp) {};%
+ \node[inner sep=0.5*\tikzumlAssemblyConnectorWidth, rectangle, draw=\tikzumlAssemblyConnectorDrawColor, fill=\tikzumlAssemblyConnectorPortFillColor] (\tikzumlAssemblyConnectorEnd@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port) at (\tikzumlAssemblyConnectorEnd@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port-tmp) {};%
+ }{%
+ \node[inner sep=0] (\tikzumlAssemblyConnectorStart@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port) at (\tikzumlAssemblyConnectorStart@nodeName.\tikzumlAssemblyConnectorStartAnchor) {};%
+ \node[inner sep=0] (\tikzumlAssemblyConnectorEnd@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port) at (\tikzumlAssemblyConnectorEnd@nodeName.\tikzumlAssemblyConnectorEndAnchor) {};%
+ }%
+ %
+ \addtocounter{tikzumlRelationNum}{-1}%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorName}{connector-\thetikzumlConnectorNum}}{%
+ \edef\tikzumlAssemblyConnectorName{relation-\thetikzumlRelationNum}%
+ \edef\tikzumlAssemblyConnectorSymbolName{\tikzumlAssemblyConnectorLabel@nodeName}%
+ }{%
+ \edef\tikzumlAssemblyConnectorSymbolName{\tikzumlAssemblyConnectorName}%
+ }%
+ %
+ \stepcounter{tikzumlRelationNum}%
+ %
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{--}}{%
+ \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorStart@nodeName}{\tikzumlAssemblyConnectorEnd@nodeName}%
+ }{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{-|}}{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorFirstArm}{tikzumlTrue}}{%
+ \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorStart@nodeName}{\tikzumlAssemblyConnectorName-2}%
+ }{%
+ \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorName-2}{\tikzumlAssemblyConnectorEnd@nodeName}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{|-}}{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorFirstArm}{tikzumlTrue}}{%
+ \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorStart@nodeName}{\tikzumlAssemblyConnectorName-2}%
+ }{%
+ \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorName-2}{\tikzumlAssemblyConnectorEnd@nodeName}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{-|-}}{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorFirstArm}{tikzumlTrue}}{%
+ \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorStart@nodeName}{\tikzumlAssemblyConnectorName-2}%
+ }{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorLastArm}{tikzumlTrue}}{%
+ \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorName-4}{\tikzumlAssemblyConnectorEnd@nodeName}%
+ }{%
+ \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorName-2}{\tikzumlAssemblyConnectorName-4}%
+ }%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{|-|}}{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorFirstArm}{tikzumlTrue}}{%
+ \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorStart@nodeName}{\tikzumlAssemblyConnectorName-2}%
+ }{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorLastArm}{tikzumlTrue}}{%
+ \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorName-4}{\tikzumlAssemblyConnectorEnd@nodeName}%
+ }{%
+ \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorName-2}{\tikzumlAssemblyConnectorName-4}%
+ }%
+ }%
+ }{}%
+ }%
+ }%
+ }%
+ }%
+ \stepcounter{tikzumlConnectorNum}%
+}%
+%
+% shortcuts of \umlassemblyconnector
+\newcommand{\umlHVassemblyconnector}[3][]{%
+ \pgfkeys{/tikzuml/HVassemblyconnector/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlHVassemblyconnector, forbidden option geometry}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/HVassemblyconnector/.cd, #1}%
+ \umlassemblyconnector[geometry=-|, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlVHassemblyconnector}[3][]{%
+ \pgfkeys{/tikzuml/VHassemblyconnector/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlVHassemblyconnector, forbidden option geometry}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/VHassemblyconnector/.cd, #1}%
+ \umlassemblyconnector[geometry=|-, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlHVHassemblyconnector}[3][]{%
+ \pgfkeys{/tikzuml/HVHassemblyconnector/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlHVHassemblyconnector, forbidden option geometry}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/HVHassemblyconnector/.cd, #1}%
+ \umlassemblyconnector[geometry=-|-, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlVHVassemblyconnector}[3][]{%
+ \pgfkeys{/tikzuml/VHVassemblyconnector/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlVHVassemblyconnector, forbidden option geometry}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/VHVassemblyconnector/.cd, #1}%
+ \umlassemblyconnector[geometry=|-|, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlport}[3][]{%
+ \pgfkeys{/tikzuml/port/.cd, draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlPortDefaultFillColor,%
+ width/.initial=\tikzumlPortDefaultWidth,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \errmessage{TIKZUML ERROR : in umlport forbidden option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/port/.cd, #1}%
+ \pgfkeys{/tikzuml/port/.cd, width/.get=\tikzumlPortWidth,%
+ draw/.get=\tikzumlPortDrawColor, fill/.get=\tikzumlPortFillColor}%
+ \edef\tikzumlPort@name{#2}%
+ \edef\tikzumlPort@anchor{#3}%
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlPort@nodeName{\tikzumlPort@name}}\x%
+ %
+ \node[inner sep=0.5*\tikzumlPortWidth, rectangle, draw=\tikzumlPortDrawColor, fill=\tikzumlPortFillColor] (\tikzumlPort@nodeName-\tikzumlPort@anchor-port) at (\tikzumlPort@nodeName.\tikzumlPort@anchor) {};%
+}%
+%
+\newcommand{\umldelegateconnector}[3][]{%
+ \def\tikzumlDelegateConnectorWithStartPort{tikzumlFalse}%
+ \def\tikzumlDelegateConnectorWithEndPort{tikzumlFalse}%
+ \pgfkeys{/tikzuml/delegateconnector/.cd,
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umldelegateconnector, forbidden option stereo}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/delegateconnector/.cd, #1}%
+ \umlrelation[style={tikzuml connector style}, stereo=delegate, #1]{#2}{#3}%
+}%
+%
+% shortcuts of \umldelegateconnector
+\newcommand{\umlHVdelegateconnector}[3][]{%
+ \pgfkeys{/tikzuml/HVdelegateconnector/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}\OR\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlHVdelegateconnector, forbidden option \keyname}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/HVdelegateconnector/.cd, #1}%
+ \umldelegateconnector[geometry=-|, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlVHdelegateconnector}[3][]{%
+ \pgfkeys{/tikzuml/VHdelegateconnector/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}\OR\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlVHdelegateconnector, forbidden option \keyname}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/VHdelegateconnector/.cd, #1}%
+ \umldelegateconnector[geometry=|-, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlHVHdelegateconnector}[3][]{%
+ \pgfkeys{/tikzuml/HVHdelegateconnector/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}\OR\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlHVHdelegateconnector, forbidden option \keyname}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/HVHdelegateconnector/.cd, #1}%
+ \umldelegateconnector[geometry=-|-, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlVHVdelegateconnector}[3][]{%
+ \pgfkeys{/tikzuml/VHVdelegateconnector/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}\OR\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlVHVdelegateconnector, forbidden option \keyname}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/VHVdelegateconnector/.cd, #1}%
+ \umldelegateconnector[geometry=|-|, #1]{#2}{#3}%
+}%
+%%% End of tikz-uml.sty
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \ No newline at end of file
diff --git a/10-entwurfsheft/.gitignore b/10-entwurfsheft/.gitignore
new file mode 100644
index 0000000..87ec682
--- /dev/null
+++ b/10-entwurfsheft/.gitignore
@@ -0,0 +1,302 @@
+## Core latex/pdflatex auxiliary files:
+*.aux
+*.lof
+*.log
+*.lot
+*.fls
+*.out
+*.toc
+*.fmt
+*.fot
+*.cb
+*.cb2
+.*.lb
+
+## Intermediate documents:
+*.dvi
+*.xdv
+*-converted-to.*
+# these rules might exclude image files for figures etc.
+# *.ps
+# *.eps
+*.pdf
+!assets/*.pdf
+
+## Generated if empty string is given at "Please type another file name for output:"
+.pdf
+
+## Bibliography auxiliary files (bibtex/biblatex/biber):
+*.bbl
+*.bcf
+*.blg
+*-blx.aux
+*-blx.bib
+*.run.xml
+
+## Build tool auxiliary files:
+*.fdb_latexmk
+*.synctex
+*.synctex(busy)
+*.synctex.gz
+*.synctex.gz(busy)
+*.pdfsync
+
+## Build tool directories for auxiliary files
+# latexrun
+latex.out/
+
+## Auxiliary and intermediate files from other packages:
+# algorithms
+*.alg
+*.loa
+
+# achemso
+acs-*.bib
+
+# amsthm
+*.thm
+
+# beamer
+*.nav
+*.pre
+*.snm
+*.vrb
+
+# changes
+*.soc
+
+# comment
+*.cut
+
+# cprotect
+*.cpt
+
+# elsarticle (documentclass of Elsevier journals)
+*.spl
+
+# endnotes
+*.ent
+
+# fixme
+*.lox
+
+# feynmf/feynmp
+*.mf
+*.mp
+*.t[1-9]
+*.t[1-9][0-9]
+*.tfm
+
+#(r)(e)ledmac/(r)(e)ledpar
+*.end
+*.?end
+*.[1-9]
+*.[1-9][0-9]
+*.[1-9][0-9][0-9]
+*.[1-9]R
+*.[1-9][0-9]R
+*.[1-9][0-9][0-9]R
+*.eledsec[1-9]
+*.eledsec[1-9]R
+*.eledsec[1-9][0-9]
+*.eledsec[1-9][0-9]R
+*.eledsec[1-9][0-9][0-9]
+*.eledsec[1-9][0-9][0-9]R
+
+# glossaries
+*.acn
+*.acr
+*.glg
+*.glo
+*.gls
+*.glsdefs
+*.lzo
+*.lzs
+*.slg
+*.slo
+*.sls
+
+# uncomment this for glossaries-extra (will ignore makeindex's style files!)
+*.ist
+
+# gnuplot
+*.gnuplot
+*.table
+
+# gnuplottex
+*-gnuplottex-*
+
+# gregoriotex
+*.gaux
+*.glog
+*.gtex
+
+# htlatex
+*.4ct
+*.4tc
+*.idv
+*.lg
+*.trc
+*.xref
+
+# hyperref
+*.brf
+
+# knitr
+*-concordance.tex
+# TODO Uncomment the next line if you use knitr and want to ignore its generated tikz files
+# *.tikz
+*-tikzDictionary
+
+# listings
+*.lol
+
+# luatexja-ruby
+*.ltjruby
+
+# makeidx
+*.idx
+*.ilg
+*.ind
+
+# minitoc
+*.maf
+*.mlf
+*.mlt
+*.mtc[0-9]*
+*.slf[0-9]*
+*.slt[0-9]*
+*.stc[0-9]*
+
+# minted
+_minted*
+*.pyg
+
+# morewrites
+*.mw
+
+# newpax
+*.newpax
+
+# nomencl
+*.nlg
+*.nlo
+*.nls
+
+# pax
+*.pax
+
+# pdfpcnotes
+*.pdfpc
+
+# sagetex
+*.sagetex.sage
+*.sagetex.py
+*.sagetex.scmd
+
+# scrwfile
+*.wrt
+
+# svg
+svg-inkscape/
+
+# sympy
+*.sout
+*.sympy
+sympy-plots-for-*.tex/
+
+# pdfcomment
+*.upa
+*.upb
+
+# pythontex
+*.pytxcode
+pythontex-files-*/
+
+# tcolorbox
+*.listing
+
+# thmtools
+*.loe
+
+# TikZ & PGF
+*.dpth
+*.md5
+*.auxlock
+
+# titletoc
+*.ptc
+
+# todonotes
+*.tdo
+
+# vhistory
+*.hst
+*.ver
+
+# easy-todo
+*.lod
+
+# xcolor
+*.xcp
+
+# xmpincl
+*.xmpi
+
+# xindy
+*.xdy
+
+# xypic precompiled matrices and outlines
+*.xyc
+*.xyd
+
+# endfloat
+*.ttt
+*.fff
+
+# Latexian
+TSWLatexianTemp*
+
+## Editors:
+# WinEdt
+*.bak
+*.sav
+
+# Texpad
+.texpadtmp
+
+# LyX
+*.lyx~
+
+# Kile
+*.backup
+
+# gummi
+.*.swp
+
+# KBibTeX
+*~[0-9]*
+
+# TeXnicCenter
+*.tps
+
+# auto folder when using emacs and auctex
+./auto/*
+*.el
+
+# expex forward references with \gathertags
+*-tags.tex
+
+# standalone packages
+*.sta
+
+# Makeindex log files
+*.lpz
+
+# xwatermark package
+*.xwm
+
+# REVTeX puts footnotes in the bibliography by default, unless the nofootinbib
+# option is specified. Footnotes are the stored in a file with suffix Notes.bib.
+# Uncomment the next line to have this generated file ignored.
+#*Notes.bib
diff --git a/10-entwurfsheft/.gitlab-ci.yml b/10-entwurfsheft/.gitlab-ci.yml
new file mode 100644
index 0000000..27d0617
--- /dev/null
+++ b/10-entwurfsheft/.gitlab-ci.yml
@@ -0,0 +1,36 @@
+plantuml:
+ stage: .pre
+ image:
+ name: plantuml/plantuml
+ entrypoint: [""]
+ script:
+ - java -jar plantuml.jar -tpdf assets/diagrams/*.puml
+ artifacts:
+ paths:
+ - assets
+
+tex:
+ stage: build
+ image: texlive/texlive
+ script:
+ - mkdir public
+ - make tex
+ - mv *.pdf public
+ artifacts:
+ paths:
+ - public
+ dependencies:
+ - plantuml
+
+pages:
+ stage: deploy
+ script:
+ - echo Hello, World!
+ artifacts:
+ paths:
+ - public
+ rules:
+ - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
+ dependencies:
+ - tex
+
diff --git a/10-entwurfsheft/.latexmkrc b/10-entwurfsheft/.latexmkrc
new file mode 100644
index 0000000..bec2b38
--- /dev/null
+++ b/10-entwurfsheft/.latexmkrc
@@ -0,0 +1,7 @@
+# https://tex.stackexchange.com/questions/1226/how-to-make-latexmk-use-makeglossaries
+add_cus_dep('glo', 'gls', 0, 'makeglo2gls');
+add_cus_dep('acn', 'acr', 0, 'makeglo2gls');
+sub makeglo2gls {
+ system("makeglossaries $_[0]");
+}
+
diff --git a/10-entwurfsheft/Makefile b/10-entwurfsheft/Makefile
new file mode 100644
index 0000000..75a951a
--- /dev/null
+++ b/10-entwurfsheft/Makefile
@@ -0,0 +1,18 @@
+MAIN = entwurfsheft
+FLAGS = -pdf
+
+all: clean compile
+compile: diagram tex
+clean: clean-diagram clean-tex
+
+dev:
+ latexmk $(FLAGS) -pvc $(MAIN)
+tex:
+ latexmk $(FLAGS) $(MAIN)
+diagram:
+ java -jar plantuml.jar -tpdf assets/diagrams/*.puml
+clean-tex:
+ latexmk -C
+clean-diagram:
+ find assets/diagrams -type f -not -name '*.puml' -delete
+
diff --git a/10-entwurfsheft/README.md b/10-entwurfsheft/README.md
new file mode 100644
index 0000000..2c08f29
--- /dev/null
+++ b/10-entwurfsheft/README.md
@@ -0,0 +1,31 @@
+# Entwurfsheft
+
+> Systemdesign und -spezifikation
+
+## Diagramme
+
+Installiere [PlantUML](https://plantuml.com/starting) (oder über einen Paketmanager).
+
+Arbeiten an Diagrammen mit Echtzeit-Vorschau (Anzeige wird beim Speichern der
+puml-Datei aktualisiert):
+```sh
+java -jar plantuml.jar -gui assets/classdiagram.puml
+
+# bzw (wenn zu PATH hinzugefügt oder Linux)
+plantuml -gui assets/classdiagram.puml
+```
+
+Bauen der Diagramme:
+```sh
+java -jar plantuml.jar -teps assets/*.puml
+
+# bzw (wenn zu PATH hinzugefügt oder Linux)
+plantuml -teps assets/*.puml
+
+# bzw über Makefile (Linux)
+make diagram
+
+# oder zum Erstellen von Diagrammen und LaTeX:
+make
+```
+
diff --git a/10-entwurfsheft/assets/.gitignore b/10-entwurfsheft/assets/.gitignore
new file mode 100644
index 0000000..16252a4
--- /dev/null
+++ b/10-entwurfsheft/assets/.gitignore
@@ -0,0 +1,3 @@
+diagrams/*
+!diagrams/*.puml
+
diff --git a/10-entwurfsheft/assets/KIT_Deckblatt.pdf b/10-entwurfsheft/assets/KIT_Deckblatt.pdf
new file mode 100644
index 0000000..7de8ed4
--- /dev/null
+++ b/10-entwurfsheft/assets/KIT_Deckblatt.pdf
Binary files differ
diff --git a/10-entwurfsheft/assets/diagrams/backendComponentDiagram.puml b/10-entwurfsheft/assets/diagrams/backendComponentDiagram.puml
new file mode 100644
index 0000000..806522c
--- /dev/null
+++ b/10-entwurfsheft/assets/diagrams/backendComponentDiagram.puml
@@ -0,0 +1,61 @@
+@startuml
+' skinparam linetype ortho
+
+'#########################################################################
+'SubscriptionsAPI
+component SubscriptionsAPI {
+
+ component SubscriptionService
+ component SubscriptionController
+ component SubscriptionDataAccessLayer
+
+ portout "Webserver" as wSub
+ portin "Database" as dSub
+ }
+
+dSub --0)- SubscriptionDataAccessLayer
+SubscriptionDataAccessLayer --0)- SubscriptionService
+SubscriptionService --0)- SubscriptionController
+SubscriptionController --0)- wSub
+
+'#########################################################################
+
+
+'#########################################################################
+'EpisodeActionsAPI
+
+component EpisodeActionsAPI {
+ component EpisodeActionService
+ component EpisodeActionController
+ component EpisodeActionDataAccessLayer
+
+ portout "Webserver" as wEpisode
+ portin "Database" as dEpisode
+}
+
+dEpisode --0)- EpisodeActionDataAccessLayer
+EpisodeActionController --0)- wEpisode
+EpisodeActionDataAccessLayer --0)- EpisodeActionService
+EpisodeActionService --0)- EpisodeActionController
+
+'#########################################################################
+
+
+'#########################################################################
+'AuthenticationAPI
+
+component AuthenticationAPI {
+ component AuthenticationService
+ component AuthenticationController
+ component AuthenticationDataAccessLayer
+
+ portout "Webserver" as wAuth
+ portin "Database" as dAuth
+}
+
+dAuth --0)- AuthenticationDataAccessLayer
+AuthenticationController --0)- wAuth
+AuthenticationDataAccessLayer --0)- AuthenticationService
+AuthenticationService --0)- AuthenticationController
+
+@enduml
diff --git a/10-entwurfsheft/assets/diagrams/classdiagram.puml b/10-entwurfsheft/assets/diagrams/classdiagram.puml
new file mode 100644
index 0000000..4b1970a
--- /dev/null
+++ b/10-entwurfsheft/assets/diagrams/classdiagram.puml
@@ -0,0 +1,463 @@
+@startuml
+' skinparam linetype ortho
+' skinparam groupInheritance 2
+allowmixing
+
+package subscriptionsAPI <<Frame>> {
+ package subscriptionDataAccessLayer <<Frame>> {
+ class SubscriptionDataAccessService <<@Repository>> {
+ <<create>> SubscriptionDataAccessService(JpaTemplate jpaTemplate)
+ int uploadSubscriptions(String username, List<SubscriptionAction> subscriptions)
+ List<String> getSubscriptions(String username)
+ List<String> getSubscriptionsSince(String username, LocalDateTime time)
+ int addSubscriptions(String username, List<SubscriptionAction> addedSubscriptions)
+ int removeSubscriptions(String username, List<SubscriptionAction> removedSubscriptions)
+ List<SubscriptionTitles> getTitles(String username)
+ }
+
+ interface SubscriptionDao {
+ int uploadSubscriptions(String username, List<SubscriptionAction> subscriptions)
+ List<String> getSubscriptions(String username)
+ List<String> getSubscriptionsSince(String username, LocalDateTime time)
+ int addSubscriptions(String username, List<SubscriptionAction> addedSubscriptions)
+ int removeSubscriptions(String username, List<SubscriptionAction> removedSubscriptions)
+ List<SubscriptionTitles> getTitles(String username)
+ }
+ }
+
+ package subscriptionService <<Frame>> {
+ class SubscriptionService <<@Service>> {
+ <<create>> SubscriptionService(SubscriptionDao subscriptionDao)
+ int uploadSubscriptions(String username, List<SubscriptionAction> subscriptions)
+ List<String> getSubscriptions(String username)
+ List<String> getSubscriptionsSince(String username, LocalDateTime time)
+ int addSubscriptions(String username, List<SubscriptionAction> addedSubscriptions)
+ int removeSubscriptions(String username, List<SubscriptionAction> removedSubscriptions)
+ List<SubscriptionTitles> getTitles(String username)
+ }
+ }
+
+ package subscriptionController <<Frame>> {
+ class SubscriptionController <<@Controller>>{
+ ' @Autowired
+ <<create>> SubscriptionController(SubscriptionService subscriptionService)
+ ' @GetMapping
+ ResponseEntity<List<String>> getSubscriptions(String username, String deviceID, String functionJSONP)
+ ' @PutMapping
+ ResponseEntity<String> uploadSubscriptions(String username, String deviceID, List<String> subscriptions)
+ ' @PostMapping
+ ResponseEntity<SubscriptionDelta> applySubscriptionDelta(String username, String deviceID, SubscriptionDelta delta)
+ ' @GetMapping
+ ResponseEntity<SubscriptionDelta> getSubscriptionDelta(String username, String deviceID, long since)
+ ResponseEntity<List<SubscriptionTitles>> getTitles(String username, String deviceID)
+ }
+
+ class SubscriptionTitles {
+ <<create>> SubscriptionTitles(Subscription subscription, List<EpisodeActionPost> episodeTitles)
+ Subscription getSubscription()
+ List<EpisodeActionPost> getEpisodesTitles()
+ }
+
+ class SubscriptionDelta {
+ <<create>> SubscriptionDelta(List<String> add, List<String> remove)
+ List<String> getRemove()
+ LocalDate getTimestamp()
+ List<List<String>> getUpdate_urls()
+ }
+ }
+
+}
+
+package episodeActionsAPI <<Frame>> {
+ package episodeActionDataAccessLayer <<Frame>> {
+ class EpisodeActionDataAccessService <<@Repository>> {
+ <<create>> EpisodeActionDataAccessService (JpaTemplate jpaTemplate)
+ long addEpisodeActions(String username, List<EpisodeActionPost> episodeActionPosts)
+ List<EpisodeActionPost> getEpisodeActions(String username)
+ List<EpisodeActionPost> getEpisodeActionsOfPodcast(String username, String podcastURL)
+ List<EpisodeActionPost> getEpisodeActionsSince(String username, LocalDateTime since)
+ List<EpisodeActionPost> getEpisodeActionsOfPodcastSince(String username, String podcastURL, LocalDateTime since)
+ }
+
+ interface EpisodeActionDao {
+ long addEpisodeActions(String username, List<EpisodeActionPost> episodeActionPosts)
+ List<EpisodeActionPost> getEpisodeActions(String username)
+ List<EpisodeActionPost> getEpisodeActionsOfPodcast(String username, String podcastURL)
+ List<EpisodeActionPost> getEpisodeActionsSince(String username, LocalDateTime since)
+ List<EpisodeActionPost> getEpisodeActionsOfPodcastSince(String username, String podcastURL, LocalDateTime since)
+ }
+ }
+
+ package episodeActionService <<Frame>> {
+ class EpisodeActionService <<@Service>> {
+ <<create>> EpisodeActionService (EpisodeActionDao episodeActionDao)
+ LocalDateTime addEpisodeActions(String username, List<EpisodeActionPosts> episodeActionPosts)
+ List<EpisodeActionPost> getEpisodeActions(String username)
+ List<EpisodeActionPost> getEpisodeActionsOfPodcast(String username, String podcastURL)
+ List<EpisodeActionPost> getEpisodeActionsSince(String username, LocalDateTime since)
+ List<EpisodeActionPost> getEpisodeActionsOfPodcastSince(String username, String podcastURL, LocalDateTime since)
+ }
+ }
+
+ package episodeActionController <<Frame>> {
+ class EpisodeActionController <<@Controller>>{
+ <<create>> EpisodeActionController (EpisodeActionService episodeActionService)
+ ResponseEntity<EpisodeActionPostResponse> addEpisodeActions(String username, EpisodeActionPostRequest episodeActionPostRequest)
+ ResponseEntity<EpisodeActionGetResponse> getEpisodeActions(String username, String deviceID, boolean aggregated)
+ ResponseEntity<EpisodeActionGetResponse> getEpisodeActionsOfPodcast(String username, String podcastURL, String deviceID, boolean aggregated)
+ ResponseEntity<EpisodeActionGetResponse> getEpisodeActionsSince(String username, String deviceID, long since, boolean aggregated)
+ ResponseEntity<EpisodeActionGetResponse> getEpisodeActionsOfPodcastSince(String username, String podcastURL, String deviceID, long since, boolean aggregated)
+ }
+
+ class EpisodeActionPostResponse {
+ <<create>> EpisodeActionPostResponse(List<Pair<String, String>> updateURLs)
+ long getTimestamp()
+ List<Pair<String, String>> getUpdatedURLs()
+ }
+
+ class EpisodeActionPost {
+ <<create>> EpisodeActionPost(String podcastURL, String episodeURL, Action action, LocalDateTime timestamp, int started, int position)
+ String getPodcastURL()
+ String getEpisodeURL()
+ int getGUID()
+ Action getAction()
+ LocalDateTime getTimestamp()
+ int getStarted()
+ int getPosition()
+ EpisodeAction getEpisodeAction()
+ }
+
+ class EpisodeActionPostRequest {
+ <<create>> EpisodeActionPostRequest(List<EpisodeActionPost> episodeActionPosts)
+ List<EpisodeActionPost> getEpisodeActionPosts()
+ }
+
+ class EpisodeActionGetResponse {
+ <<create>> EpisodeActionGetResponse(List<EpisodeActionPost> episodeActionPosts)
+ List<EpisodeActionPost> getEpisodeActionPosts()
+ long getTimestamp()
+ }
+ }
+}
+
+package authenticationAPI <<Frame>> {
+ package authenticationDataAccessLayer <<Frame>> {
+ ' interface AuthenticationDao {
+ ' String login(String username)
+ ' int logout(String username)
+ ' }
+
+ ' class AuthenticationDataAccessService <<@Respository>> {
+ ' <<create>> AuthenticationDataAccessService(JpaTemplate jpaTemplate)
+ ' String login(String username)
+ ' int logout(String username)
+ ' }
+
+ interface UserDetailsManager {
+ void createUser(UserDetails userDetails)
+ void changePassword(String oldPassword, String newPassword)
+ void deleteUser(String username)
+ void updateUser(UserDetails user)
+ boolean userExists(String username)
+ }
+ note left
+ Aus org.springframework.security.provisioning
+ - liefert Methoden zum Erstellen neuer User
+ und zum Aktualisieren bestehender.
+ end note
+
+ class JdbcUserDetailsManager <<@Repository>> {
+ <<create>> JdbcUserDetailsManager(DataSource dataSource)
+ void createUser(UserDetails user)
+ void changePassword(String oldPassword, String newPassword)
+ void deleteUser(String username)
+ void updateUser(UserDetails user)
+ boolean userExists(String username)
+ }
+ note right
+ User Management Service aus dem Paket
+ org.springframework.security.provisioning
+ der CRUD Operationen für User bereitstellt.
+ Hier sind nur die relevanten Methoden modelliert.
+ end note
+ }
+
+ package authenticationService <<Frame>> {
+ class AuthenticationService <<@Service>> {
+ --
+ <<create>> AuthenticationService(UserDetailsManager userDetailsManager)
+ List<String> verifyLogin(String username)
+ int logout(String username)
+ int forgotPassword(ForgotPasswordRequest forgotPasswordRequest)
+ .. via JdbcUserDetailsManager ..
+ int resetPassword(String username, RequestWithPassword requestWithPassword)
+ int registerUser(UserDetails user)
+ int changePassword(String username, ChangePasswordRequest changePasswordRequest)
+ int deleteUser(String username, RequestWithPassword requestWithPassword)
+ }
+
+ class JavaMailSenderImpl {}
+ note left
+ Aus org.springframework.mail.javamail.
+ Implementierung des JavaMailSender Interfaces,
+ welches das MailSender Interface durch Unterstützung
+ von MIME Nachrichten erweitert.
+ Das MailSender Interface definiert dabei eine
+ Strategie zum Versenden einfacher Mails.
+ Unterstützt sowohl JavaMail MimeMessages und
+ Spring SimpleMailMessages.
+ end note
+ }
+
+ package authenticationController <<Frame>> {
+ class AuthenticationController <<@Controller>> {
+ <<create>> AuthenticationController(AuthenticationService authenticationService)
+ ResponseEntity<List<String>> verifyLogin(String username)
+ ResponseEntity<Integer> logout(String username)
+ ResponseEntity<Integer> forgotPassword(ForgotPasswordRequest forgotPasswordRequest)
+ ResponseEntity<Integer> resetPassword(String username, RequestWithPassword requestWithPassword)
+ ResponseEntity<Integer> registerUser(UserDetails user)
+ ResponseEntity<Integer> changePassword(String username, ChangePasswordRequest changePasswordRequest)
+ ResponseEntity<Integer> deleteUser(String username, RequestWithPassword requestWithPassword)
+ }
+
+ class ChangePasswordRequest {
+ <<create>> ChangePasswordRequest(String oldPassword, String newPassword)
+ String getOldPassword()
+ String getNewPassword()
+ }
+
+ class ForgotPasswordRequest {
+ <<create>> ForgotPasswordRequest(String email)
+ String getEmail()
+ }
+
+ class RequestWithPassword {
+ <<create>> ResetPasswordRequest(String password)
+ String getPassword()
+ }
+ }
+}
+
+package model <<Frame>> {
+ class Subscription {
+ <<create>> Subscription(String url, String title)
+ int getID()
+ String getURL()
+ long getLastActionTimestamp()
+ String getTitle()
+ }
+
+ class SubscriptionAction {
+ <<create>> SubscriptionAction(int userID, int subscriptionID)
+ int getID()
+ int getUserID()
+ int getSubscriptionID()
+ long getTimestamp()
+ boolean getAdded()
+ }
+
+ class Episode {
+ <<create>> Episode(int subscriptionID, int id, String url, String title, String thumbnailURL, int total)
+ int getSubscriptionID()
+ int getID()
+ int getGUID()
+ String getURL()
+ String getTitle()
+ int getTotal()
+ }
+
+ enum Action {
+ Download
+ Play
+ Delete
+ New
+ Flattr
+ String getJsonProperty()
+ }
+
+ class EpisodeAction {
+ <<create>> EpisodeAction(Action action, LocalDateTime timestamp, int started, int position)
+ int getEpisodeID()
+ Action getAction()
+ long getTimestamp()
+ int getStarted()
+ int getPosition()
+ void setEpisodeID()
+ EpisodeActionPost getEpisodeActionPost(String podcastURL, String episodeURL)
+ }
+
+ interface UserDetails {
+ String getUsername()
+ String getPassword()
+ Collection<Authority> getAuthorities()
+ boolean isAccountExpired()
+ boolean isAccountLocked()
+ boolean isCredentialsNonExpired()
+ boolean isEnabled()
+ }
+ note left
+ Aus org.springframework.security.core.userdetails.
+ Wird für die Schnittstelle UserDetailsManager benötigt.
+ Stellt wichtige Informationen eines Users bereit.
+ Diese werden nur indirekt von Spring Security
+ benutzt, indem sie vorher in Authentication Objekten
+ gekapselt werden.
+ end note
+
+ class User {
+ --
+ <<create>> User(String username, String password)
+ int getID()
+ String getSessionToken()
+ boolean getEmailIsValidated()
+ .. interface methods ..
+ String getUsername()
+ String getPassword()
+ Collection<Authority> getAuthorities()
+ boolean isAccountExpired()
+ boolean isAccountLocked()
+ boolean isCredentialsNonExpired()
+ boolean isEnabled()
+ }
+
+ interface GrantedAuthority {
+ String getAuthority()
+ }
+ note right
+ Aus org.springframework.security.core.
+ Wird für die Schnittstelle UserDetails benötigt.
+ Repräsentiert eine Autorisierung, die einem
+ Authentication Objekt gewährt wird.
+ end note
+
+ class Authority {
+ <<create>> Authority()
+ String getAuthority()
+ }
+}
+
+package util <<Frame>> {
+ class RSSParser {
+ <<create>> RSSParser(String subscriptionURL)
+ String getSubscriptionTitle()
+ List<Episode> getEpisodes()
+ Episode getEpisodeForURL(String episodeURL)
+ }
+ note bottom
+ Verwendet intern Spring um
+ HTTP-Anfragen zu erstellen.
+ end note
+
+ class CleanCronJob {
+ <<create>> CleanCronJob(JdbcUserDetailsManager jdbcUserDetailsManager)
+ void cleanInvalidUsers()
+ }
+ note bottom
+ Hintergrundservice, der in periodischen Abständen
+ Nutzer, die ihre E-Mail-Adresse nicht nach 24 Stunden
+ bestätigt haben, wieder aus der Datenbank löscht.
+ (Auf die Assoziation zu JdbcUserDetailsManager wird
+ im Sinne der Übersichtlichkeit verzichtet.)
+ end note
+
+ class ResponseEntity<T> {
+ <<create>> ResponseEntity(T body, HttpStatusCode status)
+ T getBody()
+ HttpStatusCode getStatusCode()
+ }
+ note bottom
+ Aus org.springframework.http.
+ Erweitert die Klasse HttpEntity, welche
+ ein HTTP Anfrage- oder Antwort-Objekt
+ repräsentiert, durch einen HttpStatusCode.
+ Wird von den Controller-Methoden als
+ Rückgabewert verwendet.
+ end note
+}
+
+class SecurityConfigurationBasicAuth {
+ <<create>> SecurityConfigurationBasicAuth()
+ PasswordEncoder encoder()
+ UserDetailsManager userDetailsService()
+ SecuryFilterChain fiterChain(HTTPSecurity http) throws Excpetion
+}
+note top
+ Erstellt einen Servlet Filter (springSecurityFilterChain)
+ der für die gesamte Sicherheit zuständig ist (Schutz der URLs,
+ Validierung von Anmeldedaten, Weiterleitung zur Anmeldung, etc.).
+end note
+
+class PSEApplication {
+ <<create>> PSEApplication()
+ void main(String[] args)
+}
+
+database Datenbank
+Datenbank <-[hidden]d- subscriptionsAPI
+Datenbank <-[hidden]d- episodeActionsAPI
+Datenbank <-[hidden]d- authenticationAPI
+() SQL as SQLSub
+() SQL as SQLAuth
+() SQL as SQLEpisode
+
+Datenbank -- SQLSub
+Datenbank -- SQLAuth
+Datenbank -- SQLEpisode
+
+SubscriptionController ..o PSEApplication
+AuthenticationController ..o PSEApplication
+EpisodeActionController ..o PSEApplication
+SecurityConfigurationBasicAuth ..o PSEApplication
+
+PSEApplication --() HTTP
+
+SQLSub )-- SubscriptionDataAccessService: JPA
+' SQLAuth )-- AuthenticationDataAccessService: JPA
+SQLAuth )-- JdbcUserDetailsManager: JDBC
+SQLEpisode )-- EpisodeActionDataAccessService: JPA
+
+Subscription <. SubscriptionAction: ID
+' Subscription <.. SubscriptionDataAccessService: DB
+' SubscriptionAction <.. SubscriptionDataAccessService: DB
+SubscriptionService --o SubscriptionController
+SubscriptionDao <.. SubscriptionService: <<use>>
+Subscription --o SubscriptionTitles
+EpisodeActionPost -o SubscriptionTitles
+SubscriptionDao <|. SubscriptionDataAccessService: <<realize>>
+
+' User <.. AuthenticationDataAccessService: DB
+' User <.. JdbcUserDetailsManager: DB
+UserDetailsManager <.. AuthenticationService: <<use>>
+' AuthenticationDao <.. AuthenticationService: <<use>>
+AuthenticationService --o AuthenticationController
+' AuthenticationDao <|. AuthenticationDataAccessService: <<realize>>
+UserDetailsManager <|. JdbcUserDetailsManager: <<realize>>
+UserDetailsManager <.. SecurityConfigurationBasicAuth: <<use>>
+UserDetails <|.. User: <<realize>>
+User -> Authority
+GrantedAuthority <|.. Authority: <<realize>>
+JavaMailSenderImpl <. AuthenticationService: <<use>>
+
+Action <-- EpisodeAction
+EpisodeActionPost -o EpisodeActionGetResponse
+EpisodeActionPost -o EpisodeActionPostRequest
+EpisodeAction .> Episode: ID
+' EpisodeAction <.. EpisodeActionDataAccessService: DB
+' Episode <.. EpisodeActionDataAccessService: DB
+EpisodeActionDao <.. EpisodeActionService: <<use>>
+EpisodeActionService --o EpisodeActionController
+EpisodeActionDao <|. EpisodeActionDataAccessService: <<realize>>
+
+RSSParser <. SubscriptionDataAccessService: <<use>>
+RSSParser <. EpisodeActionDataAccessService: <<use>>
+' JdbcUserDetailsManager <-- CleanCronJob
+
+model .o Datenbank: ORM (User, SubscriptionAction, Subscription, EpisodeAction, Episode)
+' Datenbank o.. Subscription: ORM
+' Datenbank o.. SubscriptionAction: ORM
+' Datenbank o.. Episode: ORM
+' Datenbank o.. EpisodeAction: ORM
+' Datenbank o.. User: ORM
+
+@enduml
diff --git a/10-entwurfsheft/assets/diagrams/componentdiagram.puml b/10-entwurfsheft/assets/diagrams/componentdiagram.puml
new file mode 100644
index 0000000..dea4a1d
--- /dev/null
+++ b/10-entwurfsheft/assets/diagrams/componentdiagram.puml
@@ -0,0 +1,53 @@
+@startuml
+
+[App] as app
+[VueRouter] as router
+[NavbarComponent] as navbar
+[LoginPage] as login_page
+[SubscriptionsPage] as abo_page
+[EpisodesPage] as episodes_page
+[SettingsPage] as settings_page
+[ForgotPasswordPage] as forgot_page
+[ResetPasswordPage] as reset_page
+note top
+ Wird in der E-Mail zum Zurücksetzen des Passworts mit dem JWT-Token verlinkt.
+ Sendet das alte und neue Passwort und den JWT an die API.
+end note
+[RegistrationPage] as registration_page
+
+[SubscriptionComponent] as sub
+[EpisodeComponent] as episode
+[LastUpdateComponent] as last_update
+[PasswordValidatorComponent] as password
+
+app --> router
+
+app --> navbar
+router --> login_page
+router --> forgot_page
+router --> reset_page
+router --> registration_page
+router --> abo_page
+router --> episodes_page
+router --> settings_page
+
+navbar -[hidden] router
+
+episodes_page -[hidden] abo_page
+login_page -[hidden] forgot_page
+registration_page -[hidden] reset_page
+abo_page -[hidden] settings_page
+forgot_page -[hidden] episodes_page
+' forgot_page -[hidden] settings_page
+
+abo_page --> sub
+episodes_page --> episode
+
+sub --> last_update
+episode --> last_update
+
+settings_page --> password
+reset_page --> password
+registration_page --> password
+
+@enduml
diff --git a/10-entwurfsheft/assets/diagrams/db.puml b/10-entwurfsheft/assets/diagrams/db.puml
new file mode 100644
index 0000000..bdefaea
--- /dev/null
+++ b/10-entwurfsheft/assets/diagrams/db.puml
@@ -0,0 +1,78 @@
+@startuml
+' Type Symbol
+' Zero or One |o--
+' Exactly One ||--
+' Zero or Many }o--
+' One or Many }|--
+
+skinparam linetype ortho
+
+entity User {
+ * int id <<unique>>
+ * <u>String email</u>
+ * String password
+ * boolean verified
+ * long created_at
+}
+
+entity SubscriptionAction {
+ * int id <<unique>>
+ * <u>int user_id</u>
+ * long timestamp
+ * int subscription_id
+ * boolean added
+}
+
+entity Subscription {
+ * int id <<unique>>
+ * <u>String url</u>
+ * long timestamp
+ * String title
+}
+
+entity Episode {
+ * int id <<unique>>
+ * <u>int guid <<unique>></u>
+ * <u>String url</u>
+ * String title
+ * int total
+ * int subscription_id
+}
+note right
+ Wenn der Client eine GUID aus dem Feed mitsendet, wird
+ diese statt der URL verwendet um die Episode zu finden.
+ So wird die Episode auch noch gefunden, nachdem sich
+ die URL geändert hat.
+end note
+note bottom of Episode
+ Wenn für die Episoden-URL einer EpisodeAction noch keine Episode in der Datenbank steht,
+ dann schreibe dafür ein Dummy-Objekt in Datenbank und lade asynchron die Episoden der Subscription.
+ Ersetze dann die Dummy-Objekte durch die Episoden und setze den Timestamp der Subscription auf
+ die aktuelle Zeit.
+ Um DoS-Angriffe auf den Backend-Server abzuwenden, können die Episoden einer Subscription erst
+ nach einer Stunde erneut gefetched werden. Bis dahin werden für EpisodeActions, die sich auf noch
+ nicht geladene Episoden beziehen, nur Dummy-Objekte für die Episoden in die Datenbank geschrieben.
+ Es sei noch darauf hingewiesen, dass diese Dummy-Episoden bei Anfragen nicht mit ausgegeben werden.
+end note
+
+entity EpisodeAction {
+ * int id <<unique>>
+ * <u>int user_id</u>
+ * int episode_id
+ * long timestamp
+ * int action
+ * int started
+ * int position
+}
+note right
+ Speichere für jede Episode
+ nur letzte Play-Action.
+endnote
+
+User ||--o{ EpisodeAction
+User ||--o{ SubscriptionAction
+SubscriptionAction }|--|| Subscription
+EpisodeAction }|--|| Episode
+Subscription ||-right-|{ Episode
+
+@enduml
diff --git a/10-entwurfsheft/assets/diagrams/deployment.puml b/10-entwurfsheft/assets/diagrams/deployment.puml
new file mode 100644
index 0000000..26918e2
--- /dev/null
+++ b/10-entwurfsheft/assets/diagrams/deployment.puml
@@ -0,0 +1,59 @@
+@startuml
+
+node "<<device>> \nBackend Server" as backendServer{
+ database " <<database system>> \n MariaDB Server 10.6" as database {
+ rectangle rectangle1 [
+ <<schema>>
+ User
+ ]
+ rectangle rectangle2 [
+ <<schema>>
+ SubscriptionAction
+ ]
+ rectangle rectangle3 [
+ <<schema>>
+ EpisodeAction
+ ]
+ rectangle rectangle4 [
+ <<schema>>
+ Subscription
+ ]
+ rectangle rectangle5 [
+ <<schema>>
+ Episode
+ ]
+ }
+
+ node "<<framework>> \nJava Spring" as javaSpring{
+ node " <<device>> \n Tomcat Webserver"
+ }
+}
+
+node "<<device>> \nFrontend" as frontendServer {
+
+}
+
+node "<<device>> \nEndgerät" as terminal {
+ node "<<application>> \nBrowser" as browser
+ node "<<application>> \nPodcatcher" as podcatcher
+}
+
+backendServer "1" - "*" podcatcher
+
+node "<<device>> \nFrontend Server" as frontendServer{
+ node "<<framework>> \nVue.js" as vuejs {
+
+ }
+}
+
+podcatcher -[hidden] browser
+
+backendServer - "1" frontendServer
+
+database "1" -- "1" javaSpring
+
+browser "*" -- frontendServer
+
+
+
+@enduml
diff --git a/10-entwurfsheft/assets/diagrams/sequencediagram-forgotAndResetPW.puml b/10-entwurfsheft/assets/diagrams/sequencediagram-forgotAndResetPW.puml
new file mode 100644
index 0000000..603130c
--- /dev/null
+++ b/10-entwurfsheft/assets/diagrams/sequencediagram-forgotAndResetPW.puml
@@ -0,0 +1,41 @@
+@startuml
+
+skinparam ParticipantPadding 30
+
+participant AuthenticationController << (C, #ADD1B2) @Controller >>
+-> AuthenticationController: ""POST /api/2/auth/forgot.json"" \n//@RequestBody ForgotPasswordRequest forgotPasswordRequest// \n\n-> forgotPassword(//forgotPasswordRequest//)
+activate AuthenticationController
+participant AuthenticationService << (C, #ADD1B2) @Service >>
+AuthenticationController -> AuthenticationService: forgotPassword(//forgotPasswordRequest//)
+activate AuthenticationService
+participant JavaMailSenderImpl << (C, #ADD1B2) >>
+AuthenticationService -> JavaMailSenderImpl: create link to reset password with JWT as URL parameter \n-> send(SimpleMailMessage simpleMessage) with link
+activate JavaMailSenderImpl
+<<- JavaMailSenderImpl: sends email with link containing a JWT to reset password
+JavaMailSenderImpl --> AuthenticationService
+deactivate JavaMailSenderImpl
+AuthenticationService --> AuthenticationController: int indicating status
+deactivate AuthenticationService
+<-- AuthenticationController: ResponseEntity<Integer> indicating status \n\n-> ""HTTP status code""
+deactivate AuthenticationController
+||60||
+-> AuthenticationController: ""PUT /api/2/auth/{username}/resetpassword.json"" \n//@RequestParam String jwt// \n//@RequestBody ResetPasswordRequest resetPasswordRequest// \n\n-> login user (""username"") via JWT (//jwt//) \n-> resetPassword(""username"", //resetPasswordRequest//)
+activate AuthenticationController
+AuthenticationController -> AuthenticationService: resetPassword(""username"", //resetPasswordRequest//)
+activate AuthenticationService
+participant JdbcUserDetailsManager << (C, #ADD1B2) @Repository >>
+AuthenticationService -> JdbcUserDetailsManager: String oldPassword = //resetPasswordRequest//.getOldPassword() \nString newPassword = //resetPasswordRequest//.getNewPassword() \n-> changePassword(newPassword, oldPassword)
+activate JdbcUserDetailsManager
+database Database
+JdbcUserDetailsManager -> Database: change password of logged in user
+activate Database
+Database --> JdbcUserDetailsManager
+deactivate Database
+JdbcUserDetailsManager --> AuthenticationService: int indicating status
+deactivate JdbcUserDetailsManager
+AuthenticationService --> AuthenticationController: int indicating status
+deactivate AuthenticationService
+<-- AuthenticationController: ResponseEntity<Integer> indicating status \n\n-> ""HTTP status code""
+deactivate AuthenticationController
+
+@enduml \ No newline at end of file
diff --git a/10-entwurfsheft/assets/diagrams/sequencediagram-getEpisodeActions.puml b/10-entwurfsheft/assets/diagrams/sequencediagram-getEpisodeActions.puml
new file mode 100644
index 0000000..47497d5
--- /dev/null
+++ b/10-entwurfsheft/assets/diagrams/sequencediagram-getEpisodeActions.puml
@@ -0,0 +1,38 @@
+@startuml
+
+' title =**Get All Episode Actions**
+
+participant EpisodeActionController << (C, #ADD1B2) @Controller >>
+-> EpisodeActionController: ""GET /api/2/episodes/{username}.json"" \n//@RequestParam("device") String deviceID// \n//@RequestParam("aggregated") boolean aggregated// \n\n-> getEpisodeActions(""username"", //deviceID//, //aggregated//)
+note right
+ Die Parameter //deviceID// und //aggregated// werden ignoriert,
+ da nicht zwischen Geräten unterschieden und für jede
+ Episode sowieso nur die letzte Play-Action gespeichert
+ wird. Dies gilt für alle GET-Anfragen der Episode Actions API.
+end note
+activate EpisodeActionController
+participant EpisodeActionService << (C, #ADD1B2) @Service >>
+EpisodeActionController -> EpisodeActionService: getEpisodeActions(""username"")
+activate EpisodeActionService
+participant EpisodeActionDataAccessService << (C, #ADD1B2) @Repository >>
+EpisodeActionService -> EpisodeActionDataAccessService: getEpisodeActions(""username"")
+activate EpisodeActionDataAccessService
+EpisodeActionDataAccessService -> EpisodeActionDataAccessService: getEpisodeActionsSince(""username"", \nLocalDateTime.MIN.toEpochSecond(ZoneOffset.UTC))
+database Database
+activate EpisodeActionDataAccessService
+EpisodeActionDataAccessService -> Database: get all EpisodeActions for all subscribed podcasts
+activate Database
+Database --> EpisodeActionDataAccessService: List<EpisodeAction> selectedEpisodeActions \n-> then remove all older than LocalDateTime.MIN (none)
+EpisodeActionDataAccessService -> Database: join EpisodeActions in selectedEpisodeActions with episodeURL of Episode
+Database --> EpisodeActionDataAccessService
+deactivate Database
+EpisodeActionDataAccessService --> EpisodeActionDataAccessService: List<EpisodeActionPost> episodeActionPosts
+deactivate EpisodeActionDataAccessService
+EpisodeActionDataAccessService --> EpisodeActionService: List<EpisodeActionPost> episodeActionPosts
+deactivate EpisodeActionDataAccessService
+EpisodeActionService --> EpisodeActionController: List<EpisodeActionPost> episodeActionPosts
+deactivate EpisodeActionService
+<-- EpisodeActionController: ResponseEntity<EpisodeActionGetResponse> response \n\n-> ""HTTP status code"" \n-> ""JSON""
+deactivate EpisodeActionController
+
+@enduml \ No newline at end of file
diff --git a/10-entwurfsheft/assets/diagrams/sequencediagram-getEpisodeActionsOfPodcastSince.puml b/10-entwurfsheft/assets/diagrams/sequencediagram-getEpisodeActionsOfPodcastSince.puml
new file mode 100644
index 0000000..d8797d1
--- /dev/null
+++ b/10-entwurfsheft/assets/diagrams/sequencediagram-getEpisodeActionsOfPodcastSince.puml
@@ -0,0 +1,32 @@
+@startuml
+
+' title =**Get Episode Actions of Podcast Since**
+
+participant EpisodeActionController << (C, #ADD1B2) @Controller >>
+-> EpisodeActionController: ""GET /api/2/episodes/{username}.json"" \n//@RequestParam("podcast") String podcastURL// \n//@RequestParam("device") String deviceID// \n//@RequestParam("since") long since// \n//@RequestParam("aggregated") boolean aggregated// \n\n-> getEpisodeActionsOfPodcastSince(""username"", //podcastURL//, //deviceID//, //since//, //aggregated//)
+note right
+ Die Parameter //deviceID// und //aggregated// werden ignoriert.
+ Siehe Notiz in Sequenzdiagramm **Get All Episode Actions**.
+end note
+activate EpisodeActionController
+participant EpisodeActionService << (C, #ADD1B2) @Service >>
+EpisodeActionController -> EpisodeActionService: getEpisodeActionsOfPodcastSince(""username"", //podcastURL//, //since//)
+activate EpisodeActionService
+participant EpisodeActionDataAccessService << (C, #ADD1B2) @Repository >>
+EpisodeActionService -> EpisodeActionDataAccessService: getEpisodeActionsOfPodcastSince(""username"", //podcastURL//, //since//)
+activate EpisodeActionDataAccessService
+database Database
+EpisodeActionDataAccessService -> Database: get all EpisodeActions the given podcast (//podcastURL//)
+activate Database
+Database --> EpisodeActionDataAccessService: List<EpisodeAction> selectedEpisodeActions \n-> then remove all older than //since//
+EpisodeActionDataAccessService -> Database: join EpisodeActions in selectedEpisodeActions with episodeURL of Episode
+Database --> EpisodeActionDataAccessService
+deactivate Database
+EpisodeActionDataAccessService --> EpisodeActionService: List<EpisodeActionPost> episodeActionPosts
+deactivate EpisodeActionDataAccessService
+EpisodeActionService --> EpisodeActionController: List<EpisodeActionPost> episodeActionPosts
+deactivate EpisodeActionService
+<-- EpisodeActionController: ResponseEntity<EpisodeActionGetResponse> response \n\n-> ""HTTP status code"" \n-> ""JSON""
+deactivate EpisodeActionController
+
+@enduml \ No newline at end of file
diff --git a/10-entwurfsheft/assets/diagrams/sequencediagram-getSubscriptions.puml b/10-entwurfsheft/assets/diagrams/sequencediagram-getSubscriptions.puml
new file mode 100644
index 0000000..4d8ab90
--- /dev/null
+++ b/10-entwurfsheft/assets/diagrams/sequencediagram-getSubscriptions.puml
@@ -0,0 +1,38 @@
+@startuml
+
+' title =**Get All Subscriptions**
+
+participant SubscriptionController << (C, #ADD1B2) @Controller >>
+-> SubscriptionController: ""GET /subscriptions/{username}.json"" \n"" /subscriptions/{username}/{deviceid}.json"" \n//@RequestParam("jsonp") String functionJSONP// \n\n-> getSubscriptions(""username"", ""deviceid"", //functionJSONP//)
+activate SubscriptionController
+note right
+ Die Parameter ""deviceid"" und
+ //functionJSONP// werden ignoriert,
+ da nicht zwischen Geräten unterschieden
+ und JSONP nicht unterstützt wird.
+end note
+participant SubscriptionService << (C, #ADD1B2) @Service >>
+SubscriptionController -> SubscriptionService: getSubscriptions(""username"")
+activate SubscriptionService
+participant SubscriptionDataAccessService << (C, #ADD1B2) @Repository >>
+SubscriptionService -> SubscriptionDataAccessService: getSubscriptions(""username"")
+activate SubscriptionDataAccessService
+SubscriptionDataAccessService -> SubscriptionDataAccessService: getSubscriptionsSince(""username"", LocalDateTime.MIN)
+database Database
+activate SubscriptionDataAccessService
+SubscriptionDataAccessService -> Database: get all Subscriptions for ""username""
+activate Database
+Database --> SubscriptionDataAccessService: List<Subscription> subscriptions
+SubscriptionDataAccessService -> Database: get Podcasts from Subscriptions
+Database --> SubscriptionDataAccessService: List<Podcast> subscribedPodcasts
+deactivate Database
+SubscriptionDataAccessService --> SubscriptionDataAccessService: List<String> podcastURLs
+deactivate SubscriptionDataAccessService
+SubscriptionDataAccessService --> SubscriptionService: List<String> podcastURLs
+deactivate SubscriptionDataAccessService
+SubscriptionService --> SubscriptionController: List<String> podcastURLs
+deactivate SubscriptionService
+<-- SubscriptionController: ResponseEntity<List<String>> podcastURLs \n \n-> ""HTTP status code"" \n-> ""JSON""
+deactivate SubscriptionController
+
+@enduml \ No newline at end of file
diff --git a/10-entwurfsheft/assets/diagrams/sequencediagram-register.puml b/10-entwurfsheft/assets/diagrams/sequencediagram-register.puml
new file mode 100644
index 0000000..b7b7aa1
--- /dev/null
+++ b/10-entwurfsheft/assets/diagrams/sequencediagram-register.puml
@@ -0,0 +1,26 @@
+@startuml
+
+' title =**Register**
+
+participant AuthenticationController << (C, #ADD1B2) @Controller >>
+-> AuthenticationController: ""POST /api/2/auth/register.json"" \n//@RequestBody UserDetails user// \n\n-> registerUser(//user//)
+activate AuthenticationController
+participant AuthenticationService << (C, #ADD1B2) @Service >>
+AuthenticationController -> AuthenticationService: registerUser(//user//)
+activate AuthenticationService
+participant JdbcUserDetailsManager << (C, #ADD1B2) @Repository >>
+AuthenticationService -> JdbcUserDetailsManager: createUser(//user//)
+activate JdbcUserDetailsManager
+database Database
+JdbcUserDetailsManager -> Database: create new User with given UserDetails (//user//)
+activate Database
+Database --> JdbcUserDetailsManager
+deactivate Database
+JdbcUserDetailsManager --> AuthenticationService: int indicating status
+deactivate JdbcUserDetailsManager
+AuthenticationService --> AuthenticationController: int indicating status
+deactivate AuthenticationService
+<-- AuthenticationController: ResponseEntity<Integer> indicating status \n\n-> ""HTTP status code""
+deactivate AuthenticationController
+
+@enduml \ No newline at end of file
diff --git a/10-entwurfsheft/assets/diagrams/sequencediagram-uploadEpisodeActions.puml b/10-entwurfsheft/assets/diagrams/sequencediagram-uploadEpisodeActions.puml
new file mode 100644
index 0000000..d3dac57
--- /dev/null
+++ b/10-entwurfsheft/assets/diagrams/sequencediagram-uploadEpisodeActions.puml
@@ -0,0 +1,38 @@
+@startuml
+
+' title =**Upload Episode Actions**
+
+participant EpisodeActionController << (C, #ADD1B2) @Controller >>
+-> EpisodeActionController: ""POST /api/2/episodes/{username}.json"" \n//@RequestBody EpisodeActionPostRequest episodeActionPostRequest// \n\n-> addEpisodeActions(""username"", //episodeActionPostRequest//)
+activate EpisodeActionController
+participant EpisodeActionService << (C, #ADD1B2) @Service >>
+EpisodeActionController -> EpisodeActionService: addEpisodeActions(""username"", \nepisodeActionPosts = //episodeActionPostRequest//.getEpisodeActionPosts())
+activate EpisodeActionService
+participant EpisodeActionDataAccessService << (C, #ADD1B2) @Repository >>
+EpisodeActionService -> EpisodeActionDataAccessService: addEpisodeActions(""username"", episodeActionPosts)
+database Database
+activate EpisodeActionDataAccessService
+loop for each EpisodeActionPost in episodeActionPosts -> episodeAction = episodeActionPost.getEpisodeAction()
+opt episodeAction.getAction().equals(Action.PLAY)
+EpisodeActionDataAccessService -> Database: set episodeID field of episodeAction for this ""username"" via podcastURL and episodeURL
+activate Database
+Database --> EpisodeActionDataAccessService
+EpisodeActionDataAccessService -> Database: get last EpisodeAction with this episodeID if present
+Database --> EpisodeActionDataAccessService: Optional<EpisodeAction> lastEpisodeAction
+opt lastEpisodeAction.isPresent()
+EpisodeActionDataAccessService -> Database: replace lastEpisodeAction with episodeAction
+else else
+EpisodeActionDataAccessService -> Database: add episodeAction to DB as new entry
+end
+Database --> EpisodeActionDataAccessService
+deactivate Database
+end
+end
+EpisodeActionDataAccessService --> EpisodeActionService: long latestTimestamp
+deactivate EpisodeActionDataAccessService
+EpisodeActionService --> EpisodeActionController: LocalDateTime timestamp = LocalDateTime.ofEpochSecond(latestTimestamp, 0, ZoneOffset.UTC)
+deactivate EpisodeActionService
+<-- EpisodeActionController: ResponseEntity<EpisodeActionPostResponse> \n(with empty list for updateURLs) \n\n-> ""HTTP status code"" \n-> ""JSON""
+deactivate EpisodeActionController
+
+@enduml \ No newline at end of file
diff --git a/10-entwurfsheft/assets/diagrams/sequencediagram-uploadSubscriptions.puml b/10-entwurfsheft/assets/diagrams/sequencediagram-uploadSubscriptions.puml
new file mode 100644
index 0000000..1edc8cf
--- /dev/null
+++ b/10-entwurfsheft/assets/diagrams/sequencediagram-uploadSubscriptions.puml
@@ -0,0 +1,32 @@
+@startuml
+
+' title =**Upload Subscriptions**
+
+participant SubscriptionController << (C, #ADD1B2) @Controller >>
+-> SubscriptionController: ""PUT /subscriptions/{username}/{deviceid}.json"" \n//@RequestBody List<String> subscriptions// \n\n-> uploadSubscriptions(""username"", ""deviceid"", //subscriptions//)
+activate SubscriptionController
+participant SubscriptionService << (C, #ADD1B2) @Service >>
+SubscriptionController -> SubscriptionService: uploadSubscriptions(""username"", //subscriptions//)
+activate SubscriptionService
+participant SubscriptionDataAccessService << (C, #ADD1B2) @Repository >>
+SubscriptionService -> SubscriptionDataAccessService: uploadSubscriptions(""username"", //subscriptions//)
+activate SubscriptionDataAccessService
+database Database
+SubscriptionDataAccessService -> Database: delete all subsciptions of ""username""
+activate Database
+Database --> SubscriptionDataAccessService
+SubscriptionDataAccessService -> SubscriptionDataAccessService: addSubscriptions(""username"", //subscriptions//)
+activate SubscriptionDataAccessService
+SubscriptionDataAccessService -> Database: upload all subscriptions (//subscriptions//) for ""username""
+Database --> SubscriptionDataAccessService
+deactivate Database
+SubscriptionDataAccessService --> SubscriptionDataAccessService: int indicating status
+deactivate SubscriptionDataAccessService
+SubscriptionDataAccessService --> SubscriptionService: int indicating status
+deactivate SubscriptionDataAccessService
+SubscriptionService --> SubscriptionController: int indicating status
+deactivate SubscriptionService
+<-- SubscriptionController: ResponseEntity<String> with empty String for success \n\n-> ""HTTP status code"" \n-> ""JSON""
+deactivate SubscriptionController
+
+@enduml \ No newline at end of file
diff --git a/10-entwurfsheft/assets/episode.png b/10-entwurfsheft/assets/episode.png
new file mode 100644
index 0000000..c0db4a2
--- /dev/null
+++ b/10-entwurfsheft/assets/episode.png
Binary files differ
diff --git a/10-entwurfsheft/assets/help.png b/10-entwurfsheft/assets/help.png
new file mode 100644
index 0000000..39a1b84
--- /dev/null
+++ b/10-entwurfsheft/assets/help.png
Binary files differ
diff --git a/10-entwurfsheft/assets/lastupdate.png b/10-entwurfsheft/assets/lastupdate.png
new file mode 100644
index 0000000..e9b7f5c
--- /dev/null
+++ b/10-entwurfsheft/assets/lastupdate.png
Binary files differ
diff --git a/10-entwurfsheft/assets/logo.pdf b/10-entwurfsheft/assets/logo.pdf
new file mode 100644
index 0000000..91fd334
--- /dev/null
+++ b/10-entwurfsheft/assets/logo.pdf
Binary files differ
diff --git a/10-entwurfsheft/assets/logo.svg b/10-entwurfsheft/assets/logo.svg
new file mode 100644
index 0000000..1609066
--- /dev/null
+++ b/10-entwurfsheft/assets/logo.svg
@@ -0,0 +1,211 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ version="1.2"
+ width="87.589989mm"
+ height="52.16547mm"
+ viewBox="0 0 8758.9989 5216.547"
+ preserveAspectRatio="xMidYMid"
+ fill-rule="evenodd"
+ stroke-width="28.222"
+ stroke-linejoin="round"
+ xml:space="preserve"
+ id="svg206"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg">
+ <defs
+ class="ClipPathGroup"
+ id="defs8" />
+ <defs
+ id="defs51"><font
+ id="EmbeddedFont_1"
+ horiz-adv-x="2048"
+ horiz-origin-x="0"
+ horiz-origin-y="0"
+ vert-origin-x="512"
+ vert-origin-y="768"
+ vert-adv-y="1024">
+ <font-face
+ font-family="Noto Sans Display Light embedded"
+ units-per-em="2048"
+ font-weight="normal"
+ font-style="normal"
+ ascent="2170"
+ descent="609"
+ id="font-face10" />
+ <missing-glyph
+ horiz-adv-x="2048"
+ d="M 0,0 L 2047,0 2047,2047 0,2047 0,0 Z"
+ id="missing-glyph12" />
+ <glyph
+ unicode="y"
+ horiz-adv-x="927"
+ d="M 2,1089 L 127,1089 367,413 C 388,352 407,298 422,250 437,203 449,161 457,124 L 463,124 C 471,156 483,196 498,246 513,296 530,350 551,409 L 786,1089 913,1089 453,-193 C 418,-290 377,-364 328,-416 279,-468 213,-494 131,-494 107,-494 84,-493 63,-490 43,-487 25,-482 8,-476 L 8,-377 C 23,-383 40,-387 57,-391 75,-394 95,-396 117,-396 170,-396 214,-378 249,-342 284,-307 314,-252 340,-179 L 403,4 2,1089 Z"
+ id="glyph14" />
+ <glyph
+ unicode="t"
+ horiz-adv-x="610"
+ d="M 465,80 C 494,80 521,82 547,87 573,91 595,97 614,105 L 614,11 C 594,3 569,-5 541,-11 512,-17 481,-20 449,-20 363,-20 296,5 249,56 202,106 178,189 178,304 L 178,996 27,996 27,1061 178,1100 219,1350 295,1350 295,1090 608,1090 608,996 295,996 295,310 C 295,157 352,80 465,80 Z"
+ id="glyph16" />
+ <glyph
+ unicode="s"
+ horiz-adv-x="742"
+ d="M 817,289 C 817,191 782,115 713,61 643,7 545,-20 418,-20 347,-20 284,-14 228,-1 173,12 126,29 88,50 L 88,162 C 134,138 186,118 244,102 301,86 360,78 420,78 520,78 592,96 636,133 680,169 702,218 702,281 702,341 679,387 632,419 585,451 515,484 422,519 359,542 303,565 255,589 207,613 169,643 142,680 116,717 102,768 102,832 102,919 136,987 204,1037 271,1086 361,1110 473,1110 535,1110 592,1104 646,1092 700,1080 750,1063 795,1043 L 754,946 C 713,964 667,980 617,993 568,1006 518,1012 469,1012 388,1012 326,997 283,967 239,937 217,893 217,836 217,792 228,758 249,733 270,707 301,686 342,668 383,650 433,630 492,609 553,585 608,562 657,537 707,512 745,481 774,443 803,405 817,353 817,289 Z"
+ id="glyph18" />
+ <glyph
+ unicode="r"
+ horiz-adv-x="583"
+ d="M 596,1108 C 646,1108 692,1102 733,1091 L 717,983 C 674,995 632,1001 590,1001 497,1001 423,964 368,890 312,817 285,719 285,598 L 285,-1 168,-1 168,1089 266,1089 279,886 285,886 C 311,948 350,1000 402,1043 455,1086 520,1108 596,1108 Z"
+ id="glyph20" />
+ <glyph
+ unicode="o"
+ horiz-adv-x="927"
+ d="M 1030,547 C 1030,433 1012,333 976,248 940,164 887,98 818,51 749,4 665,-20 565,-20 471,-20 390,3 322,50 253,96 201,162 164,247 127,333 109,433 109,547 109,723 150,861 232,961 315,1061 429,1110 575,1110 672,1110 755,1087 822,1040 890,993 941,927 977,842 1012,757 1030,659 1030,547 Z M 229,547 C 229,407 257,294 312,208 368,123 453,80 567,80 685,80 771,123 826,209 882,295 909,408 909,547 909,637 898,717 875,787 851,856 815,911 766,951 717,990 653,1010 573,1010 459,1010 373,969 315,887 258,805 229,692 229,547 Z"
+ id="glyph22" />
+ <glyph
+ unicode="n"
+ horiz-adv-x="847"
+ d="M 633,1110 C 749,1110 838,1078 900,1014 962,950 993,850 993,713 L 993,1 877,1 877,705 C 877,809 854,885 810,935 766,985 701,1010 616,1010 395,1010 285,871 285,594 L 285,1 168,1 168,1090 262,1090 279,901 287,901 C 314,962 357,1011 416,1051 474,1091 547,1110 633,1110 Z"
+ id="glyph24" />
+ <glyph
+ unicode="m"
+ horiz-adv-x="1430"
+ d="M 1245,1110 C 1348,1110 1427,1080 1485,1018 1542,957 1571,860 1571,727 L 1571,1 1454,1 1454,723 C 1454,820 1434,892 1393,939 1352,986 1296,1010 1227,1010 1130,1010 1056,980 1005,919 953,858 928,764 928,637 L 928,1 811,1 811,723 C 811,820 791,892 750,939 709,986 653,1010 584,1010 487,1010 413,978 361,914 310,850 285,751 285,619 L 285,1 168,1 168,1090 262,1090 279,918 287,918 C 313,971 352,1016 403,1054 455,1092 521,1110 600,1110 675,1110 739,1093 791,1059 842,1025 879,975 899,908 L 907,908 C 936,972 980,1022 1038,1057 1097,1093 1166,1110 1245,1110 Z"
+ id="glyph26" />
+ <glyph
+ unicode="i"
+ horiz-adv-x="187"
+ d="M 227,1493 C 279,1493 305,1464 305,1405 305,1345 279,1315 227,1315 175,1315 150,1345 150,1405 150,1464 175,1493 227,1493 Z M 285,1090 L 285,0 168,0 168,1090 285,1090 Z"
+ id="glyph28" />
+ <glyph
+ unicode="h"
+ horiz-adv-x="847"
+ d="M 285,1059 C 285,1031 284,1003 283,977 281,951 279,926 276,901 L 285,901 C 312,962 355,1011 413,1051 471,1091 543,1110 629,1110 746,1110 836,1078 899,1014 962,950 993,850 993,713 L 993,1 877,1 877,705 C 877,809 854,885 810,935 766,985 701,1010 616,1010 395,1010 285,871 285,594 L 285,1 168,1 168,1557 285,1557 285,1059 Z"
+ id="glyph30" />
+ <glyph
+ unicode="f"
+ horiz-adv-x="689"
+ d="M 575,995 L 332,995 332,-1 213,-1 213,995 27,995 27,1058 213,1093 213,1202 C 213,1445 316,1566 522,1566 559,1566 593,1563 623,1557 653,1551 680,1544 705,1536 L 678,1439 C 655,1448 630,1454 603,1460 577,1465 550,1468 524,1468 456,1468 407,1447 377,1405 347,1362 332,1295 332,1202 L 332,1089 575,1089 575,995 Z"
+ id="glyph32" />
+ <glyph
+ unicode="e"
+ horiz-adv-x="874"
+ d="M 559,1110 C 646,1110 720,1089 779,1046 839,1003 883,944 913,869 943,794 958,708 958,611 L 958,531 229,531 C 231,386 262,275 325,198 387,121 476,82 592,82 656,82 712,88 759,100 806,111 858,130 915,156 L 915,50 C 865,25 814,7 764,-4 713,-15 655,-20 588,-20 434,-20 315,30 232,129 150,229 109,365 109,537 109,648 126,746 162,832 197,918 249,986 315,1036 382,1085 464,1110 559,1110 Z M 559,1012 C 465,1012 389,979 333,912 276,845 243,750 233,627 L 838,627 C 838,742 815,835 769,906 723,977 653,1012 559,1012 Z"
+ id="glyph34" />
+ <glyph
+ unicode="d"
+ horiz-adv-x="900"
+ d="M 535,-20 C 398,-20 293,27 219,120 145,214 109,352 109,535 109,722 147,865 224,963 301,1061 408,1110 545,1110 629,1110 698,1090 752,1050 805,1010 845,961 872,904 L 881,904 C 879,935 878,970 876,1009 873,1048 872,1084 872,1117 L 872,1557 989,1557 989,0 895,0 879,191 872,191 C 845,132 805,82 751,41 697,0 625,-20 535,-20 Z M 553,80 C 669,80 752,119 801,195 850,271 875,382 875,527 L 875,545 C 875,695 850,810 801,890 752,970 671,1010 559,1010 451,1010 369,969 313,886 257,804 229,686 229,533 229,385 256,273 309,196 363,119 444,80 553,80 Z"
+ id="glyph36" />
+ <glyph
+ unicode="c"
+ horiz-adv-x="768"
+ d="M 580,-20 C 429,-20 313,29 231,127 150,226 109,363 109,539 109,662 129,766 170,850 211,935 269,1000 343,1044 417,1088 504,1110 602,1110 651,1110 698,1106 742,1096 787,1087 825,1074 858,1057 L 825,957 C 791,972 754,984 714,993 673,1002 636,1006 600,1006 481,1006 390,964 326,881 261,798 229,685 229,541 229,405 258,294 314,210 371,126 459,84 580,84 630,84 678,90 723,101 768,112 809,125 846,142 L 846,37 C 812,20 773,6 729,-5 685,-15 636,-20 580,-20 Z"
+ id="glyph38" />
+ <glyph
+ unicode="a"
+ horiz-adv-x="822"
+ d="M 535,1108 C 651,1108 737,1078 795,1018 852,958 881,863 881,734 L 881,0 793,0 772,185 766,185 C 729,123 684,74 631,36 578,-1 503,-20 408,-20 311,-20 233,6 176,59 119,111 90,187 90,285 90,394 132,477 215,533 298,589 420,621 580,629 L 764,639 764,715 C 764,822 744,897 705,942 665,987 606,1010 528,1010 477,1010 426,1002 378,987 329,972 281,953 231,928 L 195,1022 C 242,1047 295,1067 352,1084 410,1100 470,1108 535,1108 Z M 594,543 C 466,536 370,512 307,470 244,429 213,367 213,285 213,217 232,165 271,131 310,96 363,78 430,78 535,78 617,111 676,176 735,240 764,330 764,445 L 764,551 594,543 Z"
+ id="glyph40" />
+ <glyph
+ unicode="S"
+ horiz-adv-x="875"
+ d="M 956,381 C 956,294 936,220 894,160 852,100 796,55 724,25 652,-5 571,-20 479,-20 396,-20 324,-14 262,-2 201,11 147,26 102,46 L 102,162 C 152,142 209,124 273,109 338,94 409,87 485,87 589,87 673,110 738,158 803,206 836,278 836,373 836,431 823,478 798,515 772,553 734,586 682,614 630,642 565,670 485,699 410,726 345,757 291,791 236,825 194,868 164,919 134,970 119,1035 119,1112 119,1192 138,1259 176,1314 214,1369 267,1411 333,1440 399,1469 474,1483 559,1483 626,1483 689,1476 750,1463 810,1449 868,1430 924,1405 L 883,1303 C 772,1352 663,1377 555,1377 462,1377 386,1354 328,1310 269,1266 240,1200 240,1114 240,1052 252,1001 278,964 303,926 340,895 389,869 438,843 498,817 567,791 648,762 717,731 775,698 833,664 878,623 909,573 941,523 956,459 956,381 Z"
+ id="glyph42" />
+ <glyph
+ unicode="P"
+ horiz-adv-x="848"
+ d="M 539,1462 C 869,1462 1034,1325 1034,1049 1034,908 992,798 907,718 823,638 690,598 510,598 L 311,598 311,0 193,0 193,1462 539,1462 Z M 528,1358 L 311,1358 311,702 498,702 C 629,702 730,727 803,776 875,825 911,914 911,1043 911,1152 880,1232 818,1282 756,1333 659,1358 528,1358 Z"
+ id="glyph44" />
+ <glyph
+ unicode="E"
+ horiz-adv-x="769"
+ d="M 950,0 L 193,0 193,1462 950,1462 950,1356 311,1356 311,821 913,821 913,715 311,715 311,107 950,107 950,0 Z"
+ id="glyph46" />
+ <glyph
+ unicode=" "
+ horiz-adv-x="503"
+ id="glyph48" />
+ </font></defs>
+ <defs
+ class="TextShapeIndex"
+ id="defs55" />
+ <defs
+ class="EmbeddedBulletChars"
+ id="defs87" />
+
+ <g
+ id="id10"
+ clip-path="none"
+ transform="translate(-700.00001,-2550)">
+
+ <text
+ class="SVGTextShape"
+ id="text151"
+ x="217.60002"
+ y="-56.506969"
+ style="letter-spacing:4.7625px;word-spacing:104.775px"><tspan
+ class="TextParagraph"
+ font-family="'Noto Sans Display Light', sans-serif"
+ font-size="494px"
+ font-weight="400"
+ id="tspan149"><tspan
+ class="TextPosition"
+ x="650.59998"
+ y="7647.4932"
+ id="tspan147"><tspan
+ fill="#808080"
+ stroke="none"
+ style="white-space:pre"
+ id="tspan145"
+ dx="2.1199999">Podcast Synchronisation made Efficient</tspan></tspan></tspan></text>
+ </g><g
+ id="g1277"
+ transform="translate(-700.00001,-2550)"><path
+ id="path131-3"
+ d="m 6694.0006,4763 c -559.5515,4.407 -980.3924,428.0893 -986.038,985.9863 18.2894,552.8957 454.3127,974.1166 989.0352,986.0379 v -235.0244 c -406.8751,-27.3888 -715.1078,-362.1649 -719.0259,-748.0163 12.7874,-421.0793 236.9242,-746.3999 750.0318,-749.98 895.0688,1.4728 1915.5158,0 2730.9957,0 V 4763 Z"
+ style="fill:#0084d1;fill-opacity:1"
+ clip-path="none" /><path
+ id="path131"
+ d="m 6685.0183,2562.996 c -559.5515,4.407 -980.3924,428.0893 -986.038,985.9863 18.2894,552.8957 454.3127,974.1167 989.0352,986.038 v -235.0244 c -406.8751,-27.3888 -715.1078,-362.165 -719.0259,-748.0164 12.7874,-421.0792 236.9242,-746.3998 750.0318,-749.98 895.0688,1.4728 1915.5158,0 2730.996,0 V 2562.996 Z"
+ style="fill:#0084d1;fill-opacity:1"
+ clip-path="none" /></g><g
+ id="g1263"
+ transform="translate(-700.00001,-2550)"><path
+ fill="none"
+ stroke="#069a2e"
+ stroke-width="265"
+ stroke-linejoin="round"
+ d="m 2793,5962 c 1283,0 429,-2762 1712,-2762"
+ id="path124" /><path
+ id="path110-6"
+ d="M 3198.0212,6550 V 6300.0411 H 2448.0411 V 6050.0305 5550.0094 H 2198.0305 V 6300.0411 6550 H 2448.0411 2698 Z"
+ style="fill:#069a2e;fill-opacity:1" /><path
+ id="path110"
+ d="m 4111.997,2550.0252 v 249.9589 h 749.9801 v 250.0106 500.0211 h 250.0106 v -750.0317 -249.9589 h -250.0106 -249.9589 z"
+ style="fill:#069a2e;fill-opacity:1" /></g>
+ <g
+ id="g1249"
+ transform="translate(-700.00001,-2550)"><path
+ fill="#ff8000"
+ stroke="none"
+ d="M 2215,4164 C 2412.6918,3832.6035 2379.3124,3383.7591 2135.4189,3084.8193 1956.8564,2857.4026 1671.3097,2718.8851 1382,2721 c 0,-52.6667 0,-105.3333 0,-158 -60.1303,-1.0792 190.6585,-1.2724 121.9814,2.7933 434.6311,30.3756 832.6257,336.7309 974.9655,748.2365 148.7336,402.6249 41.0263,883.7477 -266.0719,1183.8452 C 1996.6852,4716.1853 1689.0048,4838.6187 1382,4830 c 0,-61.6667 0,-123.3333 0,-185 338.199,2.9253 666.226,-186.816 833,-481 z"
+ id="path193" /><path
+ fill="#ff8000"
+ stroke="none"
+ d="m 1936,3979 c 175.8129,-283.3241 59.7943,-700.6319 -239.8255,-849.407 -94.2713,-50.9942 -201.887,-77.9344 -309.1745,-74.593 0,-57 0,-114 0,-171 396.3865,-24.0968 777.5367,297.6517 818.5878,693.1841 44.0348,337.5467 -149.4277,694.9971 -466.4953,826.9493 -110.1027,49.0687 -231.5272,73.543 -352.0925,67.8666 0,-61.6667 0,-123.3333 0,-185 220.6353,7.5804 440.8554,-115.3286 549,-308 z"
+ id="path186" /><path
+ fill="#ff8000"
+ stroke="none"
+ d="m 1659,3822 c 86.3933,-138.0398 18.2474,-344.669 -134.6962,-402.3205 C 1483.44,3402.2177 1438.3524,3394.2432 1394,3398 c 0,-56.6667 0,-113.3333 0,-170 223.1964,-19.6143 444.7886,153.3254 478.4886,375.1817 32.646,181.6951 -54.6854,381.4331 -217.3127,472.2205 -78.2316,46.131 -170.3991,69.3119 -261.1759,62.5978 0,-58.3333 0,-116.6667 0,-175 105.6736,9.5509 212.8962,-49.2218 265,-141 z"
+ id="path179" /><rect
+ class="BoundingBox"
+ stroke="none"
+ fill="none"
+ x="700"
+ y="2550"
+ width="501"
+ height="4001"
+ id="rect136"
+ style="fill:#ff8000;fill-opacity:1" /></g>
+
+</svg>
diff --git a/10-entwurfsheft/assets/navbar.png b/10-entwurfsheft/assets/navbar.png
new file mode 100644
index 0000000..dd9f8e8
--- /dev/null
+++ b/10-entwurfsheft/assets/navbar.png
Binary files differ
diff --git a/10-entwurfsheft/assets/password-margin.png b/10-entwurfsheft/assets/password-margin.png
new file mode 100644
index 0000000..d9d4fa3
--- /dev/null
+++ b/10-entwurfsheft/assets/password-margin.png
Binary files differ
diff --git a/10-entwurfsheft/assets/password.png b/10-entwurfsheft/assets/password.png
new file mode 100644
index 0000000..68248a0
--- /dev/null
+++ b/10-entwurfsheft/assets/password.png
Binary files differ
diff --git a/10-entwurfsheft/assets/subscription.png b/10-entwurfsheft/assets/subscription.png
new file mode 100644
index 0000000..58a84f9
--- /dev/null
+++ b/10-entwurfsheft/assets/subscription.png
Binary files differ
diff --git a/10-entwurfsheft/entwurfsheft.tex b/10-entwurfsheft/entwurfsheft.tex
new file mode 100644
index 0000000..9f93eda
--- /dev/null
+++ b/10-entwurfsheft/entwurfsheft.tex
@@ -0,0 +1,90 @@
+% \documentclass[a4paper, UTF8, 12pt]{article}
+% \documentclass[a4paper, UTF8, 12pt]{scrbook}
+\documentclass[parskip=half, a4paper, 12pt]{scrartcl}
+
+\usepackage[german]{babel}
+\usepackage[dvipsnames]{xcolor}
+% \usepackage{tikz}
+% \usetikzlibrary{positioning}
+% \usetikzlibrary{calc}
+% \usetikzlibrary{arrows}
+% \usetikzlibrary{intersections}
+% \usepackage{tikz-uml}
+% \usepackage{pgf-umlsd}
+% \usepgflibrary{arrows} % for pgf-umlsd
+% \tikzumlset{fill usecase=white}
+\usepackage[margin=2.5cm]{geometry}
+\usepackage{csquotes}
+\usepackage[T1]{fontenc}
+\usepackage{amsmath}
+\usepackage{pdflscape}
+\usepackage{graphicx}
+\usepackage{caption}
+\usepackage{subcaption}
+\usepackage{float}
+\usepackage{enumitem}
+% \usepackage{textpos}
+\usepackage{hyperref}
+\usepackage{fancyhdr}
+% \usepackage{multicol}
+\usepackage{rest-api}
+\usepackage{wrapfig}
+\usepackage{textcomp}
+\usepackage{ulem}
+
+
+\hypersetup{
+% ‘texdoc hyperref‘ for options
+ pdftitle={
+ PSE\textsuperscript{2}
+ - Podcast Synchronisation made Efficient Pflichtenheft
+ },
+ bookmarks=true,
+}
+\usepackage{csquotes}
+\usepackage[toc]{glossaries}
+\usepackage{lastpage}
+
+\include{sections/glossar}
+
+\title{Pflichtenheft}
+\author{KIT Students et al}
+\date{2.12.2022}
+
+\pagestyle{fancy}
+\setkomafont{pageheadfoot}{\footnotesize\scshape}
+\fancyhead{} % clear all header fields
+% \fancyhead[L]{Pflichtenheft}
+\fancyhead[L]{PSE\textsuperscript{2} - Podcast Synchronisation made Efficient}
+% \fancyhead[R]{2.12.2022}
+\fancyfoot{} % clear all footer fields
+\fancyfoot[R]{\thepage{} / \pageref{LastPage}}
+\fancyfoot[L]{Praxis der Softwareentwicklung}
+\fancyfoot[C]{}
+
+\begin{document}
+
+\include{titlepage}
+\setcounter{page}{1}
+
+\tableofcontents
+
+\include{sections/einleitung}
+\newpage
+
+\input{sections/aufbau}
+
+\include{sections/structure}
+
+\include{sections/backend}
+
+\include{sections/frontend}
+
+\include{sections/apidoc}
+
+\include{sections/changes}
+
+\printglossaries
+% \glsaddall
+
+\end{document}
diff --git a/10-entwurfsheft/pgf-umlsd.sty b/10-entwurfsheft/pgf-umlsd.sty
new file mode 100644
index 0000000..99847db
--- /dev/null
+++ b/10-entwurfsheft/pgf-umlsd.sty
@@ -0,0 +1,329 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Start of pgf-umlsd.sty
+%
+% Some macros for UML Sequence Diagrams.
+% Home page of project: http://pgf-umlsd.googlecode.com/
+% Author: Xu Yuan <xuyuan.cn@gmail.com>, Southeast University, China
+% Contributor: Nobel Huang <nobel1984@gmail.com>, Southeast University, China
+%
+% History:
+% v0.7 2012/03/05
+% - unify interface of call and callself
+% - non-instantaneous message
+% - bugfix: conflits with tikz library backgrounds
+% v0.6 2011/07/27
+% - Fix Issue 6 reported by frankmorgner@gmail.com
+% - diagram without a thread
+% - allows empty diagram
+% - New manual
+% v0.5 2009/09/30 Fix Issue 2 reported by vlado.handziski
+% - Nested callself is supported
+% - Rename sdloop and sdframe to sdblock
+% v0.4 2008/12/08 Fix Issue 1 reported by MathStuf:
+% Nested sdloop environment hides outer loop
+% v0.3 2008/11/10 in Berlin, fix for the PGF cvs version:
+% - the list items in \foreach are not evaluated by default now,
+% the `evaluate' opinion should be used
+% v0.2 2008/03/20 create project at http://pgf-umlsd.googlecode.com/
+% - use `shadows' library
+% Thanks for Dr. Ludger Humbert's <humbert@uni-wuppertal.de> feedback!
+% - reduce the parameter numbers, the user can write the content
+% of instance (such as no colon)
+% - the user can redefine the `inststyle'
+% - new option: switch underlining of the instance text
+% - new option: switch rounded corners
+% v0.1 2008/01/25 first release at http://www.fauskes.net/pgftikzexamples/
+%
+
+\NeedsTeXFormat{LaTeX2e}[1999/12/01]
+\ProvidesPackage{pgf-umlsd}[2011/07/27 v0.6 Some LaTeX macros for UML
+Sequence Diagrams.]
+
+\RequirePackage{tikz}
+\usetikzlibrary{arrows,shadows}
+
+\RequirePackage{ifthen}
+
+% Options
+% ? the instance name under line ?
+\newif\ifpgfumlsdunderline\pgfumlsdunderlinetrue
+\DeclareOption{underline}{\pgfumlsdunderlinetrue}
+\DeclareOption{underline=true}{\pgfumlsdunderlinetrue}
+\DeclareOption{underline=false}{\pgfumlsdunderlinefalse}
+% ? the instance box with rounded corners ?
+\newif\ifpgfumlsdroundedcorners\pgfumlsdroundedcornersfalse
+\DeclareOption{roundedcorners}{\pgfumlsdroundedcornerstrue}
+\DeclareOption{roundedcorners=true}{\pgfumlsdroundedcornerstrue}
+\DeclareOption{roundedcorners=false}{\pgfumlsdroundedcornersfalse}
+\ProcessOptions
+
+% new counters
+\newcounter{preinst}
+\newcounter{instnum}
+\newcounter{threadnum}
+\newcounter{seqlevel} % level
+\newcounter{callevel}
+\newcounter{callselflevel}
+\newcounter{blocklevel}
+
+% new an instance
+% Example:
+% \newinst[edge distance]{var}{name:class}
+\newcommand{\newinst}[3][0.2]{
+ \stepcounter{instnum}
+ \path (inst\thepreinst.east)+(#1,0) node[inststyle] (inst\theinstnum)
+ {\ifpgfumlsdunderline
+ \underline{#3}
+ \else
+ #3
+ \fi};
+ \path (inst\theinstnum)+(0,-0.5*\unitfactor) node (#2) {};
+ \tikzstyle{instcolor#2}=[]
+ \stepcounter{preinst}
+}
+
+% new an instance thread
+% Example:
+% \newinst[color]{var}{name}{class}
+\newcommand{\newthread}[3][gray!30]{
+ \newinst{#2}{#3}
+ \stepcounter{threadnum}
+ \node[below of=inst\theinstnum,node distance=0.8cm] (thread\thethreadnum) {};
+ \tikzstyle{threadcolor\thethreadnum}=[fill=#1]
+ \tikzstyle{instcolor#2}=[fill=#1]
+}
+
+% draw running (thick) line, should not call directly
+\newcommand*{\drawthread}[2]{
+ \begin{pgfonlayer}{umlsd@threadlayer}
+ \draw[threadstyle] (#1.west) -- (#1.east) -- (#2.east) -- (#2.west) -- cycle;
+ \end{pgfonlayer}
+}
+
+% a function call
+% Example:
+% \begin{call}[height]{caller}{function}{callee}{return}
+% \end{call}
+\newenvironment{call}[5][1]{
+\ifthenelse{\equal{#2}{#4}}
+{
+ \begin{callself}[#1]{#2}{#3}{#5}
+}
+{
+ \begin{callanother}[#1]{#2}{#3}{#4}{#5}
+}
+}
+{
+\ifthenelse{\equal{\f\thecallevel}{\t\thecallevel}}
+{
+ \end{callself}
+}
+{
+ \end{callanother}
+}
+}
+
+% function call to another instance
+% interal use only
+\newenvironment*{callanother}[5][1]{
+ \stepcounter{seqlevel}
+ \stepcounter{callevel} % push
+ \path
+ (#2)+(0,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (cf\thecallevel) {}
+ (#4.\threadbias)+(0,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (ct\thecallevel) {};
+
+ \draw[->,>=triangle 60] ({cf\thecallevel}) -- (ct\thecallevel)
+ node[midway, above] {#3};
+ \def\l\thecallevel{#1}
+ \def\f\thecallevel{#2}
+ \def\t\thecallevel{#4}
+ \def\returnvalue{#5}
+ \tikzstyle{threadstyle}+=[instcolor#2]
+}
+{
+ \addtocounter{seqlevel}{\l\thecallevel}
+ \path
+ (\f\thecallevel)+(0,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (rf\thecallevel) {}
+ (\t\thecallevel.\threadbias)+(0,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (rt\thecallevel) {};
+ \draw[dashed,->,>=angle 60] ({rt\thecallevel}) -- (rf\thecallevel)
+ node[midway, above]{\returnvalue};
+ \drawthread{ct\thecallevel}{rt\thecallevel}
+ \addtocounter{callevel}{-1} % pop
+}
+
+% a function do not need call others
+% interal use only
+% Example:
+% \begin{callself}[height]{caller}{function}{return}
+% \end{callself}
+\newenvironment*{callself}[4][1]{
+ \stepcounter{seqlevel}
+ \stepcounter{callevel} % push
+ \stepcounter{callselflevel}
+
+ \path
+ (#2)+(\thecallselflevel*0.1-0.1,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (sc\thecallevel) {}
+ ({sc\thecallevel}.east)+(0,-0.33*\unitfactor) node (scb\thecallevel) {};
+
+ \draw[->,>=triangle 60] ({sc\thecallevel}.east) -- ++(0.8,0)
+ node[near start, above right] {#3} -- ++(0,-0.33*\unitfactor)
+ -- (scb\thecallevel);
+ \def\l\thecallevel{#1}
+ \def\f\thecallevel{#2}
+ \def\t\thecallevel{#2}
+ \def\returnvalue{#4}
+ \tikzstyle{threadstyle}+=[instcolor#2]
+}{
+ \addtocounter{seqlevel}{\l\thecallevel}
+ \path (\f\thecallevel)+(\thecallselflevel*0.1-0.1,-\theseqlevel*\unitfactor-0.33*\unitfactor) node
+ (sct\thecallevel) {};
+
+ \draw[dashed,->,>=angle 60] ({sct\thecallevel}.east) node
+ (sce\thecallevel) {} -- ++(0.8,0) -- node[midway, right]{\returnvalue} ++(0,-0.33*\unitfactor) -- ++(-0.8,0);
+ \drawthread{scb\thecallevel}{sce\thecallevel}
+ \addtocounter{callevel}{-1} % pop
+ \addtocounter{callselflevel}{-1}
+}
+
+% message between threads
+% Example:
+% \mess[delay]{sender}{message content}{receiver}
+\newcommand{\mess}[4][0]{
+ \stepcounter{seqlevel}
+ \path
+ (#2)+(0,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (mess from) {};
+ \addtocounter{seqlevel}{#1}
+ \path
+ (#4)+(0,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (mess to) {};
+ \draw[->,>=angle 60] (mess from) -- (mess to) node[midway, above]
+ {#3};
+
+ \node (#3 from) at (mess from) {};
+ \node (#3 to) at (mess to) {};
+}
+
+\newenvironment{messcall}[4][1]{
+ \stepcounter{seqlevel}
+ \stepcounter{callevel} % push
+ \path
+ (#2)+(0,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (cf\thecallevel) {}
+ (#4.\threadbias)+(0,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (ct\thecallevel) {};
+
+ \draw[->,>=angle 60] ({cf\thecallevel}) -- (ct\thecallevel)
+ node[midway, above] {#3};
+ \def\l\thecallevel{#1}
+ \def\f\thecallevel{#2}
+ \def\t\thecallevel{#4}
+ \tikzstyle{threadstyle}+=[instcolor#2]
+}
+{
+ \addtocounter{seqlevel}{\l\thecallevel}
+ \path
+ (\f\thecallevel)+(0,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (rf\thecallevel) {}
+ (\t\thecallevel.\threadbias)+(0,-\theseqlevel*\unitfactor-0.3*\unitfactor) node (rt\thecallevel) {};
+ \drawthread{ct\thecallevel}{rt\thecallevel}
+ \addtocounter{callevel}{-1} % pop
+}
+
+% In the situation of multi-threads, some objects are called at the
+% same time. Currently, we have to adjust the bias of thread line
+% manually. Possible parameters are: center, west, east
+\newcommand{\setthreadbias}[1]{\global\def\threadbias{#1}}
+
+% This function makes the call earlier.
+\newcommand{\prelevel}{\addtocounter{seqlevel}{-1}}
+
+% This function makes the call later.
+\newcommand{\postlevel}{\addtocounter{seqlevel}{+1}}
+
+% a block box with caption
+% \begin{sdblock}[caption background color]{caption}{comments}
+% \end{sdblock}
+\newenvironment{sdblock}[3][white]{
+ \stepcounter{seqlevel}
+ \stepcounter{blocklevel} % push
+ \coordinate (blockbeg\theblocklevel) at (0,-\theseqlevel*\unitfactor-\unitfactor);
+ \stepcounter{seqlevel}
+ \def\blockcolor\theblocklevel{#1}
+ \def\blockname\theblocklevel{#2}
+ \def\blockcomm\theblocklevel{#3}
+ \begin{pgfinterruptboundingbox}
+}{
+ \coordinate (blockend) at (0,-\theseqlevel*\unitfactor-2*\unitfactor);
+ \path (current bounding box.east)+(0.2,0) node (boxeast) {}
+ (current bounding box.west |- {blockbeg\theblocklevel}) + (-0.2,0)
+ node (nw) {};
+ \path (boxeast |- blockend) node (se) {};
+
+ % % title
+ \node[blockstyle] (blocktitle) at (nw) {\blockname\theblocklevel};
+ \path (blocktitle.south east) + (0,0.2) node (set) {}
+ (blocktitle.south east) + (-0.2,0) node (seb) {}
+ (blocktitle.north east) + (0.2,0) node (comm) {};
+ \draw[fill=\blockcolor\theblocklevel] (blocktitle.north west) -- (blocktitle.north east) --
+ (set.center) -- (seb.center) -- (blocktitle.south west) -- cycle;
+ \node[blockstyle] (blocktitle) at (nw) {\blockname\theblocklevel};
+ \node[blockcommentstyle] (blockcomment) at (comm) {\blockcomm\theblocklevel};
+
+ \coordinate (se) at (current bounding box.south east);
+ \end{pgfinterruptboundingbox}
+
+ \draw (se) rectangle (nw);
+
+ \addtocounter{blocklevel}{-1} % pop
+ \stepcounter{seqlevel}
+}
+
+% the environment of sequence diagram
+\newenvironment{sequencediagram}{
+ % declare layers
+ \pgfdeclarelayer{umlsd@background}
+ \pgfdeclarelayer{umlsd@threadlayer}
+ \pgfsetlayers{umlsd@background,umlsd@threadlayer,main}
+
+ \begin{tikzpicture}
+ \setlength{\unitlength}{1cm}
+ \tikzstyle{sequence}=[coordinate]
+ \tikzstyle{inststyle}=[rectangle, draw, anchor=west, minimum
+ height=0.8cm, minimum width=1.6cm, fill=white,
+ drop shadow={opacity=1,fill=black}]
+ \ifpgfumlsdroundedcorners
+ \tikzstyle{inststyle}+=[rounded corners=3mm]
+ \fi
+ \tikzstyle{blockstyle}=[anchor=north west]
+ \tikzstyle{blockcommentstyle}=[anchor=north west, font=\small]
+ \tikzstyle{dot}=[inner sep=0pt,fill=black,circle,minimum size=0.2pt]
+ \global\def\unitfactor{0.6}
+ \global\def\threadbias{center}
+ % reset counters
+ \setcounter{preinst}{0}
+ \setcounter{instnum}{0}
+ \setcounter{threadnum}{0}
+ \setcounter{seqlevel}{0}
+ \setcounter{callevel}{0}
+ \setcounter{callselflevel}{0}
+ \setcounter{blocklevel}{0}
+
+ % origin
+ \node[coordinate] (inst0) {};
+}
+{
+ \begin{pgfonlayer}{umlsd@background}
+ \ifnum\c@instnum > 0
+ \foreach \t [evaluate=\t] in {1,...,\theinstnum}{
+ \draw[dotted] (inst\t) -- ++(0,-\theseqlevel*\unitfactor-2.2*\unitfactor);
+ }
+ \fi
+ \ifnum\c@threadnum > 0
+ \foreach \t [evaluate=\t] in {1,...,\thethreadnum}{
+ \path (thread\t)+(0,-\theseqlevel*\unitfactor-0.1*\unitfactor) node (threadend) {};
+ \tikzstyle{threadstyle}+=[threadcolor\t]
+ \drawthread{thread\t}{threadend}
+ }
+ \fi
+ \end{pgfonlayer}
+\end{tikzpicture}}
+
+
+%%% End of pgf-umlsd.sty
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \ No newline at end of file
diff --git a/10-entwurfsheft/sections/apidoc.tex b/10-entwurfsheft/sections/apidoc.tex
new file mode 100644
index 0000000..1eb181c
--- /dev/null
+++ b/10-entwurfsheft/sections/apidoc.tex
@@ -0,0 +1,558 @@
+\newenvironment{urlParameter}
+{
+ \newcommand{\urlParamItem}[2]
+ {
+ \rowcolor{\methodLightColor} ##1 & ##2 \\
+ }
+ \newcommand{\noUrlParameter}[1]
+ {
+ \small{\textit{##1}}
+ }
+ %\vspace{-0.61em}
+
+ \arrayrulecolor{\methodColor}
+
+ \begin{tabularx}{\textwidth}{X}
+ \rowcolor{\methodLightColor!20}
+ \textbf{URL-Parameter} \\ \hline
+ \end{tabularx}
+
+ \tabularx{\textwidth}{l X}
+}
+
+\newenvironment{pathParameter}
+{
+ \newcommand{\pathParamItem}[2]
+ {
+ \rowcolor{\methodLightColor} ##1 & ##2 \\
+ }
+ \newcommand{\noPathParameter}[1]
+ {
+ \small{\textit{##1}}
+ }
+ %\vspace{-0.61em}
+
+ \arrayrulecolor{\methodColor}
+
+ \begin{tabularx}{\textwidth}{X}
+ \rowcolor{\methodLightColor!20}
+ \textbf{Pfad-Parameter} \\ \hline
+ \end{tabularx}
+
+ \tabularx{\textwidth}{l X}
+}
+
+\newenvironment{jsonKeys}
+{
+ \newcommand{\jsonKeyItem}[2]
+ {
+ \rowcolor{\methodLightColor} ##1 & ##2 \\
+ }
+ \newcommand{\nojsonKeys}[1]
+ {
+ \small{\textit{##1}}
+ }
+ %\vspace{-0.61em}
+
+ \arrayrulecolor{\methodColor}
+
+ \begin{tabularx}{\textwidth}{X}
+ \rowcolor{\methodLightColor!20}
+ \textbf{Json-Keys} \\ \hline
+ \end{tabularx}
+
+ \tabularx{\textwidth}{l X}
+}
+
+\section{\Gls{api}}
+
+\subsection{Hypertext Transfer Protocol}
+% könnte auch unter in die Sektion API
+
+Das Hypertext Transfer Protocol (http) ist ein Protokoll zum übertragen von
+medialen Daten. Ein Webserver hört über den Port 80 auf Anfragen und antwortet.
+Eine Anfrage besteht aus einer Methode, einem Pfad, Kopfzeilen (\texttt{Header})
+und Inhalt (\texttt{Body}). Die Methode ist eine Konvention, um zu verdeutlichen
+was mit der Anfrage geschehen soll. Es können Daten abgefragt (\texttt{GET}),
+erstellt (\texttt{POST}), aktualisiert (\texttt{PUT}) oder gelöscht werden
+(\texttt{DELETE}). Der Pfad gibt an, für welche Daten die Methode gelten soll.
+Die Kopfzeilen beinhalten dabei Metadaten, wie Authentifikationen, \Glspl{cookie},
+Datentypen (MIME-Types), Sprache und das Anwenderprogramm.
+
+Der Server antwortet mit einem Statuscode, Kopfzeilen und Inhalt. Der Statuscode
+teilt mit, ob die Anfrage erhalten wurde ($\geq$ 100), erfolgreich bearbeitet
+werden konnte ($\geq$ 200), eine Weiterleitung nötig ist ($\geq$ 300),
+die Anfrage einen Fehler enthält ($\geq$ 400) oder
+ein interner Serverfehler aufgetreten ist ($\geq$ 500). In den Kopfzeilen können
+Berechtigungen gesetzt werden, welche festlegen, wie mit den Daten
+umzugehen ist.
+
+\newpage
+\subsection{Geräte} \label{Geräte}
+Die \Gls{gpodder}, welche wir für unser Produkt verwenden und erweitern, bietet eine gerätespezifische
+Synchronisation an. Diese bieten wir jedoch nicht an, denn wir synchronisieren Änderungen aller
+Geräte gleichwertig mit dem Nutzeraccount.
+Deshalb werden Geräte innerhalb der API ignoriert.
+
+\subsection{Authentication API}\label{a:auth}
+
+\subsubsection{Registrierung}\label{a:register}
+
+\begin{apiRoute}{post}{/api/2/auth/register.json}
+ {Registriert einen Nutzer mit einer E-Mail-Adresse und Passwort.
+ Versendet E-Mail mit Bestätigungslink an die angegebene E-Mail-Adresse.}
+ \begin{routeRequest}{application/json}
+ \begin{routeRequestBody}
+{
+ email: "jeff@example.com",
+ password: "MyNameIsJeff"
+}
+ \end{routeRequestBody}
+ \end{routeRequest}
+ \begin{routeResponse}{application/json}
+ \begin{routeResponseItem}{200}
+ {OK: Nutzer wurde erfolgreich angelegt.}
+ \end{routeResponseItem}
+
+ \begin{routeResponseItem}{400}
+ {Bad Request: Fehler beim Parsen der Anfrage}
+ \end{routeResponseItem}
+ \end{routeResponse}
+\end{apiRoute}
+
+\newpage
+
+\subsubsection{Anmelden}\label{a:login}
+
+\begin{apiRoute}{post}{/api/2/auth/\{username\}/login.json}
+ {Gegebenen Nutzer des gegebenen Geräts mithilfe HTTP Basic Auth einloggen.}
+ \begin{pathParameter}
+ \pathParamItem{username}{Nutzername des einzuloggenden Nutzers}
+ \end{pathParameter}
+ \begin{routeResponse}{application/json}
+ \begin{routeResponseItem}{200}
+ {OK: Die Responseheader haben ein gesetztes Session-ID \Gls{cookie}.}
+ \end{routeResponseItem}
+
+ \begin{routeResponseItem}{400}
+ {Bad Request: Der Client stellt einen \Gls{cookie} für einen falschen Nutzer bereit.}
+ \end{routeResponseItem}
+
+ \begin{routeResponseItem}{401}
+ {Unauthorized: Zugriff ohne Anmeldedaten}
+ \end{routeResponseItem}
+ \end{routeResponse}
+\end{apiRoute}
+
+\subsubsection{Abmelden}\label{a:logout}
+
+\begin{apiRoute}{post}{/api/2/auth/\{username\}/logout.json}
+ {Löscht den \Gls{cookie} beim Client.}
+ \begin{pathParameter}
+ \pathParamItem{username}{Nutzername des betreffenden Nutzers}
+ \end{pathParameter}
+ \begin{routeResponse}{application/json}
+ \begin{routeResponseItem}{200}
+ {OK: Falls der Client keinen \Gls{cookie} gesendet hat oder der Nutzer
+ erfolgreich ausgeloggt wurde.}
+ \end{routeResponseItem}
+
+ \begin{routeResponseItem}{400}
+ {Bad Request: Der Client stellt einen \Gls{cookie} für den falschen Nutzer bereit.}
+ \end{routeResponseItem}
+ \end{routeResponse}
+\end{apiRoute}
+
+\newpage
+
+\subsubsection{Passwort ändern}\label{a:changepassword}
+
+\begin{apiRoute}{put}{/api/2/auth/\{username\}/changepassword.json}
+ {Passwort des gegebenen Nutzer ändern, indem altes und neues Passwort
+ übergeben werden. }
+ \begin{pathParameter}
+ \pathParamItem{username}{Nutzername des betreffenden Nutzers}
+ \end{pathParameter}
+ \begin{routeRequest}{application/json}
+ \begin{routeRequestBody}
+{
+ password: "MyPasswordWasLeaked",
+ new_password: "SoIMadeANewOne"
+}
+ \end{routeRequestBody}
+ \end{routeRequest}
+ \begin{routeResponse}{application/json}
+ \begin{routeResponseItem}{200}
+ {OK: Die Responseheader haben ein gesetztes Session-ID \Gls{cookie}.}
+ \end{routeResponseItem}
+
+ \begin{routeResponseItem}{400}
+ {Bad Request: Der Client stellt einen \Gls{cookie} für einen falschen Nutzer bereit.}
+ \end{routeResponseItem}
+
+ \begin{routeResponseItem}{401}
+ {Unauthorized: Zugriff ohne Anmeldedaten}
+ \end{routeResponseItem}
+ \end{routeResponse}
+\end{apiRoute}
+
+\subsubsection{Passwort vergessen}\label{a:forgot}
+
+\begin{apiRoute}{post}{/api/2/auth/forgot.json}
+ {Sende eine E-Mail zum Zurücksetzen des Passworts. }
+ \begin{routeRequest}{application/json}
+ \begin{routeRequestBody}
+{
+ email: "jeff@example.com"
+}
+ \end{routeRequestBody}
+ \end{routeRequest}
+ \begin{routeResponse}{application/json}
+ \begin{routeResponseItem}{200}
+ {OK: E-Mail wurde erfolgreich versendet.}
+ \end{routeResponseItem}
+
+ \begin{routeResponseItem}{400}
+ {Bad Request: Fehler beim Parsen der Anfrage}
+ \end{routeResponseItem}
+ \end{routeResponse}
+\end{apiRoute}
+
+\newpage
+\subsubsection{Passwort zurücksetzen}\label{a:resetpassword}
+
+\begin{apiRoute}{put}{/api/2/auth/\{username\}/resetpassword.json}
+ {Passwort des gegebenen Nutzers ändern nachdem dieser sein Passwort
+ vergessen hat. }
+ \begin{pathParameter}
+ \pathParamItem{username}{Nutzername des betreffenden Nutzers}
+ \end{pathParameter}
+ \begin{urlParameter}
+ \urlParamItem{token}{JSON-Web-Token}
+ \end{urlParameter}
+ \begin{routeRequest}{application/json}
+ \begin{routeRequestBody}
+{
+ password: "APasswordIWontForgetAgain"
+}
+ \end{routeRequestBody}
+ \end{routeRequest}
+ \begin{routeResponse}{application/json}
+ \begin{routeResponseItem}{200}
+ {OK: Das Passwort wurde erfolgreich geändert.}
+ \end{routeResponseItem}
+
+ \begin{routeResponseItem}{400}
+ {Bad Request: Fehler beim Parsen der Anfragen. }
+ \end{routeResponseItem}
+
+ \begin{routeResponseItem}{401}
+ {Unauthorized: JWT ist ungültig. }
+ \end{routeResponseItem}
+ \end{routeResponse}
+\end{apiRoute}
+
+\newpage
+\subsubsection{Account löschen}\label{a:delete}
+
+\begin{apiRoute}{delete}{/api/2/auth/\{username\}/delete.json}
+ {Der Account des gegebenen Nutzers wird gelöscht.}
+ \begin{pathParameter}
+ \pathParamItem{username}{Nutzername des zu löschenden Nutzers.}
+ \end{pathParameter}
+ \begin{routeRequest}{application/json}
+ \begin{routeRequestBody}
+{
+ password: "APasswordIWontHaveToRememberAnymore"
+}
+ \end{routeRequestBody}
+ \end{routeRequest}
+ \begin{routeResponse}{application/json}
+ \begin{routeResponseItem}{200}
+ {OK: Der Account des gegebenen Nutzers wurde erfolgreich gelöscht.}
+ \end{routeResponseItem}
+
+ \begin{routeResponseItem}{400}
+ {Bad Request: Der Client stellt einen \Gls{cookie} für einen falschen Nutzer bereit.}
+ \end{routeResponseItem}
+
+ \begin{routeResponseItem}{401}
+ {Unauthorized: Zugriff ohne Anmeldedaten}
+ \end{routeResponseItem}
+ \end{routeResponse}
+\end{apiRoute}
+
+\newpage
+\subsection{Subscriptions API}\label{a:subs}
+\subsubsection{Abrufen aller \Glspl{abo}}\label{a:getSubs}
+
+\begin{apiRoute}{get}{/subscriptions/\{username\}.json}{/subscriptions/\{username\}/\{deviceid\}.json}
+ \begin{pathParameter}
+ \pathParamItem{username}{Nutzername des betreffenden Nutzers}
+ \pathParamItem{deviceid}{siehe~\nameref{Geräte}}
+ \end{pathParameter}
+
+ \begin{urlParameter}
+ \urlParamItem{jsonp}{\Gls{JSONP} wird nicht unterstützt und der Parameter entsprechend ignoriert.}
+ \end{urlParameter}
+
+ \begin{routeResponse}{application/json}
+
+ \begin{routeResponseItem}{200}
+ {OK: \Glspl{abo} werden im \Gls{json}-Format zurückgegeben.}
+ \begin{routeResponseItemBody}
+[
+ "http://example.org/feed.rss",
+ "http://example.org/podcast.php",
+ "http://example.org/foo"
+]
+ \end{routeResponseItemBody}
+ \end{routeResponseItem}
+
+ \begin{routeResponseItem}{400}{Bad Request: falsches Format}
+ \end{routeResponseItem}
+
+ \begin{routeResponseItem}{401}
+ {Unauthorized: falscher Nutzer oder nicht eingeloggt}
+ \end{routeResponseItem}
+
+ \end{routeResponse}
+\end{apiRoute}
+
+\newpage
+\subsubsection{Abrufen der Informationen aller \Glspl{abo}}\label{a:getTitles}
+
+\begin{apiRoute}{get}{/subscriptions/titles/\{username\}.json}{/subscriptions/\{username\}/\{deviceid\}.json}
+
+ \begin{pathParameter}
+ \pathParamItem{username}{Nutzername des betreffenden Nutzers}
+ \end{pathParameter}
+ \begin{routeResponse}{application/json}
+
+ \begin{routeResponseItem}{200}
+ {OK: \Glspl{abo} werden im angefragten Format zurückgegeben. Dabei werden für ein \Gls{abo} nur die aktuellsten 20 \Glspl{episode} zurückgegeben.}
+ \begin{routeResponseItemBody}
+[
+ {
+ "url": "http://example.com/podcast.php",
+ "title": "This is a cool podcast"
+ "timestamp": "2009-12-12T09:00:00",
+ "episodes": [
+ {
+ "podcast": "http://example.org/podcast.php",
+ "episode": "http://ftp.example.org/foo.ogg",
+ "title": "Episode 1: My journy",
+ "timestamp": "2009-12-12T09:00:00",
+ "guid": "AU-20190814-1342-5100-A",
+ "action": "play",
+ "started": 15,
+ "position": 120,
+ "total": 500
+ }
+ ]
+ }
+]
+ \end{routeResponseItemBody}
+ \end{routeResponseItem}
+
+ \begin{routeResponseItem}{400}{Bad Request: falsches Format}
+ \end{routeResponseItem}
+
+ \end{routeResponse}
+
+\end{apiRoute}
+\newpage
+
+\subsubsection{\Glspl{abo} hochladen}\label{a:uploadSubs}
+
+\begin{apiRoute}{put}{/subscriptions/\{username\}/\{deviceid\}.json}
+ {Falls bereits \Glspl{abo} im Nutzeraccount vorhanden, werden diese
+ zusammengeführt.}
+
+ \begin{pathParameter}
+ \pathParamItem{username}{Nutzername des betreffenden Nutzers}
+ \pathParamItem{deviceid}{siehe~\nameref{Geräte}}
+ \end{pathParameter}
+
+ \begin{routeResponse}{application/json}
+ \begin{routeResponseItem}{200}
+ {OK: \Glspl{abo} wurden aktualisiert und leerer String wird zurückgegeben.}
+ \end{routeResponseItem}
+
+ \begin{routeResponseItem}{400}{Bad Request: falsches Format}
+ \end{routeResponseItem}
+
+ \begin{routeResponseItem}{401}{Unauthorized: falscher Nutzer}
+ \end{routeResponseItem}
+ \end{routeResponse}
+\end{apiRoute}
+
+\subsubsection{Abrufen von \Gls{abo}-Änderungen}\label{a:getSubDelta}
+
+\begin{apiRoute}{get}{/api/2/subscriptions/\{username\}/\{deviceid\}.json}
+ {}
+
+ \begin{pathParameter}
+ \pathParamItem{username}{Nutzername des betreffenden Nutzers}
+ \pathParamItem{deviceid}{siehe~\nameref{Geräte}}
+ \end{pathParameter}
+
+ \begin{urlParameter}
+ \urlParamItem{since}{Timestamp-Wert der letzten Antwort}
+ \end{urlParameter}
+
+ \begin{routeResponse}{application/json}
+
+ \begin{routeResponseItemBody}
+{
+ "add": [
+ "http://example.com/feed.rss",
+ "http://example.org/podcast.php"
+ ],
+ "remove": ["http://example.net/foo.xml"],
+ "timestamp": 12347
+}
+ \end{routeResponseItemBody}
+ \end{routeResponse}
+
+\end{apiRoute}
+
+\newpage
+\subsubsection{Änderungen der \Glspl{abo} hochladen}\label{a:applySubDelta}
+
+\begin{apiRoute}{post}{/api/2/subscriptions/\{username\}/\{deviceid\}.json}
+ {}
+
+ \begin{pathParameter}
+ \pathParamItem{username}{Nutzername des betreffenden Nutzers}
+ \pathParamItem{deviceid}{siehe~\nameref{Geräte}}
+ \end{pathParameter}
+
+ \begin{routeRequest}{application/json}
+ \begin{routeRequestBody}
+{
+ "add": [
+ "http://example.com/feed.rss",
+ "http://example.org/podcast.php"
+ ],
+ "remove": ["http://example.net/foo.xml"]
+}
+ \end{routeRequestBody}
+ \end{routeRequest}
+
+ \begin{routeResponse}{application/json}
+ \begin{routeResponseItem}{200}{OK: \Glspl{abo} wurden aktualisiert.}
+ \begin{routeResponseItemBody}
+{
+ "timestamp": 1337,
+ "update_urls": []
+}
+ \end{routeResponseItemBody}
+ ``update\textunderscore urls'' wird nicht bereitgestellt, deshalb
+ wird eine leere Liste zurückgegeben.
+ \end{routeResponseItem}
+ \begin{routeResponseItem}{400}{Bad Request: falsches Format}
+ \end{routeResponseItem}
+ \end{routeResponse}
+\end{apiRoute}
+
+\newpage
+\subsection{Episode Action API}\label{a:episodeActions}
+
+\subsubsection{Episode Actions hochladen}\label{a:uploadEpisodeActions}
+
+\begin{apiRoute}{post}{/api/2/episodes/\{username\}.json}
+ {}
+
+ \begin{pathParameter}
+ \pathParamItem{username}{Nutzername des betreffenden Nutzers}
+ \end{pathParameter}
+
+ \begin{routeRequest}
+
+ \begin{routeRequestBody}
+POST /api/2/episodes/some-user.json
+[
+ {
+ "podcast": "http://example.org/podcast.php",
+ "episode": "http://ftp.example.org/foo.ogg",
+ "title": "Episode 1: My journey",
+ "timestamp": "2009-12-12T09:00:00"
+ "guid": "AU-20190814-1342-5100-A",
+ "action": "play",
+ "started": 15,
+ "position": 120,
+ "total": 500
+ }
+]
+
+ \end{routeRequestBody}
+
+ \end{routeRequest}
+
+ \begin{jsonKeys}
+ \jsonKeyItem{podcast}{Feed-URL des \Glspl{podcast} zu welchem die \Gls{episode} gehört (erforderlich)}
+ \jsonKeyItem{episode}{Medien-URL der \Gls{episode} (erforderlich)}
+ \jsonKeyItem{device}{Geräte-ID auf welcher die Aktion stattfand.}
+ \jsonKeyItem{action}{Eins von: download, play, delete, new (erforderlich)}
+ \jsonKeyItem{timestamp}{UTC-Timestamp im ISO 8601 Format, wann die Aktion stattfand}
+ \jsonKeyItem{started}{Position in Sekunden, an welcher das Anhören der \Gls{episode} gestartet wurde (nur bei Aktion: play)}
+ \jsonKeyItem{position}{Position in Sekunden, an welcher das Anhören der \Gls{episode} gestoppt wurde (nur bei Aktion: play)}
+ \jsonKeyItem{total}{Länge der \Gls{episode} (nur bei Aktion: play)}
+
+ \end{jsonKeys}
+
+ \begin{routeResponse}{application/json}
+ \begin{routeResponseItem}{200}{OK}
+ \begin{routeResponseItemBody}
+{
+ "timestamp": 1337,
+ "update_urls": []
+}
+ \end{routeResponseItemBody}
+ ``update\textunderscore urls'' wird nicht bereitgestellt, deshalb
+ wird eine leere Liste zurückgegeben.
+ \end{routeResponseItem}
+ \end{routeResponse}
+\end{apiRoute}
+
+\subsubsection{Abrufen von Episode Actions}\label{a:getEpisodeActions}
+
+\begin{apiRoute}{get}{/api/2/episodes/\{username\}.json}
+ {}
+
+ \begin{pathParameter}
+ \pathParamItem{username}{Nutzername des betreffenden Nutzers}
+ \end{pathParameter}
+
+ \begin{urlParameter}
+ \urlParamItem{podcast (string)}{URL des \Glspl{podcast}; falls gesetzt, werden nur Aktionen der \Glspl{episode} des gegebenen \Glspl{podcast} zurückgegeben.}
+ \urlParamItem{device (string)}{Device-ID; siehe~\nameref{Geräte}}
+ \urlParamItem{since (int)}{Nur \Glspl{episode}-Aktionen ab dem gegebenen Timestamp werden zurückgegeben.}
+ \urlParamItem{aggregated (bool)}{Wird ignoriert. }
+ \end{urlParameter}
+
+ \begin{routeResponse}{application/json}
+ \begin{routeResponseItem}{200}{OK}
+ \begin{routeResponseItemBody}
+{
+ "actions": [
+ {
+ "podcast": "http://example.org/podcast.php",
+ "episode": "http://ftp.example.org/foo.ogg",
+ "title": "Episode 1: My journey",
+ "timestamp": "2009-12-12T09:00:00"
+ "guid": "AU-20190814-1342-5100-A",
+ "action": "play",
+ "started": 15,
+ "position": 120,
+ "total": 500
+ }
+ ],
+ "timestamp": 12345
+}
+ \end{routeResponseItemBody}
+ \end{routeResponseItem}
+ \end{routeResponse}
+\end{apiRoute}
+
diff --git a/10-entwurfsheft/sections/aufbau.tex b/10-entwurfsheft/sections/aufbau.tex
new file mode 100644
index 0000000..c0747a9
--- /dev/null
+++ b/10-entwurfsheft/sections/aufbau.tex
@@ -0,0 +1,89 @@
+\section{Aufbau}
+
+\subsection{Architektur}
+
+\subsubsection{Aufteilung in Pakete}
+
+Das Backend wird in Pakete aufgeteilt, die den einzelnen implementierten
+\Glspl{api} der gpodder.net \Gls{api} entsprechen.
+Dies entspricht hier den \Glspl{api}: Subscriptions, Episode Actions und Authentication.
+Außerdem gibt es ein Model-Paket, welches die in den Logikschichten verwendeten Objekte modelliert.
+
+Für den Webserver selbst werden die \Glspl{api} um zusätzliche Funktionen erweitert. Denn die vorhandenen \Glspl{api} bieten nicht alle Funktionalitäten, die der Webserver benötigt, um die im Pflichtenheft beschriebenen Kriterien zu erfüllen.
+% (TODO: WebAPI bestimmen)
+
+\subsubsection{Die Architektur in den Paketen}
+
+In den Paketen selber herrscht eine 3-schichtige Architektur aus den Schichten: Controller, Service und Data-Access (siehe \ref{DAO_Pattern}).
+
+Die Controller-Schicht nimmt die Anfragen des Clients entgegen, lässt diese in den untergeordneten Schichten verarbeiten und gibt den Status der abgeschlossenen Handlung an den Client zurück.
+
+Die Service-Schicht ist die \Gls{business} des Programmes und überprüft bspw. Eingaben oder verschickt E-Mails. Sollte ein \Gls{db}aufruf nötig sein, so ruft der Service die Data-Access-Schicht auf und übergibt ihr die nötigen Informationen, was gespeichert, gelöscht, aktualisiert oder gelesen werden soll.
+
+Die Data-Access-Schicht ist für den Datenzugriff auf \Glspl{db} verantwortlich. Alle verantwortlichen Klassen für einen solchen Zugriff folgen dem \Gls{crud}-Prinzip.
+\Gls{crud} steht für die Funktionen Create (erschaffen), Read (lesen), Update (aktualisieren) und Delete (löschen). Entsprechend können Einträge in einer \Gls{db} auch nur erschaffen, gelesen, aktualisiert und gelöscht werden.
+
+\subsubsection{Das Model-Paket}\label{p:model}
+
+In einem globalen Model-Paket befinden sich alle Klassen, die für die Modellierungen von Objekten zuständig sind.
+Diese Objekte werden später in \Gls{db}abfragen gelesen und mittels objektrelationaler Abbildung (siehe \ref{t:orm}) gespeichert.
+In einer Antwort an den Client werden die Objekte, falls benötigt, als Antwort-Klassen gewrappt im \Gls{json}-Format zurückgeschickt.
+Auch kann der Client in einer Anfrage ein Objekt im \Gls{json}-Format übergeben, welches dann mithilfe von Spring als \Gls{java}-Objekt der korrespondierenden Anfrage-Klasse interpretiert wird.
+Aus diesem wird dann in Controller- und Service-Schicht das Objekt der entsprechenden Model-Klasse extrahiert.
+
+\subsubsection{Die Datenhaltungsschicht}
+
+Mit den Paketen ist bereits eine 3-schichtige Architektur aufgebaut.
+Damit Daten aber auch gelesen und gespeichert werden können ist eine vierte globale Schicht nötig - die Datenhaltungsschicht.
+
+Die Datenhaltungsschicht ist für die persistente Speicherung aller Daten zuständig.
+Diese werden meist (wie in diesem Fall) in einer \Gls{db} gespeichert.
+Der Zugriff auf die Datenhaltungsschicht erfolgt gemäß der intransparenten Schichtenarchitektur nur über die Data-Access-Schicht der Pakete.
+
+Der Vorteil dieser mehrschichtigen Architektur ist die klare Strukturierung des Programmes, womit der Code leserlicher und einfacher zu warten ist.
+
+\begin{landscape}
+
+\subsection{Klassendiagramm Backend}
+Das Klassendiagramm zeigt alle für den Entwurf relevanten Klassen des Backends mit ihren öffentlichen Methoden.
+Weiter zeigt das Diagramm die Aufteilung der Klassen in Pakete sowie schemenhaft dargestellte Verbindungen zu \Gls{db} und Webserver.
+
+% \input{assets/diagrams/classdiagram.latex}
+\includegraphics[width=\linewidth]{assets/diagrams/classdiagram}
+\end{landscape}
+
+\subsection{Sequenzdiagramme}
+
+\subsubsection{Authentication \Gls{api}}
+\subsubsection*{Registrierung \scriptsize{(\ref{a:register})}}
+\includegraphics[width=\textwidth]{assets/diagrams/sequencediagram-register}
+\subsubsection*{Passwort vergessen und zurücksetzen \scriptsize{(\ref{a:forgot}, \ref{a:resetpassword})}}
+\includegraphics[width=\textwidth]{assets/diagrams/sequencediagram-forgotAndResetPW}
+
+\subsubsection{Subscriptions \Gls{api}}
+\subsubsection*{Abonnements hochladen \scriptsize{(\ref{a:uploadSubs})}}
+\includegraphics[width=\textwidth]{assets/diagrams/sequencediagram-uploadSubscriptions}
+
+\subsubsection*{Abrufen aller Abonnements \scriptsize{(\ref{a:getSubs})}}
+\includegraphics[width=\textwidth]{assets/diagrams/sequencediagram-getSubscriptions}
+
+\subsubsection{Episode Actions \Gls{api}}
+\subsubsection*{Episode Actions hochladen \scriptsize{(\ref{a:uploadEpisodeActions})}}
+\includegraphics[width=\textwidth]{assets/diagrams/sequencediagram-uploadEpisodeActions}
+
+\subsubsection*{Abrufen aller Episode Actions seit einem Zeitpunkt \scriptsize{(\ref{a:getEpisodeActions})}}
+\includegraphics[width=\textwidth]{assets/diagrams/sequencediagram-getEpisodeActionsOfPodcastSince}
+
+\subsubsection*{Abrufen aller Episode Actions \scriptsize{(\ref{a:getEpisodeActions})}}
+\includegraphics[width=\textwidth]{assets/diagrams/sequencediagram-getEpisodeActions}
+
+\subsection{Komponentendiagramm Backend}
+\includegraphics[width=\textwidth]{assets/diagrams/backendComponentDiagram}
+
+\subsection{Verteilungsdiagram}
+\includegraphics[width=\textwidth]{assets/diagrams/deployment}
+
+\subsection{\Gls{db}-Modell}
+
+\includegraphics[width=\textwidth]{assets/diagrams/db}
+
diff --git a/10-entwurfsheft/sections/backend.tex b/10-entwurfsheft/sections/backend.tex
new file mode 100644
index 0000000..19efd65
--- /dev/null
+++ b/10-entwurfsheft/sections/backend.tex
@@ -0,0 +1,28 @@
+\section{Backend}
+
+Für das Backend wird das \Gls{java}-Framework \Gls{spring} verwendet. Neben seiner Modularität,
+bietet es viele Funktionen, die unter
+anderem die Entwicklung von Backend-Anwendungen vereinfachen.
+Darunter fällt zum Beispiel die Unterstützung von Dependency Injection, dessen
+Vorteile bereits beschrieben wurden.
+Außerdem unterstützt \Gls{java} \Gls{spring} intern eine Verwaltung von \Glspl{db}, sodass
+sich nicht mit dem \Gls{SQL}-Code an sich befasst werden muss.
+Auch bezüglich Authentifizierung und Sicherheit bietet \Gls{spring} eigene Funktionalitäten.
+
+Zusätzlich dazu wird als Build-System für das \Gls{java}-\Gls{spring}-Backend Maven verwendet.
+Maven hilft dabei alle Abhängigkeiten des Projekts zu verwalten und automatisiert
+den Build Prozess.
+Durch die zusätzliche Unterstützung von Versionskontrollsystemen und der Kompatibilität
+zu vielen Continuous Integration-Tools wird außerdem die Entwicklung in einem Team erleichtert
+und optimiert. Denn dadurch können Build- und Deployment-Prozesse automatisiert werden.
+Außerdem bietet Maven Bibliotheken zum Testen sowie zur Generierung von Dokumentationen an.
+
+Vom Backend benötigte Abhängigkeiten:
+\begin{itemize}
+ \item \Gls{spring} Web
+ \item \Gls{spring} Security
+ \item \Gls{spring} Mail Sender
+ \item \Gls{spring} Data JPA
+ \item Lombok
+ \item Rome (\Gls{rss} parsing/fetching)
+\end{itemize} \ No newline at end of file
diff --git a/10-entwurfsheft/sections/changes.tex b/10-entwurfsheft/sections/changes.tex
new file mode 100644
index 0000000..d8ac2ec
--- /dev/null
+++ b/10-entwurfsheft/sections/changes.tex
@@ -0,0 +1,41 @@
+
+\section{Änderungen zum Pflichtenheft}
+
+Im Folgenden werden die Änderungen zum Pflichtenheft aufgelistet.
+Hierbei handelt es sich um neue Kriterien, Kriterien die wegfallen und Kriterien die modifiziert wurden.
+
+\subsection{Neue Kriterien}
+
+\subsubsection{Cooldown Fetch-Vorgang}
+\begin{description}
+ \item[\textcolor{Green}{\textlangle RS11\textrangle}] \textcolor{Green}{Wenn ein Nuter ein \Gls{abo} oder eine \Gls{episode} eines \Gls{abo} hinzugefügt hat, welche noch nicht
+ in der \Gls{db} vorhanden ist, werden die Daten vom entsprechenden Server gefetched. Bis eine weitere fetch-Anfrage
+ zum selben \Gls{abo} gestartet wird, wird ein Cooldown von einer Stunde abgewartet.
+ Das hilft dabei DoS Angriffe zu vermeiden, da der Server damit nicht durch zu viele Fetch-Anfragen überlastet
+ werden kann.}
+\end{description}
+
+\subsubsection{Sprache von Browserinformationen übernehmen}
+\begin{description}
+ \item[\textcolor{Green}{\textlangle RC13\textrangle}] \textcolor{Green}{Betritt ein Nutzer zum ersten Mal die Webseite, ruft ein Skript die Browserdaten zur eingestellten Sprache ab.
+ Die Sprache wird im localStorage gespeichert und ruft entsprechend die Webseite in der jeweiligen Sprache auf.
+ Ändert der Nutzer die Sprache, so wird dies durch eine Änderung der Sprachvariable im localStorage festgehalten. }
+\end{description}
+
+\subsection{Abgeänderte Kriterien}
+
+ \subsubsection{Sessionspeicherung mit JWT}
+
+ \begin{description}
+ \item[\textlangle RS10\textrangle] Im Webfrontend angemeldete Benutzer bleiben dort angemeldet.
+ Hierfür wird ein \Gls{session-token} in einem \Gls{cookie} gespeichert.
+ \textcolor{blue}{Als \Gls{session-token} wird ein \Gls{json} Web Token verwendet.
+ Dieser Token wird für die Authentifikation genutzt.}
+ \end{description}
+
+\subsection{Entfernte Kriterien}
+
+ \begin{description}
+ \item[\textlangle RC5\textrangle]
+ \textcolor{red}{\sout{Die Weboberfläche ist kompatibel mit beliebigen \Glspl{gpodder}.}}
+ \end{description}
diff --git a/10-entwurfsheft/sections/einleitung.tex b/10-entwurfsheft/sections/einleitung.tex
new file mode 100644
index 0000000..0fd6114
--- /dev/null
+++ b/10-entwurfsheft/sections/einleitung.tex
@@ -0,0 +1,22 @@
+\section{Einleitung}
+
+Im vorangegangenen Pflichtenheft wurde ein Synchronisationsserver für \Glspl{podcast} beschrieben.
+In diesem Entwurfsheft wird die Implementierung dieses Synchronisationsservers
+mithilfe eines Entwurfes geplant.
+Wie im Pflichtenheft beschrieben, wird das finale Produkt
+aus einem Backend und einem Frontend bestehen.
+
+Das Webfrontend dient dazu, dem Nutzer eine Oberfläche zur Accountverwaltung
+und Einsicht seiner Synchronisationsstände und Daten zu ermöglichen.
+Dieses wird mithilfe des Javascript Frameworks Vue.js erstellt.
+
+Das Backend dient dazu, HTTP-Anfragen des Frontends und der \Gls{podcatcher} entgegenzunehmen,
+zu verarbeiten sowie zu beantworten.
+Damit Daten persistent gespeichert werden können, wird eine \Gls{db} eingebunden.
+Zur Erstellung des Backends wird \Gls{java} \Gls{spring} verwendet und für die \Gls{db} MariaDB.
+
+%Neben den Schichten gibt es drei große Zuordnungsbereiche in unserem Produkt.
+%Nämlich die Abonnements die ein Nutzer haben kann, deren Episoden
+%und die Accountverwaltung.
+%Deshalb unterteilen wir die einzelnen Projektklassen
+%schichtenübergreifend gemäß dieser Kategorien nochmals in einzelne Pakete.
diff --git a/10-entwurfsheft/sections/frontend.tex b/10-entwurfsheft/sections/frontend.tex
new file mode 100644
index 0000000..69a3c61
--- /dev/null
+++ b/10-entwurfsheft/sections/frontend.tex
@@ -0,0 +1,150 @@
+\section{Weboberfläche}
+
+Die Weboberfläche wird mit dem Frontend-Web-Framework Vue.js erstellt. Mit Vue
+werden wiederverwendbare, auf Datenänderungen reagierende Komponenten erstellt.
+Die Komponenten nutzen ein fertiges Aussehen von dem Frontend-CSS-Framework
+Bootstrap. Außerdem werden Icons der freien Schriftart fontawesome
+verwendet.
+
+Das Projekt wird durch den \Gls{bundler} vite aufgesetzt, gebaut und stellt einen
+Entwicklungswebserver mit Echtzeitvorschau bereit. Durch den vue-router wird bei
+der \Gls{spa} ein Seitenwechsel durch Manipulation der
+Browser-Chronik (History Manipulation) simuliert. Dadurch hat der Nutzer eine
+bessere Erfahrung, weil die Seite nicht neu geladen werden muss, wenn zu einem
+anderen Menüpunkt gewechselt wird.
+
+Wenn der Nutzer sich anmeldet wird die E-Mail-Adresse, der \Gls{session-token} und
+Spracheinstellungen in dem globallen Zustandsspeicher gespeichert, welcher durch
+die Pinia-Abhängigkeit bereitgestellt wird. Dadurch haben alle
+\Glspl{uiComponent} einfachen Zugriff auf die Daten und diese müssen nicht über
+Props in tiefliegende \Glspl{uiComponent} durchgereicht werden.
+
+Die Seiten werden als einzelne Kompontenten erstellt. Andere HTML-Strukturen
+werden als eigene Komponenten ausgelagert, wenn sie in mehreren Seiten verwendet
+werden und zur Reduzierung von Komplexität und Duplikation beitragen und selbst
+Logik beinhalten.
+
+Vom Frontend benötigte Abhängigkeiten:
+\begin{itemize}
+\item vite
+\item vue
+\item vue-router
+\item Pinia (globaler Zustandsspeicher)
+\item bootstrap
+\item fontawesome
+\item vue-i18n (Support für mehrere Sprachen)
+\end{itemize}
+
+\subsection{Komponentendiagramm Web-Frontend}
+\includegraphics[width=\textwidth]{assets/diagrams/componentdiagram}
+
+\subsection{Komponentenbeschreibung}
+
+\begin{minipage}{.7\linewidth}
+
+\subsubsection*{SubscriptionComponent}
+
+\begin{description}
+\item[Tag] \texttt{<Subscription subscription>}
+\item[Props] \mbox{} \\
+ \emph{subscription} \mbox{} Subscription-Objekt, welches Attribute zu einem \Gls{podcast} und
+ dessen \Glspl{episode} enthält.
+\item[Beschreibung] Nimmt ein Subscription-Objekt, zeigt Titel und LastUpdate und
+\Glspl{episode} der Subscription an.
+\end{description}
+\end{minipage}
+\begin{minipage}{.3\linewidth}
+ \begin{figure}[H]
+ \includegraphics[width=\textwidth]{assets/subscription.png}
+ \end{figure}
+\end{minipage}
+
+
+\vspace{.5cm}
+\begin{minipage}{.7\linewidth}
+\subsubsection*{EpisodeComponent}
+
+\begin{description}
+\item[Tag] \texttt{<Episode episode>}
+\item[Props] \mbox{} \\
+ \emph{episode} \mbox{} EpisodeAction-Objekt, welches Titel, \Gls{podcast},
+ Timestamp, Dauer und Hörfortschritt der \Gls{episode} enthält.
+\item[Beschreibung] Nimmt ein EpisodeAction-Object, zeigt Titel, \Gls{podcast}, Dauer,
+ Hörfortschritt und LastUpdate an.
+\end{description}
+\end{minipage}
+\begin{minipage}{.3\linewidth}
+ \begin{figure}[H]
+ \includegraphics[width=\textwidth]{assets/episode.png}
+ \end{figure}
+\end{minipage}
+
+
+\vspace{.5cm}
+\begin{minipage}{.7\linewidth}
+\subsubsection*{LastUpdateComponent}
+
+\begin{description}
+\item[Tag] \texttt{<LastUpdate timestamp>}
+\item[Props] \mbox{} \\
+ \emph{timestamp} \mbox{} Date-Objekt, welches die Zeit der letzten Änderung enthält
+\item[Beschreibung] Nimmt ein Timestamp und gibt die Zeit seit dem Timestamp in
+ einem menschenlesbaren Format aus.
+\end{description}
+\end{minipage}
+\begin{minipage}{.3\linewidth}
+ \begin{figure}[H]
+ \includegraphics[width=\textwidth]{assets/lastupdate.png}
+ \end{figure}
+\end{minipage}
+
+
+\vspace{.5cm}
+\begin{minipage}{.7\linewidth}
+\subsubsection*{HelpComponent}
+
+\begin{description}
+\item[Tag] \texttt{<Help>}
+\item[Beschreibung] Zeigt Hilfestellungen in einem Fenster an. Dieses kann über
+ die Navigationsleiste aufgerufen werden.
+\end{description}
+\end{minipage}
+\begin{minipage}{.3\linewidth}
+ \begin{figure}[H]
+ \includegraphics[width=\textwidth]{assets/help.png}
+ \end{figure}
+\end{minipage}
+
+
+\vspace{.5cm}
+\begin{minipage}{.7\linewidth}
+\subsubsection*{NavbarComponent}
+
+\begin{description}
+\item[Tag] \texttt{<Navbar>}
+\item[Beschreibung] Enthält route-links zu im vue-router definierten Pfaden.
+\end{description}
+\end{minipage}
+\begin{minipage}{.3\linewidth}
+ \begin{figure}[H]
+ \fbox{\includegraphics[width=\textwidth]{assets/navbar.png}}
+ \end{figure}
+\end{minipage}
+
+
+\vspace{.5cm}
+\begin{minipage}{.7\linewidth}
+\subsubsection*{PasswordValidatorComponent}
+
+\begin{description}
+\item[Tag] \texttt{<Password>}
+\item[Beschreibung] Überprüft ob der eingegebene Text die Bedingungen für ein
+ sicheres Passwort erfüllt.
+\end{description}
+\end{minipage}
+\begin{minipage}{.3\linewidth}
+ \begin{figure}[H]
+ \includegraphics[width=\textwidth]{assets/password-margin.png}
+ \end{figure}
+\end{minipage}
+
diff --git a/10-entwurfsheft/sections/glossar.tex b/10-entwurfsheft/sections/glossar.tex
new file mode 100644
index 0000000..9caad87
--- /dev/null
+++ b/10-entwurfsheft/sections/glossar.tex
@@ -0,0 +1,371 @@
+\makeglossaries
+
+\newglossaryentry{spa}
+{
+ name=Single-Page-Application,
+ description={
+ ist ein Webseiten-Modell, bei welchem dem Nutzer nur ein Webdokument
+ bereitgestellt wird. Mit einem Skript wird der Inhalt der Seite
+ dynamisch mit Daten einer API befüllt. Außerdem verwaltet die Seite
+ (nicht der Server), welcher Inhalt bei welchem Pfad angezeigt wird. Dies
+ erzeugt geringere Serverlast und eine bessere Nutzererfahrung, da die
+ Seitenstruktur beim Laden von neuen Inhalten erhalten bleibt}
+}
+
+\newglossaryentry{packagemanager}
+{
+ name=Paketmanager,
+ description={
+ ist ein Programm, welches Pakete und dessen Abhängigkeiten verwaltet,
+ installiert, entfernt und aktualisiert. Pakete können andere Programme,
+ Plugins oder Software-Bibliotheken sein}
+}
+
+\newglossaryentry{bundler}
+{
+ name=Bundler,
+ description={
+ ist ein Programm, welches genutzte Teile von Abhängigkeiten eines
+ Software-Projekts in passender Reihenfolge zusammensucht und daraus
+ Dateien erstellt, die für den Nutzer bereitgestellt werden können. Dabei
+ kann der Bundler mit zusätzlichen Modulen Dateien erzeugen, die
+ rückwärtskompatibel oder für den Nutzer schwerer einsehbar sind}
+}
+
+\newglossaryentry{java}
+{
+ name=Java,
+ description={
+ ist eine objekt-orientierte interpretierte kompilierte
+ Programmiersprache, welche plattformunabhängig auf einer virtuellen
+ Maschine ausgeführt wird}
+}
+
+\newglossaryentry{db}
+{
+ name=Datenbank,
+ plural=Datenbanken,
+ description={
+ ist ein System um Daten persistent zu speichern und effizient zu
+ verwalten. Am meisten verbreitet sind relationale Datenbanken, welche
+ Daten in Tabellen mit Referenzen zu Einträgen anderer Tabellen
+ speichern. Programme können dann über eine Anfragesprache (Structured
+ Query Language - \Gls{SQL}) komplexe Operationen auf den Daten ausführen}
+}
+
+\newglossaryentry{docker}
+{
+ name=Docker,
+ description={
+ ist ein Programm, das virtualisierte Container ausführt. Ein Programm in
+ so einem Container läuft in seiner eigenen virtuellen Umgebung, wodurch
+ das Host-System sicher bleibt. Zudem lassen sich die Container leicht
+ auf andere Systeme verteilen}
+}
+
+% RESTfull-API, JSON, RSS-Feed, Salting and Hasing, OAuth, Cookie, Garbage
+% Collection, DSGVO, Podcast, Podcatcher, Episode, Gpodder,
+
+\newglossaryentry{podcatcher}
+{
+ name=Podcatcher,
+ plural=Podcatchern,
+ description={
+ ist ein Programm, über welches man Podcasts entdecken, abonnieren und
+ Episoden von Podcasts hören kann. Mit einem Account auf einer Plattform,
+ welche eine Gpodder-API zur Verfügung stellt, können Ereignisse, die von
+ einem Nutzer ausgehen, auf anderen Podcatchern des Nutzers
+ synchronisiert werden}
+}
+
+\newglossaryentry{podcast}
+{
+ name=Podcast,
+ description={
+ ist ein RSS-Feed, dessen Einträge die Episoden darstellen}
+}
+
+\newglossaryentry{episode}
+{
+ name=Episode,
+ plural=Episoden,
+ description={
+ ist ein Eintrag in einem Podcast. Eine URL in dem Eintrag zeigt auf eine
+ Medien-Datei, welche vom Podcatcher abgespielt werden kann}
+}
+
+\newglossaryentry{rest-api}
+{
+ name=RESTful-API,
+ description={
+ ist ein Schnittstellenentwurf über das Hypertext Transfer Protocol
+ (HTTP), bei dem die Schnittstellen strukturiert als Pfad an einem
+ Endpunkt erreichbar sind. Mittels verschiedener HTTP-Methoden können an
+ der Schnittstelle Daten abgefragt (GET), gesendet (PUT), gelöscht
+ (DELETE) oder geändert (POST) werden. Die Daten, die über die
+ Schnittstelle gesendet werden liegen meist im JSON-Format vor}
+}
+
+
+\newglossaryentry{gpodder}
+{
+ name=Gpodder-API,
+ description={
+ wird von gpodder.net benutzt und entwickelt. Die API wird als
+ Schnittstelle zwischen Podcatchern und Podcast Synchronisationsservern
+ verwendet. Weitere Details sind unter
+ "https://gpoddernet.readthedocs.io/en/latest/api/" zu finden}
+}
+
+\newglossaryentry{json}
+{
+ name=JSON,
+ description={
+ (JavaScript Object Notation) ist ein Datenformat und wird zur
+ Übertragung von Strukturen und Daten eingesetzt. JSON besteht dabei aus
+ grundlegenden Datentypen sowie Objekten mit Schlüssel-Wert Paaren und
+ Listen}
+}
+
+\newglossaryentry{oauth}
+{
+ name=OAuth,
+ description={
+ (Open Authorization) ist ein offenes Protokoll, welches es Nutzern
+ ermöglicht, sich mit bereits bestehenden Accounts bei anderen Diensten
+ zu registrieren. Dabei werden benötigte Daten für die Registrierung über
+ die bereitgestellte Schnittstelle zur Verfügung gestellt}
+}
+
+\newglossaryentry{garbage-collection}
+{
+ name=Garbage Collection,
+ description={
+ ist eine automatische Speicherbereinigung, welche nicht mehr benötigten
+ Speicherplatz wieder freigibt. Die Bereinigung kann dabei in determinierten
+ Zeitintervallen erfolgen oder durch bestimmte Ereignisse ausgelöst
+ werden}
+}
+
+\newglossaryentry{salt-hash}
+{
+ name=Salting und Hashing,
+ description={
+ ist eine Methode um Passwörter so zu kodieren, dass sie nicht als
+ Klartext gespeichert werden und auch sicher vor Hash-Wörterbüchern sind.
+ Dafür wird dem Passwort ein bekanntes Wort, der Salt, angefügt, bevor
+ aus dem kompletten Wort eine Prüfsumme, ein Hash, generiert wird. Beim
+ Anmelden wird die Prüfsumme der Anmeldung mit der bekannten
+ Prüfsumme des Passworts verglichen}
+}
+
+\newglossaryentry{rss}
+{
+ name=RSS,
+ description={
+ (Really Simple Syndication) zeigt strukturiert Listen von Nachrichten
+ an. Die Änderungen werden im XML-Format in sogenannte RSS-Dateien
+ geschrieben, welche über einen Link abgerufen werden können}
+}
+
+\newglossaryentry{dsgvo}
+{
+ name=Datenschutz-Grundverordnung,
+ description={
+ (DSGVO) ist eine im europäischen Wirtschaftsraum
+ geltende Verordnung. Sie sorgt für eine Reglementierung bei der
+ Verarbeitung personenbezogener Daten. Unter anderem muss einsehbar sein,
+ welche Daten von Nutzern erhoben werden. Außerdem muss für einen Nutzer
+ die Möglichkeit bestehen, seine erhobenen Daten abrufen zu können}
+}
+
+\newglossaryentry{push-pull}
+{
+ name=Push und Pull,
+ description={
+ sind Methoden, um Daten auszutauschen. Bei der Pull-Methode
+ stellt Akteur A einem Akteur B eine Anfrage auf Daten und erhält diese
+ als Antwort. Damit Akteur A und B immer auf dem selben Stand sind, muss
+ Akteur A chronisch Anfragen an Akteur B stellen. Im Gegensatz dazu steht
+ die Push-Methode, bei der Akteur B den Akteuren mitteilt, dass er neue
+ Änderungen hat. Dafür muss Akteur B allerdings wissen mit welchen
+ anderen Akteuren er in Verbindung steht und diese Verbindung aufrecht
+ erhalten}
+}
+
+\newglossaryentry{ui-lib}
+{
+ name=UI-Bibliothek,
+ plural=UI-Bibliotheken,
+ description={
+ kümmert sich um das Layout einer Webseite. Dabei unterscheidet man
+ zwischen Design-Bibliotheken (wie Bootstrap), welche fertige
+ UI-Komponenten bereitstellen, und Layout-Bibliotheken (wie Vue oder
+ React.js), welche die Komponenten basierend auf Daten dynamisch
+ anzeigen}
+}
+
+\newglossaryentry{responsive}
+{
+ name=Responsive,
+ description={
+ Design ist ein Design-Prinzip für Webseiten, bei dem die selbe Webseite ihre
+ Komponenten dynamisch der Bildschirmbreite anpasst}
+}
+
+\newglossaryentry{pseudoprotocol}
+{
+ name=Pseudoprotokoll,
+ description={
+ ist ein URL-Schema, auf das Webseiten hören können, wenn sie sich das
+ URL-Schema im Browser anmelden. Bekannt Pseudoprotokolle sind:
+ ,,mailto:'', ,,tel:'' oder ,,irc:''}
+}
+
+\newglossaryentry{dashboard}
+{
+ name=Dashboard,
+ description={
+ ist die erste Seite auf der man landet, wenn man angemeldet ist}
+}
+
+\newglossaryentry{abo}
+{
+ name=Abonnement,
+ description={
+ ist ein abonnierter Podcast}
+}
+
+\newglossaryentry{discovery}
+{
+ name=Discovery,
+ description={
+ ist ein Feature der Gpodder-API, welches dem Nutzer eine Reihe von
+ Podcasts zum abonnieren anbietet}
+}
+
+\newglossaryentry{session-token}
+{
+ name=Session-Token,
+ description={
+ ist ein Wort, dass vom Client gespeichert wird solange der Nutzer
+ eingeloggt ist und bei jeder Anfrage an den Server mitgeschickt wird.
+ Der Server kann den Session-Token einem Nutzer zuordnen und so mit
+ nutzerspezifischen Daten antworten}
+}
+
+\newglossaryentry{cookie}
+{
+ name=Cookie,
+ description={
+ ist ein kleiner webseitenspezifischer Speicher im Browser, welcher vom
+ Server und von der Webseite gesetzt werden kann und bei jeder weiteren
+ Anfrage an den Server mitgesendet wird. Cookies bleiben entweder
+ temporär im Browserspeicher, bis der Browser geschlossen wird oder
+ permanent, bis ein optionales Verfallsdatum erreicht ist}
+}
+
+\newglossaryentry{uiComponent}
+{
+ name=UI-Komponente,
+ plural=UI-Komponenten,
+ description={
+ In Vue.js werden die grafischen Elemente einer Webseite in einzelne
+ Komponenten zerteilt.
+ Diese reagieren automatisch auf Änderungen und können ohne Neuladen
+ der Seite ihr Aussehen verändern und somit Änderungen direkt anzeigen}
+}
+
+\newglossaryentry{spring}
+{
+ name=Spring,
+ description={
+ Ein Java-Framework, welches die Entwicklung von Web-Applikationen erleichtert.
+ Dazu wird eine Reihe von Werkzeugsets zur Verfügung gestellt.
+ Unter anderem sind das Spring Web für das Erstellen von Webanwendungen,
+ Spring Security für die Verwaltung von Benutzerauthentifizierungen und
+ Spring Data JPA für die Arbeit mit relationalen Datenbanken
+ }
+}
+
+\newglossaryentry{api}
+{
+ name=API,
+ plural=APIs,
+ description={
+ Eine Schnittstelle, welche es ermöglicht auf Funktionalitäten einer Anwendung
+ zuzugreifen. APIs für Webanwendungen heißen WebAPIs.
+ Ein Beispiel für eine WebAPI ist die REST-API
+ }
+}
+
+\newglossaryentry{business}
+{
+ name=Geschäftslogik,
+ description={
+ Eine Schicht in der Anwendungsentwicklung, in der die Art und Weise, wie das
+ Programm auf Eingaben reagiert, wie Daten verarbeitet und wie sie gespeichert
+ werden sollen, festgelegt ist
+ }
+}
+
+\newglossaryentry{solid}
+{
+ name=SOLID,
+ description={
+ Eine Sammlung an Prinzipien, welche zu gutem objektorientierten Design führen soll.
+ Jedes Prinzip steht für einen Buchstaben in SOLID:
+ \textbf{S}ingle-Responsibility Prinzip,
+ \textbf{O}pen-Closed Prinzip,
+ \textbf{L}iskovsches Substitutionsprinzip,
+ \textbf{I}nterface Segregation Prinzip und
+ \textbf{D}ependency Inversion Prinzip
+ }
+}
+
+\newglossaryentry{crud}
+{
+ name=CRUD,
+ description={
+ CRUD steht für \textbf{C}reate, \textbf{R}ead, \textbf{U}pdate und \textbf{D}elete.
+ Hierbei handelt es sich um die grundlegenden Funktionen einer Anwendung,
+ die mit einer Datenbank arbeitet.
+ Hierbei können Daten angelegt, abgerufen, aktualisiert und gelöscht werden.
+ Auch in Web-Applikationen ist CRUD mit HTTP über die Anfragen POST, GET, PUT und DELETE
+ vertreten
+ }
+}
+
+\newglossaryentry{SQL}
+{
+ name=SQL,
+ description={
+ SQL (Structured Query Language) ist eine Sprache, die einen strukturierten Zugriff auf Datenbanken ermöglicht.
+ Daten können hierbei hinzugefügt, abgefragt, geändert und gelöscht werden.
+ Das besondere hierbei ist der strukturierte Zugriff auf Daten, indem explizit Daten mit bestimmten Kriterien und
+ Relationen ausgewählt und bearbeitet werden können.
+ SQL wird fast von allen verbreiteten Datenbanksystemen unterstützt
+ }
+}
+
+\newglossaryentry{Base64}
+{
+ name=Base64,
+ description={
+ Mithilfe von Base64 können 8-Bit-Binärdaten in eine ASCII-Zeichenkette
+ kodiert werden. So werden zum Beispiel E-Mail-Anhänge versendet
+ }
+}
+
+\newglossaryentry{JSONP}
+{
+ name=JSONP,
+ description={
+ JSONP ermöglicht die Übertragung von JSON-Daten zwischen verschiedenen Domains.
+ Dies wäre durch die Same-Origin-Policy nicht möglich.
+ JSONP nutzt allerdings die Tatsache aus,
+ dass sich Skripte domainübergreifend übertragen lassen.
+ Dazu werden die JSON-Daten als Argument einer übergebenen Funktion über
+ ein Skript-Element eingebunden
+ }
+}
diff --git a/10-entwurfsheft/sections/structure.tex b/10-entwurfsheft/sections/structure.tex
new file mode 100644
index 0000000..2a6ecb3
--- /dev/null
+++ b/10-entwurfsheft/sections/structure.tex
@@ -0,0 +1,104 @@
+\section{Entwurfsmuster und Techniken}
+
+\subsection{Entwurfsmuster}
+
+\subsubsection{Dependency Injection}
+
+Die Dependency Injection (dt. Abhängigkeitsinjektion) ist ein Entwurfsmuster, welches die Abhängigkeiten von Objekten bestimmt und an einem zentralen Ort speichert sowie verwaltet.
+Sollte ein Objekt also von einem anderen Objekt abhängig sein, so wird an diesem zentralen Ort nach der Abhängigkeit gesucht.
+Ist die Abhängigkeit vorhanden, so wird dieses Objekt dann an dem benötigten Ort eingesetzt (injiziert).
+Dies geschieht während der Laufzeit.
+Der zentrale Ort, an dem die Abhängigkeiten gespeichert werden, wird meist von einem Framework verwaltet.
+
+Im Falle dieses Projekts ist \Gls{spring} das Framework und der \Gls{spring} Container der zentrale Ort, an dem die Abhängigkeiten gespeichert werden.
+Der Vorteil dieses Entwurfsmusters ist, dass Objekte von anderen Objekten abgekoppelt werden, sprich: Das Objekt mit der Abhängigkeit muss nicht mehr von der expliziten Klasse Kenntnis haben und es kann nur mit Interfaces gearbeitet werden, was in den \Gls{solid}-Kriterien das D für Dependency Inversion erfüllt.
+Ein weiterer Vorteil ist, dass die Abhängigkeiten innerhalb einer Konfigurationsdatei definiert werden können.
+Sprich: Man kann mehrere Implementierungen besitzen, die alle das gleiche Interface implementieren und kann in der Konfigurationsdatei angeben, welche Implementierung gewählt werden soll.
+
+\subsubsection{Data Access Object (DAO)}
+\label{DAO_Pattern}
+
+Das Data Access Object (kurz: DAO, dt: Datenzugriffsobjekt) ist ein Entwurfsmuster, das eingesetzt wird um den Zugriff auf \Gls{db}en zu vereinfachen und die \Gls{business} von der Datenzugriffslogik zu trennen.
+Dazu gibt es zwei Komponenten: das DAO-Interface und die DAO-Implementierung.
+
+Das DAO-Interface wird von allen DAO-Implementierungen implementiert und bietet alle Datenzugriffsfunktionen an, auf die die \Gls{business} zugreift.
+Die DAO-Implementierung ist eine Klasse, die das DAO-Interface implementiert und den tatsächlichen Zugriff auf die \Gls{db} ausführt.
+
+Der Vorteil dieses Entwurfsmusters ist es mehrere Implementierungen desselben DAO-Interfaces zu besitzen.
+In Kombination mit der Dependency Injection ist es einfach zwischen den Implementierungen für verschiedene \Gls{db}en (bspw. MariaDB und My\Gls{SQL}) zu wechseln.
+Damit wird der Datenzugriff flexibler.
+Im Falle dieses Projekts wird eine DAO-Implementierung für MariaDB verwendet.
+
+Ein weiterer Vorteil ist die zuvor angesprochene Trennung der Geschäfts- und Datenzugriffslogik.
+Da sich die \Gls{business} und Datenzugriffslogik mithilfe dieses Musters in verschiedenen Komponenten befinden, sind diese voneinander getrennt und es wird einfacher die jeweiligen Implementierungen zu testen.
+Gleichzeitig verbessert sich damit die Wiederverwendbarkeit des Codes, da die DAO-Implementierungen in anderen Programmen, die mit demselben DAO-Interface arbeiten, eingesetzt werden können.
+
+Damit erfüllt das DAO-Muster die Kriterien S und O der \Gls{solid}-Kriterien.
+Das Single-Responsibility Prinzip wird erfüllt, da der Zugriff auf die \Gls{db} von der \Gls{business} getrennt wird und damit die DAO-Implementierung alleine für den Zugriff auf die \Gls{db} verantwortlich ist.
+Das Open/Closed Prinzip wird erfüllt, da die DAO-Implementierung erweitert werden kann, ohne dass der Rest vom Projekt betroffen wird und außerhalb der Klasse nur mit dem DAO-Interface gearbeitet werden kann.
+
+\subsection{Techniken}
+
+\subsubsection{JSON Web Token}
+
+\Gls{json} Web Token (JWT) ist ein offener Standard der in RFC 7519 definiert wird.
+Mit einem JWT ist es möglich Informationen sicher in einem kodierten \Gls{json} Objekt zu übertragen.
+Die Sicherheit der Daten wird dabei durch eine digitale Signatur gewährleistet.
+
+Ein JWT besteht aus drei durch Punkte ('.') voneinander getrennten Teilen:
+\texttt{Header}, \texttt{Payload} und \texttt{Signatur}.
+Der \texttt{Header} besteht dabei typischerweise aus der Information um welchen Typ von Token es sich handelt, also einen JWT,
+und der Information welcher Signierungs-Algorithmus verwendet wird.
+Diese Informationen werden \Gls{Base64} kodiert und bilden den ersten Teil des JWT.
+
+Im \texttt{Payload} Teil werden die eigentlichen Informationen \Gls{Base64} kodiert.
+
+Die \texttt{Signatur} ergibt sich durch die mit einem Punkt voneinander getrennten Kodierungen des \texttt{Headers} und
+des \texttt{Payload}-Teils. Diese Zeichenkette wird dann mit einem geheimen Schlüssel
+durch den im \texttt{Header} angegebenen Signierungs-Algorithmus signiert.
+JWT werden einmalig vom Server erzeugt und beim Client gehalten. Daher ist es
+nicht notwendig wie z.B. bei \gls{cookie} basierten Sessions, eine Liste mit gültigen Sessions auf dem Server zu verwalten, was bei mehreren Servern schwierig ist.
+
+In diesem Projekt werden JWT zur Verifikation der E-Mail-Adresse eines Benutzers und zur Überprüfung der Autorisation bei Anfragen an den Server verwendet.
+
+Zur Bestätigung der E-Mail-Adresse speichert der Server die zur Verifikation des
+Benutzers benötigten Daten in einem JWT. Dieser wird in der URL des Verifikations-Links kodiert. Wenn der Benutzer den Verifikations-Link anklickt,
+wird der JWT an den Server weitergeleitet. Dieser überprüft die Signatur des JWT ihn mit seinem geheimen Schlüssel
+und kann so die Verifikation der E-Mail-Adresse abschließen.
+
+Bei dem Login-Vorgang sendet der Client zuerst seine Anmeldedaten (Benutername und Passwort), um sich zu authentifizieren.
+Der Server überprüft die Angaben, generiert einen JWT und gibt diesen zurück, falls die Daten korrekt sind.
+Bei späteren Anfragen an den Server übermittelt der Client diesen JWT. Der Server überprüft die Validität des JWT und trifft
+basierend darauf die Entscheidung, ob die Anfrage bearbeitet oder abgelehnt wird.
+
+\subsubsection{Objektrelationale Abbildung (Object-relational mapping)}\label{t:orm}
+
+Objektrelationale Abbildung - kurz ORM von der englischen Bezeichnung \enquote{Object-relational mapping} - ist eine Technik der Softwareentwicklung.
+Sie widmet sich dem, mit der persistenten Speicherung von Laufzeit-Objekten zusammenhängenden \enquote{Impedance mismatch} Problem.
+Dieses beschreibt die Diskrepanz zwischen den in der Pogrammier- beziehungsweise \Gls{db}welt vorherrschenden Konzepten - nämlich der objektorientierten Programmierung und relationalen \Gls{db}en.
+So speichern objektorientierte Programmiersprachen Daten und Verhalten in Objekten mit eindeutiger Identität, wobei Zustand und Verhalten hinter einer Schnittstelle verborgen werden.
+Relationale \Gls{db}en hingegen speichern Daten in Tabellen und basieren auf dem mathematischen Konzept der Relationenalgebra.
+
+Objektrelationale Abbildung bietet eine Möglichkeit diese Diskrepanz zu vermindern, indem sie ein Mapping zwischen Objekten und Datenstrukturen relationaler \Gls{db}en herstellt.
+Einem, in einer objektorientierten Programmiersprache geschriebenen, Anwendungsprogramm erscheint dann die verbundene relationale \Gls{db} als objektorientierte \Gls{db}.
+Durch ORM wird also sowohl das Ablegen von Objekten mit Attributen und Methoden in relationale \Gls{db}en, als auch das Erzeugen von solchen Objekten aus entsprechenden Datensätzen ermöglicht.
+Vorteilhaft ist daran außerdem, dass die objektorientierte Programmiersprache nicht erweitert werden muss.
+Des Weiteren existiert für jede Umgebung ausgereifte Software für die Verwendung relationaler \Gls{db}en.
+Allerdings ist der Schritt in Richtung objektorientiertem Ansatz immanent ein Schritt weg von den eigentlichen Stärken relationaler \Gls{db}en.
+
+Der grundlegende Ansatz ist die Abbildung von Klassen auf Tabellen, wobei die Spalten den Attributen und die Zeilen den Objekten der Klasse zugeordnet sind.
+Dabei entspricht der Primärschlüssel der Tabelle der Objektidentität und Objektreferenzen werden mithilfe von zusätzlichen Fremdschlüsseln repräsentiert.
+%Um Vererbung abzubilden gibt es drei grundlegende Möglichkeiten.
+%Erst einmal kann für eine Vererbungshierarchie auch genau eine gemeinsame Tabelle mit allen Attributen verwendet werden, in der ein Diskriminator bestimmt, zu welcher Klasse ein Objekt gehört.
+%Als zweite Option kann pro Unterklasse eine zusätzliche verknüpfte Tabelle eingeführt werden.
+%Letztlich kann auch pro konkreter Klasse eine Tabelle verwendet werden, wobei die Tabelle für die abstrakte Basisklasse entfällt.
+
+Die von diesem Mapping betroffenen Klassen aus dem Model-Paket (\ref{p:model}) des Backends sind User, SubscriptionAction, Subscription, EpisodeAction und \Gls{episode}.
+
+Konkret für dieses Projekt findet ORM als Technik durch die Implementierung der Jakarta Persistence \Gls{api} (JPA) Anwendung.
+Dafür wird das von \Gls{spring} zur Implementierung von JPA-basierten Datenzugriffsschichten bereitgestellte Modul \Gls{spring} Data JPA genutzt.
+Als JPA-Implementation wiederum wird das Open-Source-Persistenz- und ORM-Framework Hibernate für \Gls{java} verwendet.
+Dabei erfolgen Abfragen der persistierten Objekte über die Abfragesprache Jakarta Persistence Query Language (JPQL), welche dann mittels JDBC in den entsprechen \Gls{SQL}-Dialekt für MariaDB übersetzt.
+%Hier sei angemerkt, dass JPQL eine Untermenge der Hibernate Query Language (HQL) ist.
+
+\newpage
diff --git a/10-entwurfsheft/tikz-uml.sty b/10-entwurfsheft/tikz-uml.sty
new file mode 100644
index 0000000..c6e8e0d
--- /dev/null
+++ b/10-entwurfsheft/tikz-uml.sty
@@ -0,0 +1,5377 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Start of tikz-uml.sty
+%
+% Some macros for UML Diagrams.
+% Home page of project :
+% Author: Nicolas Kielbasiewicz
+% Style from :
+% Fixed by Nicolas Kielbasiewicz (nicolas.kielbasiewicz@ensta-paristech.fr) in march 2016 to compile with pgf 3.00
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+\NeedsTeXFormat{LaTeX2e}[1995/12/01]%
+\ProvidesPackage{tikz-uml}[2011/01/26]%
+%
+\RequirePackage{etoolbox}%
+\RequirePackage{ifthen}%
+\RequirePackage{tikz}%
+\RequirePackage{xstring}%
+\RequirePackage{calc}%
+\RequirePackage{pgfopts}%
+\usetikzlibrary{backgrounds,arrows,shapes,fit,shadows,decorations.markings}%
+%
+\def\tikzumlPackageLayersNum{3}%
+\pgfkeys{/tikzuml/options/.cd, packageLayers/.initial=3}%
+\pgfkeys{/tikzuml/options/.cd, packageLayers/.store in=\tikzumlPackageLayersNum}%
+\def\tikzumlStateLayersNum{3}%
+\pgfkeys{/tikzuml/options/.cd, stateLayers/.initial=3}%
+\pgfkeys{/tikzuml/options/.cd, stateLayers/.store in=\tikzumlStateLayersNum}%
+\def\tikzumlFragmentLayersNum{3}%
+\pgfkeys{/tikzuml/options/.cd, fragmentLayers/.initial=3}%
+\pgfkeys{/tikzuml/options/.cd, fragmentLayers/.store in=\tikzumlFragmentLayersNum}%
+\def\tikzumlComponentLayersNum{3}%
+\pgfkeys{/tikzuml/options/.cd, componentLayers/.initial=3}%
+\pgfkeys{/tikzuml/options/.cd, componentLayers/.store in=\tikzumlComponentLayersNum}%
+%
+\ProcessPgfOptions{/tikzuml/options}%
+%
+\def\pgfsetlayersArg{background}%
+\pgfdeclarelayer{background}%
+\newcounter{tikzumlPackageLayers}%
+\loop \pgfdeclarelayer{package\thetikzumlPackageLayers}%
+ \xdef\pgfsetlayersArg{\pgfsetlayersArg,package\thetikzumlPackageLayers}%
+ \ifnum\tikzumlPackageLayersNum>\thetikzumlPackageLayers%
+ \stepcounter{tikzumlPackageLayers}%
+\repeat%
+%
+\newcounter{tikzumlFragmentLayers}%
+\loop \pgfdeclarelayer{fragment\thetikzumlFragmentLayers}%
+ \xdef\pgfsetlayersArg{\pgfsetlayersArg,fragment\thetikzumlFragmentLayers}%
+ \ifnum\tikzumlFragmentLayersNum>\thetikzumlFragmentLayers%
+ \stepcounter{tikzumlFragmentLayers}%
+\repeat%
+%
+\newcounter{tikzumlStateLayers}%
+\loop \pgfdeclarelayer{state\thetikzumlStateLayers}%
+ \xdef\pgfsetlayersArg{\pgfsetlayersArg,state\thetikzumlStateLayers}%
+ \ifnum\tikzumlStateLayersNum>\thetikzumlStateLayers%
+ \stepcounter{tikzumlStateLayers}%
+\repeat%
+%
+\newcounter{tikzumlComponentLayers}%
+\loop \pgfdeclarelayer{component\thetikzumlComponentLayers}%
+ \xdef\pgfsetlayersArg{\pgfsetlayersArg,component\thetikzumlComponentLayers}%
+ \ifnum\tikzumlComponentLayersNum>\thetikzumlComponentLayers%
+ \stepcounter{tikzumlComponentLayers}%
+\repeat%
+%
+\pgfdeclarelayer{lifelines}%
+\pgfdeclarelayer{activity}%
+\pgfdeclarelayer{connections}%
+\xdef\pgfsetlayersArg{\pgfsetlayersArg,lifelines,activity,connections,main}%
+\pgfsetlayers{\pgfsetlayersArg}%
+%
+\pgfkeys{/tikzuml/.cd, text/.initial=black, draw/.initial=black, font/.initial=\small,%
+ x/.initial=0, y/.initial=0,%
+ package type/.initial=tikzumlEmpty, fill package/.initial=blue!20,%
+ class width/.initial=10ex, simple interface width/.initial=4ex, class type/.initial=class, fill class/.initial=yellow!20, fill template/.initial=yellow!2,%
+ narynode width/.initial=6ex,%
+ relation geometry/.initial=--, relation angle1/.initial=-30, relation angle2/.initial=30, relation loopsize/.initial=3em, relation weight/.initial=0.5, relation pos1/.initial=0.2, relation pos2/.initial=0.8, relation pos stereo/.initial=0.5,%
+ note width/.initial=3cm, fill note/.initial=green!20,%
+ fill system/.initial=white,%
+ fill usecase/.initial=blue!20,%
+ actor below/.initial=0.5cm,%
+ state join width/.initial=3ex,%
+ state decision width/.initial=3ex,%
+ state initial width/.initial=5ex,%
+ state final width/.initial=5.5ex,%
+ state enter width/.initial=5ex,%
+ state exit width/.initial=5ex,%
+ state end width/.initial=5ex,%
+ state history width/.initial=5ex,%
+ state deep history width/.initial=5ex,%
+ state width/.initial=8ex, fill state/.initial=yellow!20,%
+ object stereo/.initial=object, fill object/.initial=yellow!20,%
+ call dt/.initial=tikzumlEmpty, call padding/.initial=2, call type/.initial=synchron, fill call/.initial=white,%
+ fragment type/.initial=opt, fragment inner xsep/.initial=1, fragment inner ysep/.initial=1, fill fragment/.initial= none,%
+ create call dt/.initial=4,%
+ component width/.initial=8ex, fill component/.initial= yellow!20,%
+ required interface distance/.initial=2.5cm, required interface width/.initial=1em, required interface padding/.initial=1cm,%
+ provided interface distance/.initial=3cm, provided interface width/.initial=1em, provided interface padding/.initial=1cm,%
+ port width/.initial=1ex, fill port/.initial= yellow!20,%
+ fill assembly connector/.initial= white,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \errmessage{TIKZUML ERROR : in tikzuml global, invalid option \keyname}%
+ }%
+}%
+%
+\pgfkeys{/tikzuml/.cd, text/.get=\tikzumlDefaultTextColor, draw/.get=\tikzumlDefaultDrawColor, font/.get=\tikzumlDefaultFont,%
+ x/.get=\tikzumlDefaultX, y/.get=\tikzumlDefaultY,%
+ package type/.get=\tikzumlPackageDefaultType, fill package/.get=\tikzumlPackageDefaultFillColor,%
+ class width/.get=\tikzumlClassDefaultWidth, simple interface width/.get=\tikzumlSimpleInterfaceDefaultWidth, class type/.get=\tikzumlClassDefaultType, fill class/.get=\tikzumlClassDefaultFillColor, fill template/.get=\tikzumlClassTemplateFillColorDefaultFillColor,%
+ narynode width/.get=\tikzumlNaryNodeDefaultWidth,%
+ relation geometry/.get=\tikzumlRelationDefaultGeometry, relation angle1/.get=\tikzumlRelationDefaultAngleO, relation angle2/.get=\tikzumlRelationDefaultAngleT, relation loopsize/.get=\tikzumlRelationDefaultLoopSize, relation weight/.get=\tikzumlRelationDefaultWeight, relation pos1/.get=\tikzumlRelationDefaultPosO, relation pos2/.get=\tikzumlRelationDefaultPosT, relation pos stereo/.get=\tikzumlRelationDefaultPosStereo,%
+ note width/.get=\tikzumlNoteDefaultWidth, fill note/.get=\tikzumlNoteDefaultFillColor,%
+ fill system/.get=\tikzumlSystemDefaultFillColor,%
+ fill usecase/.get=\tikzumlUseCaseDefaultFillColor,%
+ actor below/.get=\tikzumlActorDefaultBelow,%
+ state join width/.get=\tikzumlStateJoinDefaultWidth,%
+ state decision width/.get=\tikzumlStateDecisionDefaultWidth,%
+ state initial width/.get=\tikzumlStateInitialDefaultWidth,%
+ state final width/.get=\tikzumlStateFinalDefaultWidth,%
+ state enter width/.get=\tikzumlStateEnterDefaultWidth,%
+ state exit width/.get=\tikzumlStateExitDefaultWidth,%
+ state end width/.get=\tikzumlStateEndDefaultWidth,%
+ state history width/.get=\tikzumlStateHistoryDefaultWidth,%
+ state deep history width/.get=\tikzumlStateDeepHistoryDefaultWidth,%
+ state width/.get=\tikzumlStateDefaultWidth, fill state/.get=\tikzumlStateDefaultFillColor,%
+ object stereo/.get=\tikzumlObjectDefaultStereo, fill object/.get=\tikzumlObjectDefaultFillColor,%
+ call dt/.get=\tikzumlCallDefaultDT, call padding/.get=\tikzumlCallDefaultPadding, call type/.get=\tikzumlCallDefaultType, fill call/.get=\tikzumlCallDefaultFillColor,%
+ fragment type/.get=\tikzumlFragmentDefaultType, fragment inner xsep/.get=\tikzumlFragmentDefaultXSep, fragment inner ysep/.get=\tikzumlFragmentDefaultYSep, fill fragment/.get=\tikzumlFragmentDefaultFillColor,%
+ create call dt/.get=\tikzumlCreateCallDefaultDT,%
+ component width/.get=\tikzumlComponentDefaultWidth, fill component/.get=\tikzumlComponentDefaultFillColor,%
+ required interface distance/.get=\tikzumlRequiredInterfaceDefaultDistance, required interface width/.get=\tikzumlRequiredInterfaceDefaultWidth, required interface padding/.get=\tikzumlRequiredInterfaceDefaultPadding,%
+ provided interface distance/.get=\tikzumlProvidedInterfaceDefaultDistance, provided interface width/.get=\tikzumlProvidedInterfaceDefaultWidth, provided interface padding/.get=\tikzumlProvidedInterfaceDefaultPadding,%
+ port width/.get=\tikzumlPortDefaultWidth, fill port/.get=\tikzumlPortDefaultFillColor,%
+ fill assembly connector/.get=\tikzumlAssemblyConnectorDefaultFillColor%
+}%
+%
+% utility : change default colors
+\newcommand{\tikzumlset}[1]{%
+ \pgfkeys{/tikzuml/.cd,#1}%
+ \pgfkeys{/tikzuml/.cd, text/.get=\tikzumlDefaultTextColor, draw/.get=\tikzumlDefaultDrawColor, font/.get=\tikzumlDefaultFont,%
+ x/.get=\tikzumlDefaultX, y/.get=\tikzumlDefaultY,%
+ package type/.get=\tikzumlPackageDefaultType, fill package/.get=\tikzumlPackageDefaultFillColor,%
+ class width/.get=\tikzumlClassDefaultWidth, simple interface width/.get=\tikzumlSimpleInterfaceDefaultWidth, class type/.get=\tikzumlClassDefaultType, fill class/.get=\tikzumlClassDefaultFillColor, fill template/.get=\tikzumlClassTemplateFillColorDefaultFillColor,%
+ narynode width/.get=\tikzumlNaryNodeWidth,%
+ relation geometry/.get=\tikzumlRelationDefaultGeometry, relation angle1/.get=\tikzumlRelationDefaultAngleO, relation angle2/.get=\tikzumlRelationDefaultAngleT, relation loopsize/.get=\tikzumlRelationDefaultLoopSize, relation weight/.get=\tikzumlRelationDefaultWeight, relation pos1/.get=\tikzumlRelationDefaultPosO, relation pos2/.get=\tikzumlRelationDefaultPosT, relation pos stereo/.get=\tikzumlRelationDefaultPosStereo,%
+ note width/.get=\tikzumlNoteDefaultWidth, fill note/.get=\tikzumlNoteDefaultFillColor,%
+ fill system/.get=\tikzumlSystemDefaultFillColor,%
+ fill usecase/.get=\tikzumlUseCaseDefaultFillColor,%
+ actor below/.get=\tikzumlActorDefaultBelow,%
+ state join width/.get=\tikzumlStateJoinDefaultWidth,%
+ state decision width/.get=\tikzumlStateDecisionDefaultWidth,%
+ state initial width/.get=\tikzumlStateInitialDefaultWidth,%
+ state final width/.get=\tikzumlStateFinalDefaultWidth,%
+ state enter width/.get=\tikzumlStateEnterDefaultWidth,%
+ state exit width/.get=\tikzumlStateExitDefaultWidth,%
+ state end width/.get=\tikzumlStateEndDefaultWidth,%
+ state history width/.get=\tikzumlStateHistoryDefaultWidth,%
+ state deep history width/.get=\tikzumlStateDeepHistoryDefaultWidth,%
+ state width/.get=\tikzumlStateDefaultWidth, fill state/.get=\tikzumlStateDefaultFillColor,%
+ object stereo/.get=\tikzumlObjectDefaultStereo, fill object/.get=\tikzumlObjectDefaultFillColor,%
+ call dt/.get=\tikzumlCallDefaultDT, call padding/.get=\tikzumlCallDefaultPadding, call type/.get=\tikzumlCallDefaultType, fill call/.get=\tikzumlCallDefaultFillColor,%
+ fragment type/.get=\tikzumlFragmentDefaultType, fragment inner xsep/.get=\tikzumlFragmentDefaultXSep, fragment inner ysep/.get=\tikzumlFragmentDefaultYSep, fill fragment/.get=\tikzumlFragmentDefaultFillColor,%
+ create call dt/.get=\tikzumlCreateCallDT,%
+ component width/.get=\tikzumlComponentDefaultWidth, fill component/.get=\tikzumlComponentDefaultFillColor,%
+ required interface distance/.get=\tikzumlRequiredInterfaceDefaultDistance, required interface width/.get=\tikzumlRequiredInterfaceDefaultWidth, required interface padding/.get=\tikzumlRequiredInterfaceDefaultPadding,%
+ provided interface distance/.get=\tikzumlProvidedInterfaceDefaultDistance, provided interface width/.get=\tikzumlProvidedInterfaceDefaultWidth, provided interface padding/.get=\tikzumlProvidedInterfaceDefaultPadding,%
+ port width/.get=\tikzumlPortDefaultWidth, fill port/.get=\tikzumlPortDefaultFillColor,%
+ fill assembly connector/.get=\tikzumlAssemblyConnectorDefaultFillColor%
+ }%
+}%
+%
+% define a point
+% arg : node/coordinates of the point
+\newcommand{\umlpoint}[1]{%
+ \begin{pgfonlayer}{connections}%
+ \node[tikzuml control nodes style] at (#1) {};%
+ \end{pgfonlayer}%
+}%
+%
+\newcommand{\tikzumlskipescape}[3][_]{%
+\begingroup%
+ \def\_{#1}\edef\x{\endgroup%
+ \def\noexpand\csname #3\endcsname{#2}}\x%
+}%
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% class diagrams %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+\pgfkeys{/tikzuml/relation/.cd, attr1/.style args={#1|#2}{arg1=#1, mult1=#2},%
+ attr2/.style args={#1|#2}{arg2=#1, mult2=#2},%
+ attr/.style args={#1|#2}{arg=#1, mult=#2},%
+ recursive/.style args={#1|#2|#3}{angle1=#1, angle2=#2, loopsize=#3},%
+ anchors/.style args={#1 and #2}{anchor1=#1, anchor2=#2},%
+ recursive direction/.style args={#1 to #2}{recursive direction start=#1, recursive direction end=#2}%
+}%
+%
+\pgfkeys{/tikzuml/note/.cd, anchors/.style args={#1 and #2}{anchor1=#1, anchor2=#2}}%
+%
+\tikzstyle{tikzuml simpleclass style}=[rectangle, minimum height=2em, node distance=2em]%
+\tikzstyle{tikzuml simpleinterface style}=[circle, minimum height=1em, node distance=1em]%
+\tikzstyle{tikzuml class style}=[rectangle split, rectangle split parts=3, rectangle split part align={center, left, left}, minimum height=2em, node distance=2em]%
+\tikzstyle{tikzuml narynode style}=[diamond]%
+\tikzstyle{tikzuml template style}=[dashed, inner ysep=0.5em, inner xsep=1ex]%
+\tikzstyle{tikzuml control nodes style}=[fill=black, inner sep=1.5pt, circle]%
+%
+\tikzstyle{tikzuml association style}=[color=\tikzumlDefaultDrawColor, -]%
+\tikzstyle{tikzuml bidirectional association style}=[color=\tikzumlDefaultDrawColor, angle45-angle45]%
+\tikzstyle{tikzuml unidirectional association style}=[color=\tikzumlDefaultDrawColor, -angle 45]%
+\tikzstyle{tikzuml aggregation style}=[color=\tikzumlDefaultDrawColor, open diamond-]%
+\tikzstyle{tikzuml unidirectional aggregation style}=[color=\tikzumlDefaultDrawColor, open diamond-angle 45]%
+\tikzstyle{tikzuml composition style}=[color=\tikzumlDefaultDrawColor, diamond-]%
+\tikzstyle{tikzuml unidirectional composition style}=[color=\tikzumlDefaultDrawColor, diamond-angle 45]%
+\tikzstyle{tikzuml nesting style}=[color=\tikzumlDefaultDrawColor]%
+\tikzstyle{tikzuml dependency style}=[color=\tikzumlDefaultDrawColor, -angle 45, dashed]%
+\tikzstyle{tikzuml import style}=[color=\tikzumlDefaultDrawColor, -angle 45, dashed]%
+\tikzstyle{tikzuml inherit style}=[color=\tikzumlDefaultDrawColor, -open triangle 45]%
+\tikzstyle{tikzuml implements style}=[color=\tikzumlDefaultDrawColor, -open triangle 45, dashed]%
+%
+\pgfkeys{/tikzuml/assemblyconnectorrelation/.cd, anchors/.style args={#1 and #2}{anchor1=#1, anchor2=#2}}%
+%
+\newcounter{tikzumlPackageClassNum}%
+\newcounter{tikzumlPackageSubPackageNum}%
+\newcounter{tikzumlRelationNum}%
+\setcounter{tikzumlRelationNum}{1}%
+\newcounter{tikzumlNoteNum}%
+\setcounter{tikzumlNoteNum}{1}%
+%
+\newcounter{pos}%
+\newcounter{posT}%
+\newcounter{posStereo}%
+%
+\newcounter{tikzumlPackageLevel}%
+\setcounter{tikzumlPackageLevel}{0}%
+%
+\newif\iftikzumlpackageSimpleStyle%
+\newif\iftikzumlclassSimpleStyle%
+\newif\iftikzumlclassCircleShape%
+\newif\iftikzumlpackageWithoutCoords%
+\newif\iftikzumlclassWithoutCoords%
+\newif\iftikzumlassocclassWithoutCoords%
+\newif\iftikzumlnoteWithoutCoords%
+%
+% define a uml package
+% arg : package name
+% optional : x, y: coordinates of the package
+% type: stereotype of the package
+% name: name of the package node
+% draw, fill, text: colors
+% style: to manage every default TikZ option
+% no coords: to tell that the package position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newenvironment{umlpackage}[2][]{%
+ \pgfkeys{/tikzuml/package/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, style/.style={},%
+ name/.initial=tikzumlEmpty, type/.initial=\tikzumlPackageDefaultType, draw/.initial=\tikzumlDefaultDrawColor,%
+ fill/.initial=\tikzumlPackageDefaultFillColor, text/.initial=\tikzumlDefaultTextColor,%
+ no coords/.is if=tikzumlpackageWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/package/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/package/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/package/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlpackage, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/package/.cd, #1}%
+ \pgfkeys{/tikzuml/package/.cd, x/.get=\tikzumlPackageXShift, y/.get=\tikzumlPackageYShift, name/.get=\tikzumlPackageName, type/.get=\tikzumlPackageTypeTmp,%
+ draw/.get=\tikzumlPackageDrawColor, fill/.get=\tikzumlPackageFillColor,%
+ text/.get=\tikzumlPackageTextColor%
+ }%
+ %
+
+ %
+ \ifthenelse{\equal{\tikzumlPackageTypeTmp}{tikzumlEmpty}}{%
+ \def\tikzumlPackageType{}%
+ }{%
+ \expandafter\def\expandafter\tikzumlPackageType\expandafter{$\ll$\tikzumlPackageTypeTmp$\gg$ \\}%
+ }%
+ %
+ \ifnum\thetikzumlPackageLevel>0%
+ \let\tikzumlPackage@nameold\tikzumlPackage@fitname%
+ \def\tikzumlPackage@name{#2}%
+ \begingroup%
+ \def\_{@}\edef\x{\endgroup%
+ \def\noexpand\tikzumlPackage@fitname{\tikzumlPackage@name}}\x%
+ \let\tikzumlPackage@parentold\tikzumlPackage@parent%
+ \edef\tikzumlPackage@parent{\tikzumlPackage@parentold @@\tikzumlPackage@nameold}%
+ \else%
+ \def\tikzumlPackage@parent{}%
+ \def\tikzumlPackage@name{#2}%
+ \begingroup%
+ \def\_{@}\edef\x{\endgroup%
+ \def\noexpand\tikzumlPackage@fitname{\tikzumlPackage@name}}\x%
+ \fi%
+ %
+ \let\tikzumlPackage@nodeNameold\tikzumlPackage@nodeName%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlPackage@nodeName{\tikzumlPackage@name}}\x%
+ %
+ \ifthenelse{\equal{\tikzumlPackageName}{tikzumlEmpty}}{}{%
+ \def\tikzumlPackage@nodeName{\tikzumlPackageName}%
+ }%
+ %
+ \StrSubstitute{\tikzumlPackage@nodeName}{.}{@POINT@}{\tikzumlPackage@nodeName}%
+ %
+ \expandafter\gdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{}%
+ %
+ \setcounter{tikzumlPackageClassNum}{0}%
+ \setcounter{tikzumlPackageSubPackageNum}{0}%
+ \stepcounter{tikzumlPackageLevel}%
+ %
+ \begin{scope}[xshift=\tikzumlPackageXShift cm, yshift=\tikzumlPackageYShift cm]%
+}{%
+ \addtocounter{tikzumlPackageLevel}{-1}%
+ \begin{pgfonlayer}{package\thetikzumlPackageLevel}%
+ %
+ % if contains no class, and not simple, one define a fictive node to enable the fit option
+ \ifnum\c@tikzumlPackageClassNum=0%
+ \ifnum\c@tikzumlPackageSubPackageNum=0%
+ \iftikzumlpackageWithoutCoords%
+ \node[inner sep=1.5ex, /tikzuml/package/style] (\tikzumlPackage@nodeName-root) {\phantom{\tikzumlPackage@nodeName}};%
+ \else%
+ \node[inner sep=1.5ex, /tikzuml/package/style] (\tikzumlPackage@nodeName-root) at (0,0) {\phantom{\tikzumlPackage@nodeName}};%
+ \fi%
+ \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{(\tikzumlPackage@nodeName-root)}%
+ \fi%
+ \fi%
+ %
+ \ifnum\c@tikzumlPackageLevel>0%
+ \def\tikzumlPackageFitTmp{\csname tikzumlPackageFit\tikzumlPackage@parent\endcsname}%
+ \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent\endcsname{\tikzumlPackageFitTmp (\tikzumlPackage@nodeName) (\tikzumlPackage@nodeName-caption)}%
+ \stepcounter{tikzumlPackageSubPackageNum}%
+ \fi%
+ %
+ \node[draw=\tikzumlPackageDrawColor, fill=\tikzumlPackageFillColor, text=\tikzumlPackageTextColor, font=\tikzumlDefaultFont, inner sep=1.5ex, /tikzuml/package/style, fit = \csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname] (\tikzumlPackage@nodeName) {};%
+ \node[draw=\tikzumlPackageDrawColor, fill=\tikzumlPackageFillColor, text=\tikzumlPackageTextColor, font=\tikzumlDefaultFont, minimum height=1.5em, outer ysep=-0.3, anchor=south west] (\tikzumlPackage@nodeName-caption) at (\tikzumlPackage@nodeName.north west) {\begin{tabular}{c} \tikzumlPackageType \textbf{\tikzumlPackage@name}\end{tabular}};%
+ \end{pgfonlayer}%
+ \end{scope}%
+}%
+%
+% shortcut to define an empty package
+\newcommand{\umlemptypackage}[2][]{\begin{umlpackage}[#1]{#2} \end{umlpackage}}%
+%
+% define a uml class
+% args : name of the class
+% attributes of the class
+% operations of the class
+% optional : x, y: coordinates of the class
+% width: of the class node
+% type: type of class (class, interface, typedef, enum)
+% tags: tagged values of class
+% template: template parameters
+% simple: if used, class is empty and drawn with a rectangle
+% circle: if used with simple, class is empty and drawn with a circle
+% draw, fill, fill template, and text: colors
+% style: to manage every default TikZ option
+% no coords: to tell that the class position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlclass}[4][]{%
+ \pgfkeys{/tikzuml/class/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlClassDefaultWidth, type/.initial=\tikzumlClassDefaultType,%
+ tags/.initial={}, style/.style={},%
+ template/.initial={}, name/.initial=tikzumlEmpty,%
+ draw/.initial=\tikzumlDefaultDrawColor,%
+ fill template/.initial=\tikzumlClassTemplateFillColorDefaultFillColor,%
+ fill/.initial=\tikzumlClassDefaultFillColor,%
+ text/.initial=\tikzumlDefaultTextColor,%
+ simple/.is if=tikzumlclassSimpleStyle, circle/.is if=tikzumlclassCircleShape, no coords/.is if=tikzumlclassWithoutCoords,%
+ simple=false, circle=false, no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/class/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/class/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/class/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlclass, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/class/.cd,#1}%
+ %
+ \iftikzumlclassSimpleStyle%
+ \iftikzumlclassCircleShape%
+ \pgfkeys{/tikzuml/class/.cd, width/.initial=\tikzumlSimpleInterfaceDefaultWidth}%
+ \fi%
+ \fi%
+ %
+ \pgfkeys{/tikzuml/class/.cd, x/.get=\tikzumlClassX, y/.get=\tikzumlClassY, width/.get=\tikzumlClassMinimumWidth,%
+ type/.get=\tikzumlClassTypeTmp, tags/.get=\tikzumlClassTagsTmp, template/.get=\tikzumlClassTemplateFillColorParam,%
+ name/.get=\tikzumlClassName,%
+ draw/.get=\tikzumlClassDrawColor, fill/.get=\tikzumlClassFillColor,%
+ text/.get=\tikzumlClassTextColor, fill template/.get=\tikzumlClassTemplateFillColor%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlClassTypeTmp}{class}\OR\equal{\tikzumlClassTypeTmp}{abstract}}{%
+ \def\tikzumlClassType{}%
+ }{%
+ \expandafter\def\expandafter\tikzumlClassType\expandafter{$\ll$\tikzumlClassTypeTmp$\gg$ \\}%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlClassTagsTmp}{}}{%
+ \def\tikzumlClassTags{}%
+ }{%
+ \def\tikzumlClassTags{\\ \{\tikzumlClassTagsTmp\}}%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlClassTemplateFillColorParam}{}}{%
+ \def\tikzumlClassVPadding{}%
+ \def\tikzumlClassHPadding{}%
+ }{%
+ \def\tikzumlClassVPadding{\vspace{0.1em} \\}%
+ \def\tikzumlClassHPadding{\hspace{0.5ex} $ $}%
+ }%
+ %
+ \def\tikzumlClassName{#2}%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlClassNodeName{\tikzumlClassName}}\x%
+ %
+ \ifthenelse{\equal{\tikzumlClassName}{tikzumlEmpty}}{}{%
+ \def\tikzumlClassNodeName{\tikzumlClassName}%
+ }%
+ %
+ \StrSubstitute{\tikzumlClassNodeName}{:}{@COLON@}[\tikzumlClassNodeName]%
+ \StrSubstitute{\tikzumlClassNodeName}{\_}{@UNDERSCORE@}[\tikzumlClassNodeName]%
+ %
+ \ifthenelse{\equal{\tikzumlClassTypeTmp}{abstract}}{%
+ \let\tikzumlClassNameOld\tikzumlClassName%
+ \def\tikzumlClassName{{\it \tikzumlClassNameOld}}%
+ }{}%
+ %
+ \def\tikzumlClassPos{\tikzumlClassX,\tikzumlClassY}%
+ \def\tikzumlClassAttributes{#3}%
+ \def\tikzumlClassOperations{#4}%
+ %
+ \iftikzumlclassSimpleStyle%
+ \iftikzumlclassWithoutCoords%
+ \iftikzumlclassCircleShape%
+ \node[tikzuml simpleinterface style, draw=\tikzumlClassDrawColor, fill=\tikzumlClassFillColor, text=\tikzumlClassTextColor, font=\tikzumlDefaultFont, minimum width=\tikzumlClassMinimumWidth, /tikzuml/class/style] (\tikzumlClassNodeName) {};%
+ \node[anchor=south] (\tikzumlClassNodeName-label) at (\tikzumlClassNodeName.north) {\begin{tabular}{c}\tikzumlClassVPadding \tikzumlClassType \tikzumlClassHPadding \textbf{\tikzumlClassName} \tikzumlClassHPadding \tikzumlClassTags \end{tabular}%
+ };%
+ \else%
+ \node[tikzuml simpleclass style, draw=\tikzumlClassDrawColor, fill=\tikzumlClassFillColor, text=\tikzumlClassTextColor, font=\tikzumlDefaultFont, minimum width=\tikzumlClassMinimumWidth, /tikzuml/class/style] (\tikzumlClassNodeName) {\begin{tabular}{c}\tikzumlClassVPadding \tikzumlClassType \tikzumlClassHPadding \textbf{\tikzumlClassName} \tikzumlClassHPadding \tikzumlClassTags \end{tabular}%
+ };%
+ \fi%
+ \else%
+ \iftikzumlclassCircleShape%
+ \node[tikzuml simpleinterface style, draw=\tikzumlClassDrawColor, fill=\tikzumlClassFillColor, text=\tikzumlClassTextColor, font=\tikzumlDefaultFont, minimum width=\tikzumlClassMinimumWidth, /tikzuml/class/style] (\tikzumlClassNodeName) at (\tikzumlClassPos) {};
+ \node[anchor=south] (\tikzumlClassNodeName-label) at (\tikzumlClassNodeName.north){\begin{tabular}{c}\tikzumlClassVPadding \tikzumlClassType \tikzumlClassHPadding \textbf{\tikzumlClassName} \tikzumlClassHPadding \tikzumlClassTags \end{tabular}%
+ };%
+ \else%
+ \node[tikzuml simpleclass style, draw=\tikzumlClassDrawColor, fill=\tikzumlClassFillColor, text=\tikzumlClassTextColor, font=\tikzumlDefaultFont, minimum width=\tikzumlClassMinimumWidth, /tikzuml/class/style] (\tikzumlClassNodeName) at (\tikzumlClassPos) {\begin{tabular}{c}\tikzumlClassVPadding \tikzumlClassType \tikzumlClassHPadding \textbf{\tikzumlClassName} \tikzumlClassHPadding \tikzumlClassTags \end{tabular}%
+ };%
+ \fi%
+ \fi%
+ \else%
+ \iftikzumlclassWithoutCoords%
+ \node[tikzuml class style, draw=\tikzumlClassDrawColor, fill=\tikzumlClassFillColor, text=\tikzumlClassTextColor, font=\tikzumlDefaultFont, minimum width=\tikzumlClassMinimumWidth, /tikzuml/class/style] (\tikzumlClassNodeName) {\begin{tabular}{c}\tikzumlClassVPadding \tikzumlClassType \tikzumlClassHPadding \textbf{\tikzumlClassName} \tikzumlClassHPadding \tikzumlClassTags \end{tabular}%
+ \nodepart{second}%
+ \begin{tabular}{l}%
+ \tikzumlClassAttributes%
+ \end{tabular}%
+ \nodepart{third}%
+ \begin{tabular}{l}%
+ \tikzumlClassOperations%
+ \end{tabular}%
+ };%
+ \else%
+ \node[tikzuml class style, draw=\tikzumlClassDrawColor, fill=\tikzumlClassFillColor, text=\tikzumlClassTextColor, font=\tikzumlDefaultFont, minimum width=\tikzumlClassMinimumWidth, /tikzuml/class/style] (\tikzumlClassNodeName) at (\tikzumlClassPos) {\begin{tabular}{c}\tikzumlClassVPadding \tikzumlClassType \tikzumlClassHPadding \textbf{\tikzumlClassName} \tikzumlClassHPadding \tikzumlClassTags \end{tabular}%
+ \nodepart{second}%
+ \begin{tabular}{l}%
+ \tikzumlClassAttributes%
+ \end{tabular}%
+ \nodepart{third}%
+ \begin{tabular}{l}%
+ \tikzumlClassOperations%
+ \end{tabular}%
+ };%
+ \fi%
+ \fi%
+ %
+ \ifthenelse{\equal{\tikzumlClassTemplateFillColorParam}{}}{}{%
+ \draw (\tikzumlClassNodeName.north east) node[tikzuml template style, name=\tikzumlClassNodeName-template, draw=\tikzumlClassDrawColor, fill=\tikzumlClassTemplateFillColor, text=\tikzumlClassTextColor, font=\tikzumlDefaultFont] {\tikzumlClassTemplateFillColorParam};%
+ }%
+ %
+ % add to fit
+ \ifnum\c@tikzumlPackageLevel>0%
+ \edef\tikzumlPackageFitOld{\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname}%
+ \ifthenelse{\equal{\tikzumlClassTemplateFillColorParam}{}}{%
+ \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{\tikzumlPackageFitOld (\tikzumlClassNodeName)}%
+ }{%
+ \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{\tikzumlPackageFitOld (\tikzumlClassNodeName) (\tikzumlClassNodeName-template)}%
+ }%
+ \stepcounter{tikzumlPackageClassNum}%
+ \fi%
+ \ifnum\c@tikzumlComponentLevel>0%
+ \def\tikzumlComponentFitTmp{\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname}%
+ \ifthenelse{\equal{\tikzumlClassTemplateFillColorParam}{}}{%
+ \expandafter\xdef\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname{\tikzumlComponentFitTmp (\tikzumlClassNodeName)}%
+ }{%
+ \expandafter\xdef\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname{\tikzumlComponentFitTmp (\tikzumlClassNodeName) (\tikzumlClassNodeName-template)}%
+ }%
+ \stepcounter{tikzumlComponentSubComponentNum}%
+ \fi%
+}%
+%
+% shortcuts for interface, enum and typedef environments
+\newcommand{\umlabstract}[4][]{%
+ \pgfkeys{/tikzuml/class/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{type}}{%
+ \errmessage{TIKZUML ERROR : in umlabstract, forbidden option type}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/class/.cd, #1}%
+ \umlclass[type=abstract,#1]{#2}{#3}{#4}%
+}%
+\newcommand{\umlinterface}[4][]{%
+ \pgfkeys{/tikzuml/class/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{type}}{%
+ \errmessage{TIKZUML ERROR : in umlinterface, forbidden option type}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/class/.cd, #1}%
+ \umlclass[type=interface,#1]{#2}{#3}{#4}%
+}%
+\newcommand{\umltypedef}[4][]{%
+ \pgfkeys{/tikzuml/class/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{type}}{%
+ \errmessage{TIKZUML ERROR : in umltypedef, forbidden option type}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/class/.cd, #1}%
+ \umlclass[type=typedef,#1]{#2}{#3}{#4}%
+}%
+\newcommand{\umlenum}[4][]{%
+ \pgfkeys{/tikzuml/class/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{type}}{%
+ \errmessage{TIKZUML ERROR : in umlenum, forbidden option type}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/class/.cd, #1}%
+ \umlclass[type=enum,#1]{#2}{#3}{#4}
+}%
+%
+% shortcut to define an empty class
+\newcommand{\umlemptyclass}[2][]{\umlclass[#1]{#2}{}{}}%
+\newcommand{\umlsimpleclass}[2][]{%
+ \pgfkeys{/tikzuml/class/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{simple}}{%
+ \errmessage{TIKZUML ERROR : in umlsimpleclass, forbidden option simple}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/class/.cd, #1}%
+ \umlemptyclass[simple, #1]{#2}%
+}%
+%
+\newcommand{\umlsimpleinterface}[2][]{%
+ \pgfkeys{/tikzuml/class/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{simple}}{%
+ \errmessage{TIKZUML ERROR : in umlsimpleinterface, forbidden option simple}%
+ }{%
+ \ifthenelse{\equal{\keyname}{circle}}{%
+ \errmessage{TIKZUML ERROR : in umlsimpleinterface, forbidden option circle}%
+ }{}%
+ }%
+ }%
+ }%
+ \pgfkeys{/tikzuml/class/.cd, #1}%
+ \umlsimpleclass[circle, #1]{#2}%
+}%
+% underline the text for static arg
+\newcommand{\umlstatic}[1]{\underline{#1}}%
+\newcommand{\umlvirt}[1]{\textit{#1}}%
+%
+% define node for n-ary association
+\newcommand{\umlNarynode}[2][]{%
+ \def\tikzumlNaryNodeAnchor{.north}
+ \def\tikzumlNaryNodeLabelPos{above}
+ \pgfkeys{/tikzuml/narynode/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlNaryNodeDefaultWidth, name/.initial=tikzumlEmpty,%
+ draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlClassDefaultFillColor,%
+ text/.initial=\tikzumlDefaultTextColor, style/.style={},%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}}{%
+ \def\tikzumlNaryNodeAnchor{.north}%
+ \def\tikzumlNaryNodeLabelPos{above}%
+ }{%
+ \ifthenelse{\equal{\keyname}{above left}}{%
+ \def\tikzumlNaryNodeAnchor{.north west}%
+ \def\tikzumlNaryNodeLabelPos{above left}%
+ }{%
+ \ifthenelse{\equal{\keyname}{left}}{%
+ \def\tikzumlNaryNodeAnchor{.west}%
+ \def\tikzumlNaryNodeLabelPos{left}%
+ }{%
+ \ifthenelse{\equal{\keyname}{below left}}{%
+ \def\tikzumlNaryNodeAnchor{.south west}%
+ \def\tikzumlNaryNodeLabelPos{below left}%
+ }{%
+ \ifthenelse{\equal{\keyname}{below}}{%
+ \def\tikzumlNaryNodeAnchor{.south}%
+ \def\tikzumlNaryNodeLabelPos{below}%
+ }{%
+ \ifthenelse{\equal{\keyname}{below right}}{%
+ \def\tikzumlNaryNodeAnchor{.south east}%
+ \def\tikzumlNaryNodeLabelPos{below right}%
+ }{%
+ \ifthenelse{\equal{\keyname}{right}}{%
+ \def\tikzumlNaryNodeAnchor{.east}%
+ \def\tikzumlNaryNodeLabelPos{right}%
+ }{%
+ \ifthenelse{\equal{\keyname}{above right}}{%
+ \def\tikzumlNaryNodeAnchor{.north east}%
+ \def\tikzumlNaryNodeLabelPos{above right}%
+ }{%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/narynode/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/narynode/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlNarynode, invalid option \keyname}%
+ }%
+ }%
+ }%
+ }%
+ }%
+ }%
+ }%
+ }%
+ }%
+ }%
+ \pgfkeys{/tikzuml/narynode/.cd,#1}%
+ \pgfkeys{/tikzuml/narynode/.cd, x/.get=\tikzumlNaryNodeX, y/.get=\tikzumlNaryNodeY, width/.get=\tikzumlNaryNodeMinimumWidth,%
+ name/.get=\tikzumlNaryNodeName,%
+ draw/.get=\tikzumlNaryNodeDrawColor, fill/.get=\tikzumlNaryNodeFillColor,%
+ text/.get=\tikzumlNaryNodeTextColor%
+ }%
+ %
+ \def\tikzumlNaryName{#2}%
+ %
+ \ifthenelse{\equal{\tikzumlNaryNodeName}{tikzumlEmpty}}{%
+ \edef\tikzumlNaryNodeName{\tikzumlNaryName}%
+ }{%
+ \edef\tikzumlNaryNodeName{\tikzumlNaryNodeName}%
+ }%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlNaryNode@nodeName{\tikzumlNaryNodeName}}\x%
+ %
+ \StrSubstitute{\tikzumlNaryNode@nodeName}{:}{@COLON@}[\tikzumlNaryNode@nodeName]%
+ \StrSubstitute{\tikzumlNaryNode@nodeName}{\_}{@UNDERSCORE@}[\tikzumlNaryNode@nodeName]%
+ %
+ \def\tikzumlNarynodePos{\tikzumlNaryNodeX,\tikzumlNaryNodeY}%
+ %
+ \node[tikzuml narynode style, draw=\tikzumlNaryNodeDrawColor, fill=\tikzumlNaryNodeFillColor, text=\tikzumlNaryNodeTextColor, font=\tikzumlDefaultFont, minimum width=\tikzumlNaryNodeMinimumWidth, minimum height=\tikzumlNaryNodeMinimumWidth, /tikzuml/narynode/style] (\tikzumlNaryNode@nodeName) at (\tikzumlNarynodePos) {};%
+ \draw (\tikzumlNaryNode@nodeName\tikzumlNaryNodeAnchor) node[\tikzumlNaryNodeLabelPos] {\tikzumlNaryName};%
+ %
+ % add to fit
+ \ifnum\c@tikzumlPackageLevel>0%
+ \edef\tikzumlPackageFitOld{\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{\tikzumlPackageFitOld (\tikzumlNaryNode@nodeName)}%
+ \stepcounter{tikzumlPackageClassNum}%
+ \fi%
+}%
+%
+\newdimen\tikzumlNestingSymbolSize%
+%
+% main command to define a relation between two classes
+% args : src class
+% dest class
+% optional : geometry: geometry of the line
+% weight: barycentric weight of the middle part when geometry is a 3-line
+% arm1, arm2: lengths of first or last part when geometry id a 3-line
+% arg1, arg2, arg: name of the src/dest/dest side class type attribute defined by the relation
+% mult1, mult2, mult: multiplicity of the src/dest/dest side class type attribute defined by the relation
+% pos1, pos2, pos: position of the src/dest/dest side class type attribute defined by the relation
+% align1, align2, align: text justification of the src/dest/dest side class type attribute defined by the relation
+% anchor1, anchor2: src/dest anchors on linked classes
+% angle1, angle2, loopsize: start angle, end angle and size of the relation (only if recursive)
+% stereo: stereotype of the relation
+% pos stereo: position of the stereotype on the relation
+% style: style of the relation (association, aggregation, composition, inherit, ...)
+% name: rootname used for naming nodes of the relation
+% recursive mode: type of recursive arrow (transition for state diagrams, or default)
+% recursive direction start/end: when transition relation, start/end directions of the relation arrow
+\newcommand{\umlrelation}[3][]{%
+ \pgfkeys{/tikzuml/relation/.cd, geometry/.initial=\tikzumlRelationDefaultGeometry, weight/.initial=\tikzumlRelationDefaultWeight,%
+ arm1/.initial=auto, arm2/.initial=auto,%
+ arg1/.initial={}, arg2/.initial={}, arg/.initial={},%
+ mult1/.initial={}, mult2/.initial={}, mult/.initial={},%
+ pos1/.initial=\tikzumlRelationDefaultPosO, pos2/.initial=\tikzumlRelationDefaultPosT, pos/.initial=tikzumlEmpty,%
+ align1/.initial={}, align2/.initial={}, align/.initial={},%
+ anchor1/.initial=tikzumlEmpty, anchor2/.initial=tikzumlEmpty,%
+ angle1/.initial=\tikzumlRelationDefaultAngleO, angle2/.initial=\tikzumlRelationDefaultAngleT, loopsize/.initial=\tikzumlRelationDefaultLoopSize,%
+ stereo/.initial={}, pos stereo/.initial=\tikzumlRelationDefaultPosStereo,%
+ style/.initial=->, style2/.style={}, name/.initial=relation-\thetikzumlRelationNum,%
+ recursive mode/.initial=default, recursive direction start/.initial=right,%
+ recursive direction end/.initial=bottom,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{with port}%
+ \OR\equal{\keyname}{interface}%
+ \OR\equal{\keyname}{padding}%
+ \OR\equal{\keyname}{width}%
+ \OR\equal{\keyname}{first arm}%
+ \OR\equal{\keyname}{second arm}%
+ \OR\equal{\keyname}{middle arm}%
+ \OR\equal{\keyname}{last arm}%
+ \OR\equal{\keyname}{distance}}{}{%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/relation/.cd, style2/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/relation/.cd, style2/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlrelation, invalid option \keyname}%
+ }%
+ }%
+ }%
+ \pgfkeys{/tikzuml/relation/.cd,#1}%
+ \pgfkeys{/tikzuml/relation/.cd, geometry/.get=\tikzumlRelationGeometry, weight/.get=\tikzumlRelationWeight,%
+ arm1/.get=\tikzumlRelationArmO, arm2/.get=\tikzumlRelationArmT,%
+ arg1/.get=\tikzumlRelationAttrName, arg2/.get=\tikzumlRelationAttrNameTO, arg/.get=\tikzumlRelationAttrNameTT,%
+ mult1/.get=\tikzumlRelationMultiplicity, mult2/.get=\tikzumlRelationMultiplicityTO, mult/.get=\tikzumlRelationMultiplicityTT,%
+ pos1/.get=\tikzumlRelationPosition, pos2/.get=\tikzumlRelationPositionTO, pos/.get=\tikzumlRelationPositionTT,%
+ align1/.get=\tikzumlRelationAlign, align2/.get=\tikzumlRelationAlignTO, align/.get=\tikzumlRelationAlignTT,%
+ anchor1/.get=\tikzumlRelationSrcAnchor, anchor2/.get=\tikzumlRelationDestAnchor,%
+ angle1/.get=\tikzumlRelationStartAngle, angle2/.get=\tikzumlRelationEndAngle, loopsize/.get=\tikzumlRelationLoopSize,%
+ stereo/.get=\tikzumlRelationStereoType, pos stereo/.get=\tikzumlRelationPositionStereotype,%
+ style/.get=\tikzumlRelationStyle, name/.get=\tikzumlRelationName,%
+ recursive mode/.get=\tikzumlRelationRecursiveMode,%
+ recursive direction start/.get=\tikzumlRelationRecursiveDirectionStart,%
+ recursive direction end/.get=\tikzumlRelationRecursiveDirectionEnd%
+ }%
+ %
+ \def\tikzumlSrcClassName{#2}%
+ %
+ % managing \_ in class names for node names
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlSrcClassNodeName{\tikzumlSrcClassName}}\x%
+ %
+ \StrSubstitute{\tikzumlSrcClassNodeName}{:}{@COLON@}[\tikzumlSrcClassNodeName]%
+ \StrSubstitute{\tikzumlSrcClassNodeName}{\_}{@UNDERSCORE@}[\tikzumlSrcClassNodeName]%
+ %
+ \def\tikzumlDestClassName{#3}%
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlDestClassNodeName{\tikzumlDestClassName}}\x%
+ %
+ \StrSubstitute{\tikzumlDestClassNodeName}{:}{@COLON@}[\tikzumlDestClassNodeName]%
+ \StrSubstitute{\tikzumlDestClassNodeName}{\_}{@UNDERSCORE@}[\tikzumlDestClassNodeName]%
+ %
+ % managing alias keys
+ \def\tikzumlRelationAttrNameT{\tikzumlRelationAttrNameTO\tikzumlRelationAttrNameTT}%
+ \def\tikzumlRelationMultiplicityT{\tikzumlRelationMultiplicityTO\tikzumlRelationMultiplicityTT}%
+ \def\tikzumlRelationAlignT{\tikzumlRelationAlignTO\tikzumlRelationAlignTT}%
+ \def\posAttrName{}%
+ \def\posMultiplicity{}%
+ \def\posAttrNameT{}%
+ \def\posMultiplicityT{}%
+ %
+ \ifthenelse{\equal{\tikzumlRelationPositionTT}{tikzumlEmpty}}{%
+ \def\tikzumlRelationPositionT{\tikzumlRelationPositionTO}%
+ }{%
+ \def\tikzumlRelationPositionT{\tikzumlRelationPositionTT}%
+ }%
+ %
+ \def\attrAlign{}%
+ \def\multAlign{}%
+ \def\attrAlignT{}%
+ \def\multAlignT{}%
+ %
+ \ifthenelse{\equal{\tikzumlRelationAlign}{left}}{%
+ \def\attrAlign{above right}%
+ \def\multAlign{below right}%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationAlign}{right}}{%
+ \def\attrAlign{above left}%
+ \def\multAlign{below left}%
+ }{}%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlRelationAlignT}{left}}{%
+ \def\attrAlignT{above right}%
+ \def\multAlignT{below right}%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationAlignT}{right}}{%
+ \def\attrAlignT{above left}%
+ \def\multAlignT{below left}%
+ }{}%
+ }%
+ %
+ % def stereotype
+ \ifthenelse{\equal{\tikzumlRelationStereoType}{}}{%
+ \def\stereotype{}%
+ }{%
+ \def\stereotype{$\ll$\tikzumlRelationStereoType$\gg$}%
+ }%
+
+ % def anchors macros
+ \ifthenelse{\equal{\tikzumlRelationSrcAnchor}{tikzumlEmpty}}{%
+ \def\tikzumlRelationSrcAnchor{}%
+ }{%
+ \let\tikzumlRelationSrcAnchorold\tikzumlRelationSrcAnchor%
+ \def\tikzumlRelationSrcAnchor{.\tikzumlRelationSrcAnchorold}%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlRelationDestAnchor}{tikzumlEmpty}}{%
+ \def\tikzumlRelationDestAnchor{}%
+ }{%
+ \let\tikzumlRelationDestAnchorold\tikzumlRelationDestAnchor%
+ \def\tikzumlRelationDestAnchor{.\tikzumlRelationDestAnchorold}%
+ }%
+ %
+ \setcounter{pos}{100*\real{\tikzumlRelationPosition}}%
+ \setcounter{posT}{100*\real{\tikzumlRelationPositionT}}%
+ \setcounter{posStereo}{100*\real{\tikzumlRelationPositionStereotype}}%
+ %
+ \pgfmathsetmacro{\tikzumlRelationWeightT}{1.0-\tikzumlRelationWeight}%
+ %
+ %\newcounter{tikzumlControlNodesNum}%
+ %\setcounter{tikzumlControlNodesNum}{0}%
+ %
+ \node[inner sep=0] (\tikzumlRelationName-middle) at (barycentric cs:\tikzumlSrcClassNodeName=\tikzumlRelationWeightT,\tikzumlDestClassNodeName=\tikzumlRelationWeight) {};%
+ %
+ % straight line
+ \ifthenelse{\equal{\tikzumlRelationGeometry}{--}}%
+ {%
+ \ifthenelse{\equal{\tikzumlSrcClassNodeName}{\tikzumlDestClassNodeName}}{%
+ \def\arcNum{1}%
+ \def\arcNumT{1}%
+ %
+ \ifthenelse{\equal{\tikzumlRelationRecursiveMode}{default}}{%
+ \xdef\tikzumlLastArc{node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity}%
+ node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT}%
+ node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \xdef\tikzumlPath{(\tikzumlSrcClassNodeName) edge[in=\tikzumlRelationEndAngle, out=\tikzumlRelationStartAngle, distance=\tikzumlRelationLoopSize] \tikzumlLastArc%
+ node[midway, inner sep=0, name=\tikzumlRelationName-1, anchor=center] {} (\tikzumlDestClassNodeName) }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveMode}{transition}}{%
+ \xdef\tikzumlFirstArc{node[midway, inner sep=0, name=\tikzumlRelationName-1, anchor=center] {}}%
+ \xdef\tikzumlMidOneArc{node[midway, inner sep=0, name=\tikzumlRelationName-3, anchor=center] {}}%
+ %
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{\tikzumlRelationRecursiveDirectionEnd}}{%
+ \def\numArcs{3}%
+ \xdef\tikzumlLastArc{node[midway, inner sep=0, name=\tikzumlRelationName-5, anchor=center] {}}%
+ %
+ \begin{pgfonlayer}{connections}%
+ \draw (\tikzumlSrcClassNodeName) edge[in=\tikzumlRelationEndAngle, out=\tikzumlRelationStartAngle, distance=\tikzumlRelationLoopSize, draw=none] %
+ node[midway, inner sep=0, name=\tikzumlRelationName-tmp, anchor=center] {} (\tikzumlDestClassNodeName);%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}\OR\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{%
+ \node[inner sep=0, name=\tikzumlRelationName-2] at (\tikzumlSrcClassNodeName.\tikzumlRelationStartAngle -| \tikzumlRelationName-tmp) {};%
+ \node[inner sep=0, name=\tikzumlRelationName-4] at (\tikzumlDestClassNodeName.\tikzumlRelationEndAngle -| \tikzumlRelationName-tmp) {};%
+ }{%
+ \node[inner sep=0, name=\tikzumlRelationName-2] at (\tikzumlSrcClassNodeName.\tikzumlRelationStartAngle |- \tikzumlRelationName-tmp) {};%
+ \node[inner sep=0, name=\tikzumlRelationName-4] at (\tikzumlDestClassNodeName.\tikzumlRelationEndAngle |- \tikzumlRelationName-tmp) {};%
+ }%
+ \end{pgfonlayer}%
+ }{%
+ \def\numArcs{4}%
+ \xdef\tikzumlMidTwoArc{node[midway, inner sep=0, name=\tikzumlRelationName-5, anchor=center] {}}%
+ \xdef\tikzumlLastArc{node[midway, inner sep=0, name=\tikzumlRelationName-7, anchor=center] {}}%
+ %
+ \begin{pgfonlayer}{connections}%
+ \draw (\tikzumlSrcClassNodeName) edge[in=\tikzumlRelationEndAngle, out=\tikzumlRelationStartAngle, distance=\tikzumlRelationLoopSize, draw=none] %
+ node[midway, name=\tikzumlRelationName-4, anchor=center] {} (\tikzumlDestClassNodeName);%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}\OR\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{%
+ \node[inner sep=0, name=\tikzumlRelationName-2] at (\tikzumlSrcClassNodeName.\tikzumlRelationStartAngle -| \tikzumlRelationName-4) {};%
+ \node[inner sep=0, name=\tikzumlRelationName-6] at (\tikzumlDestClassNodeName.\tikzumlRelationEndAngle |- \tikzumlRelationName-4) {};%
+ }{%
+ \node[inner sep=0, name=\tikzumlRelationName-2] at (\tikzumlSrcClassNodeName.\tikzumlRelationStartAngle |- \tikzumlRelationName-4) {};%
+ \node[inner sep=0, name=\tikzumlRelationName-6] at (\tikzumlDestClassNodeName.\tikzumlRelationEndAngle -| \tikzumlRelationName-4) {};%
+ }%
+ \end{pgfonlayer}%
+ }%
+ %
+ \ifnum\numArcs=4%
+ \ifnum\theposStereo>300%
+ \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-300)/100}%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype}}%
+ \else%
+ \ifnum\theposStereo<100%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype}}%
+ \else%
+ \ifnum\theposStereo>200%
+ \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-200)/100}%
+ \xdef\tikzumlMidTwoArc{\tikzumlMidTwoArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype}}%
+ \else%
+ \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-100)/100}%
+ \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype}}%
+ \fi%
+ \fi%
+ \fi%
+ %
+ \ifthenelse{\thepos=300\OR\thepos=100}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{bottom}}{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{bottom}}{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{top}}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{left}}{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{left}}{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }%
+ }%
+ }%
+ }%
+ }{}%
+ %
+ \ifthenelse{\thepos=200}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{bottom}}{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{bottom}}{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{top}}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{left}}{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{left}}{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }%
+ }%
+ }%
+ }%
+ }{}%
+ %
+ \ifnum\thepos>300%
+ \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-300)/100}%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity}%
+ }%
+ \else%
+ \ifnum\thepos<100%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity}%
+ }%
+ \else%
+ \ifnum\thepos>200%
+ \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-200)/100}%
+ \xdef\tikzumlMidTwoArc{\tikzumlMidTwoArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity}%
+ }%
+ \else%
+ \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-100)/100}%
+ \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity}%
+ }%
+ \fi%
+ \fi%
+ \fi%
+ %
+ \ifthenelse{\theposT=300\OR\theposT=100}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{bottom}}{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{bottom}}{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{top}}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{left}}{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{left}}{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }%
+ }%
+ }%
+ }%
+ }{}%
+ \ifthenelse{\theposT=200}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{bottom}}{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicity{below right}%
+ }{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{bottom}}{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{top}}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{left}}{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{left}}{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }%
+ }%
+ }%
+ }%
+ }{}%
+ %
+ \ifnum\theposT>300%
+ \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-300)/100}%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT}%
+ }%
+ \else%
+ \ifnum\theposT<100%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT}%
+ }%
+ \else%
+ \ifnum\theposT>200%
+ \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-200)/100}%
+ \xdef\tikzumlMidTwoArc{\tikzumlMidTwoArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT}%
+ }%
+ \else%
+ \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-100)/100}%
+ \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT}%
+ }%
+ \fi%
+ \fi%
+ \fi%
+ \else%
+ \ifnum\theposStereo>200%
+ \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-200)/100}%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \else%
+ \ifnum\theposStereo<100%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \else%
+ \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-100)/100}%
+ \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \fi%
+ \fi%
+ %
+ \ifthenelse{\thepos=100}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}}{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{top}}{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }%
+ }{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }%
+ }%
+ }%
+ }%
+ }{}%
+ %
+ \ifthenelse{\thepos=200}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}}{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{top}}{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }%
+ }{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }%
+ }%
+ }%
+ }%
+ }{}%
+ %
+ \ifnum\thepos>200%
+ \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-200)/100}%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity}%
+ }%
+ \else%
+ \ifnum\thepos<100%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity}%
+ }%
+ \else%
+ \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-100)/100}%
+ \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity}%
+ }%
+ \fi%
+ \fi%
+ %
+ \ifthenelse{\theposT=100}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}}{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{top}}{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }%
+ }{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }%
+ }%
+ }%
+ }%
+ }{}%
+ %
+ \ifthenelse{\theposT=200}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}}{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{top}}{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }%
+ }{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }%
+ }%
+ }%
+ }%
+ }{}%
+ %
+ \ifnum\theposT>200%
+ \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-200)/100}%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT}%
+ }%
+ \else%
+ \ifnum\theposT<100%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT}%
+ }%
+ \else%
+ \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-100)/100}%
+ \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT}%
+ }%
+ \fi%
+ \fi%
+ \fi%
+ %
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{\tikzumlRelationRecursiveDirectionEnd}}{%
+ \xdef\tikzumlPath{(\tikzumlSrcClassNodeName.\tikzumlRelationStartAngle) -- \tikzumlFirstArc (\tikzumlRelationName-2.center) -- \tikzumlMidOneArc (\tikzumlRelationName-4.center) -- \tikzumlLastArc (\tikzumlDestClassNodeName.\tikzumlRelationEndAngle) }%
+ \ifnum\thetikzumlStateLevel>0%
+ \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitTmp (\tikzumlRelationName-1) (\tikzumlRelationName-2) (\tikzumlRelationName-3) (\tikzumlRelationName-4) (\tikzumlRelationName-5)}%
+ \fi%
+ }{%
+ \xdef\tikzumlPath{(\tikzumlSrcClassNodeName.\tikzumlRelationStartAngle) -- \tikzumlFirstArc (\tikzumlRelationName-2.center) -- \tikzumlMidOneArc (\tikzumlRelationName-4.center) -- \tikzumlMidTwoArc (\tikzumlRelationName-6.center) -- \tikzumlLastArc (\tikzumlDestClassNodeName.\tikzumlRelationEndAngle) }%
+ \ifnum\thetikzumlStateLevel>0%
+ \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitTmp (\tikzumlRelationName-1) (\tikzumlRelationName-2) (\tikzumlRelationName-3) (\tikzumlRelationName-4) (\tikzumlRelationName-5) (\tikzumlRelationName-6) (\tikzumlRelationName-7)}%
+ \fi%
+ }%
+ }{}%
+ }%
+ }{%
+ \def\arcNum{1}%
+ \def\arcNumT{1}%
+ %
+ \node[inner sep=0] (\tikzumlRelationName-1) at (\tikzumlRelationName-middle) {};%
+ \xdef\tikzumlLastArc{node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity}%
+ node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT}%
+ node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \xdef\tikzumlPath{(\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor) -- \tikzumlLastArc (\tikzumlDestClassNodeName\tikzumlRelationDestAnchor) }%
+ \ifnum\thetikzumlStateLevel>0%
+ \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitTmp (\tikzumlRelationName-1) }%
+ \fi%
+ }%
+ }{%
+ % first vertical then horizontal line
+ \ifthenelse{\equal{\tikzumlRelationGeometry}{|-}}%
+ {%
+ %\setcounter{tikzumlControlNodesNum}{1}%
+ %
+ \def\tikzumlFirstArc{node[midway, inner sep=0, name=\tikzumlRelationName-1, anchor=center] {} }%
+ \def\tikzumlLastArc{node[midway, inner sep=0, name=\tikzumlRelationName-3, anchor=center]{} }%
+ %
+ \begin{pgfonlayer}{connections}%
+ \node[inner sep=0] (\tikzumlRelationName-2) at (\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor |- \tikzumlDestClassNodeName\tikzumlRelationDestAnchor) {};%
+ \end{pgfonlayer}%
+ %
+ \ifnum\theposStereo>100%
+ \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-100)/100}%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \else%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \fi%
+ %
+ \ifnum\thepos>100%
+ \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-100)/100}%
+ \def\arcNum{2}%
+ \else%
+ \def\arcNum{1}%
+ \ifnum\thepos=100%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ \fi%
+ \fi%
+ %
+ \ifnum\arcNum=1%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }%
+ \fi%
+ \ifnum\arcNum=2%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }%
+ \fi%
+ %
+ \ifnum\theposT>100%
+ \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-100)/100}%
+ \def\arcNumT{2}%
+ \else%
+ \def\arcNumT{1}%
+ \ifnum\theposT=100%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ \fi%
+ \fi%
+ %
+ \ifnum\arcNumT=1%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }%
+ \fi%
+ \ifnum\arcNumT=2%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }%
+ \fi%
+ %
+ \xdef\tikzumlPath{(\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor) -- \tikzumlFirstArc (\tikzumlRelationName-2.base) -- \tikzumlLastArc (\tikzumlDestClassNodeName\tikzumlRelationDestAnchor) }%
+ \ifnum\thetikzumlStateLevel>0%
+ \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitTmp (\tikzumlRelationName-1) (\tikzumlRelationName-2) (\tikzumlRelationName-3) }%
+ \fi%
+ }{%
+ % first horizontal then vertical line
+ \ifthenelse{\equal{\tikzumlRelationGeometry}{-|}}%
+ {%
+ %\setcounter{tikzumlControlNodesNum}{1}%
+ %
+ \def\tikzumlFirstArc{node[midway, inner sep=0, name=\tikzumlRelationName-1, anchor=center]{} }%
+ \def\tikzumlLastArc{node[midway, inner sep=0, name=\tikzumlRelationName-3, anchor=center] {} }%
+ %
+ \begin{pgfonlayer}{connections}%
+ \node[inner sep=0] (\tikzumlRelationName-2) at (\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor -| \tikzumlDestClassNodeName\tikzumlRelationDestAnchor) {};%
+ \end{pgfonlayer}%
+ %
+ \ifnum\theposStereo>100%
+ \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-100)/100}%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \else%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \fi%
+ %
+ \ifnum\thepos>100%
+ \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-100)/100}%
+ \def\arcNum{2}%
+ \else%
+ \def\arcNum{1}%
+ \ifnum\thepos=100%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ \fi%
+ \fi%
+ %
+ \ifnum\arcNum=1%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }%
+ \fi%
+ \ifnum\arcNum=2%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }%
+ \fi%
+ %
+ \ifnum\theposT>100%
+ \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-100)/100}%
+ \def\arcNumT{2}%
+ \else%
+ \def\arcNumT{1}%
+ \ifnum\theposT=100%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ \fi%
+ \fi%
+ %
+ \ifnum\arcNumT=1%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }%
+ \fi%
+ \ifnum\arcNumT=2%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }%
+ \fi%
+ %
+ \xdef\tikzumlPath{(\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor) -- \tikzumlFirstArc (\tikzumlRelationName-2.base) -- \tikzumlLastArc (\tikzumlDestClassNodeName\tikzumlRelationDestAnchor) }%
+ \ifnum\thetikzumlStateLevel>0%
+ \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitTmp (\tikzumlRelationName-1) (\tikzumlRelationName-2) (\tikzumlRelationName-3) }%
+ \fi%
+ }{%
+ % first vertical, then horizontal, finally vertical line
+ \ifthenelse{\equal{\tikzumlRelationGeometry}{|-|}}%
+ {%
+ %\setcounter{tikzumlControlNodesNum}{2}%
+ %
+ \def\tikzumlFirstArc{node[midway, inner sep=0, name=\tikzumlRelationName-1, anchor=center] {} }%
+ \def\tikzumlLastArc{node[midway, inner sep=0, name=\tikzumlRelationName-5, anchor=center] {} }%
+ \def\tikzumlMidOneArc{ }%
+ %
+ \begin{pgfonlayer}{connections}%
+ %
+ \ifthenelse{\equal{\tikzumlRelationArmO}{auto}}{%
+ \ifthenelse{\equal{\tikzumlRelationArmT}{auto}}{%
+ \node[inner sep=0] (\tikzumlRelationName-3) at (\tikzumlRelationName-middle) {};%
+ \node[inner sep=0] (\tikzumlRelationName-2) at (\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor |- \tikzumlRelationName-3) {};%
+ \node[inner sep=0] (\tikzumlRelationName-4) at (\tikzumlRelationName-3 -| \tikzumlDestClassNodeName\tikzumlRelationDestAnchor) {};%
+ }{%
+ \draw (\tikzumlDestClassNodeName\tikzumlRelationDestAnchor)+(0,\tikzumlRelationArmT) node[inner sep=0, name=\tikzumlRelationName-4] {};%
+ \node[inner sep=0] (\tikzumlRelationName-2) at (\tikzumlRelationName-4 -| \tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor) {};%
+ \node[inner sep=0] (\tikzumlRelationName-3) at (barycentric cs:\tikzumlRelationName-2=0.5,\tikzumlRelationName-4=0.5) {};%
+ }%
+ }{%
+ \draw (\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor)+(0,\tikzumlRelationArmO) node[inner sep=0, name=\tikzumlRelationName-2] {};%
+ \node[inner sep=0] (\tikzumlRelationName-4) at (\tikzumlRelationName-2 -| \tikzumlDestClassNodeName\tikzumlRelationDestAnchor) {};%
+ \node[inner sep=0] (\tikzumlRelationName-3) at (barycentric cs:\tikzumlRelationName-2=0.5,\tikzumlRelationName-4=0.5) {};%
+ }%
+ \end{pgfonlayer}%
+ %
+ \ifnum\theposStereo>200%
+ \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-200)/100}%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \else%
+ \ifnum\theposStereo<100%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \else%
+ \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-100)/100}%
+ \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \fi%
+ \fi%
+ %
+ \ifthenelse{\thepos=200\OR\thepos=100}{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }{}%
+ %
+ \ifthenelse{\thepos>200}{%
+ \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-200)/100}%
+ \def\arcNum{3}%
+ }{%
+ \ifthenelse{\thepos<100}{%
+ \def\arcNum{1}%
+ }{%
+ \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-100)/100}%
+ \def\arcNum{2}%
+ }%
+ }%
+ %
+ \ifnum\arcNum=1%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }%
+ \fi%
+ \ifnum\arcNum=2%
+ \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }%
+ \fi%
+ \ifnum\arcNum=3%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }%
+ \fi%
+ %
+ \ifthenelse{\theposT=200\OR\theposT=100}{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }{}%
+ %
+ \ifthenelse{\theposT>200}{%
+ \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-200)/100}%
+ \def\arcNumT{3}%
+ }{%
+ \ifthenelse{\theposT<100}{%
+ \def\arcNumT{1}%
+ }{%
+ \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-100)/100}%
+ \def\arcNumT{2}%
+ }%
+ }%
+ %
+ \ifnum\arcNumT=1%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }%
+ \fi%
+ \ifnum\arcNumT=2%
+ \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }%
+ \fi%
+ \ifnum\arcNumT=3%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }%
+ \fi%
+ %
+ \xdef\tikzumlPath{(\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor) -- \tikzumlFirstArc (\tikzumlRelationName-2.base) -- \tikzumlMidOneArc (\tikzumlRelationName-4.base) -- \tikzumlLastArc (\tikzumlDestClassNodeName\tikzumlRelationDestAnchor) }%
+ \ifnum\thetikzumlStateLevel>0%
+ \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitTmp (\tikzumlRelationName-1) (\tikzumlRelationName-2) (\tikzumlRelationName-3) (\tikzumlRelationName-4) (\tikzumlRelationName-5) }%
+ \fi%
+ }{%
+ % first horizontal, then vertical, finally horizontal line
+ \ifthenelse{\equal{\tikzumlRelationGeometry}{-|-}}%
+ {%
+ %\setcounter{tikzumlControlNodesNum}{2}%
+ %
+ \def\tikzumlFirstArc{node[midway, inner sep=0, name=\tikzumlRelationName-1, anchor=center] {} }%
+ \def\tikzumlLastArc{node[midway, inner sep=0, name=\tikzumlRelationName-5, anchor=center] {} }%
+ \def\tikzumlMidOneArc{}%
+ %
+ \begin{pgfonlayer}{connections}%
+ %
+ \ifthenelse{\equal{\tikzumlRelationArmO}{auto}}{%
+ \ifthenelse{\equal{\tikzumlRelationArmT}{auto}}{%
+ \node[inner sep=0] (\tikzumlRelationName-3) at (\tikzumlRelationName-middle) {};%
+ \node[inner sep=0] (\tikzumlRelationName-2) at (\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor -| \tikzumlRelationName-3) {};%
+ \node[inner sep=0] (\tikzumlRelationName-4) at (\tikzumlRelationName-3 |- \tikzumlDestClassNodeName\tikzumlRelationDestAnchor) {};%
+ }{%
+ \draw (\tikzumlDestClassNodeName\tikzumlRelationDestAnchor)+(\tikzumlRelationArmT,0) node[inner sep=0, name=\tikzumlRelationName-4] {};%
+ \node[inner sep=0] (\tikzumlRelationName-2) at (\tikzumlRelationName-4 |- \tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor) {};%
+ \node[inner sep=0] (\tikzumlRelationName-3) at (barycentric cs:\tikzumlRelationName-2=0.5,\tikzumlRelationName-4=0.5) {};%
+ }%
+ }{%
+ \draw (\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor)+(\tikzumlRelationArmO,0) node[inner sep=0, name=\tikzumlRelationName-2] {};%
+ \node[inner sep=0] (\tikzumlRelationName-4) at (\tikzumlRelationName-2 |- \tikzumlDestClassNodeName\tikzumlRelationDestAnchor) {};%
+ \node[inner sep=0] (\tikzumlRelationName-3) at (barycentric cs:\tikzumlRelationName-2=0.5,\tikzumlRelationName-4=0.5) {};%
+ }%
+ \end{pgfonlayer}%
+ %
+ \ifnum\theposStereo>200%
+ \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-200)/100}%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \else%
+ \ifnum\theposStereo<100%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \else%
+ \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-100)/100}%
+ \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \fi%
+ \fi%
+ %
+ \ifthenelse{\thepos=200\OR\thepos=100}{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }{}%
+ %
+ \ifthenelse{\thepos>200}{%
+ \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-200)/100}%
+ \def\arcNum{3}%
+ }{%
+ \ifthenelse{\thepos<100}{%
+ \def\arcNum{1}%
+ }{%
+ \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-100)/100}%
+ \def\arcNum{2}%
+ }%
+ }%
+ %
+ \ifnum\arcNum=1%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }%
+ \fi%
+ \ifnum\arcNum=2%
+ \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }%
+ \fi%
+ \ifnum\arcNum=3%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }%
+ \fi%
+ %
+ \ifthenelse{\theposT=200\OR\theposT=100}{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }{}%
+ %
+ \ifthenelse{\theposT>200}{%
+ \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-200)/100}%
+ \def\arcNumT{3}%
+ }{%
+ \ifthenelse{\theposT<100}{%
+ \def\arcNumT{1}%
+ }{%
+ \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-100)/100}%
+ \def\arcNumT{2}%
+ }%
+ }%
+ %
+ \ifnum\arcNumT=1%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }%
+ \fi%
+ \ifnum\arcNumT=2%
+ \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }%
+ \fi%
+ \ifnum\arcNumT=3%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }%
+ \fi%
+ %
+ \xdef\tikzumlPath{(\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor) -- \tikzumlFirstArc (\tikzumlRelationName-2.base) -- \tikzumlMidOneArc (\tikzumlRelationName-4.base) -- \tikzumlLastArc (\tikzumlDestClassNodeName\tikzumlRelationDestAnchor) }%
+ \ifnum\thetikzumlStateLevel>0%
+ \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitTmp (\tikzumlRelationName-1) (\tikzumlRelationName-2) (\tikzumlRelationName-3) (\tikzumlRelationName-4) (\tikzumlRelationName-5) }%
+ \fi%
+ }{%
+ \errmessage{TIKZUML ERROR : Unknown geometry value !!! It should be in the following list : --, |-, -|, |-|, -|-}%
+ }%
+ }%
+ }%
+ }%
+ }%
+ %
+ \begin{pgfonlayer}{connections}%
+ \ifthenelse{\equal{\tikzumlRelationStyle}{tikzuml nesting style}}{%
+ \pgfarrowsdeclare{nested}{nested}{...}
+ {
+ \tikzumlNestingSymbolSize=0.2pt%
+ \advance\tikzumlNestingSymbolSize by .5\pgflinewidth%
+ \pgfsetdash{}{0pt} % do not dash
+ \pgfsetroundjoin % fix join
+ \pgfsetroundcap % fix cap
+ \pgfpathmoveto{\pgfpoint{-16*\tikzumlNestingSymbolSize}{0pt}}%
+ \pgfpatharc{180}{90}{8*\tikzumlNestingSymbolSize}%
+ \pgfpatharc{90}{0}{8*\tikzumlNestingSymbolSize}%
+ \pgfpatharc{0}{-90}{8*\tikzumlNestingSymbolSize}%
+ \pgfpatharc{-90}{-180}{8*\tikzumlNestingSymbolSize}%
+ \pgfpathmoveto{\pgfpoint{-8*\tikzumlNestingSymbolSize}{8*\tikzumlNestingSymbolSize}}%
+ \pgfpathlineto{\pgfpoint{-8*\tikzumlNestingSymbolSize}{-8*\tikzumlNestingSymbolSize}}%
+ \pgfusepathqstroke%
+ }%
+ \draw[auto, nested-, font=\tikzumlDefaultFont, \tikzumlRelationStyle, /tikzuml/relation/style2] \tikzumlPath ;%
+ }{
+ \draw[auto, font=\tikzumlDefaultFont, \tikzumlRelationStyle, /tikzuml/relation/style2] \tikzumlPath ;%
+ }
+ \end{pgfonlayer}%
+ %
+ \stepcounter{tikzumlRelationNum}%
+}%
+%
+% shortcuts of \umlrelation
+\newcommand{\umlHVrelation}[3][]{%
+ \pgfkeys{/tikzuml/HVrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlHVrelation, forbidden option geometry}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/HVrelation/.cd, #1}%
+ \umlrelation[geometry=-|, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlVHrelation}[3][]{%
+ \pgfkeys{/tikzuml/VHrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlVHrelation, forbidden option geometry}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/VHrelation/.cd, #1}%
+ \umlrelation[geometry=|-, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlHVHrelation}[3][]{%
+ \pgfkeys{/tikzuml/HVHrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlHVHrelation, forbidden option geometry}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/HVHrelation/.cd, #1}%
+ \umlrelation[geometry=-|-, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlVHVrelation}[3][]{%
+ \pgfkeys{/tikzuml/VHVrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlVHVrelation, forbidden option geometry}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/VHVrelation/.cd, #1}%
+ \umlrelation[geometry=|-|, #1]{#2}{#3}%
+}%
+%
+%
+% shortcuts for relations
+\newcommand{\umlinherit}[3][]{\umlrelation[style={tikzuml inherit style}, #1]{#2}{#3}}%
+\newcommand{\umlimpl}[3][]{\umlrelation[style={tikzuml implements style}, #1]{#2}{#3}}%
+\newcommand{\umlreal}[3][]{\umlrelation[style={tikzuml implements style}, #1]{#2}{#3}}%
+\newcommand{\umlassoc}[3][]{\umlrelation[style={tikzuml association style}, #1]{#2}{#3}}%
+\newcommand{\umlbiassoc}[3][]{\umlrelation[style={tikzuml bidirectional association style}, #1]{#2}{#3}}%
+\newcommand{\umluniassoc}[3][]{\umlrelation[style={tikzuml unidirectional association style}, #1]{#2}{#3}}%
+\newcommand{\umlaggreg}[3][]{\umlrelation[style={tikzuml aggregation style}, #1]{#2}{#3}}%
+\newcommand{\umluniaggreg}[3][]{\umlrelation[style={tikzuml unidirectional aggregation style}, #1]{#2}{#3}}%
+\newcommand{\umlcompo}[3][]{\umlrelation[style={tikzuml composition style}, #1]{#2}{#3}}%
+\newcommand{\umlunicompo}[3][]{\umlrelation[style={tikzuml unidirectional composition style}, #1]{#2}{#3}}%
+\newcommand{\umlimport}[3][]{\umlrelation[style={tikzuml import style}, #1]{#2}{#3}}%
+\newcommand{\umlnest}[3][]{\umlrelation[style={tikzuml nesting style}, #1]{#2}{#3}}%
+\newcommand{\umldep}[3][]{\umlrelation[style={tikzuml dependency style}, #1]{#2}{#3}}%
+\newcommand{\umlfriend}[3][]{%
+ \pgfkeys{/tikzuml/friendrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlfriend, forbidden option stereo}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/friendrelation/.cd, #1}%
+ \umlrelation[stereo=friend, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlHVinherit}[3][]{\umlHVrelation[style={tikzuml inherit style}, #1]{#2}{#3}}%
+\newcommand{\umlHVimpl}[3][]{\umlHVrelation[style={tikzuml implements style}, #1]{#2}{#3}}%
+\newcommand{\umlHVreal}[3][]{\umlHVrelation[style={tikzuml implements style}, #1]{#2}{#3}}%
+\newcommand{\umlHVassoc}[3][]{\umlHVrelation[style={tikzuml association style}, #1]{#2}{#3}}%
+\newcommand{\umlHVuniassoc}[3][]{\umlHVrelation[style={tikzuml unidirectional association style}, #1]{#2}{#3}}%
+\newcommand{\umlHVaggreg}[3][]{\umlHVrelation[style={tikzuml aggregation style}, #1]{#2}{#3}}%
+\newcommand{\umlHVuniaggreg}[3][]{\umlHVrelation[style={tikzuml unidirectional aggregation style}, #1]{#2}{#3}}%
+\newcommand{\umlHVcompo}[3][]{\umlHVrelation[style={tikzuml composition style}, #1]{#2}{#3}}%
+\newcommand{\umlHVunicompo}[3][]{\umlHVrelation[style={tikzuml unidirectional composition style}, #1]{#2}{#3}}%
+\newcommand{\umlHVimport}[3][]{\umlHVrelation[style={tikzuml import style}, #1]{#2}{#3}}%
+\newcommand{\umlHVnest}[3][]{\umlHVrelation[style={tikzuml nesting style}, #1]{#2}{#3}}%
+\newcommand{\umlHVdep}[3][]{\umlHVrelation[style={tikzuml dependency style}, #1]{#2}{#3}}%
+\newcommand{\umlHVfriend}[3][]{%
+ \pgfkeys{/tikzuml/friendrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlHVfriend, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlHVfriend, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/friendrelation/.cd, #1}%
+ \umlrelation[geometry=-|, stereo=friend, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlVHinherit}[3][]{\umlVHrelation[style={tikzuml inherit style}, #1]{#2}{#3}}%
+\newcommand{\umlVHimpl}[3][]{\umlVHrelation[style={tikzuml implements style}, #1]{#2}{#3}}%
+\newcommand{\umlVHreal}[3][]{\umlVHrelation[style={tikzuml implements style}, #1]{#2}{#3}}%
+\newcommand{\umlVHassoc}[3][]{\umlVHrelation[style={tikzuml association style}, #1]{#2}{#3}}%
+\newcommand{\umlVHuniassoc}[3][]{\umlVHrelation[style={tikzuml unidirectional association style}, #1]{#2}{#3}}%
+\newcommand{\umlVHaggreg}[3][]{\umlVHrelation[style={tikzuml aggregation style}, #1]{#2}{#3}}%
+\newcommand{\umlVHuniaggreg}[3][]{\umlVHrelation[style={tikzuml unidirectional aggregation style}, #1]{#2}{#3}}%
+\newcommand{\umlVHcompo}[3][]{\umlVHrelation[style={tikzuml composition style}, #1]{#2}{#3}}%
+\newcommand{\umlVHunicompo}[3][]{\umlVHrelation[style={tikzuml unidirectional composition style}, #1]{#2}{#3}}%
+\newcommand{\umlVHimport}[3][]{\umlVHrelation[style={tikzuml import style}, #1]{#2}{#3}}%
+\newcommand{\umlVHnest}[3][]{\umlVHrelation[style={tikzuml nesting style}, #1]{#2}{#3}}%
+\newcommand{\umlVHdep}[3][]{\umlVHrelation[style={tikzuml dependency style}, #1]{#2}{#3}}%
+\newcommand{\umlVHfriend}[3][]{%
+ \pgfkeys{/tikzuml/friendrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlVHfriend, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlVHfriend, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/friendrelation/.cd, #1}%
+ \umlrelation[geometry=|-, stereo=friend, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlHVHinherit}[3][]{\umlHVHrelation[style={tikzuml inherit style}, #1]{#2}{#3}}%
+\newcommand{\umlHVHimpl}[3][]{\umlHVHrelation[style={tikzuml implements style}, #1]{#2}{#3}}%
+\newcommand{\umlHVHreal}[3][]{\umlHVHrelation[style={tikzuml implements style}, #1]{#2}{#3}}%
+\newcommand{\umlHVHassoc}[3][]{\umlHVHrelation[style={tikzuml association style}, #1]{#2}{#3}}%
+\newcommand{\umlHVHuniassoc}[3][]{\umlHVHrelation[style={tikzuml unidirectional association style}, #1]{#2}{#3}}%
+\newcommand{\umlHVHaggreg}[3][]{\umlHVHrelation[style={tikzuml aggregation style}, #1]{#2}{#3}}%
+\newcommand{\umlHVHuniaggreg}[3][]{\umlHVHrelation[style={tikzuml unidirectional aggregation style}, #1]{#2}{#3}}%
+\newcommand{\umlHVHcompo}[3][]{\umlHVHrelation[style={tikzuml composition style}, #1]{#2}{#3}}%
+\newcommand{\umlHVHunicompo}[3][]{\umlHVHrelation[style={tikzuml unidirectional composition style}, #1]{#2}{#3}}%
+\newcommand{\umlHVHimport}[3][]{\umlHVHrelation[style={tikzuml import style}, #1]{#2}{#3}}%
+\newcommand{\umlHVHnest}[3][]{\umlHVHrelation[style={tikzuml nesting style}, #1]{#2}{#3}}%
+\newcommand{\umlHVHdep}[3][]{\umlHVHrelation[style={tikzuml dependency style}, #1]{#2}{#3}}%
+\newcommand{\umlHVHfriend}[3][]{%
+ \pgfkeys{/tikzuml/friendrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlHVHfriend, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlHVHfriend, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/friendrelation/.cd, #1}%
+ \umlrelation[geometry=-|-, stereo=friend, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlVHVinherit}[3][]{\umlVHVrelation[style={tikzuml inherit style}, #1]{#2}{#3}}%
+\newcommand{\umlVHVimpl}[3][]{\umlVHVrelation[style={tikzuml implements style}, #1]{#2}{#3}}%
+\newcommand{\umlVHVreal}[3][]{\umlVHVrelation[style={tikzuml implements style}, #1]{#2}{#3}}%
+\newcommand{\umlVHVassoc}[3][]{\umlVHVrelation[style={tikzuml association style}, #1]{#2}{#3}}%
+\newcommand{\umlVHVuniassoc}[3][]{\umlVHVrelation[style={tikzuml unidirectional association style}, #1]{#2}{#3}}%
+\newcommand{\umlVHVaggreg}[3][]{\umlVHVrelation[style={tikzuml aggregation style}, #1]{#2}{#3}}%
+\newcommand{\umlVHVuniaggreg}[3][]{\umlVHVrelation[style={tikzuml unidirectional aggregation style}, #1]{#2}{#3}}%
+\newcommand{\umlVHVcompo}[3][]{\umlVHVrelation[style={tikzuml composition style}, #1]{#2}{#3}}%
+\newcommand{\umlVHVunicompo}[3][]{\umlVHVrelation[style={tikzuml unidirectional composition style}, #1]{#2}{#3}}%
+\newcommand{\umlVHVimport}[3][]{\umlVHVrelation[style={tikzuml import style}, #1]{#2}{#3}}%
+\newcommand{\umlVHVnest}[3][]{\umlVHVrelation[style={tikzuml nesting style}, #1]{#2}{#3}}%
+\newcommand{\umlVHVdep}[3][]{\umlVHVrelation[style={tikzuml dependency style}, #1]{#2}{#3}}%
+\newcommand{\umlVHVfriend}[3][]{%
+ \pgfkeys{/tikzuml/friendrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlVHVfriend, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlVHVfriend, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/friendrelation/.cd, #1}%
+ \umlrelation[geometry=|-|, stereo=friend, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+%
+% define a node
+\newcommand{\umlnode}[2]{%
+ \node (#2) at (#1) {};%
+}%
+%
+% main command to define a relation between two classes through a control node
+% args : src class
+% control node
+% dest class
+% optional : arg1, arg2, arg: name of the src/dest/dest side class type attribute defined by the relation
+% mult1, mult2, mult: multiplicity of the src/dest/dest side class type attribute defined by the relation
+% pos1, pos2, pos: position of the src/dest/dest side class type attribute defined by the relation
+% align1, align2, align: text justification of the src/dest/dest side class type attribute defined by the relation
+% anchor1, anchor2: src/dest anchors on linked classes
+% stereo: stereotype of the relation
+% pos stereo: position of the stereotype on the relation
+% style: style of the relation (association, aggregation, composition, inherit, ...)
+% name: rootname used for naming nodes of the relation
+\newcommand{\umlCNrelation}[4][]{%
+ \pgfkeys{/tikzuml/relation/.cd, arg1/.initial={}, arg2/.initial={}, arg/.initial={},%
+ mult1/.initial={}, mult2/.initial={}, mult/.initial={},%
+ pos1/.initial=0.2, pos2/.initial=0.8, pos/.initial=tikzumlEmpty,%
+ align1/.initial={}, align2/.initial={}, align/.initial={},%
+ anchor1/.initial=tikzumlEmpty, anchor2/.initial=tikzumlEmpty,%
+ stereo/.initial={}, pos stereo/.initial=1,%
+ style/.initial=->, name/.initial=relation-\thetikzumlRelationNum,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \errmessage{TIKZUML ERROR : in umlCNrelation, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/relation/.cd,#1}%
+ \pgfkeys{/tikzuml/relation/.cd, arg1/.get=\tikzumlCNRelationAttrName, arg2/.get=\tikzumlCNRelationAttrNameTO, arg/.get=\tikzumlCNRelationAttrNameTT,%
+ mult1/.get=\tikzumlCNRelationMultiplicity, mult2/.get=\tikzumlCNRelationMultiplicityTO, mult/.get=\tikzumlCNRelationMultiplicityTT,%
+ pos1/.get=\tikzumlCNRelationPosition, pos2/.get=\tikzumlCNRelationPositionTO, pos/.get=\tikzumlCNRelationPositionTT,%
+ align1/.get=\tikzumlCNRelationAlign, align2/.get=\tikzumlCNRelationAlignTO, align/.get=\tikzumlCNRelationAlignTT,%
+ anchor1/.get=\tikzumlCNRelationSrcAnchor, anchor2/.get=\tikzumlCNRelationDestAnchor,%
+ stereo/.get=\tikzumlCNRelationStereoType, pos stereo/.get=\tikzumlCNRelationPositionStereotype,%
+ style/.get=\tikzumlCNRelationStyle, name/.get=\tikzumlCNRelationName%
+ }%
+ %
+ % managing \_ in class names for node names
+ \def\tikzumlSrcClassName{#2}%
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlSrcClassNodeName{\tikzumlSrcClassName}}\x%
+ %
+ \StrSubstitute{\tikzumlSrcClassNodeName}{:}{@COLON@}[\tikzumlSrcClassNodeName]%
+ \StrSubstitute{\tikzumlSrcClassNodeName}{\_}{@UNDERSCORE@}[\tikzumlSrcClassNodeName]%
+ %
+ \def\tikzumlDestClassName{#4}%
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlDestClassNodeName{\tikzumlDestClassName}}\x%
+ %
+ \StrSubstitute{\tikzumlDestClassNodeName}{:}{@COLON@}[\tikzumlDestClassNodeName]%
+ \StrSubstitute{\tikzumlDestClassNodeName}{\_}{@UNDERSCORE@}[\tikzumlDestClassNodeName]%
+ %
+ % managing alias keys
+ \def\tikzumlCNRelationAttrNameT{\tikzumlCNRelationAttrNameTO\tikzumlCNRelationAttrNameTT}%
+ \def\tikzumlCNRelationMultiplicityT{\tikzumlCNRelationMultiplicityTO\tikzumlCNRelationMultiplicityTT}%
+ \def\tikzumlCNRelationAlignT{\tikzumlCNRelationAlignTO\tikzumlCNRelationAlignTT}%
+ \def\orientationT{\orientationTO\orientationTT}%
+ %
+ \ifthenelse{\equal{\tikzumlCNRelationPositionTT}{tikzumlEmpty}}{%
+ \def\tikzumlCNRelationPositionT{\tikzumlCNRelationPositionTO}%
+ }{%
+ \def\tikzumlCNRelationPositionT{\tikzumlCNRelationPositionTT}%
+ }%
+ %
+ \def\attrAlign{}%
+ \def\multAlign{}%
+ \def\attrAlignT{}%
+ \def\multAlignT{}%
+ %
+ \ifthenelse{\equal{\tikzumlCNRelationAlign}{left}}{%
+ \def\attrAlign{above right}%
+ \def\multAlign{below right}%
+ }{%
+ \ifthenelse{\equal{\tikzumlCNRelationAlign}{right}}{%
+ \def\attrAlign{above left}%
+ \def\multAlign{below left}%
+ }{}%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlCNRelationAlignT}{left}}{%
+ \def\attrAlignT{above right}%
+ \def\multAlignT{below right}%
+ }{%
+ \ifthenelse{\equal{\tikzumlCNRelationAlignT}{right}}{%
+ \def\attrAlignT{above left}%
+ \def\multAlignT{below left}%
+ }{}%
+ }%
+ %
+ % def stereotype
+ \ifthenelse{\equal{\tikzumlCNRelationStereoType}{}}{%
+ \def\stereotype{}%
+ }{%
+ \def\stereotype{$\ll$\tikzumlCNRelationStereoType$\gg$}%
+ }%
+ %
+ % def anchors macros
+ \ifthenelse{\equal{\tikzumlCNRelationSrcAnchor}{tikzumlEmpty}}{%
+ \def\tikzumlCNRelationSrcAnchor{}%
+ }{%
+ \let\tikzumlCNRelationSrcAnchorold\tikzumlCNRelationSrcAnchor%
+ \def\tikzumlCNRelationSrcAnchor{.\tikzumlCNRelationSrcAnchorold}%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlCNRelationDestAnchor}{tikzumlEmpty}}{%
+ \def\tikzumlCNRelationDestAnchor{}%
+ }{%
+ \let\tikzumlCNRelationDestAnchorold\tikzumlCNRelationDestAnchor%
+ \def\tikzumlCNRelationDestAnchor{.\tikzumlCNRelationDestAnchorold}%
+ }%
+ %
+ \setcounter{pos}{100*\real{\tikzumlCNRelationPosition}}%
+ \setcounter{posT}{100*\real{\tikzumlCNRelationPositionT}}%
+ \setcounter{posStereo}{100*\real{\tikzumlCNRelationPositionStereotype}}%
+ %
+ % straight line
+ %\setcounter{tikzumlControlNodesNum}{1}%
+ %
+ \def\tikzumlFirstArc{node[midway, name=\tikzumlCNRelationName-1, anchor=center] {} }%
+ \def\tikzumlLastArc{node[midway, name=\tikzumlCNRelationName-3, anchor=center]{} }%
+ \def\posAttrName{}%
+ \def\posMultiplicity{}%
+ \def\posAttrNameT{}%
+ \def\posMultiplicityT{}%
+ %
+ \begin{pgfonlayer}{connections}%
+ \node (\tikzumlCNRelationName-2) at (#3) {};%
+ \end{pgfonlayer}%
+ %
+ \ifnum\theposStereo>100%
+ \pgfmathsetmacro{\tikzumlCNRelationPositionStereotype}{(\theposStereo-100)/100}%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlCNRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \else%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlCNRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \fi%
+ %
+ \ifnum\thepos>100%
+ \pgfmathsetmacro{\tikzumlCNRelationPosition}{(\thepos-100)/100}%
+ \def\arcNum{2}%
+ \else%
+ \def\arcNum{1}%
+ \ifnum\thepos=100%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ \fi%
+ \fi%
+ %
+ \ifnum\arcNum=1%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlCNRelationPosition, \posAttrName, \attrAlign] {\tikzumlCNRelationAttrName}%
+ node[pos=\tikzumlCNRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlCNRelationMultiplicity} }%
+ \fi%
+ \ifnum\arcNum=2%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlCNRelationPosition, \posAttrName, \attrAlign] {\tikzumlCNRelationAttrName}%
+ node[pos=\tikzumlCNRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlCNRelationMultiplicity} }%
+ \fi%
+ %
+ \ifnum\theposT>100%
+ \pgfmathsetmacro{\tikzumlCNRelationPositionT}{(\theposT-100)/100}%
+ \def\arcNumT{2}%
+ \else%
+ \def\arcNumT{1}%
+ \ifnum\theposT=100%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ \fi%
+ \fi%
+ %
+ \ifnum\arcNumT=1%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlCNRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlCNRelationAttrNameT}%
+ node[pos=\tikzumlCNRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlCNRelationMultiplicityT} }%
+ \fi%
+ \ifnum\arcNumT=2%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlCNRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlCNRelationAttrNameT}%
+ node[pos=\tikzumlCNRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlCNRelationMultiplicityT} }%
+ \fi%
+ %
+ \xdef\tikzumlPath{(\tikzumlSrcClassNodeName\tikzumlCNRelationSrcAnchor) -- \tikzumlFirstArc (\tikzumlCNRelationName-2.base) -- \tikzumlLastArc (\tikzumlDestClassNodeName\tikzumlCNRelationDestAnchor) }%
+
+ \begin{pgfonlayer}{connections}%
+ \ifthenelse{\equal{\tikzumlCNRelationStyle}{tikzuml nesting style}}{%
+ \pgfarrowsdeclare{nested}{nested}{...}
+ {
+ \tikzumlNestingSymbolSize=0.2pt%
+ \advance\tikzumlNestingSymbolSize by .5\pgflinewidth%
+ \pgfsetdash{}{0pt} % do not dash
+ \pgfsetroundjoin % fix join
+ \pgfsetroundcap % fix cap
+ \pgfpathmoveto{\pgfpoint{-16*\tikzumlNestingSymbolSize}{0pt}}%
+ \pgfpatharc{180}{90}{8*\tikzumlNestingSymbolSize}%
+ \pgfpatharc{90}{0}{8*\tikzumlNestingSymbolSize}%
+ \pgfpatharc{0}{-90}{8*\tikzumlNestingSymbolSize}%
+ \pgfpatharc{-90}{-180}{8*\tikzumlNestingSymbolSize}%
+ \pgfpathmoveto{\pgfpoint{-8*\tikzumlNestingSymbolSize}{8*\tikzumlNestingSymbolSize}}%
+ \pgfpathlineto{\pgfpoint{-8*\tikzumlNestingSymbolSize}{-8*\tikzumlNestingSymbolSize}}%
+ \pgfusepathqstroke%
+ }%
+ \draw[auto, \tikzumlCNRelationStyle, nested-, font=\tikzumlDefaultFont] \tikzumlPath ;%
+ }{
+ \draw[auto, \tikzumlCNRelationStyle, font=\tikzumlDefaultFont] \tikzumlPath ;%
+ }
+ \end{pgfonlayer}%
+ %
+ \stepcounter{tikzumlRelationNum}%
+}%
+%
+% shortcuts for cnrelations
+\newcommand{\umlCNinherit}[4][]{\umlCNrelation[style={tikzuml inherit style}, #1]{#2}{#3}{#4}}%
+\newcommand{\umlCNimpl}[4][]{\umlCNrelation[style={tikzuml implements style}, #1]{#2}{#3}{#4}}%
+\newcommand{\umlCNreal}[4][]{\umlCNrelation[style={tikzuml implements style}, #1]{#2}{#3}{#4}}%
+\newcommand{\umlCNassoc}[4][]{\umlCNrelation[style={tikzuml association style}, #1]{#2}{#3}{#4}}%
+\newcommand{\umlCNuniassoc}[4][]{\umlCNrelation[style={tikzuml unidirectional association style}, #1]{#2}{#3}{#4}}%
+\newcommand{\umlCNaggreg}[4][]{\umlCNrelation[style={tikzuml aggregation style}, #1]{#2}{#3}{#4}}%
+\newcommand{\umlCNuniaggreg}[4][]{\umlCNrelation[style={tikzuml unidirectional aggregation style}, #1]{#2}{#3}{#4}}%
+\newcommand{\umlCNcompo}[4][]{\umlCNrelation[style={tikzuml composition style}, #1]{#2}{#3}{#4}}%
+\newcommand{\umlCNunicompo}[4][]{\umlCNrelation[style={tikzuml unidirectional composition style}, #1]{#2}{#3}{#4}}%
+\newcommand{\umlCNimport}[4][]{\umlCNrelation[style={tikzuml import style}, #1]{#2}{#3}{#4}}%
+\newcommand{\umlCNnest}[4][]{\umlCNrelation[style={tikzuml nesting style}, #1]{#2}{#3}{#4}}%
+\newcommand{\umlCNdep}[4][]{\umlCNrelation[style={tikzuml dependency style}, #1]{#2}{#3}{#4}}%
+\newcommand{\umlCNfriend}[4][]{%
+ \pgfkeys{/tikzuml/friendrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlCNfriend, forbidden option stereo}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/friendrelation/.cd, #1}%
+ \umlCNrelation[stereo=friend, style={tikzuml dependency style}, #1]{#2}{#3}{#4}%
+}%
+%
+% define a note
+% arg : attached class
+% label of the note
+% optional : x,y: coordinates of the note
+% width: width of the note
+% geometry: geometry of the relation between the note and what it is about
+% weight: barycentric weight for a 3-line relation
+% arm: length of the first arm
+% anchor1, anchor2: anchors of the relation
+% draw, fill, text: colors
+% style: to manage every default TikZ option
+% no coords: to tell that the note position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlnote}[3][]{%
+ \pgfkeys{/tikzuml/note/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlNoteDefaultWidth,%
+ geometry/.initial=\tikzumlRelationDefaultGeometry,%
+ weight/.initial=\tikzumlRelationDefaultWeight, arm/.initial=auto, style/.style={},%
+ anchor1/.initial=tikzumlEmpty, anchor2/.initial=tikzumlEmpty,%
+ draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlNoteDefaultFillColor,%
+ text/.initial=\tikzumlDefaultTextColor,%
+ no coords/.is if=tikzumlnoteWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/note/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/note/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/note/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlnote, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/note/.cd, #1}%
+ \pgfkeys{/tikzuml/note/.cd, x/.get=\tikzumlNoteX, y/.get=\tikzumlNoteY, width/.get=\tikzumlNoteTextWidth,%
+ geometry/.get=\tikzumlNoteGeometry,%
+ weight/.get=\tikzumlNoteWeight, arm/.get=\tikzumlNoteArm,%
+ anchor1/.get=\tikzumlNoteSrcAnchor, anchor2/.get=\tikzumlNoteDestAnchor,%
+ draw/.get=\tikzumlNoteDrawColor, fill/.get=\tikzumlNoteFillColor,%
+ text/.get=\tikzumlNoteTextColor%
+ }%
+ %
+ \def\tikzumlClassName{#2}%
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlClassNodeName{\tikzumlClassName}}\x%
+ %
+ % def anchors macros
+ \ifthenelse{\equal{\tikzumlNoteSrcAnchor}{tikzumlEmpty}}{%
+ \def\tikzumlNoteSrcAnchor{}%
+ }{%
+ \let\tikzumlNoteSrcAnchorold\tikzumlNoteSrcAnchor%
+ \def\tikzumlNoteSrcAnchor{.\tikzumlNoteSrcAnchorold}%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlNoteDestAnchor}{tikzumlEmpty}}{%
+ \def\tikzumlNoteDestAnchor{}%
+ }{%
+ \let\tikzumlNoteDestAnchorold\tikzumlNoteDestAnchor%
+ \def\tikzumlNoteDestAnchor{.\tikzumlNoteDestAnchorold}%
+ }%
+ %
+ \iftikzumlnoteWithoutCoords%
+ \node[text=\tikzumlNoteTextColor, text width=\tikzumlNoteTextWidth, font=\tikzumlDefaultFont, outer sep=0, inner xsep=1ex, inner ysep=3ex, /tikzuml/note/style] (note-\thetikzumlNoteNum-coord) {#3};%
+ \else%
+ \node[text=\tikzumlNoteTextColor, text width=\tikzumlNoteTextWidth, font=\tikzumlDefaultFont, outer sep=0, inner xsep=1ex, inner ysep=3ex, /tikzuml/note/style] (note-\thetikzumlNoteNum-coord) at (\tikzumlNoteX, \tikzumlNoteY) {#3};%
+ \fi%
+ \draw (note-\thetikzumlNoteNum-coord.north east) node[name=note-\thetikzumlNoteNum-right-top, below=2ex, coordinate] {};%
+ \draw (note-\thetikzumlNoteNum-coord.north east) node[name=note-\thetikzumlNoteNum-top-right, left=2ex, coordinate] {};%
+ \draw[draw=\tikzumlNoteDrawColor, fill=\tikzumlNoteFillColor] (note-\thetikzumlNoteNum-coord.south west) -- (note-\thetikzumlNoteNum-coord.south east) -- (note-\thetikzumlNoteNum-right-top.base) -- (note-\thetikzumlNoteNum-top-right.base) -- (note-\thetikzumlNoteNum-coord.north west) -- cycle;%
+ \node[text=\tikzumlNoteTextColor, text width=\tikzumlNoteTextWidth, outer sep=0, inner xsep=1ex, inner ysep=3ex, font=\tikzumlDefaultFont] (note-\thetikzumlNoteNum) at (note-\thetikzumlNoteNum-coord) {#3};%
+ \draw[draw=\tikzumlNoteDrawColor] (note-\thetikzumlNoteNum-right-top) -| (note-\thetikzumlNoteNum-top-right);%
+ %
+ \pgfmathsetmacro{\tikzumlNoteWeightT}{1.0-\tikzumlNoteWeight}%
+ \node (note-\thetikzumlNoteNum-middle) at (barycentric cs:note-\thetikzumlNoteNum-coord=\tikzumlNoteWeight,\tikzumlClassNodeName=\tikzumlNoteWeightT) {};%
+ %
+ \ifthenelse{\equal{\tikzumlNoteGeometry}{--}%
+ \OR\equal{\tikzumlNoteGeometry}{-|}%
+ \OR\equal{\tikzumlNoteGeometry}{|-}}{%
+ \edef\tikzumlnotepath{\tikzumlNoteGeometry}
+ }{%
+ \ifthenelse{\equal{\tikzumlNoteGeometry}{-|-}}{%
+ \ifthenelse{\equal{\tikzumlNoteArm}{auto}}{%
+ \edef\tikzumlnotepath{-- (note-\thetikzumlNoteNum-coord\tikzumlNoteSrcAnchor -| note-\thetikzumlNoteNum-middle.center) -- (note-\thetikzumlNoteNum-middle.center) -- (note-\thetikzumlNoteNum-middle.center |- \tikzumlClassNodeName\tikzumlNoteDestAnchor) --}%
+ }{%
+ \draw (note-\thetikzumlNoteNum-coord\tikzumlNoteSrcAnchor)+(\tikzumlNoteArm,0) node[name=note-\thetikzumlNoteNum-tmp] {};
+ \edef\tikzumlnotepath{-- (note-\thetikzumlNoteNum-tmp.center) |-}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlNoteGeometry}{|-|}}{%
+ \ifthenelse{\equal{\tikzumlNoteArm}{auto}}{%
+ \edef\tikzumlnotepath{-- (note-\thetikzumlNoteNum-coord\tikzumlNoteSrcAnchor |- note-\thetikzumlNoteNum-middle.center) -- (note-\thetikzumlNoteNum-middle.center) -- (note-\thetikzumlNoteNum-middle.center -| \tikzumlClassNodeName\tikzumlNoteDestAnchor) --}%
+ }{%
+ \draw (note-\thetikzumlNoteNum-coord\tikzumlNoteSrcAnchor)+(0,\tikzumlNoteArm) node[name=note-\thetikzumlNoteNum-tmp] {};
+ \edef\tikzumlnotepath{-- (note-\thetikzumlNoteNum-tmp.center) -|}%
+ }%
+
+ }{%
+ \errmessage{TIKZUML ERROR : Unknown geometry value !!! It should be in the following list : --, |-, -|, |-|, -|-}%
+ }%
+ }%
+ }%
+ %
+ \begin{pgfonlayer}{connections}%
+ \draw[dashed] (note-\thetikzumlNoteNum-coord\tikzumlNoteSrcAnchor) \tikzumlnotepath (\tikzumlClassNodeName\tikzumlNoteDestAnchor);%
+ \end{pgfonlayer}%
+ %
+ \stepcounter{tikzumlNoteNum}%
+}%
+%
+% shortcuts for note with geometry
+\newcommand{\umlHVnote}[3][]{%
+ \pgfkeys{/tikzuml/note/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlHVnote, forbidden option geometry}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/note/.cd, #1}%
+ \umlnote[geometry=-|, #1]{#2}{#3}%
+}%
+\newcommand{\umlVHnote}[3][]{%
+ \pgfkeys{/tikzuml/note/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlVHnote, forbidden option geometry}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/note/.cd, #1}%
+ \umlnote[geometry=|-, #1]{#2}{#3}%
+}%
+\newcommand{\umlVHVnote}[3][]{%
+ \pgfkeys{/tikzuml/note/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlVHVnote, forbidden option geometry}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/note/.cd, #1}%
+ \umlnote[geometry=|-|, #1]{#2}{#3}%
+}%
+\newcommand{\umlHVHnote}[3][]{%
+ \pgfkeys{/tikzuml/note/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlHVHnote, forbidden option geometry}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/note/.cd, #1}%
+ \umlnote[geometry=-|-, #1]{#2}{#3}%
+}%
+%
+% define a uml association class (command)
+% args : name of the class
+% attributes of the class
+% operations of the class
+% optional : x,y: coordinates of the class
+% width: width of the class node
+% type: type of of class (class, interface, typedef, enum)
+% template: template parameters
+% name: name of the class node
+% geometry: geometry of the line
+% weight: barycentric weight of the middle part when geometry is a 3-line
+% arm: length of first part when geometry id a 3-line
+% anchor1, anchor2: src/dest anchors on linked classes
+% style: style of the association class (association, aggregation, composition, inherit, ...)
+% draw, fill, fill template, text: colors
+% style: to manage every default TikZ option
+% no coords: to tell that the class position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlassocclass}[5][]{%
+ \pgfkeys{/tikzuml/assocclass/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX,
+ width/.initial=\tikzumlClassDefaultWidth, type/.initial=\tikzumlClassDefaultType, style/.style={},%
+ template/.initial={}, name/.initial=tikzumlEmpty, geometry/.initial=\tikzumlRelationDefaultGeometry,%
+ weight/.initial=\tikzumlRelationDefaultWeight, arm/.initial=auto,%
+ anchor1/.initial=tikzumlEmpty, anchor2/.initial=tikzumlEmpty,%
+ draw/.initial=\tikzumlDefaultDrawColor,%
+ fill template/.initial=\tikzumlClassTemplateFillColorDefaultFillColor,%
+ fill/.initial=\tikzumlClassDefaultFillColor,%
+ text/.initial=\tikzumlDefaultTextColor,%
+ no coords/.is if=tikzumlassocclassWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/assocclass/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/assocclass/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/assocclass/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlassocclass, invalid option \keyname}%
+ }%
+ }%
+ %
+ \pgfkeys{/tikzuml/assocclass/.cd,#1}%
+ \pgfkeys{/tikzuml/assocclass/.cd, x/.get=\tikzumlAssocClassX, y/.get=\tikzumlAssocClassY,%
+ width/.get=\tikzumlAssocClassMinimumWidth, type/.get=\tikzumlAssocClassTypeTmp,%
+ template/.get=\tikzumlAssocClassTemplateParam,%
+ name/.get=\tikzumlAssocClassName, geometry/.get=\tikzumlAssocClassGeometry,%
+ weight/.get=\tikzumlAssocClassWeight, arm/.get=\tikzumlAssocClassArm,%
+ anchor1/.get=\tikzumlAssocClassSrcAnchor,%
+ anchor2/.get=\tikzumlAssocClassDestAnchor,%
+ draw/.get=\tikzumlAssocClassDrawColor, fill/.get=\tikzumlAssocClassFillColor,%
+ text/.get=\tikzumlAssocClassTextColor, fill template/.get=\tikzumlAssocClassTemplateFillColor%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlAssocClassTypeTmp}{class}\OR\equal{\tikzumlAssocClassTypeTmp}{abstract}}{%
+ \def\tikzumlAssocClassType{}%
+ }{%
+ \def\tikzumlAssocClassType{$\ll$\tikzumlAssocClassTypeTmp$\gg$ \\}%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlAssocClassTemplateParam}{}}{%
+ \def\tikzumlAssocClassVPadding{}%
+ \def\tikzumlAssocClassHPadding{}%
+ }{%
+ \def\tikzumlAssocClassVPadding{\vspace{0.1em} \\}%
+ \def\tikzumlAssocClassHPadding{\hspace{0.5ex} $ $}%
+ }%
+ %
+ \def\tikzumlAssocClassName{#2}%
+ \def\tikzumlAssocClassRelationName{#3}%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlAssocClassNodeName{\tikzumlAssocClassName}}\x%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlAssocClassRelationNodeName{\tikzumlAssocClassRelationName}}\x%
+ %
+ \ifthenelse{\equal{\tikzumlAssocClassName}{tikzumlEmpty}}{}{%
+ \def\tikzumlAssocClassNodeName{\tikzumlAssocClassName}%
+ }%
+ %
+ \StrSubstitute{\tikzumlAssocClassNodeName}{:}{@COLON@}[\tikzumlAssocClassNodeName]%
+ \StrSubstitute{\tikzumlAssocClassNodeName}{\_}{@UNDERSCORE@}[\tikzumlAssocClassNodeName]%
+ %
+ \ifthenelse{\equal{\tikzumlAssocClassTypeTmp}{abstract}}{%
+ \let\tikzumlAssocClassNameOld\tikzumlAssocClassName%
+ \def\tikzumlAssocClassName{{\it \tikzumlAssocClassNameOld}}%
+ }{}%
+ %
+ \def\tikzumlAssocClassPos{\tikzumlAssocClassX,\tikzumlAssocClassY}%
+ \def\tikzumlAssocClassAttributes{#4}%
+ \def\tikzumlAssocClassOperations{#5}%
+ %
+ % def anchors macros
+ \ifthenelse{\equal{\tikzumlAssocClassSrcAnchor}{tikzumlEmpty}}{%
+ \def\tikzumlAssocClassSrcAnchor{}%
+ }{%
+ \let\tikzumlAssocClassSrcAnchorold\tikzumlAssocClassSrcAnchor%
+ \def\tikzumlAssocClassSrcAnchor{.\tikzumlAssocClassSrcAnchorold}%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlAssocClassDestAnchor}{tikzumlEmpty}}{%
+ \def\tikzumlAssocClassDestAnchor{}%
+ }{%
+ \let\tikzumlAssocClassDestAnchorold\tikzumlAssocClassDestAnchor%
+ \def\tikzumlAssocClassDestAnchor{.\tikzumlAssocClassDestAnchorold}%
+ }%
+ %
+ \iftikzumlassocclassWithoutCoords%
+ \node[tikzuml class style, draw=\tikzumlAssocClassDrawColor, fill=\tikzumlAssocClassFillColor, text=\tikzumlAssocClassTextColor, font=\tikzumlDefaultFont, minimum width=\tikzumlAssocClassMinimumWidth, /tikzuml/assocclass/style] (\tikzumlAssocClassNodeName) {\begin{tabular}{c}\tikzumlAssocClassVPadding \tikzumlAssocClassType \tikzumlAssocClassHPadding \textbf{\tikzumlAssocClassName} \tikzumlAssocClassHPadding \end{tabular}%
+ \nodepart{second}%
+ \begin{tabular}{l}%
+ \tikzumlAssocClassAttributes%
+ \end{tabular}%
+ \nodepart{third}%
+ \begin{tabular}{l}%
+ \tikzumlAssocClassOperations%
+ \end{tabular}%
+ };%
+ \else%
+ \node[tikzuml class style, draw=\tikzumlAssocClassDrawColor, fill=\tikzumlAssocClassFillColor, text=\tikzumlAssocClassTextColor, font=\tikzumlDefaultFont, minimum width=\tikzumlAssocClassMinimumWidth, /tikzuml/assocclass/style] (\tikzumlAssocClassNodeName) at (\tikzumlAssocClassPos) {\begin{tabular}{c}\tikzumlAssocClassVPadding \tikzumlAssocClassType \tikzumlAssocClassHPadding \textbf{\tikzumlAssocClassName} \tikzumlAssocClassHPadding \end{tabular}%
+ \nodepart{second}%
+ \begin{tabular}{l}%
+ \tikzumlAssocClassAttributes%
+ \end{tabular}%
+ \nodepart{third}%
+ \begin{tabular}{l}%
+ \tikzumlAssocClassOperations%
+ \end{tabular}%
+ };%
+ \fi%
+ %
+ \ifthenelse{\equal{\tikzumlAssocClassTemplateParam}{}}{}{%
+ \draw (\tikzumlAssocClassNodeName.north east) node[tikzuml template style, name=\tikzumlAssocClassNodeName-template, draw=\tikzumlAssocClassDrawColor, fill=\tikzumlAssocClassTemplateFillColor, text=\tikzumlAssocClassTextColor, font=\tikzumlDefaultFont] {\tikzumlAssocClassTemplateParam};%
+ }%
+ %
+ \pgfmathsetmacro{\tikzumlAssocClassWeightT}{1.0-\tikzumlAssocClassWeight}
+ \node (\tikzumlAssocClassNodeName-middle) at (barycentric cs:\tikzumlAssocClassNodeName=\tikzumlAssocClassWeight,\tikzumlAssocClassRelationNodeName=\tikzumlAssocClassWeightT) {};%
+ %
+ \ifthenelse{\equal{\tikzumlAssocClassGeometry}{--}\OR\equal{\tikzumlAssocClassGeometry}{-|}\OR\equal{\tikzumlAssocClassGeometry}{|-}}{%
+ \edef\tikzumlassocclasspath{\tikzumlAssocClassGeometry}
+ }{%
+ \ifthenelse{\equal{\tikzumlAssocClassGeometry}{-|-}}{%
+ \ifthenelse{\equal{\tikzumlAssocClassArm}{auto}}{%
+ \edef\tikzumlassocclasspath{-- (\tikzumlAssocClassNodeName\tikzumlAssocClassSrcAnchor -| \tikzumlAssocClassNodeName-middle.center) -- (\tikzumlAssocClassNodeName-middle.center) -- (\tikzumlAssocClassNodeName-middle.center |- \tikzumlAssocClassRelationNodeName\tikzumlAssocClassDestAnchor) --}%
+ }{%
+ \draw (\tikzumlAssocClassNodeName\tikzumlAssocClassSrcAnchor)+(\tikzumlAssocClassArm,0) node[name=\tikzumlAssocClassNodeName-tmp] {};
+ \edef\tikzumlnotepath{-- (\tikzumlAssocClassNodeName-tmp.center) |-}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlAssocClassGeometry}{|-|}}{%
+ \ifthenelse{\equal{\tikzumlAssocClassArm}{auto}}{%
+ \edef\tikzumlassocclasspath{-- (\tikzumlAssocClassNodeName\tikzumlAssocClassSrcAnchor |- \tikzumlAssocClassNodeName-middle.center) -- (\tikzumlAssocClassNodeName-middle.center) -- (\tikzumlAssocClassNodeName-middle.center -| \tikzumlAssocClassRelationNodeName\tikzumlAssocClassDestAnchor) --}%
+ }{%
+ \draw (\tikzumlAssocClassNodeName\tikzumlAssocClassSrcAnchor)+(0,\tikzumlAssocClassArm) node[name=\tikzumlAssocClassNodeName-tmp] {};
+ \edef\tikzumlassocclasspath{-- (\thetikzumlAssocClassNodeName-tmp.center) -|}%
+ }%
+
+ }{%
+ \errmessage{TIKZUML ERROR : Unknown geometry value !!! It should be in the following list : --, |-, -|, |-|, -|-}%
+ }%
+ }%
+ }%
+ %
+ \begin{pgfonlayer}{connections}%
+ \draw[dashed] (\tikzumlAssocClassNodeName\tikzumlAssocClassSrcAnchor) \tikzumlassocclasspath (\tikzumlAssocClassRelationNodeName\tikzumlAssocClassDestAnchor);%
+ \end{pgfonlayer}%
+ %
+ % add to fit
+ \ifnum\c@tikzumlPackageLevel>0%
+ \edef\tikzumlPackageFitOld{\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname}%
+ \ifthenelse{\equal{\tikzumlAssocClassTemplateParam}{}}{%
+ \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{\tikzumlPackageFitOld (\tikzumlAssocClassNodeName)(\tikzumlAssocClassNodeName-middle)}%
+ }{%
+ \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{\tikzumlPackageFitOld (\tikzumlAssocClassNodeName) (\tikzumlAssocClassNodeName-template)(\tikzumlAssocClassNodeName-middle)}%
+ }%
+ \stepcounter{tikzumlPackageClassNum}%
+ \fi%
+}%
+%
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% use case diagrams %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+\tikzstyle{tikzuml usecase style}=[ellipse, text centered]%
+\tikzstyle{tikzuml actor style}=[ellipse, inner sep=0, outer sep=0]%
+%
+\newcounter{tikzumlSystemUseCaseNum}%
+\newcounter{tikzumlSystemLevel}%
+\newcounter{tikzumlUseCaseNum}%
+\newcounter{tikzumlActorNum}%
+%
+\newif\iftikzumlusecaseWithoutCoords%
+\newif\iftikzumlactorWithoutCoords%
+%
+% define a system
+% arg : name
+% optional : x, y: coordinates of the system
+% draw, fill, text: colors
+\newenvironment{umlsystem}[2][]{%
+ \gdef\tikzumlSystemFit{}%
+ \def\tikzumlSystemName{#2}%
+ \setcounter{tikzumlSystemUseCaseNum}{0}%
+ %
+ \pgfkeys{/tikzuml/system/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX,%
+ draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlSystemDefaultFillColor,%
+ text/.initial=\tikzumlDefaultTextColor,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \errmessage{TIKZUML ERROR : in umlsystem, invalid option \keyname}%
+ }%
+ }%
+ %
+ \pgfkeys{/tikzuml/system/.cd, #1}%
+ \pgfkeys{/tikzuml/system/.cd, x/.get=\tikzumlSystemXShift, y/.get=\tikzumlSystemYShift,%
+ draw/.get=\tikzumlSystemDrawColor, fill/.get=\tikzumlSystemFillColor,%
+ text/.get=\tikzumlSystemTextColor}%
+ %
+ \stepcounter{tikzumlSystemLevel}%
+ %
+ \begin{scope}[xshift=\tikzumlSystemXShift cm, yshift=\tikzumlSystemYShift cm]%
+}{%
+ \addtocounter{tikzumlSystemLevel}{-1}%
+ % if contains no usecase, one define a fictive node to enable the fit option
+ \ifnum\c@tikzumlSystemUseCaseNum=0%
+ \node[inner xsep=10ex, inner ysep=1em] (\tikzumlSystemName-root) at (0,0) {};%
+ \xdef\tikzumlSystemFit{(\tikzumlSystemName-root)}%
+ \fi%
+ %
+ \begin{pgfonlayer}{background}%
+ \node[inner ysep=1em, inner xsep=2ex, fit = \tikzumlSystemFit] (\tikzumlSystemName-tmp) {};%
+ \node[text=\tikzumlSystemTextColor, font=\tikzumlDefaultFont] (\tikzumlSystemName-caption-tmp) at (\tikzumlSystemName-tmp.north) {\tikzumlSystemName};%
+ \node[draw=\tikzumlSystemDrawColor, fill=\tikzumlSystemFillColor, text=\tikzumlSystemTextColor, font=\tikzumlDefaultFont, inner ysep=1em, inner xsep=2ex, fit = (\tikzumlSystemName-tmp) (\tikzumlSystemName-caption-tmp)] (\tikzumlSystemName) {};%
+ \node[text=\tikzumlSystemTextColor, font=\tikzumlDefaultFont] (\tikzumlSystemName-caption) at (\tikzumlSystemName-caption-tmp.north) {\tikzumlSystemName};%
+ \end{pgfonlayer}%
+ \end{scope}%
+ %
+}%
+%
+% define a use case
+% arg : label of the use case
+% optional : x, y: coordinates of the use case
+% name: name of the node
+% width: node width
+% draw, fill, text: colors
+% style: to manage every default TikZ option
+% no coords: to tell that the use case position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlusecase}[2][]{%
+ \stepcounter{tikzumlUseCaseNum}%
+ \pgfkeys{/tikzuml/usecase/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=auto,%
+ name/.initial=usecase-\thetikzumlUseCaseNum,%
+ draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlUseCaseDefaultFillColor,%
+ text/.initial=\tikzumlDefaultTextColor, style/.style={},%
+ no coords/.is if=tikzumlusecaseWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/usecase/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/usecase/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/usecase/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlusecase, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/usecase/.cd, #1}%
+ \pgfkeys{/tikzuml/usecase/.cd, x/.get=\tikzumlUseCaseX, y/.get=\tikzumlUseCaseY, width/.get=\tikzumlUseCaseTextWidth,%
+ name/.get=\tikzumlUseCaseName,%
+ draw/.get=\tikzumlUseCaseDrawColor, fill/.get=\tikzumlUseCaseFillColor,%
+ text/.get=\tikzumlUseCaseTextColor%
+ }%
+ %
+ \def\tikzumlUseCaseText{#2}%
+ %
+ \def\tikzumlUseCasePos{\tikzumlUseCaseX,\tikzumlUseCaseY}%
+ %
+ \ifthenelse{\equal{\tikzumlUseCaseTextWidth}{auto}}{%
+ \iftikzumlusecaseWithoutCoords%
+ \node[tikzuml usecase style, draw=\tikzumlUseCaseDrawColor, fill=\tikzumlUseCaseFillColor, text=\tikzumlUseCaseTextColor, font=\tikzumlDefaultFont, /tikzuml/usecase/style] (\tikzumlUseCaseName) {\tikzumlUseCaseText};%
+ \else%
+ \node[tikzuml usecase style, draw=\tikzumlUseCaseDrawColor, fill=\tikzumlUseCaseFillColor, text=\tikzumlUseCaseTextColor, font=\tikzumlDefaultFont, /tikzuml/usecase/style] (\tikzumlUseCaseName) at (\tikzumlUseCasePos) {\tikzumlUseCaseText};%
+ \fi%
+ }{%
+ \iftikzumlusecaseWithoutCoords%
+ \node[tikzuml usecase style, draw=\tikzumlUseCaseDrawColor, fill=\tikzumlUseCaseFillColor, text=\tikzumlUseCaseTextColor, font=\tikzumlDefaultFont, text width=\tikzumlUseCaseTextWidth, /tikzuml/usecase/style] (\tikzumlUseCaseName) {\tikzumlUseCaseText};%
+ \else%
+ \node[tikzuml usecase style, draw=\tikzumlUseCaseDrawColor, fill=\tikzumlUseCaseFillColor, text=\tikzumlUseCaseTextColor, font=\tikzumlDefaultFont, text width=\tikzumlUseCaseTextWidth, /tikzuml/usecase/style] (\tikzumlUseCaseName) at (\tikzumlUseCasePos) {\tikzumlUseCaseText};%
+ \fi%
+ }%
+ %
+ % add to fit
+ \ifnum\c@tikzumlSystemLevel>0%
+ \let\tikzumlSystemFitOld\tikzumlSystemFit%
+ \xdef\tikzumlSystemFit{\tikzumlSystemFitOld (\tikzumlUseCaseName)}%
+ \stepcounter{tikzumlSystemUseCaseNum}%
+ \fi%
+}%
+%
+% define the actor symbol
+% optional : global tikzpicture styles
+\newcommand{\picturedactor}[1]{%
+ \pgfkeys{/tikzuml/picactor/.cd, scale/.initial=1, .unknown/.code={}}%
+ \pgfkeys{/tikzuml/picactor/.cd,#1}%
+ \pgfkeys{/tikzuml/picactor/.cd, scale/.get=\tikzumlPicturedActorScale}%
+ %
+ \begin{tikzpicture}[#1]%
+ \coordinate (head) at (0,4ex);%
+ \coordinate (left-hand) at (-2ex,2ex);%
+ \coordinate (right-hand) at (2ex,2ex);%
+ \coordinate (left-foot) at (-2ex,-2ex);%
+ \coordinate (right-foot) at (2ex,-2ex);%
+ \coordinate (empty) at (0,-3ex);%
+ \draw (empty) (0,0) -- (head);%
+ \draw (left-hand) -- (right-hand);%
+ \draw (0,0) -- (left-foot) (0,0) -- (right-foot);%
+ \node[fill, draw, circle, inner sep=\tikzumlPicturedActorScale*0.3333ex, minimum size=\tikzumlPicturedActorScale*2ex, anchor=base] at (head) {};%
+ \end{tikzpicture}%
+}%
+%
+% define an actor
+% arg : var name
+% optional : x, y: coordinates of the actor
+% scale: scale factor of the actor symbol
+% below: distance between the actor symbol and its name below
+% draw, text: colors
+% style: to manage every default TikZ option
+% no coords: to tell that the actor position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlactor}[2][]{%
+ \stepcounter{tikzumlActorNum}%
+ \pgfkeys{/tikzuml/actor/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, scale/.initial=1, below/.initial=\tikzumlActorDefaultBelow,%
+ draw/.initial=\tikzumlDefaultDrawColor, text/.initial=\tikzumlDefaultTextColor,%
+ style/.style={},%
+ no coords/.is if=tikzumlactorWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/actor/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/actor/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/actor/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlactor, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/actor/.cd, #1}%
+ \pgfkeys{/tikzuml/actor/.cd,%
+ x/.get=\tikzumlActorX, y/.get=\tikzumlActorY, scale/.get=\tikzumlActorScale,%
+ below/.get=\tikzumlActorBelow,%
+ draw/.get=\tikzumlActorDrawColor, text/.get=\tikzumlActorTextColor}%
+ %
+ \def\tikzumlActorName{#2}%
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlActorNodeName{\tikzumlActorName}}\x%
+ %
+ \def\tikzumlActorPos{\tikzumlActorX,\tikzumlActorY}%
+ %
+ \iftikzumlactorWithoutCoords%
+ \node[tikzuml actor style, text=\tikzumlActorTextColor, font=\tikzumlDefaultFont, /tikzuml/actor/style] (\tikzumlActorNodeName) {\picturedactor{scale=\tikzumlActorScale, fill=white, draw=\tikzumlActorDrawColor, thick}};%
+ \else%
+ \node[tikzuml actor style, text=\tikzumlActorTextColor, font=\tikzumlDefaultFont, /tikzuml/actor/style] (\tikzumlActorNodeName) at (\tikzumlActorPos) {\picturedactor{scale=\tikzumlActorScale, fill=white, draw=\tikzumlActorDrawColor, thick}};%
+ \fi%
+ \node[text=\tikzumlActorTextColor, font=\tikzumlDefaultFont, below=\tikzumlActorScale*\tikzumlActorBelow] at (\tikzumlActorNodeName) {\tikzumlActorName};%
+ %
+}%
+
+% shortcuts for include and extend relation
+\newcommand{\umlinclude}[3][]{%
+ \pgfkeys{/tikzuml/includerelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlinclude, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlinclude, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/includerelation/.cd, #1}%
+ \umlrelation[stereo=include, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+\newcommand{\umlextend}[3][]{%
+ \pgfkeys{/tikzuml/extendrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlextend, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlextend, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/extendrelation/.cd, #1}%
+ \umlrelation[stereo=extend, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlHVinclude}[3][]{%
+ \pgfkeys{/tikzuml/includerelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlHVinclude, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlHVinclude, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/includerelation/.cd, #1}%
+ \umlrelation[geometry=-|, stereo=include, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+\newcommand{\umlHVextend}[3][]{%
+ \pgfkeys{/tikzuml/extendrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlHVextend, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlHVextend, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/extendrelation/.cd, #1}%
+ \umlrelation[geometry=-|, stereo=extend, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlVHinclude}[3][]{%
+ \pgfkeys{/tikzuml/includerelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlVHinclude, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlVHinclude, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/includerelation/.cd, #1}%
+ \umlrelation[geometry=|-, stereo=include, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+\newcommand{\umlVHextend}[3][]{%
+ \pgfkeys{/tikzuml/extendrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR :in umlVHextend, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlVHextend, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/extendrelation/.cd, #1}%
+ \umlrelation[geometry=|-, stereo=extend, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlHVHinclude}[3][]{%
+ \pgfkeys{/tikzuml/includerelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlHVHinclude, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlHVHinclude, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/includerelation/.cd, #1}%
+ \umlrelation[geometry=-|-, stereo=include, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+\newcommand{\umlHVHextend}[3][]{%
+ \pgfkeys{/tikzuml/extendrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlHVHextend, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlHVHextend, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/extendrelation/.cd, #1}%
+ \umlrelation[geometry=-|-, stereo=extend, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlVHVinclude}[3][]{%
+ \pgfkeys{/tikzuml/includerelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlVHVinclude, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlVHVinclude, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/includerelation/.cd, #1}%
+ \umlrelation[geometry=|-|, stereo=include, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+\newcommand{\umlVHVextend}[3][]{%
+ \pgfkeys{/tikzuml/extendrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlVHVextend, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlVHVextend, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/extendrelation/.cd, #1}%
+ \umlrelation[geometry=|-|, stereo=extend, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlCNinclude}[4][]{%
+ \pgfkeys{/tikzuml/includerelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlCNinclude, forbidden option stereo}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/includerelation/.cd, #1}%
+ \umlCNrelation[stereo=include, style={tikzuml dependency style}, #1]{#2}{#3}{#4}%
+}%
+\newcommand{\umlCNextend}[4][]{%
+ \pgfkeys{/tikzuml/extendrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlCNextend, forbidden option stereo}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/extendrelation/.cd, #1}%
+ \umlCNrelation[stereo=extend, style={tikzuml dependency style}, #1]{#2}{#3}{#4}%
+}%
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% state diagrams %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+\tikzstyle{tikzuml state style}=[rectangle split, rectangle split parts=2, rounded corners, inner xsep=1.5ex]%
+\tikzstyle{tikzuml transition style}=[color=\tikzumlDefaultDrawColor, rounded corners, -angle 45]%
+%
+\newcounter{tikzumlStateJoinNum}%
+\newcounter{tikzumlStateDecisionNum}%
+\newcounter{tikzumlStateInitialNum}%
+\newcounter{tikzumlStateFinalNum}%
+\newcounter{tikzumlStateEnterNum}%
+\newcounter{tikzumlStateExitNum}%
+\newcounter{tikzumlStateEndNum}%
+\newcounter{tikzumlStateHistoryNum}%
+\newcounter{tikzumlStateDeepHistoryNum}%
+\newcounter{tikzumlStateLevel}%
+\newcounter{tikzumlStateSubStateNum}%
+\newcounter{tikzumlStateText}%
+%
+\newif\iftikzumlstatejoinWithoutCoords%
+\newif\iftikzumlstatedecisionWithoutCoords%
+\newif\iftikzumlstateinitialWithoutCoords%
+\newif\iftikzumlstatefinalWithoutCoords%
+\newif\iftikzumlstateenterWithoutCoords%
+\newif\iftikzumlstateexitWithoutCoords%
+\newif\iftikzumlstateendWithoutCoords%
+\newif\iftikzumlstatehistoryWithoutCoords%
+\newif\iftikzumlstatedeephistoryWithoutCoords%
+\newif\iftikzumlstateWithoutCoords%
+%
+% define a uml join state
+% args : name of the state
+% optional : x,y: coordinates of the state
+% width: width of the state node
+% name: name of the state node
+% color: color of the join symbol
+% style: to manage every default TikZ option
+% no coords: to tell that the state position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlstatejoin}[1][]{%
+ \pgfkeys{/tikzuml/statejoin/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateJoinDefaultWidth,%
+ name/.initial=statejoin-\thetikzumlStateJoinNum,%
+ color/.initial=\tikzumlDefaultDrawColor, style/.style={},%
+ no coords/.is if=tikzumlstatejoinWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/statejoin/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/statejoin/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/statejoin/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlstatejoin, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/statejoin/.cd, #1}%
+ \pgfkeys{/tikzuml/statejoin/.cd, x/.get=\tikzumlStateJoinX, y/.get=\tikzumlStateJoinY, width/.get=\tikzumlStateJoinMinimumWidth,%
+ name/.get=\tikzumlStateJoinName, color/.get=\tikzumlStateJoinColor%
+ }%
+ %
+ \def\tikzumlStateJoinPos{\tikzumlStateJoinX,\tikzumlStateJoinY}%
+ %
+ \iftikzumlstatejoinWithoutCoords%
+ \node[circle, minimum size=\tikzumlStateJoinMinimumWidth, draw=\tikzumlStateJoinColor, fill=\tikzumlStateJoinColor, /tikzuml/statejoin/style] (\tikzumlStateJoinName) {};%
+ \else%
+ \node[circle, minimum size=\tikzumlStateJoinMinimumWidth, draw=\tikzumlStateJoinColor, fill=\tikzumlStateJoinColor, /tikzuml/statejoin/style] (\tikzumlStateJoinName) at (\tikzumlStateJoinPos) {};%
+ \fi%
+ %
+ % add to fit
+ \ifnum\c@tikzumlStateLevel>0%
+ \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlStateJoinName)}%
+ \stepcounter{tikzumlStateSubStateNum}%
+ \fi%
+ \stepcounter{tikzumlStateJoinNum}%
+}%
+%
+% define a uml decision state
+% args : name of the state
+% optional : x,y: coordinates of the state
+% width: width of the state node
+% name: name of the state node
+% color: color of the join symbol
+% style: to manage every default TikZ option
+% no coords: to tell that the state position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlstatedecision}[1][]{%
+ \pgfkeys{/tikzuml/statedecision/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateDecisionDefaultWidth,%
+ name/.initial=statedecision-\thetikzumlStateDecisionNum,%
+ color/.initial=\tikzumlDefaultDrawColor, style/.style={},%
+ no coords/.is if=tikzumlstatedecisionWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/statedecision/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/statedecision/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/statedecision/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlstatedecision, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/statedecision/.cd, #1}%
+ \pgfkeys{/tikzuml/statedecision/.cd, x/.get=\tikzumlStateDecisionX, y/.get=\tikzumlStateDecisionY, width/.get=\tikzumlStateDecisionMinimumWidth,%
+ name/.get=\tikzumlStateDecisionName, color/.get=\tikzumlStateDecisionColor%
+ }%
+ %
+ \def\tikzumlStateDecisionPos{\tikzumlStateDecisionX,\tikzumlStateDecisionY}%
+ %
+ \iftikzumlstatedecisionWithoutCoords%
+ \node[rectangle, rotate=45, minimum size=\tikzumlStateDecisionMinimumWidth, draw=\tikzumlStateDecisionColor, /tikzuml/statedecision/style] (\tikzumlStateDecisionName) {};%
+ \else%
+ \node[rectangle, rotate=45, minimum size=\tikzumlStateDecisionMinimumWidth, draw=\tikzumlStateDecisionColor, /tikzuml/statedecision/style] (\tikzumlStateDecisionName) at (\tikzumlStateDecisionPos) {};%
+ \fi%
+ %
+ % add to fit
+ \ifnum\c@tikzumlStateLevel>0%
+ \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlStateDecisionName)}%
+ \stepcounter{tikzumlStateSubStateNum}%
+ \fi%
+ \stepcounter{tikzumlStateDecisionNum}%
+}%
+%
+% define a uml initial state
+% args : name of the state
+% optional : x,y: coordinates of the state
+% width: width of the state node
+% name: name of the state node
+% entry, do, exit: entry/do/exit action of the state
+% color: color of the join symbol
+% style: to manage every default TikZ option
+% no coords: to tell that the state position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlstateinitial}[1][]{%
+ \pgfkeys{/tikzuml/stateinitial/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateInitialDefaultWidth,%
+ name/.initial=stateinitial-\thetikzumlStateInitialNum,%
+ color/.initial=\tikzumlDefaultDrawColor, style/.style={},%
+ no coords/.is if=tikzumlstateinitialWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/stateinitial/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/stateinitial/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/stateinitial/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlstateinitial, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/stateinitial/.cd, #1}%
+ \pgfkeys{/tikzuml/stateinitial/.cd, x/.get=\tikzumlStateInitialX, y/.get=\tikzumlStateInitialY, width/.get=\tikzumlStateInitialMinimumWidth,%
+ name/.get=\tikzumlStateInitialName, color/.get=\tikzumlStateInitialColor%
+ }%
+ %
+ \def\tikzumlStateInitialPos{\tikzumlStateInitialX,\tikzumlStateInitialY}%
+ %
+ \iftikzumlstateinitialWithoutCoords%
+ \node[circle, minimum size=\tikzumlStateInitialMinimumWidth, fill=\tikzumlStateInitialColor, /tikzuml/stateinitial/style] (\tikzumlStateInitialName) {};%
+ \else%
+ \node[circle, minimum size=\tikzumlStateInitialMinimumWidth, fill=\tikzumlStateInitialColor, /tikzuml/stateinitial/style] (\tikzumlStateInitialName) at (\tikzumlStateInitialPos) {};%
+ \fi%
+ %
+ % add to fit
+ \ifnum\c@tikzumlStateLevel>0%
+ \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlStateInitialName)}%
+ \stepcounter{tikzumlStateSubStateNum}%
+ \fi%
+ \stepcounter{tikzumlStateInitialNum}%
+}%
+%
+% define a uml final state
+% args : name of the state
+% optional : x,y: coordinates of the state
+% width: width of the state node
+% name: name of the state node
+% color: color of the join symbol
+% style: to manage every default TikZ option
+% no coords: to tell that the state position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlstatefinal}[1][]{%
+ \pgfkeys{/tikzuml/statefinal/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateFinalDefaultWidth,%
+ name/.initial=statefinal-\thetikzumlStateFinalNum,%
+ color/.initial=\tikzumlDefaultDrawColor, style/.style={},%
+ no coords/.is if=tikzumlstatefinalWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/statefinal/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/statefinal/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/statefinal/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlstatefinal, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/statefinal/.cd, #1}%
+ \pgfkeys{/tikzuml/statefinal/.cd, x/.get=\tikzumlStateFinalX, y/.get=\tikzumlStateFinalY, width/.get=\tikzumlStateFinalMinimumWidth,%
+ name/.get=\tikzumlStateFinalName, color/.get=\tikzumlStateFinalColor%
+ }%
+ %
+ \def\tikzumlStateFinalPos{\tikzumlStateFinalX,\tikzumlStateFinalY}%
+ %
+ \iftikzumlstatefinalWithoutCoords%
+ \node[circle, minimum size=\tikzumlStateFinalMinimumWidth, draw=\tikzumlStateFinalColor, fill=\tikzumlStateFinalColor, double, double distance=0.1cm, /tikzuml/statefinal/style] (\tikzumlStateFinalName) {};%
+ \else%
+ \node[circle, minimum size=\tikzumlStateFinalMinimumWidth, draw=\tikzumlStateFinalColor, fill=\tikzumlStateFinalColor, double, double distance=0.1cm, /tikzuml/statefinal/style] (\tikzumlStateFinalName) at (\tikzumlStateFinalPos) {};%
+ \fi%
+ %
+ % add to fit
+ \ifnum\c@tikzumlStateLevel>0%
+ \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlStateFinalName)}%
+ \stepcounter{tikzumlStateSubStateNum}%
+ \fi%
+ \stepcounter{tikzumlStateFinalNum}%
+}%
+%
+% define a uml enter state
+% args : name of the state
+% optional : x,y: coordinates of the state
+% width: width of the state node
+% name: name of the state node
+% color: color of the join symbol
+% style: to manage every default TikZ option
+% no coords: to tell that the state position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlstateenter}[1][]{%
+ \pgfkeys{/tikzuml/stateenter/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateEnterDefaultWidth,%
+ name/.initial=stateenter-\thetikzumlStateEnterNum,%
+ color/.initial=\tikzumlDefaultDrawColor, style/.style={},%
+ no coords/.is if=tikzumlstateenterWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/stateenter/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/stateenter/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/stateenter/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlstateenter, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/stateenter/.cd, #1}%
+ \pgfkeys{/tikzuml/stateenter/.cd, x/.get=\tikzumlStateEnterX, y/.get=\tikzumlStateEnterY, width/.get=\tikzumlStateEnterMinimumWidth,%
+ name/.get=\tikzumlStateEnterName, color/.get=\tikzumlStateEnterColor%
+ }%
+ %
+ \def\tikzumlStateEnterPos{\tikzumlStateEnterX,\tikzumlStateEnterY}%
+ %
+ \iftikzumlstateenterWithoutCoords%
+ \node[circle, minimum size=\tikzumlStateEnterMinimumWidth, draw=\tikzumlStateEnterColor, /tikzuml/stateenter/style] (\tikzumlStateEnterName) {};%
+ \else%
+ \node[circle, minimum size=\tikzumlStateEnterMinimumWidth, draw=\tikzumlStateEnterColor, /tikzuml/stateenter/style] (\tikzumlStateEnterName) at (\tikzumlStateEnterPos) {};%
+ \fi%
+ %
+ % add to fit
+ \ifnum\c@tikzumlStateLevel>0%
+ \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlStateEnterName)}%
+ \stepcounter{tikzumlStateSubStateNum}%
+ \fi%
+ \stepcounter{tikzumlStateEnterNum}%
+}%
+%
+% define a uml exit state
+% args : name of the state
+% optional : x,y: coordinates of the state
+% width: width of the state node
+% name: name of the state node
+% color: color of the join symbol
+% style: to manage every default TikZ option
+% no coords: to tell that the state position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlstateexit}[1][]{%
+ \pgfkeys{/tikzuml/stateexit/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateExitDefaultWidth,%
+ name/.initial=stateexit-\thetikzumlStateExitNum,%
+ color/.initial=\tikzumlDefaultDrawColor, style/.style={},%
+ no coords/.is if=tikzumlstateexitWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/stateexit/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/stateexit/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/stateexit/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlstateexit, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/stateexit/.cd, #1}%
+ \pgfkeys{/tikzuml/stateexit/.cd, x/.get=\tikzumlStateExitX, y/.get=\tikzumlStateExitY, width/.get=\tikzumlStateExitMinimumWidth,%
+ name/.get=\tikzumlStateExitName, color/.get=\tikzumlStateExitColor%
+ }%
+ %
+ \def\tikzumlStateExitPos{\tikzumlStateExitX,\tikzumlStateExitY}%
+ %
+ \iftikzumlstateexitWithoutCoords%
+ \node[circle, minimum size=\tikzumlStateExitMinimumWidth, draw=\tikzumlStateExitColor, /tikzuml/stateexit/style] (\tikzumlStateExitName) {};%
+ \else%
+ \node[circle, minimum size=\tikzumlStateExitMinimumWidth, draw=\tikzumlStateExitColor, /tikzuml/stateexit/style] (\tikzumlStateExitName) at (\tikzumlStateExitPos) {};%
+ \fi%
+ \draw[draw=\tikzumlStateExitColor] (\tikzumlStateExitName.north east) -- (\tikzumlStateExitName.south west) (\tikzumlStateExitName.north west) -- (\tikzumlStateExitName.south east);
+ %
+ % add to fit
+ \ifnum\c@tikzumlStateLevel>0%
+ \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlStateExitName)}%
+ \stepcounter{tikzumlStateSubStateNum}%
+ \fi%
+ \stepcounter{tikzumlStateExitNum}%
+}%
+%
+% define a uml end state
+% args : name of the state
+% optional : x,y: coordinates of the state
+% width: width of the state node
+% name: name of the state node
+% color: color of the join symbol
+% style: to manage every default TikZ option
+% no coords: to tell that the state position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlstateend}[1][]{%
+ \pgfkeys{/tikzuml/stateend/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateEndDefaultWidth,%
+ name/.initial=stateend-\thetikzumlStateEndNum,%
+ color/.initial=\tikzumlDefaultDrawColor, style/.style={},%
+ no coords/.is if=tikzumlstateendWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/stateend/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/stateend/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/stateend/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlstateend, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/stateend/.cd, #1}%
+ \pgfkeys{/tikzuml/stateend/.cd, x/.get=\tikzumlStateEndX, y/.get=\tikzumlStateEndY, width/.get=\tikzumlStateEndMinimumWidth,%
+ name/.get=\tikzumlStateEndName, color/.get=\tikzumlStateEndColor%
+ }%
+ %
+ \def\tikzumlStateEndPos{\tikzumlStateEndX,\tikzumlStateEndY}%
+ %
+ \iftikzumlstateendWithoutCoords%
+ \node[circle, minimum size=\tikzumlStateEndMinimumWidth, /tikzuml/stateend/style] (\tikzumlStateEndName) {};%
+ \else%
+ \node[circle, minimum size=\tikzumlStateEndMinimumWidth, /tikzuml/stateend/style] (\tikzumlStateEndName) at (\tikzumlStateEndPos) {};%
+ \fi%
+ \draw[draw=\tikzumlStateEndColor] (\tikzumlStateEndName.north east) -- (\tikzumlStateEndName.south west) (\tikzumlStateEndName.north west) -- (\tikzumlStateEndName.south east);
+ %
+ % add to fit
+ \ifnum\c@tikzumlStateLevel>0%
+ \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlStateEndName)}%
+ \stepcounter{tikzumlStateSubStateNum}%
+ \fi%
+ \stepcounter{tikzumlStateEndNum}%
+}%
+%
+\newcommand{\picturedhistory}[1]{%
+ \begin{tikzpicture}[#1]%
+ \draw[thick] (-0.1cm,-0.15cm) -- (-0.1cm,0.15cm)
+ (-0.1cm,0) -- (0.1cm,0)
+ (0.1cm,-0.15cm) -- (0.1cm,0.15cm);%
+ \end{tikzpicture}%
+}%
+%
+% define a uml history state
+% args : name of the state
+% optional : x,y: coordinates of the state
+% width: width of the state node
+% name: name of the state node
+% color: color of the join symbol
+% style: to manage every default TikZ option
+% no coords: to tell that the state position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlstatehistory}[1][]{%
+ \pgfkeys{/tikzuml/statehistory/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateHistoryDefaultWidth,%
+ name/.initial=statehistory-\thetikzumlStateHistoryNum,%
+ color/.initial=\tikzumlDefaultDrawColor, style/.style={},%
+ no coords/.is if=tikzumlstatehistoryWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/statehistory/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/statehistory/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/statehistory/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlstatehistory, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/statehistory/.cd, #1}%
+ \pgfkeys{/tikzuml/statehistory/.cd, x/.get=\tikzumlStateHistoryX, y/.get=\tikzumlStateHistoryY, width/.get=\tikzumlStateHistoryMinimumWidth,%
+ name/.get=\tikzumlStateHistoryName, color/.get=\tikzumlStateHistoryColor%
+ }%
+ %
+ \def\tikzumlStateHistoryPos{\tikzumlStateHistoryX,\tikzumlStateHistoryY}%
+ %
+ \iftikzumlstatehistoryWithoutCoords%
+ \node[circle, minimum size=\tikzumlStateHistoryMinimumWidth, draw=\tikzumlStateHistoryColor, /tikzuml/statehistory/style] (\tikzumlStateHistoryName) {\picturedhistory{draw=\tikzumlStateHistoryColor}};%
+ \else%
+ \node[circle, minimum size=\tikzumlStateHistoryMinimumWidth, draw=\tikzumlStateHistoryColor, /tikzuml/statehistory/style] (\tikzumlStateHistoryName) at (\tikzumlStateHistoryPos) {\picturedhistory{draw=\tikzumlStateHistoryColor}};%
+ \fi%
+ %
+ % add to fit
+ \ifnum\c@tikzumlStateLevel>0%
+ \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlStateHistoryName)}%
+ \stepcounter{tikzumlStateSubStateNum}%
+ \fi%
+ \stepcounter{tikzumlStateHistoryNum}%
+}%
+%
+\newcommand{\pictureddeephistory}[1]{%
+ \begin{tikzpicture}[#1]%
+ \draw[thick] (-0.1cm,-0.15cm) -- (-0.1cm,0.15cm)
+ (-0.1cm,0) -- (0.1cm,0)
+ (0.1cm,-0.15cm) -- (0.1cm,0.15cm)
+ (0.23cm,0.19cm) -- (0.23cm,0.11cm)
+ (0.20cm,0.17cm) -- (0.26cm,0.13cm)
+ (0.20cm,0.13cm) -- (0.26cm,0.17cm);%
+ \end{tikzpicture}%
+}%
+%
+% define a uml deep-history state
+% args : name of the state
+% optional : x,y: coordinates of the state
+% width: width of the state node
+% name: name of the state node
+% color: color of the join symbol
+% style: to manage every default TikZ option
+% no coords: to tell that the state position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlstatedeephistory}[1][]{%
+ \pgfkeys{/tikzuml/statedeephistory/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateDeepHistoryDefaultWidth,%
+ name/.initial=statedeephistory-\thetikzumlStateDeepHistoryNum,%
+ color/.initial=\tikzumlDefaultDrawColor, style/.style={},%
+ no coords/.is if=tikzumlstatedeephistoryWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/statedeephistory/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/statedeephistory/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/statedeephistory/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlstatedeephistory, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/statedeephistory/.cd, #1}%
+ \pgfkeys{/tikzuml/statedeephistory/.cd, x/.get=\tikzumlStateDeepHistoryX, y/.get=\tikzumlStateDeepHistoryY, width/.get=\tikzumlStateDeepHistoryMinimumWidth,%
+ name/.get=\tikzumlStateDeepHistoryName, color/.get=\tikzumlStateDeepHistoryColor%
+ }%
+ %
+ \def\tikzumlStateDeepHistoryPos{\tikzumlStateDeepHistoryX,\tikzumlStateDeepHistoryY}%
+ %
+ \iftikzumlstatedeephistoryWithoutCoords%
+ \node[circle, minimum size=\tikzumlStateDeepHistoryMinimumWidth, draw=\tikzumlStateDeepHistoryColor, /tikzuml/statedeephistory/style] (\tikzumlStateDeepHistoryName) {\pictureddeephistory{draw=\tikzumlStateDeepHistoryColor}};%
+ \else%
+ \node[circle, minimum size=\tikzumlStateDeepHistoryMinimumWidth, draw=\tikzumlStateDeepHistoryColor, /tikzuml/statedeephistory/style] (\tikzumlStateDeepHistoryName) at (\tikzumlStateDeepHistoryPos) {\pictureddeephistory{draw=\tikzumlStateDeepHistoryColor}};%
+ \fi%
+ %
+ % add to fit
+ \ifnum\c@tikzumlStateLevel>0%
+ \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlStateDeepHistoryName)}%
+ \stepcounter{tikzumlStateSubStateNum}%
+ \fi%
+ \stepcounter{tikzumlStateDeepHistoryNum}%
+}%
+%
+% define a uml state
+% args : name of the state
+% content of the state
+% optional : x,y: coordinates of the state
+% width: width of the state node
+% name: name of the state node
+% entry, do, exit: entry/do/exit action of the state
+% draw, fill, text: colors
+% style: to manage every default TikZ option
+% no coords: to tell that the state position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newenvironment{umlstate}[2][]{%
+ \ifnum\thetikzumlStateLevel>0%
+ \let\tikzumlState@nameold\tikzumlState@fitname%
+ \let\tikzumlState@parentold\tikzumlState@parent%
+ \edef\tikzumlState@parent{\tikzumlState@parentold @@\tikzumlState@nameold}%
+ \else%
+ \def\tikzumlState@parent{}%
+ \fi%
+ %
+ \stepcounter{tikzumlStateLevel}%
+ %
+ \pgfkeys{/tikzuml/state/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateDefaultWidth,%
+ name/.initial={},%
+ entry/.initial={}, do/.initial={}, exit/.initial={},%
+ draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlStateDefaultFillColor,%
+ text/.initial=\tikzumlDefaultTextColor, style/.style={},%
+ no coords/.is if=tikzumlstateWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/state/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/state/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/state/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ % \errmessage{TIKZUML ERROR : in umlstate, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/state/.cd, #1}%
+ \pgfkeys{/tikzuml/state/.cd, x/.get=\tikzumlStateXShift, y/.get=\tikzumlStateYShift, width/.get=\tikzumlStateMinimumWidth, name/.get=\tikzumlStateName,%
+ entry/.get=\tikzumlStateEntry, do/.get=\tikzumlStateDo, exit/.get=\tikzumlStateExit,%
+ draw/.get=\tikzumlStateDrawColor, fill/.get=\tikzumlStateFillColor,%
+ text/.get=\tikzumlStateTextColor%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlStateName}{}}{%
+ \edef\tikzumlState@name{#2}%
+ }{%
+ \edef\tikzumlState@name{\tikzumlStateName}%
+ }%
+ %
+ \begingroup%
+ \def\_{@}\edef\x{\endgroup%
+ \def\noexpand\tikzumlState@fitname{\tikzumlState@name}}\x%
+ %
+ \let\tikzumlState@nodeNameold\tikzumlState@nodeName%
+ \def\tikzumlState@caption{#2}%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlState@nodeName{\tikzumlState@name}}\x%
+ %
+ \expandafter\gdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{}%
+ %
+ \setcounter{tikzumlStateSubStateNum}{0}%
+ \setcounter{tikzumlStateText}{0}%
+ %
+ \def\tikzumlStateText{tikzumlEmpty}%
+ \begin{scope}[xshift=\tikzumlStateXShift cm, yshift=\tikzumlStateYShift cm]%
+}{%
+ %
+ \def\tikzumlstaterootlabel{\phantom{\tikzumlState@nodeName}}%
+ %
+ \def\tikzumlstaterootinnerysep{0.5ex}%
+ \def\tikzumlstatebodyinnerysep{2ex}%
+ %
+ \ifthenelse{\equal{\tikzumlStateEntry}{}}{}{%
+ \ifnum\c@tikzumlStateText=0%
+ \def\tikzumlStateText{entry/\tikzumlStateEntry}%
+ \else%
+ \let\tikzumlStateTextOld\tikzumlStateText%
+ \ifthenelse{\equal{\tikzumlStateText}{tikzumlEmpty}}{%
+ \def\tikzumlStateText{entry/\tikzumlStateEntry}%
+ }{%
+ \expandafter\def\expandafter\tikzumlStateText\expandafter{\tikzumlStateTextOld \\ entry/\tikzumlStateEntry}%
+ }%
+ \fi%
+ \setcounter{tikzumlStateText}{1}%
+ \ifnum\c@tikzumlStateSubStateNum=0%
+ \def\tikzumlstatebodyinnerysep{0}%
+ \def\tikzumlstaterootinnerysep{0}%
+ \fi%
+ }%
+ \ifthenelse{\equal{\tikzumlStateDo}{}}{}{%
+ \ifnum\c@tikzumlStateText=0%
+ \def\tikzumlStateText{do/\tikzumlStateDo}%
+ \else%
+ \let\tikzumlStateTextOld\tikzumlStateText%
+ \ifthenelse{\equal{\tikzumlStateText}{tikzumlEmpty}}{%
+ \def\tikzumlStateText{do/\tikzumlStateDo}%
+ }{%
+ \expandafter\def\expandafter\tikzumlStateText\expandafter{\tikzumlStateTextOld \\ do/\tikzumlStateDo}%
+ }%
+ \fi%
+ \setcounter{tikzumlStateText}{1}%
+ \ifnum\c@tikzumlStateSubStateNum=0%
+ \def\tikzumlstatebodyinnerysep{0}%
+ \def\tikzumlstaterootinnerysep{0}%
+ \fi%
+ }%
+ \ifthenelse{\equal{\tikzumlStateExit}{}}{}{%
+ \ifnum\c@tikzumlStateText=0%
+ \def\tikzumlStateText{exit/\tikzumlStateExit}%
+ \else%
+ \let\tikzumlStateTextOld\tikzumlStateText%
+ \ifthenelse{\equal{\tikzumlStateText}{tikzumlEmpty}}{%
+ \def\tikzumlStateText{exit/\tikzumlStateExit}%
+ }{%
+ \expandafter\def\expandafter\tikzumlStateText\expandafter{\tikzumlStateTextOld \\ exit/\tikzumlStateExit}%
+ }%
+ \fi%
+ \setcounter{tikzumlStateText}{1}%
+ \ifnum\c@tikzumlStateSubStateNum=0%
+ \def\tikzumlstatebodyinnerysep{0}%
+ \def\tikzumlstaterootinnerysep{0}%
+ \fi%
+ }%
+ %
+ \addtocounter{tikzumlStateLevel}{-1}%
+ \begin{pgfonlayer}{state\thetikzumlStateLevel}%
+ %
+ % if contains nothing, one define a fictive node to enable the fit option
+ \ifnum\c@tikzumlStateSubStateNum=0%
+ \iftikzumlstateWithoutCoords%
+ \node[inner ysep=\tikzumlstaterootinnerysep, minimum width=\tikzumlStateMinimumWidth, /tikzuml/state/style] (\tikzumlState@nodeName-root) {\tikzumlstaterootlabel};%
+ \else%
+ \node[inner ysep=\tikzumlstaterootinnerysep, minimum width=\tikzumlStateMinimumWidth, /tikzuml/state/style] (\tikzumlState@nodeName-root) at (0,0) {\tikzumlstaterootlabel};%
+ \fi%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{(\tikzumlState@nodeName-root)}%
+ \fi%
+ %
+ \ifnum\c@tikzumlStateLevel>0%
+ \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent\endcsname{\tikzumlStateFitTmp (\tikzumlState@nodeName-body) (\tikzumlState@nodeName-caption)}%
+ \stepcounter{tikzumlStateSubStateNum}%
+ \fi%
+ %
+ \node[inner xsep=2ex, inner ysep=\tikzumlstatebodyinnerysep, fit = \csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname, /tikzuml/state/style ] (\tikzumlState@nodeName-body) {};%
+ \def\tikzumlState@orig{body}%
+ \ifnum\c@tikzumlStateText=1%
+ \node[above=0] (\tikzumlState@nodeName-texttmp) at (\tikzumlState@nodeName-\tikzumlState@orig.north) {\begin{tabular}{l}\tikzumlStateText \end{tabular}};%
+ \def\tikzumlState@orig{texttmp}%
+ \fi%
+ \node[above] (\tikzumlState@nodeName-captiontmp) at (\tikzumlState@nodeName-\tikzumlState@orig.north) {\tikzumlState@caption};%
+ \ifnum\c@tikzumlStateText=1%
+ \node[rounded corners, draw=\tikzumlStateDrawColor, fill=\tikzumlStateFillColor, name=\tikzumlState@nodeName, fit=(\tikzumlState@nodeName-body) (\tikzumlState@nodeName-texttmp) (\tikzumlState@nodeName-captiontmp)] {};%
+ \else%
+ \node[rounded corners, draw=\tikzumlStateDrawColor, fill=\tikzumlStateFillColor, name=\tikzumlState@nodeName, fit=(\tikzumlState@nodeName-body) (\tikzumlState@nodeName-captiontmp)] {};%
+ \fi%
+ \ifnum\c@tikzumlStateText=1%
+ \node (\tikzumlState@nodeName-text) at (\tikzumlState@nodeName-texttmp) {\begin{tabular}{l}\tikzumlStateText \end{tabular}};%
+ \fi%
+ \node (\tikzumlState@nodeName-caption) at (\tikzumlState@nodeName-captiontmp) {\tikzumlState@caption};%
+ \draw (\tikzumlState@nodeName-caption.south -| \tikzumlState@nodeName.north west) -- (\tikzumlState@nodeName-caption.south -| \tikzumlState@nodeName.north east);%
+ \end{pgfonlayer}%
+ \end{scope}%
+}%
+%
+% shortcut for empty state
+\newcommand{\umlbasicstate}[2][]{\begin{umlstate}[#1]{#2}\end{umlstate}}%
+%
+% command to add text in a state, to be used inside umlstate environment
+\newcommand{\umlstatetext}[1]{%
+ \def\tikzumlStateText{#1}%
+ \setcounter{tikzumlStateText}{1}%
+}%
+%
+% shortcuts for state transitions macros
+\newcommand{\umltrans}[3][]{%
+ \ifthenelse{\equal{#2}{#3}}{%
+ \umlrelation[style={tikzuml transition style}, recursive mode=transition, #1]{#2}{#3}%
+ }{%
+ \umlrelation[style={tikzuml transition style}, #1]{#2}{#3}%
+ }%
+}%
+\newcommand{\umlHVtrans}[3][]{\umlHVrelation[style={tikzuml transition style}, #1]{#2}{#3}}%
+\newcommand{\umlVHtrans}[3][]{\umlVHrelation[style={tikzuml transition style}, #1]{#2}{#3}}%
+\newcommand{\umlVHVtrans}[3][]{\umlVHVrelation[style={tikzuml transition style}, #1]{#2}{#3}}%
+\newcommand{\umlHVHtrans}[3][]{\umlHVHrelation[style={tikzuml transition style}, #1]{#2}{#3}}%
+\newcommand{\umlCNtrans}[4][]{\umlCNrelation[style={tikzuml transition style}, #1]{#2}{#3}{#4}}%
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% sequence diagrams %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+\tikzstyle{tikzuml synchron-msg style}=[color=\tikzumlDefaultDrawColor, -triangle 45]%
+\tikzstyle{tikzuml asynchron-msg style}=[color=\tikzumlDefaultDrawColor, -angle 45]%
+\tikzstyle{tikzuml return-msg style}=[color=\tikzumlDefaultDrawColor, dashed, -angle 45]%
+\tikzstyle{tikzuml call return style}=[color=\tikzumlDefaultDrawColor, dashed, -angle 45]%
+\tikzstyle{tikzuml activity style}=[inner xsep=1ex, inner ysep=1ex]%
+%
+\newcounter{tikzumlObjectNum}%
+\newcounter{tikzumlCallLevel}%
+\newcounter{tikzumlCallNum}%
+\newcounter{tikzumlFragmentLevel}%
+\newcounter{tikzumlFragmentLevelNum}%
+\newcounter{tikzumlFragmentNum}%
+\newcounter{tikzumlFragmentPartNum}%
+\newcounter{tikzumlCallStartFragmentNum}%
+\newcounter{tikzumlCallEndFragmentNum}%
+%
+\newif\iftikzumlobjectNoDDots%
+\newif\iftikzumlcreatecallNoDDots%
+%
+% define a sequence diagram
+%
+\newenvironment{umlseqdiag}{%
+ \gdef\tikzumlInCreateCall{0}%
+ \setcounter{tikzumlObjectNum}{0}%
+ \setcounter{tikzumlCallLevel}{0}%
+ \setcounter{tikzumlCallNum}{0}%
+ \setcounter{tikzumlFragmentLevel}{0}%
+ \setcounter{tikzumlFragmentLevelNum}{0}%
+ \setcounter{tikzumlFragmentNum}{0}%
+ \setcounter{tikzumlFragmentPartNum}{0}%
+ \setcounter{tikzumlCallStartFragmentNum}{0}%
+ \setcounter{tikzumlCallEndFragmentNum}{0}%
+ %
+ \ifx \@umlactor \@empty
+ \newcommand{\umlactor}[2][]{%
+ \pgfkeys{/tikzuml/actorobj/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlactor, forbidden option stereo}%
+ }{}%
+ }%
+ }%
+ %
+ \pgfkeys{/tikzuml/actorobj/.cd, ##1}%
+ \umlobject[stereo=actor, ##1]{##2}%
+ }%
+ \else%
+ \renewcommand{\umlactor}[2][]{%
+ \pgfkeys{/tikzuml/actorobj/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlactor, forbidden option stereo}%
+ }{}%
+ }%
+ }%
+ %
+ \pgfkeys{/tikzuml/actorobj/.cd, ##1}%
+ \umlobject[stereo=actor, ##1]{##2}%
+ }%
+ \fi%
+ \begin{scope}[font=\tikzumlDefaultFont]%
+}{%
+ % draw lifelines of each object
+ \begin{pgfonlayer}{lifelines}%
+ \foreach \id in \tikzumlIdList {%
+ \draw (\csname tikzumlLastChild@\id \endcsname)+(0,-2.5ex) node[inner sep=0, name=end-\id] {};%
+ \draw[dotted] (\id) -- (end-\id);%
+ }%
+ \end{pgfonlayer}%
+ \end{scope}%
+}%
+%
+% define the database symbol
+% optional : global tikzpicture styles
+\newcommand{\pictureddatabase}[1]{%
+ \pgfkeys{/tikzuml/database/.cd, scale/.initial=1, .unknown/.code={}}%
+ \pgfkeys{/tikzuml/database/.cd,#1}%
+ \pgfkeys{/tikzuml/database/.cd, scale/.get=\tikzumlDatabaseScale}%
+ %
+ \begin{tikzpicture}[#1]%
+ \node[fill, draw, ellipse, minimum width=\tikzumlDatabaseScale*4ex, minimum height=\tikzumlDatabaseScale*2ex, inner sep=0] (bottom) at (0,-2ex) {};%
+ \node[fill, draw, ellipse, minimum width=\tikzumlDatabaseScale*4ex, minimum height=\tikzumlDatabaseScale*2ex, inner sep=0] (top) at (0,4ex) {};%
+ \fill (bottom.west) rectangle (top.east);%
+ \begin{scope}%
+ \clip (-3.5ex,-0.5ex) rectangle (3.5ex,2.5ex);%
+ \node[draw, dashed, ellipse, minimum width=\tikzumlDatabaseScale*4ex, minimum height=\tikzumlDatabaseScale*2ex, inner sep=0] (bottom2) at (0,-2ex) {};%
+ \end{scope}%
+ \node[draw, ellipse, minimum width=\tikzumlDatabaseScale*4ex, minimum height=\tikzumlDatabaseScale*2ex, inner sep=0] (top2) at (0,4ex) {};%
+ \draw (bottom.west) -- (top.west) (bottom.east) -- (top.east);%
+ \end{tikzpicture}%
+}%
+%
+% define the entity symbol
+% optional : global tikzpicture styles
+\newcommand{\picturedentity}[1]{%
+ \pgfkeys{/tikzuml/entity/.cd, scale/.initial=1, .unknown/.code={}}%
+ \pgfkeys{/tikzuml/entity/.cd,#1}%
+ \pgfkeys{/tikzuml/entity/.cd, scale/.get=\tikzumlEntityScale}%
+ %
+ \begin{tikzpicture}[#1]%
+ \node[fill, draw, circle, inner sep=0, minimum size=\tikzumlEntityScale*5ex] (center) at (0,0) {};%
+ \draw (center.south) node[coordinate, name=bottom] {};%
+ \draw (bottom)+(-2ex,0) node[coordinate, name=bottom-left] {};%
+ \draw (bottom)+(2ex,0) node[coordinate, name=bottom-right] {};%
+ \draw (center) -- (bottom);%
+ \draw (bottom-left) -- (bottom-right);%
+ \end{tikzpicture}%
+}%
+%
+% define the boundary symbol
+% optional : global tikzpicture styles
+\newcommand{\picturedboundary}[1]{%
+ \pgfkeys{/tikzuml/boundary/.cd, scale/.initial=1, .unknown/.code={}}%
+ \pgfkeys{/tikzuml/boundary/.cd,#1}%
+ \pgfkeys{/tikzuml/boundary/.cd, scale/.get=\tikzumlBoundaryScale}%
+ %
+ \begin{tikzpicture}[#1]
+ \node[fill, draw, circle, inner sep=0, minimum size=\tikzumlBoundaryScale*5ex] (center) at (0,0) {};
+ \draw (center.west)+(-0.8ex,0) node[coordinate, name=left] {};
+ \draw (left)+(0,0.2ex) node[coordinate, name=left-top] {};
+ \draw (left)+(0,-0.2ex) node[coordinate, name=left-bottom] {};
+ \draw (center) -- (left);
+ \draw (left-top) -- (left-bottom);
+ \end{tikzpicture}
+}%
+%
+% define the control symbol
+% optional : global tikzpicture styles
+\newcommand{\picturedcontrol}[1]{%
+ \pgfkeys{/tikzuml/control/.cd, scale/.initial=1, .unknown/.code={}}%
+ \pgfkeys{/tikzuml/control/.cd,#1}%
+ \pgfkeys{/tikzuml/control/.cd, scale/.get=\tikzumlControlScale}%
+ %
+ \begin{tikzpicture}[#1, decoration={markings, mark=at position 0.25 with {\arrow{>}}}]
+ \node[fill, draw, circle, inner sep=0, minimum size=\tikzumlControlScale*5ex, postaction={decorate}] (center) at (0,0) {};
+ \end{tikzpicture}
+}%
+%
+% define a uml object for a sequence diagram
+% args : name of the object
+% optional : x, y: coordinates of the object
+% stereo: stereotype of the object (object, actor, database, boundary, control, entity, multiobject)
+% class: class of the object
+% scale: scale factor of the object symbol
+% draw, fill, text; colors
+% no ddots: when used, disable printing of double dots
+\newcommand{\umlobject}[2][]{
+ \stepcounter{tikzumlObjectNum}%
+ %
+ \edef\tikzumlobject@ddot{:}%
+ \pgfkeys{/tikzuml/obj/.cd, x/.initial=tikzumlEmpty, y/.initial=\tikzumlDefaultX, stereo/.initial=\tikzumlObjectDefaultStereo,%
+ class/.initial={}, scale/.initial=1,%
+ draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlObjectDefaultFillColor,%
+ text/.initial=\tikzumlDefaultTextColor,%
+ no ddots/.is if=tikzumlobjectNoDDots,%
+ no ddots=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \errmessage{TIKZUML ERROR : in umlobject, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/obj/.cd, #1}%
+ \pgfkeys{/tikzuml/obj/.cd, x/.get=\tikzumlObjectX, y/.get=\tikzumlObjectY,%
+ stereo/.get=\tikzumlObjectStereo, class/.get=\tikzumlObjectClass,%
+ scale/.get=\tikzumlObjectScale,%
+ draw/.get=\tikzumlObjectDrawColor, fill/.get=\tikzumlObjectFillColor,%
+ text/.get=\tikzumlObjectTextColor%
+ }%
+ %
+ \iftikzumlobjectNoDDots%
+ \edef\tikzumlobject@ddot{}%
+ \fi%
+ %
+ \ifthenelse{\equal{\tikzumlObjectX}{tikzumlEmpty}}{%
+ \pgfmathsetmacro{\tikzumlObjectX}{4*(\thetikzumlObjectNum-1)}%
+ }{}%
+ %
+ \def\tikzumlObjectName{#2}%
+ \expandafter\xdef\csname tikzumlLastChild@\tikzumlObjectName \endcsname{\tikzumlObjectName}%
+ %
+ \ifnum\thetikzumlObjectNum=1%
+ \xdef\tikzumlIdList{\tikzumlObjectName}%
+ \else%
+ \let\tikzumlIdListOld\tikzumlIdList%
+ \expandafter\xdef\expandafter\tikzumlIdList\expandafter{\tikzumlIdListOld,\tikzumlObjectName}%
+ \fi%
+ %
+ \tikzstyle{tikzuml object box style}=[rectangle, text=\tikzumlObjectTextColor, font=\tikzumlDefaultFont]%
+ %
+ \ifthenelse{\equal{\tikzumlObjectStereo}{object}}{%
+ \tikzstyle{tikzuml object box style}+=[draw=\tikzumlObjectDrawColor, fill=\tikzumlObjectFillColor]%
+ }{%
+ \ifthenelse{\equal{\tikzumlObjectStereo}{multi}}{%
+ \tikzstyle{tikzuml object box style}+=[fill=\tikzumlObjectFillColor]%
+ }{}%
+ }%
+ %
+ \ifnum\tikzumlInCreateCall=1%
+ \draw (\tikzumlCreateCallObjectSrc -| \tikzumlObjectX,0) node[tikzuml object box style] (\tikzumlObjectName) {\tikzumlObjectName\tikzumlobject@ddot\tikzumlObjectClass};%
+ \else%
+ \node[tikzuml object box style] (\tikzumlObjectName) at (\tikzumlObjectX,\tikzumlObjectY) {\tikzumlObjectName\tikzumlobject@ddot\tikzumlObjectClass};%
+ \fi%
+ %
+ \ifthenelse{\equal{\tikzumlObjectStereo}{multi}}{%
+ \draw (\tikzumlObjectName.north east)+(0.4ex,0.4ex) node[name=\tikzumlObjectName-tr, coordinate] {};
+ \draw (\tikzumlObjectName.north west)+(0.4ex,0.4ex) node[name=\tikzumlObjectName-tl, coordinate] {};
+ \draw (\tikzumlObjectName.south east)+(0.4ex,0.4ex) node[name=\tikzumlObjectName-br, coordinate] {};
+ \draw (\tikzumlObjectName-tr)+(0.4ex,0.4ex) node[name=\tikzumlObjectName-ttr, coordinate] {};
+ \draw (\tikzumlObjectName-tl)+(0.4ex,0.4ex) node[name=\tikzumlObjectName-ttl, coordinate] {};
+ \draw (\tikzumlObjectName-br)+(0.4ex,0.4ex) node[name=\tikzumlObjectName-tbr, coordinate] {};
+ \fill[fill=\tikzumlObjectFillColor] (\tikzumlObjectName-ttl |- \tikzumlObjectName.north) -- (\tikzumlObjectName-ttl) -- (\tikzumlObjectName-ttr) -- (\tikzumlObjectName-tbr) -- (\tikzumlObjectName-tbr -| \tikzumlObjectName.east) -- (\tikzumlObjectName.north east) -- (\tikzumlObjectName-ttl |- \tikzumlObjectName.north);
+ \draw[draw=\tikzumlObjectDrawColor] (\tikzumlObjectName-ttl |- \tikzumlObjectName.north) -- (\tikzumlObjectName-ttl) -- (\tikzumlObjectName-ttr) -- (\tikzumlObjectName-tbr) -- (\tikzumlObjectName-tbr -| \tikzumlObjectName.east);
+ \fill[fill=\tikzumlObjectFillColor] (\tikzumlObjectName-tl |- \tikzumlObjectName.north) -- (\tikzumlObjectName-tl) -- (\tikzumlObjectName-tr) -- (\tikzumlObjectName-br) -- (\tikzumlObjectName-br -| \tikzumlObjectName.east) -- (\tikzumlObjectName.north east) -- (\tikzumlObjectName-tl |- \tikzumlObjectName.north);
+ \draw[draw=\tikzumlObjectDrawColor] (\tikzumlObjectName-tl |- \tikzumlObjectName.north) -- (\tikzumlObjectName-tl) -- (\tikzumlObjectName-tr) -- (\tikzumlObjectName-br) -- (\tikzumlObjectName-br -| \tikzumlObjectName.east);
+ \draw[draw=\tikzumlObjectDrawColor] (\tikzumlObjectName.north west) rectangle (\tikzumlObjectName.south east);
+ }{%
+ \ifthenelse{\equal{\tikzumlObjectStereo}{object}}{}{%
+ \node[above=1ex, name=\tikzumlObjectName-picture] at (\tikzumlObjectName) {\csname pictured\tikzumlObjectStereo \endcsname{draw=\tikzumlObjectDrawColor, fill=\tikzumlObjectFillColor, scale=\tikzumlObjectScale}};
+ }%
+ }%
+}%
+%
+% shortcuts for objects
+\newcommand{\umlbasicobject}[2][]{%
+ \pgfkeys{/tikzuml/basicobj/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{no ddots}}{%
+ \errmessage{TIKZUML ERROR : in umlbasicobject, forbidden option no ddots}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/basicobj/.cd, #1}%
+ \umlobject[no ddots, #1]{#2}%
+}%
+%
+\newcommand{\umldatabase}[2][]{%
+ \pgfkeys{/tikzuml/databaseobj/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umldatabase, forbidden option stereo}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/databaseobj/.cd, #1}%
+ \umlobject[stereo=database, #1]{#2}%
+}%
+\newcommand{\umlentity}[2][]{%
+ \pgfkeys{/tikzuml/entityobj/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlentity, forbidden option stereo}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/entityobj/.cd, #1}%
+ \umlobject[stereo=entity, #1]{#2}%
+}%
+\newcommand{\umlcontrol}[2][]{%
+ \pgfkeys{/tikzuml/controlobj/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlcontrol, forbidden option stereo}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/controlobj/.cd, #1}%
+ \umlobject[stereo=control, #1]{#2}%
+}%
+\newcommand{\umlboundary}[2][]{%
+ \pgfkeys{/tikzuml/boundaryobj/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlboundary, forbidden option stereo}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/boundaryobj/.cd, #1}%
+ \umlobject[stereo=boundary, #1]{#2}%
+}%
+\newcommand{\umlmulti}[2][]{%
+ \pgfkeys{/tikzuml/multiobj/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlmulti, forbidden option stereo}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/multiobj/.cd, #1}%
+ \umlobject[stereo=multi, #1]{#2}%
+}%
+%
+\newcounter{tikzumlSDNodeNum}%
+%
+% define a hidden node to lengthen lifeline of a object
+% args : object node
+% optional : dt: distance between the sdnode and the last call defined on the lifeline of the object
+% name: name of the sdnode
+\newcommand{\umlsdnode}[2][]{%
+ \pgfkeys{/tikzuml/sdnode/.cd, dt/.initial=0, name/.initial=tikzumlEmpty}%
+ \pgfkeys{/tikzuml/sdnode/.cd, #1}%
+ \pgfkeys{/tikzuml/sdnode/.cd, dt/.get=\tikzumlSDNodeDT, name/.get=\tikzumlSDNodeName}%
+ %
+ \ifthenelse{\equal{\tikzumlSDNodeName}{tikzumlEmpty}}{%
+ \expandafter\def\expandafter\tikzumlSDNode@nodeName{sdnode-\thetikzumlSDNodeNum}%
+ }{%
+ \expandafter\def\expandafter\tikzumlSDNode@nodeName{\tikzumlSDNodeName}%
+ }%
+ %
+ \stepcounter{tikzumlSDNodeNum}%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlSDNode@objnodeName{#2}}\x%
+ %
+ \draw (\expandafter\csname tikzumlLastChild@\tikzumlSDNode@objnodeName \endcsname)+(0,-\tikzumlSDNodeDT ex) node[name=\tikzumlSDNode@nodeName,coordinate] {};%
+ %
+ % update last node drawn on sender lifeline
+ \expandafter\xdef\csname tikzumlLastChild@\tikzumlSDNode@objnodeName \endcsname{\tikzumlSDNode@nodeName}%
+}%
+%
+\newlength{\tikzumlCall@xa}%
+\newlength{\tikzumlCall@xb}%
+%
+% define a uml operation call for sequence diagrams
+% args : call sender
+% call receiver
+% optional : dt: time delay from precedent event end
+% name: name of the call
+% op: operation name and input args
+% return: return value
+% type: type of the call (synchron, asynchron)
+% draw, fill, text: colors
+% padding: time padding from call start and to call end
+\newenvironment{umlcall}[3][]{%
+ \stepcounter{tikzumlCallNum}%
+ \def\tikzumlCallWithReturn{tikzumlFalse}%
+ \edef\tikzumlCall@lastchildNum{\thetikzumlCallNum}% for testing presence of sub-calls
+ \gdef\tikzumlCallBottom{0}%
+ %
+ \pgfkeys{/tikzuml/call/.cd, dt/.initial=\tikzumlCallDefaultDT, name/.initial={call-\thetikzumlCallNum},%
+ op/.initial={}, return/.initial={}, type/.initial=\tikzumlCallDefaultType,%
+ draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlCallDefaultFillColor,%
+ text/.initial=\tikzumlDefaultTextColor,%
+ padding/.initial=\tikzumlCallDefaultPadding,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{with return}}{%
+ \def\tikzumlCallWithReturn{tikzumlTrue}%
+ }{%
+ \errmessage{TIKZUML ERROR : in umlcall, invalid option \keyname}%
+ }%
+ }%
+ }%
+ \pgfkeys{/tikzuml/call/.cd, #1}%
+ \pgfkeys{/tikzuml/call/.cd, dt/.get=\tikzumlCallDT, name/.get=\tikzumlCallName, op/.get=\tikzumlCallOp,%
+ return/.get=\tikzumlCallReturn, type/.get=\tikzumlCallType,%
+ padding/.get=\tikzumlCallPadding,%
+ draw/.get=\tikzumlCallDrawColor, fill/.get=\tikzumlCallFillColor,%
+ text/.get=\tikzumlCallTextColor%
+ }%
+ %
+ \edef\tikzumlfillcall{\tikzumlCallFillColor}%
+ \edef\tikzumldrawcall{\tikzumlCallDrawColor}%
+ \edef\tikzumltextcall{\tikzumlCallTextColor}%
+ \edef\tikzumltypecall{\tikzumlCallType}%
+ %
+ \ifthenelse{\equal{\tikzumlCallDT}{tikzumlEmpty}}{%
+ \ifnum\thetikzumlCallNum=1%
+ \def\tikzumlCallDT{2}%
+ \def\tikzumlcallSrc{2}%
+ \else%
+ \def\tikzumlCallDT{2}%
+ \def\tikzumlcallSrc{1}%
+ \fi%
+ }{%
+ \def\tikzumlcallSrc{0}%
+ }%
+ %
+ \let\tikzumlCallStartNodeNameold\tikzumlCallStartNodeName%
+ \def\tikzumlCallStartNodeName{#2}%
+ \let\tikzumlCallEndNodeNameold\tikzumlCallEndNodeName%
+ \def\tikzumlCallEndNodeName{#3}%
+ \def\tikzumlcallheight{\tikzumlCallPadding}%
+ %
+ % managing time delays from previous/parent fragments
+ \ifnum\thetikzumlCallStartFragmentNum>0%
+ \let\tikzumlCallDTold\tikzumlCallDT%
+ \pgfmathparse{0.5*\tikzumlFragment@paddingy+\tikzumlCallDTold}%
+ \edef\tikzumlCallDT{\pgfmathresult}%
+ \addtocounter{tikzumlCallStartFragmentNum}{-1}
+ \fi%
+ \ifnum\thetikzumlCallEndFragmentNum>0%
+ \let\tikzumlCallDTold\tikzumlCallDT%
+ \pgfmathparse{0.5*\tikzumlFragment@paddingy+\tikzumlCallDTold}%
+ \edef\tikzumlCallDT{\pgfmathresult}%
+ \addtocounter{tikzumlCallEndFragmentNum}{-1}
+ \fi%
+ \ifnum\thetikzumlFragmentPartNum>0%
+ \let\tikzumlCallDTold\tikzumlCallDT%
+ \pgfmathparse{0.5*\tikzumlFragment@paddingy+\tikzumlCallDTold}%
+ \edef\tikzumlCallDT{\pgfmathresult}%
+ \fi%
+ %
+ % managing parent-child structure
+ \ifnum\thetikzumlCallLevel>0%
+ \let\tikzumlCall@nameold\tikzumlCall@name%
+ \edef\tikzumlCall@name{\tikzumlCallName}%
+ \let\tikzumlCall@parentold\tikzumlCall@parent%
+ \edef\tikzumlCall@parent{\tikzumlCall@parentold @@\tikzumlCall@nameold}%
+ \else%
+ \edef\tikzumlCall@parent{}%
+ \edef\tikzumlCall@parentold{}%
+ \edef\tikzumlCall@nameold{}
+ \edef\tikzumlCall@name{\tikzumlCallName}%
+ \fi%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlCall@nodeName{\tikzumlCall@name}}\x%
+ %
+ \let\tikzumlCall@nodeNameold\tikzumlCall@nodeName%
+ %
+ \def\tikzumlcallstyle{tikzuml \tikzumlCallType-msg style}%
+ %
+ % top node of activity period of call sender
+ \begin{pgfonlayer}{connections}%
+ \pgfmathparse{\tikzumlCallDT+\tikzumlcallSrc}%
+ \draw (\csname tikzumlLastChild@\tikzumlCallStartNodeName \endcsname)+(0,-\pgfmathresult ex) node[coordinate, name=tikzumlTmpNode] {};%
+ \node[tikzuml activity style] (st-\tikzumlCall@nodeName) at (\tikzumlCallStartNodeName |- tikzumlTmpNode) {};%
+ %
+ % update last node drawn on sender lifeline
+ \expandafter\xdef\csname tikzumlLastChild@\tikzumlCallStartNodeName \endcsname{st-\tikzumlCall@nodeName}%
+ %
+ % top node of activity period of call receiver
+ \ifstrequal{\tikzumlCallStartNodeName}{\tikzumlCallEndNodeName}{%
+ \draw (st-\tikzumlCall@nodeName)+(0,-0.75*\tikzumlCallPadding ex) node[coordinate, name=tikzumlTmpNode] {};%
+ \node[tikzuml activity style] (et-\tikzumlCall@nodeName) at (\tikzumlCallStartNodeName |- tikzumlTmpNode) {};%
+ }{%
+ \node[tikzuml activity style] (et-\tikzumlCall@nodeName) at (\tikzumlCallEndNodeName |- st-\tikzumlCall@nodeName) {};%
+ }%
+ %
+ % update last node drawn on receiver lifeline
+ \expandafter\xdef\csname tikzumlLastChild@\tikzumlCallEndNodeName \endcsname{et-\tikzumlCall@nodeName}%
+ \xdef\tikzumlCallBottomSrc{et-\tikzumlCall@nodeName}%
+ \end{pgfonlayer}%
+ %
+ \stepcounter{tikzumlCallLevel}%
+}{%
+ \addtocounter{tikzumlCallLevel}{-1}%
+ %
+ % bottom nodes of activity periods of call sender and receiver
+ \begin{pgfonlayer}{connections}%
+ \ifnum\tikzumlCall@lastchildNum=\thetikzumlCallNum%
+ %
+ % this test occurs a bug with latex package preview
+ \ifstrequal{\tikzumlCallStartNodeName}{\tikzumlCallEndNodeName}{%
+ \draw (\tikzumlCallBottomSrc)+(0,-\tikzumlCallPadding ex) node[coordinate, name=tikzumlTmpNode] {};%
+ \node[tikzuml activity style] (eb-\tikzumlCall@nodeName) at (\tikzumlCallEndNodeName |- tikzumlTmpNode) {};%
+ \draw (eb-\tikzumlCall@nodeName)+(0,-0.75*\tikzumlCallPadding ex) node[coordinate, name=tikzumlTmpNode] {};%
+ \node[tikzuml activity style] (sb-\tikzumlCall@nodeName) at (\tikzumlCallStartNodeName |- tikzumlTmpNode) {};%
+ }{%
+ \ifthenelse{\equal{\tikzumlCallReturn}{tikzumlEmpty}}{%
+ \pgfmathsetmacro{\tikzumlCallPaddingd}{0.5*\tikzumlCallPadding}%
+ }{%
+ \pgfmathsetmacro{\tikzumlCallPaddingd}{1.2*\tikzumlCallPadding}%
+ }%
+ \draw (\tikzumlCallBottomSrc)+(0,-\tikzumlCallPaddingd ex) node[coordinate, name=tikzumlTmpNode] {};%
+ \node[tikzuml activity style] (eb-\tikzumlCall@nodeName) at (\tikzumlCallEndNodeName |- tikzumlTmpNode) {};%
+ \node[tikzuml activity style] (sb-\tikzumlCall@nodeName) at (\tikzumlCallStartNodeName |- eb-\tikzumlCall@nodeName) {};%
+ }%
+ \xdef\tikzumlCallBottomSrc{sb-\tikzumlCall@nodeName}%
+ \else%
+ %
+ % managing time delays from previous/parent fragments
+ \ifnum\thetikzumlCallStartFragmentNum>0%
+ \let\tikzumlcallheightold\tikzumlCallPadding%
+ \pgfmathparse{\tikzumlcallheightold+0.5*\tikzumlFragment@paddingy}%
+ \edef\tikzumlcallheight{\pgfmathresult}%
+ \addtocounter{tikzumlCallStartFragmentNum}{-1}%
+ \fi%
+ \ifnum\thetikzumlCallEndFragmentNum>0%
+ \let\tikzumlcallheightold\tikzumlCallPadding%
+ \pgfmathparse{\tikzumlcallheightold+0.5*\tikzumlFragment@paddingy}%
+ \edef\tikzumlcallheight{\pgfmathresult}%
+ \addtocounter{tikzumlCallEndFragmentNum}{-1}%
+ \fi%
+ %
+ \ifstrequal{\tikzumlCallStartNodeName}{\tikzumlCallEndNodeName}{%
+ \draw (\tikzumlCallBottomSrc)+(0,-\tikzumlcallheight ex) node[coordinate, name=tikzumlTmpNode] {};%
+ \node[tikzuml activity style] (eb-\tikzumlCall@nodeName) at (\tikzumlCallEndNodeName |- tikzumlTmpNode) {};%
+ \draw (eb-\tikzumlCall@nodeName)+(0,-0.75*\tikzumlCallPadding ex) node[coordinate, name=tikzumlTmpNode] {};%
+ \node[tikzuml activity style] (sb-\tikzumlCall@nodeName) at (\tikzumlCallStartNodeName |- tikzumlTmpNode) {};%
+ }{%
+ \draw (\tikzumlCallBottomSrc)+(0,-\tikzumlcallheight ex) node[coordinate, name=tikzumlTmpNode] {};%
+ \node[tikzuml activity style] (eb-\tikzumlCall@nodeName) at (\tikzumlCallEndNodeName |- tikzumlTmpNode) {};%
+ \node[tikzuml activity style] (sb-\tikzumlCall@nodeName) at (\tikzumlCallStartNodeName |- eb-\tikzumlCall@nodeName) {};%
+ }%
+ %
+ \xdef\tikzumlCallBottomSrc{sb-\tikzumlCall@nodeName}%
+ \fi%
+ \end{pgfonlayer}%
+ %
+ % draw activity periods
+ \begin{pgfonlayer}{activity}%
+ \ifstrequal{\tikzumlCallStartNodeName}{\tikzumlCallEndNodeName}{%
+ % draw root activity period only
+ \ifnum\thetikzumlCallLevel=0%
+ \draw[draw=\tikzumldrawcall, fill=\tikzumlfillcall] (st-\tikzumlCall@nodeName.north west) rectangle (sb-\tikzumlCall@nodeName.south east);%
+ \else%
+ % draw root activity from inner call
+ \ifthenelse{\equal{\tikzumlCallStartNodeName}{\tikzumlCallEndNodeNameold}}{}{%
+ \draw[draw=\tikzumldrawcall, fill=\tikzumlfillcall] (st-\tikzumlCall@nodeName.north west) rectangle (sb-\tikzumlCall@nodeName.south east);%
+ }%
+ \fi%
+ }{%
+ % draw root activity period
+ \ifnum\thetikzumlCallLevel=0%
+ \draw[draw=\tikzumldrawcall, fill=\tikzumlfillcall] (st-\tikzumlCall@nodeName.north west) rectangle (sb-\tikzumlCall@nodeName.south east);%
+ \else%
+ % draw root activity from inner call
+ \ifthenelse{\equal{\tikzumlCallStartNodeName}{\tikzumlCallEndNodeNameold}}{}{%
+ \draw[draw=\tikzumldrawcall, fill=\tikzumlfillcall] (st-\tikzumlCall@nodeName.north west) rectangle (sb-\tikzumlCall@nodeName.south east);%
+ }%
+ \fi%
+ % draw receiver activity period
+ \draw[draw=\tikzumldrawcall, fill=\tikzumlfillcall] (et-\tikzumlCall@nodeName.north west) rectangle (eb-\tikzumlCall@nodeName.south east);%
+ }%
+ \end{pgfonlayer}%
+ \ifthenelse{\equal{\tikzumlCallDefaultFillColor}{\tikzumlCallFillColor}}{}{%
+ \fill[\tikzumlfillcall] (st-\tikzumlCall@nodeName.north west) rectangle (sb-\tikzumlCall@nodeName.south east);%
+ \draw[\tikzumldrawcall] (st-\tikzumlCall@nodeName.north west) rectangle (sb-\tikzumlCall@nodeName.south west) (st-\tikzumlCall@nodeName.north east) rectangle (sb-\tikzumlCall@nodeName.south east);%
+ }%
+ %
+ % update last nodes drawn on sender and receiver lifelines
+ \expandafter\xdef\csname tikzumlLastChild@\tikzumlCallEndNodeName \endcsname{eb-\tikzumlCall@nodeName}%
+ \expandafter\xdef\csname tikzumlLastChild@\tikzumlCallStartNodeName \endcsname{sb-\tikzumlCall@nodeName}%
+ %
+ % draw call arrows
+ \begin{pgfonlayer}{connections}%
+ \ifstrequal{\tikzumlCallStartNodeName}{\tikzumlCallEndNodeName}{%
+ \draw[\tikzumlcallstyle, \tikzumldrawcall] (st-\tikzumlCall@nodeName.east) -- ++(2.5*\tikzumlCallPadding ex,0) %
+ -- ++(0,-0.75*\tikzumlCallPadding ex) %
+ node[font=\tikzumlDefaultFont, text=\tikzumltextcall, midway, right, name=\tikzumlCall@nodeName-op] {\tikzumlCallOp} %
+ -- (et-\tikzumlCall@nodeName.east);%
+ %
+ % draw return arrow and update fit for parent fragment
+ \ifthenelse{\equal{\tikzumltypecall}{synchron}}{%
+ \ifthenelse{\NOT\equal{\tikzumlCallReturn}{}\OR\equal{\tikzumlCallWithReturn}{tikzumlTrue}}{%
+ \ifnum\c@tikzumlFragmentLevel>0%
+ \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname}%
+ \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{\tikzumlFragmentFitOld (st-\tikzumlCall@nodeName) (et-\tikzumlCall@nodeName) (eb-\tikzumlCall@nodeName) (sb-\tikzumlCall@nodeName) (\tikzumlCall@nodeName-op) (\tikzumlCall@nodeName-return)}%
+ \fi%
+ %
+ \draw[tikzuml call return style, \tikzumldrawcall] (eb-\tikzumlCall@nodeName.east) -- ++(2.5*\tikzumlCallPadding ex,0)
+ -- ++(0,-0.75*\tikzumlCallPadding ex) %
+ node[font=\tikzumlDefaultFont, text=\tikzumltextcall, midway, right, name=\tikzumlCall@nodeName-return] {\tikzumlCallReturn} %
+ -- (sb-\tikzumlCall@nodeName.east);%
+ }{%
+ \ifnum\c@tikzumlFragmentLevel>0%
+ \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname}%
+ \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{\tikzumlFragmentFitOld (st-\tikzumlCall@nodeName) (et-\tikzumlCall@nodeName) (eb-\tikzumlCall@nodeName) (sb-\tikzumlCall@nodeName) (\tikzumlCall@nodeName-op)}%
+ \fi%
+ }%
+ }{%
+ \ifnum\c@tikzumlFragmentLevel>0%
+ \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname}%
+ \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{\tikzumlFragmentFitOld (st-\tikzumlCall@nodeName) (et-\tikzumlCall@nodeName) (eb-\tikzumlCall@nodeName) (sb-\tikzumlCall@nodeName) (\tikzumlCall@nodeName-op)}%
+ \fi%
+ }%
+ }{%
+ % draw call arrows
+ \pgfextractx{\tikzumlCall@xa}{\pgfpointanchor{\tikzumlCallStartNodeName}{center}}%
+ \pgfextractx{\tikzumlCall@xb}{\pgfpointanchor{\tikzumlCallEndNodeName}{center}}%
+ %
+ \ifthenelse{\tikzumlCall@xb>\tikzumlCall@xa}{%
+ \draw[\tikzumlcallstyle, \tikzumldrawcall] (st-\tikzumlCall@nodeName.east) -- (et-\tikzumlCall@nodeName.west) %
+ node[font=\tikzumlDefaultFont, text=\tikzumltextcall, midway, above=-0.4ex, name=\tikzumlCall@nodeName-op] {\tikzumlCallOp};%
+ }{%
+ \draw[\tikzumlcallstyle, \tikzumldrawcall] (st-\tikzumlCall@nodeName.west) -- (et-\tikzumlCall@nodeName.east) %
+ node[font=\tikzumlDefaultFont, text=\tikzumltextcall, midway, above=-0.4ex, name=\tikzumlCall@nodeName-op] {\tikzumlCallOp};%
+ }%
+ %
+ % draw return arrow and update fit for parent fragment
+ \ifthenelse{\equal{\tikzumltypecall}{synchron}}{%
+ \ifthenelse{\NOT\equal{\tikzumlCallReturn}{}\OR\equal{\tikzumlCallWithReturn}{tikzumlTrue}}{%
+ \ifnum\c@tikzumlFragmentLevel>0%
+ \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname}%
+ \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{\tikzumlFragmentFitOld (st-\tikzumlCall@nodeName) (et-\tikzumlCall@nodeName) (eb-\tikzumlCall@nodeName) (sb-\tikzumlCall@nodeName) (\tikzumlCall@nodeName-op) (\tikzumlCall@nodeName-return)}%
+ \fi%
+ %
+ \ifthenelse{\tikzumlCall@xb>\tikzumlCall@xa}{%
+ \draw[tikzuml call return style, \tikzumldrawcall] (eb-\tikzumlCall@nodeName.west) -- (sb-\tikzumlCall@nodeName.east) %
+ node[font=\tikzumlDefaultFont, text=\tikzumltextcall, midway, above=-0.4ex, name=\tikzumlCall@nodeName-return] {\tikzumlCallReturn};%
+ }{%
+ \draw[tikzuml call return style, \tikzumldrawcall] (eb-\tikzumlCall@nodeName.east) -- (sb-\tikzumlCall@nodeName.west) %
+ node[font=\tikzumlDefaultFont, text=\tikzumltextcall, midway, above=-0.4ex, name=\tikzumlCall@nodeName-return] {\tikzumlCallReturn};%
+ }%
+ }{%
+ \ifnum\c@tikzumlFragmentLevel>0%
+ \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname}%
+ \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{\tikzumlFragmentFitOld (st-\tikzumlCall@nodeName) (et-\tikzumlCall@nodeName) (eb-\tikzumlCall@nodeName) (sb-\tikzumlCall@nodeName) (\tikzumlCall@nodeName-op)}%
+ \fi%
+ }%
+ }{%
+ \ifnum\c@tikzumlFragmentLevel>0%
+ \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname}%
+ \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{\tikzumlFragmentFitOld (st-\tikzumlCall@nodeName) (et-\tikzumlCall@nodeName) (eb-\tikzumlCall@nodeName) (sb-\tikzumlCall@nodeName) (\tikzumlCall@nodeName-op)}%
+ \fi%
+ }%
+ }%
+ \end{pgfonlayer}%
+}%
+%
+% alias for function self call
+\newenvironment{umlcallself}[2][]{\begin{umlcall}[#1]{#2}{#2} }{\end{umlcall}}%
+%
+% define a combined fragment
+% optional : name: name of fragment
+% type: type of fragment (opt, alt, break, loop, par, critical, ignore, consider, assert, neg, weak, strict, ref)
+% label: label of fragment (ex : condition for opt, iterator for loop, ...)
+% inner xsep, inner ysep: padding of the fragment box
+% draw, fill, text: colors
+\newenvironment{umlfragment}[1][]{%
+ % define a fragment separator
+ % optional : label of the fragment part (ex : else for alt)
+ \providecommand{\umlfpart}[1][]{%
+ \stepcounter{tikzumlFragmentPartNum}%
+ %
+ \node[outer sep=0, inner xsep=\tikzumlFragmentXSep ex, inner ysep=\tikzumlFragmentYSep ex, fit=\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname, name=\tikzumlFragment@name-Part-tmp] {};%
+ \node[anchor=east, name=\tikzumlFragment@name-PartType-\thetikzumlFragmentPartNum] at (\tikzumlFragment@name-Part-tmp.north west |- \tikzumlCallBottomSrc) {\phantom{\tikzumlFragmentType}};%
+ \draw (\tikzumlFragment@name-PartType-\thetikzumlFragmentPartNum.north west |- \tikzumlCallBottomSrc)+(0,-0.4*\tikzumlFragment@paddingy ex) node[name=\tikzumlFragment@name-PartWest-\thetikzumlFragmentPartNum] {};%
+ \draw (\tikzumlFragment@name-Part-tmp.north east |- \tikzumlCallBottomSrc)+(0,-0.4*\tikzumlFragment@paddingy ex) node[name=\tikzumlFragment@name-PartEast-\thetikzumlFragmentPartNum] {};%
+ \draw[dashed] (\tikzumlFragment@name-PartWest-\thetikzumlFragmentPartNum) -- (\tikzumlFragment@name-PartEast-\thetikzumlFragmentPartNum);
+ \draw (\tikzumlFragment@name-PartType-\thetikzumlFragmentPartNum)+(0,-0.4*\tikzumlFragment@paddingy ex) node[name=tikzumlTmpNode] {\phantom{\tikzumlFragmentType}};%
+ \node[anchor=north west] at (tikzumlTmpNode.south west) {[##1]};%
+ }%
+ %
+ \stepcounter{tikzumlFragmentNum}%
+ %
+ \pgfkeys{/tikzuml/fragment/.cd, name/.initial=fragment@\alph{tikzumlFragmentNum}, type/.initial=\tikzumlFragmentDefaultType,%
+ label/.initial=tikzumlEmpty,%
+ inner xsep/.initial=\tikzumlFragmentDefaultXSep, inner ysep/.initial=\tikzumlFragmentDefaultYSep,%
+ draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlFragmentDefaultFillColor,%
+ text/.initial=\tikzumlDefaultTextColor,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \errmessage{TIKZUML ERROR : in umlfragment, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/fragment/.cd, #1}%
+ \pgfkeys{/tikzuml/fragment/.cd, name/.get=\tikzumlFragmentName, type/.get=\tikzumlFragmentType,%
+ label/.get=\tikzumlFragmentLabel,%
+ inner xsep/.get=\tikzumlFragmentXSep, inner ysep/.get=\tikzumlFragmentYSep,%
+ draw/.get=\tikzumlFragmentDrawColor, fill/.get=\tikzumlFragmentFillColor,%
+ text/.get=\tikzumlFragmentTextColor%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlFragmentLabel}{tikzumlEmpty}}{%
+ \def\tikzumlFragmentLabel{}%
+ }{%
+ \let\tikzumlFragmentLabelold\tikzumlFragmentLabel%
+ \def\tikzumlFragmentLabel{[\tikzumlFragmentLabelold]}%
+ }%
+ %
+ \ifnum\thetikzumlFragmentLevel>0%
+ \let\tikzumlFragment@parentold\tikzumlFragment@parent%
+ \let\tikzumlFragment@nameold\tikzumlFragment@name%
+ \edef\tikzumlFragment@parent{\tikzumlFragment@nameold}%
+ \else%
+ \setcounter{tikzumlFragmentPartNum}{0}%
+ \edef\tikzumlFragment@parent{}%
+ \edef\tikzumlFragment@parentold{}%
+ \edef\tikzumlFragment@nameold{}%
+ \fi%
+ %
+ \edef\tikzumlFragment@name{\tikzumlFragmentName}%
+ \expandafter\gdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{}%
+ %
+ \stepcounter{tikzumlFragmentLevel}%
+ %
+ \ifnum\thetikzumlCallLevel>0%
+ \stepcounter{tikzumlCallStartFragmentNum}%
+ \fi%
+ %
+ \pgfmathparse{6*\tikzumlFragmentYSep}%
+ \xdef\tikzumlFragment@paddingy{\pgfmathresult}%
+ \if\c@tikzumlFragmentLevelNum=0%
+ \setcounter{tikzumlFragmentLevelNum}{\thetikzumlFragmentLevel}%
+ \fi%
+ %
+ % time delay adjustment for two consecutive fragments
+ \ifnum\thetikzumlCallEndFragmentNum>0%
+ \addtocounter{tikzumlCallEndFragmentNum}{-1}
+ \fi%
+}{%
+ %
+ \addtocounter{tikzumlFragmentLevel}{-1}%
+ %
+ \ifnum\thetikzumlFragmentLevel>0%
+ \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@parent \endcsname}%
+ \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@parent \endcsname{\tikzumlFragmentFitOld (\tikzumlFragment@name)}%
+ \fi%
+ %
+ % draw working fragment box
+ \begin{pgfonlayer}{fragment\thetikzumlFragmentLevel}%
+ \node[outer sep=0, inner xsep=\tikzumlFragmentXSep ex, inner ysep=\tikzumlFragmentYSep ex, fit=\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname, name=\tikzumlFragment@name-back] {};%
+ \end{pgfonlayer}%
+ %
+ % draw type and label
+ \node[text=\tikzumlFragmentTextColor, font=\tikzumlDefaultFont, anchor=north east, name=\tikzumlFragment@name-type] %
+ at (\tikzumlFragment@name-back.north west) {\tikzumlFragmentType};%
+ \node[text=\tikzumlFragmentTextColor, font=\tikzumlDefaultFont, anchor=north west, name=\tikzumlFragment@name-label] %
+ at (\tikzumlFragment@name-type.south west) {\tikzumlFragmentLabel};%
+ %
+ % draw final fragment box
+ \begin{pgfonlayer}{fragment\thetikzumlFragmentLevel}%
+ \node[draw=\tikzumlFragmentDrawColor, fill=\tikzumlFragmentFillColor, outer sep=0, inner sep=0, font=\tikzumlDefaultFont, fit=(\tikzumlFragment@name-back) (\tikzumlFragment@name-type) (\tikzumlFragment@name-label), name=\tikzumlFragment@name] {};%
+ \end{pgfonlayer}%
+ %
+ \draw[draw=\tikzumlFragmentDrawColor] (\tikzumlFragment@name.north west) rectangle (\tikzumlFragment@name.south east);%
+ \draw (\tikzumlFragment@name-type.south east)+(0,1ex) node[name=\tikzumlFragment@name-typetop, inner sep=0] {};%
+ \draw (\tikzumlFragment@name-type.south east)+(-1ex,0) node[name=\tikzumlFragment@name-typeleft, inner sep=0] {};%
+ \draw (\tikzumlFragment@name.north west) -| (\tikzumlFragment@name-typetop.center) -- (\tikzumlFragment@name-typeleft.center) -| (\tikzumlFragment@name.north west);%
+ %
+ \ifnum\thetikzumlCallLevel>0%
+ \stepcounter{tikzumlCallEndFragmentNum}%
+ \fi%
+}%
+%
+% define a constructor call
+% arg : call sender
+% name of constructed object
+% optional : x: coordinate of the new object
+% stereo: stereotype of the new object
+% class: class type of the new object
+% dt: time delay from last event
+% name: name of the call
+% draw, fill, text: colors
+% no ddots: when used, disable printing of double dots
+\newcommand{\umlcreatecall}[3][]{%
+ \stepcounter{tikzumlCallNum}%
+ \edef\tikzumlCall@lastchildNum{\thetikzumlCallNum}% for testing presence of sub-calls
+ \gdef\tikzumlInCreateCall{1}%
+ \pgfkeys{/tikzuml/createcall/.cd, x/.initial=tikzumlEmpty, stereo/.initial=\tikzumlObjectDefaultStereo, class/.initial={},%
+ dt/.initial=\tikzumlCreateCallDefaultDT, name/.initial=call-\thetikzumlCallNum,%
+ draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlCallDefaultFillColor,%
+ text/.initial=\tikzumlDefaultTextColor,%
+ draw obj/.initial=\tikzumlDefaultDrawColor, fill obj/.initial=\tikzumlObjectDefaultFillColor,%
+ text obj/.initial=\tikzumlDefaultTextColor,%
+ no ddots/.is if=tikzumlcreatecallNoDDots,%
+ no ddots=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \errmessage{TIKZUML ERROR : in umlcreatecall, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/createcall/.cd, #1}%
+ \pgfkeys{/tikzuml/createcall/.cd, x/.get=\tikzumlCreateCallX, stereo/.get=\tikzumlCreateCallStereo,%
+ class/.get=\tikzumlCreateCallClass,%
+ dt/.get=\tikzumlCreateCallDT, name/.get=\tikzumlCreateCallName,%
+ draw/.get=\tikzumlCreateCallDrawColor, fill/.get=\tikzumlCreateCallFillColor,%
+ text/.get=\tikzumlCreateCallTextColor,%
+ draw obj/.get=\tikzumlCreateCallObjectDrawColor, fill obj/.get=\tikzumlCreateCallObjectFillColor,%
+ text obj/.get=\tikzumlCreateCallObjectTextColor%
+ }%
+ %
+ \def\tikzumlCreateCallSrc@name{#2}%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlCreateCallSrc@nodeName{\tikzumlCreateCallSrc@name}}\x%
+ %
+ % managing time delays from previous/parent fragments
+ \ifnum\thetikzumlCallStartFragmentNum>0%
+ \let\tikzumlCreateCallDTold\tikzumlCreateCallDT%
+ \pgfmathparse{0.5*\tikzumlFragment@paddingy+\tikzumlCreateCallDTold}%
+ \edef\tikzumlCreateCallDT{\pgfmathresult}%
+ \addtocounter{tikzumlCallStartFragmentNum}{-1}
+ \fi%
+ \ifnum\thetikzumlCallEndFragmentNum>0%
+ \let\tikzumlCreateCallDTold\tikzumlCreateCallDT%
+ \pgfmathparse{0.5*\tikzumlFragment@paddingy+\tikzumlCreateCallDTold}%
+ \edef\tikzumlCreateCallDT{\pgfmathresult}%
+ \addtocounter{tikzumlCallEndFragmentNum}{-1}
+ \fi%
+ \ifnum\thetikzumlFragmentPartNum>0%
+ \let\tikzumlCreateCallDTold\tikzumlCreateCallDT%
+ \pgfmathparse{0.5*\tikzumlFragment@paddingy+\tikzumlCreateCallDTold}%
+ \edef\tikzumlCreateCallDT{\pgfmathresult}%
+ \fi%
+ %
+ % managing parent-child structure
+ \ifnum\thetikzumlCallLevel>0%
+ \let\tikzumlCall@nameold\tikzumlCall@name%
+ \def\tikzumlCall@name{\tikzumlCreateCallName}%
+ \let\tikzumlCall@parentold\tikzumlCall@parent%
+ \edef\tikzumlCall@parent{\tikzumlCall@parentold @@\tikzumlCall@nameold}%
+ \else%
+ \edef\tikzumlCall@parent{}%
+ \edef\tikzumlCall@parentold{}%
+ \edef\tikzumlCall@nameold{}
+ \edef\tikzumlCall@name{\tikzumlCreateCallName}%
+ \fi%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlCreateCall@nodeName{\tikzumlCall@name}}\x%
+ %
+ \draw (\csname tikzumlLastChild@\tikzumlCreateCallSrc@nodeName \endcsname)+(0,-\tikzumlCreateCallDT ex) node[name=st-\tikzumlCreateCall@nodeName, tikzuml activity style] {};%
+ %
+ \xdef\tikzumlCreateCallObjectSrc{st-\tikzumlCreateCall@nodeName}%
+ %
+ \iftikzumlcreatecallNoDDots%
+ \umlobject[x=\tikzumlCreateCallX, stereo=\tikzumlCreateCallStereo, class=\tikzumlCreateCallClass, draw=\tikzumlCreateCallObjectDrawColor, fill=\tikzumlCreateCallObjectFillColor, text=\tikzumlCreateCallObjectTextColor, no ddots]{#3}%
+ \else
+ \umlobject[x=\tikzumlCreateCallX, stereo=\tikzumlCreateCallStereo, class=\tikzumlCreateCallClass, draw=\tikzumlCreateCallObjectDrawColor, fill=\tikzumlCreateCallObjectFillColor, text=\tikzumlCreateCallObjectTextColor]{#3}%
+ \fi
+ %
+ \draw (\csname tikzumlLastChild@\tikzumlCreateCallSrc@nodeName \endcsname |- #3)+(0,-0.5*\tikzumlCreateCallDT ex) node[name=sb-\tikzumlCreateCall@nodeName, tikzuml activity style] {};%
+ %
+ \expandafter\xdef\csname tikzumlLastChild@\tikzumlCreateCallSrc@nodeName \endcsname{sb-\tikzumlCreateCall@nodeName}%
+ \xdef\tikzumlCallBottomSrc{sb-\tikzumlCreateCall@nodeName}%
+ %
+ \begin{pgfonlayer}{connections}%
+ \draw[tikzuml synchron-msg style, \tikzumlCreateCallDrawColor] (st-\tikzumlCreateCall@nodeName) -- (#3) node[midway, above, font=\tikzumlDefaultFont, text=\tikzumlCreateCallTextColor, name=\tikzumlCreateCall@nodeName-op] {create};%
+ \end{pgfonlayer}%
+ %
+ \ifnum\thetikzumlCallLevel=0%
+ \begin{pgfonlayer}{activity}%
+ \draw[draw=\tikzumlCreateCallDrawColor, fill=\tikzumlCreateCallFillColor] (st-\tikzumlCreateCall@nodeName.north west) rectangle (sb-\tikzumlCreateCall@nodeName.south east);%
+ \end{pgfonlayer}%
+ \fi%
+ % add to fit fragment
+ \ifnum\c@tikzumlFragmentLevel>0%
+ \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname}%
+ \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{\tikzumlFragmentFitOld (st-\tikzumlCreateCall@nodeName) (sb-\tikzumlCreateCall@nodeName) (\tikzumlCreateCall@nodeName-op) (#3) }%
+ \fi%
+}
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% component diagrams %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+\tikzstyle{tikzuml connector style}=[color=\tikzumlDefaultDrawColor, -]%
+%
+\newcounter{tikzumlComponentLevel}%
+\newcounter{tikzumlComponentSubComponentNum}%
+\newcounter{tikzumlConnectorNum}%
+\setcounter{tikzumlConnectorNum}{1}%
+%
+\newif\iftikzumlcomponentWithoutCoords%
+%
+\newcommand{\picturedcomponent}[1]{%
+ \pgfkeys{/tikzuml/component/picture/.cd, scale/.initial=1, .unknown/.code={}}%
+ \pgfkeys{/tikzuml/component/picture/.cd,#1}%
+ \pgfkeys{/tikzuml/component/picture/.cd, scale/.get=\tikzumlComponentScale}%
+ \begin{tikzpicture}[#1]%
+ \filldraw (0,0) rectangle (1ex,1.5ex);%
+ \filldraw (-0.2ex,0.4ex) rectangle (0.2ex,0.6ex);%
+ \filldraw (-0.2ex,0.9ex) rectangle (0.2ex,1.1ex);%
+ \end{tikzpicture}%
+}%
+%
+% define a uml component
+% args : name of the component
+% content of the component
+% optional args : x,y coordinates of the component
+% width of the component node
+\newenvironment{umlcomponent}[2][]{%
+ \ifnum\thetikzumlComponentLevel>0%
+ \let\tikzumlComponent@nameold\tikzumlComponent@fitname%
+ \let\tikzumlComponent@parentold\tikzumlComponent@parent%
+ \edef\tikzumlComponent@parent{\tikzumlComponent@parentold @@\tikzumlComponent@nameold}%
+ \else%
+ \def\tikzumlComponent@parent{}%
+ \fi%
+ %
+ \stepcounter{tikzumlComponentLevel}%
+ %
+ \pgfkeys{/tikzuml/component/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlComponentDefaultWidth, name/.initial={},%
+ draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlComponentDefaultFillColor,%
+ text/.initial=\tikzumlDefaultTextColor, style/.style={},%
+ no coords/.is if=tikzumlcomponentWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/component/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/component/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/component/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlcomponent, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/component/.cd, #1}%
+ \pgfkeys{/tikzuml/component/.cd, x/.get=\tikzumlComponentXShift, y/.get=\tikzumlComponentYShift,%
+ width/.get=\tikzumlComponentMinimumWidth, name/.get=\tikzumlComponentName,%
+ draw/.get=\tikzumlComponentDrawColor, fill/.get=\tikzumlComponentFillColor,%
+ text/.get=\tikzumlComponentTextColor%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlComponentName}{}}{%
+ \edef\tikzumlComponent@name{#2}%
+ }{%
+ \edef\tikzumlComponent@name{\tikzumlComponentName}%
+ }%
+ %
+ \begingroup%
+ \def\_{@}\edef\x{\endgroup%
+ \def\noexpand\tikzumlComponent@fitname{\tikzumlComponent@name}}\x%
+ %
+ \let\tikzumlComponent@nodeNameold\tikzumlComponent@nodeName%
+ \def\tikzumlComponent@caption{#2}%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlComponent@nodeName{\tikzumlComponent@name}}\x%
+ %
+ \expandafter\gdef\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname{}%
+ %
+ \setcounter{tikzumlComponentSubComponentNum}{0}%
+ %
+ \begin{scope}[xshift=\tikzumlComponentXShift cm, yshift=\tikzumlComponentYShift cm]%
+}{%
+ \addtocounter{tikzumlComponentLevel}{-1}%
+ \begin{pgfonlayer}{component\thetikzumlComponentLevel}%
+ %
+ % if contains nothing, one define a fictive node to enable the fit option
+ \ifnum\c@tikzumlComponentSubComponentNum=0%
+ \iftikzumlcomponentWithoutCoords%
+ \node[inner ysep=0.5ex, minimum width=\tikzumlComponentMinimumWidth, font=\tikzumlDefaultFont, /tikzuml/component/style] (\tikzumlComponent@nodeName-root) {\phantom{\tikzumlComponent@nodeName}};%
+ \else%
+ \node[inner ysep=0.5ex, minimum width=\tikzumlComponentMinimumWidth, font=\tikzumlDefaultFont, /tikzuml/component/style] (\tikzumlComponent@nodeName-root) at (0,0) {\phantom{\tikzumlComponent@nodeName}};%
+ \fi%
+ \expandafter\xdef\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname{(\tikzumlComponent@nodeName-root)}%
+ \fi%
+ %
+ \ifnum\c@tikzumlComponentLevel>0%
+ \def\tikzumlComponentFitTmp{\csname tikzumlComponentFit\tikzumlComponent@parent\endcsname}%
+ \expandafter\xdef\csname tikzumlComponentFit\tikzumlComponent@parent\endcsname{\tikzumlComponentFitTmp (\tikzumlComponent@nodeName-body) (\tikzumlComponent@nodeName-caption)}%
+ \stepcounter{tikzumlComponentSubComponentNum}%
+ \fi%
+ %
+ \node[inner sep=2ex, font=\tikzumlDefaultFont, fit = \csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname] (\tikzumlComponent@nodeName-body) {};%
+ \node[above, font=\tikzumlDefaultFont] (\tikzumlComponent@nodeName-captiontmp) at (\tikzumlComponent@nodeName-body.north) {\tikzumlComponent@caption};%
+ \node (\tikzumlComponent@nodeName-logotmp) at (\tikzumlComponent@nodeName-captiontmp.north -| \tikzumlComponent@nodeName-body.east) {\picturedcomponent{draw=\tikzumlComponentDrawColor, fill=\tikzumlComponentFillColor, font=\tikzumlDefaultFont} };%
+ \node[draw=\tikzumlComponentDrawColor, fill=\tikzumlComponentFillColor, name=\tikzumlComponent@nodeName, /tikzuml/component/style, fit=(\tikzumlComponent@nodeName-body) (\tikzumlComponent@nodeName-captiontmp)] {};%
+ \node[font=\tikzumlDefaultFont] (\tikzumlComponent@nodeName-caption) at (\tikzumlComponent@nodeName-captiontmp) {\tikzumlComponent@caption};%
+ \draw (\tikzumlComponent@nodeName-caption.north -| \tikzumlComponent@nodeName.east) node[font=\tikzumlDefaultFont, xshift=-1ex, below=-1ex, name=\tikzumlComponent@nodeName-logo] {\picturedcomponent{draw=\tikzumlComponentDrawColor, fill=\tikzumlComponentFillColor, font=\tikzumlDefaultFont} };%
+ \draw (\tikzumlComponent@nodeName-caption.south -| \tikzumlComponent@nodeName.north west) -- (\tikzumlComponent@nodeName-caption.south -| \tikzumlComponent@nodeName.north east);%
+ \coordinate (\tikzumlComponent@nodeName-west-port) at (\tikzumlComponent@nodeName.west);
+ \coordinate (\tikzumlComponent@nodeName-east-port) at (\tikzumlComponent@nodeName.east);
+ \coordinate (\tikzumlComponent@nodeName-south-port) at (\tikzumlComponent@nodeName.south);
+ \coordinate (\tikzumlComponent@nodeName-north-port) at (\tikzumlComponent@nodeName.north);
+ \end{pgfonlayer}%
+ \end{scope}%
+ %
+ % add to fit
+ \ifnum\c@tikzumlPackageLevel>0%
+ \edef\tikzumlPackageFitOld{\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{\tikzumlPackageFitOld (\tikzumlComponent@nodeName)}%
+ \stepcounter{tikzumlPackageClassNum}%
+ \fi%
+}%
+%
+% shortcut for empty component
+\newcommand{\umlbasiccomponent}[2][]{\begin{umlcomponent}[#1]{#2} \end{umlcomponent}}%
+%
+\newcommand{\umlrequiredinterface}[2][]{%
+ \def\tikzumlInterfaceWithPort{tikzumlFalse}%
+ \pgfkeys{/tikzuml/requiredinterfacerelation/.cd, interface/.initial={}, distance/.initial=\tikzumlRequiredInterfaceDefaultDistance,%
+ name/.initial=tikzumlEmpty, width/.initial=\tikzumlRequiredInterfaceDefaultWidth,%
+ padding/.initial=\tikzumlRequiredInterfaceDefaultPadding,%
+ draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlComponentDefaultFillColor,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{with port}}{%
+ \def\tikzumlInterfaceWithPort{tikzumlTrue}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/requiredinterfacerelation/.cd, #1}%
+ \pgfkeys{/tikzuml/requiredinterfacerelation/.cd, interface/.get=\tikzumlRequiredInterfaceLabel,%
+ distance/.get=\tikzumlRequiredInterfaceDistance,%
+ name/.get=\tikzumlRequiredInterfaceName,%
+ width/.get=\tikzumlRequiredInterfaceWidth,%
+ padding/.get=\tikzumlRequiredInterfacePadding,%
+ draw/.get=\tikzumlRequiredInterfaceDrawColor,%
+ fill/.get=\tikzumlRequiredInterfaceFillColor%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlRequiredInterfaceName}{tikzumlEmpty}}{%
+ \edef\tikzumlRequiredInterface@interfacename{#2-east-interface}%
+ \edef\tikzumlRequiredInterface@portname{#2-east-port}%
+ \edef\tikzumlRequiredInterface@paddingname{#2-east-padding}%
+ }{%
+ \edef\tikzumlRequiredInterface@interfacename{\tikzumlRequiredInterfaceName}%
+ \edef\tikzumlRequiredInterface@portname{\tikzumlRequiredInterfaceName-port}%
+ \edef\tikzumlRequiredInterface@paddingname{\tikzumlRequiredInterfaceName-padding}%
+ }%
+ %
+ \edef\tikzumlRequiredInterface@name{#2}%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlRequiredInterface@nodeName{\tikzumlRequiredInterface@name}}\x%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlRequiredInterface@interfacenodeName{\tikzumlRequiredInterface@interfacename}}\x%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlRequiredInterface@portnodeName{\tikzumlRequiredInterface@portname}}\x%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlRequiredInterface@paddingnodeName{\tikzumlRequiredInterface@paddingname}}\x%
+ %
+ \ifthenelse{\equal{\tikzumlInterfaceWithPort}{tikzumlTrue}}{%
+ \node[inner sep=0.5*\tikzumlRequiredInterfaceWidth, rectangle, draw=\tikzumlRequiredInterfaceDrawColor, fill=\tikzumlRequiredInterfaceFillColor] (\tikzumlRequiredInterface@portnodeName) at (\tikzumlRequiredInterface@nodeName.east) {};%
+ }{%
+ \node[inner sep=0] (\tikzumlRequiredInterface@nodeName-east-port) at (\tikzumlRequiredInterface@nodeName.east) {};%
+ }%
+ \begin{scope}%
+ \draw (\tikzumlRequiredInterface@nodeName)+(\tikzumlRequiredInterfaceDistance,0) node[inner sep=0, text width=\tikzumlRequiredInterfaceWidth, circle, name=\tikzumlRequiredInterface@interfacenodeName-tmp] {};%
+ \clip (\tikzumlRequiredInterface@interfacenodeName-tmp.north) rectangle (\tikzumlRequiredInterface@interfacenodeName-tmp.south -| \tikzumlRequiredInterface@interfacenodeName-tmp.west);%
+ \node[inner sep=0, text width=\tikzumlRequiredInterfaceWidth, circle, draw=\tikzumlRequiredInterfaceDrawColor] (\tikzumlRequiredInterface@interfacenodeName) at (\tikzumlRequiredInterface@interfacenodeName-tmp) {};%
+ \end{scope}%
+ \node[above] at (\tikzumlRequiredInterface@interfacenodeName.north) {\tikzumlRequiredInterfaceLabel};%
+ %
+ \umlrelation[style={tikzuml connector style}, #1]{\tikzumlRequiredInterface@portnodeName}{\tikzumlRequiredInterface@interfacenodeName}%
+ %
+ \draw (\tikzumlRequiredInterface@interfacenodeName)+(\tikzumlRequiredInterfacePadding,0) node[name=\tikzumlRequiredInterface@paddingnodeName] {};%
+ %
+ % add to fit
+ \ifnum\c@tikzumlComponentLevel>0%
+ \def\tikzumlComponentFitTmp{\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname{\tikzumlComponentFitTmp (\tikzumlRequiredInterface@paddingnodeName) (\tikzumlRequiredInterface@portnodeName) }%
+ \fi%
+}%
+%
+\newcommand{\umlprovidedinterface}[2][]{%
+ \def\tikzumlInterfaceWithPort{tikzumlFalse}%
+ \pgfkeys{/tikzuml/providedinterfacerelation/.cd, interface/.initial={}, distance/.initial=\tikzumlProvidedInterfaceDefaultDistance,%
+ name/.initial=tikzumlEmpty, width/.initial=\tikzumlProvidedInterfaceDefaultWidth,%
+ padding/.initial=\tikzumlProvidedInterfaceDefaultPadding,%
+ draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlComponentDefaultFillColor,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{with port}}{%
+ \def\tikzumlInterfaceWithPort{tikzumlTrue}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/providedinterfacerelation/.cd, #1}%
+ \pgfkeys{/tikzuml/providedinterfacerelation/.cd, interface/.get=\tikzumlProvidedInterfaceLabel,%
+ distance/.get=\tikzumlProvidedInterfaceDistance,%
+ name/.get=\tikzumlProvidedInterfaceName,%
+ width/.get=\tikzumlProvidedInterfaceWidth,%
+ padding/.get=\tikzumlProvidedInterfacePadding,%
+ draw/.get=\tikzumlProvidedInterfaceDrawColor,%
+ fill/.get=\tikzumlProvidedInterfaceFillColor%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlProvidedInterfaceName}{tikzumlEmpty}}{%
+ \edef\tikzumlProvidedInterface@interfacename{#2-west-interface}%
+ \edef\tikzumlProvidedInterface@portname{#2-west-port}%
+ \edef\tikzumlProvidedInterface@paddingname{#2-west-padding}%
+ }{%
+ \edef\tikzumlProvidedInterface@interfacename{\tikzumlProvidedInterfaceName}%
+ \edef\tikzumlProvidedInterface@portname{\tikzumlProvidedInterfaceName-port}%
+ \edef\tikzumlProvidedInterface@paddingname{\tikzumlProvidedInterfaceName-padding}%
+ }%
+ %
+ \edef\tikzumlProvidedInterface@name{#2}%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlProvidedInterface@nodeName{\tikzumlProvidedInterface@name}}\x%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlProvidedInterface@interfacenodeName{\tikzumlProvidedInterface@interfacename}}\x%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlProvidedInterface@portnodeName{\tikzumlProvidedInterface@portname}}\x%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlProvidedInterface@paddingnodeName{\tikzumlProvidedInterface@paddingname}}\x%
+ %
+ \ifthenelse{\equal{\tikzumlInterfaceWithPort}{tikzumlTrue}}{%
+ \node[inner sep=0.5*\tikzumlProvidedInterfaceWidth, rectangle, draw=\tikzumlProvidedInterfaceDrawColor, fill=\tikzumlProvidedInterfaceFillColor] (\tikzumlProvidedInterface@portnodeName) at (\tikzumlProvidedInterface@nodeName.west) {};%
+ }{%
+ \node[inner sep=0] (\tikzumlProvidedInterface@portnodeName) at (\tikzumlProvidedInterface@nodeName.west) {};%
+ }%
+ \draw (\tikzumlProvidedInterface@nodeName)+(-\tikzumlProvidedInterfaceDistance,0) node[inner sep=0, text width=\tikzumlProvidedInterfaceWidth, circle, draw=\tikzumlProvidedInterfaceDrawColor, fill=\tikzumlProvidedInterfaceFillColor, name=\tikzumlProvidedInterface@interfacenodeName] {};%
+ \node[above] at (\tikzumlProvidedInterface@interfacenodeName.north)
+ {\tikzumlProvidedInterfaceLabel};%
+ %
+ \umlrelation[style={tikzuml connector style}, #1]{\tikzumlProvidedInterface@portnodeName}{\tikzumlProvidedInterface@interfacenodeName}%
+ %
+ \draw (\tikzumlProvidedInterface@interfacenodeName)+(-\tikzumlProvidedInterfacePadding,0) node[name=\tikzumlProvidedInterface@paddingnodeName] {};%
+ %
+ % add to fit
+ \ifnum\thetikzumlComponentLevel>0%
+ \def\tikzumlComponentFitTmp{\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname{\tikzumlComponentFitTmp (\tikzumlProvidedInterface@paddingnodeName) (\tikzumlProvidedInterface@portnodeName) }%
+ \fi%
+}%
+%
+\newlength{\tikzuml@AC@xa}%
+\newlength{\tikzuml@AC@ya}%
+\newlength{\tikzuml@AC@xb}%
+\newlength{\tikzuml@AC@yb}%
+\newlength{\tikzuml@AC@xi}%
+\newlength{\tikzuml@AC@yi}%
+\newlength{\tikzuml@AC@xic}%
+\newlength{\tikzuml@AC@yic}%
+\newlength{\tikzuml@AC@xio}%
+\newlength{\tikzuml@AC@yio}%
+\newlength{\tikzuml@AC@AB}%
+\newlength{\tikzuml@AC@lambda}%
+\newlength{\tikzuml@AC@xtrc}%
+\newlength{\tikzuml@AC@ytrc}%
+\newlength{\tikzuml@AC@xtlc}%
+\newlength{\tikzuml@AC@ytlc}%
+\newlength{\tikzuml@AC@xblc}%
+\newlength{\tikzuml@AC@yblc}%
+\newlength{\tikzuml@AC@xbrc}%
+\newlength{\tikzuml@AC@ybrc}%
+\newlength{\tikzuml@AC@middleArm}%
+%
+\newcommand{\umlassemblyconnectorsymbol}[2]{%
+ \ifthenelse{\NOT\equal{\tikzumlAssemblyConnectorLabel}{}}{%
+ \edef\tikzuml@ACStart@name{#1}%
+ \edef\tikzuml@ACEnd@name{#2}%
+ \edef\tikzuml@AC@width{\tikzumlAssemblyConnectorWidth}%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzuml@ACStart@nodeName{\tikzuml@ACStart@name}}\x%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzuml@ACEnd@nodeName{\tikzuml@ACEnd@name}}\x%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzuml@ACInterface@nodeName{\tikzumlAssemblyConnectorSymbolName}}\x%
+ %
+ \pgfextractx{\tikzuml@AC@xa}{\pgfpointanchor{\tikzuml@ACStart@nodeName}{\tikzumlAssemblyConnectorStartAnchor}}%
+ \pgfextracty{\tikzuml@AC@ya}{\pgfpointanchor{\tikzuml@ACStart@nodeName}{\tikzumlAssemblyConnectorStartAnchor}}%
+ \pgfextractx{\tikzuml@AC@xb}{\pgfpointanchor{\tikzuml@ACEnd@nodeName}{\tikzumlAssemblyConnectorEndAnchor}}%
+ \pgfextracty{\tikzuml@AC@yb}{\pgfpointanchor{\tikzuml@ACEnd@nodeName}{\tikzumlAssemblyConnectorEndAnchor}}%
+ \pgfmathsetlength{\tikzuml@AC@xi}{0.5*\tikzuml@AC@xa+0.5*\tikzuml@AC@xb}%
+ \pgfmathsetlength{\tikzuml@AC@yi}{0.5*\tikzuml@AC@ya+0.5*\tikzuml@AC@yb}%
+ \pgfmathsetlength{\tikzuml@AC@AB}{veclen(\tikzuml@AC@xa-\tikzuml@AC@xb,\tikzuml@AC@ya-\tikzuml@AC@yb)}%
+ \pgfmathsetlength{\tikzuml@AC@lambda}{0.25*\tikzuml@AC@width/\tikzuml@AC@AB}%
+ \pgfmathsetlength{\tikzuml@AC@xic}{\tikzuml@AC@xi-\tikzuml@AC@lambda*(\tikzuml@AC@xb-\tikzuml@AC@xa)}%
+ \pgfmathsetlength{\tikzuml@AC@yic}{\tikzuml@AC@yi-\tikzuml@AC@lambda*(\tikzuml@AC@yb-\tikzuml@AC@ya)}%
+ \pgfmathsetlength{\tikzuml@AC@xio}{\tikzuml@AC@xi+\tikzuml@AC@lambda*(\tikzuml@AC@xb-\tikzuml@AC@xa)}%
+ \pgfmathsetlength{\tikzuml@AC@yio}{\tikzuml@AC@yi+\tikzuml@AC@lambda*(\tikzuml@AC@yb-\tikzuml@AC@ya)}%
+ \node[inner sep=0.5*\tikzuml@AC@width] (\tikzuml@ACInterface@nodeName-interface) at (\tikzuml@AC@xi,\tikzuml@AC@yi) {};%
+ \node[inner sep=0, text width=\tikzuml@AC@width, circle, draw=\tikzumlAssemblyConnectorDrawColor, fill=\tikzumlAssemblyConnectorFillColor] (\tikzuml@ACInterface@nodeName-io) at (\tikzuml@AC@xio,\tikzuml@AC@yio) {};%
+ \begin{scope}%
+ \pgfmathsetlength{\tikzuml@AC@xtrc}{\tikzuml@AC@xic-2*\tikzuml@AC@lambda*(\tikzuml@AC@yb-\tikzuml@AC@ya)}%
+ \pgfmathsetlength{\tikzuml@AC@ytrc}{\tikzuml@AC@yic+2*\tikzuml@AC@lambda*(\tikzuml@AC@xb-\tikzuml@AC@xa)}%
+ \pgfmathsetlength{\tikzuml@AC@xbrc}{\tikzuml@AC@xic+2*\tikzuml@AC@lambda*(\tikzuml@AC@yb-\tikzuml@AC@ya)}%
+ \pgfmathsetlength{\tikzuml@AC@ybrc}{\tikzuml@AC@yic-2*\tikzuml@AC@lambda*(\tikzuml@AC@xb-\tikzuml@AC@xa)}%
+ \pgfmathsetlength{\tikzuml@AC@xtlc}{\tikzuml@AC@xic-3*\tikzuml@AC@lambda*(\tikzuml@AC@yb-\tikzuml@AC@ya+\tikzuml@AC@xb-\tikzuml@AC@xa)}%
+ \pgfmathsetlength{\tikzuml@AC@ytlc}{\tikzuml@AC@yic+3*\tikzuml@AC@lambda*(\tikzuml@AC@xb-\tikzuml@AC@xa+\tikzuml@AC@ya-\tikzuml@AC@yb)}%
+ \pgfmathsetlength{\tikzuml@AC@xblc}{\tikzuml@AC@xic+3*\tikzuml@AC@lambda*(\tikzuml@AC@yb-\tikzuml@AC@ya+\tikzuml@AC@xa-\tikzuml@AC@xb)}%
+ \pgfmathsetlength{\tikzuml@AC@yblc}{\tikzuml@AC@yic-3*\tikzuml@AC@lambda*(\tikzuml@AC@xb-\tikzuml@AC@xa+\tikzuml@AC@yb-\tikzuml@AC@ya)}%
+ \coordinate (\tikzuml@ACInterface@nodeName-trc) at (\tikzuml@AC@xtrc,\tikzuml@AC@ytrc);%
+ \coordinate (\tikzuml@ACInterface@nodeName-brc) at (\tikzuml@AC@xbrc,\tikzuml@AC@ybrc);%
+ \coordinate (\tikzuml@ACInterface@nodeName-tlc) at (\tikzuml@AC@xtlc,\tikzuml@AC@ytlc);%
+ \coordinate (\tikzuml@ACInterface@nodeName-blc) at (\tikzuml@AC@xblc,\tikzuml@AC@yblc);%
+ \clip (\tikzuml@ACInterface@nodeName-trc) -- (\tikzuml@ACInterface@nodeName-tlc) -- (\tikzuml@ACInterface@nodeName-blc) -- (\tikzuml@ACInterface@nodeName-brc) -- cycle;%
+ \node[inner sep=0, text width=\tikzuml@AC@width, circle, draw=\tikzumlAssemblyConnectorDrawColor, fill=\tikzumlAssemblyConnectorFillColor] (\tikzuml@ACInterface@nodeName-ic) at (\tikzuml@AC@xic,\tikzuml@AC@yic) {};%
+ \end{scope}%
+ \node[above, font=\tikzumlDefaultFont] at (\tikzuml@ACInterface@nodeName-interface.north)
+ {\tikzumlAssemblyConnectorLabel};%
+ }{}%
+}%
+%
+\newcommand{\umlassemblyconnector}[3][]{%
+ \def\tikzumlAssemblyConnectorWithPort{tikzumlFalse}%
+ \def\tikzumlAssemblyConnectorFirstArm{tikzumlFalse}%
+ \def\tikzumlAssemblyConnectorSecondArm{tikzumlFalse}%
+ \def\tikzumlAssemblyConnectorMiddleArm{tikzumlFalse}%
+ \def\tikzumlAssemblyConnectorLastArm{tikzumlFalse}%
+ \pgfkeys{/tikzuml/assemblyconnectorrelation/.cd, geometry/.initial=--, interface/.initial={},%
+ arm1/.initial={auto}, arm2/.initial={auto},%
+ name/.initial=connector-\thetikzumlConnectorNum, width/.initial=1em,%
+ anchor1/.initial={}, anchor2/.initial={},%
+ draw/.initial=\tikzumlDefaultDrawColor,%
+ fill assembly connector/.initial=\tikzumlAssemblyConnectorDefaultFillColor,%
+ fill port/.initial=\tikzumlPortDefaultFillColor,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{with port}}{%
+ \def\tikzumlAssemblyConnectorWithPort{tikzumlTrue}%
+ }{%
+ \ifthenelse{\equal{\keyname}{first arm}}{%
+ \def\tikzumlAssemblyConnectorFirstArm{tikzumlTrue}%
+ }{%
+ \ifthenelse{\equal{\keyname}{second arm}}{%
+ \def\tikzumlAssemblyConnectorSecondArm{tikzumlTrue}%
+ }{%
+ \ifthenelse{\equal{\keyname}{middle arm}}{%
+ \def\tikzumlAssemblyConnectorMiddleArm{tikzumlTrue}%
+ }{%
+ \ifthenelse{\equal{\keyname}{last arm}}{%
+ \def\tikzumlAssemblyConnectorLastArm{tikzumlTrue}%
+ }{%
+ }%
+ }%
+ }%
+ }%
+ }%
+ }%
+ }%
+ \pgfkeys{/tikzuml/assemblyconnectorrelation/.cd, #1}%
+ \pgfkeys{/tikzuml/assemblyconnectorrelation/.cd, geometry/.get=\tikzumlAssemblyConnectorGeometry,%
+ name/.get=\tikzumlAssemblyConnectorName,%
+ interface/.get=\tikzumlAssemblyConnectorLabel,%
+ width/.get=\tikzumlAssemblyConnectorWidth,%
+ arm1/.get=\tikzumlAssemblyConnectorStartArm,%
+ arm2/.get=\tikzumlAssemblyConnectorEndArm,%
+ anchor1/.get=\tikzumlAssemblyConnectorStartAnchorTmp,%
+ anchor2/.get=\tikzumlAssemblyConnectorEndAnchorTmp,%
+ draw/.get=\tikzumlAssemblyConnectorDrawColor,%
+ fill assembly connector/.get=\tikzumlAssemblyConnectorFillColor,%
+ fill port/.get=\tikzumlAssemblyConnectorPortFillColor%
+ }%
+ %
+ \edef\tikzumlAssemblyConnectorStart@name{#2}%
+ \edef\tikzumlAssemblyConnectorEnd@name{#3}%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlAssemblyConnectorStart@nodeName{\tikzumlAssemblyConnectorStart@name}}\x%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlAssemblyConnectorEnd@nodeName{\tikzumlAssemblyConnectorEnd@name}}\x%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlAssemblyConnectorLabel@nodeName{\tikzumlAssemblyConnectorLabel}}\x%
+ %
+ \pgfextractx{\tikzuml@AC@xa}{\pgfpointanchor{\tikzumlAssemblyConnectorStart@nodeName}{center}}%
+ \pgfextracty{\tikzuml@AC@ya}{\pgfpointanchor{\tikzumlAssemblyConnectorStart@nodeName}{center}}%
+ \pgfextractx{\tikzuml@AC@xb}{\pgfpointanchor{\tikzumlAssemblyConnectorEnd@nodeName}{center}}%
+ \pgfextracty{\tikzuml@AC@yb}{\pgfpointanchor{\tikzumlAssemblyConnectorEnd@nodeName}{center}}%
+ %
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{--}}{%
+ \ifthenelse{\tikzuml@AC@xb>\tikzuml@AC@xa}{%
+ \def\tikzumlAssemblyConnectorStartAnchor{east}%
+ \def\tikzumlAssemblyConnectorEndAnchor{west}%
+ }{%
+ \def\tikzumlAssemblyConnectorStartAnchor{west}%
+ \def\tikzumlAssemblyConnectorEndAnchor{east}%
+ }
+ }{}%
+ %
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{-|}}{%
+ \ifthenelse{\tikzuml@AC@xb>\tikzuml@AC@xa}{%
+ \def\tikzumlAssemblyConnectorStartAnchor{east}%
+ }{%
+ \def\tikzumlAssemblyConnectorStartAnchor{west}%
+ }
+ \ifthenelse{\tikzuml@AC@yb>\tikzuml@AC@ya}{%
+ \def\tikzumlAssemblyConnectorEndAnchor{south}%
+ }{%
+ \def\tikzumlAssemblyConnectorEndAnchor{north}%
+ }
+ }{}%
+ %
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{|-}}{%
+ \ifthenelse{\tikzuml@AC@xb>\tikzuml@AC@xa}{%
+ \def\tikzumlAssemblyConnectorEndAnchor{west}%
+ }{%
+ \def\tikzumlAssemblyConnectorEndAnchor{east}%
+ }
+ \ifthenelse{\tikzuml@AC@yb>\tikzuml@AC@ya}{%
+ \def\tikzumlAssemblyConnectorStartAnchor{north}%
+ }{%
+ \def\tikzumlAssemblyConnectorStartAnchor{south}%
+ }
+ }{}%
+ %
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{-|-}}{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorStartArm}{auto}}{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorEndArm}{auto}}{%
+ \pgfmathsetlength{\tikzuml@AC@middleArm}{0.5 * \tikzuml@AC@xa + 0.5 * \tikzuml@AC@xb}%
+ }{%
+ \pgfmathsetlength{\tikzuml@AC@middleArm}{\tikzuml@AC@xb+\tikzumlAssemblyConnectorEndArm}%
+ }%
+ }{%
+ \pgfmathsetlength{\tikzuml@AC@middleArm}{\tikzuml@AC@xa+\tikzumlAssemblyConnectorStartArm}%
+ }%
+ \pgfmathparse{\tikzuml@AC@middleArm>\tikzuml@AC@xa}
+ \pgfmathparse{\tikzuml@AC@middleArm>\tikzuml@AC@xb}
+ \ifthenelse{\lengthtest{\tikzuml@AC@middleArm>\tikzuml@AC@xa}}{%
+ \def\tikzumlAssemblyConnectorStartAnchor{east}%
+ }{%
+ \def\tikzumlAssemblyConnectorStartAnchor{west}%
+ }
+ \ifthenelse{\lengthtest{\tikzuml@AC@middleArm>\tikzuml@AC@xb}}{%
+ \def\tikzumlAssemblyConnectorEndAnchor{east}%
+ }{%
+ \def\tikzumlAssemblyConnectorEndAnchor{west}%
+ }
+ }{}%
+ %
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{|-|}}{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorStartArm}{auto}}{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorEndArm}{auto}}{%
+ \pgfmathsetlength{\tikzuml@AC@middleArm}{0.5 * \tikzuml@AC@ya + 0.5 * \tikzuml@AC@yb}%
+ }{%
+ \pgfmathsetlength{\tikzuml@AC@middleArm}{\tikzuml@AC@yb+\tikzumlAssemblyConnectorEndArm}%
+ }%
+ }{%
+ \pgfmathsetlength{\tikzuml@AC@middleArm}{\tikzuml@AC@ya+\tikzumlAssemblyConnectorStartArm}%
+ }%
+ \ifthenelse{\tikzuml@AC@middleArm>\tikzuml@AC@ya}{%
+ \def\tikzumlAssemblyConnectorStartAnchor{north}%
+ }{%
+ \def\tikzumlAssemblyConnectorStartAnchor{south}%
+ }
+ \ifthenelse{\tikzuml@AC@middleArm>\tikzuml@AC@yb}{%
+ \def\tikzumlAssemblyConnectorEndAnchor{north}%
+ }{%
+ \def\tikzumlAssemblyConnectorEndAnchor{south}%
+ }
+ }{}%
+ %
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorStartAnchorTmp}{}}{%
+ }{%
+ \def\tikzumlAssemblyConnectorStartAnchor{\tikzumlAssemblyConnectorStartAnchorTmp}%
+ }%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorEndAnchorTmp}{}}{%
+ }{%
+ \def\tikzumlAssemblyConnectorEndAnchor{\tikzumlAssemblyConnectorEndAnchorTmp}%
+ }%
+ %
+ \node[inner sep=0] (\tikzumlAssemblyConnectorStart@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port-tmp) at (\tikzumlAssemblyConnectorStart@nodeName.\tikzumlAssemblyConnectorStartAnchor) {};%
+ \node[inner sep=0] (\tikzumlAssemblyConnectorEnd@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port-tmp) at (\tikzumlAssemblyConnectorEnd@nodeName.\tikzumlAssemblyConnectorEndAnchor) {};%
+ %
+ \umlrelation[style={tikzuml connector style}, #1]{\tikzumlAssemblyConnectorStart@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port-tmp}{\tikzumlAssemblyConnectorEnd@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port-tmp}%
+ %
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorWithPort}{tikzumlTrue}}{%
+ \node[inner sep=0.5*\tikzumlAssemblyConnectorWidth, rectangle, draw=\tikzumlAssemblyConnectorDrawColor, fill=\tikzumlAssemblyConnectorPortFillColor] (\tikzumlAssemblyConnectorStart@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port) at (\tikzumlAssemblyConnectorStart@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port-tmp) {};%
+ \node[inner sep=0.5*\tikzumlAssemblyConnectorWidth, rectangle, draw=\tikzumlAssemblyConnectorDrawColor, fill=\tikzumlAssemblyConnectorPortFillColor] (\tikzumlAssemblyConnectorEnd@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port) at (\tikzumlAssemblyConnectorEnd@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port-tmp) {};%
+ }{%
+ \node[inner sep=0] (\tikzumlAssemblyConnectorStart@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port) at (\tikzumlAssemblyConnectorStart@nodeName.\tikzumlAssemblyConnectorStartAnchor) {};%
+ \node[inner sep=0] (\tikzumlAssemblyConnectorEnd@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port) at (\tikzumlAssemblyConnectorEnd@nodeName.\tikzumlAssemblyConnectorEndAnchor) {};%
+ }%
+ %
+ \addtocounter{tikzumlRelationNum}{-1}%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorName}{connector-\thetikzumlConnectorNum}}{%
+ \edef\tikzumlAssemblyConnectorName{relation-\thetikzumlRelationNum}%
+ \edef\tikzumlAssemblyConnectorSymbolName{\tikzumlAssemblyConnectorLabel@nodeName}%
+ }{%
+ \edef\tikzumlAssemblyConnectorSymbolName{\tikzumlAssemblyConnectorName}%
+ }%
+ %
+ \stepcounter{tikzumlRelationNum}%
+ %
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{--}}{%
+ \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorStart@nodeName}{\tikzumlAssemblyConnectorEnd@nodeName}%
+ }{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{-|}}{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorFirstArm}{tikzumlTrue}}{%
+ \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorStart@nodeName}{\tikzumlAssemblyConnectorName-2}%
+ }{%
+ \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorName-2}{\tikzumlAssemblyConnectorEnd@nodeName}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{|-}}{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorFirstArm}{tikzumlTrue}}{%
+ \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorStart@nodeName}{\tikzumlAssemblyConnectorName-2}%
+ }{%
+ \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorName-2}{\tikzumlAssemblyConnectorEnd@nodeName}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{-|-}}{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorFirstArm}{tikzumlTrue}}{%
+ \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorStart@nodeName}{\tikzumlAssemblyConnectorName-2}%
+ }{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorLastArm}{tikzumlTrue}}{%
+ \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorName-4}{\tikzumlAssemblyConnectorEnd@nodeName}%
+ }{%
+ \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorName-2}{\tikzumlAssemblyConnectorName-4}%
+ }%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{|-|}}{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorFirstArm}{tikzumlTrue}}{%
+ \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorStart@nodeName}{\tikzumlAssemblyConnectorName-2}%
+ }{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorLastArm}{tikzumlTrue}}{%
+ \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorName-4}{\tikzumlAssemblyConnectorEnd@nodeName}%
+ }{%
+ \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorName-2}{\tikzumlAssemblyConnectorName-4}%
+ }%
+ }%
+ }{}%
+ }%
+ }%
+ }%
+ }%
+ \stepcounter{tikzumlConnectorNum}%
+}%
+%
+% shortcuts of \umlassemblyconnector
+\newcommand{\umlHVassemblyconnector}[3][]{%
+ \pgfkeys{/tikzuml/HVassemblyconnector/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlHVassemblyconnector, forbidden option geometry}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/HVassemblyconnector/.cd, #1}%
+ \umlassemblyconnector[geometry=-|, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlVHassemblyconnector}[3][]{%
+ \pgfkeys{/tikzuml/VHassemblyconnector/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlVHassemblyconnector, forbidden option geometry}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/VHassemblyconnector/.cd, #1}%
+ \umlassemblyconnector[geometry=|-, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlHVHassemblyconnector}[3][]{%
+ \pgfkeys{/tikzuml/HVHassemblyconnector/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlHVHassemblyconnector, forbidden option geometry}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/HVHassemblyconnector/.cd, #1}%
+ \umlassemblyconnector[geometry=-|-, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlVHVassemblyconnector}[3][]{%
+ \pgfkeys{/tikzuml/VHVassemblyconnector/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlVHVassemblyconnector, forbidden option geometry}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/VHVassemblyconnector/.cd, #1}%
+ \umlassemblyconnector[geometry=|-|, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlport}[3][]{%
+ \pgfkeys{/tikzuml/port/.cd, draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlPortDefaultFillColor,%
+ width/.initial=\tikzumlPortDefaultWidth,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \errmessage{TIKZUML ERROR : in umlport forbidden option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/port/.cd, #1}%
+ \pgfkeys{/tikzuml/port/.cd, width/.get=\tikzumlPortWidth,%
+ draw/.get=\tikzumlPortDrawColor, fill/.get=\tikzumlPortFillColor}%
+ \edef\tikzumlPort@name{#2}%
+ \edef\tikzumlPort@anchor{#3}%
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlPort@nodeName{\tikzumlPort@name}}\x%
+ %
+ \node[inner sep=0.5*\tikzumlPortWidth, rectangle, draw=\tikzumlPortDrawColor, fill=\tikzumlPortFillColor] (\tikzumlPort@nodeName-\tikzumlPort@anchor-port) at (\tikzumlPort@nodeName.\tikzumlPort@anchor) {};%
+}%
+%
+\newcommand{\umldelegateconnector}[3][]{%
+ \def\tikzumlDelegateConnectorWithStartPort{tikzumlFalse}%
+ \def\tikzumlDelegateConnectorWithEndPort{tikzumlFalse}%
+ \pgfkeys{/tikzuml/delegateconnector/.cd,
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umldelegateconnector, forbidden option stereo}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/delegateconnector/.cd, #1}%
+ \umlrelation[style={tikzuml connector style}, stereo=delegate, #1]{#2}{#3}%
+}%
+%
+% shortcuts of \umldelegateconnector
+\newcommand{\umlHVdelegateconnector}[3][]{%
+ \pgfkeys{/tikzuml/HVdelegateconnector/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}\OR\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlHVdelegateconnector, forbidden option \keyname}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/HVdelegateconnector/.cd, #1}%
+ \umldelegateconnector[geometry=-|, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlVHdelegateconnector}[3][]{%
+ \pgfkeys{/tikzuml/VHdelegateconnector/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}\OR\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlVHdelegateconnector, forbidden option \keyname}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/VHdelegateconnector/.cd, #1}%
+ \umldelegateconnector[geometry=|-, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlHVHdelegateconnector}[3][]{%
+ \pgfkeys{/tikzuml/HVHdelegateconnector/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}\OR\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlHVHdelegateconnector, forbidden option \keyname}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/HVHdelegateconnector/.cd, #1}%
+ \umldelegateconnector[geometry=-|-, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlVHVdelegateconnector}[3][]{%
+ \pgfkeys{/tikzuml/VHVdelegateconnector/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}\OR\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlVHVdelegateconnector, forbidden option \keyname}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/VHVdelegateconnector/.cd, #1}%
+ \umldelegateconnector[geometry=|-|, #1]{#2}{#3}%
+}%
+%%% End of tikz-uml.sty
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \ No newline at end of file
diff --git a/10-entwurfsheft/titlepage.tex b/10-entwurfsheft/titlepage.tex
new file mode 100644
index 0000000..cc1d67b
--- /dev/null
+++ b/10-entwurfsheft/titlepage.tex
@@ -0,0 +1,75 @@
+%% Encoding: UTF-8 %%
+
+%% titlepage.tex
+
+\def\usesf{}
+\let\usesf\sffamily % diese Zeile auskommentieren für normalen TeX Font
+
+\begin{titlepage}
+
+\setlength{\unitlength}{1pt}
+\begin{picture}(00,0)(70,770)
+ \includegraphics[width=\paperwidth]{assets/KIT_Deckblatt.pdf}
+\end{picture}
+
+\thispagestyle{empty}
+
+\begin{center}
+\hbox{}
+\vfill
+\includegraphics[width=.5\textwidth]{assets/logo.pdf}
+\vskip 1cm
+{\usesf
+ {\huge\bfseries PSE\textsuperscript{2} - Podcast Synchronisation \\
+ made Efficient\\
+ Entwurfsheft \par}
+\vskip 1.8cm
+{\Large Wintersemester 2022/2023\\}
+%von\\[2mm]
+\vskip 1.5cm
+
+% {\large\bfseries Vorname Nachname\\}
+% \vskip 1.2cm
+Praxis der Softwareentwicklung \\
+Prof. Dr.-Ing. Gregor Snelting \\
+Fakultät für Informatik\\
+Karlsruher Institut für Technologie\\
+\vskip 1.5cm
+\begin{tabular}{p{20mm}l}
+Autoren:
+& Daniel Hönlinger \\
+& Gero Beckmann \\
+& Immanuel Reitz \\
+& Julius Friesen \\
+& Lukas Schmidheissler \\
+\\
+Betreuer: & M.Sc. Hans-Peter Lehmann \\
+ & M.Sc. Daniel Seemaier
+\end{tabular}
+}
+\end{center}
+\vfill
+
+%\begin{textblock}{10}[0,0](4,15)
+% \includegraphics[width=.3\textwidth]{logos/logo.pdf}
+%\end{textblock}
+
+% \begin{textblock}{8}[0,0](14,14)
+% \includegraphics[width=.3\textwidth]{logos/KASTEL_logo.pdf}
+% \end{textblock}
+
+\end{titlepage}
+
+% \thispagestyle{empty}
+% \ \vfill
+% \begin{flushleft}
+% Copyright $\copyright$ ITI und Verfasser 201?\\
+% \ \\
+% Institut für Theoretische Informatik
+% Fakultät für Informatik\\
+% Karlsruher Institut für Technologie\\
+% Am Fasanengarten 5\\
+% 76131 Karlsruhe
+% \end{flushleft}
+% \newpage
+
diff --git a/11-entwurfsheft-kolloquium/.gitignore b/11-entwurfsheft-kolloquium/.gitignore
new file mode 100644
index 0000000..87ec682
--- /dev/null
+++ b/11-entwurfsheft-kolloquium/.gitignore
@@ -0,0 +1,302 @@
+## Core latex/pdflatex auxiliary files:
+*.aux
+*.lof
+*.log
+*.lot
+*.fls
+*.out
+*.toc
+*.fmt
+*.fot
+*.cb
+*.cb2
+.*.lb
+
+## Intermediate documents:
+*.dvi
+*.xdv
+*-converted-to.*
+# these rules might exclude image files for figures etc.
+# *.ps
+# *.eps
+*.pdf
+!assets/*.pdf
+
+## Generated if empty string is given at "Please type another file name for output:"
+.pdf
+
+## Bibliography auxiliary files (bibtex/biblatex/biber):
+*.bbl
+*.bcf
+*.blg
+*-blx.aux
+*-blx.bib
+*.run.xml
+
+## Build tool auxiliary files:
+*.fdb_latexmk
+*.synctex
+*.synctex(busy)
+*.synctex.gz
+*.synctex.gz(busy)
+*.pdfsync
+
+## Build tool directories for auxiliary files
+# latexrun
+latex.out/
+
+## Auxiliary and intermediate files from other packages:
+# algorithms
+*.alg
+*.loa
+
+# achemso
+acs-*.bib
+
+# amsthm
+*.thm
+
+# beamer
+*.nav
+*.pre
+*.snm
+*.vrb
+
+# changes
+*.soc
+
+# comment
+*.cut
+
+# cprotect
+*.cpt
+
+# elsarticle (documentclass of Elsevier journals)
+*.spl
+
+# endnotes
+*.ent
+
+# fixme
+*.lox
+
+# feynmf/feynmp
+*.mf
+*.mp
+*.t[1-9]
+*.t[1-9][0-9]
+*.tfm
+
+#(r)(e)ledmac/(r)(e)ledpar
+*.end
+*.?end
+*.[1-9]
+*.[1-9][0-9]
+*.[1-9][0-9][0-9]
+*.[1-9]R
+*.[1-9][0-9]R
+*.[1-9][0-9][0-9]R
+*.eledsec[1-9]
+*.eledsec[1-9]R
+*.eledsec[1-9][0-9]
+*.eledsec[1-9][0-9]R
+*.eledsec[1-9][0-9][0-9]
+*.eledsec[1-9][0-9][0-9]R
+
+# glossaries
+*.acn
+*.acr
+*.glg
+*.glo
+*.gls
+*.glsdefs
+*.lzo
+*.lzs
+*.slg
+*.slo
+*.sls
+
+# uncomment this for glossaries-extra (will ignore makeindex's style files!)
+*.ist
+
+# gnuplot
+*.gnuplot
+*.table
+
+# gnuplottex
+*-gnuplottex-*
+
+# gregoriotex
+*.gaux
+*.glog
+*.gtex
+
+# htlatex
+*.4ct
+*.4tc
+*.idv
+*.lg
+*.trc
+*.xref
+
+# hyperref
+*.brf
+
+# knitr
+*-concordance.tex
+# TODO Uncomment the next line if you use knitr and want to ignore its generated tikz files
+# *.tikz
+*-tikzDictionary
+
+# listings
+*.lol
+
+# luatexja-ruby
+*.ltjruby
+
+# makeidx
+*.idx
+*.ilg
+*.ind
+
+# minitoc
+*.maf
+*.mlf
+*.mlt
+*.mtc[0-9]*
+*.slf[0-9]*
+*.slt[0-9]*
+*.stc[0-9]*
+
+# minted
+_minted*
+*.pyg
+
+# morewrites
+*.mw
+
+# newpax
+*.newpax
+
+# nomencl
+*.nlg
+*.nlo
+*.nls
+
+# pax
+*.pax
+
+# pdfpcnotes
+*.pdfpc
+
+# sagetex
+*.sagetex.sage
+*.sagetex.py
+*.sagetex.scmd
+
+# scrwfile
+*.wrt
+
+# svg
+svg-inkscape/
+
+# sympy
+*.sout
+*.sympy
+sympy-plots-for-*.tex/
+
+# pdfcomment
+*.upa
+*.upb
+
+# pythontex
+*.pytxcode
+pythontex-files-*/
+
+# tcolorbox
+*.listing
+
+# thmtools
+*.loe
+
+# TikZ & PGF
+*.dpth
+*.md5
+*.auxlock
+
+# titletoc
+*.ptc
+
+# todonotes
+*.tdo
+
+# vhistory
+*.hst
+*.ver
+
+# easy-todo
+*.lod
+
+# xcolor
+*.xcp
+
+# xmpincl
+*.xmpi
+
+# xindy
+*.xdy
+
+# xypic precompiled matrices and outlines
+*.xyc
+*.xyd
+
+# endfloat
+*.ttt
+*.fff
+
+# Latexian
+TSWLatexianTemp*
+
+## Editors:
+# WinEdt
+*.bak
+*.sav
+
+# Texpad
+.texpadtmp
+
+# LyX
+*.lyx~
+
+# Kile
+*.backup
+
+# gummi
+.*.swp
+
+# KBibTeX
+*~[0-9]*
+
+# TeXnicCenter
+*.tps
+
+# auto folder when using emacs and auctex
+./auto/*
+*.el
+
+# expex forward references with \gathertags
+*-tags.tex
+
+# standalone packages
+*.sta
+
+# Makeindex log files
+*.lpz
+
+# xwatermark package
+*.xwm
+
+# REVTeX puts footnotes in the bibliography by default, unless the nofootinbib
+# option is specified. Footnotes are the stored in a file with suffix Notes.bib.
+# Uncomment the next line to have this generated file ignored.
+#*Notes.bib
diff --git a/11-entwurfsheft-kolloquium/.gitlab-ci.yml b/11-entwurfsheft-kolloquium/.gitlab-ci.yml
new file mode 100644
index 0000000..27d0617
--- /dev/null
+++ b/11-entwurfsheft-kolloquium/.gitlab-ci.yml
@@ -0,0 +1,36 @@
+plantuml:
+ stage: .pre
+ image:
+ name: plantuml/plantuml
+ entrypoint: [""]
+ script:
+ - java -jar plantuml.jar -tpdf assets/diagrams/*.puml
+ artifacts:
+ paths:
+ - assets
+
+tex:
+ stage: build
+ image: texlive/texlive
+ script:
+ - mkdir public
+ - make tex
+ - mv *.pdf public
+ artifacts:
+ paths:
+ - public
+ dependencies:
+ - plantuml
+
+pages:
+ stage: deploy
+ script:
+ - echo Hello, World!
+ artifacts:
+ paths:
+ - public
+ rules:
+ - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
+ dependencies:
+ - tex
+
diff --git a/11-entwurfsheft-kolloquium/CHANGELOG.md b/11-entwurfsheft-kolloquium/CHANGELOG.md
new file mode 100644
index 0000000..7671a41
--- /dev/null
+++ b/11-entwurfsheft-kolloquium/CHANGELOG.md
@@ -0,0 +1,34 @@
+# Changelog
+Alle Änderungen an diesem Projekt werden in dieser Datei dokumentiert.
+Die Versionsnummern folgt der Syntax in `sdqbeamer.cls`.
+
+## [2022-05-03 v3.1.3]
+- Die Breite des Gruppennamens in der Fußzeile kann nun über `\groupnamewidth{}` gesteuert werden
+- FIX: zweizeilige Fußzeilen haben nun gleichmäßigen vertikalen Abstand (Issue #16 in Gitlab)
+
+## [2021-08-10 v3.1.2]
+- FIX: framesubtitle wird nun angezeigt (Issue #6 in Gitlab)
+
+## [2020-12-08 v3.1.1]
+- FIX: Titelbild (Issue #4 in Gitlab)
+
+## [2020-12-07 v3.1]
+- Umgebung ``contentblock`` (farbloser Block mit fetter Überschrift) hinzugefügt
+- Farbboxen (``greenblock``, ``blueblock``, …) hinzugefügt
+- Abstufungen der KIT-Farben in 10er-Schritten entsprechend der Gestaltungsrichtlinien eingeführt
+- FIX: Navigationspunkte für Subsections in eine Zeile gesetzt, um vertikal Platz zu sparen
+- FIX: ``inputenc`` an den Anfang von ``sdqbeamer.cls`` verschoben
+
+## [2020-11-16 v3.0]
+- Seitenformat 16:10 hinzugefügt
+- Umstellung auf KIT-Design vom 1. August 2020
+ - Anpassung auf neues Farbschema und Maße
+ - neues Titelbild aus der KIT-Bildwelt
+- Neue Optionen:
+ - durch `smallfoot` und `bigfoot` kann die Schriftgröße der Fußzeile gesteuert werden
+ - durch `navbarkit` kann eine Fußzeile nach KIT-Vorgaben erzwungen werden
+- Deutsch (`de`) ist nun die Standard-Option
+- Ordner `templates` wurde gelöscht und die Inhalte in `sdqbeamer.cls` integriert
+- Globale Größe auf 10 pt verringert (vorher: 11 pt), da der beschreibbare Bereich im Vergleich zur 2009er Version kleiner geworden ist
+- SDQ-spezifische Logos und Titelbilder entfernt. Diese sind ab sofort im Branch »sdq« verfügbar.
+- Fix: Zeilenumbruch bei Titel in der Fußzeile repariert \ No newline at end of file
diff --git a/11-entwurfsheft-kolloquium/Makefile b/11-entwurfsheft-kolloquium/Makefile
new file mode 100644
index 0000000..67f5384
--- /dev/null
+++ b/11-entwurfsheft-kolloquium/Makefile
@@ -0,0 +1,18 @@
+MAIN = presentation
+FLAGS = -pdf
+
+all: clean compile
+compile: diagram tex
+clean: clean-diagram clean-tex
+
+dev:
+ latexmk $(FLAGS) -pvc $(MAIN)
+tex:
+ latexmk $(FLAGS) $(MAIN)
+diagram:
+ java -jar plantuml.jar -tpdf assets/diagrams/*.puml
+clean-tex:
+ latexmk -C
+clean-diagram:
+ find assets/diagrams -type f -not -name '*.puml' -delete
+
diff --git a/11-entwurfsheft-kolloquium/README.md b/11-entwurfsheft-kolloquium/README.md
new file mode 100644
index 0000000..6a5e9ea
--- /dev/null
+++ b/11-entwurfsheft-kolloquium/README.md
@@ -0,0 +1,118 @@
+LaTeX-Vorlage für Präsentationen
+================================
+
+Das vorliegende Paket dient als Vorlage für Präsentationen im [Corporate Design des KIT](https://intranet.kit.edu/gestaltungsrichtlinien.php) (Fassung vom 1. August 2020).
+
+Es wird an der Forschungsgruppe [DSiS](https://dsis.kastel.kit.edu) an der KIT-Fakultät für Informatik entwickelt und basiert auf [LaTeX Beamer](https://ctan.org/pkg/beamer).
+
+Autor: [Dr.-Ing. Erik Burger](https://dsis.kastel.kit.edu/staff_erik_burger.php)
+mit Beiträgen von Christian Hammer, Klaus Krogmann und Maximilian Schambach
+
+Siehe https://sdqweb.ipd.kit.edu/wiki/Dokumentvorlagen
+
+Hinweise, Verbesserungsvorschläge
+=================================
+
+Bitte verwenden Sie das [Issue-Tracking-System von Gitlab](https://git.scc.kit.edu/i43/dokumentvorlagen/praesentationen/beamer/-/issues), um auf Probleme mit der Vorlage hinzuweisen oder Erweiterungswünsche zu äußern. Sie können gerne auch eine Änderung per Merge-Request vorschlagen.
+
+Verwendung
+==========
+
+Optionen der Dokumentklasse `sdqbeamer`
+-----------------------------------------
+Durch die folgenden Optionen kann das Seitenverhältnis der Folien bestimmt werden:
+
+| Seitenverhältnis | Option |
+| ---------------- | ------------------- |
+| 16:9 | `16:9` (Standard) |
+| 16:10 | `16:10` |
+| 4:3 | `4:3` |
+
+Die Schriftgröße in der Fußzeile ist standardmäßig größer gewählt, als in den Gestaltungsrichtlinien vorgegeben. Diese Vorgabe kann durch die Option `smallfoot` erzwungen werden.
+
+| Schriftgröße Fußzeile | Option |
+| ----------------------| -------------------- |
+| etwas größer (12pt) | `bigfoot` (Standard) |
+| KIT-Vorgabe (9pt) | `smallfoot` |
+
+Die Plazierung der Navigationsleiste kann durch folgende Optionen beeinflußt werden:
+
+| Position | Option | Bemerkung |
+| ------------------------ | ---------------- | ------------------------------------------ |
+| oberhalb der Trennlinie | `navbarinline` | Standard |
+| unterhalb der Trennlinie | `navbarinfooter` | keine Subsection-Punkte, Größe `smallfoot` |
+| Seitenleiste links | `navbarside` | keine Subsection-Punkte |
+| keine Navigationsleiste | `navbaroff` | |
+| KIT-Vorgabe | `navbarkit` | entspricht `navbaroff` und `smallfoot` |
+
+Als Sprache sind Deutsch und Englisch verfügbar. Durch die Sprachwahl werden automatisch die passenden Logos und Formate (z.B. Datum) gewählt.
+
+| Sprache | |
+| -------- |---------------- |
+| Deutsch | `de` (Standard) |
+| Englisch | `en` |
+
+Beispiel: `\documentclass[de,16:9,navbarinline]{sdqbeamer}`
+
+Titelbild
+---------
+
+Das Bild auf der Titelfolie kann mit dem Befehl
+
+`\titleimage{myimage}` (ohne Dateiendung)
+
+gesetzt werden. Um ein eigenes Bild zu verwenden, bitte die Datei (z.B. `myimage.jpg`) ins `logos/`-Verzeichnis legen und den Befehl anpassen. Mitgeliefert wird ein generisches Bild aus der KIT-Bildwelt (https://intranet.kit.edu/gestaltungsrichtlinien.php) in der Datei `logos/banner_2020_kit.jpg`. Falls kein Titelbild eingefügt werden soll, bitte `\titleimage{}` setzen.
+
+Für 16:9-Folien sollte das Verhältnis des Bildes 160:37 betragen, für 4:3-Folien 63:20. Es können auch breitere Bilder verwendet werden, da das Titelbild auf die Höhe des Rahmens skaliert und zentriert wird.
+
+Logo und Name Abteilung/KIT-Fakultät/Institut
+---------------------------------------------
+
+Das Logo rechts oben auf der Titelfolie kann mit dem folgenden Befehl gesetzt werden:
+
+`\grouplogo{mylogo}` (ohne Dateiendung)
+
+Um ein eigenes Logo zu verwenden, bitte die Datei (z.B. `mylogo.pdf`) in das Verzeichnis `logos/` legen und den Befehl anpassen. Falls kein Logo eingefügt werden soll, bitte `\grouplogo{}` setzen.
+
+Der Gruppenname kann mit folgendem Befehl gesetzt werden:
+
+`\groupname{Software Design and Quality}`
+
+Der Gruppenname erscheint in der Fußzeile rechts unten. Lange Namen werden in zwei Zeilen umgebrochen. Falls der Gruppenname leer gelassen wird (`\groupname{}`), wird die volle Breite der Fußzeile für Autornamen und Titel verwendet.
+
+Die Standardbreite des Gruppennamens sind 50 mm. Sie kann mit
+
+`\groupnamewidth{80mm}`
+
+verändert werden, wodurch sich auch die Breite des Textfeldes mit Autor und Titel entsprechend ändert. Umbrüche sind mit `\\` möglich. Statt zweizeiliger Fußzeilen empfiehlt sich eventuell die Option `smallfoot`.
+
+LaTeX allgemein
+---------------
+Siehe https://sdqweb.ipd.kit.edu/wiki/LaTeX
+
+Dateistruktur
+============
+`presentation.tex`
+------------------
+Hauptdatei des LaTeX-Dokuments.
+
+`presentation.bib`
+-------------
+Beispieldatei für BibTeX-Referenzen
+https://sdqweb.ipd.kit.edu/wiki/BibTeX-Literaturlisten
+
+`sdqbeamer.cls`
+-----------------
+Dokumentklasse für Präsentationen im KIT-Design.
+
+`logos/`
+--------
+In diesem Verzeichnis befinden das KIT-Logo als PDF sowie das Hintergrundbild der Titelfolie als JPG.
+
+`CHANGELOG.md`
+--------------
+Dokumentation der Änderungen in den jeweiligen Versionen.
+
+`README.md`
+-----------
+Dieser Text.
diff --git a/11-entwurfsheft-kolloquium/assets/.gitignore b/11-entwurfsheft-kolloquium/assets/.gitignore
new file mode 100644
index 0000000..16252a4
--- /dev/null
+++ b/11-entwurfsheft-kolloquium/assets/.gitignore
@@ -0,0 +1,3 @@
+diagrams/*
+!diagrams/*.puml
+
diff --git a/11-entwurfsheft-kolloquium/assets/.gitingnore b/11-entwurfsheft-kolloquium/assets/.gitingnore
new file mode 100644
index 0000000..16252a4
--- /dev/null
+++ b/11-entwurfsheft-kolloquium/assets/.gitingnore
@@ -0,0 +1,3 @@
+diagrams/*
+!diagrams/*.puml
+
diff --git a/11-entwurfsheft-kolloquium/assets/KIT_Deckblatt.pdf b/11-entwurfsheft-kolloquium/assets/KIT_Deckblatt.pdf
new file mode 100644
index 0000000..7de8ed4
--- /dev/null
+++ b/11-entwurfsheft-kolloquium/assets/KIT_Deckblatt.pdf
Binary files differ
diff --git a/11-entwurfsheft-kolloquium/assets/diagrams/backendComponentDiagram.puml b/11-entwurfsheft-kolloquium/assets/diagrams/backendComponentDiagram.puml
new file mode 100644
index 0000000..806522c
--- /dev/null
+++ b/11-entwurfsheft-kolloquium/assets/diagrams/backendComponentDiagram.puml
@@ -0,0 +1,61 @@
+@startuml
+' skinparam linetype ortho
+
+'#########################################################################
+'SubscriptionsAPI
+component SubscriptionsAPI {
+
+ component SubscriptionService
+ component SubscriptionController
+ component SubscriptionDataAccessLayer
+
+ portout "Webserver" as wSub
+ portin "Database" as dSub
+ }
+
+dSub --0)- SubscriptionDataAccessLayer
+SubscriptionDataAccessLayer --0)- SubscriptionService
+SubscriptionService --0)- SubscriptionController
+SubscriptionController --0)- wSub
+
+'#########################################################################
+
+
+'#########################################################################
+'EpisodeActionsAPI
+
+component EpisodeActionsAPI {
+ component EpisodeActionService
+ component EpisodeActionController
+ component EpisodeActionDataAccessLayer
+
+ portout "Webserver" as wEpisode
+ portin "Database" as dEpisode
+}
+
+dEpisode --0)- EpisodeActionDataAccessLayer
+EpisodeActionController --0)- wEpisode
+EpisodeActionDataAccessLayer --0)- EpisodeActionService
+EpisodeActionService --0)- EpisodeActionController
+
+'#########################################################################
+
+
+'#########################################################################
+'AuthenticationAPI
+
+component AuthenticationAPI {
+ component AuthenticationService
+ component AuthenticationController
+ component AuthenticationDataAccessLayer
+
+ portout "Webserver" as wAuth
+ portin "Database" as dAuth
+}
+
+dAuth --0)- AuthenticationDataAccessLayer
+AuthenticationController --0)- wAuth
+AuthenticationDataAccessLayer --0)- AuthenticationService
+AuthenticationService --0)- AuthenticationController
+
+@enduml
diff --git a/11-entwurfsheft-kolloquium/assets/diagrams/classdiagram-authentication.puml b/11-entwurfsheft-kolloquium/assets/diagrams/classdiagram-authentication.puml
new file mode 100644
index 0000000..a2b3518
--- /dev/null
+++ b/11-entwurfsheft-kolloquium/assets/diagrams/classdiagram-authentication.puml
@@ -0,0 +1,112 @@
+@startuml
+
+package authenticationAPI <<Frame>> {
+ package authenticationDataAccessLayer <<Frame>> {
+ ' interface AuthenticationDao {
+ ' String login(String username)
+ ' int logout(String username)
+ ' }
+
+ ' class AuthenticationDataAccessService <<@Respository>> {
+ ' <<create>> AuthenticationDataAccessService(JpaTemplate jpaTemplate)
+ ' String login(String username)
+ ' int logout(String username)
+ ' }
+
+ interface UserDetailsManager {
+ void createUser(UserDetails userDetails)
+ void changePassword(String oldPassword, String newPassword)
+ void deleteUser(String username)
+ void updateUser(UserDetails user)
+ boolean userExists(String username)
+ }
+ note left
+ Aus org.springframework.security.provisioning
+ - liefert Methoden zum Erstellen neuer User
+ und zum Aktualisieren bestehender.
+ end note
+
+ class JdbcUserDetailsManager <<@Repository>> {
+ <<create>> JdbcUserDetailsManager(DataSource dataSource)
+ void createUser(UserDetails user)
+ void changePassword(String oldPassword, String newPassword)
+ void deleteUser(String username)
+ void updateUser(UserDetails user)
+ boolean userExists(String username)
+ }
+ note right
+ User Management Service aus dem Paket
+ org.springframework.security.provisioning
+ der CRUD Operationen für User bereitstellt.
+ Hier sind nur die relevanten Methoden modelliert.
+ end note
+ }
+
+ package authenticationService <<Frame>> {
+ class AuthenticationService <<@Service>> {
+ --
+ <<create>> AuthenticationService(UserDetailsManager userDetailsManager)
+ List<String> verifyLogin(String username)
+ int logout(String username)
+ int forgotPassword(ForgotPasswordRequest forgotPasswordRequest)
+ .. via JdbcUserDetailsManager ..
+ int resetPassword(String username, RequestWithPassword requestWithPassword)
+ int registerUser(UserDetails user)
+ int changePassword(String username, ChangePasswordRequest changePasswordRequest)
+ int deleteUser(String username, RequestWithPassword requestWithPassword)
+ }
+
+ class JavaMailSenderImpl {}
+ note left
+ Aus org.springframework.mail.javamail.
+ Implementierung des JavaMailSender Interfaces,
+ welches das MailSender Interface durch Unterstützung
+ von MIME Nachrichten erweitert.
+ Das MailSender Interface definiert dabei eine
+ Strategie zum Versenden einfacher Mails.
+ Unterstützt sowohl JavaMail MimeMessages und
+ Spring SimpleMailMessages.
+ end note
+ }
+
+ package authenticationController <<Frame>> {
+ class AuthenticationController <<@Controller>> {
+ <<create>> AuthenticationController(AuthenticationService authenticationService)
+ ResponseEntity<List<String>> verifyLogin(String username)
+ ResponseEntity<Integer> logout(String username)
+ ResponseEntity<Integer> forgotPassword(ForgotPasswordRequest forgotPasswordRequest)
+ ResponseEntity<Integer> resetPassword(String username, RequestWithPassword requestWithPassword)
+ ResponseEntity<Integer> registerUser(UserDetails user)
+ ResponseEntity<Integer> changePassword(String username, ChangePasswordRequest changePasswordRequest)
+ ResponseEntity<Integer> deleteUser(String username, RequestWithPassword requestWithPassword)
+ }
+
+ class ChangePasswordRequest {
+ <<create>> ChangePasswordRequest(String oldPassword, String newPassword)
+ String getOldPassword()
+ String getNewPassword()
+ }
+
+ class ForgotPasswordRequest {
+ <<create>> ForgotPasswordRequest(String email)
+ String getEmail()
+ }
+
+ class RequestWithPassword {
+ <<create>> ResetPasswordRequest(String password)
+ String getPassword()
+ }
+ }
+}
+
+' User <.. AuthenticationDataAccessService: DB
+' User <.. JdbcUserDetailsManager: DB
+UserDetailsManager <.. AuthenticationService: <<use>>
+' AuthenticationDao <.. AuthenticationService: <<use>>
+AuthenticationService --o AuthenticationController
+' AuthenticationDao <|. AuthenticationDataAccessService: <<realize>>
+UserDetailsManager <|. JdbcUserDetailsManager: <<realize>>
+JavaMailSenderImpl <. AuthenticationService: <<use>>
+
+@enduml
+
diff --git a/11-entwurfsheft-kolloquium/assets/diagrams/classdiagram-episode-actions.puml b/11-entwurfsheft-kolloquium/assets/diagrams/classdiagram-episode-actions.puml
new file mode 100644
index 0000000..7a4530e
--- /dev/null
+++ b/11-entwurfsheft-kolloquium/assets/diagrams/classdiagram-episode-actions.puml
@@ -0,0 +1,84 @@
+@startuml
+
+package episodeActionsAPI <<Frame>> {
+ package episodeActionDataAccessLayer <<Frame>> {
+ class EpisodeActionDataAccessService <<@Repository>> {
+ <<create>> EpisodeActionDataAccessService (JpaTemplate jpaTemplate)
+ long addEpisodeActions(String username, List<EpisodeActionPost> episodeActionPosts)
+ List<EpisodeActionPost> getEpisodeActions(String username)
+ List<EpisodeActionPost> getEpisodeActionsOfPodcast(String username, String podcastURL)
+ List<EpisodeActionPost> getEpisodeActionsSince(String username, LocalDateTime since)
+ List<EpisodeActionPost> getEpisodeActionsOfPodcastSince(String username, String podcastURL, LocalDateTime since)
+ }
+
+ interface EpisodeActionDao {
+ long addEpisodeActions(String username, List<EpisodeActionPost> episodeActionPosts)
+ List<EpisodeActionPost> getEpisodeActions(String username)
+ List<EpisodeActionPost> getEpisodeActionsOfPodcast(String username, String podcastURL)
+ List<EpisodeActionPost> getEpisodeActionsSince(String username, LocalDateTime since)
+ List<EpisodeActionPost> getEpisodeActionsOfPodcastSince(String username, String podcastURL, LocalDateTime since)
+ }
+ }
+
+ package episodeActionService <<Frame>> {
+ class EpisodeActionService <<@Service>> {
+ <<create>> EpisodeActionService (EpisodeActionDao episodeActionDao)
+ LocalDateTime addEpisodeActions(String username, List<EpisodeActionPosts> episodeActionPosts)
+ List<EpisodeActionPost> getEpisodeActions(String username)
+ List<EpisodeActionPost> getEpisodeActionsOfPodcast(String username, String podcastURL)
+ List<EpisodeActionPost> getEpisodeActionsSince(String username, LocalDateTime since)
+ List<EpisodeActionPost> getEpisodeActionsOfPodcastSince(String username, String podcastURL, LocalDateTime since)
+ }
+ }
+
+ package episodeActionController <<Frame>> {
+ class EpisodeActionController <<@Controller>>{
+ <<create>> EpisodeActionController (EpisodeActionService episodeActionService)
+ ResponseEntity<EpisodeActionPostResponse> addEpisodeActions(String username, EpisodeActionPostRequest episodeActionPostRequest)
+ ResponseEntity<EpisodeActionGetResponse> getEpisodeActions(String username, String deviceID, boolean aggregated)
+ ResponseEntity<EpisodeActionGetResponse> getEpisodeActionsOfPodcast(String username, String podcastURL, String deviceID, boolean aggregated)
+ ResponseEntity<EpisodeActionGetResponse> getEpisodeActionsSince(String username, String deviceID, long since, boolean aggregated)
+ ResponseEntity<EpisodeActionGetResponse> getEpisodeActionsOfPodcastSince(String username, String podcastURL, String deviceID, long since, boolean aggregated)
+ }
+
+ class EpisodeActionPostResponse {
+ <<create>> EpisodeActionPostResponse(List<Pair<String, String>> updateURLs)
+ long getTimestamp()
+ List<Pair<String, String>> getUpdatedURLs()
+ }
+
+ class EpisodeActionPost {
+ <<create>> EpisodeActionPost(String podcastURL, String episodeURL, Action action, LocalDateTime timestamp, int started, int position)
+ String getPodcastURL()
+ String getEpisodeURL()
+ int getGUID()
+ Action getAction()
+ LocalDateTime getTimestamp()
+ int getStarted()
+ int getPosition()
+ EpisodeAction getEpisodeAction()
+ }
+
+ class EpisodeActionPostRequest {
+ <<create>> EpisodeActionPostRequest(List<EpisodeActionPost> episodeActionPosts)
+ List<EpisodeActionPost> getEpisodeActionPosts()
+ }
+
+ class EpisodeActionGetResponse {
+ <<create>> EpisodeActionGetResponse(List<EpisodeActionPost> episodeActionPosts)
+ List<EpisodeActionPost> getEpisodeActionPosts()
+ long getTimestamp()
+ }
+ }
+}
+
+EpisodeActionPost -o EpisodeActionGetResponse
+EpisodeActionPost -o EpisodeActionPostRequest
+' EpisodeAction <.. EpisodeActionDataAccessService: DB
+' Episode <.. EpisodeActionDataAccessService: DB
+EpisodeActionDao <.. EpisodeActionService: <<use>>
+EpisodeActionService --o EpisodeActionController
+EpisodeActionDao <|. EpisodeActionDataAccessService: <<realize>>
+
+@enduml
+
diff --git a/11-entwurfsheft-kolloquium/assets/diagrams/classdiagram-model.puml b/11-entwurfsheft-kolloquium/assets/diagrams/classdiagram-model.puml
new file mode 100644
index 0000000..72ad49f
--- /dev/null
+++ b/11-entwurfsheft-kolloquium/assets/diagrams/classdiagram-model.puml
@@ -0,0 +1,109 @@
+@startuml
+
+package model <<Frame>> {
+ class Subscription {
+ <<create>> Subscription(String url, String title)
+ int getID()
+ String getURL()
+ long getLastActionTimestamp()
+ String getTitle()
+ }
+
+ class SubscriptionAction {
+ <<create>> SubscriptionAction(int userID, int subscriptionID)
+ int getID()
+ int getUserID()
+ int getSubscriptionID()
+ long getTimestamp()
+ boolean getAdded()
+ }
+
+ class Episode {
+ <<create>> Episode(int subscriptionID, int id, String url, String title, String thumbnailURL, int total)
+ int getSubscriptionID()
+ int getID()
+ int getGUID()
+ String getURL()
+ String getTitle()
+ int getTotal()
+ }
+
+ enum Action {
+ Download
+ Play
+ Delete
+ New
+ Flattr
+ String getJsonProperty()
+ }
+
+ class EpisodeAction {
+ <<create>> EpisodeAction(Action action, LocalDateTime timestamp, int started, int position)
+ int getEpisodeID()
+ Action getAction()
+ long getTimestamp()
+ int getStarted()
+ int getPosition()
+ void setEpisodeID()
+ EpisodeActionPost getEpisodeActionPost(String podcastURL, String episodeURL)
+ }
+
+ interface UserDetails {
+ String getUsername()
+ String getPassword()
+ Collection<Authority> getAuthorities()
+ boolean isAccountExpired()
+ boolean isAccountLocked()
+ boolean isCredentialsNonExpired()
+ boolean isEnabled()
+ }
+ note left
+ Aus org.springframework.security.core.userdetails.
+ Wird für die Schnittstelle UserDetailsManager benötigt.
+ Stellt wichtige Informationen eines Users bereit.
+ Diese werden nur indirekt von Spring Security
+ benutzt, indem sie vorher in Authentication Objekten
+ gekapselt werden.
+ end note
+
+ class User {
+ --
+ <<create>> User(String username, String password)
+ int getID()
+ String getSessionToken()
+ boolean getEmailIsValidated()
+ .. interface methods ..
+ String getUsername()
+ String getPassword()
+ Collection<Authority> getAuthorities()
+ boolean isAccountExpired()
+ boolean isAccountLocked()
+ boolean isCredentialsNonExpired()
+ boolean isEnabled()
+ }
+
+ interface GrantedAuthority {
+ String getAuthority()
+ }
+ note right
+ Aus org.springframework.security.core.
+ Wird für die Schnittstelle UserDetails benötigt.
+ Repräsentiert eine Autorisierung, die einem
+ Authentication Objekt gewährt wird.
+ end note
+
+ class Authority {
+ <<create>> Authority()
+ String getAuthority()
+ }
+}
+
+Subscription <. SubscriptionAction: ID
+Action <-- EpisodeAction
+EpisodeAction .> Episode: ID
+UserDetails <|.. User: <<realize>>
+User -> Authority
+GrantedAuthority <|.. Authority: <<realize>>
+
+@enduml
+
diff --git a/11-entwurfsheft-kolloquium/assets/diagrams/classdiagram-subscriptions.puml b/11-entwurfsheft-kolloquium/assets/diagrams/classdiagram-subscriptions.puml
new file mode 100644
index 0000000..432f185
--- /dev/null
+++ b/11-entwurfsheft-kolloquium/assets/diagrams/classdiagram-subscriptions.puml
@@ -0,0 +1,75 @@
+@startuml
+
+package subscriptionsAPI <<Frame>> {
+ package subscriptionDataAccessLayer <<Frame>> {
+ class SubscriptionDataAccessService <<@Repository>> {
+ <<create>> SubscriptionDataAccessService(JpaTemplate jpaTemplate)
+ int uploadSubscriptions(String username, List<SubscriptionAction> subscriptions)
+ List<String> getSubscriptions(String username)
+ List<String> getSubscriptionsSince(String username, LocalDateTime time)
+ int addSubscriptions(String username, List<SubscriptionAction> addedSubscriptions)
+ int removeSubscriptions(String username, List<SubscriptionAction> removedSubscriptions)
+ List<SubscriptionTitles> getTitles(String username)
+ }
+
+ interface SubscriptionDao {
+ int uploadSubscriptions(String username, List<SubscriptionAction> subscriptions)
+ List<String> getSubscriptions(String username)
+ List<String> getSubscriptionsSince(String username, LocalDateTime time)
+ int addSubscriptions(String username, List<SubscriptionAction> addedSubscriptions)
+ int removeSubscriptions(String username, List<SubscriptionAction> removedSubscriptions)
+ List<SubscriptionTitles> getTitles(String username)
+ }
+ }
+
+ package subscriptionService <<Frame>> {
+ class SubscriptionService <<@Service>> {
+ <<create>> SubscriptionService(SubscriptionDao subscriptionDao)
+ int uploadSubscriptions(String username, List<SubscriptionAction> subscriptions)
+ List<String> getSubscriptions(String username)
+ List<String> getSubscriptionsSince(String username, LocalDateTime time)
+ int addSubscriptions(String username, List<SubscriptionAction> addedSubscriptions)
+ int removeSubscriptions(String username, List<SubscriptionAction> removedSubscriptions)
+ List<SubscriptionTitles> getTitles(String username)
+ }
+ }
+
+ package subscriptionController <<Frame>> {
+ class SubscriptionController <<@Controller>>{
+ ' @Autowired
+ <<create>> SubscriptionController(SubscriptionService subscriptionService)
+ ' @GetMapping
+ ResponseEntity<List<String>> getSubscriptions(String username, String deviceID, String functionJSONP)
+ ' @PutMapping
+ ResponseEntity<String> uploadSubscriptions(String username, String deviceID, List<String> subscriptions)
+ ' @PostMapping
+ ResponseEntity<SubscriptionDelta> applySubscriptionDelta(String username, String deviceID, SubscriptionDelta delta)
+ ' @GetMapping
+ ResponseEntity<SubscriptionDelta> getSubscriptionDelta(String username, String deviceID, long since)
+ ResponseEntity<List<SubscriptionTitles>> getTitles(String username, String deviceID)
+ }
+
+ class SubscriptionTitles {
+ <<create>> SubscriptionTitles(Subscription subscription, List<EpisodeActionPost> episodeTitles)
+ Subscription getSubscription()
+ List<EpisodeActionPost> getEpisodesTitles()
+ }
+
+ class SubscriptionDelta {
+ <<create>> SubscriptionDelta(List<String> add, List<String> remove)
+ List<String> getRemove()
+ LocalDate getTimestamp()
+ List<List<String>> getUpdate_urls()
+ }
+ }
+
+}
+
+' Subscription <.. SubscriptionDataAccessService: DB
+' SubscriptionAction <.. SubscriptionDataAccessService: DB
+SubscriptionService --o SubscriptionController
+SubscriptionDao <.. SubscriptionService: <<use>>
+SubscriptionDao <|. SubscriptionDataAccessService: <<realize>>
+
+@enduml
+
diff --git a/11-entwurfsheft-kolloquium/assets/diagrams/classdiagram-util.puml b/11-entwurfsheft-kolloquium/assets/diagrams/classdiagram-util.puml
new file mode 100644
index 0000000..03dfc9a
--- /dev/null
+++ b/11-entwurfsheft-kolloquium/assets/diagrams/classdiagram-util.puml
@@ -0,0 +1,43 @@
+@startuml
+
+package util <<Frame>> {
+ class RSSParser {
+ <<create>> RSSParser(String subscriptionURL)
+ String getSubscriptionTitle()
+ List<Episode> getEpisodes()
+ Episode getEpisodeForURL(String episodeURL)
+ }
+ note bottom
+ Verwendet intern Spring um
+ HTTP-Anfragen zu erstellen.
+ end note
+
+ class CleanCronJob {
+ <<create>> CleanCronJob(JdbcUserDetailsManager jdbcUserDetailsManager)
+ void cleanInvalidUsers()
+ }
+ note bottom
+ Hintergrundservice, der in periodischen Abständen
+ Nutzer, die ihre E-Mail-Adresse nicht nach 24 Stunden
+ bestätigt haben, wieder aus der Datenbank löscht.
+ (Auf die Assoziation zu JdbcUserDetailsManager wird
+ im Sinne der Übersichtlichkeit verzichtet.)
+ end note
+
+ class ResponseEntity<T> {
+ <<create>> ResponseEntity(T body, HttpStatusCode status)
+ T getBody()
+ HttpStatusCode getStatusCode()
+ }
+ note bottom
+ Aus org.springframework.http.
+ Erweitert die Klasse HttpEntity, welche
+ ein HTTP Anfrage- oder Antwort-Objekt
+ repräsentiert, durch einen HttpStatusCode.
+ Wird von den Controller-Methoden als
+ Rückgabewert verwendet.
+ end note
+}
+
+@enduml
+
diff --git a/11-entwurfsheft-kolloquium/assets/diagrams/classdiagram.puml b/11-entwurfsheft-kolloquium/assets/diagrams/classdiagram.puml
new file mode 100644
index 0000000..f833aa2
--- /dev/null
+++ b/11-entwurfsheft-kolloquium/assets/diagrams/classdiagram.puml
@@ -0,0 +1,68 @@
+@startuml
+' skinparam linetype ortho
+' skinparam groupInheritance 2
+allowmixing
+
+!include classdiagram-authentication.puml
+!include classdiagram-episode-actions.puml
+!include classdiagram-model.puml
+!include classdiagram-subscriptions.puml
+!include classdiagram-util.puml
+
+class SecurityConfigurationBasicAuth {
+ <<create>> SecurityConfigurationBasicAuth()
+ PasswordEncoder encoder()
+ UserDetailsManager userDetailsService()
+ SecuryFilterChain fiterChain(HTTPSecurity http) throws Excpetion
+}
+note top
+ Erstellt einen Servlet Filter (springSecurityFilterChain)
+ der für die gesamte Sicherheit zuständig ist (Schutz der URLs,
+ Validierung von Anmeldedaten, Weiterleitung zur Anmeldung, etc.).
+end note
+
+class PSEApplication {
+ <<create>> PSEApplication()
+ void main(String[] args)
+}
+
+database Datenbank
+Datenbank <-[hidden]d- subscriptionsAPI
+Datenbank <-[hidden]d- episodeActionsAPI
+Datenbank <-[hidden]d- authenticationAPI
+() SQL as SQLSub
+() SQL as SQLAuth
+() SQL as SQLEpisode
+
+Datenbank -- SQLSub
+Datenbank -- SQLAuth
+Datenbank -- SQLEpisode
+
+Subscription --o SubscriptionTitles
+EpisodeActionPost -o SubscriptionTitles
+UserDetailsManager <.. SecurityConfigurationBasicAuth: <<use>>
+
+SubscriptionController ..o PSEApplication
+AuthenticationController ..o PSEApplication
+EpisodeActionController ..o PSEApplication
+SecurityConfigurationBasicAuth ..o PSEApplication
+
+PSEApplication --() HTTP
+
+SQLSub )-- SubscriptionDataAccessService: JPA
+' SQLAuth )-- AuthenticationDataAccessService: JPA
+SQLAuth )-- JdbcUserDetailsManager: JDBC
+SQLEpisode )-- EpisodeActionDataAccessService: JPA
+
+RSSParser <. SubscriptionDataAccessService: <<use>>
+RSSParser <. EpisodeActionDataAccessService: <<use>>
+' JdbcUserDetailsManager <-- CleanCronJob
+
+model .o Datenbank: ORM (User, SubscriptionAction, Subscription, EpisodeAction, Episode)
+' Datenbank o.. Subscription: ORM
+' Datenbank o.. SubscriptionAction: ORM
+' Datenbank o.. Episode: ORM
+' Datenbank o.. EpisodeAction: ORM
+' Datenbank o.. User: ORM
+
+@enduml
diff --git a/11-entwurfsheft-kolloquium/assets/diagrams/componentdiagram.puml b/11-entwurfsheft-kolloquium/assets/diagrams/componentdiagram.puml
new file mode 100644
index 0000000..dea4a1d
--- /dev/null
+++ b/11-entwurfsheft-kolloquium/assets/diagrams/componentdiagram.puml
@@ -0,0 +1,53 @@
+@startuml
+
+[App] as app
+[VueRouter] as router
+[NavbarComponent] as navbar
+[LoginPage] as login_page
+[SubscriptionsPage] as abo_page
+[EpisodesPage] as episodes_page
+[SettingsPage] as settings_page
+[ForgotPasswordPage] as forgot_page
+[ResetPasswordPage] as reset_page
+note top
+ Wird in der E-Mail zum Zurücksetzen des Passworts mit dem JWT-Token verlinkt.
+ Sendet das alte und neue Passwort und den JWT an die API.
+end note
+[RegistrationPage] as registration_page
+
+[SubscriptionComponent] as sub
+[EpisodeComponent] as episode
+[LastUpdateComponent] as last_update
+[PasswordValidatorComponent] as password
+
+app --> router
+
+app --> navbar
+router --> login_page
+router --> forgot_page
+router --> reset_page
+router --> registration_page
+router --> abo_page
+router --> episodes_page
+router --> settings_page
+
+navbar -[hidden] router
+
+episodes_page -[hidden] abo_page
+login_page -[hidden] forgot_page
+registration_page -[hidden] reset_page
+abo_page -[hidden] settings_page
+forgot_page -[hidden] episodes_page
+' forgot_page -[hidden] settings_page
+
+abo_page --> sub
+episodes_page --> episode
+
+sub --> last_update
+episode --> last_update
+
+settings_page --> password
+reset_page --> password
+registration_page --> password
+
+@enduml
diff --git a/11-entwurfsheft-kolloquium/assets/diagrams/db.puml b/11-entwurfsheft-kolloquium/assets/diagrams/db.puml
new file mode 100644
index 0000000..bdefaea
--- /dev/null
+++ b/11-entwurfsheft-kolloquium/assets/diagrams/db.puml
@@ -0,0 +1,78 @@
+@startuml
+' Type Symbol
+' Zero or One |o--
+' Exactly One ||--
+' Zero or Many }o--
+' One or Many }|--
+
+skinparam linetype ortho
+
+entity User {
+ * int id <<unique>>
+ * <u>String email</u>
+ * String password
+ * boolean verified
+ * long created_at
+}
+
+entity SubscriptionAction {
+ * int id <<unique>>
+ * <u>int user_id</u>
+ * long timestamp
+ * int subscription_id
+ * boolean added
+}
+
+entity Subscription {
+ * int id <<unique>>
+ * <u>String url</u>
+ * long timestamp
+ * String title
+}
+
+entity Episode {
+ * int id <<unique>>
+ * <u>int guid <<unique>></u>
+ * <u>String url</u>
+ * String title
+ * int total
+ * int subscription_id
+}
+note right
+ Wenn der Client eine GUID aus dem Feed mitsendet, wird
+ diese statt der URL verwendet um die Episode zu finden.
+ So wird die Episode auch noch gefunden, nachdem sich
+ die URL geändert hat.
+end note
+note bottom of Episode
+ Wenn für die Episoden-URL einer EpisodeAction noch keine Episode in der Datenbank steht,
+ dann schreibe dafür ein Dummy-Objekt in Datenbank und lade asynchron die Episoden der Subscription.
+ Ersetze dann die Dummy-Objekte durch die Episoden und setze den Timestamp der Subscription auf
+ die aktuelle Zeit.
+ Um DoS-Angriffe auf den Backend-Server abzuwenden, können die Episoden einer Subscription erst
+ nach einer Stunde erneut gefetched werden. Bis dahin werden für EpisodeActions, die sich auf noch
+ nicht geladene Episoden beziehen, nur Dummy-Objekte für die Episoden in die Datenbank geschrieben.
+ Es sei noch darauf hingewiesen, dass diese Dummy-Episoden bei Anfragen nicht mit ausgegeben werden.
+end note
+
+entity EpisodeAction {
+ * int id <<unique>>
+ * <u>int user_id</u>
+ * int episode_id
+ * long timestamp
+ * int action
+ * int started
+ * int position
+}
+note right
+ Speichere für jede Episode
+ nur letzte Play-Action.
+endnote
+
+User ||--o{ EpisodeAction
+User ||--o{ SubscriptionAction
+SubscriptionAction }|--|| Subscription
+EpisodeAction }|--|| Episode
+Subscription ||-right-|{ Episode
+
+@enduml
diff --git a/11-entwurfsheft-kolloquium/assets/diagrams/deployment.puml b/11-entwurfsheft-kolloquium/assets/diagrams/deployment.puml
new file mode 100644
index 0000000..26918e2
--- /dev/null
+++ b/11-entwurfsheft-kolloquium/assets/diagrams/deployment.puml
@@ -0,0 +1,59 @@
+@startuml
+
+node "<<device>> \nBackend Server" as backendServer{
+ database " <<database system>> \n MariaDB Server 10.6" as database {
+ rectangle rectangle1 [
+ <<schema>>
+ User
+ ]
+ rectangle rectangle2 [
+ <<schema>>
+ SubscriptionAction
+ ]
+ rectangle rectangle3 [
+ <<schema>>
+ EpisodeAction
+ ]
+ rectangle rectangle4 [
+ <<schema>>
+ Subscription
+ ]
+ rectangle rectangle5 [
+ <<schema>>
+ Episode
+ ]
+ }
+
+ node "<<framework>> \nJava Spring" as javaSpring{
+ node " <<device>> \n Tomcat Webserver"
+ }
+}
+
+node "<<device>> \nFrontend" as frontendServer {
+
+}
+
+node "<<device>> \nEndgerät" as terminal {
+ node "<<application>> \nBrowser" as browser
+ node "<<application>> \nPodcatcher" as podcatcher
+}
+
+backendServer "1" - "*" podcatcher
+
+node "<<device>> \nFrontend Server" as frontendServer{
+ node "<<framework>> \nVue.js" as vuejs {
+
+ }
+}
+
+podcatcher -[hidden] browser
+
+backendServer - "1" frontendServer
+
+database "1" -- "1" javaSpring
+
+browser "*" -- frontendServer
+
+
+
+@enduml
diff --git a/11-entwurfsheft-kolloquium/assets/diagrams/sequencediagram-forgotAndResetPW.puml b/11-entwurfsheft-kolloquium/assets/diagrams/sequencediagram-forgotAndResetPW.puml
new file mode 100644
index 0000000..603130c
--- /dev/null
+++ b/11-entwurfsheft-kolloquium/assets/diagrams/sequencediagram-forgotAndResetPW.puml
@@ -0,0 +1,41 @@
+@startuml
+
+skinparam ParticipantPadding 30
+
+participant AuthenticationController << (C, #ADD1B2) @Controller >>
+-> AuthenticationController: ""POST /api/2/auth/forgot.json"" \n//@RequestBody ForgotPasswordRequest forgotPasswordRequest// \n\n-> forgotPassword(//forgotPasswordRequest//)
+activate AuthenticationController
+participant AuthenticationService << (C, #ADD1B2) @Service >>
+AuthenticationController -> AuthenticationService: forgotPassword(//forgotPasswordRequest//)
+activate AuthenticationService
+participant JavaMailSenderImpl << (C, #ADD1B2) >>
+AuthenticationService -> JavaMailSenderImpl: create link to reset password with JWT as URL parameter \n-> send(SimpleMailMessage simpleMessage) with link
+activate JavaMailSenderImpl
+<<- JavaMailSenderImpl: sends email with link containing a JWT to reset password
+JavaMailSenderImpl --> AuthenticationService
+deactivate JavaMailSenderImpl
+AuthenticationService --> AuthenticationController: int indicating status
+deactivate AuthenticationService
+<-- AuthenticationController: ResponseEntity<Integer> indicating status \n\n-> ""HTTP status code""
+deactivate AuthenticationController
+||60||
+-> AuthenticationController: ""PUT /api/2/auth/{username}/resetpassword.json"" \n//@RequestParam String jwt// \n//@RequestBody ResetPasswordRequest resetPasswordRequest// \n\n-> login user (""username"") via JWT (//jwt//) \n-> resetPassword(""username"", //resetPasswordRequest//)
+activate AuthenticationController
+AuthenticationController -> AuthenticationService: resetPassword(""username"", //resetPasswordRequest//)
+activate AuthenticationService
+participant JdbcUserDetailsManager << (C, #ADD1B2) @Repository >>
+AuthenticationService -> JdbcUserDetailsManager: String oldPassword = //resetPasswordRequest//.getOldPassword() \nString newPassword = //resetPasswordRequest//.getNewPassword() \n-> changePassword(newPassword, oldPassword)
+activate JdbcUserDetailsManager
+database Database
+JdbcUserDetailsManager -> Database: change password of logged in user
+activate Database
+Database --> JdbcUserDetailsManager
+deactivate Database
+JdbcUserDetailsManager --> AuthenticationService: int indicating status
+deactivate JdbcUserDetailsManager
+AuthenticationService --> AuthenticationController: int indicating status
+deactivate AuthenticationService
+<-- AuthenticationController: ResponseEntity<Integer> indicating status \n\n-> ""HTTP status code""
+deactivate AuthenticationController
+
+@enduml \ No newline at end of file
diff --git a/11-entwurfsheft-kolloquium/assets/diagrams/sequencediagram-getEpisodeActions.puml b/11-entwurfsheft-kolloquium/assets/diagrams/sequencediagram-getEpisodeActions.puml
new file mode 100644
index 0000000..47497d5
--- /dev/null
+++ b/11-entwurfsheft-kolloquium/assets/diagrams/sequencediagram-getEpisodeActions.puml
@@ -0,0 +1,38 @@
+@startuml
+
+' title =**Get All Episode Actions**
+
+participant EpisodeActionController << (C, #ADD1B2) @Controller >>
+-> EpisodeActionController: ""GET /api/2/episodes/{username}.json"" \n//@RequestParam("device") String deviceID// \n//@RequestParam("aggregated") boolean aggregated// \n\n-> getEpisodeActions(""username"", //deviceID//, //aggregated//)
+note right
+ Die Parameter //deviceID// und //aggregated// werden ignoriert,
+ da nicht zwischen Geräten unterschieden und für jede
+ Episode sowieso nur die letzte Play-Action gespeichert
+ wird. Dies gilt für alle GET-Anfragen der Episode Actions API.
+end note
+activate EpisodeActionController
+participant EpisodeActionService << (C, #ADD1B2) @Service >>
+EpisodeActionController -> EpisodeActionService: getEpisodeActions(""username"")
+activate EpisodeActionService
+participant EpisodeActionDataAccessService << (C, #ADD1B2) @Repository >>
+EpisodeActionService -> EpisodeActionDataAccessService: getEpisodeActions(""username"")
+activate EpisodeActionDataAccessService
+EpisodeActionDataAccessService -> EpisodeActionDataAccessService: getEpisodeActionsSince(""username"", \nLocalDateTime.MIN.toEpochSecond(ZoneOffset.UTC))
+database Database
+activate EpisodeActionDataAccessService
+EpisodeActionDataAccessService -> Database: get all EpisodeActions for all subscribed podcasts
+activate Database
+Database --> EpisodeActionDataAccessService: List<EpisodeAction> selectedEpisodeActions \n-> then remove all older than LocalDateTime.MIN (none)
+EpisodeActionDataAccessService -> Database: join EpisodeActions in selectedEpisodeActions with episodeURL of Episode
+Database --> EpisodeActionDataAccessService
+deactivate Database
+EpisodeActionDataAccessService --> EpisodeActionDataAccessService: List<EpisodeActionPost> episodeActionPosts
+deactivate EpisodeActionDataAccessService
+EpisodeActionDataAccessService --> EpisodeActionService: List<EpisodeActionPost> episodeActionPosts
+deactivate EpisodeActionDataAccessService
+EpisodeActionService --> EpisodeActionController: List<EpisodeActionPost> episodeActionPosts
+deactivate EpisodeActionService
+<-- EpisodeActionController: ResponseEntity<EpisodeActionGetResponse> response \n\n-> ""HTTP status code"" \n-> ""JSON""
+deactivate EpisodeActionController
+
+@enduml \ No newline at end of file
diff --git a/11-entwurfsheft-kolloquium/assets/diagrams/sequencediagram-getEpisodeActionsOfPodcastSince.puml b/11-entwurfsheft-kolloquium/assets/diagrams/sequencediagram-getEpisodeActionsOfPodcastSince.puml
new file mode 100644
index 0000000..d8797d1
--- /dev/null
+++ b/11-entwurfsheft-kolloquium/assets/diagrams/sequencediagram-getEpisodeActionsOfPodcastSince.puml
@@ -0,0 +1,32 @@
+@startuml
+
+' title =**Get Episode Actions of Podcast Since**
+
+participant EpisodeActionController << (C, #ADD1B2) @Controller >>
+-> EpisodeActionController: ""GET /api/2/episodes/{username}.json"" \n//@RequestParam("podcast") String podcastURL// \n//@RequestParam("device") String deviceID// \n//@RequestParam("since") long since// \n//@RequestParam("aggregated") boolean aggregated// \n\n-> getEpisodeActionsOfPodcastSince(""username"", //podcastURL//, //deviceID//, //since//, //aggregated//)
+note right
+ Die Parameter //deviceID// und //aggregated// werden ignoriert.
+ Siehe Notiz in Sequenzdiagramm **Get All Episode Actions**.
+end note
+activate EpisodeActionController
+participant EpisodeActionService << (C, #ADD1B2) @Service >>
+EpisodeActionController -> EpisodeActionService: getEpisodeActionsOfPodcastSince(""username"", //podcastURL//, //since//)
+activate EpisodeActionService
+participant EpisodeActionDataAccessService << (C, #ADD1B2) @Repository >>
+EpisodeActionService -> EpisodeActionDataAccessService: getEpisodeActionsOfPodcastSince(""username"", //podcastURL//, //since//)
+activate EpisodeActionDataAccessService
+database Database
+EpisodeActionDataAccessService -> Database: get all EpisodeActions the given podcast (//podcastURL//)
+activate Database
+Database --> EpisodeActionDataAccessService: List<EpisodeAction> selectedEpisodeActions \n-> then remove all older than //since//
+EpisodeActionDataAccessService -> Database: join EpisodeActions in selectedEpisodeActions with episodeURL of Episode
+Database --> EpisodeActionDataAccessService
+deactivate Database
+EpisodeActionDataAccessService --> EpisodeActionService: List<EpisodeActionPost> episodeActionPosts
+deactivate EpisodeActionDataAccessService
+EpisodeActionService --> EpisodeActionController: List<EpisodeActionPost> episodeActionPosts
+deactivate EpisodeActionService
+<-- EpisodeActionController: ResponseEntity<EpisodeActionGetResponse> response \n\n-> ""HTTP status code"" \n-> ""JSON""
+deactivate EpisodeActionController
+
+@enduml \ No newline at end of file
diff --git a/11-entwurfsheft-kolloquium/assets/diagrams/sequencediagram-getSubscriptions.puml b/11-entwurfsheft-kolloquium/assets/diagrams/sequencediagram-getSubscriptions.puml
new file mode 100644
index 0000000..6e6895f
--- /dev/null
+++ b/11-entwurfsheft-kolloquium/assets/diagrams/sequencediagram-getSubscriptions.puml
@@ -0,0 +1,36 @@
+@startuml
+
+' title =**Get All Subscriptions**
+
+participant SubscriptionController << (C, #ADD1B2) @Controller >>
+-> SubscriptionController: ""GET /subscriptions/{username}.json"" \n"" /subscriptions/{username}/{deviceid}.json"" \n//@RequestParam("jsonp") String functionJSONP// \n\n-> getSubscriptions(""username"", ""deviceid"", //functionJSONP//)
+activate SubscriptionController
+note right
+ Die Parameter ""deviceid"" und
+ //functionJSONP// werden ignoriert,
+ da nicht zwischen Geräten unterschieden
+ und JSONP nicht unterstützt wird.
+end note
+participant SubscriptionService << (C, #ADD1B2) @Service >>
+SubscriptionController -> SubscriptionService: getSubscriptions(""username"")
+activate SubscriptionService
+participant SubscriptionDataAccessService << (C, #ADD1B2) @Repository >>
+SubscriptionService -> SubscriptionDataAccessService: getSubscriptions(""username"")
+activate SubscriptionDataAccessService
+SubscriptionDataAccessService -> SubscriptionDataAccessService: getSubscriptionsSince(""username"", LocalDateTime.MIN)
+database Database
+activate SubscriptionDataAccessService
+SubscriptionDataAccessService -> Database: get all Podcasts from Subscriptions for ""username""
+activate Database
+Database --> SubscriptionDataAccessService: List<Podcast> subscribedPodcasts
+deactivate Database
+SubscriptionDataAccessService --> SubscriptionDataAccessService: List<String> podcastURLs
+deactivate SubscriptionDataAccessService
+SubscriptionDataAccessService --> SubscriptionService: List<String> podcastURLs
+deactivate SubscriptionDataAccessService
+SubscriptionService --> SubscriptionController: List<String> podcastURLs
+deactivate SubscriptionService
+<-- SubscriptionController: ResponseEntity<List<String>> podcastURLs \n \n-> ""HTTP status code"" \n-> ""JSON""
+deactivate SubscriptionController
+
+@enduml \ No newline at end of file
diff --git a/11-entwurfsheft-kolloquium/assets/diagrams/sequencediagram-register.puml b/11-entwurfsheft-kolloquium/assets/diagrams/sequencediagram-register.puml
new file mode 100644
index 0000000..b7b7aa1
--- /dev/null
+++ b/11-entwurfsheft-kolloquium/assets/diagrams/sequencediagram-register.puml
@@ -0,0 +1,26 @@
+@startuml
+
+' title =**Register**
+
+participant AuthenticationController << (C, #ADD1B2) @Controller >>
+-> AuthenticationController: ""POST /api/2/auth/register.json"" \n//@RequestBody UserDetails user// \n\n-> registerUser(//user//)
+activate AuthenticationController
+participant AuthenticationService << (C, #ADD1B2) @Service >>
+AuthenticationController -> AuthenticationService: registerUser(//user//)
+activate AuthenticationService
+participant JdbcUserDetailsManager << (C, #ADD1B2) @Repository >>
+AuthenticationService -> JdbcUserDetailsManager: createUser(//user//)
+activate JdbcUserDetailsManager
+database Database
+JdbcUserDetailsManager -> Database: create new User with given UserDetails (//user//)
+activate Database
+Database --> JdbcUserDetailsManager
+deactivate Database
+JdbcUserDetailsManager --> AuthenticationService: int indicating status
+deactivate JdbcUserDetailsManager
+AuthenticationService --> AuthenticationController: int indicating status
+deactivate AuthenticationService
+<-- AuthenticationController: ResponseEntity<Integer> indicating status \n\n-> ""HTTP status code""
+deactivate AuthenticationController
+
+@enduml \ No newline at end of file
diff --git a/11-entwurfsheft-kolloquium/assets/diagrams/sequencediagram-uploadEpisodeActions.puml b/11-entwurfsheft-kolloquium/assets/diagrams/sequencediagram-uploadEpisodeActions.puml
new file mode 100644
index 0000000..d3dac57
--- /dev/null
+++ b/11-entwurfsheft-kolloquium/assets/diagrams/sequencediagram-uploadEpisodeActions.puml
@@ -0,0 +1,38 @@
+@startuml
+
+' title =**Upload Episode Actions**
+
+participant EpisodeActionController << (C, #ADD1B2) @Controller >>
+-> EpisodeActionController: ""POST /api/2/episodes/{username}.json"" \n//@RequestBody EpisodeActionPostRequest episodeActionPostRequest// \n\n-> addEpisodeActions(""username"", //episodeActionPostRequest//)
+activate EpisodeActionController
+participant EpisodeActionService << (C, #ADD1B2) @Service >>
+EpisodeActionController -> EpisodeActionService: addEpisodeActions(""username"", \nepisodeActionPosts = //episodeActionPostRequest//.getEpisodeActionPosts())
+activate EpisodeActionService
+participant EpisodeActionDataAccessService << (C, #ADD1B2) @Repository >>
+EpisodeActionService -> EpisodeActionDataAccessService: addEpisodeActions(""username"", episodeActionPosts)
+database Database
+activate EpisodeActionDataAccessService
+loop for each EpisodeActionPost in episodeActionPosts -> episodeAction = episodeActionPost.getEpisodeAction()
+opt episodeAction.getAction().equals(Action.PLAY)
+EpisodeActionDataAccessService -> Database: set episodeID field of episodeAction for this ""username"" via podcastURL and episodeURL
+activate Database
+Database --> EpisodeActionDataAccessService
+EpisodeActionDataAccessService -> Database: get last EpisodeAction with this episodeID if present
+Database --> EpisodeActionDataAccessService: Optional<EpisodeAction> lastEpisodeAction
+opt lastEpisodeAction.isPresent()
+EpisodeActionDataAccessService -> Database: replace lastEpisodeAction with episodeAction
+else else
+EpisodeActionDataAccessService -> Database: add episodeAction to DB as new entry
+end
+Database --> EpisodeActionDataAccessService
+deactivate Database
+end
+end
+EpisodeActionDataAccessService --> EpisodeActionService: long latestTimestamp
+deactivate EpisodeActionDataAccessService
+EpisodeActionService --> EpisodeActionController: LocalDateTime timestamp = LocalDateTime.ofEpochSecond(latestTimestamp, 0, ZoneOffset.UTC)
+deactivate EpisodeActionService
+<-- EpisodeActionController: ResponseEntity<EpisodeActionPostResponse> \n(with empty list for updateURLs) \n\n-> ""HTTP status code"" \n-> ""JSON""
+deactivate EpisodeActionController
+
+@enduml \ No newline at end of file
diff --git a/11-entwurfsheft-kolloquium/assets/diagrams/sequencediagram-uploadSubscriptions.puml b/11-entwurfsheft-kolloquium/assets/diagrams/sequencediagram-uploadSubscriptions.puml
new file mode 100644
index 0000000..1edc8cf
--- /dev/null
+++ b/11-entwurfsheft-kolloquium/assets/diagrams/sequencediagram-uploadSubscriptions.puml
@@ -0,0 +1,32 @@
+@startuml
+
+' title =**Upload Subscriptions**
+
+participant SubscriptionController << (C, #ADD1B2) @Controller >>
+-> SubscriptionController: ""PUT /subscriptions/{username}/{deviceid}.json"" \n//@RequestBody List<String> subscriptions// \n\n-> uploadSubscriptions(""username"", ""deviceid"", //subscriptions//)
+activate SubscriptionController
+participant SubscriptionService << (C, #ADD1B2) @Service >>
+SubscriptionController -> SubscriptionService: uploadSubscriptions(""username"", //subscriptions//)
+activate SubscriptionService
+participant SubscriptionDataAccessService << (C, #ADD1B2) @Repository >>
+SubscriptionService -> SubscriptionDataAccessService: uploadSubscriptions(""username"", //subscriptions//)
+activate SubscriptionDataAccessService
+database Database
+SubscriptionDataAccessService -> Database: delete all subsciptions of ""username""
+activate Database
+Database --> SubscriptionDataAccessService
+SubscriptionDataAccessService -> SubscriptionDataAccessService: addSubscriptions(""username"", //subscriptions//)
+activate SubscriptionDataAccessService
+SubscriptionDataAccessService -> Database: upload all subscriptions (//subscriptions//) for ""username""
+Database --> SubscriptionDataAccessService
+deactivate Database
+SubscriptionDataAccessService --> SubscriptionDataAccessService: int indicating status
+deactivate SubscriptionDataAccessService
+SubscriptionDataAccessService --> SubscriptionService: int indicating status
+deactivate SubscriptionDataAccessService
+SubscriptionService --> SubscriptionController: int indicating status
+deactivate SubscriptionService
+<-- SubscriptionController: ResponseEntity<String> with empty String for success \n\n-> ""HTTP status code"" \n-> ""JSON""
+deactivate SubscriptionController
+
+@enduml \ No newline at end of file
diff --git a/11-entwurfsheft-kolloquium/assets/episode.png b/11-entwurfsheft-kolloquium/assets/episode.png
new file mode 100644
index 0000000..c0db4a2
--- /dev/null
+++ b/11-entwurfsheft-kolloquium/assets/episode.png
Binary files differ
diff --git a/11-entwurfsheft-kolloquium/assets/help.png b/11-entwurfsheft-kolloquium/assets/help.png
new file mode 100644
index 0000000..39a1b84
--- /dev/null
+++ b/11-entwurfsheft-kolloquium/assets/help.png
Binary files differ
diff --git a/11-entwurfsheft-kolloquium/assets/lastupdate.png b/11-entwurfsheft-kolloquium/assets/lastupdate.png
new file mode 100644
index 0000000..e9b7f5c
--- /dev/null
+++ b/11-entwurfsheft-kolloquium/assets/lastupdate.png
Binary files differ
diff --git a/11-entwurfsheft-kolloquium/assets/logo.pdf b/11-entwurfsheft-kolloquium/assets/logo.pdf
new file mode 100644
index 0000000..91fd334
--- /dev/null
+++ b/11-entwurfsheft-kolloquium/assets/logo.pdf
Binary files differ
diff --git a/11-entwurfsheft-kolloquium/assets/logo.svg b/11-entwurfsheft-kolloquium/assets/logo.svg
new file mode 100644
index 0000000..1609066
--- /dev/null
+++ b/11-entwurfsheft-kolloquium/assets/logo.svg
@@ -0,0 +1,211 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ version="1.2"
+ width="87.589989mm"
+ height="52.16547mm"
+ viewBox="0 0 8758.9989 5216.547"
+ preserveAspectRatio="xMidYMid"
+ fill-rule="evenodd"
+ stroke-width="28.222"
+ stroke-linejoin="round"
+ xml:space="preserve"
+ id="svg206"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg">
+ <defs
+ class="ClipPathGroup"
+ id="defs8" />
+ <defs
+ id="defs51"><font
+ id="EmbeddedFont_1"
+ horiz-adv-x="2048"
+ horiz-origin-x="0"
+ horiz-origin-y="0"
+ vert-origin-x="512"
+ vert-origin-y="768"
+ vert-adv-y="1024">
+ <font-face
+ font-family="Noto Sans Display Light embedded"
+ units-per-em="2048"
+ font-weight="normal"
+ font-style="normal"
+ ascent="2170"
+ descent="609"
+ id="font-face10" />
+ <missing-glyph
+ horiz-adv-x="2048"
+ d="M 0,0 L 2047,0 2047,2047 0,2047 0,0 Z"
+ id="missing-glyph12" />
+ <glyph
+ unicode="y"
+ horiz-adv-x="927"
+ d="M 2,1089 L 127,1089 367,413 C 388,352 407,298 422,250 437,203 449,161 457,124 L 463,124 C 471,156 483,196 498,246 513,296 530,350 551,409 L 786,1089 913,1089 453,-193 C 418,-290 377,-364 328,-416 279,-468 213,-494 131,-494 107,-494 84,-493 63,-490 43,-487 25,-482 8,-476 L 8,-377 C 23,-383 40,-387 57,-391 75,-394 95,-396 117,-396 170,-396 214,-378 249,-342 284,-307 314,-252 340,-179 L 403,4 2,1089 Z"
+ id="glyph14" />
+ <glyph
+ unicode="t"
+ horiz-adv-x="610"
+ d="M 465,80 C 494,80 521,82 547,87 573,91 595,97 614,105 L 614,11 C 594,3 569,-5 541,-11 512,-17 481,-20 449,-20 363,-20 296,5 249,56 202,106 178,189 178,304 L 178,996 27,996 27,1061 178,1100 219,1350 295,1350 295,1090 608,1090 608,996 295,996 295,310 C 295,157 352,80 465,80 Z"
+ id="glyph16" />
+ <glyph
+ unicode="s"
+ horiz-adv-x="742"
+ d="M 817,289 C 817,191 782,115 713,61 643,7 545,-20 418,-20 347,-20 284,-14 228,-1 173,12 126,29 88,50 L 88,162 C 134,138 186,118 244,102 301,86 360,78 420,78 520,78 592,96 636,133 680,169 702,218 702,281 702,341 679,387 632,419 585,451 515,484 422,519 359,542 303,565 255,589 207,613 169,643 142,680 116,717 102,768 102,832 102,919 136,987 204,1037 271,1086 361,1110 473,1110 535,1110 592,1104 646,1092 700,1080 750,1063 795,1043 L 754,946 C 713,964 667,980 617,993 568,1006 518,1012 469,1012 388,1012 326,997 283,967 239,937 217,893 217,836 217,792 228,758 249,733 270,707 301,686 342,668 383,650 433,630 492,609 553,585 608,562 657,537 707,512 745,481 774,443 803,405 817,353 817,289 Z"
+ id="glyph18" />
+ <glyph
+ unicode="r"
+ horiz-adv-x="583"
+ d="M 596,1108 C 646,1108 692,1102 733,1091 L 717,983 C 674,995 632,1001 590,1001 497,1001 423,964 368,890 312,817 285,719 285,598 L 285,-1 168,-1 168,1089 266,1089 279,886 285,886 C 311,948 350,1000 402,1043 455,1086 520,1108 596,1108 Z"
+ id="glyph20" />
+ <glyph
+ unicode="o"
+ horiz-adv-x="927"
+ d="M 1030,547 C 1030,433 1012,333 976,248 940,164 887,98 818,51 749,4 665,-20 565,-20 471,-20 390,3 322,50 253,96 201,162 164,247 127,333 109,433 109,547 109,723 150,861 232,961 315,1061 429,1110 575,1110 672,1110 755,1087 822,1040 890,993 941,927 977,842 1012,757 1030,659 1030,547 Z M 229,547 C 229,407 257,294 312,208 368,123 453,80 567,80 685,80 771,123 826,209 882,295 909,408 909,547 909,637 898,717 875,787 851,856 815,911 766,951 717,990 653,1010 573,1010 459,1010 373,969 315,887 258,805 229,692 229,547 Z"
+ id="glyph22" />
+ <glyph
+ unicode="n"
+ horiz-adv-x="847"
+ d="M 633,1110 C 749,1110 838,1078 900,1014 962,950 993,850 993,713 L 993,1 877,1 877,705 C 877,809 854,885 810,935 766,985 701,1010 616,1010 395,1010 285,871 285,594 L 285,1 168,1 168,1090 262,1090 279,901 287,901 C 314,962 357,1011 416,1051 474,1091 547,1110 633,1110 Z"
+ id="glyph24" />
+ <glyph
+ unicode="m"
+ horiz-adv-x="1430"
+ d="M 1245,1110 C 1348,1110 1427,1080 1485,1018 1542,957 1571,860 1571,727 L 1571,1 1454,1 1454,723 C 1454,820 1434,892 1393,939 1352,986 1296,1010 1227,1010 1130,1010 1056,980 1005,919 953,858 928,764 928,637 L 928,1 811,1 811,723 C 811,820 791,892 750,939 709,986 653,1010 584,1010 487,1010 413,978 361,914 310,850 285,751 285,619 L 285,1 168,1 168,1090 262,1090 279,918 287,918 C 313,971 352,1016 403,1054 455,1092 521,1110 600,1110 675,1110 739,1093 791,1059 842,1025 879,975 899,908 L 907,908 C 936,972 980,1022 1038,1057 1097,1093 1166,1110 1245,1110 Z"
+ id="glyph26" />
+ <glyph
+ unicode="i"
+ horiz-adv-x="187"
+ d="M 227,1493 C 279,1493 305,1464 305,1405 305,1345 279,1315 227,1315 175,1315 150,1345 150,1405 150,1464 175,1493 227,1493 Z M 285,1090 L 285,0 168,0 168,1090 285,1090 Z"
+ id="glyph28" />
+ <glyph
+ unicode="h"
+ horiz-adv-x="847"
+ d="M 285,1059 C 285,1031 284,1003 283,977 281,951 279,926 276,901 L 285,901 C 312,962 355,1011 413,1051 471,1091 543,1110 629,1110 746,1110 836,1078 899,1014 962,950 993,850 993,713 L 993,1 877,1 877,705 C 877,809 854,885 810,935 766,985 701,1010 616,1010 395,1010 285,871 285,594 L 285,1 168,1 168,1557 285,1557 285,1059 Z"
+ id="glyph30" />
+ <glyph
+ unicode="f"
+ horiz-adv-x="689"
+ d="M 575,995 L 332,995 332,-1 213,-1 213,995 27,995 27,1058 213,1093 213,1202 C 213,1445 316,1566 522,1566 559,1566 593,1563 623,1557 653,1551 680,1544 705,1536 L 678,1439 C 655,1448 630,1454 603,1460 577,1465 550,1468 524,1468 456,1468 407,1447 377,1405 347,1362 332,1295 332,1202 L 332,1089 575,1089 575,995 Z"
+ id="glyph32" />
+ <glyph
+ unicode="e"
+ horiz-adv-x="874"
+ d="M 559,1110 C 646,1110 720,1089 779,1046 839,1003 883,944 913,869 943,794 958,708 958,611 L 958,531 229,531 C 231,386 262,275 325,198 387,121 476,82 592,82 656,82 712,88 759,100 806,111 858,130 915,156 L 915,50 C 865,25 814,7 764,-4 713,-15 655,-20 588,-20 434,-20 315,30 232,129 150,229 109,365 109,537 109,648 126,746 162,832 197,918 249,986 315,1036 382,1085 464,1110 559,1110 Z M 559,1012 C 465,1012 389,979 333,912 276,845 243,750 233,627 L 838,627 C 838,742 815,835 769,906 723,977 653,1012 559,1012 Z"
+ id="glyph34" />
+ <glyph
+ unicode="d"
+ horiz-adv-x="900"
+ d="M 535,-20 C 398,-20 293,27 219,120 145,214 109,352 109,535 109,722 147,865 224,963 301,1061 408,1110 545,1110 629,1110 698,1090 752,1050 805,1010 845,961 872,904 L 881,904 C 879,935 878,970 876,1009 873,1048 872,1084 872,1117 L 872,1557 989,1557 989,0 895,0 879,191 872,191 C 845,132 805,82 751,41 697,0 625,-20 535,-20 Z M 553,80 C 669,80 752,119 801,195 850,271 875,382 875,527 L 875,545 C 875,695 850,810 801,890 752,970 671,1010 559,1010 451,1010 369,969 313,886 257,804 229,686 229,533 229,385 256,273 309,196 363,119 444,80 553,80 Z"
+ id="glyph36" />
+ <glyph
+ unicode="c"
+ horiz-adv-x="768"
+ d="M 580,-20 C 429,-20 313,29 231,127 150,226 109,363 109,539 109,662 129,766 170,850 211,935 269,1000 343,1044 417,1088 504,1110 602,1110 651,1110 698,1106 742,1096 787,1087 825,1074 858,1057 L 825,957 C 791,972 754,984 714,993 673,1002 636,1006 600,1006 481,1006 390,964 326,881 261,798 229,685 229,541 229,405 258,294 314,210 371,126 459,84 580,84 630,84 678,90 723,101 768,112 809,125 846,142 L 846,37 C 812,20 773,6 729,-5 685,-15 636,-20 580,-20 Z"
+ id="glyph38" />
+ <glyph
+ unicode="a"
+ horiz-adv-x="822"
+ d="M 535,1108 C 651,1108 737,1078 795,1018 852,958 881,863 881,734 L 881,0 793,0 772,185 766,185 C 729,123 684,74 631,36 578,-1 503,-20 408,-20 311,-20 233,6 176,59 119,111 90,187 90,285 90,394 132,477 215,533 298,589 420,621 580,629 L 764,639 764,715 C 764,822 744,897 705,942 665,987 606,1010 528,1010 477,1010 426,1002 378,987 329,972 281,953 231,928 L 195,1022 C 242,1047 295,1067 352,1084 410,1100 470,1108 535,1108 Z M 594,543 C 466,536 370,512 307,470 244,429 213,367 213,285 213,217 232,165 271,131 310,96 363,78 430,78 535,78 617,111 676,176 735,240 764,330 764,445 L 764,551 594,543 Z"
+ id="glyph40" />
+ <glyph
+ unicode="S"
+ horiz-adv-x="875"
+ d="M 956,381 C 956,294 936,220 894,160 852,100 796,55 724,25 652,-5 571,-20 479,-20 396,-20 324,-14 262,-2 201,11 147,26 102,46 L 102,162 C 152,142 209,124 273,109 338,94 409,87 485,87 589,87 673,110 738,158 803,206 836,278 836,373 836,431 823,478 798,515 772,553 734,586 682,614 630,642 565,670 485,699 410,726 345,757 291,791 236,825 194,868 164,919 134,970 119,1035 119,1112 119,1192 138,1259 176,1314 214,1369 267,1411 333,1440 399,1469 474,1483 559,1483 626,1483 689,1476 750,1463 810,1449 868,1430 924,1405 L 883,1303 C 772,1352 663,1377 555,1377 462,1377 386,1354 328,1310 269,1266 240,1200 240,1114 240,1052 252,1001 278,964 303,926 340,895 389,869 438,843 498,817 567,791 648,762 717,731 775,698 833,664 878,623 909,573 941,523 956,459 956,381 Z"
+ id="glyph42" />
+ <glyph
+ unicode="P"
+ horiz-adv-x="848"
+ d="M 539,1462 C 869,1462 1034,1325 1034,1049 1034,908 992,798 907,718 823,638 690,598 510,598 L 311,598 311,0 193,0 193,1462 539,1462 Z M 528,1358 L 311,1358 311,702 498,702 C 629,702 730,727 803,776 875,825 911,914 911,1043 911,1152 880,1232 818,1282 756,1333 659,1358 528,1358 Z"
+ id="glyph44" />
+ <glyph
+ unicode="E"
+ horiz-adv-x="769"
+ d="M 950,0 L 193,0 193,1462 950,1462 950,1356 311,1356 311,821 913,821 913,715 311,715 311,107 950,107 950,0 Z"
+ id="glyph46" />
+ <glyph
+ unicode=" "
+ horiz-adv-x="503"
+ id="glyph48" />
+ </font></defs>
+ <defs
+ class="TextShapeIndex"
+ id="defs55" />
+ <defs
+ class="EmbeddedBulletChars"
+ id="defs87" />
+
+ <g
+ id="id10"
+ clip-path="none"
+ transform="translate(-700.00001,-2550)">
+
+ <text
+ class="SVGTextShape"
+ id="text151"
+ x="217.60002"
+ y="-56.506969"
+ style="letter-spacing:4.7625px;word-spacing:104.775px"><tspan
+ class="TextParagraph"
+ font-family="'Noto Sans Display Light', sans-serif"
+ font-size="494px"
+ font-weight="400"
+ id="tspan149"><tspan
+ class="TextPosition"
+ x="650.59998"
+ y="7647.4932"
+ id="tspan147"><tspan
+ fill="#808080"
+ stroke="none"
+ style="white-space:pre"
+ id="tspan145"
+ dx="2.1199999">Podcast Synchronisation made Efficient</tspan></tspan></tspan></text>
+ </g><g
+ id="g1277"
+ transform="translate(-700.00001,-2550)"><path
+ id="path131-3"
+ d="m 6694.0006,4763 c -559.5515,4.407 -980.3924,428.0893 -986.038,985.9863 18.2894,552.8957 454.3127,974.1166 989.0352,986.0379 v -235.0244 c -406.8751,-27.3888 -715.1078,-362.1649 -719.0259,-748.0163 12.7874,-421.0793 236.9242,-746.3999 750.0318,-749.98 895.0688,1.4728 1915.5158,0 2730.9957,0 V 4763 Z"
+ style="fill:#0084d1;fill-opacity:1"
+ clip-path="none" /><path
+ id="path131"
+ d="m 6685.0183,2562.996 c -559.5515,4.407 -980.3924,428.0893 -986.038,985.9863 18.2894,552.8957 454.3127,974.1167 989.0352,986.038 v -235.0244 c -406.8751,-27.3888 -715.1078,-362.165 -719.0259,-748.0164 12.7874,-421.0792 236.9242,-746.3998 750.0318,-749.98 895.0688,1.4728 1915.5158,0 2730.996,0 V 2562.996 Z"
+ style="fill:#0084d1;fill-opacity:1"
+ clip-path="none" /></g><g
+ id="g1263"
+ transform="translate(-700.00001,-2550)"><path
+ fill="none"
+ stroke="#069a2e"
+ stroke-width="265"
+ stroke-linejoin="round"
+ d="m 2793,5962 c 1283,0 429,-2762 1712,-2762"
+ id="path124" /><path
+ id="path110-6"
+ d="M 3198.0212,6550 V 6300.0411 H 2448.0411 V 6050.0305 5550.0094 H 2198.0305 V 6300.0411 6550 H 2448.0411 2698 Z"
+ style="fill:#069a2e;fill-opacity:1" /><path
+ id="path110"
+ d="m 4111.997,2550.0252 v 249.9589 h 749.9801 v 250.0106 500.0211 h 250.0106 v -750.0317 -249.9589 h -250.0106 -249.9589 z"
+ style="fill:#069a2e;fill-opacity:1" /></g>
+ <g
+ id="g1249"
+ transform="translate(-700.00001,-2550)"><path
+ fill="#ff8000"
+ stroke="none"
+ d="M 2215,4164 C 2412.6918,3832.6035 2379.3124,3383.7591 2135.4189,3084.8193 1956.8564,2857.4026 1671.3097,2718.8851 1382,2721 c 0,-52.6667 0,-105.3333 0,-158 -60.1303,-1.0792 190.6585,-1.2724 121.9814,2.7933 434.6311,30.3756 832.6257,336.7309 974.9655,748.2365 148.7336,402.6249 41.0263,883.7477 -266.0719,1183.8452 C 1996.6852,4716.1853 1689.0048,4838.6187 1382,4830 c 0,-61.6667 0,-123.3333 0,-185 338.199,2.9253 666.226,-186.816 833,-481 z"
+ id="path193" /><path
+ fill="#ff8000"
+ stroke="none"
+ d="m 1936,3979 c 175.8129,-283.3241 59.7943,-700.6319 -239.8255,-849.407 -94.2713,-50.9942 -201.887,-77.9344 -309.1745,-74.593 0,-57 0,-114 0,-171 396.3865,-24.0968 777.5367,297.6517 818.5878,693.1841 44.0348,337.5467 -149.4277,694.9971 -466.4953,826.9493 -110.1027,49.0687 -231.5272,73.543 -352.0925,67.8666 0,-61.6667 0,-123.3333 0,-185 220.6353,7.5804 440.8554,-115.3286 549,-308 z"
+ id="path186" /><path
+ fill="#ff8000"
+ stroke="none"
+ d="m 1659,3822 c 86.3933,-138.0398 18.2474,-344.669 -134.6962,-402.3205 C 1483.44,3402.2177 1438.3524,3394.2432 1394,3398 c 0,-56.6667 0,-113.3333 0,-170 223.1964,-19.6143 444.7886,153.3254 478.4886,375.1817 32.646,181.6951 -54.6854,381.4331 -217.3127,472.2205 -78.2316,46.131 -170.3991,69.3119 -261.1759,62.5978 0,-58.3333 0,-116.6667 0,-175 105.6736,9.5509 212.8962,-49.2218 265,-141 z"
+ id="path179" /><rect
+ class="BoundingBox"
+ stroke="none"
+ fill="none"
+ x="700"
+ y="2550"
+ width="501"
+ height="4001"
+ id="rect136"
+ style="fill:#ff8000;fill-opacity:1" /></g>
+
+</svg>
diff --git a/11-entwurfsheft-kolloquium/assets/navbar.png b/11-entwurfsheft-kolloquium/assets/navbar.png
new file mode 100644
index 0000000..dd9f8e8
--- /dev/null
+++ b/11-entwurfsheft-kolloquium/assets/navbar.png
Binary files differ
diff --git a/11-entwurfsheft-kolloquium/assets/password-margin.png b/11-entwurfsheft-kolloquium/assets/password-margin.png
new file mode 100644
index 0000000..d9d4fa3
--- /dev/null
+++ b/11-entwurfsheft-kolloquium/assets/password-margin.png
Binary files differ
diff --git a/11-entwurfsheft-kolloquium/assets/password.png b/11-entwurfsheft-kolloquium/assets/password.png
new file mode 100644
index 0000000..68248a0
--- /dev/null
+++ b/11-entwurfsheft-kolloquium/assets/password.png
Binary files differ
diff --git a/11-entwurfsheft-kolloquium/assets/subscription.png b/11-entwurfsheft-kolloquium/assets/subscription.png
new file mode 100644
index 0000000..58a84f9
--- /dev/null
+++ b/11-entwurfsheft-kolloquium/assets/subscription.png
Binary files differ
diff --git a/11-entwurfsheft-kolloquium/logos/banner_2020_kit.jpg b/11-entwurfsheft-kolloquium/logos/banner_2020_kit.jpg
new file mode 100644
index 0000000..70ae1d0
--- /dev/null
+++ b/11-entwurfsheft-kolloquium/logos/banner_2020_kit.jpg
Binary files differ
diff --git a/11-entwurfsheft-kolloquium/notizen b/11-entwurfsheft-kolloquium/notizen
new file mode 100644
index 0000000..70ac63b
--- /dev/null
+++ b/11-entwurfsheft-kolloquium/notizen
@@ -0,0 +1,40 @@
+Titelseite:
+- Begrüßung
+
+Einführung:
+- Podcast: RSS-Feed, Episoden, Audio/Video
+- Podcatcher: lokale Verwaltung von Podcasts, API Unterstützung,
+Abspielen von Episoden
+- Synchronisationsserver (das soll unser Produkt werden): Hörfortschritte,
+Abonnements, Discovery (bei AntennaPod z.B. iTunes)
+
+Zielsetzung:
+
+Synchronisation (die Art, die wir bei uns anwenden):
+- alle Aktionen werden auf den Server und infolge dessen auf alle Podcatcher
+übertragen
+
+Features:
+- Synchronisation: Abos, Hörfortschritt
+- Weboberfläche: Aboliste, Zuletzt gehört
+- Account-Verwaltung: Registrieren, Anmelden, Passwort ändern/zurücksetzen,
+Account löschen, Daten importieren/exportieren
+
+UI-Journey:
+- login.html:
+ - Sprache ändern
+ - OAuth (kann)
+ - Registrieren (muss): neues Fenster, E-Mail + 2-mal Passwort (sicher?),
+ vergeben? -> Fehler / Bestätigungslink per E-Mail (gültig 24h)
+ - Anmelden (muss): E-Mail + Passwort eingeben, Login merken,
+ login, Fehlermeldung oder Dashboard
+ - Passwort vergessen: neues Fenster, E-Mail eingeben, falls Account wird
+ Link versendet, 24h gültig, nach betätigen PW zweimal eingeben & bestätigen
+ (Anforderungen)
+
+- podcasts.html: Abonnements, Eisoden, Hörfortschritte
+
+- listening.html: Zuletzt gehörte Episoden, Hörfortschritt, Wann gehört
+
+- settings.html: PW ändern, Gpodder Import, pers. Daten imp./exp.,
+ Account löschen
diff --git a/11-entwurfsheft-kolloquium/presentation.tex b/11-entwurfsheft-kolloquium/presentation.tex
new file mode 100644
index 0000000..ca05873
--- /dev/null
+++ b/11-entwurfsheft-kolloquium/presentation.tex
@@ -0,0 +1,52 @@
+%% Beispiel-Präsentation mit LaTeX Beamer im KIT-Design
+%% entsprechend den Gestaltungsrichtlinien vom 1. August 2020
+%%
+%% Siehe https://sdqweb.ipd.kit.edu/wiki/Dokumentvorlagen
+
+%% Beispiel-Präsentation
+\documentclass[xcolor={dvipsnames}]{sdqbeamer}
+\usepackage{multicol}
+\usepackage{fontawesome5}
+\usepackage{rest-api}
+\usepackage{graphicx}
+\usepackage{ulem}
+\usepackage[dvipsnames]{xcolor}
+
+
+%% Titelbild
+\titleimage{banner_2020_kit}
+
+%% Gruppenlogo
+\grouplogo{kitlogo_de_rgb}
+
+%% Gruppenname und Breite (Standard: 50 mm)
+\groupname{Praxis der Softwareentwicklung}
+%\groupnamewidth{50mm}
+
+\title[Kolloquium Pflichtenheft]{
+ PSE\textsuperscript{2} - Podcast Synchronisation made Efficient
+}
+\subtitle{Kolloquium Entwurfsheft}
+\author[Immanuel Reitz]{Immanuel Reitz}
+
+\date[17.\,01.\,2023]{17. Januar 2023}
+
+\begin{document}
+
+\KITtitleframe
+
+\include{slides/apiExtension}
+
+\include{slides/architecture}
+
+\include{slides/pattern}
+
+\include{slides/classdiagram}
+
+\include{slides/sequence}
+
+\include{slides/frontend}
+
+\include{slides/changes}
+%comment
+\end{document}
diff --git a/11-entwurfsheft-kolloquium/presentation.tex.orig b/11-entwurfsheft-kolloquium/presentation.tex.orig
new file mode 100644
index 0000000..8dd6019
--- /dev/null
+++ b/11-entwurfsheft-kolloquium/presentation.tex.orig
@@ -0,0 +1,68 @@
+%% Beispiel-Präsentation mit LaTeX Beamer im KIT-Design
+%% entsprechend den Gestaltungsrichtlinien vom 1. August 2020
+%%
+%% Siehe https://sdqweb.ipd.kit.edu/wiki/Dokumentvorlagen
+
+%% Beispiel-Präsentation
+\documentclass{sdqbeamer}
+
+\usepackage{tikz}
+\usetikzlibrary{positioning}
+\usetikzlibrary{calc}
+\usetikzlibrary{arrows}
+\usepackage{multicol}
+\usepackage{fontawesome5}
+\usepackage{tikz}
+\usepackage{tikz-uml}
+\usepackage{rest-api}
+\usetikzlibrary{positioning, arrows, chains}
+\usetikzlibrary[calc]
+
+
+%% Titelbild
+\titleimage{banner_2020_kit}
+
+%% Gruppenlogo
+\grouplogo{kitlogo_de_rgb}
+
+%% Gruppenname und Breite (Standard: 50 mm)
+\groupname{Praxis der Softwareentwicklung}
+%\groupnamewidth{50mm}
+
+\title[Kolloquium Pflichtenheft]{
+ PSE\textsuperscript{2} - Podcast Synchronisation made Efficient
+}
+\subtitle{Kolloquium Entwurfsheft}
+\author[Immanuel Reitz]{Immanuel Reitz}
+
+\date[17.\,01.\,2023]{17. Januar 2023}
+
+\begin{document}
+
+\KITtitleframe
+
+\include{slides/apiExtension}
+% Folie Einführung
+\include{slides/einführung}
+
+% Folie Zielsetzung
+\include{slides/zielsetzung}
+
+\include{slides/architektur}
+
+\include{slides/classdiagram}
+
+\include{slides/abläufe}
+
+<<<<<<< HEAD
+% TODO: Folie Features
+\include{slides/features}
+
+\include{slides/frontend}
+
+% TODO: User-Journey
+=======
+\include{slides/pattern}
+>>>>>>> main
+
+\end{document}
diff --git a/11-entwurfsheft-kolloquium/sdqbeamer.cls b/11-entwurfsheft-kolloquium/sdqbeamer.cls
new file mode 100644
index 0000000..1b9c2b8
--- /dev/null
+++ b/11-entwurfsheft-kolloquium/sdqbeamer.cls
@@ -0,0 +1,975 @@
+%% Vorlage für Präsentationen mit LaTeX Beamer im KIT-Design
+%% entsprechend den Gestaltungsrichtlinien vom 1. August 2020
+%%
+%% Siehe https://sdqweb.ipd.kit.edu/wiki/Dokumentvorlagen
+
+
+\NeedsTeXFormat{LaTeX2e}
+\ProvidesClass{sdqbeamer}[2022-05-03 v3.1.3 SDQ Beamer class]
+
+\RequirePackage[utf8]{inputenc}
+\RequirePackage[T1]{fontenc}
+
+\newif\ifsectionnavigation
+\newif\ifnavbarinfoot
+\newif\ifnavbarinline
+\newif\ifnavbarside
+\newif\iffourtothree
+\newif\ifsixteentonine
+\newif\ifsixteentoten
+\newif\ifgerman
+\newif\ifsmallfooterfont
+
+\def\kitslogan#1{\def\@kitslogan{#1}}
+\def\kitlogo#1{\def\@kitlogo{#1}}
+\def\groupname#1{\def\@groupname{#1}}
+\def\groupnamewidth#1{\def\@groupnamewidth{#1}}
+
+% siehe README.md
+\DeclareOption{de}{
+ \kitslogan{KIT -- Die Forschungsuniversität in der Helmholtz-Gemeinschaft}
+ \kitlogo{pse_logo}
+ \germantrue
+ \PassOptionsToPackage{autostyle}{csquotes}
+ }
+\DeclareOption{en}{
+ \kitslogan{KIT -- The Research University in the Helmholtz Association}
+ \kitlogo{kitlogo_en_rgb}
+ \germanfalse
+ }
+\DeclareOption{4:3}{
+ \fourtothreetrue
+ \sixteentoninefalse
+ \sixteentotenfalse
+}
+\DeclareOption{16:9}{
+ \fourtothreefalse
+ \sixteentoninetrue
+ \sixteentotenfalse
+}
+\DeclareOption{16:10}{
+ \fourtothreefalse
+ \sixteentoninefalse
+ \sixteentotentrue
+}
+\DeclareOption{navbarside}{
+ \sectionnavigationtrue
+ \navbarsidetrue
+ \navbarinlinefalse
+ \navbarinfootfalse
+}
+\DeclareOption{navbarinline}{
+ \sectionnavigationtrue
+ \navbarsidefalse
+ \navbarinlinetrue
+ \navbarinfootfalse
+}
+\DeclareOption{navbarinfooter}{
+ \sectionnavigationtrue
+ \navbarsidefalse
+ \navbarinlinefalse
+ \navbarinfoottrue
+}
+\DeclareOption{navbaroff}{
+ \sectionnavigationfalse
+}
+\DeclareOption{navbarkit}{
+ \sectionnavigationfalse
+ \smallfooterfonttrue
+}
+\DeclareOption{smallfoot}{
+ \smallfooterfonttrue
+}
+\DeclareOption{bigfoot}{
+ \smallfooterfontfalse
+}
+
+\ExecuteOptions{de,16:9,navbarinline,bigfoot}
+
+\DeclareOption*{\PassOptionsToClass{\CurrentOption}{beamer}}
+
+\ProcessOptions\relax
+
+\LoadClass[10pt,utf8]{beamer}
+
+% Babel-Paket wird nur bei deutscher Sprache benötigt
+\ifgerman
+ \RequirePackage[ngerman]{babel}
+\fi
+\RequirePackage{csquotes}
+\RequirePackage{hyperref}
+\RequirePackage[absolute,overlay]{textpos}
+
+%% ---------------
+%% | Typographie |
+%% ---------------
+
+\RequirePackage{microtype}
+
+\RequirePackage[scaled=.92]{helvet}
+\RequirePackage[scaled=.78]{beramono}
+\RequirePackage{libertineRoman}
+
+\setbeamerfont{title}{series=\bfseries,size=\Large}
+\setbeamerfont{frametitle}{series=\bfseries,size=\Large}
+\setbeamerfont{framesubtitle}{series=\bfseries,size=\normalsize}
+
+%% -----------------
+%% | Folien-Layout |
+%% -----------------
+
+% Seitenverhältnis
+%
+% Die Folien sind auf die Standardhöhe in LaTeX Beamer (9,6 cm) normiert.
+% Die Maße der KIT-Gestaltungsrichtlinien (Folienhöhe 14,3 cm) wurden durch
+% den Quotienten 1,5 geteilt.
+
+\RequirePackage{geometry}
+\iffourtothree
+ \geometry{papersize={12.8cm,9.6cm}}
+\fi
+\ifsixteentoten
+ \geometry{papersize={15.36cm,9.6cm}}
+\fi
+\ifsixteentonine
+ \geometry{papersize={17.07cm,9.6cm}}
+\fi
+
+% Ränder laut Gestaltungsrichtlinen; 3 mm -> 2 mm, 11 mm -> 7,3 mm
+\newlength{\kitoutermargin}
+\setlength{\kitoutermargin}{2mm}
+\newlength{\kitinnermargin}
+\setlength{\kitinnermargin}{7.3mm}
+\newlength{\kitbottommargin}
+\setlength{\kitbottommargin}{\kitinnermargin}
+
+% Ränder außen
+\setbeamersize{text margin left=\kitinnermargin,text margin right=\kitinnermargin}
+
+% keine Navigationssymbole
+\setbeamertemplate{navigation symbols}{}
+\setbeamercovered{invisible}
+\useinnertheme{rounded}
+\beamer@compresstrue % Miniframes (Navigations-Punkte) für Subsections immer in einer Zeile, ohne Umbrüche
+
+% Folientitel
+\setbeamertemplate{frametitle}{
+ \ifbeamer@plainframe\else%
+ % Unterkante Titeltext: 22,5 mm -> 15 mm von Seitenkopf
+ \begin{textblock*}{\dimexpr\paperwidth-30mm-2\kitinnermargin}[0,1](\kitinnermargin,15mm)%
+ \usebeamerfont{frametitle}\insertframetitle%
+ \ifx\insertframesubtitle\@empty\else\\[.1em]\fi
+ \usebeamerfont{framesubtitle}\insertframesubtitle%
+ \end{textblock*}%
+ \begin{textblock*}{20mm}[1,1](\dimexpr\paperwidth-\kitinnermargin\relax,15mm)%j
+ \includegraphics[width=20mm]{logos/\@kitlogo}%
+ \end{textblock*}%
+ \fi
+% Rand oben (ergibt Beginn des Textes bei 34 mm -> 22,7 mm)
+ \vspace {18mm}
+}
+
+%% Fußzeile
+\newlength{\kitbottom}
+ % Navbar in Footer: Schmale Fußzeile
+\ifnavbarinfoot
+ % Bei Navbar in Footer immer kleiner Font in der Fußzeile
+ \setbeamerfont{footer}{size=\fontsize{6pt}{7.2pt}\selectfont}
+ \setlength{\kitbottom}{4mm}
+\else
+ % Ansonsten kleiner Text nur, wenn "smallfoot" gewählt
+ \ifsmallfooterfont
+ \setbeamerfont{footer}{size=\fontsize{6pt}{7.2pt}\selectfont}
+ \else
+ \setbeamerfont{footer}{size=\scriptsize}
+ \fi
+ \setlength{\kitbottom}{\kitbottommargin}
+\fi
+\setbeamerfont{page number in head/foot}{series=\bfseries}
+
+\newlength{\kitbottomdepth}
+\newlength{\kitbottomheight}
+\newlength{\kitfootergroupwidth}
+
+\setbeamertemplate{footline}{%
+\setlength{\kitbottomdepth}{\dimexpr.5\kitbottom-.5em\relax}%
+\setlength{\kitbottomheight}{\dimexpr.5\kitbottom+.5em\relax}%
+ %% die "%" am Ende sind nötig, damit keine Abstände eingefügt werden
+ %
+ % Falls kein Gruppenname angegeben, die ganze Breite der Fußzeile für den Titel nutzen.
+ \ifdefined\@groupname%
+ \ifx\@groupname\empty%
+ \setlength{\kitfootergroupwidth}{0mm}%
+ \else%
+ % Falls die Breite des Gruppenlogos definiert ist, diese nehmen, sonst 50 mm
+ \ifdefined\@groupnamewidth%
+ \setlength{\kitfootergroupwidth}{\@groupnamewidth}%
+ \else%
+ \setlength{\kitfootergroupwidth}{50mm}%
+ \fi%
+ \fi%
+ \else
+ \setlength{\kitfootergroupwidth}{0mm}%
+ \fi
+ \usebeamerfont{footer}%
+ \ifsectionnavigation%
+ % Option "navbarinline"
+ \ifnavbarinline%
+ \begin{beamercolorbox}[wd=\paperwidth, leftskip=2mm, rightskip=2mm]{}
+ \insertnavigation{\dimexpr\paperwidth-4mm\relax}
+ \vspace{1mm}
+ \end{beamercolorbox}%
+ \fi%
+ % Option "navbarinfooter"
+ \ifnavbarinfoot%
+ % Punkte für Subsections deaktivieren
+ \setbeamertemplate{mini frames}{}%
+ \begin{beamercolorbox}[wd=\paperwidth, leftskip=1mm, rightskip=1mm]{}%
+ \insertsectionnavigationhorizontal{\dimexpr\paperwidth-\kitoutermargin\relax}{}{}
+ \end{beamercolorbox}%
+ \fi%
+ \fi%
+ \leavevmode%
+ \begin{beamercolorbox}[wd=13mm, ht=\kitbottomheight, dp=\kitbottomdepth, leftskip=4mm]{}
+ \usebeamerfont{page number in head/foot}%
+ \strut\insertframenumber{}/\inserttotalframenumber%
+ \end{beamercolorbox}%
+ \begin{beamercolorbox}[wd=20mm, ht=\kitbottomheight, dp=\kitbottomdepth]{}
+ \usebeamerfont{date in head/foot}%
+ \strut\insertshortdate%
+ \end{beamercolorbox}%
+ % Die Boxen mit dem Titel und dem Gruppennamen sind vertikal zentriert, damit auch zweizeilige Texte schön aussehen
+ % Daher müssen sie um \kitbottomdepth nach unten verschoben werden
+ \raisebox{-\kitbottomdepth}{
+ % Die Box hat daher auch Höhe \kitbottom und Tiefe 0mm
+ \begin{beamercolorbox}[wd=\dimexpr\paperwidth-37mm-\kitfootergroupwidth, ht=\kitbottom, dp=0mm]{}%
+ % Inhalt vertikal zentrieren; Anpassung um 1.5 pt, damit bei einzeiligem Inhalt genau die Baseline der Blöcke mit Seitenzahl und Datum getroffen wird
+ \vbox to\kitbottom{\vfill\vskip1.5pt%
+ \beamer@shortauthor\ifx\beamer@shortauthor\empty\else: \fi\beamer@shorttitle%
+ \vfill}%
+ \end{beamercolorbox}%
+ \ifdefined\@groupname%
+ \begin{beamercolorbox}[wd=\kitfootergroupwidth, ht=\kitbottom, dp=0mm, rightskip=\kitinnermargin]{}
+ \vbox to\kitbottom{\vfill\vskip1.5pt%
+ \raggedleft\@groupname%
+ \vfill}%
+ \end{beamercolorbox}%
+ \fi%
+ }%
+}
+
+%% Option "navbarside"
+\ifnavbarside
+\useoutertheme[height=0cm,width=3.5cm,left]{sidebar}
+
+\setbeamerfont{title in sidebar}{family=\sffamily,series=\mdseries,size={\fontsize{10pt}{11pt}}}
+\setbeamerfont{section in sidebar}{family=\sffamily,series=\mdseries,size={\fontsize{9pt}{9.9pt}}}
+\setbeamerfont{subsection in sidebar}{family=\sffamily,series=\mdseries,size={\fontsize{8pt}{8.8pt}}}
+
+\setbeamertemplate{sidebar \beamer@sidebarside}
+ {\vskip1.5cm%
+ \hskip6.5mm%
+ \advance\beamer@sidebarwidth by -5mm%
+ \insertverticalnavigation{\beamer@sidebarwidth}%
+ }%
+\fi
+
+%% Hintergrund
+\usebackgroundtemplate{
+ % Trennlinie nicht bei "plain"-Frames
+ \ifbeamer@plainframe\else\kitseparationline\fi
+}
+
+% Trennlinie
+\newcommand{\kitseparationline}{
+ \begin{pgfpicture}{0mm}{0mm}{\paperwidth}{\paperheight}
+ \pgfsetstrokecolor{black!15}
+ \pgfsetlinewidth{.5pt}
+ \pgfpathmoveto{\pgfpoint{\kitoutermargin}{\kitinnermargin}}
+ \pgfpathlineto{\pgfpoint{\paperwidth-\kitoutermargin}{\kitinnermargin}}
+ \pgfusepath{stroke}
+ \end{pgfpicture}%
+}
+
+
+%% --------------
+%% | Titelseite |
+%% --------------
+
+\def\titleimage#1{\def\@titleimage{#1}}
+\def\grouplogo#1{\def\@grouplogo{#1}}
+
+\newcommand{\KITtitleframe}{
+ \begin{frame}[plain]
+ \titlepage
+ \end{frame}
+}
+
+\newlength{\kittitleimageheight}
+\setbeamertemplate{title page}{
+ % From textpos documentation (https://ctan.org/pkg/textpos)
+ %
+ % \begin{textblock}{<hsize>}[<ho>,<vo>](<hpos>,<vpos>)
+ % The coordinates <ho> and <vo> are fractions of the width and height of the text
+ % box, respectively, and state that the box is to be placed so that the reference point
+ % (<ho>,<vo>) within the box is to be placed at the point (<hpos>,<vpos>) on the page.
+
+ % KIT-Logo
+ \begin{textblock*}{30mm}(\kitinnermargin,6.7mm)
+ \includegraphics[width=30mm]{logos/\@kitlogo}
+ \end{textblock*}
+
+ % Gruppenlogo
+ \ifdefined\@grouplogo
+ \ifx\@grouplogo\empty \else
+ \begin{textblock*}{20mm}(\dimexpr\paperwidth-24mm\relax,6.7mm)
+ \includegraphics[width=20mm,height=20mm,keepaspectratio]{logos/\@grouplogo}
+ \end{textblock*}
+ \fi % falls \grouplogo{} aufgerufen wird, kein Gruppenlogo einbinden
+ \else
+ \begin{textblock*}{20mm}(\dimexpr\paperwidth-24mm\relax,6.7mm)
+ \colorbox{kit-purple100!20}{\parbox[t][12mm][c]{19mm}{\color{kit-purple100}\scriptsize\centering
+ \ifgerman
+ Bitte Logo über \texttt{\textbackslash grouplogo\{\}} festlegen.
+ \else
+ Please set a logo using \texttt{\textbackslash grouplogo\{\}}.
+ \fi
+ }}
+ \end{textblock*}
+ \fi
+
+ % Titel
+ \begin{textblock*}{\dimexpr\paperwidth-8mm\relax}[0,.5](\kitinnermargin,28mm)
+ \usebeamerfont*{title}\inserttitle
+ \end{textblock*}
+
+ % Untertitel
+ \begin{textblock*}{\dimexpr\paperwidth-8mm\relax}(\kitinnermargin,36mm)
+ \small\textbf{\insertsubtitle}
+ \end{textblock*}
+
+ % Autor
+ \begin{textblock*}{\dimexpr\paperwidth-8mm\relax}(\kitinnermargin,41mm)
+ \small\insertauthor~\textbar~\insertdate
+ \end{textblock*}
+
+ % Titelbild
+ \setlength{\kittitleimageheight}{40mm}
+ \begin{textblock*}{\paperwidth}(\kitoutermargin,\dimexpr\paperheight-\kitbottommargin-\kittitleimageheight)
+ \begin{pgfpicture}{0mm}{0mm}{\paperwidth}{\kittitleimageheight}
+ % Clipping-Pfad um titelbild
+ \pgfsetstrokecolor{black!15}
+ \pgfsetlinewidth{1pt}
+ \pgfsetcornersarced{\pgfpoint{3mm}{3mm}}
+ \pgfpathmoveto{\pgfpoint{\paperwidth-2\kitoutermargin}{0mm}}
+ \pgfpathlineto{\pgfpoint{\paperwidth-2\kitoutermargin}{\kittitleimageheight}}
+ \pgfsetcornersarced{\pgfpointorigin}
+ \pgfpathlineto{\pgfpoint{0mm}{\kittitleimageheight}}
+ \pgfsetcornersarced{\pgfpoint{3mm}{3mm}}
+ \pgfpathlineto{\pgfpointorigin}
+ \pgfsetcornersarced{\pgfpointorigin}
+ \pgfpathclose
+ \pgfusepath{stroke,clip}
+ \pgfsetstrokecolor{black}
+
+ % Titelbild
+ \ifdefined\@titleimage
+ \ifx\@titleimage\empty \else%
+ \pgftext[at=\pgfpoint{.5\paperwidth}{0mm},center,bottom]{%
+ \includegraphics[height=40mm]{logos/\@titleimage}
+ }
+ \fi % Bei Aufruf von \titleimage{} leeren Rahmen anzeigen.
+ \else
+ \pgftext[at=\pgfpoint{.5\paperwidth}{.5\kittitleimageheight},center,base]{%
+ \colorbox{kit-purple100!20}{\parbox[c][\kittitleimageheight][c]{\paperwidth}{\color{kit-purple100}\centering Bitte Titelbild über \texttt{\textbackslash titleimage\{\}} festlegen.
+ }}%
+ }
+ \fi
+
+
+ \end{pgfpicture}%
+ \end{textblock*}
+
+
+ % KIT slogan
+ \begin{textblock*}{80mm}[0,.5](\kitoutermargin,\dimexpr\paperheight-.5\kitbottommargin)
+ \fontsize{5.5pt}{5.5pt}\selectfont\@kitslogan
+ \end{textblock*}
+
+ \begin{textblock*}{30mm}[1,.5](\dimexpr\paperwidth-\kitoutermargin\relax,\dimexpr\paperheight-.5\kitbottommargin)
+ \fontsize{11pt}{11pt}\selectfont\bfseries\raggedleft%
+ {\href{https://www.kit.edu}{www.kit.edu}}
+ \end{textblock*}
+
+}
+%% ---------------
+%% | /Titelseite |
+%% ---------------
+
+%% ----------
+%% | Farben |
+%% ----------
+%% KIT-Farbschema
+
+% KIT color green :
+\definecolor{kit-green}{RGB}{0, 150, 130}
+\definecolor{kit-green100}{RGB}{0, 150, 130}
+\definecolor{kit-green90}{rgb}{0.1, 0.6294, 0.5588}
+\definecolor{kit-green80}{rgb}{0.2, 0.6706, 0.6078}
+\definecolor{kit-green75}{rgb}{0.25, 0.6912, 0.6324}
+\definecolor{kit-green70}{rgb}{0.3, 0.7118, 0.6569}
+\definecolor{kit-green60}{rgb}{0.4, 0.7529, 0.7059}
+\definecolor{kit-green50}{rgb}{0.5, 0.7941, 0.7549}
+\definecolor{kit-green40}{rgb}{0.6, 0.8353, 0.8039}
+\definecolor{kit-green30}{rgb}{0.7, 0.8765, 0.8529}
+\definecolor{kit-green25}{rgb}{0.75, 0.8971, 0.8775}
+\definecolor{kit-green20}{rgb}{0.8, 0.9176, 0.902}
+\definecolor{kit-green15}{rgb}{0.85, 0.9382, 0.9265}
+\definecolor{kit-green10}{rgb}{0.9, 0.9588, 0.951}
+\definecolor{kit-green5}{rgb}{0.95, 0.9794, 0.9755}
+
+% KIT color blue:
+\definecolor{kit-blue}{RGB}{70, 100, 170}
+\definecolor{kit-blue100}{RGB}{70, 100, 170}
+\definecolor{kit-blue90}{rgb}{0.3471, 0.4529, 0.7}
+\definecolor{kit-blue80}{rgb}{0.4196, 0.5137, 0.7333}
+\definecolor{kit-blue75}{rgb}{0.4559, 0.5441, 0.75}
+\definecolor{kit-blue70}{rgb}{0.4922, 0.5745, 0.7667}
+\definecolor{kit-blue60}{rgb}{0.5647, 0.6353, 0.8}
+\definecolor{kit-blue50}{rgb}{0.6373, 0.6961, 0.8333}
+\definecolor{kit-blue40}{rgb}{0.7098, 0.7569, 0.8667}
+\definecolor{kit-blue30}{rgb}{0.7824, 0.8176, 0.9}
+\definecolor{kit-blue25}{rgb}{0.8186, 0.848, 0.9167}
+\definecolor{kit-blue20}{rgb}{0.8549, 0.8784, 0.9333}
+\definecolor{kit-blue15}{rgb}{0.8912, 0.9088, 0.95}
+\definecolor{kit-blue10}{rgb}{0.9275, 0.9392, 0.9667}
+\definecolor{kit-blue5}{rgb}{0.9637, 0.9696, 0.9833}
+
+% KIT color red :
+\definecolor{kit-red}{RGB}{162, 34, 35}
+\definecolor{kit-red100}{RGB}{162, 34, 35}
+\definecolor{kit-red90}{rgb}{0.6718, 0.22, 0.2235}
+\definecolor{kit-red80}{rgb}{0.7082, 0.3067, 0.3098}
+\definecolor{kit-red75}{rgb}{0.7265, 0.35, 0.3529}
+\definecolor{kit-red70}{rgb}{0.7447, 0.3933, 0.3961}
+\definecolor{kit-red60}{rgb}{0.7812, 0.48, 0.4824}
+\definecolor{kit-red50}{rgb}{0.8176, 0.5667, 0.5686}
+\definecolor{kit-red40}{rgb}{0.8541, 0.6533, 0.6549}
+\definecolor{kit-red30}{rgb}{0.8906, 0.74, 0.7412}
+\definecolor{kit-red25}{rgb}{0.9088, 0.7833, 0.7843}
+\definecolor{kit-red20}{rgb}{0.9271, 0.8267, 0.8275}
+\definecolor{kit-red15}{rgb}{0.9453, 0.87, 0.8706}
+\definecolor{kit-red10}{rgb}{0.9635, 0.9133, 0.9137}
+\definecolor{kit-red5}{rgb}{0.9818, 0.9567, 0.9569}
+
+% KIT color yellow :
+\definecolor{kit-yellow}{RGB}{252, 229, 0}
+\definecolor{kit-yellow100}{RGB}{252, 229, 0}
+\definecolor{kit-yellow90}{rgb}{0.9894, 0.9082, 0.1}
+\definecolor{kit-yellow80}{rgb}{0.9906, 0.9184, 0.2}
+\definecolor{kit-yellow75}{rgb}{0.9912, 0.9235, 0.25}
+\definecolor{kit-yellow70}{rgb}{0.9918, 0.9286, 0.3}
+\definecolor{kit-yellow60}{rgb}{0.9929, 0.9388, 0.4}
+\definecolor{kit-yellow50}{rgb}{0.9941, 0.949, 0.5}
+\definecolor{kit-yellow40}{rgb}{0.9953, 0.9592, 0.6}
+\definecolor{kit-yellow30}{rgb}{0.9965, 0.9694, 0.7}
+\definecolor{kit-yellow25}{rgb}{0.9971, 0.9745, 0.75}
+\definecolor{kit-yellow20}{rgb}{0.9976, 0.9796, 0.8}
+\definecolor{kit-yellow15}{rgb}{0.9982, 0.9847, 0.85}
+\definecolor{kit-yellow10}{rgb}{0.9988, 0.9898, 0.9}
+\definecolor{kit-yellow5}{rgb}{0.9994, 0.9949, 0.95}
+
+% KIT color orange :
+\definecolor{kit-orange}{RGB}{223, 155, 27}
+\definecolor{kit-orange100}{RGB}{223, 155, 27}
+\definecolor{kit-orange90}{rgb}{0.8871, 0.6471, 0.1953}
+\definecolor{kit-orange80}{rgb}{0.8996, 0.6863, 0.2847}
+\definecolor{kit-orange75}{rgb}{0.9059, 0.7059, 0.3294}
+\definecolor{kit-orange70}{rgb}{0.9122, 0.7255, 0.3741}
+\definecolor{kit-orange60}{rgb}{0.9247, 0.7647, 0.4635}
+\definecolor{kit-orange50}{rgb}{0.9373, 0.8039, 0.5529}
+\definecolor{kit-orange40}{rgb}{0.9498, 0.8431, 0.6424}
+\definecolor{kit-orange30}{rgb}{0.9624, 0.8824, 0.7318}
+\definecolor{kit-orange25}{rgb}{0.9686, 0.902, 0.7765}
+\definecolor{kit-orange20}{rgb}{0.9749, 0.9216, 0.8212}
+\definecolor{kit-orange15}{rgb}{0.9812, 0.9412, 0.8659}
+\definecolor{kit-orange10}{rgb}{0.9875, 0.9608, 0.9106}
+\definecolor{kit-orange5}{rgb}{0.9937, 0.9804, 0.9553}
+
+% KIT color lightgreen :
+\definecolor{kit-lightgreen}{RGB}{140, 182, 60}
+\definecolor{kit-lightgreen100}{RGB}{140, 182, 60}
+\definecolor{kit-lightgreen90}{rgb}{0.5941, 0.7424, 0.3118}
+\definecolor{kit-lightgreen80}{rgb}{0.6392, 0.771, 0.3882}
+\definecolor{kit-lightgreen75}{rgb}{0.6618, 0.7853, 0.4265}
+\definecolor{kit-lightgreen70}{rgb}{0.6843, 0.7996, 0.4647}
+\definecolor{kit-lightgreen60}{rgb}{0.7294, 0.8282, 0.5412}
+\definecolor{kit-lightgreen50}{rgb}{0.7745, 0.8569, 0.6176}
+\definecolor{kit-lightgreen40}{rgb}{0.8196, 0.8855, 0.6941}
+\definecolor{kit-lightgreen30}{rgb}{0.8647, 0.9141, 0.7706}
+\definecolor{kit-lightgreen25}{rgb}{0.8873, 0.9284, 0.8088}
+\definecolor{kit-lightgreen20}{rgb}{0.9098, 0.9427, 0.8471}
+\definecolor{kit-lightgreen15}{rgb}{0.9324, 0.9571, 0.8853}
+\definecolor{kit-lightgreen10}{rgb}{0.9549, 0.9714, 0.9235}
+\definecolor{kit-lightgreen5}{rgb}{0.9775, 0.9857, 0.9618}
+
+
+% KIT color purple :
+\definecolor{kit-purple}{RGB}{163, 16, 124}
+\definecolor{kit-purple100}{RGB}{163, 16, 124}
+\definecolor{kit-purple90}{rgb}{0.6753, 0.1565, 0.5376}
+\definecolor{kit-purple80}{rgb}{0.7114, 0.2502, 0.589}
+\definecolor{kit-purple75}{rgb}{0.7294, 0.2971, 0.6147}
+\definecolor{kit-purple70}{rgb}{0.7475, 0.3439, 0.6404}
+\definecolor{kit-purple60}{rgb}{0.7835, 0.4376, 0.6918}
+\definecolor{kit-purple50}{rgb}{0.8196, 0.5314, 0.7431}
+\definecolor{kit-purple40}{rgb}{0.8557, 0.6251, 0.7945}
+\definecolor{kit-purple30}{rgb}{0.8918, 0.7188, 0.8459}
+\definecolor{kit-purple25}{rgb}{0.9098, 0.7657, 0.8716}
+\definecolor{kit-purple20}{rgb}{0.9278, 0.8125, 0.8973}
+\definecolor{kit-purple15}{rgb}{0.9459, 0.8594, 0.9229}
+\definecolor{kit-purple10}{rgb}{0.9639, 0.9063, 0.9486}
+\definecolor{kit-purple5}{rgb}{0.982, 0.9531, 0.9743}
+
+% KIT color brown :
+\definecolor{kit-brown}{RGB}{167, 130, 46}
+\definecolor{kit-brown100}{RGB}{167, 130, 46}
+\definecolor{kit-brown90}{rgb}{0.6894, 0.5588, 0.2624}
+\definecolor{kit-brown80}{rgb}{0.7239, 0.6078, 0.3443}
+\definecolor{kit-brown75}{rgb}{0.7412, 0.6324, 0.3853}
+\definecolor{kit-brown70}{rgb}{0.7584, 0.6569, 0.4263}
+\definecolor{kit-brown60}{rgb}{0.7929, 0.7059, 0.5082}
+\definecolor{kit-brown50}{rgb}{0.8275, 0.7549, 0.5902}
+\definecolor{kit-brown40}{rgb}{0.862, 0.8039, 0.6722}
+\definecolor{kit-brown30}{rgb}{0.8965, 0.8529, 0.7541}
+\definecolor{kit-brown25}{rgb}{0.9137, 0.8775, 0.7951}
+\definecolor{kit-brown20}{rgb}{0.931, 0.902, 0.8361}
+\definecolor{kit-brown15}{rgb}{0.9482, 0.9265, 0.8771}
+\definecolor{kit-brown10}{rgb}{0.9655, 0.951, 0.918}
+\definecolor{kit-brown5}{rgb}{0.9827, 0.9755, 0.959}
+
+% KIT color cyan :
+\definecolor{kit-cyan}{RGB}{35, 161, 224}
+\definecolor{kit-cyan100}{RGB}{35, 161, 224}
+\definecolor{kit-cyan90}{rgb}{0.2235, 0.6682, 0.8906}
+\definecolor{kit-cyan80}{rgb}{0.3098, 0.7051, 0.9027}
+\definecolor{kit-cyan75}{rgb}{0.3529, 0.7235, 0.9088}
+\definecolor{kit-cyan70}{rgb}{0.3961, 0.742, 0.9149}
+\definecolor{kit-cyan60}{rgb}{0.4824, 0.7788, 0.9271}
+\definecolor{kit-cyan50}{rgb}{0.5686, 0.8157, 0.9392}
+\definecolor{kit-cyan40}{rgb}{0.6549, 0.8525, 0.9514}
+\definecolor{kit-cyan30}{rgb}{0.7412, 0.8894, 0.9635}
+\definecolor{kit-cyan25}{rgb}{0.7843, 0.9078, 0.9696}
+\definecolor{kit-cyan20}{rgb}{0.8275, 0.9263, 0.9757}
+\definecolor{kit-cyan15}{rgb}{0.8706, 0.9447, 0.9818}
+\definecolor{kit-cyan10}{rgb}{0.9137, 0.9631, 0.9878}
+\definecolor{kit-cyan5}{rgb}{0.9569, 0.9816, 0.9939}
+
+% KIT color gray :
+\definecolor{kit-gray}{RGB}{0, 0, 0}
+\definecolor{kit-gray100}{RGB}{0, 0, 0}
+\definecolor{kit-gray90}{rgb}{0.1, 0.1, 0.1}
+\definecolor{kit-gray80}{rgb}{0.2, 0.2, 0.2}
+\definecolor{kit-gray75}{rgb}{0.25, 0.25, 0.25}
+\definecolor{kit-gray70}{rgb}{0.3, 0.3, 0.3}
+\definecolor{kit-gray60}{rgb}{0.4, 0.4, 0.4}
+\definecolor{kit-gray50}{rgb}{0.5, 0.5, 0.5}
+\definecolor{kit-gray40}{rgb}{0.6, 0.6, 0.6}
+\definecolor{kit-gray30}{rgb}{0.7, 0.7, 0.7}
+\definecolor{kit-gray25}{rgb}{0.75, 0.75, 0.75}
+\definecolor{kit-gray20}{rgb}{0.8, 0.8, 0.8}
+\definecolor{kit-gray15}{rgb}{0.85, 0.85, 0.85}
+\definecolor{kit-gray10}{rgb}{0.9, 0.9, 0.9}
+\definecolor{kit-gray5}{rgb}{0.95, 0.95, 0.95}
+
+
+
+\setbeamercolor*{normal text}{fg=black}
+\setbeamercolor*{alerted text}{fg=kit-red100}
+\setbeamercolor*{example text}{fg=black}
+\setbeamercolor*{structure}{fg=black}
+
+\setbeamercolor*{palette primary}{fg=black,bg=black!15}
+\setbeamercolor*{palette secondary}{fg=black,bg=black!15}
+\setbeamercolor*{palette tertiary}{fg=black,bg=black!15}
+\setbeamercolor*{palette quaternary}{fg=black,bg=black!15}
+
+\setbeamercolor*{palette sidebar primary}{fg=black!75}
+\setbeamercolor*{palette sidebar secondary}{fg=black!75}
+\setbeamercolor*{palette sidebar tertiary}{fg=black!75}
+\setbeamercolor*{palette sidebar quaternary}{fg=black!75}
+
+\setbeamercolor*{item projected}{fg=white,bg=kit-green100}
+
+\setbeamercolor*{block title}{fg=white,bg=kit-green100}
+\setbeamercolor*{block title alerted}{use=alerted text,fg=white,bg=alerted text.fg!75!black}
+\setbeamercolor*{block title example}{fg=white,bg=kit-blue100}
+
+\setbeamercolor*{block body}{fg=black,bg=kit-green15}
+\setbeamercolor*{block body alerted}{parent=normal text,use=block title alerted,bg=block title alerted.bg!10!bg}
+\setbeamercolor*{block body example}{fg=black,bg=kit-blue15}
+
+\setbeamercolor*{separation line}{}
+\setbeamercolor*{fine separation line}{}
+
+\setbeamercolor*{background canvas}{bg=white}
+
+%% -----------
+%% | /Farben |
+%% -----------
+
+%% -----------------------------------
+%% | halbgerundete Aufzählungspunkte |
+%% -----------------------------------
+
+\newcommand{\itemizeColor}{kit-green100}
+
+% KIT-Aufzählungszeichen
+\newcommand{\KITmark}{%
+ \begin{pgfpicture}{0mm}{0mm}{1ex}{1ex}
+ {\pgfsetcornersarced{\pgfpoint{.3ex}{.3ex}}
+ \pgfpathmoveto{\pgfpoint{0cm}{1ex}}
+ \pgfpathlineto{\pgfpoint{1ex}{1ex}}
+ \pgfpathlineto{\pgfpoint{1ex}{0cm}}}
+ {\pgfsetcornersarced{\pgfpoint{.3ex}{.3ex}}
+ \pgfpathmoveto{\pgfpoint{1ex}{0cm}}
+ \pgfpathlineto{\pgfpointorigin}
+ \pgfpathlineto{\pgfpoint{0cm}{1ex}}}
+ \color{\itemizeColor}
+ \pgfusepath{fill}
+ \end{pgfpicture}%
+}
+
+% \setbeamertemplate{itemize items}{\raisebox{.2ex}{\KITmark}}
+\setbeamertemplate{itemize items}[square]
+\setbeamercolor{itemize item}{fg=kit-green100}
+
+%% ----------------------
+%% | Inhaltsverzeichnis |
+%% ----------------------
+
+\setbeamertemplate{section in toc}{\normalsize\textbf{\textcolor{kit-blue}{\inserttocsectionnumber.~\inserttocsection}}\par}
+\setbeamertemplate{subsection in toc}{\small\hspace{1.2em}\raisebox{.2ex}{\KITmark}\hspace{\labelsep}\inserttocsubsection\par}
+
+%% ------------------------------
+%% | halbgerundete Beamer-Boxen |
+%% ------------------------------
+
+\renewcommand\beamerboxesrounded[2][]{%
+ \global\let\beamer@firstlineitemizeunskip=\relax%
+ \vbox\bgroup%
+ \setkeys{beamerboxes}{upper=block title,lower=block body,width=\textwidth,shadow=false}%
+ \setkeys{beamerboxes}{#1}%
+ {%
+ \usebeamercolor{\bmb@lower}%
+ \globalcolorstrue%
+ \colorlet{lower.bg}{bg}%
+ }%
+ {%
+ \usebeamercolor{\bmb@upper}%
+ \globalcolorstrue%
+ \colorlet{upper.bg}{bg}%
+ }%
+ %
+ % Typeset head
+ %
+ \vskip4bp
+ \setbox\bmb@box=\hbox{%
+ \begin{minipage}[b]{\bmb@width}%
+ \usebeamercolor[fg]{\bmb@upper}%
+ #2%
+ \end{minipage}}%
+ \ifdim\wd\bmb@box=0pt%
+ \setbox\bmb@box=\hbox{}%
+ \ht\bmb@box=1.5pt%
+ \bmb@prevheight=-4.5pt%
+ \else%
+ \wd\bmb@box=\bmb@width%
+ \bmb@temp=\dp\bmb@box%
+ \ifdim\bmb@temp<1.5pt%
+ \bmb@temp=1.5pt%
+ \fi%
+ \setbox\bmb@box=\hbox{\raise\bmb@temp\hbox{\box\bmb@box}}%
+ \dp\bmb@box=0pt%
+ \bmb@prevheight=\ht\bmb@box%
+ \fi%
+ \bmb@temp=\bmb@width%
+ \bmb@dima=\bmb@temp\advance\bmb@dima by2.2bp%
+ \bmb@dimb=\bmb@temp\advance\bmb@dimb by4bp%
+ \hbox{%
+ \begin{pgfpicture}{0bp}{+-\ht\bmb@box}{0bp}{+-\ht\bmb@box}
+ \ifdim\wd\bmb@box=0pt%
+ \color{lower.bg}%
+ \else%
+ \color{upper.bg}%
+ \fi%
+ \pgfpathqmoveto{-4bp}{-1bp}
+ % Adaption for "KIT-Design"
+ \pgfpathlineto{\pgfpoint{-4bp}{3bp}}
+ %\pgfpathqcurveto{-4bp}{1.2bp}{-2.2bp}{3bp}{0bp}{3bp}
+ \pgfpathlineto{\pgfpoint{\bmb@temp}{3bp}}
+ \pgfpathcurveto%
+ {\pgfpoint{\bmb@dima}{3bp}}%
+ {\pgfpoint{\bmb@dimb}{1.2bp}}%
+ {\pgfpoint{\bmb@dimb}{-1bp}}%
+ \bmb@dima=-\ht\bmb@box%
+ \advance\bmb@dima by-2pt%
+ \pgfpathlineto{\pgfpoint{\bmb@dimb}{\bmb@dima}}
+ \pgfpathlineto{\pgfpoint{-4bp}{\bmb@dima}}
+ \pgfusepath{fill}
+ \end{pgfpicture}%
+ \copy\bmb@box%
+ }%
+ \nointerlineskip%
+ \vskip-1pt%
+ \ifdim\wd\bmb@box=0pt%
+ \else%
+ \hbox{%
+ \begin{pgfpicture}{0pt}{0pt}{\bmb@width}{6pt}
+ \bmb@dima=\bmb@width%
+ \advance\bmb@dima by8bp%
+ \pgfpathrectangle{\pgfpoint{-4bp}{-1bp}}{\pgfpoint{\bmb@dima}{8bp}}
+ \pgfusepath{clip}
+ {\pgftransformshift{\pgfpoint{-4bp}{0bp}}\pgftext[left,base]{\pgfuseshading{bmb@transition}}}%
+ \end{pgfpicture}%
+ }%
+ \nointerlineskip%
+ \vskip-0.5pt%
+ \fi%
+ \ifbmb@shadow%
+ \setbox\bmb@boxshadow=\hbox{\pgfuseshading{bmb@shadow}}%
+ \setbox\bmb@boxshadowball=\hbox{\pgfuseshading{bmb@shadowball}}%
+ \setbox\bmb@boxshadowballlarge=\hbox{\pgfuseshading{bmb@shadowballlarge}}%
+ \fi%
+ \setbox\bmb@colorbox=\hbox{{\pgfpicturetrue\pgfsetcolor{lower.bg}}}%
+ \setbox\bmb@box=\hbox\bgroup\begin{minipage}[b]{\bmb@width}%
+ \vskip2pt%
+ \usebeamercolor[fg]{\bmb@lower}%
+ \colorlet{beamerstructure}{upper.bg}%
+ \colorlet{structure}{upper.bg}%
+ %\color{.}%
+ }
+
+\def\endbeamerboxesrounded{%
+ \end{minipage}\egroup%
+ \wd\bmb@box=\bmb@width%
+ \bmb@temp=\dp\bmb@box%
+ \advance\bmb@temp by.5pt%
+ \setbox\bmb@box=\hbox{\raise\bmb@temp\hbox{\box\bmb@box}}%
+ \dp\bmb@box=0pt%
+ \bmb@temp=\wd\bmb@box%
+ \bmb@dima=\bmb@temp\advance\bmb@dima by2.2bp%
+ \bmb@dimb=\bmb@temp\advance\bmb@dimb by4bp%
+ \hbox{%
+ \begin{pgfpicture}{0bp}{0bp}{0bp}{0bp}
+ \ifbmb@shadow%
+ {\pgftransformshift{\pgfpoint{4bp}{-3bp}}\pgftext{\copy\bmb@boxshadowball}}
+ \begin{pgfscope}
+ {%
+ \advance\bmb@temp by-1bp%
+ \pgfpathrectangle{\pgfpoint{\bmb@temp}{-7bp}}{\pgfpoint{9bp}{9bp}}%
+ \pgfusepath{clip}
+ }%
+ {\pgftransformshift{\pgfpoint{\bmb@temp}{1bp}}\pgftext{\box\bmb@boxshadowballlarge}}
+ \end{pgfscope}
+ \begin{pgfscope}
+ \advance\bmb@temp by-4bp%
+ \pgfpathrectangle{\pgfpoint{4bp}{-7bp}}{\pgfpoint{\bmb@temp}{5bp}}
+ \pgfusepath{clip}
+ {\pgftransformshift{\pgfpoint{4bp}{-7bp}}\pgftext[left,base]{\copy\bmb@boxshadow}}%
+ \end{pgfscope}
+ \begin{pgfscope}
+ \advance\bmb@temp by 4bp%
+ \bmb@dima=\ht\bmb@box%
+ \advance\bmb@dima by\bmb@prevheight%
+ \advance\bmb@dima by 4bp%
+ \pgfpathrectangle{\pgfpoint{\bmb@temp}{1bp}}{\pgfpoint{4bp}{\bmb@dima}}
+ \pgfusepath{clip}
+ \advance\bmb@dima by-4bp%
+ {\pgftransformshift{\pgfpoint{\bmb@temp}{\bmb@dima}}\pgftext{\box\bmb@boxshadowball}}
+ \advance\bmb@dima by-1bp%
+ \pgfpathrectangle{\pgfpoint{\bmb@temp}{1bp}}{\pgfpoint{4bp}{\bmb@dima}}
+ \pgfusepath{clip}
+ \advance\bmb@temp by4bp%
+ {\pgftransformshift{\pgfpoint{\bmb@temp}{-3bp}}%
+ \pgftransformrotate{90}%
+ \pgftext[left,base]{\box\bmb@boxshadow}}%
+ \end{pgfscope}
+ \fi%
+ \unhbox\bmb@colorbox%
+ \pgfpathqmoveto{-4bp}{1bp}
+ \pgfpathqcurveto{-4bp}{-1.2bp}{-2.2bp}{-3bp}{0bp}{-3bp}
+ \pgfpathlineto{\pgfpoint{\the\bmb@dimb}{-3bp}}
+ {
+ \bmb@dima=\ht\bmb@box%
+ \pgfpathlineto{\pgfpoint{\bmb@dimb}{\bmb@dima}}
+ \pgfpathlineto{\pgfpoint{-4bp}{\bmb@dima}}
+ \pgfusepath{fill}
+ }
+ \ifbmb@shadow%
+ {
+ \color{black!50!bg}
+ \pgfsetlinewidth{0pt}
+ \pgfpathmoveto{\pgfpoint{\bmb@dimb}{-.5bp}}
+ \bmb@dima=\ht\bmb@box%
+ \advance\bmb@dima by\bmb@prevheight%
+ \advance\bmb@dima by 1bp%
+ \pgfpathlineto{\pgfpoint{\bmb@dimb}{\bmb@dima}}
+ \pgfusepath{stroke}
+ \bmb@temp=\bmb@dima
+ \advance\bmb@dima by 1bp%
+ \color{black!31!bg}
+ \pgfpathmoveto{\pgfpoint{\bmb@dimb}{\bmb@temp}}
+ \pgfpathlineto{\pgfpoint{\bmb@dimb}{\bmb@dima}}
+ \pgfusepath{stroke}
+ \advance\bmb@dima by 1bp%
+ \advance\bmb@temp by 1bp%
+ \color{black!19!bg}
+ \pgfpathmoveto{\pgfpoint{\bmb@dimb}{\bmb@temp}}
+ \pgfpathlineto{\pgfpoint{\bmb@dimb}{\bmb@dima}}
+ \pgfusepath{stroke}
+ \advance\bmb@dima by 1bp%
+ \advance\bmb@temp by 1bp%
+ \color{black!6!bg}
+ \pgfpathmoveto{\pgfpoint{\bmb@dimb}{\bmb@temp}}
+ \pgfpathlineto{\pgfpoint{\bmb@dimb}{\bmb@dima}}
+ \pgfusepath{stroke}
+ \advance\bmb@dima by 1.5bp%
+ \advance\bmb@temp by 1bp%
+ \color{bg}
+ \pgfpathmoveto{\pgfpoint{\bmb@dimb}{\bmb@temp}}
+ \pgfpathlineto{\pgfpoint{\bmb@dimb}{\bmb@dima}}
+ \pgfusepath{stroke}
+ }
+ \fi
+ \end{pgfpicture}%
+ \box\bmb@box%
+ }%
+ \ifbmb@shadow%
+ \vskip4bp minus 2bp%
+ \else%
+ \vskip2bp%
+ \fi%
+ \egroup% of \vbox\bgroup
+}
+
+
+%% -------------------------------
+%% | /halbgerundete Beamer-Boxen |
+%% -------------------------------
+
+
+%% ----------------------
+%% | Block-Definitionen |
+%% ----------------------
+
+% Content environment for structuring. Basically a headline followed by text
+\newenvironment<>{contentblock}[1]{\begingroup%
+ \setbeamertemplate{blocks}[default]
+ \setbeamercolor{block body}{fg=black,bg=}%
+ \setbeamercolor{block title}{fg=black,bg=}%
+ \setbeamerfont*{block title}{family=\sffamily,series=\bfseries,size=\large}
+ \begin{block}#2{#1}%
+ }{\end{block}%
+\endgroup}
+
+
+\newenvironment<>{greenblock}[1]{\begingroup%
+ \setbeamercolor{block body}{fg=black,bg=kit-green15}%
+ \setbeamercolor{block title}{fg=white,bg=kit-green100}%
+ \begin{block}#2{#1}%
+ }{\end{block}
+\endgroup}
+
+\newenvironment<>{blueblock}[1]{\begingroup%
+ \setbeamercolor{block body}{fg=black,bg=kit-blue15}%
+ \setbeamercolor{block title}{fg=white,bg=kit-blue100}%
+ \setbeamercolor{itemize item}{fg=kit-blue100}
+ \begin{block}#2{#1}%
+ }{\end{block}
+\endgroup}
+
+\newenvironment<>{redblock}[1]{\begingroup%
+ \setbeamercolor{block body}{fg=black,bg=kit-red15}%
+ \setbeamercolor{block title}{fg=white,bg=kit-red100}%
+ \setbeamercolor{itemize item}{fg=kit-red100}%
+ \begin{block}#2{#1}%
+ }{\end{block}%
+\endgroup}
+
+\newenvironment<>{brownblock}[1]{\begingroup%
+ \setbeamercolor{block body}{fg=black,bg=kit-brown15}%
+ \setbeamercolor{block title}{fg=white,bg=kit-brown100}%
+ \setbeamercolor{itemize item}{fg=kit-brown100}%
+ \begin{block}#2{#1}%
+ }{\end{block}%
+\endgroup}
+
+\newenvironment<>{purpleblock}[1]{\begingroup%
+ \setbeamercolor{block body}{fg=black,bg=kit-purple15}%
+ \setbeamercolor{block title}{fg=white,bg=kit-purple100}%
+ \setbeamercolor{itemize item}{fg=kit-purple100}%
+ \begin{block}#2{#1}%
+ }{\end{block}%
+\endgroup}
+
+\newenvironment<>{grayblock}[1]{\begingroup%
+ \setbeamercolor{block body}{fg=black,bg=kit-gray15}%
+ \setbeamercolor{block title}{fg=white,bg=kit-gray70}%
+ \setbeamercolor{itemize item}{fg=kit-gray70}%
+ \begin{block}#2{#1}%
+ }{\end{block}%
+\endgroup}
+
+\newenvironment<>{yellowblock}[1]{\begingroup%
+ \setbeamercolor{block body}{fg=black,bg=kit-yellow30}%
+ \setbeamercolor{block title}{fg=black,bg=kit-yellow100}%
+ \setbeamercolor{itemize item}{fg=kit-yellow100}%
+ \begin{block}#2{#1}%
+ }{\end{block}%
+\endgroup}
+
+\newenvironment<>{lightgreenblock}[1]{\begingroup%
+ \setbeamercolor{block body}{fg=black,bg=kit-lightgreen15}%
+ \setbeamercolor{block title}{fg=white,bg=kit-lightgreen100}%
+ \setbeamercolor{itemize item}{fg=kit-lightgreen100}%
+ \begin{block}#2{#1}%
+ }{\end{block}%
+\endgroup}
+
+\newenvironment<>{orangeblock}[1]{\begingroup%
+ \setbeamercolor{block body}{fg=black,bg=kit-orange15}%
+ \setbeamercolor{block title}{fg=white,bg=kit-orange100}%
+ \setbeamercolor{itemize item}{fg=kit-orange100}%
+ \begin{block}#2{#1}%
+ }{\end{block}%
+\endgroup}
+
+\newenvironment<>{cyanblock}[1]{\begingroup%
+ \setbeamercolor{block body}{fg=black,bg=kit-cyan15}%
+ \setbeamercolor{block title}{fg=white,bg=kit-cyan100}%
+ \setbeamercolor{itemize item}{fg=kit-cyan100}%
+ \begin{block}#2{#1}%
+ }{\end{block}%
+\endgroup}
+
+\newenvironment<>{maroonblock}[1]{\begingroup%
+\setbeamercolor{block body}{fg=black,bg=Maroon!15}%
+\setbeamercolor{block title}{fg=white,bg=Maroon}%
+ \setbeamercolor{itemize item}{fg=Maroon}%
+\begin{block}#2{#1}%
+}{\end{block}%
+\endgroup}
+%% ------------------------------
+%% | /Block-Definitionen |
+%% ------------------------------
+
+%% use this for setting the total page number
+\newcommand{\beginbackup}{
+ \newcounter{framenumbervorappendix}
+ \setcounter{framenumbervorappendix}{\value{framenumber}}
+}
+\newcommand{\backupend}{
+ \addtocounter{framenumbervorappendix}{-\value{framenumber}}
+ \addtocounter{framenumber}{\value{framenumbervorappendix}}
+}
diff --git a/11-entwurfsheft-kolloquium/slides/apiExtension.tex b/11-entwurfsheft-kolloquium/slides/apiExtension.tex
new file mode 100644
index 0000000..df1c027
--- /dev/null
+++ b/11-entwurfsheft-kolloquium/slides/apiExtension.tex
@@ -0,0 +1,39 @@
+\begin{frame}{API Erweiterung}
+
+ \begin{columns}[t]
+ \begin{column}{.3\textwidth}
+ \centering{\fontsize{30pt}{36pt}\selectfont\faLock}
+ \vspace{.2cm}
+ \begin{orangeblock}{Authentication}
+ \begin{itemize}
+ \item Registrierung
+ \item Passwort ändern
+ \item Passwort vergessen
+ \item Passwort zurücksetzen
+ \item Account löschen
+ \end{itemize}
+ \end{orangeblock}
+ \end{column}
+ \begin{column}{.3\textwidth}
+ \centering{\fontsize{30pt}{36pt}\selectfont\faDownload}
+ \vspace{.2cm}
+ \begin{greenblock}{Subscriptions}
+ \begin{itemize}
+ \item Abrufen der Informationen aller Abonnements
+ \end{itemize}
+ \end{greenblock}
+ \end{column}
+ \begin{column}{.3\textwidth}
+ \centering{\fontsize{30pt}{36pt}\selectfont\faSpinner}
+ \vspace{.2cm}
+ \begin{blueblock}{Episode Actions}
+ \begin{itemize}
+ \item Episode Actions hochladen
+ \item Episode Actions abrufen
+ \end{itemize}
+ \end{blueblock}
+ \end{column}
+ \end{columns}
+
+\end{frame}
+
diff --git a/11-entwurfsheft-kolloquium/slides/architecture.tex b/11-entwurfsheft-kolloquium/slides/architecture.tex
new file mode 100644
index 0000000..edd9f1b
--- /dev/null
+++ b/11-entwurfsheft-kolloquium/slides/architecture.tex
@@ -0,0 +1,7 @@
+\begin{frame}{Architektur}
+
+ \begin{figure}[h]
+ \includegraphics[width=0.73\textwidth]{assets/diagrams/backendComponentDiagram}
+ \end{figure}
+
+\end{frame} \ No newline at end of file
diff --git a/11-entwurfsheft-kolloquium/slides/changes.tex b/11-entwurfsheft-kolloquium/slides/changes.tex
new file mode 100644
index 0000000..b3ba6de
--- /dev/null
+++ b/11-entwurfsheft-kolloquium/slides/changes.tex
@@ -0,0 +1,22 @@
+\begin{frame}[t]{Änderungen Pflichtenheft}
+
+ \begin{block}{Neue Kriterien}
+ \begin{itemize}
+ \item \textlangle RS11\textrangle \, Cooldown Fetch-Vorgang
+ \item \textlangle RC13\textrangle \, Sprache von Browserinformationen
+ \end{itemize}
+ \end{block}
+
+ \begin{blueblock}{Abgeänderte Kriterien}
+ \begin{itemize}
+ \item \textlangle RS10\textrangle \, Sessions mit JSON Web Token
+ \end{itemize}
+ \end{blueblock}
+
+ \begin{maroonblock}{Entfernte Kriterien}
+ \begin{itemize}
+ \item \textlangle RC5\textrangle \, Frontend kompatibel mit beliebigen Gpodder APIs
+ \end{itemize}
+ \end{maroonblock}
+
+\end{frame}
diff --git a/11-entwurfsheft-kolloquium/slides/classdiagram.tex b/11-entwurfsheft-kolloquium/slides/classdiagram.tex
new file mode 100644
index 0000000..aeecec0
--- /dev/null
+++ b/11-entwurfsheft-kolloquium/slides/classdiagram.tex
@@ -0,0 +1,57 @@
+\begin{frame}[t]{Überblick: Klassendiagramm}
+ \centering
+ \includegraphics[width=\textwidth]{assets/diagrams/classdiagram}
+ \vspace{.3cm}
+ \begin{greenblock}{Abhängigkeiten}
+ \vspace{-.2cm}
+ \begin{columns}
+ \begin{column}{.4\textwidth}
+ \begin{itemize}
+ \item Spring Web
+ \item Spring Security
+ \item Spring Mail Sender
+ \end{itemize}
+ \end{column}
+ \begin{column}{.4\textwidth}
+ \begin{itemize}
+ \item Spring Data JPA
+ \item Lombok
+ \item Rome (RSS parsing/fetching)
+ \end{itemize}
+ \end{column}
+ \end{columns}
+
+ \end{greenblock}
+\end{frame}
+
+% sub
+% episode
+% auth
+% model
+% util
+
+\begin{frame}[t]{Subscriptions-API}
+ \centering
+ \includegraphics[width=\textwidth]{assets/diagrams/classdiagram-subscriptions}
+\end{frame}
+
+\begin{frame}[t]{EpisodeActions-API}
+ \centering
+ \includegraphics[width=\textwidth]{assets/diagrams/classdiagram-episode-actions}
+\end{frame}
+
+\begin{frame}[t]{Authentication-API}
+ \centering
+ \includegraphics[width=.73\textwidth]{assets/diagrams/classdiagram-authentication}
+\end{frame}
+
+\begin{frame}[t]{Model-Paket}
+ \centering
+ \includegraphics[width=\textwidth]{assets/diagrams/classdiagram-model}
+\end{frame}
+
+\begin{frame}[t]{Util-Paket}
+ \centering
+ \includegraphics[width=\textwidth]{assets/diagrams/classdiagram-util}
+\end{frame}
+
diff --git a/11-entwurfsheft-kolloquium/slides/frontend.tex b/11-entwurfsheft-kolloquium/slides/frontend.tex
new file mode 100644
index 0000000..c49d94f
--- /dev/null
+++ b/11-entwurfsheft-kolloquium/slides/frontend.tex
@@ -0,0 +1,21 @@
+\begin{frame}{Weboberfläche}
+ \begin{minipage}{.77\textwidth}
+ \centering
+ \includegraphics[width=\textwidth]{assets/diagrams/componentdiagram}
+ \end{minipage}
+ \hspace{.3cm}
+ \begin{minipage}{.18\textwidth}
+ \begin{greenblock}{Abhängigkeiten}
+ \begin{itemize}
+ \item vite
+ \item vue
+ \item vue-router
+ \item Pinia
+ \item bootstrap
+ \item fontawesome
+ \item vue-i18n
+ \end{itemize}
+ \end{greenblock}
+ \end{minipage}
+\end{frame}
+
diff --git a/11-entwurfsheft-kolloquium/slides/pattern.tex b/11-entwurfsheft-kolloquium/slides/pattern.tex
new file mode 100644
index 0000000..1f6366e
--- /dev/null
+++ b/11-entwurfsheft-kolloquium/slides/pattern.tex
@@ -0,0 +1,26 @@
+\begin{frame}{Entwurfsmuster}
+ \begin{columns}[t]
+ \column{.5\textwidth}
+ \centering{\fontsize{30pt}{36pt}\selectfont\faSyringe}
+ \begin{greenblock}{Dependency Injection}
+ \begin{itemize}
+ \item Bestimmt Abhängigkeiten in Klassen
+ \item Speichert Instanzen dieser Abhängigkeiten an zentralem Ort
+ % Wichtig für Interface Abhängigkeiten:
+ \item Instanz in Konfiguration festlegbar
+ \item Setzt Instanzen während der Laufzeit an benötigter Stelle ein
+ \end{itemize}
+ \end{greenblock}
+ \column{.5\textwidth}
+ \centering{\fontsize{30pt}{36pt}\selectfont\faDatabase}
+ \begin{blueblock}{Data Access Object (DAO)}
+ \color{kit-blue100}
+ \begin{itemize}
+ \item DAO-Interface als Schnittstelle zwischen Geschäftslogik und Datenzugriffslogik
+ \item DAO-Implementierungen als Varianten der Datenzugriffslogik (MariaDB, MySQL, etc.)
+ \item[$\Rightarrow$] Austauschbare Implementierungen
+ \end{itemize}
+ \end{blueblock}
+ \end{columns}
+\end{frame}
+
diff --git a/11-entwurfsheft-kolloquium/slides/sequence.tex b/11-entwurfsheft-kolloquium/slides/sequence.tex
new file mode 100644
index 0000000..393e502
--- /dev/null
+++ b/11-entwurfsheft-kolloquium/slides/sequence.tex
@@ -0,0 +1,7 @@
+\begin{frame}{Abläufe: Abrufen aller Abonnements}
+
+ \begin{figure}[h]
+ \includegraphics[width=0.83\textwidth]{assets/diagrams/sequencediagram-getSubscriptions}
+ \end{figure}
+
+\end{frame} \ No newline at end of file
diff --git a/20-implementierungsheft/.gitignore b/20-implementierungsheft/.gitignore
new file mode 100644
index 0000000..b1b3dda
--- /dev/null
+++ b/20-implementierungsheft/.gitignore
@@ -0,0 +1,305 @@
+## Core latex/pdflatex auxiliary files:
+*.aux
+*.lof
+*.log
+*.lot
+*.fls
+*.out
+*.toc
+*.fmt
+*.fot
+*.cb
+*.cb2
+.*.lb
+
+## Intermediate documents:
+*.dvi
+*.xdv
+*-converted-to.*
+# these rules might exclude image files for figures etc.
+# *.ps
+# *.eps
+*.pdf
+!assets/*.pdf
+
+## Generated if empty string is given at "Please type another file name for output:"
+.pdf
+
+## Bibliography auxiliary files (bibtex/biblatex/biber):
+*.bbl
+*.bcf
+*.blg
+*-blx.aux
+*-blx.bib
+*.run.xml
+
+## Build tool auxiliary files:
+*.fdb_latexmk
+*.synctex
+*.synctex(busy)
+*.synctex.gz
+*.synctex.gz(busy)
+*.pdfsync
+
+## Build tool directories for auxiliary files
+# latexrun
+latex.out/
+
+## Auxiliary and intermediate files from other packages:
+# algorithms
+*.alg
+*.loa
+
+# achemso
+acs-*.bib
+
+# amsthm
+*.thm
+
+# beamer
+*.nav
+*.pre
+*.snm
+*.vrb
+
+# changes
+*.soc
+
+# comment
+*.cut
+
+# cprotect
+*.cpt
+
+# elsarticle (documentclass of Elsevier journals)
+*.spl
+
+# endnotes
+*.ent
+
+# fixme
+*.lox
+
+# feynmf/feynmp
+*.mf
+*.mp
+*.t[1-9]
+*.t[1-9][0-9]
+*.tfm
+
+#(r)(e)ledmac/(r)(e)ledpar
+*.end
+*.?end
+*.[1-9]
+*.[1-9][0-9]
+*.[1-9][0-9][0-9]
+*.[1-9]R
+*.[1-9][0-9]R
+*.[1-9][0-9][0-9]R
+*.eledsec[1-9]
+*.eledsec[1-9]R
+*.eledsec[1-9][0-9]
+*.eledsec[1-9][0-9]R
+*.eledsec[1-9][0-9][0-9]
+*.eledsec[1-9][0-9][0-9]R
+
+# glossaries
+*.acn
+*.acr
+*.glg
+*.glo
+*.gls
+*.glsdefs
+*.lzo
+*.lzs
+*.slg
+*.slo
+*.sls
+
+# uncomment this for glossaries-extra (will ignore makeindex's style files!)
+*.ist
+
+# gnuplot
+*.gnuplot
+*.table
+
+# gnuplottex
+*-gnuplottex-*
+
+# gregoriotex
+*.gaux
+*.glog
+*.gtex
+
+# htlatex
+*.4ct
+*.4tc
+*.idv
+*.lg
+*.trc
+*.xref
+
+# hyperref
+*.brf
+
+# knitr
+*-concordance.tex
+# TODO Uncomment the next line if you use knitr and want to ignore its generated tikz files
+# *.tikz
+*-tikzDictionary
+
+# listings
+*.lol
+
+# luatexja-ruby
+*.ltjruby
+
+# makeidx
+*.idx
+*.ilg
+*.ind
+
+# minitoc
+*.maf
+*.mlf
+*.mlt
+*.mtc[0-9]*
+*.slf[0-9]*
+*.slt[0-9]*
+*.stc[0-9]*
+
+# minted
+_minted*
+*.pyg
+
+# morewrites
+*.mw
+
+# newpax
+*.newpax
+
+# nomencl
+*.nlg
+*.nlo
+*.nls
+
+# pax
+*.pax
+
+# pdfpcnotes
+*.pdfpc
+
+# sagetex
+*.sagetex.sage
+*.sagetex.py
+*.sagetex.scmd
+
+# scrwfile
+*.wrt
+
+# svg
+svg-inkscape/
+
+# sympy
+*.sout
+*.sympy
+sympy-plots-for-*.tex/
+
+# pdfcomment
+*.upa
+*.upb
+
+# pythontex
+*.pytxcode
+pythontex-files-*/
+
+# tcolorbox
+*.listing
+
+# thmtools
+*.loe
+
+# TikZ & PGF
+*.dpth
+*.md5
+*.auxlock
+
+# titletoc
+*.ptc
+
+# todonotes
+*.tdo
+
+# vhistory
+*.hst
+*.ver
+
+# easy-todo
+*.lod
+
+# xcolor
+*.xcp
+
+# xmpincl
+*.xmpi
+
+# xindy
+*.xdy
+
+# xypic precompiled matrices and outlines
+*.xyc
+*.xyd
+
+# endfloat
+*.ttt
+*.fff
+
+# Latexian
+TSWLatexianTemp*
+
+## Editors:
+# WinEdt
+*.bak
+*.sav
+
+# Texpad
+.texpadtmp
+
+# LyX
+*.lyx~
+
+# Kile
+*.backup
+
+# gummi
+.*.swp
+
+# KBibTeX
+*~[0-9]*
+
+# TeXnicCenter
+*.tps
+
+# auto folder when using emacs and auctex
+./auto/*
+*.el
+
+# expex forward references with \gathertags
+*-tags.tex
+
+# standalone packages
+*.sta
+
+# Makeindex log files
+*.lpz
+
+# xwatermark package
+*.xwm
+
+# REVTeX puts footnotes in the bibliography by default, unless the nofootinbib
+# option is specified. Footnotes are the stored in a file with suffix Notes.bib.
+# Uncomment the next line to have this generated file ignored.
+#*Notes.bib
+
+# Gannt Diagramm als EPS ignorieren
+assets/gantt.eps \ No newline at end of file
diff --git a/20-implementierungsheft/.gitlab-ci.yml b/20-implementierungsheft/.gitlab-ci.yml
new file mode 100644
index 0000000..27d0617
--- /dev/null
+++ b/20-implementierungsheft/.gitlab-ci.yml
@@ -0,0 +1,36 @@
+plantuml:
+ stage: .pre
+ image:
+ name: plantuml/plantuml
+ entrypoint: [""]
+ script:
+ - java -jar plantuml.jar -tpdf assets/diagrams/*.puml
+ artifacts:
+ paths:
+ - assets
+
+tex:
+ stage: build
+ image: texlive/texlive
+ script:
+ - mkdir public
+ - make tex
+ - mv *.pdf public
+ artifacts:
+ paths:
+ - public
+ dependencies:
+ - plantuml
+
+pages:
+ stage: deploy
+ script:
+ - echo Hello, World!
+ artifacts:
+ paths:
+ - public
+ rules:
+ - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
+ dependencies:
+ - tex
+
diff --git a/20-implementierungsheft/.latexmkrc b/20-implementierungsheft/.latexmkrc
new file mode 100644
index 0000000..bec2b38
--- /dev/null
+++ b/20-implementierungsheft/.latexmkrc
@@ -0,0 +1,7 @@
+# https://tex.stackexchange.com/questions/1226/how-to-make-latexmk-use-makeglossaries
+add_cus_dep('glo', 'gls', 0, 'makeglo2gls');
+add_cus_dep('acn', 'acr', 0, 'makeglo2gls');
+sub makeglo2gls {
+ system("makeglossaries $_[0]");
+}
+
diff --git a/20-implementierungsheft/Makefile b/20-implementierungsheft/Makefile
new file mode 100644
index 0000000..335b123
--- /dev/null
+++ b/20-implementierungsheft/Makefile
@@ -0,0 +1,18 @@
+MAIN = implementierungsheft
+FLAGS = -pdf
+
+all: clean compile
+compile: diagram tex
+clean: clean-diagram clean-tex
+
+dev:
+ latexmk $(FLAGS) -pvc $(MAIN)
+tex:
+ latexmk $(FLAGS) $(MAIN)
+diagram:
+ java -jar plantuml.jar -tpdf assets/diagrams/*.puml
+clean-tex:
+ latexmk -C
+clean-diagram:
+ find assets/diagrams -type f -not -name '*.puml' -delete
+
diff --git a/20-implementierungsheft/README.md b/20-implementierungsheft/README.md
new file mode 100644
index 0000000..2c08f29
--- /dev/null
+++ b/20-implementierungsheft/README.md
@@ -0,0 +1,31 @@
+# Entwurfsheft
+
+> Systemdesign und -spezifikation
+
+## Diagramme
+
+Installiere [PlantUML](https://plantuml.com/starting) (oder über einen Paketmanager).
+
+Arbeiten an Diagrammen mit Echtzeit-Vorschau (Anzeige wird beim Speichern der
+puml-Datei aktualisiert):
+```sh
+java -jar plantuml.jar -gui assets/classdiagram.puml
+
+# bzw (wenn zu PATH hinzugefügt oder Linux)
+plantuml -gui assets/classdiagram.puml
+```
+
+Bauen der Diagramme:
+```sh
+java -jar plantuml.jar -teps assets/*.puml
+
+# bzw (wenn zu PATH hinzugefügt oder Linux)
+plantuml -teps assets/*.puml
+
+# bzw über Makefile (Linux)
+make diagram
+
+# oder zum Erstellen von Diagrammen und LaTeX:
+make
+```
+
diff --git a/20-implementierungsheft/assets/.gitignore b/20-implementierungsheft/assets/.gitignore
new file mode 100644
index 0000000..16252a4
--- /dev/null
+++ b/20-implementierungsheft/assets/.gitignore
@@ -0,0 +1,3 @@
+diagrams/*
+!diagrams/*.puml
+
diff --git a/20-implementierungsheft/assets/KIT_Deckblatt.pdf b/20-implementierungsheft/assets/KIT_Deckblatt.pdf
new file mode 100644
index 0000000..7de8ed4
--- /dev/null
+++ b/20-implementierungsheft/assets/KIT_Deckblatt.pdf
Binary files differ
diff --git a/20-implementierungsheft/assets/diagrams/backendComponentDiagram.puml b/20-implementierungsheft/assets/diagrams/backendComponentDiagram.puml
new file mode 100644
index 0000000..806522c
--- /dev/null
+++ b/20-implementierungsheft/assets/diagrams/backendComponentDiagram.puml
@@ -0,0 +1,61 @@
+@startuml
+' skinparam linetype ortho
+
+'#########################################################################
+'SubscriptionsAPI
+component SubscriptionsAPI {
+
+ component SubscriptionService
+ component SubscriptionController
+ component SubscriptionDataAccessLayer
+
+ portout "Webserver" as wSub
+ portin "Database" as dSub
+ }
+
+dSub --0)- SubscriptionDataAccessLayer
+SubscriptionDataAccessLayer --0)- SubscriptionService
+SubscriptionService --0)- SubscriptionController
+SubscriptionController --0)- wSub
+
+'#########################################################################
+
+
+'#########################################################################
+'EpisodeActionsAPI
+
+component EpisodeActionsAPI {
+ component EpisodeActionService
+ component EpisodeActionController
+ component EpisodeActionDataAccessLayer
+
+ portout "Webserver" as wEpisode
+ portin "Database" as dEpisode
+}
+
+dEpisode --0)- EpisodeActionDataAccessLayer
+EpisodeActionController --0)- wEpisode
+EpisodeActionDataAccessLayer --0)- EpisodeActionService
+EpisodeActionService --0)- EpisodeActionController
+
+'#########################################################################
+
+
+'#########################################################################
+'AuthenticationAPI
+
+component AuthenticationAPI {
+ component AuthenticationService
+ component AuthenticationController
+ component AuthenticationDataAccessLayer
+
+ portout "Webserver" as wAuth
+ portin "Database" as dAuth
+}
+
+dAuth --0)- AuthenticationDataAccessLayer
+AuthenticationController --0)- wAuth
+AuthenticationDataAccessLayer --0)- AuthenticationService
+AuthenticationService --0)- AuthenticationController
+
+@enduml
diff --git a/20-implementierungsheft/assets/diagrams/class_after.puml b/20-implementierungsheft/assets/diagrams/class_after.puml
new file mode 100644
index 0000000..0a8f475
--- /dev/null
+++ b/20-implementierungsheft/assets/diagrams/class_after.puml
@@ -0,0 +1,574 @@
+@startuml
+' skinparam linetype ortho
+' skinparam groupInheritance 2
+allowmixing
+
+package authentication_api <<Frame>> {
+
+ package controller as auth.controller <<Frame>> {
+
+ class AuthenticationController <<@RestController>> {
+ + <<create>> AuthenticationController(AuthenticationService, EMailConfigProperties):
+ + logout(String, HttpServletResponse): HttpStatus
+ + registerUser(UserInfoRequest): HttpStatus
+ + forgotPassword(String): HttpStatus
+ + getDeviceList(String, HttpServletResponse): ResponseEntity<List<DeviceWrapper>>
+ + login(String, HttpServletResponse): HttpStatus
+ + deleteUser(String, PasswordRequest): HttpStatus
+ + changePassword(String, ChangePasswordRequest): HttpStatus
+ + verifyRegistration(String, String, HttpServletResponse): HttpStatus
+ + resetPassword(String, String, PasswordRequest): HttpStatus
+ }
+
+ entity AuthenticationResponse << record >> {
+ + <<create>> AuthenticationResponse(String):
+ + token(): String
+ }
+
+ entity ChangePasswordRequest << record >> {
+ + <<create>> ChangePasswordRequest(String, String):
+ + oldPassword(): String
+ + newPassword(): String
+ }
+
+ entity DeviceWrapper << record >> {
+ + <<create>> DeviceWrapper():
+ + <<create>> DeviceWrapper(String, String, String, int):
+ + id(): String
+ + caption(): String
+ + type(): String
+ + subscriptions(): int
+ }
+
+ entity ForgotPasswordRequest << record >> {
+ + <<create>> ForgotPasswordRequest(String):
+ + email(): String
+ }
+
+ entity PasswordRequest << record >> {
+ + <<create>> PasswordRequest(String):
+ + password(): String
+ }
+
+ entity UserInfoRequest << record >> {
+ + <<create>> UserInfoRequest(String, String, String):
+ + password(): String
+ + email(): String
+ + username(): String
+ }
+ }
+
+ package data_access as auth.dao <<Frame>> {
+
+ interface AuthenticationDao <<@Repository>> {
+ + findByEmail(String): Optional<User>
+ + deleteAllByEnabledFalseAndCreatedAtLessThan(long): void
+ + existsByUsername(String): boolean
+ + findByUsername(String): Optional<User>
+ }
+ }
+
+ package service as auth.service <<Frame>> {
+
+ class AuthenticationService <<@Service>> {
+ + <<create>> AuthenticationService(AuthenticationDao, PasswordEncoder, JwtService, EMailServiceImpl, EncryptionService, InputCheckService):
+ + verifyRegistration(String, String): HttpStatus
+ + logout(String, HttpServletResponse): HttpStatus
+ + changePassword(String, ChangePasswordRequest): HttpStatus
+ + registerUser(UserInfoRequest): HttpStatus
+ + deleteUser(String, PasswordRequest): HttpStatus
+ + forgotPassword(String): HttpStatus
+ + resetPassword(String, String, PasswordRequest): HttpStatus
+ + deleteInvalidUsersOlderThan(long): void
+ + login(String, HttpServletResponse): HttpStatus
+ }
+
+ class EMailServiceImpl <<@Service>> {
+ + <<create>> EMailServiceImpl(JavaMailSender, EMailConfigProperties, JwtService):
+ - substitutePlaceholders(String, UserDetails, String): String
+ + sendVerification(String, UserDetails): void
+ + sendPasswordReset(String, UserDetails): void
+ - generatePasswordResetURLString(UserDetails): String
+ - sendMail(String, String, String): void
+ - generateVerificationURLString(UserDetails): String
+ }
+
+ class EncryptionService <<@Service>> {
+ + <<create>> EncryptionService(SecurityConfigProperties):
+ + saltAndHashEmail(String): String
+ - getSalt(): byte[]
+ }
+
+ class InputCheckService <<@Service>> {
+ + <<create>> InputCheckService():
+ + validateEmail(String): boolean
+ + validateUsername(String): boolean
+ + validatePassword(String): boolean
+ }
+
+ class ResourceReader {
+ + <<create>> ResourceReader():
+ + readFileToString(String): String
+ }
+ }
+}
+
+package config <<Frame>> {
+
+ class ApplicationConfig <<@Configuration>> {
+ + <<create>> ApplicationConfig(AuthenticationDao):
+ + userDetailsService(): UserDetailsService
+ + addInterceptors(InterceptorRegistry): void
+ + authenticationManager(AuthenticationConfiguration): AuthenticationManager
+ + passwordEncoder(): PasswordEncoder
+ + corsConfigurer(): WebMvcConfigurer
+ + authenticationProvider(): AuthenticationProvider
+ }
+
+ class AuthenticationValidatorInterceptor {
+ + <<create>> AuthenticationValidatorInterceptor():
+ - extractUsernamePathVariable(HttpServletRequest): String?
+ + preHandle(HttpServletRequest, HttpServletResponse, Object): boolean
+ }
+
+ entity EMailConfigProperties << record >> {
+ + <<create>> EMailConfigProperties(String, String, String):
+ + resetUrlPath(): String
+ + verificationUrl(): String
+ + dashboardBaseUrl(): String
+ }
+
+ class JwtAuthenticationFilter <<@Component>> {
+ + <<create>> JwtAuthenticationFilter(JwtService, UserDetailsService):
+ # doFilterInternal(HttpServletRequest, HttpServletResponse, FilterChain): void
+ - authenticateIfValid(Cookie, HttpServletRequest): void
+ }
+
+ class JwtService <<@Service>> {
+ + <<create>> JwtService(SecurityConfigProperties):
+ + generateUrlTokenString(UserDetails): String
+ + isTokenValid(String, UserDetails): boolean
+ + generateAccessTokenString(UserDetails): String
+ + extractUsername(String): String
+ + extractClaim(String, Function<Claims, T>): T
+ - isTokenExpired(String): boolean
+ + generateTokenString(Map<String, Object>, UserDetails, long): String
+ - extractExpiration(String): Date
+ - extractAllClaims(String): Claims
+ - getSigningKey(): Key
+ }
+
+ class SecurityConfig <<@Configuration>> {
+ + <<create>> SecurityConfig(JwtAuthenticationFilter, AuthenticationProvider):
+ ~ corsConfigurationSource(): CorsConfigurationSource
+ + securityFilterChain(HttpSecurity): SecurityFilterChain
+ }
+
+ entity SecurityConfigProperties << record >> {
+ + <<create>> SecurityConfigProperties(String, String):
+ + jwtSigningKey(): String
+ + emailSigningKey(): String
+ }
+}
+
+package episode_actions_api <<Frame>> {
+
+ package controller as episode.controller <<Frame>> {
+
+ class EpisodeActionController <<@RestController>> {
+ + <<create>> EpisodeActionController(EpisodeActionService):
+ + addEpisodeActions(String, List<EpisodeActionPost>): ResponseEntity<UpdateURLsWrapper>
+ + getEpisodeActionsOfPodcast(String, String): ResponseEntity<EpisodeActionGetResponse>
+ + getEpisodeActions(String): ResponseEntity<EpisodeActionGetResponse>
+ + getEpisodeActionsSince(String, long): ResponseEntity<EpisodeActionGetResponse>
+ + getEpisodeActionsOfPodcastSince(String, String, long): ResponseEntity<EpisodeActionGetResponse>
+ }
+
+ class EpisodeActionGetResponse {
+ + <<create>> EpisodeActionGetResponse(List<EpisodeActionPost>):
+ + getTimestamp(): long
+ + getActions(): List<EpisodeActionPost>
+ }
+
+ class EpisodeActionPost {
+ + <<create>> EpisodeActionPost():
+ + <<create>> EpisodeActionPost(String, String, String, String, int, EpisodeAction):
+ + equals(Object): boolean
+ + hashCode(): int
+ + builder(): EpisodeActionPostBuilder
+ + getPodcastURL(): String
+ + getEpisodeURL(): String
+ + getTitle(): String
+ + getGuid(): String
+ + setGuid(String): void
+ + setEpisodeAction(EpisodeAction): void
+ + setTotal(int): void
+ + getTotal(): int
+ + setTitle(String): void
+ # canEqual(Object): boolean
+ + getEpisodeAction(): EpisodeAction
+ + toString(): String
+ + setPodcastURL(String): void
+ + setEpisodeURL(String): void
+ }
+ }
+
+ package data_access as episode.dao <<Frame>> {
+
+ interface EpisodeActionDao <<@Repository>> {
+ + findByUserUsernameAndEpisodeSubscriptionUrl(String, String): List<EpisodeAction>
+ + delete(EpisodeAction): void
+ + findByUserUsernameAndTimestampGreaterThanEqual(String, LocalDateTime): List<EpisodeAction>
+ + findByUserUsername(String): List<EpisodeAction>
+ + findByUserAndEpisodeUrlAndAction(User, String, Action): Optional<EpisodeAction>
+ + findByUserUsernameAndTimestampGreaterThanEqualAndEpisodeSubscriptionUrl(String, LocalDateTime, String): List<EpisodeAction>
+ + deleteByUserUsernameAndEpisodeSubscriptionUrl(String, String): void
+ + existsByUserAndEpisodeUrlAndAction(User, String, Action): boolean
+ }
+
+ interface EpisodeDao <<@Repository>> {
+ + existsByGuid(String): boolean
+ + findByUrl(String): Optional<Episode>
+ + existsByUrl(String): boolean
+ + findByGuid(String): Optional<Episode>
+ }
+ }
+
+ package service as episode.service <<Frame>> {
+
+ class EpisodeActionService <<@Service>> {
+ + <<create>> EpisodeActionService(EpisodeActionDao, EpisodeDao, AuthenticationDao, SubscriptionDao, SubscriptionActionDao, RSSParser):
+ - episodeActionPostsToEpisodeActions(User, List<EpisodeActionPost>): List<EpisodeAction>
+ - createEpisode(EpisodeActionPost): Episode
+ + getEpisodeActionsOfPodcastSince(String, String, long): List<EpisodeActionPost>
+ - getEpisodeFromDatabase(EpisodeActionPost): Episode
+ - addEpisodeActionsToDatabase(User, List<EpisodeAction>): void
+ - addNewestEpisodeActionToDatabase(User, EpisodeAction): void
+ - episodeActionsToEpisodeActionPosts(List<EpisodeAction>): List<EpisodeActionPost>
+ - addEpisodeActionToDatabase(User, EpisodeAction): void
+ + getEpisodeActionsSince(String, long): List<EpisodeActionPost>
+ - episodeActionPostToEpisodeAction(User, EpisodeActionPost): EpisodeAction
+ + getEpisodeActions(String): List<EpisodeActionPost>
+ + getEpisodeActionsOfPodcast(String, String): List<EpisodeActionPost>
+ + addEpisodeActions(String, List<EpisodeActionPost>): void
+ }
+ }
+}
+
+package model <<Frame>> {
+
+ enum Action << enumeration >> {
+ + <<create>> Action():
+ + valueOf(String): Action
+ + getJsonProperty(): String
+ + values(): Action[]
+ }
+
+ class Episode <<@Entity>> {
+ + <<create>> Episode():
+ + <<create>> Episode(Long, String, String, String, int, Subscription, List<EpisodeAction>):
+ + getId(): Long
+ # canEqual(Object): boolean
+ + getGuid(): String
+ + setTitle(String): void
+ + builder(): EpisodeBuilder
+ + setTotal(int): void
+ + setGuid(String): void
+ + equals(Object): boolean
+ + setSubscription(Subscription): void
+ + getUrl(): String
+ + getTitle(): String
+ + toString(): String
+ + getTotal(): int
+ + setUrl(String): void
+ + setEpisodeActions(List<EpisodeAction>): void
+ + getSubscription(): Subscription
+ + getEpisodeActions(): List<EpisodeAction>
+ + setId(Long): void
+ + hashCode(): int
+ }
+
+ class EpisodeAction <<@Entity>> {
+ + <<create>> EpisodeAction(Long, User, Episode, LocalDateTime, Action, int, int):
+ + <<create>> EpisodeAction():
+ + getEpisode(): Episode
+ + setEpisode(Episode): void
+ + setPosition(int): void
+ # canEqual(Object): boolean
+ + setUser(User): void
+ + setStarted(int): void
+ + getId(): Long
+ + getUser(): User
+ + getTimestamp(): LocalDateTime
+ + getAction(): Action
+ + getStarted(): int
+ + hashCode(): int
+ + setTimestamp(LocalDateTime): void
+ + equals(Object): boolean
+ + getPosition(): int
+ + builder(): EpisodeActionBuilder
+ + setId(Long): void
+ + setAction(Action): void
+ + toString(): String
+ + toEpisodeActionPost(): EpisodeActionPost
+ }
+
+ enum Role << enumeration >> {
+ + <<create>> Role():
+ + valueOf(String): Role
+ + toString(): String
+ + values(): Role[]
+ }
+
+ class Subscription <<@Entity>> {
+ + <<create>> Subscription():
+ + <<create>> Subscription(Long, String, String, long, List<SubscriptionAction>, List<Episode>):
+ + setId(Long): void
+ + getId(): Long
+ + equals(Object): boolean
+ + getUrl(): String
+ + hashCode(): int
+ + builder(): SubscriptionBuilder
+ # canEqual(Object): boolean
+ + toString(): String
+ + getTitle(): String
+ + getTimestamp(): long
+ + setEpisodes(List<Episode>): void
+ + getSubscriptionActions(): List<SubscriptionAction>
+ + getEpisodes(): List<Episode>
+ + setSubscriptionActions(List<SubscriptionAction>): void
+ + setUrl(String): void
+ + setTitle(String): void
+ + setTimestamp(long): void
+ + addEpisode(Episode): void
+ }
+
+ class SubscriptionAction <<@Entity>> {
+ + <<create>> SubscriptionAction():
+ + <<create>> SubscriptionAction(int, User, long, Subscription, boolean):
+ + equals(Object): boolean
+ + getId(): int
+ + getUser(): User
+ + getTimestamp(): long
+ + getSubscription(): Subscription
+ + isAdded(): boolean
+ # canEqual(Object): boolean
+ + setId(int): void
+ + hashCode(): int
+ + setUser(User): void
+ + toString(): String
+ + builder(): SubscriptionActionBuilder
+ + setTimestamp(long): void
+ + setSubscription(Subscription): void
+ + setAdded(boolean): void
+ }
+
+ class User <<@Entity>> {
+ + <<create>> User(Long, String, String, String, boolean, long, Role, List<SubscriptionAction>, List<EpisodeAction>):
+ + <<create>> User():
+ + getId(): Long
+ + setCreatedAt(long): void
+ + getUsername(): String
+ + builder(): UserBuilder
+ + toString(): String
+ + getEmail(): String
+ + setPassword(String): void
+ + setSubscriptionActions(List<SubscriptionAction>): void
+ + equals(Object): boolean
+ + getPassword(): String
+ + setEmail(String): void
+ + setRole(Role): void
+ + isEnabled(): boolean
+ + setUsername(String): void
+ + getCreatedAt(): long
+ + getRole(): Role
+ + getSubscriptionActions(): List<SubscriptionAction>
+ # canEqual(Object): boolean
+ + hashCode(): int
+ + setEnabled(boolean): void
+ + setEpisodeActions(List<EpisodeAction>): void
+ + getEpisodeActions(): List<EpisodeAction>
+ + setId(Long): void
+ + getAuthorities(): Collection<GrantedAuthority>
+ + isCredentialsNonExpired(): boolean
+ + isAccountNonLocked(): boolean
+ + isAccountNonExpired(): boolean
+ }
+}
+
+package subscriptions_api <<Frame>> {
+
+ package controller as subscription.controller <<Frame>> {
+
+ class SubscriptionController <<@RestController>> {
+ + <<create>> SubscriptionController(SubscriptionService):
+ + applySubscriptionDelta(String, String, SubscriptionDelta): ResponseEntity<UpdateURLsWrapper>
+ + getSubscriptions(String, String, String): ResponseEntity<List<String>>
+ + getSubscriptionDelta(String, String, long): ResponseEntity<SubscriptionDelta>
+ + getTitles(String): ResponseEntity<List<SubscriptionTitles>>
+ + uploadSubscriptions(String, String, List<String>): ResponseEntity<String>
+ }
+
+ class SubscriptionDelta {
+ + <<create>> SubscriptionDelta(List<String>, List<String>):
+ + getTimestamp(): long
+ + getRemove(): List<String>
+ + getAdd(): List<String>
+ }
+
+ entity SubscriptionTitles << record >> {
+ + <<create>> SubscriptionTitles(Subscription, List<EpisodeActionPost>):
+ + episodes(): List<EpisodeActionPost>
+ + subscription(): Subscription
+ }
+ }
+
+ package data_access as subscription.dao <<Frame>> {
+
+ interface SubscriptionActionDao <<@Repository>> {
+ + findByUserUsernameAndAddedTrue(String): List<SubscriptionAction>
+ + existsByUserAndSubscription(User, Subscription): boolean
+ + findByUserAndSubscription(User, Subscription): Optional<SubscriptionAction>
+ + findByUserUsernameAndTimestampGreaterThanEqual(String, long): List<SubscriptionAction>
+ + findByUserUsernameAndAddedTrueAndTimestampGreaterThanEqual(String, long): List<SubscriptionAction>
+ }
+
+ interface SubscriptionDao <<@Repository>> {
+ + findByUrl(String): Optional<Subscription>
+ + existsByUrl(String): boolean
+ }
+ }
+
+ package service as subscription.service <<Frame>> {
+
+ class SubscriptionService <<@Service>> {
+ + <<create>> SubscriptionService(RSSParser, AuthenticationDao, SubscriptionDao, SubscriptionActionDao, EpisodeActionDao, EpisodeActionService):
+ + getTitles(String): List<SubscriptionTitles>
+ + getSubscriptions(String): List<String>
+ + applySubscriptionDelta(String, SubscriptionDelta): int
+ + getSubscriptionDelta(String, long): SubscriptionDelta
+ + uploadSubscriptions(String, List<String>): int
+ }
+ }
+}
+
+package util <<Frame>> {
+
+ class RSSParser <<@Component>> {
+ + <<create>> RSSParser(EpisodeDao, SubscriptionDao):
+ + validate(Subscription): void
+ - parseTimeToSeconds(String): int
+ - parseEpisode(SyndEntry, Subscription): Episode
+ - saveEpisodes(List<Episode>): void
+ - fetchSubscriptionFeed(Subscription): Map<String, Episode>?
+ - saveSubscription(Subscription): void
+ - deleteSubscription(Subscription): void
+ - getFetchedEpisodeForURL(String, Map<String, Episode>): Episode
+ - deleteEpisodes(List<Episode>): void
+ }
+
+ class Scheduler <<@Component>> {
+ + <<create>> Scheduler():
+ + clean(): void
+ }
+
+ class UpdateURLsWrapper {
+ + <<create>> UpdateURLsWrapper():
+ + getTimestamp(): long
+ + getUpdateURLs(): List<Pair<String, String>>
+ }
+}
+
+class ServerApplication <<@SpringBootApplication>> {
+ + <<create>> ServerApplication():
+ + main(String[]): void
+}
+
+database Datenbank
+Datenbank <-[hidden]d- subscriptions_api
+Datenbank <-[hidden]d- episode_actions_api
+Datenbank <-[hidden]d- authentication_api
+() SQL as SQLSub
+() SQL as SQLAuth
+() SQL as SQLEpisode
+
+Datenbank -- SQLSub
+Datenbank -- SQLAuth
+Datenbank -- SQLEpisode
+
+SubscriptionController ..o ServerApplication
+AuthenticationController ..o ServerApplication
+EpisodeActionController ..o ServerApplication
+
+ServerApplication --() HTTP
+
+SQLSub )-- SubscriptionActionDao: JPA
+SQLSub )-- SubscriptionDao: JPA
+SQLAuth )-- AuthenticationDao: JPA
+SQLEpisode )-- EpisodeActionDao: JPA
+SQLEpisode )-- EpisodeDao: JPA
+
+model .o Datenbank: ORM (User, SubscriptionAction, Subscription, EpisodeAction, Episode)
+' Datenbank o.. Subscription: ORM
+' Datenbank o.. SubscriptionAction: ORM
+' Datenbank o.. Episode: ORM
+' Datenbank o.. EpisodeAction: ORM
+' Datenbank o.. User: ORM
+
+ApplicationConfig "1" *-[#595959,plain]-> "authenticationDao\n1" AuthenticationDao
+ApplicationConfig -[#595959,dashed]-> AuthenticationValidatorInterceptor : "«create»"
+AuthenticationController "1" *-[#595959,plain]-> "authenticationService\n1" AuthenticationService
+AuthenticationController -[#595959,dashed]-> DeviceWrapper : "«create»"
+AuthenticationController "1" *-[#595959,plain]-> "eMailConfigProperties\n1" EMailConfigProperties
+AuthenticationService "1" *-[#595959,plain]-> "authenticationDao\n1" AuthenticationDao
+AuthenticationService "1" *-[#595959,plain]-> "eMailService\n1" EMailServiceImpl
+AuthenticationService "1" *-[#595959,plain]-> "encryptionService\n1" EncryptionService
+AuthenticationService "1" *-[#595959,plain]-> "inputCheckService\n1" InputCheckService
+AuthenticationService "1" *-[#595959,plain]-> "jwtService\n1" JwtService
+AuthenticationService "1" *-[#595959,plain]-> "DEFAULT_USER\n1" Role
+EMailServiceImpl "1" *-[#595959,plain]-> "eMailConfigProperties\n1" EMailConfigProperties
+EMailServiceImpl "1" *-[#595959,plain]-> "jwtService\n1" JwtService
+EncryptionService "1" *-[#595959,plain]-> "securityConfigProperties\n1" SecurityConfigProperties
+Episode "1" *-[#595959,plain]-> "episodeActions\n*" EpisodeAction
+Episode "1" *-[#595959,plain]-> "subscription\n1" Subscription
+EpisodeAction "1" *-[#595959,plain]-> "action\n1" Action
+EpisodeAction "1" *-[#595959,plain]-> "episode\n1" Episode
+EpisodeAction -[#595959,dashed]-> EpisodeActionPost : "«create»"
+EpisodeAction "1" *-[#595959,plain]-> "user\n1" User
+EpisodeActionController -[#595959,dashed]-> EpisodeActionGetResponse : "«create»"
+EpisodeActionController "1" *-[#595959,plain]-> "episodeActionService\n1" EpisodeActionService
+EpisodeActionController -[#595959,dashed]-> UpdateURLsWrapper : "«create»"
+EpisodeActionGetResponse "1" *-[#595959,plain]-> "actions\n*" EpisodeActionPost
+EpisodeActionPost "1" *-[#595959,plain]-> "episodeAction\n1" EpisodeAction
+EpisodeActionService "1" *-[#595959,plain]-> "authenticationDao\n1" AuthenticationDao
+EpisodeActionService "1" *-[#595959,plain]-> "episodeActionDao\n1" EpisodeActionDao
+EpisodeActionService "1" *-[#595959,plain]-> "episodeDao\n1" EpisodeDao
+EpisodeActionService "1" *-[#595959,plain]-> "rssParser\n1" RSSParser
+EpisodeActionService -[#595959,dashed]-> Subscription : "«create»"
+EpisodeActionService "1" *-[#595959,plain]-> "subscriptionActionDao\n1" SubscriptionActionDao
+EpisodeActionService "1" *-[#595959,plain]-> "subscriptionDao\n1" SubscriptionDao
+JwtAuthenticationFilter "1" *-[#595959,plain]-> "jwtService\n1" JwtService
+JwtService "1" *-[#595959,plain]-> "securityConfigProperties\n1" SecurityConfigProperties
+RSSParser "1" *-[#595959,plain]-> "episodeDao\n1" EpisodeDao
+RSSParser "1" *-[#595959,plain]-> "subscriptionDao\n1" SubscriptionDao
+Scheduler "1" *-[#595959,plain]-> "authenticationService\n1" AuthenticationService
+SecurityConfig "1" *-[#595959,plain]-> "jwtAuthFilter\n1" JwtAuthenticationFilter
+Subscription "1" *-[#595959,plain]-> "episodes\n*" Episode
+Subscription "1" *-[#595959,plain]-> "subscriptionActions\n*" SubscriptionAction
+SubscriptionAction "1" *-[#595959,plain]-> "subscription\n1" Subscription
+SubscriptionAction "1" *-[#595959,plain]-> "user\n1" User
+SubscriptionController "1" *-[#595959,plain]-> "subscriptionService\n1" SubscriptionService
+SubscriptionController -[#595959,dashed]-> UpdateURLsWrapper : "«create»"
+SubscriptionService "1" *-[#595959,plain]-> "authenticationDao\n1" AuthenticationDao
+SubscriptionService "1" *-[#595959,plain]-> "episodeActionDao\n1" EpisodeActionDao
+SubscriptionService "1" *-[#595959,plain]-> "episodeActionService\n1" EpisodeActionService
+SubscriptionService "1" *-[#595959,plain]-> "rssParser\n1" RSSParser
+SubscriptionService "1" *-[#595959,plain]-> "subscriptionActionDao\n1" SubscriptionActionDao
+SubscriptionService "1" *-[#595959,plain]-> "subscriptionDao\n1" SubscriptionDao
+SubscriptionService -[#595959,dashed]-> SubscriptionDelta : "«create»"
+SubscriptionService -[#595959,dashed]-> SubscriptionTitles : "«create»"
+SubscriptionTitles "1" *-[#595959,plain]-> "subscription\n1" Subscription
+User "1" *-[#595959,plain]-> "episodeActions\n*" EpisodeAction
+User "1" *-[#595959,plain]-> "role\n1" Role
+User "1" *-[#595959,plain]-> "subscriptionActions\n*" SubscriptionAction
+@enduml
diff --git a/20-implementierungsheft/assets/diagrams/classdiagram.puml b/20-implementierungsheft/assets/diagrams/classdiagram.puml
new file mode 100644
index 0000000..4b1970a
--- /dev/null
+++ b/20-implementierungsheft/assets/diagrams/classdiagram.puml
@@ -0,0 +1,463 @@
+@startuml
+' skinparam linetype ortho
+' skinparam groupInheritance 2
+allowmixing
+
+package subscriptionsAPI <<Frame>> {
+ package subscriptionDataAccessLayer <<Frame>> {
+ class SubscriptionDataAccessService <<@Repository>> {
+ <<create>> SubscriptionDataAccessService(JpaTemplate jpaTemplate)
+ int uploadSubscriptions(String username, List<SubscriptionAction> subscriptions)
+ List<String> getSubscriptions(String username)
+ List<String> getSubscriptionsSince(String username, LocalDateTime time)
+ int addSubscriptions(String username, List<SubscriptionAction> addedSubscriptions)
+ int removeSubscriptions(String username, List<SubscriptionAction> removedSubscriptions)
+ List<SubscriptionTitles> getTitles(String username)
+ }
+
+ interface SubscriptionDao {
+ int uploadSubscriptions(String username, List<SubscriptionAction> subscriptions)
+ List<String> getSubscriptions(String username)
+ List<String> getSubscriptionsSince(String username, LocalDateTime time)
+ int addSubscriptions(String username, List<SubscriptionAction> addedSubscriptions)
+ int removeSubscriptions(String username, List<SubscriptionAction> removedSubscriptions)
+ List<SubscriptionTitles> getTitles(String username)
+ }
+ }
+
+ package subscriptionService <<Frame>> {
+ class SubscriptionService <<@Service>> {
+ <<create>> SubscriptionService(SubscriptionDao subscriptionDao)
+ int uploadSubscriptions(String username, List<SubscriptionAction> subscriptions)
+ List<String> getSubscriptions(String username)
+ List<String> getSubscriptionsSince(String username, LocalDateTime time)
+ int addSubscriptions(String username, List<SubscriptionAction> addedSubscriptions)
+ int removeSubscriptions(String username, List<SubscriptionAction> removedSubscriptions)
+ List<SubscriptionTitles> getTitles(String username)
+ }
+ }
+
+ package subscriptionController <<Frame>> {
+ class SubscriptionController <<@Controller>>{
+ ' @Autowired
+ <<create>> SubscriptionController(SubscriptionService subscriptionService)
+ ' @GetMapping
+ ResponseEntity<List<String>> getSubscriptions(String username, String deviceID, String functionJSONP)
+ ' @PutMapping
+ ResponseEntity<String> uploadSubscriptions(String username, String deviceID, List<String> subscriptions)
+ ' @PostMapping
+ ResponseEntity<SubscriptionDelta> applySubscriptionDelta(String username, String deviceID, SubscriptionDelta delta)
+ ' @GetMapping
+ ResponseEntity<SubscriptionDelta> getSubscriptionDelta(String username, String deviceID, long since)
+ ResponseEntity<List<SubscriptionTitles>> getTitles(String username, String deviceID)
+ }
+
+ class SubscriptionTitles {
+ <<create>> SubscriptionTitles(Subscription subscription, List<EpisodeActionPost> episodeTitles)
+ Subscription getSubscription()
+ List<EpisodeActionPost> getEpisodesTitles()
+ }
+
+ class SubscriptionDelta {
+ <<create>> SubscriptionDelta(List<String> add, List<String> remove)
+ List<String> getRemove()
+ LocalDate getTimestamp()
+ List<List<String>> getUpdate_urls()
+ }
+ }
+
+}
+
+package episodeActionsAPI <<Frame>> {
+ package episodeActionDataAccessLayer <<Frame>> {
+ class EpisodeActionDataAccessService <<@Repository>> {
+ <<create>> EpisodeActionDataAccessService (JpaTemplate jpaTemplate)
+ long addEpisodeActions(String username, List<EpisodeActionPost> episodeActionPosts)
+ List<EpisodeActionPost> getEpisodeActions(String username)
+ List<EpisodeActionPost> getEpisodeActionsOfPodcast(String username, String podcastURL)
+ List<EpisodeActionPost> getEpisodeActionsSince(String username, LocalDateTime since)
+ List<EpisodeActionPost> getEpisodeActionsOfPodcastSince(String username, String podcastURL, LocalDateTime since)
+ }
+
+ interface EpisodeActionDao {
+ long addEpisodeActions(String username, List<EpisodeActionPost> episodeActionPosts)
+ List<EpisodeActionPost> getEpisodeActions(String username)
+ List<EpisodeActionPost> getEpisodeActionsOfPodcast(String username, String podcastURL)
+ List<EpisodeActionPost> getEpisodeActionsSince(String username, LocalDateTime since)
+ List<EpisodeActionPost> getEpisodeActionsOfPodcastSince(String username, String podcastURL, LocalDateTime since)
+ }
+ }
+
+ package episodeActionService <<Frame>> {
+ class EpisodeActionService <<@Service>> {
+ <<create>> EpisodeActionService (EpisodeActionDao episodeActionDao)
+ LocalDateTime addEpisodeActions(String username, List<EpisodeActionPosts> episodeActionPosts)
+ List<EpisodeActionPost> getEpisodeActions(String username)
+ List<EpisodeActionPost> getEpisodeActionsOfPodcast(String username, String podcastURL)
+ List<EpisodeActionPost> getEpisodeActionsSince(String username, LocalDateTime since)
+ List<EpisodeActionPost> getEpisodeActionsOfPodcastSince(String username, String podcastURL, LocalDateTime since)
+ }
+ }
+
+ package episodeActionController <<Frame>> {
+ class EpisodeActionController <<@Controller>>{
+ <<create>> EpisodeActionController (EpisodeActionService episodeActionService)
+ ResponseEntity<EpisodeActionPostResponse> addEpisodeActions(String username, EpisodeActionPostRequest episodeActionPostRequest)
+ ResponseEntity<EpisodeActionGetResponse> getEpisodeActions(String username, String deviceID, boolean aggregated)
+ ResponseEntity<EpisodeActionGetResponse> getEpisodeActionsOfPodcast(String username, String podcastURL, String deviceID, boolean aggregated)
+ ResponseEntity<EpisodeActionGetResponse> getEpisodeActionsSince(String username, String deviceID, long since, boolean aggregated)
+ ResponseEntity<EpisodeActionGetResponse> getEpisodeActionsOfPodcastSince(String username, String podcastURL, String deviceID, long since, boolean aggregated)
+ }
+
+ class EpisodeActionPostResponse {
+ <<create>> EpisodeActionPostResponse(List<Pair<String, String>> updateURLs)
+ long getTimestamp()
+ List<Pair<String, String>> getUpdatedURLs()
+ }
+
+ class EpisodeActionPost {
+ <<create>> EpisodeActionPost(String podcastURL, String episodeURL, Action action, LocalDateTime timestamp, int started, int position)
+ String getPodcastURL()
+ String getEpisodeURL()
+ int getGUID()
+ Action getAction()
+ LocalDateTime getTimestamp()
+ int getStarted()
+ int getPosition()
+ EpisodeAction getEpisodeAction()
+ }
+
+ class EpisodeActionPostRequest {
+ <<create>> EpisodeActionPostRequest(List<EpisodeActionPost> episodeActionPosts)
+ List<EpisodeActionPost> getEpisodeActionPosts()
+ }
+
+ class EpisodeActionGetResponse {
+ <<create>> EpisodeActionGetResponse(List<EpisodeActionPost> episodeActionPosts)
+ List<EpisodeActionPost> getEpisodeActionPosts()
+ long getTimestamp()
+ }
+ }
+}
+
+package authenticationAPI <<Frame>> {
+ package authenticationDataAccessLayer <<Frame>> {
+ ' interface AuthenticationDao {
+ ' String login(String username)
+ ' int logout(String username)
+ ' }
+
+ ' class AuthenticationDataAccessService <<@Respository>> {
+ ' <<create>> AuthenticationDataAccessService(JpaTemplate jpaTemplate)
+ ' String login(String username)
+ ' int logout(String username)
+ ' }
+
+ interface UserDetailsManager {
+ void createUser(UserDetails userDetails)
+ void changePassword(String oldPassword, String newPassword)
+ void deleteUser(String username)
+ void updateUser(UserDetails user)
+ boolean userExists(String username)
+ }
+ note left
+ Aus org.springframework.security.provisioning
+ - liefert Methoden zum Erstellen neuer User
+ und zum Aktualisieren bestehender.
+ end note
+
+ class JdbcUserDetailsManager <<@Repository>> {
+ <<create>> JdbcUserDetailsManager(DataSource dataSource)
+ void createUser(UserDetails user)
+ void changePassword(String oldPassword, String newPassword)
+ void deleteUser(String username)
+ void updateUser(UserDetails user)
+ boolean userExists(String username)
+ }
+ note right
+ User Management Service aus dem Paket
+ org.springframework.security.provisioning
+ der CRUD Operationen für User bereitstellt.
+ Hier sind nur die relevanten Methoden modelliert.
+ end note
+ }
+
+ package authenticationService <<Frame>> {
+ class AuthenticationService <<@Service>> {
+ --
+ <<create>> AuthenticationService(UserDetailsManager userDetailsManager)
+ List<String> verifyLogin(String username)
+ int logout(String username)
+ int forgotPassword(ForgotPasswordRequest forgotPasswordRequest)
+ .. via JdbcUserDetailsManager ..
+ int resetPassword(String username, RequestWithPassword requestWithPassword)
+ int registerUser(UserDetails user)
+ int changePassword(String username, ChangePasswordRequest changePasswordRequest)
+ int deleteUser(String username, RequestWithPassword requestWithPassword)
+ }
+
+ class JavaMailSenderImpl {}
+ note left
+ Aus org.springframework.mail.javamail.
+ Implementierung des JavaMailSender Interfaces,
+ welches das MailSender Interface durch Unterstützung
+ von MIME Nachrichten erweitert.
+ Das MailSender Interface definiert dabei eine
+ Strategie zum Versenden einfacher Mails.
+ Unterstützt sowohl JavaMail MimeMessages und
+ Spring SimpleMailMessages.
+ end note
+ }
+
+ package authenticationController <<Frame>> {
+ class AuthenticationController <<@Controller>> {
+ <<create>> AuthenticationController(AuthenticationService authenticationService)
+ ResponseEntity<List<String>> verifyLogin(String username)
+ ResponseEntity<Integer> logout(String username)
+ ResponseEntity<Integer> forgotPassword(ForgotPasswordRequest forgotPasswordRequest)
+ ResponseEntity<Integer> resetPassword(String username, RequestWithPassword requestWithPassword)
+ ResponseEntity<Integer> registerUser(UserDetails user)
+ ResponseEntity<Integer> changePassword(String username, ChangePasswordRequest changePasswordRequest)
+ ResponseEntity<Integer> deleteUser(String username, RequestWithPassword requestWithPassword)
+ }
+
+ class ChangePasswordRequest {
+ <<create>> ChangePasswordRequest(String oldPassword, String newPassword)
+ String getOldPassword()
+ String getNewPassword()
+ }
+
+ class ForgotPasswordRequest {
+ <<create>> ForgotPasswordRequest(String email)
+ String getEmail()
+ }
+
+ class RequestWithPassword {
+ <<create>> ResetPasswordRequest(String password)
+ String getPassword()
+ }
+ }
+}
+
+package model <<Frame>> {
+ class Subscription {
+ <<create>> Subscription(String url, String title)
+ int getID()
+ String getURL()
+ long getLastActionTimestamp()
+ String getTitle()
+ }
+
+ class SubscriptionAction {
+ <<create>> SubscriptionAction(int userID, int subscriptionID)
+ int getID()
+ int getUserID()
+ int getSubscriptionID()
+ long getTimestamp()
+ boolean getAdded()
+ }
+
+ class Episode {
+ <<create>> Episode(int subscriptionID, int id, String url, String title, String thumbnailURL, int total)
+ int getSubscriptionID()
+ int getID()
+ int getGUID()
+ String getURL()
+ String getTitle()
+ int getTotal()
+ }
+
+ enum Action {
+ Download
+ Play
+ Delete
+ New
+ Flattr
+ String getJsonProperty()
+ }
+
+ class EpisodeAction {
+ <<create>> EpisodeAction(Action action, LocalDateTime timestamp, int started, int position)
+ int getEpisodeID()
+ Action getAction()
+ long getTimestamp()
+ int getStarted()
+ int getPosition()
+ void setEpisodeID()
+ EpisodeActionPost getEpisodeActionPost(String podcastURL, String episodeURL)
+ }
+
+ interface UserDetails {
+ String getUsername()
+ String getPassword()
+ Collection<Authority> getAuthorities()
+ boolean isAccountExpired()
+ boolean isAccountLocked()
+ boolean isCredentialsNonExpired()
+ boolean isEnabled()
+ }
+ note left
+ Aus org.springframework.security.core.userdetails.
+ Wird für die Schnittstelle UserDetailsManager benötigt.
+ Stellt wichtige Informationen eines Users bereit.
+ Diese werden nur indirekt von Spring Security
+ benutzt, indem sie vorher in Authentication Objekten
+ gekapselt werden.
+ end note
+
+ class User {
+ --
+ <<create>> User(String username, String password)
+ int getID()
+ String getSessionToken()
+ boolean getEmailIsValidated()
+ .. interface methods ..
+ String getUsername()
+ String getPassword()
+ Collection<Authority> getAuthorities()
+ boolean isAccountExpired()
+ boolean isAccountLocked()
+ boolean isCredentialsNonExpired()
+ boolean isEnabled()
+ }
+
+ interface GrantedAuthority {
+ String getAuthority()
+ }
+ note right
+ Aus org.springframework.security.core.
+ Wird für die Schnittstelle UserDetails benötigt.
+ Repräsentiert eine Autorisierung, die einem
+ Authentication Objekt gewährt wird.
+ end note
+
+ class Authority {
+ <<create>> Authority()
+ String getAuthority()
+ }
+}
+
+package util <<Frame>> {
+ class RSSParser {
+ <<create>> RSSParser(String subscriptionURL)
+ String getSubscriptionTitle()
+ List<Episode> getEpisodes()
+ Episode getEpisodeForURL(String episodeURL)
+ }
+ note bottom
+ Verwendet intern Spring um
+ HTTP-Anfragen zu erstellen.
+ end note
+
+ class CleanCronJob {
+ <<create>> CleanCronJob(JdbcUserDetailsManager jdbcUserDetailsManager)
+ void cleanInvalidUsers()
+ }
+ note bottom
+ Hintergrundservice, der in periodischen Abständen
+ Nutzer, die ihre E-Mail-Adresse nicht nach 24 Stunden
+ bestätigt haben, wieder aus der Datenbank löscht.
+ (Auf die Assoziation zu JdbcUserDetailsManager wird
+ im Sinne der Übersichtlichkeit verzichtet.)
+ end note
+
+ class ResponseEntity<T> {
+ <<create>> ResponseEntity(T body, HttpStatusCode status)
+ T getBody()
+ HttpStatusCode getStatusCode()
+ }
+ note bottom
+ Aus org.springframework.http.
+ Erweitert die Klasse HttpEntity, welche
+ ein HTTP Anfrage- oder Antwort-Objekt
+ repräsentiert, durch einen HttpStatusCode.
+ Wird von den Controller-Methoden als
+ Rückgabewert verwendet.
+ end note
+}
+
+class SecurityConfigurationBasicAuth {
+ <<create>> SecurityConfigurationBasicAuth()
+ PasswordEncoder encoder()
+ UserDetailsManager userDetailsService()
+ SecuryFilterChain fiterChain(HTTPSecurity http) throws Excpetion
+}
+note top
+ Erstellt einen Servlet Filter (springSecurityFilterChain)
+ der für die gesamte Sicherheit zuständig ist (Schutz der URLs,
+ Validierung von Anmeldedaten, Weiterleitung zur Anmeldung, etc.).
+end note
+
+class PSEApplication {
+ <<create>> PSEApplication()
+ void main(String[] args)
+}
+
+database Datenbank
+Datenbank <-[hidden]d- subscriptionsAPI
+Datenbank <-[hidden]d- episodeActionsAPI
+Datenbank <-[hidden]d- authenticationAPI
+() SQL as SQLSub
+() SQL as SQLAuth
+() SQL as SQLEpisode
+
+Datenbank -- SQLSub
+Datenbank -- SQLAuth
+Datenbank -- SQLEpisode
+
+SubscriptionController ..o PSEApplication
+AuthenticationController ..o PSEApplication
+EpisodeActionController ..o PSEApplication
+SecurityConfigurationBasicAuth ..o PSEApplication
+
+PSEApplication --() HTTP
+
+SQLSub )-- SubscriptionDataAccessService: JPA
+' SQLAuth )-- AuthenticationDataAccessService: JPA
+SQLAuth )-- JdbcUserDetailsManager: JDBC
+SQLEpisode )-- EpisodeActionDataAccessService: JPA
+
+Subscription <. SubscriptionAction: ID
+' Subscription <.. SubscriptionDataAccessService: DB
+' SubscriptionAction <.. SubscriptionDataAccessService: DB
+SubscriptionService --o SubscriptionController
+SubscriptionDao <.. SubscriptionService: <<use>>
+Subscription --o SubscriptionTitles
+EpisodeActionPost -o SubscriptionTitles
+SubscriptionDao <|. SubscriptionDataAccessService: <<realize>>
+
+' User <.. AuthenticationDataAccessService: DB
+' User <.. JdbcUserDetailsManager: DB
+UserDetailsManager <.. AuthenticationService: <<use>>
+' AuthenticationDao <.. AuthenticationService: <<use>>
+AuthenticationService --o AuthenticationController
+' AuthenticationDao <|. AuthenticationDataAccessService: <<realize>>
+UserDetailsManager <|. JdbcUserDetailsManager: <<realize>>
+UserDetailsManager <.. SecurityConfigurationBasicAuth: <<use>>
+UserDetails <|.. User: <<realize>>
+User -> Authority
+GrantedAuthority <|.. Authority: <<realize>>
+JavaMailSenderImpl <. AuthenticationService: <<use>>
+
+Action <-- EpisodeAction
+EpisodeActionPost -o EpisodeActionGetResponse
+EpisodeActionPost -o EpisodeActionPostRequest
+EpisodeAction .> Episode: ID
+' EpisodeAction <.. EpisodeActionDataAccessService: DB
+' Episode <.. EpisodeActionDataAccessService: DB
+EpisodeActionDao <.. EpisodeActionService: <<use>>
+EpisodeActionService --o EpisodeActionController
+EpisodeActionDao <|. EpisodeActionDataAccessService: <<realize>>
+
+RSSParser <. SubscriptionDataAccessService: <<use>>
+RSSParser <. EpisodeActionDataAccessService: <<use>>
+' JdbcUserDetailsManager <-- CleanCronJob
+
+model .o Datenbank: ORM (User, SubscriptionAction, Subscription, EpisodeAction, Episode)
+' Datenbank o.. Subscription: ORM
+' Datenbank o.. SubscriptionAction: ORM
+' Datenbank o.. Episode: ORM
+' Datenbank o.. EpisodeAction: ORM
+' Datenbank o.. User: ORM
+
+@enduml
diff --git a/20-implementierungsheft/assets/diagrams/componentdiagram.puml b/20-implementierungsheft/assets/diagrams/componentdiagram.puml
new file mode 100644
index 0000000..7e23754
--- /dev/null
+++ b/20-implementierungsheft/assets/diagrams/componentdiagram.puml
@@ -0,0 +1,79 @@
+@startuml
+
+[App] as app
+[VueRouter] as router
+
+[EpisodesViewComponent] as episodes_view
+[ForgotPasswordViewComponent] as forgot_password_view
+[LoginViewComponent] as login_view
+[RegistrationViewComponent] as registration_view
+[ResetPasswordViewComponent] as reset_password_view
+[settingsViewComponent] as settings_view
+[SubscriptionsViewComponent] as subscriptions_view
+
+[DashboardLayoutComponent] as dashboard_layout
+[EpisodeComponent] as episode
+[ErrorLogComponent] as error_log
+[FloatingLabelInputComponent] as floating_label_input
+[FormLayoutComponent] as form_layout
+[HelpComponent] as help
+[LastUpdateComponent] as last_update
+[LoadingComponent] as loading
+[NavbarComponent] as navbar
+[PasswordInputComponent] as password_input
+[PasswordValidatorComponent] as password_validator
+[ProgressTimeComponent] as progress_time
+[SubscriptionComponent] as subscription
+
+app --> router
+app --> navbar
+app --> help
+app --> error_log
+
+password_validator --> password_input
+password_input --> floating_label_input
+
+router --> registration_view
+router --> login_view
+router --> reset_password_view
+router --> forgot_password_view
+router --> episodes_view
+router --> subscriptions_view
+router --> settings_view
+
+
+login_view --> form_layout
+login_view --> floating_label_input
+login_view --> password_input
+
+forgot_password_view --> form_layout
+forgot_password_view --> floating_label_input
+
+registration_view --> form_layout
+registration_view --> password_validator
+registration_view --> floating_label_input
+
+reset_password_view --> form_layout
+reset_password_view --> password_validator
+
+settings_view --> dashboard_layout
+settings_view --> floating_label_input
+settings_view --> password_input
+settings_view --> password_validator
+
+episodes_view --> dashboard_layout
+episodes_view --> episode
+episodes_view --> loading
+
+episode --> last_update
+episode --> progress_time
+
+subscriptions_view --> dashboard_layout
+subscriptions_view --> floating_label_input
+subscriptions_view --> loading
+subscriptions_view --> subscription
+
+subscription --> last_update
+subscription --> progress_time
+
+@enduml
diff --git a/20-implementierungsheft/assets/diagrams/db.puml b/20-implementierungsheft/assets/diagrams/db.puml
new file mode 100644
index 0000000..bdefaea
--- /dev/null
+++ b/20-implementierungsheft/assets/diagrams/db.puml
@@ -0,0 +1,78 @@
+@startuml
+' Type Symbol
+' Zero or One |o--
+' Exactly One ||--
+' Zero or Many }o--
+' One or Many }|--
+
+skinparam linetype ortho
+
+entity User {
+ * int id <<unique>>
+ * <u>String email</u>
+ * String password
+ * boolean verified
+ * long created_at
+}
+
+entity SubscriptionAction {
+ * int id <<unique>>
+ * <u>int user_id</u>
+ * long timestamp
+ * int subscription_id
+ * boolean added
+}
+
+entity Subscription {
+ * int id <<unique>>
+ * <u>String url</u>
+ * long timestamp
+ * String title
+}
+
+entity Episode {
+ * int id <<unique>>
+ * <u>int guid <<unique>></u>
+ * <u>String url</u>
+ * String title
+ * int total
+ * int subscription_id
+}
+note right
+ Wenn der Client eine GUID aus dem Feed mitsendet, wird
+ diese statt der URL verwendet um die Episode zu finden.
+ So wird die Episode auch noch gefunden, nachdem sich
+ die URL geändert hat.
+end note
+note bottom of Episode
+ Wenn für die Episoden-URL einer EpisodeAction noch keine Episode in der Datenbank steht,
+ dann schreibe dafür ein Dummy-Objekt in Datenbank und lade asynchron die Episoden der Subscription.
+ Ersetze dann die Dummy-Objekte durch die Episoden und setze den Timestamp der Subscription auf
+ die aktuelle Zeit.
+ Um DoS-Angriffe auf den Backend-Server abzuwenden, können die Episoden einer Subscription erst
+ nach einer Stunde erneut gefetched werden. Bis dahin werden für EpisodeActions, die sich auf noch
+ nicht geladene Episoden beziehen, nur Dummy-Objekte für die Episoden in die Datenbank geschrieben.
+ Es sei noch darauf hingewiesen, dass diese Dummy-Episoden bei Anfragen nicht mit ausgegeben werden.
+end note
+
+entity EpisodeAction {
+ * int id <<unique>>
+ * <u>int user_id</u>
+ * int episode_id
+ * long timestamp
+ * int action
+ * int started
+ * int position
+}
+note right
+ Speichere für jede Episode
+ nur letzte Play-Action.
+endnote
+
+User ||--o{ EpisodeAction
+User ||--o{ SubscriptionAction
+SubscriptionAction }|--|| Subscription
+EpisodeAction }|--|| Episode
+Subscription ||-right-|{ Episode
+
+@enduml
diff --git a/20-implementierungsheft/assets/diagrams/deployment.puml b/20-implementierungsheft/assets/diagrams/deployment.puml
new file mode 100644
index 0000000..26918e2
--- /dev/null
+++ b/20-implementierungsheft/assets/diagrams/deployment.puml
@@ -0,0 +1,59 @@
+@startuml
+
+node "<<device>> \nBackend Server" as backendServer{
+ database " <<database system>> \n MariaDB Server 10.6" as database {
+ rectangle rectangle1 [
+ <<schema>>
+ User
+ ]
+ rectangle rectangle2 [
+ <<schema>>
+ SubscriptionAction
+ ]
+ rectangle rectangle3 [
+ <<schema>>
+ EpisodeAction
+ ]
+ rectangle rectangle4 [
+ <<schema>>
+ Subscription
+ ]
+ rectangle rectangle5 [
+ <<schema>>
+ Episode
+ ]
+ }
+
+ node "<<framework>> \nJava Spring" as javaSpring{
+ node " <<device>> \n Tomcat Webserver"
+ }
+}
+
+node "<<device>> \nFrontend" as frontendServer {
+
+}
+
+node "<<device>> \nEndgerät" as terminal {
+ node "<<application>> \nBrowser" as browser
+ node "<<application>> \nPodcatcher" as podcatcher
+}
+
+backendServer "1" - "*" podcatcher
+
+node "<<device>> \nFrontend Server" as frontendServer{
+ node "<<framework>> \nVue.js" as vuejs {
+
+ }
+}
+
+podcatcher -[hidden] browser
+
+backendServer - "1" frontendServer
+
+database "1" -- "1" javaSpring
+
+browser "*" -- frontendServer
+
+
+
+@enduml
diff --git a/20-implementierungsheft/assets/diagrams/gantt-plan.puml b/20-implementierungsheft/assets/diagrams/gantt-plan.puml
new file mode 100644
index 0000000..0e90aa2
--- /dev/null
+++ b/20-implementierungsheft/assets/diagrams/gantt-plan.puml
@@ -0,0 +1,31 @@
+@startgantt
+
+printscale daily zoom 5
+project starts on 2023-01-30
+
+-- Backend --
+[Controller-Schicht] on {Immanuel} lasts 2 days
+[Service-Schicht (Daten durchreichen)] on {Daniel} lasts 2 days
+[Authentifizierung] on {Gero} lasts 4 days
+[Model-Paket] on {Daniel} lasts 1 days
+[Datenbank aufsetzen] on {Immanuel} lasts 4 days
+[Util-Paket (RSSParser)] on {Daniel} {Lukas} lasts 6 days
+[DataAccess-Schicht] on {Immanuel} {Julius} lasts 8 days
+[Service-Schicht (Geschäftslogik)] on {Daniel} {Immanuel} lasts 8 days
+[Util-Paket (CleanCronJob)] on {Julius} lasts 2 days
+-- Frontend --
+[Komponenten] on {Gero} {Julius} {Lukas} lasts 15 days
+[API-Anbindung] on {Gero} {Lukas} lasts 4 days
+
+'Backend
+[Service-Schicht (Daten durchreichen)] starts at [Controller-Schicht]'s end
+[Datenbank aufsetzen] starts at [Model-Paket]'s end
+[Authentifizierung] starts at [Controller-Schicht]'s end
+[DataAccess-Schicht] starts at [Datenbank aufsetzen]'s end
+[Util-Paket (RSSParser)] starts at [Datenbank aufsetzen]'s end
+[Service-Schicht (Geschäftslogik)] starts at [DataAccess-Schicht]'s end
+[Util-Paket (CleanCronJob)] starts at [DataAccess-Schicht]'s end
+'Frontend
+[API-Anbindung] starts at [DataAccess-Schicht]'s end
+
+@endgantt \ No newline at end of file
diff --git a/20-implementierungsheft/assets/diagrams/gantt-reality.puml b/20-implementierungsheft/assets/diagrams/gantt-reality.puml
new file mode 100644
index 0000000..f726c56
--- /dev/null
+++ b/20-implementierungsheft/assets/diagrams/gantt-reality.puml
@@ -0,0 +1,39 @@
+@startgantt
+
+printscale daily zoom 5
+project starts on 2023-01-30
+
+-- Backend --
+[Controller-Schicht] on {Immanuel} lasts 3 days
+[Model-Paket] on {Daniel} lasts 3 days
+[Datenbank aufsetzen] on {Immanuel} lasts 6 days
+[Util-Paket (RSSParser)] on {Daniel} {Lukas} lasts 32 days
+[DAO-Interfaces] on {Julius} {Immanuel} lasts 6 days
+[Authentifizierung] on {Immanuel} lasts 13 days
+[Service-Schicht mit Datenzugriff] on {Julius} lasts 14 days
+[Util-Paket (CleanCronJob)] on {Daniel} lasts 2 days
+[Docker] on {Daniel} lasts 12 days
+[EMailService] on {Gero} lasts 1 days
+-- Frontend --
+[Komponenten] on {Gero} {Julius} lasts 15 days
+[Mehrsprachigkeit] on {Lukas} lasts 5 days
+[Router] on {Gero} lasts 1 days
+[API-Anbindung] on {Gero} {Lukas} lasts 28 days
+[Error-Handling] on {Gero} lasts 5 days
+
+'Backend
+[Datenbank aufsetzen] starts at [Model-Paket]'s end
+[Util-Paket (RSSParser)] starts at [Datenbank aufsetzen]'s end
+[DAO-Interfaces] starts at [Datenbank aufsetzen]'s end
+[Authentifizierung] starts at [DAO-Interfaces]'s end
+[Service-Schicht mit Datenzugriff] starts at [DAO-Interfaces]'s end
+[Util-Paket (CleanCronJob)] starts at [DAO-Interfaces]'s end
+[Docker] starts at [Util-Paket (CleanCronJob)]'s end
+[EMailService] starts 2023-02-14
+'Frontend
+[Mehrsprachigkeit] starts 2023-02-01
+[Router] starts at [Mehrsprachigkeit]'s end
+[API-Anbindung] starts at [Router]'s end
+[Error-Handling] starts 2023-02-05
+
+@endgantt \ No newline at end of file
diff --git a/20-implementierungsheft/assets/diagrams/sequencediagram-forgotAndResetPW.puml b/20-implementierungsheft/assets/diagrams/sequencediagram-forgotAndResetPW.puml
new file mode 100644
index 0000000..603130c
--- /dev/null
+++ b/20-implementierungsheft/assets/diagrams/sequencediagram-forgotAndResetPW.puml
@@ -0,0 +1,41 @@
+@startuml
+
+skinparam ParticipantPadding 30
+
+participant AuthenticationController << (C, #ADD1B2) @Controller >>
+-> AuthenticationController: ""POST /api/2/auth/forgot.json"" \n//@RequestBody ForgotPasswordRequest forgotPasswordRequest// \n\n-> forgotPassword(//forgotPasswordRequest//)
+activate AuthenticationController
+participant AuthenticationService << (C, #ADD1B2) @Service >>
+AuthenticationController -> AuthenticationService: forgotPassword(//forgotPasswordRequest//)
+activate AuthenticationService
+participant JavaMailSenderImpl << (C, #ADD1B2) >>
+AuthenticationService -> JavaMailSenderImpl: create link to reset password with JWT as URL parameter \n-> send(SimpleMailMessage simpleMessage) with link
+activate JavaMailSenderImpl
+<<- JavaMailSenderImpl: sends email with link containing a JWT to reset password
+JavaMailSenderImpl --> AuthenticationService
+deactivate JavaMailSenderImpl
+AuthenticationService --> AuthenticationController: int indicating status
+deactivate AuthenticationService
+<-- AuthenticationController: ResponseEntity<Integer> indicating status \n\n-> ""HTTP status code""
+deactivate AuthenticationController
+||60||
+-> AuthenticationController: ""PUT /api/2/auth/{username}/resetpassword.json"" \n//@RequestParam String jwt// \n//@RequestBody ResetPasswordRequest resetPasswordRequest// \n\n-> login user (""username"") via JWT (//jwt//) \n-> resetPassword(""username"", //resetPasswordRequest//)
+activate AuthenticationController
+AuthenticationController -> AuthenticationService: resetPassword(""username"", //resetPasswordRequest//)
+activate AuthenticationService
+participant JdbcUserDetailsManager << (C, #ADD1B2) @Repository >>
+AuthenticationService -> JdbcUserDetailsManager: String oldPassword = //resetPasswordRequest//.getOldPassword() \nString newPassword = //resetPasswordRequest//.getNewPassword() \n-> changePassword(newPassword, oldPassword)
+activate JdbcUserDetailsManager
+database Database
+JdbcUserDetailsManager -> Database: change password of logged in user
+activate Database
+Database --> JdbcUserDetailsManager
+deactivate Database
+JdbcUserDetailsManager --> AuthenticationService: int indicating status
+deactivate JdbcUserDetailsManager
+AuthenticationService --> AuthenticationController: int indicating status
+deactivate AuthenticationService
+<-- AuthenticationController: ResponseEntity<Integer> indicating status \n\n-> ""HTTP status code""
+deactivate AuthenticationController
+
+@enduml \ No newline at end of file
diff --git a/20-implementierungsheft/assets/diagrams/sequencediagram-getEpisodeActions.puml b/20-implementierungsheft/assets/diagrams/sequencediagram-getEpisodeActions.puml
new file mode 100644
index 0000000..47497d5
--- /dev/null
+++ b/20-implementierungsheft/assets/diagrams/sequencediagram-getEpisodeActions.puml
@@ -0,0 +1,38 @@
+@startuml
+
+' title =**Get All Episode Actions**
+
+participant EpisodeActionController << (C, #ADD1B2) @Controller >>
+-> EpisodeActionController: ""GET /api/2/episodes/{username}.json"" \n//@RequestParam("device") String deviceID// \n//@RequestParam("aggregated") boolean aggregated// \n\n-> getEpisodeActions(""username"", //deviceID//, //aggregated//)
+note right
+ Die Parameter //deviceID// und //aggregated// werden ignoriert,
+ da nicht zwischen Geräten unterschieden und für jede
+ Episode sowieso nur die letzte Play-Action gespeichert
+ wird. Dies gilt für alle GET-Anfragen der Episode Actions API.
+end note
+activate EpisodeActionController
+participant EpisodeActionService << (C, #ADD1B2) @Service >>
+EpisodeActionController -> EpisodeActionService: getEpisodeActions(""username"")
+activate EpisodeActionService
+participant EpisodeActionDataAccessService << (C, #ADD1B2) @Repository >>
+EpisodeActionService -> EpisodeActionDataAccessService: getEpisodeActions(""username"")
+activate EpisodeActionDataAccessService
+EpisodeActionDataAccessService -> EpisodeActionDataAccessService: getEpisodeActionsSince(""username"", \nLocalDateTime.MIN.toEpochSecond(ZoneOffset.UTC))
+database Database
+activate EpisodeActionDataAccessService
+EpisodeActionDataAccessService -> Database: get all EpisodeActions for all subscribed podcasts
+activate Database
+Database --> EpisodeActionDataAccessService: List<EpisodeAction> selectedEpisodeActions \n-> then remove all older than LocalDateTime.MIN (none)
+EpisodeActionDataAccessService -> Database: join EpisodeActions in selectedEpisodeActions with episodeURL of Episode
+Database --> EpisodeActionDataAccessService
+deactivate Database
+EpisodeActionDataAccessService --> EpisodeActionDataAccessService: List<EpisodeActionPost> episodeActionPosts
+deactivate EpisodeActionDataAccessService
+EpisodeActionDataAccessService --> EpisodeActionService: List<EpisodeActionPost> episodeActionPosts
+deactivate EpisodeActionDataAccessService
+EpisodeActionService --> EpisodeActionController: List<EpisodeActionPost> episodeActionPosts
+deactivate EpisodeActionService
+<-- EpisodeActionController: ResponseEntity<EpisodeActionGetResponse> response \n\n-> ""HTTP status code"" \n-> ""JSON""
+deactivate EpisodeActionController
+
+@enduml \ No newline at end of file
diff --git a/20-implementierungsheft/assets/diagrams/sequencediagram-getEpisodeActionsOfPodcastSince.puml b/20-implementierungsheft/assets/diagrams/sequencediagram-getEpisodeActionsOfPodcastSince.puml
new file mode 100644
index 0000000..d8797d1
--- /dev/null
+++ b/20-implementierungsheft/assets/diagrams/sequencediagram-getEpisodeActionsOfPodcastSince.puml
@@ -0,0 +1,32 @@
+@startuml
+
+' title =**Get Episode Actions of Podcast Since**
+
+participant EpisodeActionController << (C, #ADD1B2) @Controller >>
+-> EpisodeActionController: ""GET /api/2/episodes/{username}.json"" \n//@RequestParam("podcast") String podcastURL// \n//@RequestParam("device") String deviceID// \n//@RequestParam("since") long since// \n//@RequestParam("aggregated") boolean aggregated// \n\n-> getEpisodeActionsOfPodcastSince(""username"", //podcastURL//, //deviceID//, //since//, //aggregated//)
+note right
+ Die Parameter //deviceID// und //aggregated// werden ignoriert.
+ Siehe Notiz in Sequenzdiagramm **Get All Episode Actions**.
+end note
+activate EpisodeActionController
+participant EpisodeActionService << (C, #ADD1B2) @Service >>
+EpisodeActionController -> EpisodeActionService: getEpisodeActionsOfPodcastSince(""username"", //podcastURL//, //since//)
+activate EpisodeActionService
+participant EpisodeActionDataAccessService << (C, #ADD1B2) @Repository >>
+EpisodeActionService -> EpisodeActionDataAccessService: getEpisodeActionsOfPodcastSince(""username"", //podcastURL//, //since//)
+activate EpisodeActionDataAccessService
+database Database
+EpisodeActionDataAccessService -> Database: get all EpisodeActions the given podcast (//podcastURL//)
+activate Database
+Database --> EpisodeActionDataAccessService: List<EpisodeAction> selectedEpisodeActions \n-> then remove all older than //since//
+EpisodeActionDataAccessService -> Database: join EpisodeActions in selectedEpisodeActions with episodeURL of Episode
+Database --> EpisodeActionDataAccessService
+deactivate Database
+EpisodeActionDataAccessService --> EpisodeActionService: List<EpisodeActionPost> episodeActionPosts
+deactivate EpisodeActionDataAccessService
+EpisodeActionService --> EpisodeActionController: List<EpisodeActionPost> episodeActionPosts
+deactivate EpisodeActionService
+<-- EpisodeActionController: ResponseEntity<EpisodeActionGetResponse> response \n\n-> ""HTTP status code"" \n-> ""JSON""
+deactivate EpisodeActionController
+
+@enduml \ No newline at end of file
diff --git a/20-implementierungsheft/assets/diagrams/sequencediagram-getSubscriptions.puml b/20-implementierungsheft/assets/diagrams/sequencediagram-getSubscriptions.puml
new file mode 100644
index 0000000..4d8ab90
--- /dev/null
+++ b/20-implementierungsheft/assets/diagrams/sequencediagram-getSubscriptions.puml
@@ -0,0 +1,38 @@
+@startuml
+
+' title =**Get All Subscriptions**
+
+participant SubscriptionController << (C, #ADD1B2) @Controller >>
+-> SubscriptionController: ""GET /subscriptions/{username}.json"" \n"" /subscriptions/{username}/{deviceid}.json"" \n//@RequestParam("jsonp") String functionJSONP// \n\n-> getSubscriptions(""username"", ""deviceid"", //functionJSONP//)
+activate SubscriptionController
+note right
+ Die Parameter ""deviceid"" und
+ //functionJSONP// werden ignoriert,
+ da nicht zwischen Geräten unterschieden
+ und JSONP nicht unterstützt wird.
+end note
+participant SubscriptionService << (C, #ADD1B2) @Service >>
+SubscriptionController -> SubscriptionService: getSubscriptions(""username"")
+activate SubscriptionService
+participant SubscriptionDataAccessService << (C, #ADD1B2) @Repository >>
+SubscriptionService -> SubscriptionDataAccessService: getSubscriptions(""username"")
+activate SubscriptionDataAccessService
+SubscriptionDataAccessService -> SubscriptionDataAccessService: getSubscriptionsSince(""username"", LocalDateTime.MIN)
+database Database
+activate SubscriptionDataAccessService
+SubscriptionDataAccessService -> Database: get all Subscriptions for ""username""
+activate Database
+Database --> SubscriptionDataAccessService: List<Subscription> subscriptions
+SubscriptionDataAccessService -> Database: get Podcasts from Subscriptions
+Database --> SubscriptionDataAccessService: List<Podcast> subscribedPodcasts
+deactivate Database
+SubscriptionDataAccessService --> SubscriptionDataAccessService: List<String> podcastURLs
+deactivate SubscriptionDataAccessService
+SubscriptionDataAccessService --> SubscriptionService: List<String> podcastURLs
+deactivate SubscriptionDataAccessService
+SubscriptionService --> SubscriptionController: List<String> podcastURLs
+deactivate SubscriptionService
+<-- SubscriptionController: ResponseEntity<List<String>> podcastURLs \n \n-> ""HTTP status code"" \n-> ""JSON""
+deactivate SubscriptionController
+
+@enduml \ No newline at end of file
diff --git a/20-implementierungsheft/assets/diagrams/sequencediagram-register.puml b/20-implementierungsheft/assets/diagrams/sequencediagram-register.puml
new file mode 100644
index 0000000..b7b7aa1
--- /dev/null
+++ b/20-implementierungsheft/assets/diagrams/sequencediagram-register.puml
@@ -0,0 +1,26 @@
+@startuml
+
+' title =**Register**
+
+participant AuthenticationController << (C, #ADD1B2) @Controller >>
+-> AuthenticationController: ""POST /api/2/auth/register.json"" \n//@RequestBody UserDetails user// \n\n-> registerUser(//user//)
+activate AuthenticationController
+participant AuthenticationService << (C, #ADD1B2) @Service >>
+AuthenticationController -> AuthenticationService: registerUser(//user//)
+activate AuthenticationService
+participant JdbcUserDetailsManager << (C, #ADD1B2) @Repository >>
+AuthenticationService -> JdbcUserDetailsManager: createUser(//user//)
+activate JdbcUserDetailsManager
+database Database
+JdbcUserDetailsManager -> Database: create new User with given UserDetails (//user//)
+activate Database
+Database --> JdbcUserDetailsManager
+deactivate Database
+JdbcUserDetailsManager --> AuthenticationService: int indicating status
+deactivate JdbcUserDetailsManager
+AuthenticationService --> AuthenticationController: int indicating status
+deactivate AuthenticationService
+<-- AuthenticationController: ResponseEntity<Integer> indicating status \n\n-> ""HTTP status code""
+deactivate AuthenticationController
+
+@enduml \ No newline at end of file
diff --git a/20-implementierungsheft/assets/diagrams/sequencediagram-uploadEpisodeActions.puml b/20-implementierungsheft/assets/diagrams/sequencediagram-uploadEpisodeActions.puml
new file mode 100644
index 0000000..d3dac57
--- /dev/null
+++ b/20-implementierungsheft/assets/diagrams/sequencediagram-uploadEpisodeActions.puml
@@ -0,0 +1,38 @@
+@startuml
+
+' title =**Upload Episode Actions**
+
+participant EpisodeActionController << (C, #ADD1B2) @Controller >>
+-> EpisodeActionController: ""POST /api/2/episodes/{username}.json"" \n//@RequestBody EpisodeActionPostRequest episodeActionPostRequest// \n\n-> addEpisodeActions(""username"", //episodeActionPostRequest//)
+activate EpisodeActionController
+participant EpisodeActionService << (C, #ADD1B2) @Service >>
+EpisodeActionController -> EpisodeActionService: addEpisodeActions(""username"", \nepisodeActionPosts = //episodeActionPostRequest//.getEpisodeActionPosts())
+activate EpisodeActionService
+participant EpisodeActionDataAccessService << (C, #ADD1B2) @Repository >>
+EpisodeActionService -> EpisodeActionDataAccessService: addEpisodeActions(""username"", episodeActionPosts)
+database Database
+activate EpisodeActionDataAccessService
+loop for each EpisodeActionPost in episodeActionPosts -> episodeAction = episodeActionPost.getEpisodeAction()
+opt episodeAction.getAction().equals(Action.PLAY)
+EpisodeActionDataAccessService -> Database: set episodeID field of episodeAction for this ""username"" via podcastURL and episodeURL
+activate Database
+Database --> EpisodeActionDataAccessService
+EpisodeActionDataAccessService -> Database: get last EpisodeAction with this episodeID if present
+Database --> EpisodeActionDataAccessService: Optional<EpisodeAction> lastEpisodeAction
+opt lastEpisodeAction.isPresent()
+EpisodeActionDataAccessService -> Database: replace lastEpisodeAction with episodeAction
+else else
+EpisodeActionDataAccessService -> Database: add episodeAction to DB as new entry
+end
+Database --> EpisodeActionDataAccessService
+deactivate Database
+end
+end
+EpisodeActionDataAccessService --> EpisodeActionService: long latestTimestamp
+deactivate EpisodeActionDataAccessService
+EpisodeActionService --> EpisodeActionController: LocalDateTime timestamp = LocalDateTime.ofEpochSecond(latestTimestamp, 0, ZoneOffset.UTC)
+deactivate EpisodeActionService
+<-- EpisodeActionController: ResponseEntity<EpisodeActionPostResponse> \n(with empty list for updateURLs) \n\n-> ""HTTP status code"" \n-> ""JSON""
+deactivate EpisodeActionController
+
+@enduml \ No newline at end of file
diff --git a/20-implementierungsheft/assets/diagrams/sequencediagram-uploadSubscriptions.puml b/20-implementierungsheft/assets/diagrams/sequencediagram-uploadSubscriptions.puml
new file mode 100644
index 0000000..1edc8cf
--- /dev/null
+++ b/20-implementierungsheft/assets/diagrams/sequencediagram-uploadSubscriptions.puml
@@ -0,0 +1,32 @@
+@startuml
+
+' title =**Upload Subscriptions**
+
+participant SubscriptionController << (C, #ADD1B2) @Controller >>
+-> SubscriptionController: ""PUT /subscriptions/{username}/{deviceid}.json"" \n//@RequestBody List<String> subscriptions// \n\n-> uploadSubscriptions(""username"", ""deviceid"", //subscriptions//)
+activate SubscriptionController
+participant SubscriptionService << (C, #ADD1B2) @Service >>
+SubscriptionController -> SubscriptionService: uploadSubscriptions(""username"", //subscriptions//)
+activate SubscriptionService
+participant SubscriptionDataAccessService << (C, #ADD1B2) @Repository >>
+SubscriptionService -> SubscriptionDataAccessService: uploadSubscriptions(""username"", //subscriptions//)
+activate SubscriptionDataAccessService
+database Database
+SubscriptionDataAccessService -> Database: delete all subsciptions of ""username""
+activate Database
+Database --> SubscriptionDataAccessService
+SubscriptionDataAccessService -> SubscriptionDataAccessService: addSubscriptions(""username"", //subscriptions//)
+activate SubscriptionDataAccessService
+SubscriptionDataAccessService -> Database: upload all subscriptions (//subscriptions//) for ""username""
+Database --> SubscriptionDataAccessService
+deactivate Database
+SubscriptionDataAccessService --> SubscriptionDataAccessService: int indicating status
+deactivate SubscriptionDataAccessService
+SubscriptionDataAccessService --> SubscriptionService: int indicating status
+deactivate SubscriptionDataAccessService
+SubscriptionService --> SubscriptionController: int indicating status
+deactivate SubscriptionService
+<-- SubscriptionController: ResponseEntity<String> with empty String for success \n\n-> ""HTTP status code"" \n-> ""JSON""
+deactivate SubscriptionController
+
+@enduml \ No newline at end of file
diff --git a/20-implementierungsheft/assets/episode.png b/20-implementierungsheft/assets/episode.png
new file mode 100644
index 0000000..c0db4a2
--- /dev/null
+++ b/20-implementierungsheft/assets/episode.png
Binary files differ
diff --git a/20-implementierungsheft/assets/errorlog.png b/20-implementierungsheft/assets/errorlog.png
new file mode 100644
index 0000000..3f6ea82
--- /dev/null
+++ b/20-implementierungsheft/assets/errorlog.png
Binary files differ
diff --git a/20-implementierungsheft/assets/floatinglabelinput.png b/20-implementierungsheft/assets/floatinglabelinput.png
new file mode 100644
index 0000000..25f013b
--- /dev/null
+++ b/20-implementierungsheft/assets/floatinglabelinput.png
Binary files differ
diff --git a/20-implementierungsheft/assets/gantt-plan-eps-converted-to.pdf b/20-implementierungsheft/assets/gantt-plan-eps-converted-to.pdf
new file mode 100644
index 0000000..add028f
--- /dev/null
+++ b/20-implementierungsheft/assets/gantt-plan-eps-converted-to.pdf
Binary files differ
diff --git a/20-implementierungsheft/assets/gantt-plan.eps b/20-implementierungsheft/assets/gantt-plan.eps
new file mode 100644
index 0000000..0242842
--- /dev/null
+++ b/20-implementierungsheft/assets/gantt-plan.eps
@@ -0,0 +1,8314 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%Creator: PlantUML v1.2023.0
+%%Title: noTitle
+%%BoundingBox: 0 0 1049 488
+%%ColorUsage: Color
+%%Origin: 0 0
+%%EndComments
+
+gsave
+0 488 translate
+.01 -.01 scale
+/simplerect {
+newpath moveto 1 index 0 rlineto
+0 exch rlineto
+neg 0 rlineto
+} def
+/rquadto {
+3 index 3 index 4 2 roll rcurveto
+} def
+/P$h {
+134 12 rlineto
+0 26 rlineto
+-353 0 rlineto
+0 -26 rlineto
+134 -12 rlineto
+0 -534 rlineto
+-131 46 rlineto
+0 -25 rlineto
+190 -109 rlineto
+25 0 rlineto
+0 621 rlineto
+closepath
+} def
+/P$1d {
+0 -60 -42 -87 rquadto
+-40 -26 -120 -26 rquadto
+-173 0 rlineto
+0 240 rlineto
+173 0 rlineto
+81 0 121 -31 rquadto
+40 -31 40 -95 rquadto
+closepath
+} def
+/P$30 {
+109 17 rlineto
+0 34 rlineto
+-340 0 rlineto
+0 -34 rlineto
+109 -17 rlineto
+0 -750 rlineto
+-109 -15 rlineto
+0 -34 rlineto
+340 0 rlineto
+0 34 rlineto
+-109 15 rlineto
+0 750 rlineto
+} def
+/P$k {
+0 143 rlineto
+-84 0 rlineto
+0 -143 rlineto
+-290 0 rlineto
+0 -65 rlineto
+318 -448 rlineto
+56 0 rlineto
+0 443 rlineto
+89 0 rlineto
+0 70 rlineto
+-89 0 rlineto
+closepath
+} def
+/P$a {
+0 125 rlineto
+-21 0 rlineto
+-28 -54 rlineto
+-25 0 -57 7 rquadto
+-32 6 -57 17 rquadto
+0 342 rlineto
+78 12 rlineto
+0 21 rlineto
+-217 0 rlineto
+0 -21 rlineto
+57 -12 rlineto
+0 -390 rlineto
+-57 -12 rlineto
+0 -21 rlineto
+132 0 rlineto
+4 57 rlineto
+29 -25 79 -46 rquadto
+50 -23 79 -23 rquadto
+7 0 rlineto
+closepath
+} def
+/P$1u {
+0 -85 rlineto
+268 0 rlineto
+0 85 rlineto
+-268 0 rlineto
+} def
+/P$2p {
+0 -65 -45 -100 rquadto
+-45 -35 -129 -35 rquadto
+-243 0 rlineto
+0 279 rlineto
+248 0 rlineto
+81 0 125 -37 rquadto
+45 -37 45 -106 rquadto
+} def
+/P$1i {
+-196 -265 rlineto
+-71 59 rlineto
+0 206 rlineto
+-96 0 rlineto
+0 -796 rlineto
+96 0 rlineto
+0 498 rlineto
+256 -282 rlineto
+112 0 rlineto
+-235 250 rlineto
+248 331 rlineto
+-112 0 rlineto
+} def
+/P$8 {
+0 51 -3 73 rquadto
+34 -20 78 -34 rquadto
+45 -15 76 -15 rquadto
+59 0 89 35 rquadto
+31 34 31 100 rquadto
+0 301 rlineto
+56 12 rlineto
+0 21 rlineto
+-198 0 rlineto
+0 -21 rlineto
+60 -12 rlineto
+0 -295 rlineto
+0 -84 -81 -84 rquadto
+-45 0 -109 14 rquadto
+0 365 rlineto
+62 12 rlineto
+0 21 rlineto
+-201 0 rlineto
+0 -21 rlineto
+57 -12 rlineto
+0 -626 rlineto
+-68 -10 rlineto
+0 -21 rlineto
+150 0 rlineto
+0 198 rlineto
+closepath
+} def
+/P$2j {
+0 -146 -175 -146 rquadto
+-204 0 rlineto
+0 298 rlineto
+207 0 rlineto
+171 0 171 -151 rquadto
+} def
+/P$x {
+206 0 206 151 rquadto
+0 357 rlineto
+54 14 rlineto
+0 39 rlineto
+-201 0 rlineto
+-14 -42 rlineto
+-45 31 -82 42 rquadto
+-35 12 -73 12 rquadto
+-170 0 -170 -165 rquadto
+0 -60 25 -98 rquadto
+25 -37 71 -54 rquadto
+48 -18 150 -20 rquadto
+71 -1 rlineto
+0 -81 rlineto
+0 -100 -81 -100 rquadto
+-50 0 -110 31 rquadto
+-21 68 rlineto
+-39 0 rlineto
+0 -132 rlineto
+89 -14 129 -17 rquadto
+42 -3 85 -3 rquadto
+closepath
+} def
+/P$3f {
+235 0 350 106 rquadto
+114 104 114 315 rquadto
+0 212 -110 323 rquadto
+-109 109 -326 109 rquadto
+-303 -3 rlineto
+-109 0 rlineto
+0 -34 rlineto
+109 -17 rlineto
+0 -750 rlineto
+-109 -15 rlineto
+0 -34 rlineto
+385 0 rlineto
+} def
+/P$1 {
+0 240 -215 240 rquadto
+-103 0 -156 -60 rquadto
+-53 -62 -53 -179 rquadto
+0 -117 53 -178 rquadto
+53 -62 160 -62 rquadto
+104 0 157 60 rquadto
+53 60 53 179 rquadto
+closepath
+} def
+/P$2w {
+0 281 rlineto
+423 0 rlineto
+0 85 rlineto
+-423 0 rlineto
+0 306 rlineto
+-101 0 rlineto
+0 -756 rlineto
+537 0 rlineto
+0 82 rlineto
+-435 0 rlineto
+} def
+/P$33 {
+-82 3 rlineto
+-85 3 -115 32 rquadto
+-29 29 -29 100 rquadto
+0 110 90 110 rquadto
+42 0 73 -9 rquadto
+32 -9 64 -25 rquadto
+0 -212 rlineto
+} def
+/P$2l {
+0 -121 -32 -173 rquadto
+-31 -53 -104 -53 rquadto
+-81 0 -118 56 rquadto
+-37 54 -37 176 rquadto
+0 114 35 168 rquadto
+37 54 120 54 rquadto
+71 0 104 -53 rquadto
+32 -54 32 -176 rquadto
+} def
+/P$1j {
+0 100 40 154 rquadto
+42 53 121 53 rquadto
+62 0 100 -25 rquadto
+37 -25 51 -64 rquadto
+84 25 rlineto
+-51 137 -235 137 rquadto
+-129 0 -196 -76 rquadto
+-67 -76 -67 -228 rquadto
+0 -145 67 -221 rquadto
+67 -76 192 -76 rquadto
+256 0 256 309 rquadto
+0 12 rlineto
+-414 0 rlineto
+closepath
+} def
+/P$1p {
+0 151 -67 226 rquadto
+-67 75 -195 75 rquadto
+-126 0 -192 -76 rquadto
+-64 -78 -64 -225 rquadto
+0 -301 259 -301 rquadto
+134 0 196 73 rquadto
+62 73 62 228 rquadto
+closepath
+} def
+/P$0 {
+-17 0 rlineto
+-239 -562 rlineto
+0 523 rlineto
+87 12 rlineto
+0 26 rlineto
+-223 0 rlineto
+0 -26 rlineto
+84 -12 rlineto
+0 -576 rlineto
+-84 -14 rlineto
+0 -25 rlineto
+198 0 rlineto
+214 498 rlineto
+231 -498 rlineto
+187 0 rlineto
+0 25 rlineto
+-82 14 rlineto
+0 576 rlineto
+82 12 rlineto
+0 26 rlineto
+-265 0 rlineto
+0 -26 rlineto
+89 -12 rlineto
+0 -523 rlineto
+-262 562 rlineto
+} def
+/P$35 {
+0 109 101 109 rquadto
+79 0 146 -20 rquadto
+0 -470 rlineto
+-89 -17 rlineto
+0 -28 rlineto
+193 0 rlineto
+0 553 rlineto
+76 15 rlineto
+0 28 rlineto
+-175 0 rlineto
+-4 -48 rlineto
+-45 25 -104 43 rquadto
+-57 17 -98 17 rquadto
+-151 0 -151 -175 rquadto
+0 -389 rlineto
+-76 -17 rlineto
+0 -28 rlineto
+181 0 rlineto
+0 426 rlineto
+} def
+/P$l {
+-1 0 rlineto
+-234 329 rlineto
+235 0 rlineto
+0 -329 rlineto
+closepath
+} def
+/P$1a {
+0 -109 -26 -159 rquadto
+-26 -50 -87 -50 rquadto
+-21 0 -48 4 rquadto
+-26 4 -43 14 rquadto
+0 421 rlineto
+37 9 92 9 rquadto
+57 0 85 -56 rquadto
+28 -56 28 -184 rquadto
+closepath
+} def
+/P$7 {
+-50 0 -78 42 rquadto
+-26 40 -26 120 rquadto
+196 0 rlineto
+0 -87 -23 -125 rquadto
+-21 -37 -68 -37 rquadto
+closepath
+} def
+/P$2i {
+0 107 -70 171 rquadto
+-68 62 -189 62 rquadto
+-223 0 rlineto
+0 295 rlineto
+-101 0 rlineto
+0 -756 rlineto
+318 0 rlineto
+126 0 195 59 rquadto
+70 59 70 167 rquadto
+closepath
+} def
+/P$m {
+112 0 167 46 rquadto
+56 45 56 140 rquadto
+0 98 -60 151 rquadto
+-59 53 -170 53 rquadto
+-93 0 -165 -20 rquadto
+-6 -137 rlineto
+32 0 rlineto
+21 90 rlineto
+21 12 51 20 rquadto
+29 6 57 6 rquadto
+76 0 112 -35 rquadto
+37 -35 37 -123 rquadto
+0 -59 -15 -90 rquadto
+-15 -31 -50 -45 rquadto
+-34 -15 -92 -15 rquadto
+-45 0 -87 12 rquadto
+-46 0 rlineto
+0 -325 rlineto
+332 0 rlineto
+0 75 rlineto
+-289 0 rlineto
+0 207 rlineto
+53 -10 114 -10 rquadto
+closepath
+} def
+/P$j {
+0 87 -60 137 rquadto
+-59 50 -170 50 rquadto
+-93 0 -176 -20 rquadto
+-4 -137 rlineto
+31 0 rlineto
+21 90 rlineto
+20 10 54 18 rquadto
+34 7 65 7 rquadto
+76 0 112 -34 rquadto
+37 -35 37 -117 rquadto
+0 -64 -34 -96 rquadto
+-34 -34 -104 -37 rquadto
+-70 -4 rlineto
+0 -40 rlineto
+70 -3 rlineto
+54 -3 81 -34 rquadto
+26 -31 26 -95 rquadto
+0 -65 -28 -95 rquadto
+-28 -31 -90 -31 rquadto
+-26 0 -54 7 rquadto
+-28 7 -50 18 rquadto
+-17 79 rlineto
+-32 0 rlineto
+0 -125 rlineto
+48 -12 82 -17 rquadto
+35 -4 71 -4 rquadto
+209 0 209 160 rquadto
+0 68 -37 109 rquadto
+-37 39 -106 50 rquadto
+89 9 131 50 rquadto
+42 40 42 114 rquadto
+closepath
+} def
+/P$29 {
+0 156 -48 279 rquadto
+-48 123 -150 232 rquadto
+-93 0 rlineto
+101 -112 148 -237 rquadto
+46 -125 46 -275 rquadto
+0 -150 -48 -275 rquadto
+-46 -125 -146 -237 rquadto
+93 0 rlineto
+101 109 150 232 rquadto
+48 123 48 278 rquadto
+0 1 rlineto
+} def
+/P$2d {
+0 -73 rlineto
+325 -432 rlineto
+-307 0 rlineto
+0 -75 rlineto
+421 0 rlineto
+0 73 rlineto
+-326 432 rlineto
+337 0 rlineto
+0 75 rlineto
+-450 0 rlineto
+} def
+/P$s {
+0 -67 -26 -98 rquadto
+-26 -32 -79 -32 rquadto
+-51 0 -78 31 rquadto
+-25 31 -25 100 rquadto
+0 68 25 98 rquadto
+25 28 78 28 rquadto
+54 0 79 -29 rquadto
+26 -29 26 -96 rquadto
+closepath
+} def
+/P$1n {
+0 121 31 175 rquadto
+32 51 104 51 rquadto
+82 0 118 -56 rquadto
+37 -57 37 -176 rquadto
+0 -115 -37 -168 rquadto
+-35 -54 -117 -54 rquadto
+-73 0 -106 54 rquadto
+-31 53 -31 175 rquadto
+closepath
+} def
+/P$1s {
+0 -445 rlineto
+0 -62 -3 -135 rquadto
+90 0 rlineto
+4 98 4 118 rquadto
+1 0 rlineto
+23 -75 53 -101 rquadto
+31 -28 85 -28 rquadto
+18 0 39 6 rquadto
+0 87 rlineto
+-20 -4 -51 -4 rquadto
+-60 0 -92 51 rquadto
+-31 51 -31 148 rquadto
+0 303 rlineto
+-96 0 rlineto
+} def
+/P$2a {
+-85 -221 rlineto
+-345 0 rlineto
+-87 221 rlineto
+-106 0 rlineto
+309 -756 rlineto
+117 0 rlineto
+303 756 rlineto
+-104 0 rlineto
+closepath
+} def
+/P$3p {
+-109 -15 rlineto
+0 -34 rlineto
+326 0 rlineto
+0 34 rlineto
+-95 15 rlineto
+0 526 rlineto
+0 85 -26 150 rquadto
+-26 64 -79 101 rquadto
+-53 35 -117 35 rquadto
+-81 0 -132 -18 rquadto
+0 -154 rlineto
+42 0 rlineto
+18 87 rlineto
+12 15 34 23 rquadto
+23 7 50 7 rquadto
+89 0 89 -120 rquadto
+0 -639 rlineto
+} def
+/P$20 {
+0 -756 rlineto
+103 0 rlineto
+0 756 rlineto
+-103 0 rlineto
+} def
+/P$1y {
+0 -581 rlineto
+96 0 rlineto
+0 581 rlineto
+-96 0 rlineto
+} def
+/P$3m {
+-131 15 rlineto
+0 746 rlineto
+168 0 rlineto
+134 0 198 -12 rquadto
+39 -176 rlineto
+40 0 rlineto
+-10 243 rlineto
+-667 0 rlineto
+0 -34 rlineto
+109 -17 rlineto
+0 -750 rlineto
+-109 -15 rlineto
+0 -34 rlineto
+362 0 rlineto
+0 34 rlineto
+} def
+/P$n {
+0 101 -51 157 rquadto
+-51 54 -148 54 rquadto
+-110 0 -168 -85 rquadto
+-57 -85 -57 -246 rquadto
+0 -104 29 -181 rquadto
+31 -78 85 -117 rquadto
+56 -40 128 -40 rquadto
+71 0 142 17 rquadto
+0 112 rlineto
+-31 0 rlineto
+-17 -65 rlineto
+-17 -9 -45 -15 rquadto
+-26 -7 -48 -7 rquadto
+-70 0 -110 70 rquadto
+-39 68 -43 201 rquadto
+79 -42 160 -42 rquadto
+85 0 131 48 rquadto
+45 48 45 140 rquadto
+closepath
+} def
+/P$10 {
+-39 20 rlineto
+-82 42 -148 42 rquadto
+-151 0 -151 -162 rquadto
+0 -350 rlineto
+-54 -14 rlineto
+0 -39 rlineto
+223 0 rlineto
+0 381 rlineto
+0 48 20 76 rquadto
+21 28 60 28 rquadto
+43 0 89 -20 rquadto
+0 -412 rlineto
+-51 -14 rlineto
+0 -39 rlineto
+220 0 rlineto
+0 498 rlineto
+54 14 rlineto
+0 39 rlineto
+-214 0 rlineto
+-9 -48 rlineto
+} def
+/P$38 {
+103 15 rlineto
+0 28 rlineto
+-309 0 rlineto
+0 -28 rlineto
+101 -15 rlineto
+0 -814 rlineto
+-101 -15 rlineto
+0 -28 rlineto
+206 0 rlineto
+0 857 rlineto
+closepath
+} def
+/P$4 {
+0 84 78 84 rquadto
+60 0 112 -15 rquadto
+0 -362 rlineto
+-68 -12 rlineto
+0 -21 rlineto
+150 0 rlineto
+0 425 rlineto
+57 12 rlineto
+0 21 rlineto
+-134 0 rlineto
+-3 -37 rlineto
+-34 18 -79 32 rquadto
+-45 14 -76 14 rquadto
+-117 0 -117 -134 rquadto
+0 -300 rlineto
+-59 -12 rlineto
+0 -21 rlineto
+140 0 rlineto
+0 328 rlineto
+closepath
+} def
+/P$13 {
+-498 0 rlineto
+0 -110 rlineto
+51 -53 93 -96 rquadto
+93 -92 135 -145 rquadto
+43 -53 64 -109 rquadto
+20 -57 20 -129 rquadto
+0 -64 -31 -103 rquadto
+-29 -39 -81 -39 rquadto
+-37 0 -59 7 rquadto
+-20 6 -39 21 rquadto
+-25 114 rlineto
+-51 0 rlineto
+0 -178 rlineto
+46 -10 92 -18 rquadto
+45 -7 96 -7 rquadto
+129 0 198 54 rquadto
+68 53 68 151 rquadto
+0 60 -20 110 rquadto
+-20 50 -65 98 rquadto
+-43 46 -175 154 rquadto
+-50 40 -109 92 rquadto
+385 0 rlineto
+0 132 rlineto
+} def
+/P$f {
+0 339 -215 339 rquadto
+-103 0 -156 -85 rquadto
+-53 -87 -53 -253 rquadto
+0 -162 53 -248 rquadto
+53 -87 160 -87 rquadto
+103 0 156 85 rquadto
+54 84 54 250 rquadto
+closepath
+} def
+/P$b {
+32 0 rlineto
+17 89 rlineto
+17 21 60 40 rquadto
+45 17 87 17 rquadto
+68 0 106 -34 rquadto
+39 -35 39 -96 rquadto
+0 -35 -15 -57 rquadto
+-14 -23 -39 -39 rquadto
+-23 -15 -54 -26 rquadto
+-29 -10 -62 -21 rquadto
+-32 -12 -64 -25 rquadto
+-29 -14 -54 -34 rquadto
+-23 -21 -39 -53 rquadto
+-14 -31 -14 -76 rquadto
+0 -78 57 -121 rquadto
+59 -45 162 -45 rquadto
+79 0 171 21 rquadto
+0 135 rlineto
+-31 0 rlineto
+-17 -79 rlineto
+-50 -37 -123 -37 rquadto
+-64 0 -101 28 rquadto
+-37 26 -37 73 rquadto
+0 31 14 53 rquadto
+15 20 39 35 rquadto
+25 14 56 25 rquadto
+31 10 64 21 rquadto
+32 10 62 26 rquadto
+31 14 54 35 rquadto
+25 21 39 54 rquadto
+15 31 15 78 rquadto
+0 95 -57 146 rquadto
+-57 51 -167 51 rquadto
+-53 0 -106 -9 rquadto
+-53 -9 -95 -25 rquadto
+0 -151 rlineto
+} def
+/P$2e {
+-93 0 -151 -37 rquadto
+-56 -37 -71 -106 rquadto
+96 -14 rlineto
+9 40 42 62 rquadto
+34 21 87 21 rquadto
+145 0 145 -168 rquadto
+0 -93 rlineto
+-1 0 rlineto
+-28 56 -76 84 rquadto
+-46 28 -110 28 rquadto
+-106 0 -156 -70 rquadto
+-50 -71 -50 -223 rquadto
+0 -154 53 -228 rquadto
+54 -73 164 -73 rquadto
+62 0 107 28 rquadto
+45 28 70 81 rquadto
+0 0 rlineto
+0 -17 1 -56 rquadto
+3 -40 4 -43 rquadto
+92 0 rlineto
+-3 29 -3 120 rquadto
+0 443 rlineto
+0 245 -243 245 rquadto
+closepath
+} def
+/P$2u {
+0 -98 rlineto
+87 0 rlineto
+0 98 rlineto
+-87 0 rlineto
+closepath
+} def
+/P$1v {
+0 104 -82 162 rquadto
+-81 57 -229 57 rquadto
+-276 0 -320 -192 rquadto
+100 -20 rlineto
+17 68 71 101 rquadto
+56 31 153 31 rquadto
+98 0 151 -34 rquadto
+54 -34 54 -100 rquadto
+0 -37 -17 -60 rquadto
+-15 -23 -46 -37 rquadto
+-31 -15 -73 -25 rquadto
+-42 -10 -93 -21 rquadto
+-89 -20 -135 -40 rquadto
+-46 -20 -73 -43 rquadto
+-26 -25 -40 -57 rquadto
+-14 -32 -14 -75 rquadto
+0 -96 73 -150 rquadto
+75 -53 214 -53 rquadto
+128 0 195 40 rquadto
+68 39 96 134 rquadto
+-101 17 rlineto
+-15 -59 -62 -85 rquadto
+-46 -28 -129 -28 rquadto
+-90 0 -139 29 rquadto
+-46 29 -46 90 rquadto
+0 34 17 57 rquadto
+18 21 53 37 rquadto
+35 15 140 39 rquadto
+34 7 68 17 rquadto
+34 7 65 20 rquadto
+32 10 59 26 rquadto
+28 15 48 39 rquadto
+20 21 31 53 rquadto
+12 29 12 70 rquadto
+} def
+/P$1e {
+0 -132 -187 -132 rquadto
+-192 0 rlineto
+0 271 rlineto
+200 0 rlineto
+93 0 135 -34 rquadto
+43 -34 43 -104 rquadto
+} def
+/P$1c {
+0 100 -73 156 rquadto
+-73 56 -204 56 rquadto
+-306 0 rlineto
+0 -756 rlineto
+275 0 rlineto
+265 0 265 182 rquadto
+0 67 -37 114 rquadto
+-37 45 -106 60 rquadto
+90 9 139 59 rquadto
+48 50 48 126 rquadto
+closepath
+} def
+/P$9 {
+0 254 rlineto
+107 12 rlineto
+0 26 rlineto
+-279 0 rlineto
+0 -26 rlineto
+76 -12 rlineto
+0 -576 rlineto
+-84 -14 rlineto
+0 -25 rlineto
+492 0 rlineto
+0 156 rlineto
+-32 0 rlineto
+-15 -106 rlineto
+-54 -6 -157 -6 rquadto
+-106 0 rlineto
+0 273 rlineto
+192 0 rlineto
+15 -78 rlineto
+29 0 rlineto
+0 200 rlineto
+-29 0 rlineto
+-15 -78 rlineto
+-192 0 rlineto
+} def
+/P$1w {
+31 -57 75 -84 rquadto
+43 -26 110 -26 rquadto
+93 0 139 46 rquadto
+45 46 45 157 rquadto
+0 387 rlineto
+-96 0 rlineto
+0 -368 rlineto
+0 -60 -12 -90 rquadto
+-10 -29 -37 -43 rquadto
+-25 -14 -70 -14 rquadto
+-68 0 -109 46 rquadto
+-40 46 -40 128 rquadto
+0 342 rlineto
+-96 0 rlineto
+0 -796 rlineto
+96 0 rlineto
+0 207 rlineto
+0 32 -3 67 rquadto
+-1 34 -1 40 rquadto
+1 0 rlineto
+} def
+/P$1b {
+-56 -14 rlineto
+0 -37 rlineto
+225 0 rlineto
+0 201 rlineto
+0 54 -6 110 rquadto
+23 -18 67 -31 rquadto
+45 -14 87 -14 rquadto
+120 0 175 65 rquadto
+54 65 54 209 rquadto
+0 142 -70 223 rquadto
+-70 79 -198 79 rquadto
+-95 0 -278 -40 rquadto
+0 -753 rlineto
+} def
+/P$34 {
+48 -28 103 -45 rquadto
+56 -18 92 -18 rquadto
+78 0 117 45 rquadto
+39 45 39 129 rquadto
+0 393 rlineto
+71 15 rlineto
+0 28 rlineto
+-256 0 rlineto
+0 -28 rlineto
+79 -15 rlineto
+0 -381 rlineto
+0 -53 -26 -82 rquadto
+-25 -31 -79 -31 rquadto
+-56 0 -140 18 rquadto
+0 476 rlineto
+81 15 rlineto
+0 28 rlineto
+-257 0 rlineto
+0 -28 rlineto
+71 -15 rlineto
+0 -507 rlineto
+-71 -17 rlineto
+0 -28 rlineto
+170 0 rlineto
+6 48 rlineto
+} def
+/P$3l {
+0 -137 -40 -198 rquadto
+-39 -62 -123 -62 rquadto
+-84 0 -121 59 rquadto
+-35 59 -35 201 rquadto
+0 143 37 204 rquadto
+37 59 120 59 rquadto
+82 0 123 -62 rquadto
+40 -62 40 -201 rquadto
+closepath
+} def
+/P$12 {
+-220 -515 rlineto
+-37 -14 rlineto
+0 -39 rlineto
+281 0 rlineto
+0 39 rlineto
+-65 15 rlineto
+129 304 rlineto
+115 -306 rlineto
+-65 -14 rlineto
+0 -39 rlineto
+181 0 rlineto
+0 39 rlineto
+-40 12 rlineto
+-217 534 rlineto
+-37 95 -65 137 rquadto
+-28 43 -62 65 rquadto
+-34 21 -78 21 rquadto
+-46 0 -96 -10 rquadto
+0 -142 rlineto
+35 0 rlineto
+25 73 rlineto
+17 14 42 14 rquadto
+23 0 39 -10 rquadto
+17 -10 32 -31 rquadto
+15 -18 28 -48 rquadto
+14 -28 39 -85 rquadto
+} def
+/P$2c {
+0 510 rlineto
+-96 0 rlineto
+0 -510 rlineto
+-81 0 rlineto
+0 -70 rlineto
+81 0 rlineto
+0 -65 rlineto
+0 -79 34 -114 rquadto
+35 -34 107 -34 rquadto
+40 0 68 6 rquadto
+0 73 rlineto
+-25 -4 -43 -4 rquadto
+-37 0 -54 18 rquadto
+-15 18 -15 68 rquadto
+0 51 rlineto
+114 0 rlineto
+0 70 rlineto
+-114 0 rlineto
+} def
+/P$o {
+57 0 84 -39 rquadto
+26 -39 26 -126 rquadto
+0 -79 -25 -115 rquadto
+-25 -35 -79 -35 rquadto
+-67 0 -142 25 rquadto
+0 148 32 220 rquadto
+34 71 103 71 rquadto
+closepath
+} def
+/P$18 {
+112 0 162 59 rquadto
+50 59 50 185 rquadto
+0 48 rlineto
+-289 0 rlineto
+0 9 rlineto
+0 87 14 125 rquadto
+14 35 45 56 rquadto
+32 18 87 18 rquadto
+51 0 129 -17 rquadto
+0 45 rlineto
+-31 18 -82 31 rquadto
+-51 12 -100 12 rquadto
+-135 0 -201 -70 rquadto
+-64 -70 -64 -218 rquadto
+0 -143 60 -214 rquadto
+62 -71 187 -71 rquadto
+closepath
+} def
+/P$u {
+-121 0 -121 170 rquadto
+0 75 29 110 rquadto
+29 34 90 34 rquadto
+62 0 126 -25 rquadto
+0 -150 -29 -220 rquadto
+-29 -70 -95 -70 rquadto
+closepath
+} def
+/P$2f {
+0 -70 -20 -121 rquadto
+-18 -51 -54 -78 rquadto
+-34 -28 -79 -28 rquadto
+-73 0 -107 54 rquadto
+-32 53 -32 173 rquadto
+0 118 31 171 rquadto
+31 51 107 51 rquadto
+45 0 81 -26 rquadto
+35 -26 54 -76 rquadto
+20 -51 20 -120 rquadto
+} def
+/P$3c {
+0 -142 -26 -204 rquadto
+-26 -62 -85 -62 rquadto
+-56 0 -81 59 rquadto
+-25 59 -25 207 rquadto
+0 148 25 209 rquadto
+25 60 81 60 rquadto
+57 0 84 -62 rquadto
+28 -64 28 -207 rquadto
+closepath
+} def
+/P$g {
+0 -157 -29 -226 rquadto
+-29 -70 -95 -70 rquadto
+-62 0 -90 65 rquadto
+-28 65 -28 231 rquadto
+0 165 28 234 rquadto
+28 67 90 67 rquadto
+64 0 93 -70 rquadto
+31 -71 31 -231 rquadto
+closepath
+} def
+/P$1z {
+-67 0 -104 -42 rquadto
+-35 -40 -35 -115 rquadto
+0 -193 rlineto
+0 -62 -28 -92 rquadto
+-28 -31 -87 -34 rquadto
+0 -68 rlineto
+57 -1 85 -32 rquadto
+29 -31 29 -93 rquadto
+0 -193 rlineto
+0 -76 34 -117 rquadto
+35 -40 106 -40 rquadto
+73 0 rlineto
+0 68 rlineto
+-34 0 rlineto
+-48 0 -70 29 rquadto
+-20 28 -20 85 rquadto
+0 190 rlineto
+0 51 -28 89 rquadto
+-28 35 -75 46 rquadto
+0 1 rlineto
+46 10 75 48 rquadto
+28 35 28 87 rquadto
+0 192 rlineto
+0 56 20 85 rquadto
+21 29 70 29 rquadto
+34 0 rlineto
+0 68 rlineto
+-73 0 rlineto
+} def
+/P$p {
+-32 0 rlineto
+0 -154 rlineto
+406 0 rlineto
+0 37 rlineto
+-292 617 rlineto
+-64 0 rlineto
+287 -579 rlineto
+-287 0 rlineto
+-17 79 rlineto
+closepath
+} def
+/P$3i {
+-73 23 -153 40 rquadto
+-79 15 -171 15 rquadto
+-206 0 -321 -110 rquadto
+-115 -112 -115 -317 rquadto
+0 -223 112 -334 rquadto
+112 -110 328 -110 rquadto
+154 0 298 37 rquadto
+0 182 rlineto
+-42 0 rlineto
+-17 -104 rlineto
+-43 -31 -104 -46 rquadto
+-60 -17 -129 -17 rquadto
+-162 0 -237 96 rquadto
+-75 96 -75 295 rquadto
+0 187 76 284 rquadto
+78 96 229 96 rquadto
+53 0 110 -12 rquadto
+59 -12 90 -31 rquadto
+0 -242 rlineto
+-109 -15 rlineto
+0 -34 rlineto
+314 0 rlineto
+0 34 rlineto
+-82 15 rlineto
+0 278 rlineto
+} def
+/P$2q {
+50 0 70 -29 rquadto
+21 -29 21 -85 rquadto
+0 -192 rlineto
+0 -53 28 -89 rquadto
+28 -35 75 -46 rquadto
+0 -1 rlineto
+-45 -10 -75 -46 rquadto
+-28 -35 -28 -89 rquadto
+0 -190 rlineto
+0 -57 -21 -85 rquadto
+-20 -29 -70 -29 rquadto
+-31 0 rlineto
+0 -68 rlineto
+70 0 rlineto
+70 0 106 40 rquadto
+35 40 35 117 rquadto
+0 193 rlineto
+0 62 28 93 rquadto
+28 31 87 32 rquadto
+0 68 rlineto
+-59 1 -87 32 rquadto
+-28 31 -28 93 rquadto
+0 193 rlineto
+0 75 -37 115 rquadto
+-35 42 -104 42 rquadto
+-70 0 rlineto
+0 -68 rlineto
+31 0 rlineto
+} def
+/P$2g {
+0 -184 98 -285 rquadto
+100 -101 278 -101 rquadto
+126 0 204 43 rquadto
+78 42 120 135 rquadto
+-96 28 rlineto
+-32 -64 -89 -93 rquadto
+-56 -29 -140 -29 rquadto
+-131 0 -201 79 rquadto
+-68 78 -68 223 rquadto
+0 142 73 226 rquadto
+73 82 203 82 rquadto
+75 0 139 -21 rquadto
+64 -23 104 -62 rquadto
+0 -135 rlineto
+-226 0 rlineto
+0 -85 rlineto
+320 0 rlineto
+0 260 rlineto
+-59 60 -146 95 rquadto
+-87 32 -190 32 rquadto
+-117 0 -203 -46 rquadto
+-85 -48 -132 -135 rquadto
+-45 -89 -45 -209 rquadto
+} def
+/P$24 {
+-114 0 rlineto
+-212 -581 rlineto
+103 0 rlineto
+128 378 rlineto
+7 21 37 128 rquadto
+18 -64 rlineto
+20 -62 rlineto
+132 -379 rlineto
+103 0 rlineto
+-217 581 rlineto
+} def
+/P$2y {
+0 304 -214 304 rquadto
+-134 0 -179 -101 rquadto
+-3 0 rlineto
+1 4 1 92 rquadto
+0 226 rlineto
+-96 0 rlineto
+0 -690 rlineto
+0 -89 -3 -118 rquadto
+93 0 rlineto
+1 1 1 15 rquadto
+1 12 3 40 rquadto
+1 26 1 37 rquadto
+1 0 rlineto
+26 -54 68 -78 rquadto
+42 -25 110 -25 rquadto
+107 0 160 71 rquadto
+53 71 53 225 rquadto
+closepath
+} def
+/P$37 {
+-65 0 -101 54 rquadto
+-35 53 -35 156 rquadto
+256 0 rlineto
+0 -112 -29 -160 rquadto
+-29 -50 -89 -50 rquadto
+} def
+/P$11 {
+62 -70 112 -101 rquadto
+51 -31 92 -31 rquadto
+31 0 rlineto
+0 201 rlineto
+-32 0 rlineto
+-34 -73 rlineto
+-35 0 -82 15 rquadto
+-46 15 -82 37 rquadto
+0 334 rlineto
+87 14 rlineto
+0 39 rlineto
+-328 0 rlineto
+0 -39 rlineto
+70 -14 rlineto
+0 -445 rlineto
+-70 -14 rlineto
+0 -39 rlineto
+231 0 rlineto
+6 115 rlineto
+} def
+/P$3e {
+0 -178 -96 -270 rquadto
+-95 -92 -275 -92 rquadto
+-114 0 rlineto
+0 734 rlineto
+76 4 181 4 rquadto
+156 0 229 -92 rquadto
+75 -92 75 -284 rquadto
+closepath
+} def
+/P$2n {
+-92 0 -162 -32 rquadto
+-68 -34 -107 -98 rquadto
+-37 -65 -37 -154 rquadto
+0 -481 rlineto
+103 0 rlineto
+0 471 rlineto
+0 104 51 159 rquadto
+53 53 153 53 rquadto
+101 0 157 -56 rquadto
+57 -56 57 -162 rquadto
+0 -465 rlineto
+101 0 rlineto
+0 471 rlineto
+0 92 -39 159 rquadto
+-39 65 -110 101 rquadto
+-70 34 -167 34 rquadto
+} def
+/P$2s {
+53 0 93 -23 rquadto
+42 -23 65 -65 rquadto
+25 -42 25 -87 rquadto
+0 -48 rlineto
+-106 3 rlineto
+-67 0 -103 14 rquadto
+-34 12 -53 39 rquadto
+-18 26 -18 70 rquadto
+0 46 25 73 rquadto
+25 25 71 25 rquadto
+closepath
+} def
+/P$i {
+-401 0 rlineto
+0 -71 rlineto
+90 -82 rlineto
+87 -76 128 -123 rquadto
+42 -46 59 -96 rquadto
+18 -51 18 -115 rquadto
+0 -64 -29 -96 rquadto
+-28 -34 -93 -34 rquadto
+-26 0 -54 7 rquadto
+-26 7 -46 18 rquadto
+-17 79 rlineto
+-32 0 rlineto
+0 -125 rlineto
+89 -21 151 -21 rquadto
+107 0 160 45 rquadto
+54 43 54 126 rquadto
+0 54 -21 103 rquadto
+-21 48 -65 96 rquadto
+-43 46 -145 134 rquadto
+-43 35 -92 81 rquadto
+337 0 rlineto
+0 75 rlineto
+closepath
+} def
+/P$1h {
+0 117 35 173 rquadto
+35 54 109 54 rquadto
+51 0 85 -28 rquadto
+35 -28 43 -85 rquadto
+96 6 rlineto
+-10 84 -71 134 rquadto
+-59 50 -151 50 rquadto
+-121 0 -185 -76 rquadto
+-64 -78 -64 -225 rquadto
+0 -146 64 -223 rquadto
+64 -78 184 -78 rquadto
+89 0 148 46 rquadto
+59 45 73 126 rquadto
+-98 7 rlineto
+-7 -48 -39 -76 rquadto
+-29 -28 -85 -28 rquadto
+-76 0 -110 51 rquadto
+-34 50 -34 170 rquadto
+} def
+/P$2x {
+-301 -365 rlineto
+-100 75 rlineto
+0 290 rlineto
+-101 0 rlineto
+0 -756 rlineto
+101 0 rlineto
+0 378 rlineto
+365 -378 rlineto
+120 0 rlineto
+-321 328 rlineto
+365 428 rlineto
+-128 0 rlineto
+} def
+/P$2h {
+0 -504 rlineto
+0 -84 4 -160 rquadto
+-26 95 -48 150 rquadto
+-195 515 rlineto
+-71 0 rlineto
+-198 -515 rlineto
+-29 -90 rlineto
+-17 -59 rlineto
+1 59 rlineto
+1 101 rlineto
+0 504 rlineto
+-90 0 rlineto
+0 -756 rlineto
+134 0 rlineto
+201 523 rlineto
+10 32 20 68 rquadto
+10 35 14 51 rquadto
+3 -20 17 -64 rquadto
+14 -43 18 -56 rquadto
+196 -523 rlineto
+132 0 rlineto
+0 756 rlineto
+-92 0 rlineto
+} def
+/P$39 {
+120 12 rlineto
+0 23 rlineto
+-315 0 rlineto
+0 -23 rlineto
+120 -12 rlineto
+0 -479 rlineto
+-118 42 rlineto
+0 -23 rlineto
+171 -96 rlineto
+21 0 rlineto
+0 557 rlineto
+} def
+/P$3a {
+0 306 -193 306 rquadto
+-92 0 -140 -78 rquadto
+-46 -79 -46 -228 rquadto
+0 -146 46 -223 rquadto
+48 -78 145 -78 rquadto
+92 0 140 76 rquadto
+48 76 48 225 rquadto
+closepath
+} def
+/P$3d {
+-360 0 rlineto
+0 -64 rlineto
+82 -75 rlineto
+78 -68 114 -110 rquadto
+37 -43 53 -89 rquadto
+17 -45 17 -103 rquadto
+0 -57 -26 -87 rquadto
+-25 -29 -84 -29 rquadto
+-23 0 -48 6 rquadto
+-25 6 -43 17 rquadto
+-14 71 rlineto
+-29 0 rlineto
+0 -112 rlineto
+79 -18 135 -18 rquadto
+96 0 145 40 rquadto
+48 39 48 112 rquadto
+0 50 -20 93 rquadto
+-18 43 -57 87 rquadto
+-39 42 -131 120 rquadto
+-39 32 -82 73 rquadto
+303 0 rlineto
+0 67 rlineto
+} def
+/P$15 {
+0 -182 -20 -262 rquadto
+-20 -79 -64 -79 rquadto
+-43 0 -62 78 rquadto
+-18 76 -18 264 rquadto
+0 192 18 271 rquadto
+18 78 62 78 rquadto
+42 0 62 -81 rquadto
+21 -81 21 -268 rquadto
+} def
+/P$d {
+-64 3 rlineto
+-65 1 -89 25 rquadto
+-23 21 -23 76 rquadto
+0 85 70 85 rquadto
+32 0 56 -7 rquadto
+25 -7 50 -18 rquadto
+0 -164 rlineto
+closepath
+} def
+/P$c {
+75 0 110 31 rquadto
+35 29 35 93 rquadto
+0 309 rlineto
+56 12 rlineto
+0 21 rlineto
+-125 0 rlineto
+-9 -45 rlineto
+-56 54 -142 54 rquadto
+-117 0 -117 -135 rquadto
+0 -46 17 -76 rquadto
+17 -29 56 -45 rquadto
+39 -15 114 -17 rquadto
+68 -3 rlineto
+0 -71 rlineto
+0 -46 -17 -68 rquadto
+-17 -23 -53 -23 rquadto
+-50 0 -90 23 rquadto
+-15 57 rlineto
+-28 0 rlineto
+0 -100 rlineto
+79 -17 139 -17 rquadto
+closepath
+} def
+/P$1k {
+-7 -92 -46 -134 rquadto
+-37 -42 -110 -42 rquadto
+-70 0 -110 46 rquadto
+-40 46 -43 129 rquadto
+312 0 rlineto
+} def
+/P$16 {
+0 107 -76 167 rquadto
+-76 59 -214 59 rquadto
+-109 0 -217 -25 rquadto
+-6 -189 rlineto
+53 0 rlineto
+31 125 rlineto
+51 29 106 29 rquadto
+71 0 110 -45 rquadto
+40 -46 40 -128 rquadto
+0 -70 -32 -107 rquadto
+-31 -37 -103 -42 rquadto
+-68 -4 rlineto
+0 -70 rlineto
+65 -4 rlineto
+53 -4 78 -39 rquadto
+25 -34 25 -104 rquadto
+0 -65 -29 -103 rquadto
+-29 -37 -84 -37 rquadto
+-31 0 -51 9 rquadto
+-20 9 -39 20 rquadto
+-25 114 rlineto
+-51 0 rlineto
+0 -178 rlineto
+60 -15 103 -20 rquadto
+43 -6 85 -6 rquadto
+264 0 264 193 rquadto
+0 79 -42 129 rquadto
+-42 48 -120 60 rquadto
+198 23 198 196 rquadto
+closepath
+} def
+/P$2v {
+0 -98 rlineto
+89 0 rlineto
+0 98 rlineto
+-89 0 rlineto
+} def
+/P$3o {
+0 89 -56 134 rquadto
+-56 45 -165 45 rquadto
+-45 0 -100 -9 rquadto
+-53 -9 -82 -20 rquadto
+0 -146 rlineto
+28 0 rlineto
+31 82 rlineto
+48 43 123 43 rquadto
+123 0 123 -104 rquadto
+0 -78 -96 -110 rquadto
+-56 -18 rlineto
+-64 -20 -93 -42 rquadto
+-29 -21 -45 -53 rquadto
+-15 -31 -15 -76 rquadto
+0 -78 53 -123 rquadto
+54 -45 145 -45 rquadto
+65 0 164 20 rquadto
+0 129 rlineto
+-29 0 rlineto
+-26 -68 rlineto
+-34 -31 -106 -31 rquadto
+-51 0 -78 26 rquadto
+-26 25 -26 68 rquadto
+0 35 23 60 rquadto
+25 23 75 40 rquadto
+92 31 120 46 rquadto
+29 14 50 35 rquadto
+20 20 31 48 rquadto
+10 26 10 67 rquadto
+closepath
+} def
+/P$r {
+0 -78 -31 -112 rquadto
+-29 -35 -95 -35 rquadto
+-64 0 -92 34 rquadto
+-28 32 -28 114 rquadto
+0 82 28 115 rquadto
+29 32 92 32 rquadto
+65 0 95 -34 rquadto
+31 -34 31 -114 rquadto
+closepath
+} def
+/P$2b {
+-4 15 rlineto
+-12 43 -39 114 rquadto
+-96 248 rlineto
+282 0 rlineto
+-96 -250 rlineto
+-15 -35 -29 -82 rquadto
+-15 -45 rlineto
+} def
+/P$2r {
+0 -756 rlineto
+101 0 rlineto
+0 671 rlineto
+382 0 rlineto
+0 84 rlineto
+-484 0 rlineto
+} def
+/P$3g {
+0 28 -20 48 rquadto
+-20 20 -48 20 rquadto
+-28 0 -48 -20 rquadto
+-20 -20 -20 -48 rquadto
+0 -28 20 -48 rquadto
+20 -20 48 -20 rquadto
+28 0 48 20 rquadto
+20 20 20 48 rquadto
+closepath
+} def
+/P$e {
+0 87 -60 137 rquadto
+-59 50 -170 50 rquadto
+-93 0 -176 -20 rquadto
+-4 -137 rlineto
+31 0 rlineto
+21 90 rlineto
+20 10 54 18 rquadto
+34 7 65 7 rquadto
+76 0 112 -34 rquadto
+37 -35 37 -117 rquadto
+0 -64 -34 -96 rquadto
+-34 -34 -104 -37 rquadto
+-70 -4 rlineto
+0 -40 rlineto
+70 -3 rlineto
+54 -3 81 -34 rquadto
+26 -31 26 -95 rquadto
+0 -65 -28 -95 rquadto
+-28 -31 -90 -31 rquadto
+-26 0 -54 7 rquadto
+-28 7 -50 18 rquadto
+-17 79 rlineto
+-32 0 rlineto
+0 -125 rlineto
+48 -12 82 -17 rquadto
+35 -4 71 -4 rquadto
+209 0 209 160 rquadto
+0 68 -37 109 rquadto
+-37 39 -106 50 rquadto
+89 9 131 50 rquadto
+42 40 42 114 rquadto
+} def
+/P$22 {
+0 368 rlineto
+0 57 10 89 rquadto
+10 31 35 45 rquadto
+25 14 73 14 rquadto
+68 0 109 -46 rquadto
+40 -48 40 -132 rquadto
+0 -337 rlineto
+96 0 rlineto
+0 457 rlineto
+0 101 3 123 rquadto
+-92 0 rlineto
+0 -3 -1 -14 rquadto
+0 -12 -1 -26 rquadto
+0 -15 0 -59 rquadto
+-1 0 rlineto
+-34 60 -78 85 rquadto
+-43 25 -107 25 rquadto
+-96 0 -140 -46 rquadto
+-43 -48 -43 -157 rquadto
+0 -387 rlineto
+96 0 rlineto
+} def
+/P$5 {
+-25 0 rlineto
+-170 -451 rlineto
+-173 451 rlineto
+-26 0 rlineto
+-217 -631 rlineto
+-56 -14 rlineto
+0 -25 rlineto
+250 0 rlineto
+0 25 rlineto
+-96 14 rlineto
+156 460 rlineto
+176 -454 rlineto
+21 0 rlineto
+168 454 rlineto
+148 -460 rlineto
+-101 -14 rlineto
+0 -25 rlineto
+217 0 rlineto
+0 25 rlineto
+-57 14 rlineto
+-214 631 rlineto
+closepath
+} def
+/P$1m {
+-26 56 -71 81 rquadto
+-43 23 -109 23 rquadto
+-109 0 -160 -73 rquadto
+-51 -75 -51 -225 rquadto
+0 -304 212 -304 rquadto
+67 0 110 25 rquadto
+43 23 70 76 rquadto
+1 0 rlineto
+-1 -65 rlineto
+0 -240 rlineto
+96 0 rlineto
+0 676 rlineto
+0 90 3 120 rquadto
+-92 0 rlineto
+-1 -9 -3 -39 rquadto
+-1 -31 -1 -54 rquadto
+-3 0 rlineto
+closepath
+} def
+/P$3j {
+0 160 rlineto
+-28 0 rlineto
+-35 -70 rlineto
+-32 0 -76 9 rquadto
+-42 7 -75 21 rquadto
+0 446 rlineto
+103 15 rlineto
+0 28 rlineto
+-282 0 rlineto
+0 -28 rlineto
+75 -15 rlineto
+0 -507 rlineto
+-75 -17 rlineto
+0 -28 rlineto
+173 0 rlineto
+6 75 rlineto
+37 -32 101 -60 rquadto
+65 -29 104 -29 rquadto
+9 0 rlineto
+} def
+/P$q {
+0 53 -26 90 rquadto
+-26 37 -70 57 rquadto
+56 20 85 64 rquadto
+31 43 31 106 rquadto
+0 92 -53 139 rquadto
+-51 46 -162 46 rquadto
+-209 0 -209 -185 rquadto
+0 -65 31 -107 rquadto
+31 -42 84 -62 rquadto
+-42 -20 -68 -56 rquadto
+-26 -37 -26 -92 rquadto
+0 -81 50 -125 rquadto
+50 -45 143 -45 rquadto
+90 0 140 45 rquadto
+50 43 50 125 rquadto
+closepath
+} def
+/P$1l {
+0 -368 rlineto
+0 -57 -12 -89 rquadto
+-10 -31 -35 -45 rquadto
+-23 -14 -71 -14 rquadto
+-70 0 -110 48 rquadto
+-39 46 -39 131 rquadto
+0 337 rlineto
+-96 0 rlineto
+0 -457 rlineto
+0 -101 -3 -123 rquadto
+90 0 rlineto
+1 3 1 15 rquadto
+0 10 0 26 rquadto
+1 14 3 57 rquadto
+1 0 rlineto
+32 -60 76 -85 rquadto
+43 -25 109 -25 rquadto
+95 0 139 48 rquadto
+45 46 45 156 rquadto
+0 387 rlineto
+-96 0 rlineto
+} def
+/P$28 {
+0 121 31 175 rquadto
+32 51 104 51 rquadto
+82 0 118 -56 rquadto
+37 -57 37 -176 rquadto
+0 -115 -37 -168 rquadto
+-35 -54 -117 -54 rquadto
+-73 0 -106 54 rquadto
+-31 53 -31 175 rquadto
+} def
+/P$2t {
+-192 0 -228 -198 rquadto
+100 -17 rlineto
+9 62 43 98 rquadto
+34 34 84 34 rquadto
+56 0 87 -39 rquadto
+32 -39 32 -112 rquadto
+0 -450 rlineto
+-145 0 rlineto
+0 -82 rlineto
+248 0 rlineto
+0 531 rlineto
+0 109 -60 173 rquadto
+-59 62 -162 62 rquadto
+} def
+/P$31 {
+48 -26 101 -45 rquadto
+53 -18 93 -18 rquadto
+43 0 81 17 rquadto
+37 15 56 51 rquadto
+48 -26 114 -46 rquadto
+65 -21 109 -21 rquadto
+151 0 151 175 rquadto
+0 393 rlineto
+76 15 rlineto
+0 28 rlineto
+-270 0 rlineto
+0 -28 rlineto
+89 -15 rlineto
+0 -381 rlineto
+0 -109 -101 -109 rquadto
+-17 0 -39 3 rquadto
+-21 1 -43 4 rquadto
+-21 3 -42 7 rquadto
+-20 4 -32 6 rquadto
+10 34 10 75 rquadto
+0 393 rlineto
+89 15 rlineto
+0 28 rlineto
+-282 0 rlineto
+0 -28 rlineto
+87 -15 rlineto
+0 -381 rlineto
+0 -53 -26 -81 rquadto
+-26 -28 -81 -28 rquadto
+-56 0 -139 18 rquadto
+0 471 rlineto
+90 15 rlineto
+0 28 rlineto
+-271 0 rlineto
+0 -28 rlineto
+76 -15 rlineto
+0 -507 rlineto
+-76 -17 rlineto
+0 -28 rlineto
+175 0 rlineto
+4 48 rlineto
+} def
+/P$2 {
+0 -106 -31 -153 rquadto
+-29 -48 -95 -48 rquadto
+-64 0 -92 46 rquadto
+-28 45 -28 154 rquadto
+0 109 28 156 rquadto
+29 46 92 46 rquadto
+64 0 95 -48 rquadto
+31 -48 31 -154 rquadto
+closepath
+} def
+/P$v {
+134 12 rlineto
+0 26 rlineto
+-353 0 rlineto
+0 -26 rlineto
+134 -12 rlineto
+0 -534 rlineto
+-131 46 rlineto
+0 -25 rlineto
+190 -109 rlineto
+25 0 rlineto
+0 621 rlineto
+} def
+/P$w {
+-101 -15 rlineto
+0 -42 rlineto
+375 0 rlineto
+0 42 rlineto
+-89 15 rlineto
+0 475 rlineto
+0 126 -70 196 rquadto
+-70 68 -200 68 rquadto
+-43 0 -87 -6 rquadto
+-42 -4 -67 -12 rquadto
+0 -178 rlineto
+53 0 rlineto
+17 104 rlineto
+10 14 31 21 rquadto
+20 7 45 7 rquadto
+40 0 67 -28 rquadto
+26 -28 26 -84 rquadto
+0 -565 rlineto
+} def
+/P$26 {
+0 117 -46 204 rquadto
+-45 87 -129 134 rquadto
+-82 46 -192 46 rquadto
+-282 0 rlineto
+0 -756 rlineto
+250 0 rlineto
+192 0 296 96 rquadto
+104 95 104 273 rquadto
+closepath
+} def
+/P$3n {
+243 -264 rlineto
+-62 -17 rlineto
+0 -28 rlineto
+210 0 rlineto
+0 28 rlineto
+-73 15 rlineto
+-170 173 rlineto
+218 335 rlineto
+64 15 rlineto
+0 28 rlineto
+-243 0 rlineto
+0 -28 rlineto
+54 -15 rlineto
+-164 -257 rlineto
+-78 85 rlineto
+0 171 rlineto
+62 15 rlineto
+0 28 rlineto
+-243 0 rlineto
+0 -28 rlineto
+75 -15 rlineto
+0 -814 rlineto
+-87 -15 rlineto
+0 -28 rlineto
+193 0 rlineto
+0 614 rlineto
+} def
+/P$17 {
+0 276 rlineto
+129 17 rlineto
+0 42 rlineto
+-407 0 rlineto
+0 -42 rlineto
+93 -17 rlineto
+0 -668 rlineto
+-101 -15 rlineto
+0 -42 rlineto
+654 0 rlineto
+0 210 rlineto
+-54 0 rlineto
+-18 -137 rlineto
+-28 -4 -95 -6 rquadto
+-65 -3 -103 -3 rquadto
+-96 0 rlineto
+0 321 rlineto
+190 0 rlineto
+18 -100 rlineto
+51 0 rlineto
+0 265 rlineto
+-51 0 rlineto
+-18 -101 rlineto
+-190 0 rlineto
+} def
+/P$2m {
+0 82 -62 128 rquadto
+-62 43 -173 43 rquadto
+-109 0 -168 -35 rquadto
+-57 -35 -75 -110 rquadto
+84 -17 rlineto
+12 46 51 68 rquadto
+39 21 107 21 rquadto
+73 0 106 -21 rquadto
+34 -23 34 -68 rquadto
+0 -34 -23 -54 rquadto
+-23 -21 -76 -35 rquadto
+-68 -18 rlineto
+-82 -21 -118 -42 rquadto
+-34 -20 -54 -50 rquadto
+-20 -29 -20 -73 rquadto
+0 -79 56 -120 rquadto
+57 -42 165 -42 rquadto
+96 0 153 34 rquadto
+56 34 71 107 rquadto
+-87 10 rlineto
+-7 -39 -43 -59 rquadto
+-34 -20 -93 -20 rquadto
+-65 0 -96 20 rquadto
+-29 18 -29 59 rquadto
+0 25 12 42 rquadto
+12 15 37 26 rquadto
+25 10 106 31 rquadto
+76 18 110 35 rquadto
+34 15 53 35 rquadto
+20 20 31 46 rquadto
+10 25 10 57 rquadto
+} def
+/P$1t {
+0 -796 rlineto
+96 0 rlineto
+0 796 rlineto
+-96 0 rlineto
+} def
+/P$27 {
+0 -140 -78 -214 rquadto
+-76 -75 -221 -75 rquadto
+-146 0 rlineto
+0 592 rlineto
+168 0 rlineto
+84 0 146 -35 rquadto
+62 -35 96 -104 rquadto
+34 -68 34 -162 rquadto
+} def
+/P$3b {
+0 -142 -26 -204 rquadto
+-26 -62 -85 -62 rquadto
+-56 0 -81 59 rquadto
+-25 59 -25 207 rquadto
+0 148 25 209 rquadto
+25 60 81 60 rquadto
+57 0 84 -62 rquadto
+28 -64 28 -207 rquadto
+} def
+/P$2k {
+0 304 -214 304 rquadto
+-65 0 -109 -23 rquadto
+-43 -25 -71 -78 rquadto
+0 0 rlineto
+0 17 -3 51 rquadto
+-1 34 -3 39 rquadto
+-93 0 rlineto
+3 -29 3 -120 rquadto
+0 -676 rlineto
+96 0 rlineto
+0 226 rlineto
+0 35 -1 82 rquadto
+1 0 rlineto
+28 -56 71 -79 rquadto
+43 -25 109 -25 rquadto
+110 0 162 75 rquadto
+51 73 51 223 rquadto
+closepath
+} def
+/P$1g {
+53 0 93 -23 rquadto
+42 -23 65 -65 rquadto
+25 -42 25 -87 rquadto
+0 -48 rlineto
+-106 3 rlineto
+-67 0 -103 14 rquadto
+-34 12 -53 39 rquadto
+-18 26 -18 70 rquadto
+0 46 25 73 rquadto
+25 25 71 25 rquadto
+} def
+/P$2o {
+-196 -314 rlineto
+-235 0 rlineto
+0 314 rlineto
+-101 0 rlineto
+0 -756 rlineto
+356 0 rlineto
+126 0 196 57 rquadto
+70 56 70 157 rquadto
+0 84 -50 142 rquadto
+-48 57 -135 71 rquadto
+215 326 rlineto
+-118 0 rlineto
+closepath
+} def
+/P$23 {
+50 0 70 -29 rquadto
+21 -29 21 -85 rquadto
+0 -192 rlineto
+0 -53 28 -89 rquadto
+28 -35 75 -46 rquadto
+0 -1 rlineto
+-45 -10 -75 -46 rquadto
+-28 -35 -28 -89 rquadto
+0 -190 rlineto
+0 -57 -21 -85 rquadto
+-20 -29 -70 -29 rquadto
+-31 0 rlineto
+0 -68 rlineto
+70 0 rlineto
+70 0 106 40 rquadto
+35 40 35 117 rquadto
+0 193 rlineto
+0 62 28 93 rquadto
+28 31 87 32 rquadto
+0 68 rlineto
+-59 1 -87 32 rquadto
+-28 31 -28 93 rquadto
+0 193 rlineto
+0 75 -37 115 rquadto
+-35 42 -104 42 rquadto
+-70 0 rlineto
+0 -68 rlineto
+31 0 rlineto
+closepath
+} def
+/P$1q {
+0 -120 -35 -175 rquadto
+-35 -54 -120 -54 rquadto
+-84 0 -121 56 rquadto
+-37 54 -37 173 rquadto
+0 114 35 171 rquadto
+37 57 118 57 rquadto
+85 0 123 -54 rquadto
+37 -56 37 -175 rquadto
+} def
+/P$z {
+39 -20 rlineto
+82 -42 148 -42 rquadto
+151 0 151 162 rquadto
+0 350 rlineto
+56 14 rlineto
+0 39 rlineto
+-275 0 rlineto
+0 -39 rlineto
+50 -14 rlineto
+0 -326 rlineto
+0 -50 -21 -76 rquadto
+-20 -28 -57 -28 rquadto
+-45 0 -89 20 rquadto
+0 410 rlineto
+50 14 rlineto
+0 39 rlineto
+-273 0 rlineto
+0 -39 rlineto
+53 -14 rlineto
+0 -445 rlineto
+-53 -14 rlineto
+0 -39 rlineto
+214 0 rlineto
+7 48 rlineto
+} def
+/P$25 {
+0 -154 48 -278 rquadto
+48 -123 150 -232 rquadto
+92 0 rlineto
+-100 110 -146 237 rquadto
+-46 125 -46 275 rquadto
+0 148 45 273 rquadto
+46 125 148 239 rquadto
+-92 0 rlineto
+-101 -109 -150 -232 rquadto
+-48 -125 -48 -279 rquadto
+0 -1 rlineto
+} def
+/P$3 {
+0 -26 rlineto
+104 -12 rlineto
+0 -573 rlineto
+-25 0 rlineto
+-123 0 -168 9 rquadto
+-12 101 rlineto
+-32 0 rlineto
+0 -153 rlineto
+575 0 rlineto
+0 153 rlineto
+-32 0 rlineto
+-12 -101 rlineto
+-15 -3 -65 -6 rquadto
+-48 -3 -106 -3 rquadto
+-25 0 rlineto
+0 573 rlineto
+104 12 rlineto
+0 26 rlineto
+-303 0 rlineto
+} def
+/P$3h {
+101 15 rlineto
+0 28 rlineto
+-309 0 rlineto
+0 -28 rlineto
+101 -15 rlineto
+0 -507 rlineto
+-84 -17 rlineto
+0 -28 rlineto
+190 0 rlineto
+0 553 rlineto
+} def
+/P$t {
+0 -98 54 -153 rquadto
+54 -54 156 -54 rquadto
+110 0 162 81 rquadto
+53 79 53 251 rquadto
+0 165 -67 253 rquadto
+-67 85 -187 85 rquadto
+-79 0 -146 -15 rquadto
+0 -114 rlineto
+32 0 rlineto
+15 70 rlineto
+15 7 42 14 rquadto
+26 4 53 4 rquadto
+78 0 120 -68 rquadto
+42 -68 46 -201 rquadto
+-75 42 -151 42 rquadto
+-85 0 -135 -51 rquadto
+-48 -51 -48 -143 rquadto
+closepath
+} def
+/P$32 {
+96 0 142 40 rquadto
+46 39 46 121 rquadto
+0 403 rlineto
+75 15 rlineto
+0 28 rlineto
+-164 0 rlineto
+-12 -59 rlineto
+-71 71 -184 71 rquadto
+-153 0 -153 -178 rquadto
+0 -59 23 -98 rquadto
+23 -39 73 -59 rquadto
+51 -20 148 -21 rquadto
+89 -3 rlineto
+0 -93 rlineto
+0 -60 -23 -90 rquadto
+-21 -29 -68 -29 rquadto
+-64 0 -115 31 rquadto
+-21 73 rlineto
+-35 0 rlineto
+0 -129 rlineto
+103 -21 181 -21 rquadto
+closepath
+} def
+/P$1f {
+-87 0 -131 -45 rquadto
+-43 -46 -43 -128 rquadto
+0 -90 59 -137 rquadto
+59 -48 190 -53 rquadto
+131 -1 rlineto
+0 -31 rlineto
+0 -71 -31 -101 rquadto
+-29 -31 -93 -31 rquadto
+-64 0 -93 21 rquadto
+-29 21 -35 70 rquadto
+-101 -7 rlineto
+25 -157 234 -157 rquadto
+109 0 164 50 rquadto
+56 50 56 145 rquadto
+0 250 rlineto
+0 43 10 65 rquadto
+10 21 42 21 rquadto
+14 0 32 -4 rquadto
+0 60 rlineto
+-37 7 -75 7 rquadto
+-54 0 -79 -28 rquadto
+-23 -28 -26 -87 rquadto
+-3 0 rlineto
+-37 65 -87 93 rquadto
+-48 28 -118 28 rquadto
+closepath
+} def
+/P$14 {
+0 409 -257 409 rquadto
+-125 0 -189 -104 rquadto
+-62 -104 -62 -304 rquadto
+0 -193 62 -296 rquadto
+64 -104 193 -104 rquadto
+123 0 187 103 rquadto
+65 101 65 298 rquadto
+closepath
+} def
+/P$36 {
+0 10 rlineto
+0 87 18 135 rquadto
+18 48 59 75 rquadto
+40 25 106 25 rquadto
+34 0 81 -4 rquadto
+46 -6 76 -14 rquadto
+0 35 rlineto
+-29 18 -82 34 rquadto
+-51 14 -106 14 rquadto
+-139 0 -203 -75 rquadto
+-64 -75 -64 -240 rquadto
+0 -156 64 -232 rquadto
+65 -76 187 -76 rquadto
+228 0 228 260 rquadto
+0 51 rlineto
+-365 0 rlineto
+closepath
+} def
+/P$y {
+-50 1 rlineto
+-56 3 -78 31 rquadto
+-21 26 -21 87 rquadto
+0 50 17 73 rquadto
+17 23 45 23 rquadto
+40 0 87 -20 rquadto
+0 -196 rlineto
+} def
+/P$1x {
+0 -92 rlineto
+96 0 rlineto
+0 92 rlineto
+-96 0 rlineto
+closepath
+} def
+/P$3k {
+0 314 -278 314 rquadto
+-135 0 -204 -79 rquadto
+-67 -81 -67 -234 rquadto
+0 -151 67 -231 rquadto
+68 -79 209 -79 rquadto
+135 0 204 78 rquadto
+68 78 68 232 rquadto
+closepath
+} def
+/P$21 {
+0 -368 rlineto
+0 -84 -23 -115 rquadto
+-23 -32 -82 -32 rquadto
+-62 0 -98 46 rquadto
+-35 46 -35 132 rquadto
+0 337 rlineto
+-95 0 rlineto
+0 -457 rlineto
+0 -101 -3 -123 rquadto
+90 0 rlineto
+1 3 1 15 rquadto
+0 10 0 26 rquadto
+1 14 3 57 rquadto
+1 0 rlineto
+31 -62 70 -85 rquadto
+40 -25 100 -25 rquadto
+65 0 103 26 rquadto
+39 26 54 84 rquadto
+1 0 rlineto
+29 -59 71 -84 rquadto
+43 -26 103 -26 rquadto
+89 0 128 48 rquadto
+40 46 40 156 rquadto
+0 387 rlineto
+-95 0 rlineto
+0 -368 rlineto
+0 -84 -23 -115 rquadto
+-23 -32 -82 -32 rquadto
+-64 0 -100 46 rquadto
+-34 46 -34 132 rquadto
+0 337 rlineto
+-95 0 rlineto
+} def
+/P$19 {
+-34 0 -51 37 rquadto
+-17 37 -17 134 rquadto
+126 0 rlineto
+0 -78 -4 -109 rquadto
+-4 -32 -18 -46 rquadto
+-12 -15 -34 -15 rquadto
+} def
+/P$3q {
+103 15 rlineto
+0 28 rlineto
+-309 0 rlineto
+0 -28 rlineto
+101 -15 rlineto
+0 -814 rlineto
+-101 -15 rlineto
+0 -28 rlineto
+206 0 rlineto
+0 857 rlineto
+} def
+/P$1r {
+-46 14 -96 14 rquadto
+-115 0 -115 -132 rquadto
+0 -387 rlineto
+-67 0 rlineto
+0 -70 rlineto
+70 0 rlineto
+28 -129 rlineto
+65 0 rlineto
+0 129 rlineto
+106 0 rlineto
+0 70 rlineto
+-106 0 rlineto
+0 367 rlineto
+0 42 12 59 rquadto
+14 15 48 15 rquadto
+18 0 54 -6 rquadto
+0 70 rlineto
+} def
+/P$1o {
+-125 0 -195 81 rquadto
+-70 81 -70 221 rquadto
+0 139 73 223 rquadto
+73 84 196 84 rquadto
+159 0 239 -157 rquadto
+84 42 rlineto
+-46 98 -132 150 rquadto
+-84 50 -195 50 rquadto
+-114 0 -198 -46 rquadto
+-82 -48 -126 -135 rquadto
+-43 -89 -43 -209 rquadto
+0 -181 96 -284 rquadto
+98 -103 271 -103 rquadto
+120 0 201 48 rquadto
+81 46 118 139 rquadto
+-96 32 rlineto
+-26 -65 -85 -100 rquadto
+-57 -35 -137 -35 rquadto
+} def
+/P$2z {
+0 -121 -32 -173 rquadto
+-32 -53 -104 -53 rquadto
+-56 0 -89 25 rquadto
+-32 23 -50 75 rquadto
+-17 51 -17 132 rquadto
+0 115 35 170 rquadto
+37 53 120 53 rquadto
+71 0 104 -53 rquadto
+32 -53 32 -176 rquadto
+} def
+/P$6 {
+0 9 rlineto
+0 67 14 104 rquadto
+15 37 46 57 rquadto
+31 18 81 18 rquadto
+26 0 62 -4 rquadto
+35 -4 59 -9 rquadto
+0 26 rlineto
+-23 15 -64 26 rquadto
+-39 10 -81 10 rquadto
+-107 0 -157 -57 rquadto
+-48 -57 -48 -184 rquadto
+0 -120 50 -179 rquadto
+50 -59 143 -59 rquadto
+176 0 176 201 rquadto
+0 39 rlineto
+-282 0 rlineto
+closepath
+} def
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+3720 2533 moveto
+P$0
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+4662 2302 moveto
+P$1
+4573 2302 moveto
+P$2
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+11603 2533 moveto
+P$3
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+12203 2402 moveto
+P$4
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+20020 2549 moveto
+P$5
+20376 2302 moveto
+P$6
+20482 2100 moveto
+P$7
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+27603 2533 moveto
+P$3
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+28209 2038 moveto
+P$8
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+35757 2239 moveto
+P$9
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+36475 2061 moveto
+P$a
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+43567 2357 moveto
+P$b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+44326 2064 moveto
+P$c
+44392 2299 moveto
+P$d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+51517 2357 moveto
+P$b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+52203 2402 moveto
+P$4
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+59720 2533 moveto
+P$0
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+60662 2302 moveto
+P$1
+60573 2302 moveto
+P$2
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+67603 2533 moveto
+P$3
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+68203 2402 moveto
+P$4
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+76020 2549 moveto
+P$5
+76376 2302 moveto
+P$6
+76482 2100 moveto
+P$7
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+83603 2533 moveto
+P$3
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+84209 2038 moveto
+P$8
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+91757 2239 moveto
+P$9
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+92475 2061 moveto
+P$a
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+99567 2357 moveto
+P$b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+100326 2064 moveto
+P$c
+100392 2299 moveto
+P$d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+3960 3555 moveto
+P$e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+4462 3403 moveto
+P$f
+4371 3403 moveto
+P$g
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+11960 3555 moveto
+P$e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+12306 3694 moveto
+P$h
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+20056 3694 moveto
+P$h
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+28195 3733 moveto
+P$i
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+36210 3555 moveto
+P$j
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+44145 3589 moveto
+P$k
+44060 3189 moveto
+P$l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+51987 3350 moveto
+P$m
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+60220 3530 moveto
+P$n
+60018 3705 moveto
+P$o
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+67848 3233 moveto
+P$p
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+76192 3238 moveto
+P$q
+76123 3557 moveto
+P$r
+76104 3238 moveto
+P$s
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+83782 3278 moveto
+P$t
+83993 3110 moveto
+P$u
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+91806 3694 moveto
+P$v
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+92462 3403 moveto
+P$f
+92371 3403 moveto
+P$g
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+99806 3694 moveto
+P$v
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+100306 3694 moveto
+P$h
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+4793 392 moveto
+P$w
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+5420 557 moveto
+P$x
+5457 843 moveto
+P$y
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+5954 617 moveto
+P$z
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+6812 1071 moveto
+P$10
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+7420 557 moveto
+P$x
+7457 843 moveto
+P$y
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+7970 684 moveto
+P$11
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+8470 1137 moveto
+P$12
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+9648 1120 moveto
+P$13
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+10254 723 moveto
+P$14
+10082 723 moveto
+P$15
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+10848 1120 moveto
+P$13
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+11459 906 moveto
+P$16
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+56556 784 moveto
+P$17
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+57239 556 moveto
+P$18
+57232 615 moveto
+P$19
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+57896 829 moveto
+P$1a
+57521 339 moveto
+P$1b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+58420 684 moveto
+P$11
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+59062 1071 moveto
+P$10
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+59670 557 moveto
+P$x
+59707 843 moveto
+P$y
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+60220 684 moveto
+P$11
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+60720 1137 moveto
+P$12
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+61898 1120 moveto
+P$13
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+62504 723 moveto
+P$14
+62332 723 moveto
+P$15
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+63098 1120 moveto
+P$13
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+63709 906 moveto
+P$16
+fill
+100 setlinewidth
+0.75 0.75 0.75 setrgbcolor
+newpath
+0 4100 moveto
+0 40843 rlineto
+stroke
+100 setlinewidth
+0.75 0.75 0.75 setrgbcolor
+newpath
+8000 4100 moveto
+0 40843 rlineto
+stroke
+100 setlinewidth
+0.75 0.75 0.75 setrgbcolor
+newpath
+16000 4100 moveto
+0 40843 rlineto
+stroke
+100 setlinewidth
+0.75 0.75 0.75 setrgbcolor
+newpath
+24000 4100 moveto
+0 40843 rlineto
+stroke
+100 setlinewidth
+0.75 0.75 0.75 setrgbcolor
+newpath
+32000 4100 moveto
+0 40843 rlineto
+stroke
+100 setlinewidth
+0.75 0.75 0.75 setrgbcolor
+newpath
+40000 4100 moveto
+0 40843 rlineto
+stroke
+100 setlinewidth
+0.75 0.75 0.75 setrgbcolor
+newpath
+48000 4100 moveto
+0 40843 rlineto
+stroke
+100 setlinewidth
+0.75 0.75 0.75 setrgbcolor
+newpath
+56000 4100 moveto
+0 40843 rlineto
+stroke
+100 setlinewidth
+0.75 0.75 0.75 setrgbcolor
+newpath
+64000 4100 moveto
+0 40843 rlineto
+stroke
+100 setlinewidth
+0.75 0.75 0.75 setrgbcolor
+newpath
+72000 4100 moveto
+0 40843 rlineto
+stroke
+100 setlinewidth
+0.75 0.75 0.75 setrgbcolor
+newpath
+80000 4100 moveto
+0 40843 rlineto
+stroke
+100 setlinewidth
+0.75 0.75 0.75 setrgbcolor
+newpath
+88000 4100 moveto
+0 40843 rlineto
+stroke
+100 setlinewidth
+0.75 0.75 0.75 setrgbcolor
+newpath
+96000 4100 moveto
+0 40843 rlineto
+stroke
+100 setlinewidth
+0.75 0.75 0.75 setrgbcolor
+newpath
+104000 4100 moveto
+0 40843 rlineto
+stroke
+100 setlinewidth
+0.75 0.75 0.75 setrgbcolor
+newpath
+0 4100 moveto
+104000 0 rlineto
+stroke
+100 setlinewidth
+0.75 0.75 0.75 setrgbcolor
+newpath
+0 44943 moveto
+104000 0 rlineto
+stroke
+150 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+12000 8829 moveto
+0 1032 rlineto
+stroke
+150 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+12000 9862 moveto
+3900 0 rlineto
+stroke
+0.09 0.09 0.09 setrgbcolor
+newpath
+15500 9462 moveto
+0 400 rlineto
+0 400 rlineto
+400 -400 rlineto
+15500 9462 lineto
+closepath eofill
+150 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+15500 9462 moveto
+0 400 rlineto
+0 400 rlineto
+400 -400 rlineto
+15500 9462 lineto
+closepath stroke
+150 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+4000 13824 moveto
+0 1032 rlineto
+stroke
+150 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+4000 14856 moveto
+3900 0 rlineto
+stroke
+0.09 0.09 0.09 setrgbcolor
+newpath
+7500 14456 moveto
+0 400 rlineto
+0 400 rlineto
+400 -400 rlineto
+7500 14456 lineto
+closepath eofill
+150 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+7500 14456 moveto
+0 400 rlineto
+0 400 rlineto
+400 -400 rlineto
+7500 14456 lineto
+closepath stroke
+150 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+12000 8829 moveto
+0 2697 rlineto
+stroke
+150 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+12000 11527 moveto
+3900 0 rlineto
+stroke
+0.09 0.09 0.09 setrgbcolor
+newpath
+15500 11127 moveto
+0 400 rlineto
+0 400 rlineto
+400 -400 rlineto
+15500 11127 lineto
+closepath eofill
+150 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+15500 11127 moveto
+0 400 rlineto
+0 400 rlineto
+400 -400 rlineto
+15500 11127 lineto
+closepath stroke
+150 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+36000 15489 moveto
+0 2697 rlineto
+stroke
+150 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+36000 18186 moveto
+3900 0 rlineto
+stroke
+0.09 0.09 0.09 setrgbcolor
+newpath
+39500 17786 moveto
+0 400 rlineto
+0 400 rlineto
+400 -400 rlineto
+39500 17786 lineto
+closepath eofill
+150 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+39500 17786 moveto
+0 400 rlineto
+0 400 rlineto
+400 -400 rlineto
+39500 17786 lineto
+closepath stroke
+150 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+36000 15489 moveto
+0 1032 rlineto
+stroke
+150 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+36000 16521 moveto
+3900 0 rlineto
+stroke
+0.09 0.09 0.09 setrgbcolor
+newpath
+39500 16121 moveto
+0 400 rlineto
+0 400 rlineto
+400 -400 rlineto
+39500 16121 lineto
+closepath eofill
+150 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+39500 16121 moveto
+0 400 rlineto
+0 400 rlineto
+400 -400 rlineto
+39500 16121 lineto
+closepath stroke
+150 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+68000 18819 moveto
+0 1032 rlineto
+stroke
+150 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+68000 19851 moveto
+3900 0 rlineto
+stroke
+0.09 0.09 0.09 setrgbcolor
+newpath
+71500 19451 moveto
+0 400 rlineto
+0 400 rlineto
+400 -400 rlineto
+71500 19451 lineto
+closepath eofill
+150 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+71500 19451 moveto
+0 400 rlineto
+0 400 rlineto
+400 -400 rlineto
+71500 19451 lineto
+closepath stroke
+150 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+68000 18819 moveto
+0 2697 rlineto
+stroke
+150 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+68000 21516 moveto
+3900 0 rlineto
+stroke
+0.09 0.09 0.09 setrgbcolor
+newpath
+71500 21116 moveto
+0 400 rlineto
+0 400 rlineto
+400 -400 rlineto
+71500 21116 lineto
+closepath eofill
+150 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+71500 21116 moveto
+0 400 rlineto
+0 400 rlineto
+400 -400 rlineto
+71500 21116 lineto
+closepath stroke
+150 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+68000 18819 moveto
+0 9292 rlineto
+stroke
+150 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+68000 28111 moveto
+3900 0 rlineto
+stroke
+0.09 0.09 0.09 setrgbcolor
+newpath
+71500 27711 moveto
+0 400 rlineto
+0 400 rlineto
+400 -400 rlineto
+71500 27711 lineto
+closepath eofill
+150 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+71500 27711 moveto
+0 400 rlineto
+0 400 rlineto
+400 -400 rlineto
+71500 27711 lineto
+closepath stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+0 5732 moveto
+500 0 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+5800 5732 moveto
+98100 0 rlineto
+stroke
+0.89 0.89 0.94 setrgbcolor
+15600 1264 200 7564 simplerect
+closepath eofill
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+200 7564 moveto
+15600 0 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+200 8829 moveto
+15600 0 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+200 7564 moveto
+0 1264 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+15800 7564 moveto
+0 1264 rlineto
+stroke
+0.89 0.89 0.94 setrgbcolor
+15600 1264 16200 9229 simplerect
+closepath eofill
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+16200 9229 moveto
+15600 0 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+16200 10494 moveto
+15600 0 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+16200 9229 moveto
+0 1264 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+31800 9229 moveto
+0 1264 rlineto
+stroke
+0.89 0.89 0.94 setrgbcolor
+31600 1264 16200 10894 simplerect
+closepath eofill
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+16200 10894 moveto
+31600 0 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+16200 12159 moveto
+31600 0 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+16200 10894 moveto
+0 1264 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+47800 10894 moveto
+0 1264 rlineto
+stroke
+0.89 0.89 0.94 setrgbcolor
+7600 1264 200 12559 simplerect
+closepath eofill
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+200 12559 moveto
+7600 0 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+200 13824 moveto
+7600 0 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+200 12559 moveto
+0 1264 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+7800 12559 moveto
+0 1264 rlineto
+stroke
+0.89 0.89 0.94 setrgbcolor
+31600 1264 8200 14224 simplerect
+closepath eofill
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+8200 14224 moveto
+31600 0 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+8200 15489 moveto
+31600 0 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+8200 14224 moveto
+0 1264 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+39800 14224 moveto
+0 1264 rlineto
+stroke
+0.89 0.89 0.94 setrgbcolor
+23600 1264 40200 15889 simplerect
+closepath eofill
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+40200 15889 moveto
+23600 0 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+40200 17154 moveto
+23600 0 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+40200 15889 moveto
+0 1264 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+63800 15889 moveto
+0 1264 rlineto
+stroke
+0.89 0.89 0.94 setrgbcolor
+31600 1264 40200 17554 simplerect
+closepath eofill
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+40200 17554 moveto
+31600 0 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+40200 18819 moveto
+31600 0 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+40200 17554 moveto
+0 1264 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+71800 17554 moveto
+0 1264 rlineto
+stroke
+0.89 0.89 0.94 setrgbcolor
+31600 1264 72200 19219 simplerect
+closepath eofill
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+72200 19219 moveto
+31600 0 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+72200 20484 moveto
+31600 0 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+72200 19219 moveto
+0 1264 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+103800 19219 moveto
+0 1264 rlineto
+stroke
+0.89 0.89 0.94 setrgbcolor
+15600 1264 72200 20884 simplerect
+closepath eofill
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+72200 20884 moveto
+15600 0 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+72200 22148 moveto
+15600 0 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+72200 20884 moveto
+0 1264 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+87800 20884 moveto
+0 1264 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+0 23981 moveto
+500 0 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+5900 23981 moveto
+98000 0 rlineto
+stroke
+0.89 0.89 0.94 setrgbcolor
+39600 1264 200 25813 simplerect
+closepath eofill
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+200 25813 moveto
+39600 0 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+200 27078 moveto
+39600 0 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+200 25813 moveto
+0 1264 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+39800 25813 moveto
+0 1264 rlineto
+stroke
+0.89 0.89 0.94 setrgbcolor
+15600 1264 72200 27478 simplerect
+closepath eofill
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+72200 27478 moveto
+15600 0 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+72200 28743 moveto
+15600 0 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+72200 27478 moveto
+0 1264 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+87800 27478 moveto
+0 1264 rlineto
+stroke
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+1675 5919 moveto
+P$1c
+1528 5570 moveto
+P$1d
+1571 5909 moveto
+P$1e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+1921 6142 moveto
+P$1f
+1943 6069 moveto
+P$1g
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+2448 5838 moveto
+P$1h
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+3339 6131 moveto
+P$1i
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+3648 5861 moveto
+P$1j
+3962 5788 moveto
+P$1k
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+4543 6131 moveto
+P$1l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+5140 6038 moveto
+P$1m
+4848 5841 moveto
+P$1n
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+1025 7912 moveto
+P$1o
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+1965 8306 moveto
+P$1p
+1864 8306 moveto
+P$1q
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+2443 8596 moveto
+P$1l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+2896 8591 moveto
+P$1r
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+2976 8596 moveto
+P$1s
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+3865 8306 moveto
+P$1p
+3764 8306 moveto
+P$1q
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+3973 8596 moveto
+P$1t
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+4173 8596 moveto
+P$1t
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+4448 8326 moveto
+P$1j
+4762 8252 moveto
+P$1k
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+4976 8596 moveto
+P$1s
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+5348 8346 moveto
+P$1u
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+6382 8387 moveto
+P$1v
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+6548 8302 moveto
+P$1h
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+7170 8115 moveto
+P$1w
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+7673 7891 moveto
+P$1x
+7673 8596 moveto
+P$1y
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+7948 8302 moveto
+P$1h
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+8570 8115 moveto
+P$1w
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+9296 8591 moveto
+P$1r
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+9875 8824 moveto
+P$1z
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+10101 8596 moveto
+P$20
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+10712 8596 moveto
+P$21
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+11612 8596 moveto
+P$21
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+12321 8607 moveto
+P$1f
+12343 8534 moveto
+P$1g
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+13143 8596 moveto
+P$1l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+13468 8015 moveto
+P$22
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+14048 8326 moveto
+P$1j
+14362 8252 moveto
+P$1k
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+14573 8596 moveto
+P$1t
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+14750 8756 moveto
+P$23
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+32882 10052 moveto
+P$1v
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+33048 9991 moveto
+P$1j
+33362 9917 moveto
+P$1k
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+33576 10261 moveto
+P$1s
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+34229 10261 moveto
+P$24
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+34573 9556 moveto
+P$1x
+34573 10261 moveto
+P$1y
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+34848 9967 moveto
+P$1h
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+35448 9991 moveto
+P$1j
+35762 9917 moveto
+P$1k
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+35948 10011 moveto
+P$1u
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+36982 10052 moveto
+P$1v
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+37148 9967 moveto
+P$1h
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+37770 9780 moveto
+P$1w
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+38273 9556 moveto
+P$1x
+38273 10261 moveto
+P$1y
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+38548 9967 moveto
+P$1h
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+39170 9780 moveto
+P$1w
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+39896 10256 moveto
+P$1r
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+40268 9975 moveto
+P$25
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+41342 9875 moveto
+P$26
+41239 9875 moveto
+P$27
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+41621 10272 moveto
+P$1f
+41643 10199 moveto
+P$1g
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+42296 10256 moveto
+P$1r
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+42448 9991 moveto
+P$1j
+42762 9917 moveto
+P$1k
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+43343 10261 moveto
+P$1l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+44240 10167 moveto
+P$1m
+43948 9970 moveto
+P$28
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+44568 9680 moveto
+P$22
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+45076 10261 moveto
+P$1s
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+45548 9967 moveto
+P$1h
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+46170 9780 moveto
+P$1w
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+46676 10261 moveto
+P$1s
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+47148 9991 moveto
+P$1j
+47462 9917 moveto
+P$1k
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+47673 9556 moveto
+P$1x
+47673 10261 moveto
+P$1y
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+47948 9967 moveto
+P$1h
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+48570 9780 moveto
+P$1w
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+49148 9991 moveto
+P$1j
+49462 9917 moveto
+P$1k
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+50043 10261 moveto
+P$1l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+50498 9977 moveto
+P$29
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+51175 10489 moveto
+P$1z
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+52042 9875 moveto
+P$26
+51939 9875 moveto
+P$27
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+52321 10272 moveto
+P$1f
+52343 10199 moveto
+P$1g
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+53143 10261 moveto
+P$1l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+53373 9556 moveto
+P$1x
+53373 10261 moveto
+P$1y
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+53648 9991 moveto
+P$1j
+53962 9917 moveto
+P$1k
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+54173 10261 moveto
+P$1t
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+54350 10420 moveto
+P$23
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+17226 11926 moveto
+P$2a
+16967 11246 moveto
+P$2b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+17468 11345 moveto
+P$22
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+18196 11921 moveto
+P$1r
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+18370 11445 moveto
+P$1w
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+18948 11656 moveto
+P$1j
+19262 11582 moveto
+P$1k
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+19843 11926 moveto
+P$1l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+20296 11921 moveto
+P$1r
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+20373 11221 moveto
+P$1x
+20373 11926 moveto
+P$1y
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+20693 11415 moveto
+P$2c
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+20873 11221 moveto
+P$1x
+20873 11926 moveto
+P$1y
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+21045 11926 moveto
+P$2d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+21673 11221 moveto
+P$1x
+21673 11926 moveto
+P$1y
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+21948 11656 moveto
+P$1j
+22262 11582 moveto
+P$1k
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+22476 11926 moveto
+P$1s
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+22968 11345 moveto
+P$22
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+23843 11926 moveto
+P$1l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+24293 12154 moveto
+P$2e
+24442 11635 moveto
+P$2f
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+25175 12154 moveto
+P$1z
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+25354 11545 moveto
+P$2g
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+26348 11656 moveto
+P$1j
+26662 11582 moveto
+P$1k
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+26876 11926 moveto
+P$1s
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+27765 11635 moveto
+P$1p
+27664 11635 moveto
+P$1q
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+27850 12085 moveto
+P$23
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+8934 13591 moveto
+P$2h
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+9665 13300 moveto
+P$1p
+9564 13300 moveto
+P$1q
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+10140 13497 moveto
+P$1m
+9848 13300 moveto
+P$28
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+10448 13321 moveto
+P$1j
+10762 13247 moveto
+P$1k
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+10973 13591 moveto
+P$1t
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+11148 13341 moveto
+P$1u
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+12175 13061 moveto
+P$2i
+12071 13063 moveto
+P$2j
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+12421 13602 moveto
+P$1f
+12443 13528 moveto
+P$1g
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+13239 13591 moveto
+P$1i
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+13548 13321 moveto
+P$1j
+13862 13247 moveto
+P$1k
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+14296 13586 moveto
+P$1r
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+14875 13819 moveto
+P$1z
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+15742 13205 moveto
+P$26
+15639 13205 moveto
+P$27
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+16021 13602 moveto
+P$1f
+16043 13528 moveto
+P$1g
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+16843 13591 moveto
+P$1l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+17073 12886 moveto
+P$1x
+17073 13591 moveto
+P$1y
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+17348 13321 moveto
+P$1j
+17662 13247 moveto
+P$1k
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+17873 13591 moveto
+P$1t
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+18050 13750 moveto
+P$23
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+9342 14870 moveto
+P$26
+9239 14870 moveto
+P$27
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+9621 15267 moveto
+P$1f
+9643 15193 moveto
+P$1g
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+10296 15251 moveto
+P$1r
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+10448 14985 moveto
+P$1j
+10762 14912 moveto
+P$1k
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+11343 15256 moveto
+P$1l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+12065 14962 moveto
+P$2k
+11964 14965 moveto
+P$2l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+12321 15267 moveto
+P$1f
+12343 15193 moveto
+P$1g
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+13143 15256 moveto
+P$1l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+13739 15256 moveto
+P$1i
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+14421 15267 moveto
+P$1f
+14443 15193 moveto
+P$1g
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+14968 14675 moveto
+P$22
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+15593 14745 moveto
+P$2c
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+16210 15095 moveto
+P$2m
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+16448 14985 moveto
+P$1j
+16762 14912 moveto
+P$1k
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+17196 15251 moveto
+P$1r
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+17245 15256 moveto
+P$2d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+17948 14985 moveto
+P$1j
+18262 14912 moveto
+P$1k
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+18843 15256 moveto
+P$1l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+19575 15484 moveto
+P$1z
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+19801 15256 moveto
+P$20
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+20412 15256 moveto
+P$21
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+21312 15256 moveto
+P$21
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+22021 15267 moveto
+P$1f
+22043 15193 moveto
+P$1g
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+22843 15256 moveto
+P$1l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+23168 14675 moveto
+P$22
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+23748 14985 moveto
+P$1j
+24062 14912 moveto
+P$1k
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+24273 15256 moveto
+P$1t
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+24450 15415 moveto
+P$23
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+40992 16932 moveto
+P$2n
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+41696 16916 moveto
+P$1r
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+41773 16216 moveto
+P$1x
+41773 16921 moveto
+P$1y
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+41973 16921 moveto
+P$1t
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+42148 16671 moveto
+P$1u
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+43175 16391 moveto
+P$2i
+43071 16393 moveto
+P$2j
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+43421 16932 moveto
+P$1f
+43443 16858 moveto
+P$1g
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+44239 16921 moveto
+P$1i
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+44548 16650 moveto
+P$1j
+44862 16577 moveto
+P$1k
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+45296 16916 moveto
+P$1r
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+45668 16635 moveto
+P$25
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+46625 16921 moveto
+P$2o
+46610 16382 moveto
+P$2p
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+47482 16711 moveto
+P$1v
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+48182 16711 moveto
+P$1v
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+48875 16391 moveto
+P$2i
+48771 16393 moveto
+P$2j
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+49121 16932 moveto
+P$1f
+49143 16858 moveto
+P$1g
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+49576 16921 moveto
+P$1s
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+50410 16760 moveto
+P$2m
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+50648 16650 moveto
+P$1j
+50962 16577 moveto
+P$1k
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+51176 16921 moveto
+P$1s
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+51798 16636 moveto
+P$29
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+52475 17149 moveto
+P$1z
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+53342 16535 moveto
+P$26
+53239 16535 moveto
+P$27
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+53621 16932 moveto
+P$1f
+53643 16858 moveto
+P$1g
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+54443 16921 moveto
+P$1l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+54673 16216 moveto
+P$1x
+54673 16921 moveto
+P$1y
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+54948 16650 moveto
+P$1j
+55262 16577 moveto
+P$1k
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+55473 16921 moveto
+P$1t
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+55650 17080 moveto
+P$2q
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+56575 17149 moveto
+P$1z
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+56790 16921 moveto
+P$2r
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+57468 16339 moveto
+P$22
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+58339 16921 moveto
+P$1i
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+58721 16932 moveto
+P$1f
+58743 16858 moveto
+P$1g
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+59610 16760 moveto
+P$2m
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+59750 17080 moveto
+P$23
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+41342 18200 moveto
+P$26
+41239 18200 moveto
+P$27
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+41621 18596 moveto
+P$1f
+41643 18523 moveto
+P$1g
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+42296 18581 moveto
+P$1r
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+42521 18596 moveto
+P$1f
+42543 18523 moveto
+P$2s
+43526 18586 moveto
+P$2a
+43267 17906 moveto
+P$2b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+43748 18292 moveto
+P$1h
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+44348 18292 moveto
+P$1h
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+44948 18315 moveto
+P$1j
+45262 18242 moveto
+P$1k
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+45910 18425 moveto
+P$2m
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+46510 18425 moveto
+P$2m
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+46648 18336 moveto
+P$1u
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+47682 18376 moveto
+P$1v
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+47848 18292 moveto
+P$1h
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+48470 18104 moveto
+P$1w
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+48973 17881 moveto
+P$1x
+48973 18586 moveto
+P$1y
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+49248 18292 moveto
+P$1h
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+49870 18104 moveto
+P$1w
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+50596 18581 moveto
+P$1r
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+51175 18814 moveto
+P$1z
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+51401 18586 moveto
+P$20
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+52012 18586 moveto
+P$21
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+52912 18586 moveto
+P$21
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+53621 18596 moveto
+P$1f
+53643 18523 moveto
+P$1g
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+54443 18586 moveto
+P$1l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+54768 18004 moveto
+P$22
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+55348 18315 moveto
+P$1j
+55662 18242 moveto
+P$1k
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+55873 18586 moveto
+P$1t
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+56050 18745 moveto
+P$2q
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+56975 18814 moveto
+P$1z
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+57345 18596 moveto
+P$2t
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+57868 18004 moveto
+P$22
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+58373 18586 moveto
+P$1t
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+58573 17881 moveto
+P$1x
+58573 18586 moveto
+P$1y
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+58868 18004 moveto
+P$22
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+59810 18425 moveto
+P$2m
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+59950 18745 moveto
+P$23
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+73282 20041 moveto
+P$1v
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+73448 19980 moveto
+P$1j
+73762 19907 moveto
+P$1k
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+73976 20250 moveto
+P$1s
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+74629 20250 moveto
+P$24
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+74973 19546 moveto
+P$1x
+74973 20250 moveto
+P$1y
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+75248 19957 moveto
+P$1h
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+75848 19980 moveto
+P$1j
+76162 19907 moveto
+P$1k
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+76348 20000 moveto
+P$1u
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+77382 20041 moveto
+P$1v
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+77548 19957 moveto
+P$1h
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+78170 19769 moveto
+P$1w
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+78673 19546 moveto
+P$1x
+78673 20250 moveto
+P$1y
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+78948 19957 moveto
+P$1h
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+79570 19769 moveto
+P$1w
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+80296 20246 moveto
+P$1r
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+80668 19964 moveto
+P$25
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+81054 19869 moveto
+P$2g
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+82048 19980 moveto
+P$1j
+82362 19907 moveto
+P$1k
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+83010 20089 moveto
+P$2m
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+83248 19957 moveto
+P$1h
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+83870 19769 moveto
+P$1w
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+84521 20261 moveto
+P$1f
+84543 20188 moveto
+P$2s
+84662 19596 moveto
+P$2u
+84450 19596 moveto
+P$2v
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+85093 19739 moveto
+P$2c
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+85496 20246 moveto
+P$1r
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+86010 20089 moveto
+P$2m
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+86173 20250 moveto
+P$1t
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+86865 19960 moveto
+P$1p
+86764 19960 moveto
+P$1q
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+87193 20479 moveto
+P$2e
+87342 19960 moveto
+P$2f
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+87573 19546 moveto
+P$1x
+87573 20250 moveto
+P$1y
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+88139 20250 moveto
+P$1i
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+88598 19966 moveto
+P$29
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+89275 20479 moveto
+P$1z
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+90142 19864 moveto
+P$26
+90039 19864 moveto
+P$27
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+90421 20261 moveto
+P$1f
+90443 20188 moveto
+P$1g
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+91243 20250 moveto
+P$1l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+91473 19546 moveto
+P$1x
+91473 20250 moveto
+P$1y
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+91748 19980 moveto
+P$1j
+92062 19907 moveto
+P$1k
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+92273 20250 moveto
+P$1t
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+92450 20410 moveto
+P$2q
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+93375 20479 moveto
+P$1z
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+93601 20250 moveto
+P$20
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+94212 20250 moveto
+P$21
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+95112 20250 moveto
+P$21
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+95821 20261 moveto
+P$1f
+95843 20188 moveto
+P$1g
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+96643 20250 moveto
+P$1l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+96968 19669 moveto
+P$22
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+97548 19980 moveto
+P$1j
+97862 19907 moveto
+P$1k
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+98073 20250 moveto
+P$1t
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+98250 20410 moveto
+P$23
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+88592 21926 moveto
+P$2n
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+89296 21911 moveto
+P$1r
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+89373 21211 moveto
+P$1x
+89373 21915 moveto
+P$1y
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+89573 21915 moveto
+P$1t
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+89748 21665 moveto
+P$1u
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+90775 21386 moveto
+P$2i
+90671 21387 moveto
+P$2j
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+91021 21926 moveto
+P$1f
+91043 21853 moveto
+P$1g
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+91839 21915 moveto
+P$1i
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+92148 21645 moveto
+P$1j
+92462 21572 moveto
+P$1k
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+92896 21911 moveto
+P$1r
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+93268 21629 moveto
+P$25
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+94025 21231 moveto
+P$1o
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+94473 21915 moveto
+P$1t
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+94748 21645 moveto
+P$1j
+95062 21572 moveto
+P$1k
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+95421 21926 moveto
+P$1f
+95443 21853 moveto
+P$1g
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+96243 21915 moveto
+P$1l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+96825 21231 moveto
+P$1o
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+97276 21915 moveto
+P$1s
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+98165 21625 moveto
+P$1p
+98064 21625 moveto
+P$1q
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+98643 21915 moveto
+P$1l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+99045 21926 moveto
+P$2t
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+99965 21625 moveto
+P$1p
+99864 21625 moveto
+P$1q
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+100565 21622 moveto
+P$2k
+100464 21625 moveto
+P$2l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+100898 21631 moveto
+P$29
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+101575 22143 moveto
+P$1z
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+101945 21926 moveto
+P$2t
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+102468 21334 moveto
+P$22
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+102973 21915 moveto
+P$1t
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+103173 21211 moveto
+P$1x
+103173 21915 moveto
+P$1y
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+103468 21334 moveto
+P$22
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+104410 21754 moveto
+P$2m
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+104550 22075 moveto
+P$23
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+1192 23707 moveto
+P$2w
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+1776 24380 moveto
+P$1s
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+2665 24090 moveto
+P$1p
+2564 24090 moveto
+P$1q
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+3143 24380 moveto
+P$1l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+3596 24376 moveto
+P$1r
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+3748 24110 moveto
+P$1j
+4062 24036 moveto
+P$1k
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+4643 24380 moveto
+P$1l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+5240 24286 moveto
+P$1m
+4948 24090 moveto
+P$1n
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+1193 26845 moveto
+P$2x
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+1865 26554 moveto
+P$1p
+1764 26554 moveto
+P$1q
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+2312 26845 moveto
+P$21
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+3365 26551 moveto
+P$2y
+3264 26554 moveto
+P$2z
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+3965 26554 moveto
+P$1p
+3864 26554 moveto
+P$1q
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+4443 26845 moveto
+P$1l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+4748 26575 moveto
+P$1j
+5062 26501 moveto
+P$1k
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+5643 26845 moveto
+P$1l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+6096 26840 moveto
+P$1r
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+6248 26575 moveto
+P$1j
+6562 26501 moveto
+P$1k
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+7143 26845 moveto
+P$1l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+7875 27073 moveto
+P$1z
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+8054 26464 moveto
+P$2g
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+9048 26575 moveto
+P$1j
+9362 26501 moveto
+P$1k
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+9576 26845 moveto
+P$1s
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+10465 26554 moveto
+P$1p
+10364 26554 moveto
+P$1q
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+10550 27004 moveto
+P$2q
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+11475 27073 moveto
+P$1z
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+11845 26856 moveto
+P$2t
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+12368 26264 moveto
+P$22
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+12873 26845 moveto
+P$1t
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+13073 26140 moveto
+P$1x
+13073 26845 moveto
+P$1y
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+13368 26264 moveto
+P$22
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+14310 26684 moveto
+P$2m
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+14450 27004 moveto
+P$2q
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+15375 27073 moveto
+P$1z
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+15590 26845 moveto
+P$2r
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+16268 26264 moveto
+P$22
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+17139 26845 moveto
+P$1i
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+17521 26856 moveto
+P$1f
+17543 26783 moveto
+P$1g
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+18410 26684 moveto
+P$2m
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+18550 27004 moveto
+P$23
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+88826 28510 moveto
+P$2a
+88567 27830 moveto
+P$2b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+89575 27980 moveto
+P$2i
+89471 27982 moveto
+P$2j
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+89701 28510 moveto
+P$20
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+89948 28260 moveto
+P$1u
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+90926 28510 moveto
+P$2a
+90667 27830 moveto
+P$2b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+91443 28510 moveto
+P$1l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+92165 28216 moveto
+P$2k
+92064 28219 moveto
+P$2l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+92273 27805 moveto
+P$1x
+92273 28510 moveto
+P$1y
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+92843 28510 moveto
+P$1l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+93440 28416 moveto
+P$1m
+93148 28219 moveto
+P$28
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+93768 27929 moveto
+P$22
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+94643 28510 moveto
+P$1l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+95093 28738 moveto
+P$2e
+95242 28219 moveto
+P$2f
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+95975 28738 moveto
+P$1z
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+96154 28129 moveto
+P$2g
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+97148 28240 moveto
+P$1j
+97462 28166 moveto
+P$1k
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+97676 28510 moveto
+P$1s
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+98565 28219 moveto
+P$1p
+98464 28219 moveto
+P$1q
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+98650 28669 moveto
+P$2q
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+99575 28738 moveto
+P$1z
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+99790 28510 moveto
+P$2r
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+100468 27929 moveto
+P$22
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+101339 28510 moveto
+P$1i
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+101721 28521 moveto
+P$1f
+101743 28447 moveto
+P$1g
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+102610 28349 moveto
+P$2m
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+102750 28669 moveto
+P$23
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+278 30105 moveto
+P$30
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+606 29608 moveto
+P$31
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+1606 29608 moveto
+P$31
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+2695 29547 moveto
+P$32
+2779 29852 moveto
+P$33
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+3206 29608 moveto
+P$34
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+3898 29986 moveto
+P$35
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+4565 29857 moveto
+P$36
+4703 29594 moveto
+P$37
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+5232 30113 moveto
+P$38
+fill
+100 setlinewidth
+0 0 0 setrgbcolor
+newpath
+0 30438 moveto
+104000 0 rlineto
+stroke
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+3525 31347 moveto
+P$39
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+4165 31086 moveto
+P$3a
+4084 31086 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+4665 31086 moveto
+P$3a
+4584 31086 moveto
+P$3c
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+11650 31383 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+12165 31086 moveto
+P$3a
+12084 31086 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+12665 31086 moveto
+P$3a
+12584 31086 moveto
+P$3c
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+19525 31347 moveto
+P$39
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+20165 31086 moveto
+P$3a
+20084 31086 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+20665 31086 moveto
+P$3a
+20584 31086 moveto
+P$3c
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+27525 31347 moveto
+P$39
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+28165 31086 moveto
+P$3a
+28084 31086 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+28665 31086 moveto
+P$3a
+28584 31086 moveto
+P$3c
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+35525 31347 moveto
+P$39
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+36165 31086 moveto
+P$3a
+36084 31086 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+36665 31086 moveto
+P$3a
+36584 31086 moveto
+P$3c
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+43525 31347 moveto
+P$39
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+44165 31086 moveto
+P$3a
+44084 31086 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+44665 31086 moveto
+P$3a
+44584 31086 moveto
+P$3c
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+51525 31347 moveto
+P$39
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+52165 31086 moveto
+P$3a
+52084 31086 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+52665 31086 moveto
+P$3a
+52584 31086 moveto
+P$3c
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+59525 31347 moveto
+P$39
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+60165 31086 moveto
+P$3a
+60084 31086 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+60665 31086 moveto
+P$3a
+60584 31086 moveto
+P$3c
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+67525 31347 moveto
+P$39
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+68165 31086 moveto
+P$3a
+68084 31086 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+68665 31086 moveto
+P$3a
+68584 31086 moveto
+P$3c
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+75525 31347 moveto
+P$39
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+76165 31086 moveto
+P$3a
+76084 31086 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+76665 31086 moveto
+P$3a
+76584 31086 moveto
+P$3c
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+83525 31347 moveto
+P$39
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+84165 31086 moveto
+P$3a
+84084 31086 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+84665 31086 moveto
+P$3a
+84584 31086 moveto
+P$3c
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+91525 31347 moveto
+P$39
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+92165 31086 moveto
+P$3a
+92084 31086 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+92665 31086 moveto
+P$3a
+92584 31086 moveto
+P$3c
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+99525 31347 moveto
+P$39
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+100165 31086 moveto
+P$3a
+100084 31086 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+100665 31086 moveto
+P$3a
+100584 31086 moveto
+P$3c
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+754 32926 moveto
+P$3e
+423 32505 moveto
+P$3f
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+1195 32747 moveto
+P$32
+1279 33052 moveto
+P$33
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+1706 32808 moveto
+P$34
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+2440 32565 moveto
+P$3g
+2434 33313 moveto
+P$3h
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+2765 33057 moveto
+P$36
+2903 32794 moveto
+P$37
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+3432 33313 moveto
+P$38
+fill
+100 setlinewidth
+0 0 0 setrgbcolor
+newpath
+0 33638 moveto
+104000 0 rlineto
+stroke
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+3525 34547 moveto
+P$39
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+4165 34286 moveto
+P$3a
+4084 34286 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+4665 34286 moveto
+P$3a
+4584 34286 moveto
+P$3c
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+19525 34547 moveto
+P$39
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+20165 34286 moveto
+P$3a
+20084 34286 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+20665 34286 moveto
+P$3a
+20584 34286 moveto
+P$3c
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+27525 34547 moveto
+P$39
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+28165 34286 moveto
+P$3a
+28084 34286 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+28665 34286 moveto
+P$3a
+28584 34286 moveto
+P$3c
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+43525 34547 moveto
+P$39
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+44165 34286 moveto
+P$3a
+44084 34286 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+44665 34286 moveto
+P$3a
+44584 34286 moveto
+P$3c
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+51525 34547 moveto
+P$39
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+52165 34286 moveto
+P$3a
+52084 34286 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+52665 34286 moveto
+P$3a
+52584 34286 moveto
+P$3c
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+59525 34547 moveto
+P$39
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+60165 34286 moveto
+P$3a
+60084 34286 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+60665 34286 moveto
+P$3a
+60584 34286 moveto
+P$3c
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+75525 34547 moveto
+P$39
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+76165 34286 moveto
+P$3a
+76084 34286 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+76665 34286 moveto
+P$3a
+76584 34286 moveto
+P$3c
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+83525 34547 moveto
+P$39
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+84165 34286 moveto
+P$3a
+84084 34286 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+84665 34286 moveto
+P$3a
+84584 34286 moveto
+P$3c
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+91525 34547 moveto
+P$39
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+92165 34286 moveto
+P$3a
+92084 34286 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+92665 34286 moveto
+P$3a
+92584 34286 moveto
+P$3c
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+99525 34547 moveto
+P$39
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+100165 34286 moveto
+P$3a
+100084 34286 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+100665 34286 moveto
+P$3a
+100584 34286 moveto
+P$3c
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+815 36513 moveto
+P$3i
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+1065 36257 moveto
+P$36
+1203 35994 moveto
+P$37
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+1921 35944 moveto
+P$3j
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+2500 36255 moveto
+P$3k
+2385 36255 moveto
+P$3l
+fill
+100 setlinewidth
+0 0 0 setrgbcolor
+newpath
+0 36838 moveto
+104000 0 rlineto
+stroke
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+3525 37747 moveto
+P$39
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+4165 37486 moveto
+P$3a
+4084 37486 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+4665 37486 moveto
+P$3a
+4584 37486 moveto
+P$3c
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+11525 37747 moveto
+P$39
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+12165 37486 moveto
+P$3a
+12084 37486 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+12665 37486 moveto
+P$3a
+12584 37486 moveto
+P$3c
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+19650 37783 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+20165 37486 moveto
+P$3a
+20084 37486 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+20665 37486 moveto
+P$3a
+20584 37486 moveto
+P$3c
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+27650 37783 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+28165 37486 moveto
+P$3a
+28084 37486 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+28665 37486 moveto
+P$3a
+28584 37486 moveto
+P$3c
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+35650 37783 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+36165 37486 moveto
+P$3a
+36084 37486 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+36665 37486 moveto
+P$3a
+36584 37486 moveto
+P$3c
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+43525 37747 moveto
+P$39
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+44165 37486 moveto
+P$3a
+44084 37486 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+44665 37486 moveto
+P$3a
+44584 37486 moveto
+P$3c
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+75525 37747 moveto
+P$39
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+76165 37486 moveto
+P$3a
+76084 37486 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+76665 37486 moveto
+P$3a
+76584 37486 moveto
+P$3c
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+83525 37747 moveto
+P$39
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+84165 37486 moveto
+P$3a
+84084 37486 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+84665 37486 moveto
+P$3a
+84584 37486 moveto
+P$3c
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+400 38940 moveto
+P$3m
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+998 39586 moveto
+P$35
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+1718 39469 moveto
+P$3n
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+2495 39147 moveto
+P$32
+2579 39452 moveto
+P$33
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+3259 39590 moveto
+P$3o
+fill
+100 setlinewidth
+0 0 0 setrgbcolor
+newpath
+0 40038 moveto
+104000 0 rlineto
+stroke
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+3525 40947 moveto
+P$39
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+4165 40686 moveto
+P$3a
+4084 40686 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+4665 40686 moveto
+P$3a
+4584 40686 moveto
+P$3c
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+11525 40947 moveto
+P$39
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+12165 40686 moveto
+P$3a
+12084 40686 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+12665 40686 moveto
+P$3a
+12584 40686 moveto
+P$3c
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+19525 40947 moveto
+P$39
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+20165 40686 moveto
+P$3a
+20084 40686 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+20665 40686 moveto
+P$3a
+20584 40686 moveto
+P$3c
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+27525 40947 moveto
+P$39
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+28165 40686 moveto
+P$3a
+28084 40686 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+28665 40686 moveto
+P$3a
+28584 40686 moveto
+P$3c
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+35525 40947 moveto
+P$39
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+36165 40686 moveto
+P$3a
+36084 40686 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+36665 40686 moveto
+P$3a
+36584 40686 moveto
+P$3c
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+43525 40947 moveto
+P$39
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+44165 40686 moveto
+P$3a
+44084 40686 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+44665 40686 moveto
+P$3a
+44584 40686 moveto
+P$3c
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+51525 40947 moveto
+P$39
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+52165 40686 moveto
+P$3a
+52084 40686 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+52665 40686 moveto
+P$3a
+52584 40686 moveto
+P$3c
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+59525 40947 moveto
+P$39
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+60165 40686 moveto
+P$3a
+60084 40686 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+60665 40686 moveto
+P$3a
+60584 40686 moveto
+P$3c
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+75525 40947 moveto
+P$39
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+76165 40686 moveto
+P$3a
+76084 40686 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+76665 40686 moveto
+P$3a
+76584 40686 moveto
+P$3c
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+83525 40947 moveto
+P$39
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+84165 40686 moveto
+P$3a
+84084 40686 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+84665 40686 moveto
+P$3a
+84584 40686 moveto
+P$3c
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+260 42155 moveto
+P$3p
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+698 42786 moveto
+P$35
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+1432 42913 moveto
+P$3q
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+1840 42165 moveto
+P$3g
+1834 42913 moveto
+P$3h
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+2198 42786 moveto
+P$35
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+3159 42790 moveto
+P$3o
+fill
+100 setlinewidth
+0 0 0 setrgbcolor
+newpath
+0 43238 moveto
+104000 0 rlineto
+stroke
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+3525 44147 moveto
+P$39
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+4165 43886 moveto
+P$3a
+4084 43886 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+4665 43886 moveto
+P$3a
+4584 43886 moveto
+P$3c
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+11525 44147 moveto
+P$39
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+12165 43886 moveto
+P$3a
+12084 43886 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+12665 43886 moveto
+P$3a
+12584 43886 moveto
+P$3c
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+19525 44147 moveto
+P$39
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+20165 43886 moveto
+P$3a
+20084 43886 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+20665 43886 moveto
+P$3a
+20584 43886 moveto
+P$3c
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+27525 44147 moveto
+P$39
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+28165 43886 moveto
+P$3a
+28084 43886 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+28665 43886 moveto
+P$3a
+28584 43886 moveto
+P$3c
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+35525 44147 moveto
+P$39
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+36165 43886 moveto
+P$3a
+36084 43886 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+36665 43886 moveto
+P$3a
+36584 43886 moveto
+P$3c
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+43525 44147 moveto
+P$39
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+44165 43886 moveto
+P$3a
+44084 43886 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+44665 43886 moveto
+P$3a
+44584 43886 moveto
+P$3c
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+51525 44147 moveto
+P$39
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+52165 43886 moveto
+P$3a
+52084 43886 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+52665 43886 moveto
+P$3a
+52584 43886 moveto
+P$3c
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+59525 44147 moveto
+P$39
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+60165 43886 moveto
+P$3a
+60084 43886 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+60665 43886 moveto
+P$3a
+60584 43886 moveto
+P$3c
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+67525 44147 moveto
+P$39
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+68165 43886 moveto
+P$3a
+68084 43886 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+68665 43886 moveto
+P$3a
+68584 43886 moveto
+P$3c
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+75525 44147 moveto
+P$39
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+76165 43886 moveto
+P$3a
+76084 43886 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+76665 43886 moveto
+P$3a
+76584 43886 moveto
+P$3c
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+83525 44147 moveto
+P$39
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+84165 43886 moveto
+P$3a
+84084 43886 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+84665 43886 moveto
+P$3a
+84584 43886 moveto
+P$3c
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+3960 46899 moveto
+P$e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+4462 46747 moveto
+P$f
+4371 46747 moveto
+P$g
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+11960 46899 moveto
+P$e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+12306 47038 moveto
+P$h
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+20056 47038 moveto
+P$h
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+28195 47077 moveto
+P$i
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+36210 46899 moveto
+P$j
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+44145 46933 moveto
+P$k
+44060 46533 moveto
+P$l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+51987 46694 moveto
+P$m
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+60220 46874 moveto
+P$n
+60018 47049 moveto
+P$o
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+67848 46577 moveto
+P$p
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+76192 46581 moveto
+P$q
+76123 46900 moveto
+P$r
+76104 46581 moveto
+P$s
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+83782 46622 moveto
+P$t
+83993 46453 moveto
+P$u
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+91806 47038 moveto
+P$v
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+92462 46747 moveto
+P$f
+92371 46747 moveto
+P$g
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+99806 47038 moveto
+P$v
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+100306 47038 moveto
+P$h
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+3720 45877 moveto
+P$0
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+4662 45645 moveto
+P$1
+4573 45645 moveto
+P$2
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+11603 45877 moveto
+P$3
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+12203 45745 moveto
+P$4
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+20020 45892 moveto
+P$5
+20376 45645 moveto
+P$6
+20482 45444 moveto
+P$7
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+27603 45877 moveto
+P$3
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+28209 45381 moveto
+P$8
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+35757 45583 moveto
+P$9
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+36475 45405 moveto
+P$a
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+43567 45700 moveto
+P$b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+44326 45408 moveto
+P$c
+44392 45642 moveto
+P$d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+51517 45700 moveto
+P$b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+52203 45745 moveto
+P$4
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+59720 45877 moveto
+P$0
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+60662 45645 moveto
+P$1
+60573 45645 moveto
+P$2
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+67603 45877 moveto
+P$3
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+68203 45745 moveto
+P$4
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+76020 45892 moveto
+P$5
+76376 45645 moveto
+P$6
+76482 45444 moveto
+P$7
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+83603 45877 moveto
+P$3
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+84209 45381 moveto
+P$8
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+91757 45583 moveto
+P$9
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+92475 45405 moveto
+P$a
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+99567 45700 moveto
+P$b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+100326 45408 moveto
+P$c
+100392 45642 moveto
+P$d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+4793 47735 moveto
+P$w
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+5420 47901 moveto
+P$x
+5457 48187 moveto
+P$y
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+5954 47960 moveto
+P$z
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+6812 48415 moveto
+P$10
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+7420 47901 moveto
+P$x
+7457 48187 moveto
+P$y
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+7970 48027 moveto
+P$11
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+8470 48481 moveto
+P$12
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+9648 48463 moveto
+P$13
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+10254 48067 moveto
+P$14
+10082 48067 moveto
+P$15
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+10848 48463 moveto
+P$13
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+11459 48249 moveto
+P$16
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+56556 48127 moveto
+P$17
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+57239 47899 moveto
+P$18
+57232 47959 moveto
+P$19
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+57896 48173 moveto
+P$1a
+57521 47682 moveto
+P$1b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+58420 48027 moveto
+P$11
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+59062 48415 moveto
+P$10
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+59670 47901 moveto
+P$x
+59707 48187 moveto
+P$y
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+60220 48027 moveto
+P$11
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+60720 48481 moveto
+P$12
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+61898 48463 moveto
+P$13
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+62504 48067 moveto
+P$14
+62332 48067 moveto
+P$15
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+63098 48463 moveto
+P$13
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+63709 48249 moveto
+P$16
+fill
+grestore
+showpage
+%plantuml done
+%%EOF
diff --git a/20-implementierungsheft/assets/gantt-plan.pdf b/20-implementierungsheft/assets/gantt-plan.pdf
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/20-implementierungsheft/assets/gantt-plan.pdf
diff --git a/20-implementierungsheft/assets/gantt-reality-eps-converted-to.pdf b/20-implementierungsheft/assets/gantt-reality-eps-converted-to.pdf
new file mode 100644
index 0000000..5379947
--- /dev/null
+++ b/20-implementierungsheft/assets/gantt-reality-eps-converted-to.pdf
Binary files differ
diff --git a/20-implementierungsheft/assets/gantt-reality.eps b/20-implementierungsheft/assets/gantt-reality.eps
new file mode 100644
index 0000000..435dbb1
--- /dev/null
+++ b/20-implementierungsheft/assets/gantt-reality.eps
@@ -0,0 +1,11142 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%Creator: PlantUML v1.2023.0
+%%Title: noTitle
+%%BoundingBox: 0 0 2081 554
+%%ColorUsage: Color
+%%Origin: 0 0
+%%EndComments
+
+gsave
+0 554 translate
+.01 -.01 scale
+/simplerect {
+newpath moveto 1 index 0 rlineto
+0 exch rlineto
+neg 0 rlineto
+} def
+/rquadto {
+3 index 3 index 4 2 roll rcurveto
+} def
+/P$h {
+134 12 rlineto
+0 26 rlineto
+-353 0 rlineto
+0 -26 rlineto
+134 -12 rlineto
+0 -534 rlineto
+-131 46 rlineto
+0 -25 rlineto
+190 -109 rlineto
+25 0 rlineto
+0 621 rlineto
+closepath
+} def
+/P$1e {
+0 -60 -42 -87 rquadto
+-40 -26 -120 -26 rquadto
+-173 0 rlineto
+0 240 rlineto
+173 0 rlineto
+81 0 121 -31 rquadto
+40 -31 40 -95 rquadto
+closepath
+} def
+/P$32 {
+109 17 rlineto
+0 34 rlineto
+-340 0 rlineto
+0 -34 rlineto
+109 -17 rlineto
+0 -750 rlineto
+-109 -15 rlineto
+0 -34 rlineto
+340 0 rlineto
+0 34 rlineto
+-109 15 rlineto
+0 750 rlineto
+} def
+/P$k {
+0 143 rlineto
+-84 0 rlineto
+0 -143 rlineto
+-290 0 rlineto
+0 -65 rlineto
+318 -448 rlineto
+56 0 rlineto
+0 443 rlineto
+89 0 rlineto
+0 70 rlineto
+-89 0 rlineto
+closepath
+} def
+/P$a {
+0 125 rlineto
+-21 0 rlineto
+-28 -54 rlineto
+-25 0 -57 7 rquadto
+-32 6 -57 17 rquadto
+0 342 rlineto
+78 12 rlineto
+0 21 rlineto
+-217 0 rlineto
+0 -21 rlineto
+57 -12 rlineto
+0 -390 rlineto
+-57 -12 rlineto
+0 -21 rlineto
+132 0 rlineto
+4 57 rlineto
+29 -25 79 -46 rquadto
+50 -23 79 -23 rquadto
+7 0 rlineto
+closepath
+} def
+/P$1v {
+0 -85 rlineto
+268 0 rlineto
+0 85 rlineto
+-268 0 rlineto
+} def
+/P$2j {
+0 -65 -45 -100 rquadto
+-45 -35 -129 -35 rquadto
+-243 0 rlineto
+0 279 rlineto
+248 0 rlineto
+81 0 125 -37 rquadto
+45 -37 45 -106 rquadto
+} def
+/P$1j {
+-196 -265 rlineto
+-71 59 rlineto
+0 206 rlineto
+-96 0 rlineto
+0 -796 rlineto
+96 0 rlineto
+0 498 rlineto
+256 -282 rlineto
+112 0 rlineto
+-235 250 rlineto
+248 331 rlineto
+-112 0 rlineto
+} def
+/P$8 {
+0 51 -3 73 rquadto
+34 -20 78 -34 rquadto
+45 -15 76 -15 rquadto
+59 0 89 35 rquadto
+31 34 31 100 rquadto
+0 301 rlineto
+56 12 rlineto
+0 21 rlineto
+-198 0 rlineto
+0 -21 rlineto
+60 -12 rlineto
+0 -295 rlineto
+0 -84 -81 -84 rquadto
+-45 0 -109 14 rquadto
+0 365 rlineto
+62 12 rlineto
+0 21 rlineto
+-201 0 rlineto
+0 -21 rlineto
+57 -12 rlineto
+0 -626 rlineto
+-68 -10 rlineto
+0 -21 rlineto
+150 0 rlineto
+0 198 rlineto
+closepath
+} def
+/P$28 {
+0 -146 -175 -146 rquadto
+-204 0 rlineto
+0 298 rlineto
+207 0 rlineto
+171 0 171 -151 rquadto
+} def
+/P$y {
+206 0 206 151 rquadto
+0 357 rlineto
+54 14 rlineto
+0 39 rlineto
+-201 0 rlineto
+-14 -42 rlineto
+-45 31 -82 42 rquadto
+-35 12 -73 12 rquadto
+-170 0 -170 -165 rquadto
+0 -60 25 -98 rquadto
+25 -37 71 -54 rquadto
+48 -18 150 -20 rquadto
+71 -1 rlineto
+0 -81 rlineto
+0 -100 -81 -100 rquadto
+-50 0 -110 31 rquadto
+-21 68 rlineto
+-39 0 rlineto
+0 -132 rlineto
+89 -14 129 -17 rquadto
+42 -3 85 -3 rquadto
+closepath
+} def
+/P$3g {
+235 0 350 106 rquadto
+114 104 114 315 rquadto
+0 212 -110 323 rquadto
+-109 109 -326 109 rquadto
+-303 -3 rlineto
+-109 0 rlineto
+0 -34 rlineto
+109 -17 rlineto
+0 -750 rlineto
+-109 -15 rlineto
+0 -34 rlineto
+385 0 rlineto
+} def
+/P$1 {
+0 240 -215 240 rquadto
+-103 0 -156 -60 rquadto
+-53 -62 -53 -179 rquadto
+0 -117 53 -178 rquadto
+53 -62 160 -62 rquadto
+104 0 157 60 rquadto
+53 60 53 179 rquadto
+closepath
+} def
+/P$2x {
+0 281 rlineto
+423 0 rlineto
+0 85 rlineto
+-423 0 rlineto
+0 306 rlineto
+-101 0 rlineto
+0 -756 rlineto
+537 0 rlineto
+0 82 rlineto
+-435 0 rlineto
+} def
+/P$35 {
+-82 3 rlineto
+-85 3 -115 32 rquadto
+-29 29 -29 100 rquadto
+0 110 90 110 rquadto
+42 0 73 -9 rquadto
+32 -9 64 -25 rquadto
+0 -212 rlineto
+} def
+/P$2c {
+0 -121 -32 -173 rquadto
+-31 -53 -104 -53 rquadto
+-81 0 -118 56 rquadto
+-37 54 -37 176 rquadto
+0 114 35 168 rquadto
+37 54 120 54 rquadto
+71 0 104 -53 rquadto
+32 -54 32 -176 rquadto
+} def
+/P$1k {
+0 100 40 154 rquadto
+42 53 121 53 rquadto
+62 0 100 -25 rquadto
+37 -25 51 -64 rquadto
+84 25 rlineto
+-51 137 -235 137 rquadto
+-129 0 -196 -76 rquadto
+-67 -76 -67 -228 rquadto
+0 -145 67 -221 rquadto
+67 -76 192 -76 rquadto
+256 0 256 309 rquadto
+0 12 rlineto
+-414 0 rlineto
+closepath
+} def
+/P$1q {
+0 151 -67 226 rquadto
+-67 75 -195 75 rquadto
+-126 0 -192 -76 rquadto
+-64 -78 -64 -225 rquadto
+0 -301 259 -301 rquadto
+134 0 196 73 rquadto
+62 73 62 228 rquadto
+closepath
+} def
+/P$0 {
+-17 0 rlineto
+-239 -562 rlineto
+0 523 rlineto
+87 12 rlineto
+0 26 rlineto
+-223 0 rlineto
+0 -26 rlineto
+84 -12 rlineto
+0 -576 rlineto
+-84 -14 rlineto
+0 -25 rlineto
+198 0 rlineto
+214 498 rlineto
+231 -498 rlineto
+187 0 rlineto
+0 25 rlineto
+-82 14 rlineto
+0 576 rlineto
+82 12 rlineto
+0 26 rlineto
+-265 0 rlineto
+0 -26 rlineto
+89 -12 rlineto
+0 -523 rlineto
+-262 562 rlineto
+} def
+/P$37 {
+0 109 101 109 rquadto
+79 0 146 -20 rquadto
+0 -470 rlineto
+-89 -17 rlineto
+0 -28 rlineto
+193 0 rlineto
+0 553 rlineto
+76 15 rlineto
+0 28 rlineto
+-175 0 rlineto
+-4 -48 rlineto
+-45 25 -104 43 rquadto
+-57 17 -98 17 rquadto
+-151 0 -151 -175 rquadto
+0 -389 rlineto
+-76 -17 rlineto
+0 -28 rlineto
+181 0 rlineto
+0 426 rlineto
+} def
+/P$l {
+-1 0 rlineto
+-234 329 rlineto
+235 0 rlineto
+0 -329 rlineto
+closepath
+} def
+/P$1b {
+0 -109 -26 -159 rquadto
+-26 -50 -87 -50 rquadto
+-21 0 -48 4 rquadto
+-26 4 -43 14 rquadto
+0 421 rlineto
+37 9 92 9 rquadto
+57 0 85 -56 rquadto
+28 -56 28 -184 rquadto
+closepath
+} def
+/P$7 {
+-50 0 -78 42 rquadto
+-26 40 -26 120 rquadto
+196 0 rlineto
+0 -87 -23 -125 rquadto
+-21 -37 -68 -37 rquadto
+closepath
+} def
+/P$27 {
+0 107 -70 171 rquadto
+-68 62 -189 62 rquadto
+-223 0 rlineto
+0 295 rlineto
+-101 0 rlineto
+0 -756 rlineto
+318 0 rlineto
+126 0 195 59 rquadto
+70 59 70 167 rquadto
+closepath
+} def
+/P$m {
+112 0 167 46 rquadto
+56 45 56 140 rquadto
+0 98 -60 151 rquadto
+-59 53 -170 53 rquadto
+-93 0 -165 -20 rquadto
+-6 -137 rlineto
+32 0 rlineto
+21 90 rlineto
+21 12 51 20 rquadto
+29 6 57 6 rquadto
+76 0 112 -35 rquadto
+37 -35 37 -123 rquadto
+0 -59 -15 -90 rquadto
+-15 -31 -50 -45 rquadto
+-34 -15 -92 -15 rquadto
+-45 0 -87 12 rquadto
+-46 0 rlineto
+0 -325 rlineto
+332 0 rlineto
+0 75 rlineto
+-289 0 rlineto
+0 207 rlineto
+53 -10 114 -10 rquadto
+closepath
+} def
+/P$j {
+0 87 -60 137 rquadto
+-59 50 -170 50 rquadto
+-93 0 -176 -20 rquadto
+-4 -137 rlineto
+31 0 rlineto
+21 90 rlineto
+20 10 54 18 rquadto
+34 7 65 7 rquadto
+76 0 112 -34 rquadto
+37 -35 37 -117 rquadto
+0 -64 -34 -96 rquadto
+-34 -34 -104 -37 rquadto
+-70 -4 rlineto
+0 -40 rlineto
+70 -3 rlineto
+54 -3 81 -34 rquadto
+26 -31 26 -95 rquadto
+0 -65 -28 -95 rquadto
+-28 -31 -90 -31 rquadto
+-26 0 -54 7 rquadto
+-28 7 -50 18 rquadto
+-17 79 rlineto
+-32 0 rlineto
+0 -125 rlineto
+48 -12 82 -17 rquadto
+35 -4 71 -4 rquadto
+209 0 209 160 rquadto
+0 68 -37 109 rquadto
+-37 39 -106 50 rquadto
+89 9 131 50 rquadto
+42 40 42 114 rquadto
+closepath
+} def
+/P$2f {
+0 -73 rlineto
+325 -432 rlineto
+-307 0 rlineto
+0 -75 rlineto
+421 0 rlineto
+0 73 rlineto
+-326 432 rlineto
+337 0 rlineto
+0 75 rlineto
+-450 0 rlineto
+} def
+/P$2k {
+0 156 -48 279 rquadto
+-48 123 -150 232 rquadto
+-93 0 rlineto
+101 -112 148 -237 rquadto
+46 -125 46 -275 rquadto
+0 -150 -48 -275 rquadto
+-46 -125 -146 -237 rquadto
+93 0 rlineto
+101 109 150 232 rquadto
+48 123 48 278 rquadto
+0 1 rlineto
+} def
+/P$s {
+0 -67 -26 -98 rquadto
+-26 -32 -79 -32 rquadto
+-51 0 -78 31 rquadto
+-25 31 -25 100 rquadto
+0 68 25 98 rquadto
+25 28 78 28 rquadto
+54 0 79 -29 rquadto
+26 -29 26 -96 rquadto
+closepath
+} def
+/P$1o {
+0 121 31 175 rquadto
+32 51 104 51 rquadto
+82 0 118 -56 rquadto
+37 -57 37 -176 rquadto
+0 -115 -37 -168 rquadto
+-35 -54 -117 -54 rquadto
+-73 0 -106 54 rquadto
+-31 53 -31 175 rquadto
+closepath
+} def
+/P$1t {
+0 -445 rlineto
+0 -62 -3 -135 rquadto
+90 0 rlineto
+4 98 4 118 rquadto
+1 0 rlineto
+23 -75 53 -101 rquadto
+31 -28 85 -28 rquadto
+18 0 39 6 rquadto
+0 87 rlineto
+-20 -4 -51 -4 rquadto
+-60 0 -92 51 rquadto
+-31 51 -31 148 rquadto
+0 303 rlineto
+-96 0 rlineto
+} def
+/P$2n {
+-85 -221 rlineto
+-345 0 rlineto
+-87 221 rlineto
+-106 0 rlineto
+309 -756 rlineto
+117 0 rlineto
+303 756 rlineto
+-104 0 rlineto
+closepath
+} def
+/P$3n {
+-109 -15 rlineto
+0 -34 rlineto
+326 0 rlineto
+0 34 rlineto
+-95 15 rlineto
+0 526 rlineto
+0 85 -26 150 rquadto
+-26 64 -79 101 rquadto
+-53 35 -117 35 rquadto
+-81 0 -132 -18 rquadto
+0 -154 rlineto
+42 0 rlineto
+18 87 rlineto
+12 15 34 23 rquadto
+23 7 50 7 rquadto
+89 0 89 -120 rquadto
+0 -639 rlineto
+} def
+/P$21 {
+0 -756 rlineto
+103 0 rlineto
+0 756 rlineto
+-103 0 rlineto
+} def
+/P$1z {
+0 -581 rlineto
+96 0 rlineto
+0 581 rlineto
+-96 0 rlineto
+} def
+/P$3k {
+-131 15 rlineto
+0 746 rlineto
+168 0 rlineto
+134 0 198 -12 rquadto
+39 -176 rlineto
+40 0 rlineto
+-10 243 rlineto
+-667 0 rlineto
+0 -34 rlineto
+109 -17 rlineto
+0 -750 rlineto
+-109 -15 rlineto
+0 -34 rlineto
+362 0 rlineto
+0 34 rlineto
+} def
+/P$n {
+0 101 -51 157 rquadto
+-51 54 -148 54 rquadto
+-110 0 -168 -85 rquadto
+-57 -85 -57 -246 rquadto
+0 -104 29 -181 rquadto
+31 -78 85 -117 rquadto
+56 -40 128 -40 rquadto
+71 0 142 17 rquadto
+0 112 rlineto
+-31 0 rlineto
+-17 -65 rlineto
+-17 -9 -45 -15 rquadto
+-26 -7 -48 -7 rquadto
+-70 0 -110 70 rquadto
+-39 68 -43 201 rquadto
+79 -42 160 -42 rquadto
+85 0 131 48 rquadto
+45 48 45 140 rquadto
+closepath
+} def
+/P$11 {
+-39 20 rlineto
+-82 42 -148 42 rquadto
+-151 0 -151 -162 rquadto
+0 -350 rlineto
+-54 -14 rlineto
+0 -39 rlineto
+223 0 rlineto
+0 381 rlineto
+0 48 20 76 rquadto
+21 28 60 28 rquadto
+43 0 89 -20 rquadto
+0 -412 rlineto
+-51 -14 rlineto
+0 -39 rlineto
+220 0 rlineto
+0 498 rlineto
+54 14 rlineto
+0 39 rlineto
+-214 0 rlineto
+-9 -48 rlineto
+} def
+/P$3a {
+103 15 rlineto
+0 28 rlineto
+-309 0 rlineto
+0 -28 rlineto
+101 -15 rlineto
+0 -814 rlineto
+-101 -15 rlineto
+0 -28 rlineto
+206 0 rlineto
+0 857 rlineto
+closepath
+} def
+/P$4 {
+0 84 78 84 rquadto
+60 0 112 -15 rquadto
+0 -362 rlineto
+-68 -12 rlineto
+0 -21 rlineto
+150 0 rlineto
+0 425 rlineto
+57 12 rlineto
+0 21 rlineto
+-134 0 rlineto
+-3 -37 rlineto
+-34 18 -79 32 rquadto
+-45 14 -76 14 rquadto
+-117 0 -117 -134 rquadto
+0 -300 rlineto
+-59 -12 rlineto
+0 -21 rlineto
+140 0 rlineto
+0 328 rlineto
+closepath
+} def
+/P$14 {
+-498 0 rlineto
+0 -110 rlineto
+51 -53 93 -96 rquadto
+93 -92 135 -145 rquadto
+43 -53 64 -109 rquadto
+20 -57 20 -129 rquadto
+0 -64 -31 -103 rquadto
+-29 -39 -81 -39 rquadto
+-37 0 -59 7 rquadto
+-20 6 -39 21 rquadto
+-25 114 rlineto
+-51 0 rlineto
+0 -178 rlineto
+46 -10 92 -18 rquadto
+45 -7 96 -7 rquadto
+129 0 198 54 rquadto
+68 53 68 151 rquadto
+0 60 -20 110 rquadto
+-20 50 -65 98 rquadto
+-43 46 -175 154 rquadto
+-50 40 -109 92 rquadto
+385 0 rlineto
+0 132 rlineto
+} def
+/P$f {
+0 339 -215 339 rquadto
+-103 0 -156 -85 rquadto
+-53 -87 -53 -253 rquadto
+0 -162 53 -248 rquadto
+53 -87 160 -87 rquadto
+103 0 156 85 rquadto
+54 84 54 250 rquadto
+closepath
+} def
+/P$b {
+32 0 rlineto
+17 89 rlineto
+17 21 60 40 rquadto
+45 17 87 17 rquadto
+68 0 106 -34 rquadto
+39 -35 39 -96 rquadto
+0 -35 -15 -57 rquadto
+-14 -23 -39 -39 rquadto
+-23 -15 -54 -26 rquadto
+-29 -10 -62 -21 rquadto
+-32 -12 -64 -25 rquadto
+-29 -14 -54 -34 rquadto
+-23 -21 -39 -53 rquadto
+-14 -31 -14 -76 rquadto
+0 -78 57 -121 rquadto
+59 -45 162 -45 rquadto
+79 0 171 21 rquadto
+0 135 rlineto
+-31 0 rlineto
+-17 -79 rlineto
+-50 -37 -123 -37 rquadto
+-64 0 -101 28 rquadto
+-37 26 -37 73 rquadto
+0 31 14 53 rquadto
+15 20 39 35 rquadto
+25 14 56 25 rquadto
+31 10 64 21 rquadto
+32 10 62 26 rquadto
+31 14 54 35 rquadto
+25 21 39 54 rquadto
+15 31 15 78 rquadto
+0 95 -57 146 rquadto
+-57 51 -167 51 rquadto
+-53 0 -106 -9 rquadto
+-53 -9 -95 -25 rquadto
+0 -151 rlineto
+} def
+/P$2s {
+-93 0 -151 -37 rquadto
+-56 -37 -71 -106 rquadto
+96 -14 rlineto
+9 40 42 62 rquadto
+34 21 87 21 rquadto
+145 0 145 -168 rquadto
+0 -93 rlineto
+-1 0 rlineto
+-28 56 -76 84 rquadto
+-46 28 -110 28 rquadto
+-106 0 -156 -70 rquadto
+-50 -71 -50 -223 rquadto
+0 -154 53 -228 rquadto
+54 -73 164 -73 rquadto
+62 0 107 28 rquadto
+45 28 70 81 rquadto
+0 0 rlineto
+0 -17 1 -56 rquadto
+3 -40 4 -43 rquadto
+92 0 rlineto
+-3 29 -3 120 rquadto
+0 443 rlineto
+0 245 -243 245 rquadto
+closepath
+} def
+/P$1w {
+0 104 -82 162 rquadto
+-81 57 -229 57 rquadto
+-276 0 -320 -192 rquadto
+100 -20 rlineto
+17 68 71 101 rquadto
+56 31 153 31 rquadto
+98 0 151 -34 rquadto
+54 -34 54 -100 rquadto
+0 -37 -17 -60 rquadto
+-15 -23 -46 -37 rquadto
+-31 -15 -73 -25 rquadto
+-42 -10 -93 -21 rquadto
+-89 -20 -135 -40 rquadto
+-46 -20 -73 -43 rquadto
+-26 -25 -40 -57 rquadto
+-14 -32 -14 -75 rquadto
+0 -96 73 -150 rquadto
+75 -53 214 -53 rquadto
+128 0 195 40 rquadto
+68 39 96 134 rquadto
+-101 17 rlineto
+-15 -59 -62 -85 rquadto
+-46 -28 -129 -28 rquadto
+-90 0 -139 29 rquadto
+-46 29 -46 90 rquadto
+0 34 17 57 rquadto
+18 21 53 37 rquadto
+35 15 140 39 rquadto
+34 7 68 17 rquadto
+34 7 65 20 rquadto
+32 10 59 26 rquadto
+28 15 48 39 rquadto
+20 21 31 53 rquadto
+12 29 12 70 rquadto
+} def
+/P$1f {
+0 -132 -187 -132 rquadto
+-192 0 rlineto
+0 271 rlineto
+200 0 rlineto
+93 0 135 -34 rquadto
+43 -34 43 -104 rquadto
+} def
+/P$1d {
+0 100 -73 156 rquadto
+-73 56 -204 56 rquadto
+-306 0 rlineto
+0 -756 rlineto
+275 0 rlineto
+265 0 265 182 rquadto
+0 67 -37 114 rquadto
+-37 45 -106 60 rquadto
+90 9 139 59 rquadto
+48 50 48 126 rquadto
+closepath
+} def
+/P$9 {
+0 254 rlineto
+107 12 rlineto
+0 26 rlineto
+-279 0 rlineto
+0 -26 rlineto
+76 -12 rlineto
+0 -576 rlineto
+-84 -14 rlineto
+0 -25 rlineto
+492 0 rlineto
+0 156 rlineto
+-32 0 rlineto
+-15 -106 rlineto
+-54 -6 -157 -6 rquadto
+-106 0 rlineto
+0 273 rlineto
+192 0 rlineto
+15 -78 rlineto
+29 0 rlineto
+0 200 rlineto
+-29 0 rlineto
+-15 -78 rlineto
+-192 0 rlineto
+} def
+/P$1x {
+31 -57 75 -84 rquadto
+43 -26 110 -26 rquadto
+93 0 139 46 rquadto
+45 46 45 157 rquadto
+0 387 rlineto
+-96 0 rlineto
+0 -368 rlineto
+0 -60 -12 -90 rquadto
+-10 -29 -37 -43 rquadto
+-25 -14 -70 -14 rquadto
+-68 0 -109 46 rquadto
+-40 46 -40 128 rquadto
+0 342 rlineto
+-96 0 rlineto
+0 -796 rlineto
+96 0 rlineto
+0 207 rlineto
+0 32 -3 67 rquadto
+-1 34 -1 40 rquadto
+1 0 rlineto
+} def
+/P$1c {
+-56 -14 rlineto
+0 -37 rlineto
+225 0 rlineto
+0 201 rlineto
+0 54 -6 110 rquadto
+23 -18 67 -31 rquadto
+45 -14 87 -14 rquadto
+120 0 175 65 rquadto
+54 65 54 209 rquadto
+0 142 -70 223 rquadto
+-70 79 -198 79 rquadto
+-95 0 -278 -40 rquadto
+0 -753 rlineto
+} def
+/P$36 {
+48 -28 103 -45 rquadto
+56 -18 92 -18 rquadto
+78 0 117 45 rquadto
+39 45 39 129 rquadto
+0 393 rlineto
+71 15 rlineto
+0 28 rlineto
+-256 0 rlineto
+0 -28 rlineto
+79 -15 rlineto
+0 -381 rlineto
+0 -53 -26 -82 rquadto
+-25 -31 -79 -31 rquadto
+-56 0 -140 18 rquadto
+0 476 rlineto
+81 15 rlineto
+0 28 rlineto
+-257 0 rlineto
+0 -28 rlineto
+71 -15 rlineto
+0 -507 rlineto
+-71 -17 rlineto
+0 -28 rlineto
+170 0 rlineto
+6 48 rlineto
+} def
+/P$3s {
+0 -137 -40 -198 rquadto
+-39 -62 -123 -62 rquadto
+-84 0 -121 59 rquadto
+-35 59 -35 201 rquadto
+0 143 37 204 rquadto
+37 59 120 59 rquadto
+82 0 123 -62 rquadto
+40 -62 40 -201 rquadto
+closepath
+} def
+/P$13 {
+-220 -515 rlineto
+-37 -14 rlineto
+0 -39 rlineto
+281 0 rlineto
+0 39 rlineto
+-65 15 rlineto
+129 304 rlineto
+115 -306 rlineto
+-65 -14 rlineto
+0 -39 rlineto
+181 0 rlineto
+0 39 rlineto
+-40 12 rlineto
+-217 534 rlineto
+-37 95 -65 137 rquadto
+-28 43 -62 65 rquadto
+-34 21 -78 21 rquadto
+-46 0 -96 -10 rquadto
+0 -142 rlineto
+35 0 rlineto
+25 73 rlineto
+17 14 42 14 rquadto
+23 0 39 -10 rquadto
+17 -10 32 -31 rquadto
+15 -18 28 -48 rquadto
+14 -28 39 -85 rquadto
+} def
+/P$2d {
+0 510 rlineto
+-96 0 rlineto
+0 -510 rlineto
+-81 0 rlineto
+0 -70 rlineto
+81 0 rlineto
+0 -65 rlineto
+0 -79 34 -114 rquadto
+35 -34 107 -34 rquadto
+40 0 68 6 rquadto
+0 73 rlineto
+-25 -4 -43 -4 rquadto
+-37 0 -54 18 rquadto
+-15 18 -15 68 rquadto
+0 51 rlineto
+114 0 rlineto
+0 70 rlineto
+-114 0 rlineto
+} def
+/P$o {
+57 0 84 -39 rquadto
+26 -39 26 -126 rquadto
+0 -79 -25 -115 rquadto
+-25 -35 -79 -35 rquadto
+-67 0 -142 25 rquadto
+0 148 32 220 rquadto
+34 71 103 71 rquadto
+closepath
+} def
+/P$19 {
+112 0 162 59 rquadto
+50 59 50 185 rquadto
+0 48 rlineto
+-289 0 rlineto
+0 9 rlineto
+0 87 14 125 rquadto
+14 35 45 56 rquadto
+32 18 87 18 rquadto
+51 0 129 -17 rquadto
+0 45 rlineto
+-31 18 -82 31 rquadto
+-51 12 -100 12 rquadto
+-135 0 -201 -70 rquadto
+-64 -70 -64 -218 rquadto
+0 -143 60 -214 rquadto
+62 -71 187 -71 rquadto
+closepath
+} def
+/P$u {
+-121 0 -121 170 rquadto
+0 75 29 110 rquadto
+29 34 90 34 rquadto
+62 0 126 -25 rquadto
+0 -150 -29 -220 rquadto
+-29 -70 -95 -70 rquadto
+closepath
+} def
+/P$2t {
+0 -70 -20 -121 rquadto
+-18 -51 -54 -78 rquadto
+-34 -28 -79 -28 rquadto
+-73 0 -107 54 rquadto
+-32 53 -32 173 rquadto
+0 118 31 171 rquadto
+31 51 107 51 rquadto
+45 0 81 -26 rquadto
+35 -26 54 -76 rquadto
+20 -51 20 -120 rquadto
+} def
+/P$3e {
+0 -142 -26 -204 rquadto
+-26 -62 -85 -62 rquadto
+-56 0 -81 59 rquadto
+-25 59 -25 207 rquadto
+0 148 25 209 rquadto
+25 60 81 60 rquadto
+57 0 84 -62 rquadto
+28 -64 28 -207 rquadto
+closepath
+} def
+/P$g {
+0 -157 -29 -226 rquadto
+-29 -70 -95 -70 rquadto
+-62 0 -90 65 rquadto
+-28 65 -28 231 rquadto
+0 165 28 234 rquadto
+28 67 90 67 rquadto
+64 0 93 -70 rquadto
+31 -71 31 -231 rquadto
+closepath
+} def
+/P$20 {
+-67 0 -104 -42 rquadto
+-35 -40 -35 -115 rquadto
+0 -193 rlineto
+0 -62 -28 -92 rquadto
+-28 -31 -87 -34 rquadto
+0 -68 rlineto
+57 -1 85 -32 rquadto
+29 -31 29 -93 rquadto
+0 -193 rlineto
+0 -76 34 -117 rquadto
+35 -40 106 -40 rquadto
+73 0 rlineto
+0 68 rlineto
+-34 0 rlineto
+-48 0 -70 29 rquadto
+-20 28 -20 85 rquadto
+0 190 rlineto
+0 51 -28 89 rquadto
+-28 35 -75 46 rquadto
+0 1 rlineto
+46 10 75 48 rquadto
+28 35 28 87 rquadto
+0 192 rlineto
+0 56 20 85 rquadto
+21 29 70 29 rquadto
+34 0 rlineto
+0 68 rlineto
+-73 0 rlineto
+} def
+/P$p {
+-32 0 rlineto
+0 -154 rlineto
+406 0 rlineto
+0 37 rlineto
+-292 617 rlineto
+-64 0 rlineto
+287 -579 rlineto
+-287 0 rlineto
+-17 79 rlineto
+closepath
+} def
+/P$3p {
+-73 23 -153 40 rquadto
+-79 15 -171 15 rquadto
+-206 0 -321 -110 rquadto
+-115 -112 -115 -317 rquadto
+0 -223 112 -334 rquadto
+112 -110 328 -110 rquadto
+154 0 298 37 rquadto
+0 182 rlineto
+-42 0 rlineto
+-17 -104 rlineto
+-43 -31 -104 -46 rquadto
+-60 -17 -129 -17 rquadto
+-162 0 -237 96 rquadto
+-75 96 -75 295 rquadto
+0 187 76 284 rquadto
+78 96 229 96 rquadto
+53 0 110 -12 rquadto
+59 -12 90 -31 rquadto
+0 -242 rlineto
+-109 -15 rlineto
+0 -34 rlineto
+314 0 rlineto
+0 34 rlineto
+-82 15 rlineto
+0 278 rlineto
+} def
+/P$2l {
+50 0 70 -29 rquadto
+21 -29 21 -85 rquadto
+0 -192 rlineto
+0 -53 28 -89 rquadto
+28 -35 75 -46 rquadto
+0 -1 rlineto
+-45 -10 -75 -46 rquadto
+-28 -35 -28 -89 rquadto
+0 -190 rlineto
+0 -57 -21 -85 rquadto
+-20 -29 -70 -29 rquadto
+-31 0 rlineto
+0 -68 rlineto
+70 0 rlineto
+70 0 106 40 rquadto
+35 40 35 117 rquadto
+0 193 rlineto
+0 62 28 93 rquadto
+28 31 87 32 rquadto
+0 68 rlineto
+-59 1 -87 32 rquadto
+-28 31 -28 93 rquadto
+0 193 rlineto
+0 75 -37 115 rquadto
+-35 42 -104 42 rquadto
+-70 0 rlineto
+0 -68 rlineto
+31 0 rlineto
+} def
+/P$2w {
+0 -184 98 -285 rquadto
+100 -101 278 -101 rquadto
+126 0 204 43 rquadto
+78 42 120 135 rquadto
+-96 28 rlineto
+-32 -64 -89 -93 rquadto
+-56 -29 -140 -29 rquadto
+-131 0 -201 79 rquadto
+-68 78 -68 223 rquadto
+0 142 73 226 rquadto
+73 82 203 82 rquadto
+75 0 139 -21 rquadto
+64 -23 104 -62 rquadto
+0 -135 rlineto
+-226 0 rlineto
+0 -85 rlineto
+320 0 rlineto
+0 260 rlineto
+-59 60 -146 95 rquadto
+-87 32 -190 32 rquadto
+-117 0 -203 -46 rquadto
+-85 -48 -132 -135 rquadto
+-45 -89 -45 -209 rquadto
+} def
+/P$2u {
+-114 0 rlineto
+-212 -581 rlineto
+103 0 rlineto
+128 378 rlineto
+7 21 37 128 rquadto
+18 -64 rlineto
+20 -62 rlineto
+132 -379 rlineto
+103 0 rlineto
+-217 581 rlineto
+} def
+/P$2z {
+0 304 -214 304 rquadto
+-134 0 -179 -101 rquadto
+-3 0 rlineto
+1 4 1 92 rquadto
+0 226 rlineto
+-96 0 rlineto
+0 -690 rlineto
+0 -89 -3 -118 rquadto
+93 0 rlineto
+1 1 1 15 rquadto
+1 12 3 40 rquadto
+1 26 1 37 rquadto
+1 0 rlineto
+26 -54 68 -78 rquadto
+42 -25 110 -25 rquadto
+107 0 160 71 rquadto
+53 71 53 225 rquadto
+closepath
+} def
+/P$39 {
+-65 0 -101 54 rquadto
+-35 53 -35 156 rquadto
+256 0 rlineto
+0 -112 -29 -160 rquadto
+-29 -50 -89 -50 rquadto
+} def
+/P$12 {
+62 -70 112 -101 rquadto
+51 -31 92 -31 rquadto
+31 0 rlineto
+0 201 rlineto
+-32 0 rlineto
+-34 -73 rlineto
+-35 0 -82 15 rquadto
+-46 15 -82 37 rquadto
+0 334 rlineto
+87 14 rlineto
+0 39 rlineto
+-328 0 rlineto
+0 -39 rlineto
+70 -14 rlineto
+0 -445 rlineto
+-70 -14 rlineto
+0 -39 rlineto
+231 0 rlineto
+6 115 rlineto
+} def
+/P$2v {
+0 -756 rlineto
+573 0 rlineto
+0 82 rlineto
+-471 0 rlineto
+0 243 rlineto
+440 0 rlineto
+0 82 rlineto
+-440 0 rlineto
+0 262 rlineto
+493 0 rlineto
+0 84 rlineto
+-595 0 rlineto
+} def
+/P$3f {
+0 -178 -96 -270 rquadto
+-95 -92 -275 -92 rquadto
+-114 0 rlineto
+0 734 rlineto
+76 4 181 4 rquadto
+156 0 229 -92 rquadto
+75 -92 75 -284 rquadto
+closepath
+} def
+/P$2g {
+-92 0 -162 -32 rquadto
+-68 -34 -107 -98 rquadto
+-37 -65 -37 -154 rquadto
+0 -481 rlineto
+103 0 rlineto
+0 471 rlineto
+0 104 51 159 rquadto
+53 53 153 53 rquadto
+101 0 157 -56 rquadto
+57 -56 57 -162 rquadto
+0 -465 rlineto
+101 0 rlineto
+0 471 rlineto
+0 92 -39 159 rquadto
+-39 65 -110 101 rquadto
+-70 34 -167 34 rquadto
+} def
+/P$i {
+-401 0 rlineto
+0 -71 rlineto
+90 -82 rlineto
+87 -76 128 -123 rquadto
+42 -46 59 -96 rquadto
+18 -51 18 -115 rquadto
+0 -64 -29 -96 rquadto
+-28 -34 -93 -34 rquadto
+-26 0 -54 7 rquadto
+-26 7 -46 18 rquadto
+-17 79 rlineto
+-32 0 rlineto
+0 -125 rlineto
+89 -21 151 -21 rquadto
+107 0 160 45 rquadto
+54 43 54 126 rquadto
+0 54 -21 103 rquadto
+-21 48 -65 96 rquadto
+-43 46 -145 134 rquadto
+-43 35 -92 81 rquadto
+337 0 rlineto
+0 75 rlineto
+closepath
+} def
+/P$1i {
+0 117 35 173 rquadto
+35 54 109 54 rquadto
+51 0 85 -28 rquadto
+35 -28 43 -85 rquadto
+96 6 rlineto
+-10 84 -71 134 rquadto
+-59 50 -151 50 rquadto
+-121 0 -185 -76 rquadto
+-64 -78 -64 -225 rquadto
+0 -146 64 -223 rquadto
+64 -78 184 -78 rquadto
+89 0 148 46 rquadto
+59 45 73 126 rquadto
+-98 7 rlineto
+-7 -48 -39 -76 rquadto
+-29 -28 -85 -28 rquadto
+-76 0 -110 51 rquadto
+-34 50 -34 170 rquadto
+} def
+/P$2y {
+-301 -365 rlineto
+-100 75 rlineto
+0 290 rlineto
+-101 0 rlineto
+0 -756 rlineto
+101 0 rlineto
+0 378 rlineto
+365 -378 rlineto
+120 0 rlineto
+-321 328 rlineto
+365 428 rlineto
+-128 0 rlineto
+} def
+/P$25 {
+0 -504 rlineto
+0 -84 4 -160 rquadto
+-26 95 -48 150 rquadto
+-195 515 rlineto
+-71 0 rlineto
+-198 -515 rlineto
+-29 -90 rlineto
+-17 -59 rlineto
+1 59 rlineto
+1 101 rlineto
+0 504 rlineto
+-90 0 rlineto
+0 -756 rlineto
+134 0 rlineto
+201 523 rlineto
+10 32 20 68 rquadto
+10 35 14 51 rquadto
+3 -20 17 -64 rquadto
+14 -43 18 -56 rquadto
+196 -523 rlineto
+132 0 rlineto
+0 756 rlineto
+-92 0 rlineto
+} def
+/P$3b {
+120 12 rlineto
+0 23 rlineto
+-315 0 rlineto
+0 -23 rlineto
+120 -12 rlineto
+0 -479 rlineto
+-118 42 rlineto
+0 -23 rlineto
+171 -96 rlineto
+21 0 rlineto
+0 557 rlineto
+} def
+/P$3c {
+0 306 -193 306 rquadto
+-92 0 -140 -78 rquadto
+-46 -79 -46 -228 rquadto
+0 -146 46 -223 rquadto
+48 -78 145 -78 rquadto
+92 0 140 76 rquadto
+48 76 48 225 rquadto
+closepath
+} def
+/P$3j {
+-360 0 rlineto
+0 -64 rlineto
+82 -75 rlineto
+78 -68 114 -110 rquadto
+37 -43 53 -89 rquadto
+17 -45 17 -103 rquadto
+0 -57 -26 -87 rquadto
+-25 -29 -84 -29 rquadto
+-23 0 -48 6 rquadto
+-25 6 -43 17 rquadto
+-14 71 rlineto
+-29 0 rlineto
+0 -112 rlineto
+79 -18 135 -18 rquadto
+96 0 145 40 rquadto
+48 39 48 112 rquadto
+0 50 -20 93 rquadto
+-18 43 -57 87 rquadto
+-39 42 -131 120 rquadto
+-39 32 -82 73 rquadto
+303 0 rlineto
+0 67 rlineto
+} def
+/P$16 {
+0 -182 -20 -262 rquadto
+-20 -79 -64 -79 rquadto
+-43 0 -62 78 rquadto
+-18 76 -18 264 rquadto
+0 192 18 271 rquadto
+18 78 62 78 rquadto
+42 0 62 -81 rquadto
+21 -81 21 -268 rquadto
+} def
+/P$d {
+-64 3 rlineto
+-65 1 -89 25 rquadto
+-23 21 -23 76 rquadto
+0 85 70 85 rquadto
+32 0 56 -7 rquadto
+25 -7 50 -18 rquadto
+0 -164 rlineto
+closepath
+} def
+/P$c {
+75 0 110 31 rquadto
+35 29 35 93 rquadto
+0 309 rlineto
+56 12 rlineto
+0 21 rlineto
+-125 0 rlineto
+-9 -45 rlineto
+-56 54 -142 54 rquadto
+-117 0 -117 -135 rquadto
+0 -46 17 -76 rquadto
+17 -29 56 -45 rquadto
+39 -15 114 -17 rquadto
+68 -3 rlineto
+0 -71 rlineto
+0 -46 -17 -68 rquadto
+-17 -23 -53 -23 rquadto
+-50 0 -90 23 rquadto
+-15 57 rlineto
+-28 0 rlineto
+0 -100 rlineto
+79 -17 139 -17 rquadto
+closepath
+} def
+/P$w {
+-401 0 rlineto
+0 -71 rlineto
+90 -82 rlineto
+87 -76 128 -123 rquadto
+42 -46 59 -96 rquadto
+18 -51 18 -115 rquadto
+0 -64 -29 -96 rquadto
+-28 -34 -93 -34 rquadto
+-26 0 -54 7 rquadto
+-26 7 -46 18 rquadto
+-17 79 rlineto
+-32 0 rlineto
+0 -125 rlineto
+89 -21 151 -21 rquadto
+107 0 160 45 rquadto
+54 43 54 126 rquadto
+0 54 -21 103 rquadto
+-21 48 -65 96 rquadto
+-43 46 -145 134 rquadto
+-43 35 -92 81 rquadto
+337 0 rlineto
+0 75 rlineto
+} def
+/P$1l {
+-7 -92 -46 -134 rquadto
+-37 -42 -110 -42 rquadto
+-70 0 -110 46 rquadto
+-40 46 -43 129 rquadto
+312 0 rlineto
+} def
+/P$17 {
+0 107 -76 167 rquadto
+-76 59 -214 59 rquadto
+-109 0 -217 -25 rquadto
+-6 -189 rlineto
+53 0 rlineto
+31 125 rlineto
+51 29 106 29 rquadto
+71 0 110 -45 rquadto
+40 -46 40 -128 rquadto
+0 -70 -32 -107 rquadto
+-31 -37 -103 -42 rquadto
+-68 -4 rlineto
+0 -70 rlineto
+65 -4 rlineto
+53 -4 78 -39 rquadto
+25 -34 25 -104 rquadto
+0 -65 -29 -103 rquadto
+-29 -37 -84 -37 rquadto
+-31 0 -51 9 rquadto
+-20 9 -39 20 rquadto
+-25 114 rlineto
+-51 0 rlineto
+0 -178 rlineto
+60 -15 103 -20 rquadto
+43 -6 85 -6 rquadto
+264 0 264 193 rquadto
+0 79 -42 129 rquadto
+-42 48 -120 60 rquadto
+198 23 198 196 rquadto
+closepath
+} def
+/P$3m {
+0 89 -56 134 rquadto
+-56 45 -165 45 rquadto
+-45 0 -100 -9 rquadto
+-53 -9 -82 -20 rquadto
+0 -146 rlineto
+28 0 rlineto
+31 82 rlineto
+48 43 123 43 rquadto
+123 0 123 -104 rquadto
+0 -78 -96 -110 rquadto
+-56 -18 rlineto
+-64 -20 -93 -42 rquadto
+-29 -21 -45 -53 rquadto
+-15 -31 -15 -76 rquadto
+0 -78 53 -123 rquadto
+54 -45 145 -45 rquadto
+65 0 164 20 rquadto
+0 129 rlineto
+-29 0 rlineto
+-26 -68 rlineto
+-34 -31 -106 -31 rquadto
+-51 0 -78 26 rquadto
+-26 25 -26 68 rquadto
+0 35 23 60 rquadto
+25 23 75 40 rquadto
+92 31 120 46 rquadto
+29 14 50 35 rquadto
+20 20 31 48 rquadto
+10 26 10 67 rquadto
+closepath
+} def
+/P$r {
+0 -78 -31 -112 rquadto
+-29 -35 -95 -35 rquadto
+-64 0 -92 34 rquadto
+-28 32 -28 114 rquadto
+0 82 28 115 rquadto
+29 32 92 32 rquadto
+65 0 95 -34 rquadto
+31 -34 31 -114 rquadto
+closepath
+} def
+/P$2q {
+0 -142 -71 -221 rquadto
+-70 -81 -198 -81 rquadto
+-129 0 -201 79 rquadto
+-70 79 -70 223 rquadto
+0 142 71 226 rquadto
+71 82 198 82 rquadto
+131 0 201 -81 rquadto
+70 -81 70 -228 rquadto
+} def
+/P$2o {
+-4 15 rlineto
+-12 43 -39 114 rquadto
+-96 248 rlineto
+282 0 rlineto
+-96 -250 rlineto
+-15 -35 -29 -82 rquadto
+-15 -45 rlineto
+} def
+/P$2m {
+0 -756 rlineto
+101 0 rlineto
+0 671 rlineto
+382 0 rlineto
+0 84 rlineto
+-484 0 rlineto
+} def
+/P$3h {
+0 28 -20 48 rquadto
+-20 20 -48 20 rquadto
+-28 0 -48 -20 rquadto
+-20 -20 -20 -48 rquadto
+0 -28 20 -48 rquadto
+20 -20 48 -20 rquadto
+28 0 48 20 rquadto
+20 20 20 48 rquadto
+closepath
+} def
+/P$e {
+0 87 -60 137 rquadto
+-59 50 -170 50 rquadto
+-93 0 -176 -20 rquadto
+-4 -137 rlineto
+31 0 rlineto
+21 90 rlineto
+20 10 54 18 rquadto
+34 7 65 7 rquadto
+76 0 112 -34 rquadto
+37 -35 37 -117 rquadto
+0 -64 -34 -96 rquadto
+-34 -34 -104 -37 rquadto
+-70 -4 rlineto
+0 -40 rlineto
+70 -3 rlineto
+54 -3 81 -34 rquadto
+26 -31 26 -95 rquadto
+0 -65 -28 -95 rquadto
+-28 -31 -90 -31 rquadto
+-26 0 -54 7 rquadto
+-28 7 -50 18 rquadto
+-17 79 rlineto
+-32 0 rlineto
+0 -125 rlineto
+48 -12 82 -17 rquadto
+35 -4 71 -4 rquadto
+209 0 209 160 rquadto
+0 68 -37 109 rquadto
+-37 39 -106 50 rquadto
+89 9 131 50 rquadto
+42 40 42 114 rquadto
+} def
+/P$23 {
+0 368 rlineto
+0 57 10 89 rquadto
+10 31 35 45 rquadto
+25 14 73 14 rquadto
+68 0 109 -46 rquadto
+40 -48 40 -132 rquadto
+0 -337 rlineto
+96 0 rlineto
+0 457 rlineto
+0 101 3 123 rquadto
+-92 0 rlineto
+0 -3 -1 -14 rquadto
+0 -12 -1 -26 rquadto
+0 -15 0 -59 rquadto
+-1 0 rlineto
+-34 60 -78 85 rquadto
+-43 25 -107 25 rquadto
+-96 0 -140 -46 rquadto
+-43 -48 -43 -157 rquadto
+0 -387 rlineto
+96 0 rlineto
+} def
+/P$5 {
+-25 0 rlineto
+-170 -451 rlineto
+-173 451 rlineto
+-26 0 rlineto
+-217 -631 rlineto
+-56 -14 rlineto
+0 -25 rlineto
+250 0 rlineto
+0 25 rlineto
+-96 14 rlineto
+156 460 rlineto
+176 -454 rlineto
+21 0 rlineto
+168 454 rlineto
+148 -460 rlineto
+-101 -14 rlineto
+0 -25 rlineto
+217 0 rlineto
+0 25 rlineto
+-57 14 rlineto
+-214 631 rlineto
+closepath
+} def
+/P$1n {
+-26 56 -71 81 rquadto
+-43 23 -109 23 rquadto
+-109 0 -160 -73 rquadto
+-51 -75 -51 -225 rquadto
+0 -304 212 -304 rquadto
+67 0 110 25 rquadto
+43 23 70 76 rquadto
+1 0 rlineto
+-1 -65 rlineto
+0 -240 rlineto
+96 0 rlineto
+0 676 rlineto
+0 90 3 120 rquadto
+-92 0 rlineto
+-1 -9 -3 -39 rquadto
+-1 -31 -1 -54 rquadto
+-3 0 rlineto
+closepath
+} def
+/P$3q {
+0 160 rlineto
+-28 0 rlineto
+-35 -70 rlineto
+-32 0 -76 9 rquadto
+-42 7 -75 21 rquadto
+0 446 rlineto
+103 15 rlineto
+0 28 rlineto
+-282 0 rlineto
+0 -28 rlineto
+75 -15 rlineto
+0 -507 rlineto
+-75 -17 rlineto
+0 -28 rlineto
+173 0 rlineto
+6 75 rlineto
+37 -32 101 -60 rquadto
+65 -29 104 -29 rquadto
+9 0 rlineto
+} def
+/P$q {
+0 53 -26 90 rquadto
+-26 37 -70 57 rquadto
+56 20 85 64 rquadto
+31 43 31 106 rquadto
+0 92 -53 139 rquadto
+-51 46 -162 46 rquadto
+-209 0 -209 -185 rquadto
+0 -65 31 -107 rquadto
+31 -42 84 -62 rquadto
+-42 -20 -68 -56 rquadto
+-26 -37 -26 -92 rquadto
+0 -81 50 -125 rquadto
+50 -45 143 -45 rquadto
+90 0 140 45 rquadto
+50 43 50 125 rquadto
+closepath
+} def
+/P$1m {
+0 -368 rlineto
+0 -57 -12 -89 rquadto
+-10 -31 -35 -45 rquadto
+-23 -14 -71 -14 rquadto
+-70 0 -110 48 rquadto
+-39 46 -39 131 rquadto
+0 337 rlineto
+-96 0 rlineto
+0 -457 rlineto
+0 -101 -3 -123 rquadto
+90 0 rlineto
+1 3 1 15 rquadto
+0 10 0 26 rquadto
+1 14 3 57 rquadto
+1 0 rlineto
+32 -60 76 -85 rquadto
+43 -25 109 -25 rquadto
+95 0 139 48 rquadto
+45 46 45 156 rquadto
+0 387 rlineto
+-96 0 rlineto
+} def
+/P$26 {
+0 121 31 175 rquadto
+32 51 104 51 rquadto
+82 0 118 -56 rquadto
+37 -57 37 -176 rquadto
+0 -115 -37 -168 rquadto
+-35 -54 -117 -54 rquadto
+-73 0 -106 54 rquadto
+-31 53 -31 175 rquadto
+} def
+/P$2r {
+-192 0 -228 -198 rquadto
+100 -17 rlineto
+9 62 43 98 rquadto
+34 34 84 34 rquadto
+56 0 87 -39 rquadto
+32 -39 32 -112 rquadto
+0 -450 rlineto
+-145 0 rlineto
+0 -82 rlineto
+248 0 rlineto
+0 531 rlineto
+0 109 -60 173 rquadto
+-59 62 -162 62 rquadto
+} def
+/P$33 {
+48 -26 101 -45 rquadto
+53 -18 93 -18 rquadto
+43 0 81 17 rquadto
+37 15 56 51 rquadto
+48 -26 114 -46 rquadto
+65 -21 109 -21 rquadto
+151 0 151 175 rquadto
+0 393 rlineto
+76 15 rlineto
+0 28 rlineto
+-270 0 rlineto
+0 -28 rlineto
+89 -15 rlineto
+0 -381 rlineto
+0 -109 -101 -109 rquadto
+-17 0 -39 3 rquadto
+-21 1 -43 4 rquadto
+-21 3 -42 7 rquadto
+-20 4 -32 6 rquadto
+10 34 10 75 rquadto
+0 393 rlineto
+89 15 rlineto
+0 28 rlineto
+-282 0 rlineto
+0 -28 rlineto
+87 -15 rlineto
+0 -381 rlineto
+0 -53 -26 -81 rquadto
+-26 -28 -81 -28 rquadto
+-56 0 -139 18 rquadto
+0 471 rlineto
+90 15 rlineto
+0 28 rlineto
+-271 0 rlineto
+0 -28 rlineto
+76 -15 rlineto
+0 -507 rlineto
+-76 -17 rlineto
+0 -28 rlineto
+175 0 rlineto
+4 48 rlineto
+} def
+/P$2 {
+0 -106 -31 -153 rquadto
+-29 -48 -95 -48 rquadto
+-64 0 -92 46 rquadto
+-28 45 -28 154 rquadto
+0 109 28 156 rquadto
+29 46 92 46 rquadto
+64 0 95 -48 rquadto
+31 -48 31 -154 rquadto
+closepath
+} def
+/P$v {
+134 12 rlineto
+0 26 rlineto
+-353 0 rlineto
+0 -26 rlineto
+134 -12 rlineto
+0 -534 rlineto
+-131 46 rlineto
+0 -25 rlineto
+190 -109 rlineto
+25 0 rlineto
+0 621 rlineto
+} def
+/P$x {
+-101 -15 rlineto
+0 -42 rlineto
+375 0 rlineto
+0 42 rlineto
+-89 15 rlineto
+0 475 rlineto
+0 126 -70 196 rquadto
+-70 68 -200 68 rquadto
+-43 0 -87 -6 rquadto
+-42 -4 -67 -12 rquadto
+0 -178 rlineto
+53 0 rlineto
+17 104 rlineto
+10 14 31 21 rquadto
+20 7 45 7 rquadto
+40 0 67 -28 rquadto
+26 -28 26 -84 rquadto
+0 -565 rlineto
+} def
+/P$29 {
+0 117 -46 204 rquadto
+-45 87 -129 134 rquadto
+-82 46 -192 46 rquadto
+-282 0 rlineto
+0 -756 rlineto
+250 0 rlineto
+192 0 296 96 rquadto
+104 95 104 273 rquadto
+closepath
+} def
+/P$3l {
+243 -264 rlineto
+-62 -17 rlineto
+0 -28 rlineto
+210 0 rlineto
+0 28 rlineto
+-73 15 rlineto
+-170 173 rlineto
+218 335 rlineto
+64 15 rlineto
+0 28 rlineto
+-243 0 rlineto
+0 -28 rlineto
+54 -15 rlineto
+-164 -257 rlineto
+-78 85 rlineto
+0 171 rlineto
+62 15 rlineto
+0 28 rlineto
+-243 0 rlineto
+0 -28 rlineto
+75 -15 rlineto
+0 -814 rlineto
+-87 -15 rlineto
+0 -28 rlineto
+193 0 rlineto
+0 614 rlineto
+} def
+/P$18 {
+0 276 rlineto
+129 17 rlineto
+0 42 rlineto
+-407 0 rlineto
+0 -42 rlineto
+93 -17 rlineto
+0 -668 rlineto
+-101 -15 rlineto
+0 -42 rlineto
+654 0 rlineto
+0 210 rlineto
+-54 0 rlineto
+-18 -137 rlineto
+-28 -4 -95 -6 rquadto
+-65 -3 -103 -3 rquadto
+-96 0 rlineto
+0 321 rlineto
+190 0 rlineto
+18 -100 rlineto
+51 0 rlineto
+0 265 rlineto
+-51 0 rlineto
+-18 -101 rlineto
+-190 0 rlineto
+} def
+/P$2e {
+0 82 -62 128 rquadto
+-62 43 -173 43 rquadto
+-109 0 -168 -35 rquadto
+-57 -35 -75 -110 rquadto
+84 -17 rlineto
+12 46 51 68 rquadto
+39 21 107 21 rquadto
+73 0 106 -21 rquadto
+34 -23 34 -68 rquadto
+0 -34 -23 -54 rquadto
+-23 -21 -76 -35 rquadto
+-68 -18 rlineto
+-82 -21 -118 -42 rquadto
+-34 -20 -54 -50 rquadto
+-20 -29 -20 -73 rquadto
+0 -79 56 -120 rquadto
+57 -42 165 -42 rquadto
+96 0 153 34 rquadto
+56 34 71 107 rquadto
+-87 10 rlineto
+-7 -39 -43 -59 rquadto
+-34 -20 -93 -20 rquadto
+-65 0 -96 20 rquadto
+-29 18 -29 59 rquadto
+0 25 12 42 rquadto
+12 15 37 26 rquadto
+25 10 106 31 rquadto
+76 18 110 35 rquadto
+34 15 53 35 rquadto
+20 20 31 46 rquadto
+10 25 10 57 rquadto
+} def
+/P$1u {
+0 -796 rlineto
+96 0 rlineto
+0 796 rlineto
+-96 0 rlineto
+} def
+/P$3t {
+0 79 -54 125 rquadto
+-54 45 -154 45 rquadto
+-84 0 -157 -18 rquadto
+-4 -125 rlineto
+28 0 rlineto
+20 82 rlineto
+17 9 48 17 rquadto
+31 6 57 6 rquadto
+70 0 103 -31 rquadto
+32 -31 32 -104 rquadto
+0 -59 -31 -89 rquadto
+-29 -29 -93 -32 rquadto
+-62 -3 rlineto
+0 -35 rlineto
+62 -4 rlineto
+50 -3 73 -31 rquadto
+23 -28 23 -84 rquadto
+0 -59 -26 -85 rquadto
+-25 -28 -81 -28 rquadto
+-21 0 -48 6 rquadto
+-25 6 -43 17 rquadto
+-15 71 rlineto
+-29 0 rlineto
+0 -112 rlineto
+43 -12 75 -15 rquadto
+31 -3 62 -3 rquadto
+189 0 189 143 rquadto
+0 62 -34 98 rquadto
+-32 35 -93 45 rquadto
+79 7 117 45 rquadto
+39 35 39 101 rquadto
+} def
+/P$2a {
+0 -140 -78 -214 rquadto
+-76 -75 -221 -75 rquadto
+-146 0 rlineto
+0 592 rlineto
+168 0 rlineto
+84 0 146 -35 rquadto
+62 -35 96 -104 rquadto
+34 -68 34 -162 rquadto
+} def
+/P$3d {
+0 -142 -26 -204 rquadto
+-26 -62 -85 -62 rquadto
+-56 0 -81 59 rquadto
+-25 59 -25 207 rquadto
+0 148 25 209 rquadto
+25 60 81 60 rquadto
+57 0 84 -62 rquadto
+28 -64 28 -207 rquadto
+} def
+/P$2b {
+0 304 -214 304 rquadto
+-65 0 -109 -23 rquadto
+-43 -25 -71 -78 rquadto
+0 0 rlineto
+0 17 -3 51 rquadto
+-1 34 -3 39 rquadto
+-93 0 rlineto
+3 -29 3 -120 rquadto
+0 -676 rlineto
+96 0 rlineto
+0 226 rlineto
+0 35 -1 82 rquadto
+1 0 rlineto
+28 -56 71 -79 rquadto
+43 -25 109 -25 rquadto
+110 0 162 75 rquadto
+51 73 51 223 rquadto
+closepath
+} def
+/P$1h {
+53 0 93 -23 rquadto
+42 -23 65 -65 rquadto
+25 -42 25 -87 rquadto
+0 -48 rlineto
+-106 3 rlineto
+-67 0 -103 14 rquadto
+-34 12 -53 39 rquadto
+-18 26 -18 70 rquadto
+0 46 25 73 rquadto
+25 25 71 25 rquadto
+} def
+/P$2i {
+-196 -314 rlineto
+-235 0 rlineto
+0 314 rlineto
+-101 0 rlineto
+0 -756 rlineto
+356 0 rlineto
+126 0 196 57 rquadto
+70 56 70 157 rquadto
+0 84 -50 142 rquadto
+-48 57 -135 71 rquadto
+215 326 rlineto
+-118 0 rlineto
+closepath
+} def
+/P$24 {
+50 0 70 -29 rquadto
+21 -29 21 -85 rquadto
+0 -192 rlineto
+0 -53 28 -89 rquadto
+28 -35 75 -46 rquadto
+0 -1 rlineto
+-45 -10 -75 -46 rquadto
+-28 -35 -28 -89 rquadto
+0 -190 rlineto
+0 -57 -21 -85 rquadto
+-20 -29 -70 -29 rquadto
+-31 0 rlineto
+0 -68 rlineto
+70 0 rlineto
+70 0 106 40 rquadto
+35 40 35 117 rquadto
+0 193 rlineto
+0 62 28 93 rquadto
+28 31 87 32 rquadto
+0 68 rlineto
+-59 1 -87 32 rquadto
+-28 31 -28 93 rquadto
+0 193 rlineto
+0 75 -37 115 rquadto
+-35 42 -104 42 rquadto
+-70 0 rlineto
+0 -68 rlineto
+31 0 rlineto
+closepath
+} def
+/P$1r {
+0 -120 -35 -175 rquadto
+-35 -54 -120 -54 rquadto
+-84 0 -121 56 rquadto
+-37 54 -37 173 rquadto
+0 114 35 171 rquadto
+37 57 118 57 rquadto
+85 0 123 -54 rquadto
+37 -56 37 -175 rquadto
+} def
+/P$2p {
+0 118 -45 207 rquadto
+-45 89 -131 137 rquadto
+-84 46 -200 46 rquadto
+-115 0 -201 -46 rquadto
+-84 -48 -129 -137 rquadto
+-43 -89 -43 -207 rquadto
+0 -182 100 -284 rquadto
+100 -103 276 -103 rquadto
+115 0 200 46 rquadto
+85 45 129 132 rquadto
+45 87 45 207 rquadto
+closepath
+} def
+/P$10 {
+39 -20 rlineto
+82 -42 148 -42 rquadto
+151 0 151 162 rquadto
+0 350 rlineto
+56 14 rlineto
+0 39 rlineto
+-275 0 rlineto
+0 -39 rlineto
+50 -14 rlineto
+0 -326 rlineto
+0 -50 -21 -76 rquadto
+-20 -28 -57 -28 rquadto
+-45 0 -89 20 rquadto
+0 410 rlineto
+50 14 rlineto
+0 39 rlineto
+-273 0 rlineto
+0 -39 rlineto
+53 -14 rlineto
+0 -445 rlineto
+-53 -14 rlineto
+0 -39 rlineto
+214 0 rlineto
+7 48 rlineto
+} def
+/P$2h {
+0 -154 48 -278 rquadto
+48 -123 150 -232 rquadto
+92 0 rlineto
+-100 110 -146 237 rquadto
+-46 125 -46 275 rquadto
+0 148 45 273 rquadto
+46 125 148 239 rquadto
+-92 0 rlineto
+-101 -109 -150 -232 rquadto
+-48 -125 -48 -279 rquadto
+0 -1 rlineto
+} def
+/P$3 {
+0 -26 rlineto
+104 -12 rlineto
+0 -573 rlineto
+-25 0 rlineto
+-123 0 -168 9 rquadto
+-12 101 rlineto
+-32 0 rlineto
+0 -153 rlineto
+575 0 rlineto
+0 153 rlineto
+-32 0 rlineto
+-12 -101 rlineto
+-15 -3 -65 -6 rquadto
+-48 -3 -106 -3 rquadto
+-25 0 rlineto
+0 573 rlineto
+104 12 rlineto
+0 26 rlineto
+-303 0 rlineto
+} def
+/P$3i {
+101 15 rlineto
+0 28 rlineto
+-309 0 rlineto
+0 -28 rlineto
+101 -15 rlineto
+0 -507 rlineto
+-84 -17 rlineto
+0 -28 rlineto
+190 0 rlineto
+0 553 rlineto
+} def
+/P$t {
+0 -98 54 -153 rquadto
+54 -54 156 -54 rquadto
+110 0 162 81 rquadto
+53 79 53 251 rquadto
+0 165 -67 253 rquadto
+-67 85 -187 85 rquadto
+-79 0 -146 -15 rquadto
+0 -114 rlineto
+32 0 rlineto
+15 70 rlineto
+15 7 42 14 rquadto
+26 4 53 4 rquadto
+78 0 120 -68 rquadto
+42 -68 46 -201 rquadto
+-75 42 -151 42 rquadto
+-85 0 -135 -51 rquadto
+-48 -51 -48 -143 rquadto
+closepath
+} def
+/P$34 {
+96 0 142 40 rquadto
+46 39 46 121 rquadto
+0 403 rlineto
+75 15 rlineto
+0 28 rlineto
+-164 0 rlineto
+-12 -59 rlineto
+-71 71 -184 71 rquadto
+-153 0 -153 -178 rquadto
+0 -59 23 -98 rquadto
+23 -39 73 -59 rquadto
+51 -20 148 -21 rquadto
+89 -3 rlineto
+0 -93 rlineto
+0 -60 -23 -90 rquadto
+-21 -29 -68 -29 rquadto
+-64 0 -115 31 rquadto
+-21 73 rlineto
+-35 0 rlineto
+0 -129 rlineto
+103 -21 181 -21 rquadto
+closepath
+} def
+/P$1g {
+-87 0 -131 -45 rquadto
+-43 -46 -43 -128 rquadto
+0 -90 59 -137 rquadto
+59 -48 190 -53 rquadto
+131 -1 rlineto
+0 -31 rlineto
+0 -71 -31 -101 rquadto
+-29 -31 -93 -31 rquadto
+-64 0 -93 21 rquadto
+-29 21 -35 70 rquadto
+-101 -7 rlineto
+25 -157 234 -157 rquadto
+109 0 164 50 rquadto
+56 50 56 145 rquadto
+0 250 rlineto
+0 43 10 65 rquadto
+10 21 42 21 rquadto
+14 0 32 -4 rquadto
+0 60 rlineto
+-37 7 -75 7 rquadto
+-54 0 -79 -28 rquadto
+-23 -28 -26 -87 rquadto
+-3 0 rlineto
+-37 65 -87 93 rquadto
+-48 28 -118 28 rquadto
+closepath
+} def
+/P$31 {
+0 -350 rlineto
+-409 0 rlineto
+0 350 rlineto
+-101 0 rlineto
+0 -756 rlineto
+101 0 rlineto
+0 320 rlineto
+409 0 rlineto
+0 -320 rlineto
+103 0 rlineto
+0 756 rlineto
+-103 0 rlineto
+} def
+/P$15 {
+0 409 -257 409 rquadto
+-125 0 -189 -104 rquadto
+-62 -104 -62 -304 rquadto
+0 -193 62 -296 rquadto
+64 -104 193 -104 rquadto
+123 0 187 103 rquadto
+65 101 65 298 rquadto
+closepath
+} def
+/P$38 {
+0 10 rlineto
+0 87 18 135 rquadto
+18 48 59 75 rquadto
+40 25 106 25 rquadto
+34 0 81 -4 rquadto
+46 -6 76 -14 rquadto
+0 35 rlineto
+-29 18 -82 34 rquadto
+-51 14 -106 14 rquadto
+-139 0 -203 -75 rquadto
+-64 -75 -64 -240 rquadto
+0 -156 64 -232 rquadto
+65 -76 187 -76 rquadto
+228 0 228 260 rquadto
+0 51 rlineto
+-365 0 rlineto
+closepath
+} def
+/P$z {
+-50 1 rlineto
+-56 3 -78 31 rquadto
+-21 26 -21 87 rquadto
+0 50 17 73 rquadto
+17 23 45 23 rquadto
+40 0 87 -20 rquadto
+0 -196 rlineto
+} def
+/P$1y {
+0 -92 rlineto
+96 0 rlineto
+0 92 rlineto
+-96 0 rlineto
+closepath
+} def
+/P$3r {
+0 314 -278 314 rquadto
+-135 0 -204 -79 rquadto
+-67 -81 -67 -234 rquadto
+0 -151 67 -231 rquadto
+68 -79 209 -79 rquadto
+135 0 204 78 rquadto
+68 78 68 232 rquadto
+closepath
+} def
+/P$22 {
+0 -368 rlineto
+0 -84 -23 -115 rquadto
+-23 -32 -82 -32 rquadto
+-62 0 -98 46 rquadto
+-35 46 -35 132 rquadto
+0 337 rlineto
+-95 0 rlineto
+0 -457 rlineto
+0 -101 -3 -123 rquadto
+90 0 rlineto
+1 3 1 15 rquadto
+0 10 0 26 rquadto
+1 14 3 57 rquadto
+1 0 rlineto
+31 -62 70 -85 rquadto
+40 -25 100 -25 rquadto
+65 0 103 26 rquadto
+39 26 54 84 rquadto
+1 0 rlineto
+29 -59 71 -84 rquadto
+43 -26 103 -26 rquadto
+89 0 128 48 rquadto
+40 46 40 156 rquadto
+0 387 rlineto
+-95 0 rlineto
+0 -368 rlineto
+0 -84 -23 -115 rquadto
+-23 -32 -82 -32 rquadto
+-64 0 -100 46 rquadto
+-34 46 -34 132 rquadto
+0 337 rlineto
+-95 0 rlineto
+} def
+/P$1a {
+-34 0 -51 37 rquadto
+-17 37 -17 134 rquadto
+126 0 rlineto
+0 -78 -4 -109 rquadto
+-4 -32 -18 -46 rquadto
+-12 -15 -34 -15 rquadto
+} def
+/P$3o {
+103 15 rlineto
+0 28 rlineto
+-309 0 rlineto
+0 -28 rlineto
+101 -15 rlineto
+0 -814 rlineto
+-101 -15 rlineto
+0 -28 rlineto
+206 0 rlineto
+0 857 rlineto
+} def
+/P$1s {
+-46 14 -96 14 rquadto
+-115 0 -115 -132 rquadto
+0 -387 rlineto
+-67 0 rlineto
+0 -70 rlineto
+70 0 rlineto
+28 -129 rlineto
+65 0 rlineto
+0 129 rlineto
+106 0 rlineto
+0 70 rlineto
+-106 0 rlineto
+0 367 rlineto
+0 42 12 59 rquadto
+14 15 48 15 rquadto
+18 0 54 -6 rquadto
+0 70 rlineto
+} def
+/P$1p {
+-125 0 -195 81 rquadto
+-70 81 -70 221 rquadto
+0 139 73 223 rquadto
+73 84 196 84 rquadto
+159 0 239 -157 rquadto
+84 42 rlineto
+-46 98 -132 150 rquadto
+-84 50 -195 50 rquadto
+-114 0 -198 -46 rquadto
+-82 -48 -126 -135 rquadto
+-43 -89 -43 -209 rquadto
+0 -181 96 -284 rquadto
+98 -103 271 -103 rquadto
+120 0 201 48 rquadto
+81 46 118 139 rquadto
+-96 32 rlineto
+-26 -65 -85 -100 rquadto
+-57 -35 -137 -35 rquadto
+} def
+/P$30 {
+0 -121 -32 -173 rquadto
+-32 -53 -104 -53 rquadto
+-56 0 -89 25 rquadto
+-32 23 -50 75 rquadto
+-17 51 -17 132 rquadto
+0 115 35 170 rquadto
+37 53 120 53 rquadto
+71 0 104 -53 rquadto
+32 -53 32 -176 rquadto
+} def
+/P$6 {
+0 9 rlineto
+0 67 14 104 rquadto
+15 37 46 57 rquadto
+31 18 81 18 rquadto
+26 0 62 -4 rquadto
+35 -4 59 -9 rquadto
+0 26 rlineto
+-23 15 -64 26 rquadto
+-39 10 -81 10 rquadto
+-107 0 -157 -57 rquadto
+-48 -57 -48 -184 rquadto
+0 -120 50 -179 rquadto
+50 -59 143 -59 rquadto
+176 0 176 201 rquadto
+0 39 rlineto
+-282 0 rlineto
+closepath
+} def
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+3720 2533 moveto
+P$0
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+4662 2302 moveto
+P$1
+4573 2302 moveto
+P$2
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+11603 2533 moveto
+P$3
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+12203 2402 moveto
+P$4
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+20020 2549 moveto
+P$5
+20376 2302 moveto
+P$6
+20482 2100 moveto
+P$7
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+27603 2533 moveto
+P$3
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+28209 2038 moveto
+P$8
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+35757 2239 moveto
+P$9
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+36475 2061 moveto
+P$a
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+43567 2357 moveto
+P$b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+44326 2064 moveto
+P$c
+44392 2299 moveto
+P$d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+51517 2357 moveto
+P$b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+52203 2402 moveto
+P$4
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+59720 2533 moveto
+P$0
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+60662 2302 moveto
+P$1
+60573 2302 moveto
+P$2
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+67603 2533 moveto
+P$3
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+68203 2402 moveto
+P$4
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+76020 2549 moveto
+P$5
+76376 2302 moveto
+P$6
+76482 2100 moveto
+P$7
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+83603 2533 moveto
+P$3
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+84209 2038 moveto
+P$8
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+91757 2239 moveto
+P$9
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+92475 2061 moveto
+P$a
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+99567 2357 moveto
+P$b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+100326 2064 moveto
+P$c
+100392 2299 moveto
+P$d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+107517 2357 moveto
+P$b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+108203 2402 moveto
+P$4
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+115720 2533 moveto
+P$0
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+116662 2302 moveto
+P$1
+116573 2302 moveto
+P$2
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+123603 2533 moveto
+P$3
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+124203 2402 moveto
+P$4
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+132020 2549 moveto
+P$5
+132376 2302 moveto
+P$6
+132482 2100 moveto
+P$7
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+139603 2533 moveto
+P$3
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+140209 2038 moveto
+P$8
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+147757 2239 moveto
+P$9
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+148475 2061 moveto
+P$a
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+155567 2357 moveto
+P$b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+156326 2064 moveto
+P$c
+156392 2299 moveto
+P$d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+163517 2357 moveto
+P$b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+164203 2402 moveto
+P$4
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+171720 2533 moveto
+P$0
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+172662 2302 moveto
+P$1
+172573 2302 moveto
+P$2
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+179603 2533 moveto
+P$3
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+180203 2402 moveto
+P$4
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+188020 2549 moveto
+P$5
+188376 2302 moveto
+P$6
+188482 2100 moveto
+P$7
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+195603 2533 moveto
+P$3
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+196209 2038 moveto
+P$8
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+203757 2239 moveto
+P$9
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+204475 2061 moveto
+P$a
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+3960 3555 moveto
+P$e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+4462 3403 moveto
+P$f
+4371 3403 moveto
+P$g
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+11960 3555 moveto
+P$e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+12306 3694 moveto
+P$h
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+20056 3694 moveto
+P$h
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+28195 3733 moveto
+P$i
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+36210 3555 moveto
+P$j
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+44145 3589 moveto
+P$k
+44060 3189 moveto
+P$l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+51987 3350 moveto
+P$m
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+60220 3530 moveto
+P$n
+60018 3705 moveto
+P$o
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+67848 3233 moveto
+P$p
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+76192 3238 moveto
+P$q
+76123 3557 moveto
+P$r
+76104 3238 moveto
+P$s
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+83782 3278 moveto
+P$t
+83993 3110 moveto
+P$u
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+91806 3694 moveto
+P$v
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+92462 3403 moveto
+P$f
+92371 3403 moveto
+P$g
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+99806 3694 moveto
+P$v
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+100306 3694 moveto
+P$h
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+107806 3694 moveto
+P$v
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+108445 3733 moveto
+P$i
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+115806 3694 moveto
+P$v
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+116460 3555 moveto
+P$j
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+123806 3694 moveto
+P$v
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+124395 3589 moveto
+P$k
+124310 3189 moveto
+P$l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+131806 3694 moveto
+P$v
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+132237 3350 moveto
+P$m
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+139806 3694 moveto
+P$v
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+140470 3530 moveto
+P$n
+140268 3705 moveto
+P$o
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+147806 3694 moveto
+P$v
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+148098 3233 moveto
+P$p
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+155806 3694 moveto
+P$v
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+156442 3238 moveto
+P$q
+156373 3557 moveto
+P$r
+156354 3238 moveto
+P$s
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+163806 3694 moveto
+P$v
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+164032 3278 moveto
+P$t
+164243 3110 moveto
+P$u
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+171945 3733 moveto
+P$w
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+172462 3403 moveto
+P$f
+172371 3403 moveto
+P$g
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+179945 3733 moveto
+P$w
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+180306 3694 moveto
+P$h
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+187945 3733 moveto
+P$w
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+188445 3733 moveto
+P$i
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+195945 3733 moveto
+P$w
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+196460 3555 moveto
+P$j
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+203945 3733 moveto
+P$w
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+204395 3589 moveto
+P$k
+204310 3189 moveto
+P$l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+4793 392 moveto
+P$x
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+5420 557 moveto
+P$y
+5457 843 moveto
+P$z
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+5954 617 moveto
+P$10
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+6812 1071 moveto
+P$11
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+7420 557 moveto
+P$y
+7457 843 moveto
+P$z
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+7970 684 moveto
+P$12
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+8470 1137 moveto
+P$13
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+9648 1120 moveto
+P$14
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+10254 723 moveto
+P$15
+10082 723 moveto
+P$16
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+10848 1120 moveto
+P$14
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+11459 906 moveto
+P$17
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+108556 784 moveto
+P$18
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+109239 556 moveto
+P$19
+109232 615 moveto
+P$1a
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+109896 829 moveto
+P$1b
+109521 339 moveto
+P$1c
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+110420 684 moveto
+P$12
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+111062 1071 moveto
+P$11
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+111670 557 moveto
+P$y
+111707 843 moveto
+P$z
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+112220 684 moveto
+P$12
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+112720 1137 moveto
+P$13
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+113898 1120 moveto
+P$14
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+114504 723 moveto
+P$15
+114332 723 moveto
+P$16
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+115098 1120 moveto
+P$14
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+115709 906 moveto
+P$17
+fill
+100 setlinewidth
+0.75 0.75 0.75 setrgbcolor
+newpath
+0 4100 moveto
+0 47503 rlineto
+stroke
+100 setlinewidth
+0.75 0.75 0.75 setrgbcolor
+newpath
+8000 4100 moveto
+0 47503 rlineto
+stroke
+100 setlinewidth
+0.75 0.75 0.75 setrgbcolor
+newpath
+16000 4100 moveto
+0 47503 rlineto
+stroke
+100 setlinewidth
+0.75 0.75 0.75 setrgbcolor
+newpath
+24000 4100 moveto
+0 47503 rlineto
+stroke
+100 setlinewidth
+0.75 0.75 0.75 setrgbcolor
+newpath
+32000 4100 moveto
+0 47503 rlineto
+stroke
+100 setlinewidth
+0.75 0.75 0.75 setrgbcolor
+newpath
+40000 4100 moveto
+0 47503 rlineto
+stroke
+100 setlinewidth
+0.75 0.75 0.75 setrgbcolor
+newpath
+48000 4100 moveto
+0 47503 rlineto
+stroke
+100 setlinewidth
+0.75 0.75 0.75 setrgbcolor
+newpath
+56000 4100 moveto
+0 47503 rlineto
+stroke
+100 setlinewidth
+0.75 0.75 0.75 setrgbcolor
+newpath
+64000 4100 moveto
+0 47503 rlineto
+stroke
+100 setlinewidth
+0.75 0.75 0.75 setrgbcolor
+newpath
+72000 4100 moveto
+0 47503 rlineto
+stroke
+100 setlinewidth
+0.75 0.75 0.75 setrgbcolor
+newpath
+80000 4100 moveto
+0 47503 rlineto
+stroke
+100 setlinewidth
+0.75 0.75 0.75 setrgbcolor
+newpath
+88000 4100 moveto
+0 47503 rlineto
+stroke
+100 setlinewidth
+0.75 0.75 0.75 setrgbcolor
+newpath
+96000 4100 moveto
+0 47503 rlineto
+stroke
+100 setlinewidth
+0.75 0.75 0.75 setrgbcolor
+newpath
+104000 4100 moveto
+0 47503 rlineto
+stroke
+100 setlinewidth
+0.75 0.75 0.75 setrgbcolor
+newpath
+112000 4100 moveto
+0 47503 rlineto
+stroke
+100 setlinewidth
+0.75 0.75 0.75 setrgbcolor
+newpath
+120000 4100 moveto
+0 47503 rlineto
+stroke
+100 setlinewidth
+0.75 0.75 0.75 setrgbcolor
+newpath
+128000 4100 moveto
+0 47503 rlineto
+stroke
+100 setlinewidth
+0.75 0.75 0.75 setrgbcolor
+newpath
+136000 4100 moveto
+0 47503 rlineto
+stroke
+100 setlinewidth
+0.75 0.75 0.75 setrgbcolor
+newpath
+144000 4100 moveto
+0 47503 rlineto
+stroke
+100 setlinewidth
+0.75 0.75 0.75 setrgbcolor
+newpath
+152000 4100 moveto
+0 47503 rlineto
+stroke
+100 setlinewidth
+0.75 0.75 0.75 setrgbcolor
+newpath
+160000 4100 moveto
+0 47503 rlineto
+stroke
+100 setlinewidth
+0.75 0.75 0.75 setrgbcolor
+newpath
+168000 4100 moveto
+0 47503 rlineto
+stroke
+100 setlinewidth
+0.75 0.75 0.75 setrgbcolor
+newpath
+176000 4100 moveto
+0 47503 rlineto
+stroke
+100 setlinewidth
+0.75 0.75 0.75 setrgbcolor
+newpath
+184000 4100 moveto
+0 47503 rlineto
+stroke
+100 setlinewidth
+0.75 0.75 0.75 setrgbcolor
+newpath
+192000 4100 moveto
+0 47503 rlineto
+stroke
+100 setlinewidth
+0.75 0.75 0.75 setrgbcolor
+newpath
+200000 4100 moveto
+0 47503 rlineto
+stroke
+100 setlinewidth
+0.75 0.75 0.75 setrgbcolor
+newpath
+208000 4100 moveto
+0 47503 rlineto
+stroke
+100 setlinewidth
+0.75 0.75 0.75 setrgbcolor
+newpath
+0 4100 moveto
+208000 0 rlineto
+stroke
+100 setlinewidth
+0.75 0.75 0.75 setrgbcolor
+newpath
+0 51603 moveto
+208000 0 rlineto
+stroke
+150 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+20000 10494 moveto
+0 1032 rlineto
+stroke
+150 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+20000 11527 moveto
+3900 0 rlineto
+stroke
+0.09 0.09 0.09 setrgbcolor
+newpath
+23500 11127 moveto
+0 400 rlineto
+0 400 rlineto
+400 -400 rlineto
+23500 11127 lineto
+closepath eofill
+150 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+23500 11127 moveto
+0 400 rlineto
+0 400 rlineto
+400 -400 rlineto
+23500 11127 lineto
+closepath stroke
+150 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+68000 12159 moveto
+0 1032 rlineto
+stroke
+150 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+68000 13192 moveto
+3900 0 rlineto
+stroke
+0.09 0.09 0.09 setrgbcolor
+newpath
+71500 12792 moveto
+0 400 rlineto
+0 400 rlineto
+400 -400 rlineto
+71500 12792 lineto
+closepath eofill
+150 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+71500 12792 moveto
+0 400 rlineto
+0 400 rlineto
+400 -400 rlineto
+71500 12792 lineto
+closepath stroke
+150 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+68000 12159 moveto
+0 2697 rlineto
+stroke
+150 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+68000 14856 moveto
+3900 0 rlineto
+stroke
+0.09 0.09 0.09 setrgbcolor
+newpath
+71500 14456 moveto
+0 400 rlineto
+0 400 rlineto
+400 -400 rlineto
+71500 14456 lineto
+closepath eofill
+150 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+71500 14456 moveto
+0 400 rlineto
+0 400 rlineto
+400 -400 rlineto
+71500 14456 lineto
+closepath stroke
+150 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+92000 15489 moveto
+0 1032 rlineto
+stroke
+150 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+92000 16521 moveto
+3900 0 rlineto
+stroke
+0.09 0.09 0.09 setrgbcolor
+newpath
+95500 16121 moveto
+0 400 rlineto
+0 400 rlineto
+400 -400 rlineto
+95500 16121 lineto
+closepath eofill
+150 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+95500 16121 moveto
+0 400 rlineto
+0 400 rlineto
+400 -400 rlineto
+95500 16121 lineto
+closepath stroke
+150 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+92000 15489 moveto
+0 2697 rlineto
+stroke
+150 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+92000 18186 moveto
+3900 0 rlineto
+stroke
+0.09 0.09 0.09 setrgbcolor
+newpath
+95500 17786 moveto
+0 400 rlineto
+0 400 rlineto
+400 -400 rlineto
+95500 17786 lineto
+closepath eofill
+150 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+95500 17786 moveto
+0 400 rlineto
+0 400 rlineto
+400 -400 rlineto
+95500 17786 lineto
+closepath stroke
+150 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+92000 15489 moveto
+0 4362 rlineto
+stroke
+150 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+92000 19851 moveto
+3900 0 rlineto
+stroke
+0.09 0.09 0.09 setrgbcolor
+newpath
+95500 19451 moveto
+0 400 rlineto
+0 400 rlineto
+400 -400 rlineto
+95500 19451 lineto
+closepath eofill
+150 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+95500 19451 moveto
+0 400 rlineto
+0 400 rlineto
+400 -400 rlineto
+95500 19451 lineto
+closepath stroke
+150 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+108000 20484 moveto
+0 1032 rlineto
+stroke
+150 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+108000 21516 moveto
+3900 0 rlineto
+stroke
+0.09 0.09 0.09 setrgbcolor
+newpath
+111500 21116 moveto
+0 400 rlineto
+0 400 rlineto
+400 -400 rlineto
+111500 21116 lineto
+closepath eofill
+150 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+111500 21116 moveto
+0 400 rlineto
+0 400 rlineto
+400 -400 rlineto
+111500 21116 lineto
+closepath stroke
+150 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+52000 30408 moveto
+0 1032 rlineto
+stroke
+150 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+52000 31440 moveto
+3900 0 rlineto
+stroke
+0.09 0.09 0.09 setrgbcolor
+newpath
+55500 31040 moveto
+0 400 rlineto
+0 400 rlineto
+400 -400 rlineto
+55500 31040 lineto
+closepath eofill
+150 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+55500 31040 moveto
+0 400 rlineto
+0 400 rlineto
+400 -400 rlineto
+55500 31040 lineto
+closepath stroke
+150 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+60000 32073 moveto
+0 1032 rlineto
+stroke
+150 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+60000 33105 moveto
+3900 0 rlineto
+stroke
+0.09 0.09 0.09 setrgbcolor
+newpath
+63500 32705 moveto
+0 400 rlineto
+0 400 rlineto
+400 -400 rlineto
+63500 32705 lineto
+closepath eofill
+150 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+63500 32705 moveto
+0 400 rlineto
+0 400 rlineto
+400 -400 rlineto
+63500 32705 lineto
+closepath stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+0 5732 moveto
+500 0 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+5800 5732 moveto
+202100 0 rlineto
+stroke
+0.89 0.89 0.94 setrgbcolor
+23600 1264 200 7564 simplerect
+closepath eofill
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+200 7564 moveto
+23600 0 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+200 8829 moveto
+23600 0 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+200 7564 moveto
+0 1264 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+23800 7564 moveto
+0 1264 rlineto
+stroke
+0.89 0.89 0.94 setrgbcolor
+23600 1264 200 9229 simplerect
+closepath eofill
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+200 9229 moveto
+23600 0 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+200 10494 moveto
+23600 0 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+200 9229 moveto
+0 1264 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+23800 9229 moveto
+0 1264 rlineto
+stroke
+0.89 0.89 0.94 setrgbcolor
+47600 1264 24200 10894 simplerect
+closepath eofill
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+24200 10894 moveto
+47600 0 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+24200 12159 moveto
+47600 0 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+24200 10894 moveto
+0 1264 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+71800 10894 moveto
+0 1264 rlineto
+stroke
+0.89 0.89 0.94 setrgbcolor
+127600 1264 72200 12559 simplerect
+closepath eofill
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+72200 12559 moveto
+127600 0 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+72200 13824 moveto
+127600 0 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+72200 12559 moveto
+0 1264 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+199800 12559 moveto
+0 1264 rlineto
+stroke
+0.89 0.89 0.94 setrgbcolor
+23600 1264 72200 14224 simplerect
+closepath eofill
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+72200 14224 moveto
+23600 0 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+72200 15489 moveto
+23600 0 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+72200 14224 moveto
+0 1264 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+95800 14224 moveto
+0 1264 rlineto
+stroke
+0.89 0.89 0.94 setrgbcolor
+103600 1264 96200 15889 simplerect
+closepath eofill
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+96200 15889 moveto
+103600 0 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+96200 17154 moveto
+103600 0 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+96200 15889 moveto
+0 1264 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+199800 15889 moveto
+0 1264 rlineto
+stroke
+0.89 0.89 0.94 setrgbcolor
+111600 1264 96200 17554 simplerect
+closepath eofill
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+96200 17554 moveto
+111600 0 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+96200 18819 moveto
+111600 0 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+96200 17554 moveto
+0 1264 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+207800 17554 moveto
+0 1264 rlineto
+stroke
+0.89 0.89 0.94 setrgbcolor
+15600 1264 96200 19219 simplerect
+closepath eofill
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+96200 19219 moveto
+15600 0 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+96200 20484 moveto
+15600 0 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+96200 19219 moveto
+0 1264 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+111800 19219 moveto
+0 1264 rlineto
+stroke
+0.89 0.89 0.94 setrgbcolor
+95600 1264 112200 20884 simplerect
+closepath eofill
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+112200 20884 moveto
+95600 0 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+112200 22148 moveto
+95600 0 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+112200 20884 moveto
+0 1264 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+207800 20884 moveto
+0 1264 rlineto
+stroke
+0.89 0.89 0.94 setrgbcolor
+7600 1264 120200 22548 simplerect
+closepath eofill
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+120200 22548 moveto
+7600 0 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+120200 23813 moveto
+7600 0 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+120200 22548 moveto
+0 1264 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+127800 22548 moveto
+0 1264 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+0 25646 moveto
+500 0 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+5900 25646 moveto
+202000 0 rlineto
+stroke
+0.89 0.89 0.94 setrgbcolor
+63600 1264 200 27478 simplerect
+closepath eofill
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+200 27478 moveto
+63600 0 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+200 28743 moveto
+63600 0 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+200 27478 moveto
+0 1264 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+63800 27478 moveto
+0 1264 rlineto
+stroke
+0.89 0.89 0.94 setrgbcolor
+39600 1264 16200 29143 simplerect
+closepath eofill
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+16200 29143 moveto
+39600 0 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+16200 30408 moveto
+39600 0 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+16200 29143 moveto
+0 1264 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+55800 29143 moveto
+0 1264 rlineto
+stroke
+0.89 0.89 0.94 setrgbcolor
+7600 1264 56200 30808 simplerect
+closepath eofill
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+56200 30808 moveto
+7600 0 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+56200 32073 moveto
+7600 0 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+56200 30808 moveto
+0 1264 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+63800 30808 moveto
+0 1264 rlineto
+stroke
+0.89 0.89 0.94 setrgbcolor
+111600 1264 64200 32473 simplerect
+closepath eofill
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+64200 32473 moveto
+111600 0 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+64200 33738 moveto
+111600 0 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+64200 32473 moveto
+0 1264 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+175800 32473 moveto
+0 1264 rlineto
+stroke
+0.89 0.89 0.94 setrgbcolor
+39600 1264 48200 34138 simplerect
+closepath eofill
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+48200 34138 moveto
+39600 0 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+48200 35403 moveto
+39600 0 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+48200 34138 moveto
+0 1264 rlineto
+stroke
+100 setlinewidth
+0.09 0.09 0.09 setrgbcolor
+newpath
+87800 34138 moveto
+0 1264 rlineto
+stroke
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+1675 5919 moveto
+P$1d
+1528 5570 moveto
+P$1e
+1571 5909 moveto
+P$1f
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+1921 6142 moveto
+P$1g
+1943 6069 moveto
+P$1h
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+2448 5838 moveto
+P$1i
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+3339 6131 moveto
+P$1j
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+3648 5861 moveto
+P$1k
+3962 5788 moveto
+P$1l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+4543 6131 moveto
+P$1m
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+5140 6038 moveto
+P$1n
+4848 5841 moveto
+P$1o
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+1025 7912 moveto
+P$1p
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+1965 8306 moveto
+P$1q
+1864 8306 moveto
+P$1r
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+2443 8596 moveto
+P$1m
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+2896 8591 moveto
+P$1s
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+2976 8596 moveto
+P$1t
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+3865 8306 moveto
+P$1q
+3764 8306 moveto
+P$1r
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+3973 8596 moveto
+P$1u
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+4173 8596 moveto
+P$1u
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+4448 8326 moveto
+P$1k
+4762 8252 moveto
+P$1l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+4976 8596 moveto
+P$1t
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+5348 8346 moveto
+P$1v
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+6382 8387 moveto
+P$1w
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+6548 8302 moveto
+P$1i
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+7170 8115 moveto
+P$1x
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+7673 7891 moveto
+P$1y
+7673 8596 moveto
+P$1z
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+7948 8302 moveto
+P$1i
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+8570 8115 moveto
+P$1x
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+9296 8591 moveto
+P$1s
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+9875 8824 moveto
+P$20
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+10101 8596 moveto
+P$21
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+10712 8596 moveto
+P$22
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+11612 8596 moveto
+P$22
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+12321 8607 moveto
+P$1g
+12343 8534 moveto
+P$1h
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+13143 8596 moveto
+P$1m
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+13468 8015 moveto
+P$23
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+14048 8326 moveto
+P$1k
+14362 8252 moveto
+P$1l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+14573 8596 moveto
+P$1u
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+14750 8756 moveto
+P$24
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+1334 10261 moveto
+P$25
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+2065 9970 moveto
+P$1q
+1964 9970 moveto
+P$1r
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+2540 10167 moveto
+P$1n
+2248 9970 moveto
+P$26
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+2848 9991 moveto
+P$1k
+3162 9917 moveto
+P$1l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+3373 10261 moveto
+P$1u
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+3548 10011 moveto
+P$1v
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+4575 9731 moveto
+P$27
+4471 9733 moveto
+P$28
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+4821 10272 moveto
+P$1g
+4843 10199 moveto
+P$1h
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+5639 10261 moveto
+P$1j
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+5948 9991 moveto
+P$1k
+6262 9917 moveto
+P$1l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+6696 10256 moveto
+P$1s
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+7275 10489 moveto
+P$20
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+8142 9875 moveto
+P$29
+8039 9875 moveto
+P$2a
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+8421 10272 moveto
+P$1g
+8443 10199 moveto
+P$1h
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+9243 10261 moveto
+P$1m
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+9473 9556 moveto
+P$1y
+9473 10261 moveto
+P$1z
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+9748 9991 moveto
+P$1k
+10062 9917 moveto
+P$1l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+10273 10261 moveto
+P$1u
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+10450 10420 moveto
+P$24
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+25342 11540 moveto
+P$29
+25239 11540 moveto
+P$2a
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+25621 11937 moveto
+P$1g
+25643 11863 moveto
+P$1h
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+26296 11921 moveto
+P$1s
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+26448 11656 moveto
+P$1k
+26762 11582 moveto
+P$1l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+27343 11926 moveto
+P$1m
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+28065 11632 moveto
+P$2b
+27964 11635 moveto
+P$2c
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+28321 11937 moveto
+P$1g
+28343 11863 moveto
+P$1h
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+29143 11926 moveto
+P$1m
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+29739 11926 moveto
+P$1j
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+30421 11937 moveto
+P$1g
+30443 11863 moveto
+P$1h
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+30968 11345 moveto
+P$23
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+31593 11415 moveto
+P$2d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+32210 11765 moveto
+P$2e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+32448 11656 moveto
+P$1k
+32762 11582 moveto
+P$1l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+33196 11921 moveto
+P$1s
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+33245 11926 moveto
+P$2f
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+33948 11656 moveto
+P$1k
+34262 11582 moveto
+P$1l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+34843 11926 moveto
+P$1m
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+35575 12154 moveto
+P$20
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+35801 11926 moveto
+P$21
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+36412 11926 moveto
+P$22
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+37312 11926 moveto
+P$22
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+38021 11937 moveto
+P$1g
+38043 11863 moveto
+P$1h
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+38843 11926 moveto
+P$1m
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+39168 11345 moveto
+P$23
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+39748 11656 moveto
+P$1k
+40062 11582 moveto
+P$1l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+40273 11926 moveto
+P$1u
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+40450 12085 moveto
+P$24
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+72992 13602 moveto
+P$2g
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+73696 13586 moveto
+P$1s
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+73773 12886 moveto
+P$1y
+73773 13591 moveto
+P$1z
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+73973 13591 moveto
+P$1u
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+74148 13341 moveto
+P$1v
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+75175 13061 moveto
+P$27
+75071 13063 moveto
+P$28
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+75421 13602 moveto
+P$1g
+75443 13528 moveto
+P$1h
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+76239 13591 moveto
+P$1j
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+76548 13321 moveto
+P$1k
+76862 13247 moveto
+P$1l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+77296 13586 moveto
+P$1s
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+77668 13305 moveto
+P$2h
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+78625 13591 moveto
+P$2i
+78610 13052 moveto
+P$2j
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+79482 13381 moveto
+P$1w
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+80182 13381 moveto
+P$1w
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+80875 13061 moveto
+P$27
+80771 13063 moveto
+P$28
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+81121 13602 moveto
+P$1g
+81143 13528 moveto
+P$1h
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+81576 13591 moveto
+P$1t
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+82410 13430 moveto
+P$2e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+82648 13321 moveto
+P$1k
+82962 13247 moveto
+P$1l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+83176 13591 moveto
+P$1t
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+83798 13306 moveto
+P$2k
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+84475 13819 moveto
+P$20
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+85342 13205 moveto
+P$29
+85239 13205 moveto
+P$2a
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+85621 13602 moveto
+P$1g
+85643 13528 moveto
+P$1h
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+86443 13591 moveto
+P$1m
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+86673 12886 moveto
+P$1y
+86673 13591 moveto
+P$1z
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+86948 13321 moveto
+P$1k
+87262 13247 moveto
+P$1l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+87473 13591 moveto
+P$1u
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+87650 13750 moveto
+P$2l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+88575 13819 moveto
+P$20
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+88790 13591 moveto
+P$2m
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+89468 13010 moveto
+P$23
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+90339 13591 moveto
+P$1j
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+90721 13602 moveto
+P$1g
+90743 13528 moveto
+P$1h
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+91610 13430 moveto
+P$2e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+91750 13750 moveto
+P$24
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+73342 14870 moveto
+P$29
+73239 14870 moveto
+P$2a
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+74026 15256 moveto
+P$2n
+73767 14576 moveto
+P$2o
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+74903 14875 moveto
+P$2p
+74798 14875 moveto
+P$2q
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+75048 15006 moveto
+P$1v
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+75501 15256 moveto
+P$21
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+76143 15256 moveto
+P$1m
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+76596 15251 moveto
+P$1s
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+76748 14985 moveto
+P$1k
+77062 14912 moveto
+P$1l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+77276 15256 moveto
+P$1t
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+77793 14745 moveto
+P$2d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+78121 15267 moveto
+P$1g
+78143 15193 moveto
+P$1h
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+78648 14962 moveto
+P$1i
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+79248 14985 moveto
+P$1k
+79562 14912 moveto
+P$1l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+80210 15095 moveto
+P$2e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+80875 15484 moveto
+P$20
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+81245 15267 moveto
+P$2r
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+81768 14675 moveto
+P$23
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+82273 15256 moveto
+P$1u
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+82473 14551 moveto
+P$1y
+82473 15256 moveto
+P$1z
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+82768 14675 moveto
+P$23
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+83710 15095 moveto
+P$2e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+83850 15415 moveto
+P$2l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+84775 15484 moveto
+P$20
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+85001 15256 moveto
+P$21
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+85612 15256 moveto
+P$22
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+86512 15256 moveto
+P$22
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+87221 15267 moveto
+P$1g
+87243 15193 moveto
+P$1h
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+88043 15256 moveto
+P$1m
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+88368 14675 moveto
+P$23
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+88948 14985 moveto
+P$1k
+89262 14912 moveto
+P$1l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+89473 15256 moveto
+P$1u
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+89650 15415 moveto
+P$24
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+97226 16921 moveto
+P$2n
+96967 16241 moveto
+P$2o
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+97468 16339 moveto
+P$23
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+98196 16916 moveto
+P$1s
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+98370 16439 moveto
+P$1x
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+98948 16650 moveto
+P$1k
+99262 16577 moveto
+P$1l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+99843 16921 moveto
+P$1m
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+100296 16916 moveto
+P$1s
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+100373 16216 moveto
+P$1y
+100373 16921 moveto
+P$1z
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+100693 16410 moveto
+P$2d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+100873 16216 moveto
+P$1y
+100873 16921 moveto
+P$1z
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+101045 16921 moveto
+P$2f
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+101673 16216 moveto
+P$1y
+101673 16921 moveto
+P$1z
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+101948 16650 moveto
+P$1k
+102262 16577 moveto
+P$1l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+102476 16921 moveto
+P$1t
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+102968 16339 moveto
+P$23
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+103843 16921 moveto
+P$1m
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+104293 17149 moveto
+P$2s
+104442 16630 moveto
+P$2t
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+105175 17149 moveto
+P$20
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+105401 16921 moveto
+P$21
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+106012 16921 moveto
+P$22
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+106912 16921 moveto
+P$22
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+107621 16932 moveto
+P$1g
+107643 16858 moveto
+P$1h
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+108443 16921 moveto
+P$1m
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+108768 16339 moveto
+P$23
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+109348 16650 moveto
+P$1k
+109662 16577 moveto
+P$1l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+109873 16921 moveto
+P$1u
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+110050 17080 moveto
+P$24
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+97282 18376 moveto
+P$1w
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+97448 18315 moveto
+P$1k
+97762 18242 moveto
+P$1l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+97976 18586 moveto
+P$1t
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+98629 18586 moveto
+P$2u
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+98973 17881 moveto
+P$1y
+98973 18586 moveto
+P$1z
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+99248 18292 moveto
+P$1i
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+99848 18315 moveto
+P$1k
+100162 18242 moveto
+P$1l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+100348 18336 moveto
+P$1v
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+101382 18376 moveto
+P$1w
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+101548 18292 moveto
+P$1i
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+102170 18104 moveto
+P$1x
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+102673 17881 moveto
+P$1y
+102673 18586 moveto
+P$1z
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+102948 18292 moveto
+P$1i
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+103570 18104 moveto
+P$1x
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+104296 18581 moveto
+P$1s
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+105012 18586 moveto
+P$22
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+105573 17881 moveto
+P$1y
+105573 18586 moveto
+P$1z
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+105996 18581 moveto
+P$1s
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+107042 18200 moveto
+P$29
+106939 18200 moveto
+P$2a
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+107321 18596 moveto
+P$1g
+107343 18523 moveto
+P$1h
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+107996 18581 moveto
+P$1s
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+108148 18315 moveto
+P$1k
+108462 18242 moveto
+P$1l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+109043 18586 moveto
+P$1m
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+109245 18586 moveto
+P$2f
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+109968 18004 moveto
+P$23
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+110693 18814 moveto
+P$2s
+110842 18295 moveto
+P$2t
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+111076 18586 moveto
+P$1t
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+111473 17881 moveto
+P$1y
+111473 18586 moveto
+P$1z
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+111793 18075 moveto
+P$2d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+112093 18075 moveto
+P$2d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+112775 18814 moveto
+P$20
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+113145 18596 moveto
+P$2r
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+113668 18004 moveto
+P$23
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+114173 18586 moveto
+P$1u
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+114373 17881 moveto
+P$1y
+114373 18586 moveto
+P$1z
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+114668 18004 moveto
+P$23
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+115610 18425 moveto
+P$2e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+115750 18745 moveto
+P$24
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+112592 20261 moveto
+P$2g
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+113296 20246 moveto
+P$1s
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+113373 19546 moveto
+P$1y
+113373 20250 moveto
+P$1z
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+113573 20250 moveto
+P$1u
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+113748 20000 moveto
+P$1v
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+114775 19721 moveto
+P$27
+114671 19722 moveto
+P$28
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+115021 20261 moveto
+P$1g
+115043 20188 moveto
+P$1h
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+115839 20250 moveto
+P$1j
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+116148 19980 moveto
+P$1k
+116462 19907 moveto
+P$1l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+116896 20246 moveto
+P$1s
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+117268 19964 moveto
+P$2h
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+118025 19566 moveto
+P$1p
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+118473 20250 moveto
+P$1u
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+118748 19980 moveto
+P$1k
+119062 19907 moveto
+P$1l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+119421 20261 moveto
+P$1g
+119443 20188 moveto
+P$1h
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+120243 20250 moveto
+P$1m
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+120825 19566 moveto
+P$1p
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+121276 20250 moveto
+P$1t
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+122165 19960 moveto
+P$1q
+122064 19960 moveto
+P$1r
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+122643 20250 moveto
+P$1m
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+123045 20261 moveto
+P$2r
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+123965 19960 moveto
+P$1q
+123864 19960 moveto
+P$1r
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+124565 19957 moveto
+P$2b
+124464 19960 moveto
+P$2c
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+124898 19966 moveto
+P$2k
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+125575 20479 moveto
+P$20
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+126442 19864 moveto
+P$29
+126339 19864 moveto
+P$2a
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+126721 20261 moveto
+P$1g
+126743 20188 moveto
+P$1h
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+127543 20250 moveto
+P$1m
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+127773 19546 moveto
+P$1y
+127773 20250 moveto
+P$1z
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+128048 19980 moveto
+P$1k
+128362 19907 moveto
+P$1l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+128573 20250 moveto
+P$1u
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+128750 20410 moveto
+P$24
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+113342 21529 moveto
+P$29
+113239 21529 moveto
+P$2a
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+113965 21625 moveto
+P$1q
+113864 21625 moveto
+P$1r
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+114148 21622 moveto
+P$1i
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+115039 21915 moveto
+P$1j
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+115348 21645 moveto
+P$1k
+115662 21572 moveto
+P$1l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+115876 21915 moveto
+P$1t
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+116775 22143 moveto
+P$20
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+117642 21529 moveto
+P$29
+117539 21529 moveto
+P$2a
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+117921 21926 moveto
+P$1g
+117943 21853 moveto
+P$1h
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+118743 21915 moveto
+P$1m
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+118973 21211 moveto
+P$1y
+118973 21915 moveto
+P$1z
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+119248 21645 moveto
+P$1k
+119562 21572 moveto
+P$1l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+119773 21915 moveto
+P$1u
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+119950 22075 moveto
+P$24
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+128290 23580 moveto
+P$2v
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+129634 23580 moveto
+P$25
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+130021 23591 moveto
+P$1g
+130043 23518 moveto
+P$1h
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+130473 22876 moveto
+P$1y
+130473 23580 moveto
+P$1z
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+130673 23580 moveto
+P$1u
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+131482 23371 moveto
+P$1w
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+131648 23310 moveto
+P$1k
+131962 23236 moveto
+P$1l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+132176 23580 moveto
+P$1t
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+132829 23580 moveto
+P$2u
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+133173 22876 moveto
+P$1y
+133173 23580 moveto
+P$1z
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+133448 23286 moveto
+P$1i
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+134048 23310 moveto
+P$1k
+134362 23236 moveto
+P$1l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+135075 23808 moveto
+P$20
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+135254 23199 moveto
+P$2w
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+136248 23310 moveto
+P$1k
+136562 23236 moveto
+P$1l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+136776 23580 moveto
+P$1t
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+137665 23290 moveto
+P$1q
+137564 23290 moveto
+P$1r
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+137750 23740 moveto
+P$24
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+1192 25372 moveto
+P$2x
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+1776 26045 moveto
+P$1t
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+2665 25754 moveto
+P$1q
+2564 25754 moveto
+P$1r
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+3143 26045 moveto
+P$1m
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+3596 26040 moveto
+P$1s
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+3748 25775 moveto
+P$1k
+4062 25701 moveto
+P$1l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+4643 26045 moveto
+P$1m
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+5240 25951 moveto
+P$1n
+4948 25754 moveto
+P$1o
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+1193 28510 moveto
+P$2y
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+1865 28219 moveto
+P$1q
+1764 28219 moveto
+P$1r
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+2312 28510 moveto
+P$22
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+3365 28216 moveto
+P$2z
+3264 28219 moveto
+P$30
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+3965 28219 moveto
+P$1q
+3864 28219 moveto
+P$1r
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+4443 28510 moveto
+P$1m
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+4748 28240 moveto
+P$1k
+5062 28166 moveto
+P$1l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+5643 28510 moveto
+P$1m
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+6096 28505 moveto
+P$1s
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+6248 28240 moveto
+P$1k
+6562 28166 moveto
+P$1l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+7143 28510 moveto
+P$1m
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+7875 28738 moveto
+P$20
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+8054 28129 moveto
+P$2w
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+9048 28240 moveto
+P$1k
+9362 28166 moveto
+P$1l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+9576 28510 moveto
+P$1t
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+10465 28219 moveto
+P$1q
+10364 28219 moveto
+P$1r
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+10550 28669 moveto
+P$2l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+11475 28738 moveto
+P$20
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+11845 28521 moveto
+P$2r
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+12368 27929 moveto
+P$23
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+12873 28510 moveto
+P$1u
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+13073 27805 moveto
+P$1y
+13073 28510 moveto
+P$1z
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+13368 27929 moveto
+P$23
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+14310 28349 moveto
+P$2e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+14450 28669 moveto
+P$24
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+17334 30175 moveto
+P$25
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+17648 29905 moveto
+P$1k
+17962 29831 moveto
+P$1l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+18270 29694 moveto
+P$1x
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+18776 30175 moveto
+P$1t
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+19610 30014 moveto
+P$2e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+20265 29881 moveto
+P$2z
+20164 29884 moveto
+P$30
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+20376 30175 moveto
+P$1t
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+20921 30186 moveto
+P$1g
+20943 30112 moveto
+P$1h
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+21448 29881 moveto
+P$1i
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+22070 29694 moveto
+P$1x
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+22573 29470 moveto
+P$1y
+22573 30175 moveto
+P$1z
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+22993 30403 moveto
+P$2s
+23142 29884 moveto
+P$2t
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+23739 30175 moveto
+P$1j
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+24048 29905 moveto
+P$1k
+24362 29831 moveto
+P$1l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+24573 29470 moveto
+P$1y
+24573 30175 moveto
+P$1z
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+24996 30170 moveto
+P$1s
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+25575 30403 moveto
+P$20
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+25790 30175 moveto
+P$2m
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+26468 29594 moveto
+P$23
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+27339 30175 moveto
+P$1j
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+27721 30186 moveto
+P$1g
+27743 30112 moveto
+P$1h
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+28610 30014 moveto
+P$2e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+28750 30334 moveto
+P$24
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+64825 31840 moveto
+P$2i
+64810 31301 moveto
+P$2j
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+65565 31549 moveto
+P$1q
+65464 31549 moveto
+P$1r
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+65768 31259 moveto
+P$23
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+66496 31835 moveto
+P$1s
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+66648 31569 moveto
+P$1k
+66962 31496 moveto
+P$1l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+67176 31840 moveto
+P$1t
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+68075 32068 moveto
+P$20
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+68254 31459 moveto
+P$2w
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+69248 31569 moveto
+P$1k
+69562 31496 moveto
+P$1l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+69776 31840 moveto
+P$1t
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+70665 31549 moveto
+P$1q
+70564 31549 moveto
+P$1r
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+70750 31999 moveto
+P$24
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+65226 33505 moveto
+P$2n
+64967 32825 moveto
+P$2o
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+65975 32975 moveto
+P$27
+65871 32977 moveto
+P$28
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+66101 33505 moveto
+P$21
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+66348 33255 moveto
+P$1v
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+67326 33505 moveto
+P$2n
+67067 32825 moveto
+P$2o
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+67843 33505 moveto
+P$1m
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+68565 33211 moveto
+P$2b
+68464 33214 moveto
+P$2c
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+68673 32800 moveto
+P$1y
+68673 33505 moveto
+P$1z
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+69243 33505 moveto
+P$1m
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+69840 33411 moveto
+P$1n
+69548 33214 moveto
+P$26
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+70168 32923 moveto
+P$23
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+71043 33505 moveto
+P$1m
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+71493 33733 moveto
+P$2s
+71642 33214 moveto
+P$2t
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+72375 33733 moveto
+P$20
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+72554 33123 moveto
+P$2w
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+73548 33234 moveto
+P$1k
+73862 33161 moveto
+P$1l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+74076 33505 moveto
+P$1t
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+74965 33214 moveto
+P$1q
+74864 33214 moveto
+P$1r
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+75050 33664 moveto
+P$2l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+75975 33733 moveto
+P$20
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+76190 33505 moveto
+P$2m
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+76868 32923 moveto
+P$23
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+77739 33505 moveto
+P$1j
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+78121 33516 moveto
+P$1g
+78143 33442 moveto
+P$1h
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+79010 33344 moveto
+P$2e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+79150 33664 moveto
+P$24
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+48690 35170 moveto
+P$2v
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+49376 35170 moveto
+P$1t
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+49776 35170 moveto
+P$1t
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+50665 34879 moveto
+P$1q
+50564 34879 moveto
+P$1r
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+50776 35170 moveto
+P$1t
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+51148 34920 moveto
+P$1v
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+52101 35170 moveto
+P$31
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+52521 35181 moveto
+P$1g
+52543 35107 moveto
+P$1h
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+53343 35170 moveto
+P$1m
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+53940 35076 moveto
+P$1n
+53648 34879 moveto
+P$26
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+54173 35170 moveto
+P$1u
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+54373 34465 moveto
+P$1y
+54373 35170 moveto
+P$1z
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+54943 35170 moveto
+P$1m
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+55393 35398 moveto
+P$2s
+55542 34879 moveto
+P$2t
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+56275 35398 moveto
+P$20
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+56454 34788 moveto
+P$2w
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+57448 34899 moveto
+P$1k
+57762 34826 moveto
+P$1l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+57976 35170 moveto
+P$1t
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+58865 34879 moveto
+P$1q
+58764 34879 moveto
+P$1r
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+58950 35329 moveto
+P$24
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+278 36765 moveto
+P$32
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+606 36268 moveto
+P$33
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+1606 36268 moveto
+P$33
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+2695 36207 moveto
+P$34
+2779 36512 moveto
+P$35
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+3206 36268 moveto
+P$36
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+3898 36646 moveto
+P$37
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+4565 36516 moveto
+P$38
+4703 36254 moveto
+P$39
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+5232 36773 moveto
+P$3a
+fill
+100 setlinewidth
+0 0 0 setrgbcolor
+newpath
+0 37098 moveto
+208000 0 rlineto
+stroke
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+3525 38007 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+4165 37746 moveto
+P$3c
+4084 37746 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+4665 37746 moveto
+P$3c
+4584 37746 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+11525 38007 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+12165 37746 moveto
+P$3c
+12084 37746 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+12665 37746 moveto
+P$3c
+12584 37746 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+19525 38007 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+20165 37746 moveto
+P$3c
+20084 37746 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+20665 37746 moveto
+P$3c
+20584 37746 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+27525 38007 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+28165 37746 moveto
+P$3c
+28084 37746 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+28665 37746 moveto
+P$3c
+28584 37746 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+35525 38007 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+36165 37746 moveto
+P$3c
+36084 37746 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+36665 37746 moveto
+P$3c
+36584 37746 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+43525 38007 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+44165 37746 moveto
+P$3c
+44084 37746 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+44665 37746 moveto
+P$3c
+44584 37746 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+51525 38007 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+52165 37746 moveto
+P$3c
+52084 37746 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+52665 37746 moveto
+P$3c
+52584 37746 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+59525 38007 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+60165 37746 moveto
+P$3c
+60084 37746 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+60665 37746 moveto
+P$3c
+60584 37746 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+67525 38007 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+68165 37746 moveto
+P$3c
+68084 37746 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+68665 37746 moveto
+P$3c
+68584 37746 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+75525 38007 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+76165 37746 moveto
+P$3c
+76084 37746 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+76665 37746 moveto
+P$3c
+76584 37746 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+83525 38007 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+84165 37746 moveto
+P$3c
+84084 37746 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+84665 37746 moveto
+P$3c
+84584 37746 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+91525 38007 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+92165 37746 moveto
+P$3c
+92084 37746 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+92665 37746 moveto
+P$3c
+92584 37746 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+99525 38007 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+100165 37746 moveto
+P$3c
+100084 37746 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+100665 37746 moveto
+P$3c
+100584 37746 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+107525 38007 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+108165 37746 moveto
+P$3c
+108084 37746 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+108665 37746 moveto
+P$3c
+108584 37746 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+115525 38007 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+116165 37746 moveto
+P$3c
+116084 37746 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+116665 37746 moveto
+P$3c
+116584 37746 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+123525 38007 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+124165 37746 moveto
+P$3c
+124084 37746 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+124665 37746 moveto
+P$3c
+124584 37746 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+131525 38007 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+132165 37746 moveto
+P$3c
+132084 37746 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+132665 37746 moveto
+P$3c
+132584 37746 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+139525 38007 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+140165 37746 moveto
+P$3c
+140084 37746 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+140665 37746 moveto
+P$3c
+140584 37746 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+147525 38007 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+148165 37746 moveto
+P$3c
+148084 37746 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+148665 37746 moveto
+P$3c
+148584 37746 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+155525 38007 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+156165 37746 moveto
+P$3c
+156084 37746 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+156665 37746 moveto
+P$3c
+156584 37746 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+163525 38007 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+164165 37746 moveto
+P$3c
+164084 37746 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+164665 37746 moveto
+P$3c
+164584 37746 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+171525 38007 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+172165 37746 moveto
+P$3c
+172084 37746 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+172665 37746 moveto
+P$3c
+172584 37746 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+179525 38007 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+180165 37746 moveto
+P$3c
+180084 37746 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+180665 37746 moveto
+P$3c
+180584 37746 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+187525 38007 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+188165 37746 moveto
+P$3c
+188084 37746 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+188665 37746 moveto
+P$3c
+188584 37746 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+195525 38007 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+196165 37746 moveto
+P$3c
+196084 37746 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+196665 37746 moveto
+P$3c
+196584 37746 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+754 39585 moveto
+P$3f
+423 39165 moveto
+P$3g
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+1195 39407 moveto
+P$34
+1279 39712 moveto
+P$35
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+1706 39468 moveto
+P$36
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+2440 39224 moveto
+P$3h
+2434 39973 moveto
+P$3i
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+2765 39716 moveto
+P$38
+2903 39454 moveto
+P$39
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+3432 39973 moveto
+P$3a
+fill
+100 setlinewidth
+0 0 0 setrgbcolor
+newpath
+0 40298 moveto
+208000 0 rlineto
+stroke
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+3525 41207 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+4165 40946 moveto
+P$3c
+4084 40946 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+4665 40946 moveto
+P$3c
+4584 40946 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+11525 41207 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+12165 40946 moveto
+P$3c
+12084 40946 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+12665 40946 moveto
+P$3c
+12584 40946 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+19525 41207 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+20165 40946 moveto
+P$3c
+20084 40946 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+20665 40946 moveto
+P$3c
+20584 40946 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+75525 41207 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+76165 40946 moveto
+P$3c
+76084 40946 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+76665 40946 moveto
+P$3c
+76584 40946 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+83525 41207 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+84165 40946 moveto
+P$3c
+84084 40946 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+84665 40946 moveto
+P$3c
+84584 40946 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+91525 41207 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+92165 40946 moveto
+P$3c
+92084 40946 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+92665 40946 moveto
+P$3c
+92584 40946 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+99650 41243 moveto
+P$3j
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+100165 40946 moveto
+P$3c
+100084 40946 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+100665 40946 moveto
+P$3c
+100584 40946 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+107650 41243 moveto
+P$3j
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+108165 40946 moveto
+P$3c
+108084 40946 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+108665 40946 moveto
+P$3c
+108584 40946 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+115650 41243 moveto
+P$3j
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+116165 40946 moveto
+P$3c
+116084 40946 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+116665 40946 moveto
+P$3c
+116584 40946 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+123650 41243 moveto
+P$3j
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+124165 40946 moveto
+P$3c
+124084 40946 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+124665 40946 moveto
+P$3c
+124584 40946 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+131650 41243 moveto
+P$3j
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+132165 40946 moveto
+P$3c
+132084 40946 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+132665 40946 moveto
+P$3c
+132584 40946 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+139650 41243 moveto
+P$3j
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+140165 40946 moveto
+P$3c
+140084 40946 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+140665 40946 moveto
+P$3c
+140584 40946 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+147650 41243 moveto
+P$3j
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+148165 40946 moveto
+P$3c
+148084 40946 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+148665 40946 moveto
+P$3c
+148584 40946 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+155650 41243 moveto
+P$3j
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+156165 40946 moveto
+P$3c
+156084 40946 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+156665 40946 moveto
+P$3c
+156584 40946 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+163650 41243 moveto
+P$3j
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+164165 40946 moveto
+P$3c
+164084 40946 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+164665 40946 moveto
+P$3c
+164584 40946 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+171650 41243 moveto
+P$3j
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+172165 40946 moveto
+P$3c
+172084 40946 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+172665 40946 moveto
+P$3c
+172584 40946 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+179650 41243 moveto
+P$3j
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+180165 40946 moveto
+P$3c
+180084 40946 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+180665 40946 moveto
+P$3c
+180584 40946 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+187650 41243 moveto
+P$3j
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+188165 40946 moveto
+P$3c
+188084 40946 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+188665 40946 moveto
+P$3c
+188584 40946 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+195650 41243 moveto
+P$3j
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+196165 40946 moveto
+P$3c
+196084 40946 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+196665 40946 moveto
+P$3c
+196584 40946 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+203525 41207 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+204165 40946 moveto
+P$3c
+204084 40946 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+204665 40946 moveto
+P$3c
+204584 40946 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+400 42399 moveto
+P$3k
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+998 43046 moveto
+P$37
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+1718 42929 moveto
+P$3l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+2495 42607 moveto
+P$34
+2579 42912 moveto
+P$35
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+3259 43049 moveto
+P$3m
+fill
+100 setlinewidth
+0 0 0 setrgbcolor
+newpath
+0 43498 moveto
+208000 0 rlineto
+stroke
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+19525 44407 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+20165 44146 moveto
+P$3c
+20084 44146 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+20665 44146 moveto
+P$3c
+20584 44146 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+27525 44407 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+28165 44146 moveto
+P$3c
+28084 44146 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+28665 44146 moveto
+P$3c
+28584 44146 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+35525 44407 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+36165 44146 moveto
+P$3c
+36084 44146 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+36665 44146 moveto
+P$3c
+36584 44146 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+43525 44407 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+44165 44146 moveto
+P$3c
+44084 44146 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+44665 44146 moveto
+P$3c
+44584 44146 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+51525 44407 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+52165 44146 moveto
+P$3c
+52084 44146 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+52665 44146 moveto
+P$3c
+52584 44146 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+67525 44407 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+68165 44146 moveto
+P$3c
+68084 44146 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+68665 44146 moveto
+P$3c
+68584 44146 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+75650 44443 moveto
+P$3j
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+76165 44146 moveto
+P$3c
+76084 44146 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+76665 44146 moveto
+P$3c
+76584 44146 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+83650 44443 moveto
+P$3j
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+84165 44146 moveto
+P$3c
+84084 44146 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+84665 44146 moveto
+P$3c
+84584 44146 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+91650 44443 moveto
+P$3j
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+92165 44146 moveto
+P$3c
+92084 44146 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+92665 44146 moveto
+P$3c
+92584 44146 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+99650 44443 moveto
+P$3j
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+100165 44146 moveto
+P$3c
+100084 44146 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+100665 44146 moveto
+P$3c
+100584 44146 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+107650 44443 moveto
+P$3j
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+108165 44146 moveto
+P$3c
+108084 44146 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+108665 44146 moveto
+P$3c
+108584 44146 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+115650 44443 moveto
+P$3j
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+116165 44146 moveto
+P$3c
+116084 44146 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+116665 44146 moveto
+P$3c
+116584 44146 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+123650 44443 moveto
+P$3j
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+124165 44146 moveto
+P$3c
+124084 44146 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+124665 44146 moveto
+P$3c
+124584 44146 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+131650 44443 moveto
+P$3j
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+132165 44146 moveto
+P$3c
+132084 44146 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+132665 44146 moveto
+P$3c
+132584 44146 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+139650 44443 moveto
+P$3j
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+140165 44146 moveto
+P$3c
+140084 44146 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+140665 44146 moveto
+P$3c
+140584 44146 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+147650 44443 moveto
+P$3j
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+148165 44146 moveto
+P$3c
+148084 44146 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+148665 44146 moveto
+P$3c
+148584 44146 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+155650 44443 moveto
+P$3j
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+156165 44146 moveto
+P$3c
+156084 44146 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+156665 44146 moveto
+P$3c
+156584 44146 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+163650 44443 moveto
+P$3j
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+164165 44146 moveto
+P$3c
+164084 44146 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+164665 44146 moveto
+P$3c
+164584 44146 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+171650 44443 moveto
+P$3j
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+172165 44146 moveto
+P$3c
+172084 44146 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+172665 44146 moveto
+P$3c
+172584 44146 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+179525 44407 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+180165 44146 moveto
+P$3c
+180084 44146 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+180665 44146 moveto
+P$3c
+180584 44146 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+187525 44407 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+188165 44146 moveto
+P$3c
+188084 44146 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+188665 44146 moveto
+P$3c
+188584 44146 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+195525 44407 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+196165 44146 moveto
+P$3c
+196084 44146 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+196665 44146 moveto
+P$3c
+196584 44146 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+260 45615 moveto
+P$3n
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+698 46246 moveto
+P$37
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+1432 46373 moveto
+P$3o
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+1840 45624 moveto
+P$3h
+1834 46373 moveto
+P$3i
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+2198 46246 moveto
+P$37
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+3159 46249 moveto
+P$3m
+fill
+100 setlinewidth
+0 0 0 setrgbcolor
+newpath
+0 46698 moveto
+208000 0 rlineto
+stroke
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+3525 47607 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+4165 47346 moveto
+P$3c
+4084 47346 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+4665 47346 moveto
+P$3c
+4584 47346 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+11525 47607 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+12165 47346 moveto
+P$3c
+12084 47346 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+12665 47346 moveto
+P$3c
+12584 47346 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+19525 47607 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+20165 47346 moveto
+P$3c
+20084 47346 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+20665 47346 moveto
+P$3c
+20584 47346 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+27525 47607 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+28165 47346 moveto
+P$3c
+28084 47346 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+28665 47346 moveto
+P$3c
+28584 47346 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+35525 47607 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+36165 47346 moveto
+P$3c
+36084 47346 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+36665 47346 moveto
+P$3c
+36584 47346 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+43525 47607 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+44165 47346 moveto
+P$3c
+44084 47346 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+44665 47346 moveto
+P$3c
+44584 47346 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+51525 47607 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+52165 47346 moveto
+P$3c
+52084 47346 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+52665 47346 moveto
+P$3c
+52584 47346 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+59525 47607 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+60165 47346 moveto
+P$3c
+60084 47346 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+60665 47346 moveto
+P$3c
+60584 47346 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+75525 47607 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+76165 47346 moveto
+P$3c
+76084 47346 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+76665 47346 moveto
+P$3c
+76584 47346 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+83525 47607 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+84165 47346 moveto
+P$3c
+84084 47346 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+84665 47346 moveto
+P$3c
+84584 47346 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+91525 47607 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+92165 47346 moveto
+P$3c
+92084 47346 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+92665 47346 moveto
+P$3c
+92584 47346 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+99525 47607 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+100165 47346 moveto
+P$3c
+100084 47346 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+100665 47346 moveto
+P$3c
+100584 47346 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+107525 47607 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+108165 47346 moveto
+P$3c
+108084 47346 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+108665 47346 moveto
+P$3c
+108584 47346 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+115525 47607 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+116165 47346 moveto
+P$3c
+116084 47346 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+116665 47346 moveto
+P$3c
+116584 47346 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+123525 47607 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+124165 47346 moveto
+P$3c
+124084 47346 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+124665 47346 moveto
+P$3c
+124584 47346 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+131525 47607 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+132165 47346 moveto
+P$3c
+132084 47346 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+132665 47346 moveto
+P$3c
+132584 47346 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+139525 47607 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+140165 47346 moveto
+P$3c
+140084 47346 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+140665 47346 moveto
+P$3c
+140584 47346 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+147525 47607 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+148165 47346 moveto
+P$3c
+148084 47346 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+148665 47346 moveto
+P$3c
+148584 47346 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+155525 47607 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+156165 47346 moveto
+P$3c
+156084 47346 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+156665 47346 moveto
+P$3c
+156584 47346 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+163525 47607 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+164165 47346 moveto
+P$3c
+164084 47346 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+164665 47346 moveto
+P$3c
+164584 47346 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+171525 47607 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+172165 47346 moveto
+P$3c
+172084 47346 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+172665 47346 moveto
+P$3c
+172584 47346 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+179525 47607 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+180165 47346 moveto
+P$3c
+180084 47346 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+180665 47346 moveto
+P$3c
+180584 47346 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+187525 47607 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+188165 47346 moveto
+P$3c
+188084 47346 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+188665 47346 moveto
+P$3c
+188584 47346 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+195525 47607 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+196165 47346 moveto
+P$3c
+196084 47346 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+196665 47346 moveto
+P$3c
+196584 47346 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+203525 47607 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+204165 47346 moveto
+P$3c
+204084 47346 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+204665 47346 moveto
+P$3c
+204584 47346 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+815 49573 moveto
+P$3p
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+1065 49316 moveto
+P$38
+1203 49054 moveto
+P$39
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+1921 49004 moveto
+P$3q
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+2500 49315 moveto
+P$3r
+2385 49315 moveto
+P$3s
+fill
+100 setlinewidth
+0 0 0 setrgbcolor
+newpath
+0 49898 moveto
+208000 0 rlineto
+stroke
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+3525 50807 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+4165 50546 moveto
+P$3c
+4084 50546 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+4665 50546 moveto
+P$3c
+4584 50546 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+11525 50807 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+12165 50546 moveto
+P$3c
+12084 50546 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+12665 50546 moveto
+P$3c
+12584 50546 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+19525 50807 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+20165 50546 moveto
+P$3c
+20084 50546 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+20665 50546 moveto
+P$3c
+20584 50546 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+27525 50807 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+28165 50546 moveto
+P$3c
+28084 50546 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+28665 50546 moveto
+P$3c
+28584 50546 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+35525 50807 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+36165 50546 moveto
+P$3c
+36084 50546 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+36665 50546 moveto
+P$3c
+36584 50546 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+43525 50807 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+44165 50546 moveto
+P$3c
+44084 50546 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+44665 50546 moveto
+P$3c
+44584 50546 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+51650 50843 moveto
+P$3j
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+52165 50546 moveto
+P$3c
+52084 50546 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+52665 50546 moveto
+P$3c
+52584 50546 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+59665 50682 moveto
+P$3t
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+60165 50546 moveto
+P$3c
+60084 50546 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+60665 50546 moveto
+P$3c
+60584 50546 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+67650 50843 moveto
+P$3j
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+68165 50546 moveto
+P$3c
+68084 50546 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+68665 50546 moveto
+P$3c
+68584 50546 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+75650 50843 moveto
+P$3j
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+76165 50546 moveto
+P$3c
+76084 50546 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+76665 50546 moveto
+P$3c
+76584 50546 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+83650 50843 moveto
+P$3j
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+84165 50546 moveto
+P$3c
+84084 50546 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+84665 50546 moveto
+P$3c
+84584 50546 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+91525 50807 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+92165 50546 moveto
+P$3c
+92084 50546 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+92665 50546 moveto
+P$3c
+92584 50546 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+99525 50807 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+100165 50546 moveto
+P$3c
+100084 50546 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+100665 50546 moveto
+P$3c
+100584 50546 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+107525 50807 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+108165 50546 moveto
+P$3c
+108084 50546 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+108665 50546 moveto
+P$3c
+108584 50546 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+115525 50807 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+116165 50546 moveto
+P$3c
+116084 50546 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+116665 50546 moveto
+P$3c
+116584 50546 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+123650 50843 moveto
+P$3j
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+124165 50546 moveto
+P$3c
+124084 50546 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+1 0 0 setrgbcolor
+newpath
+124665 50546 moveto
+P$3c
+124584 50546 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+131525 50807 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+132165 50546 moveto
+P$3c
+132084 50546 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+132665 50546 moveto
+P$3c
+132584 50546 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+139525 50807 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+140165 50546 moveto
+P$3c
+140084 50546 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+140665 50546 moveto
+P$3c
+140584 50546 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+147525 50807 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+148165 50546 moveto
+P$3c
+148084 50546 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+148665 50546 moveto
+P$3c
+148584 50546 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+155525 50807 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+156165 50546 moveto
+P$3c
+156084 50546 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+156665 50546 moveto
+P$3c
+156584 50546 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+163525 50807 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+164165 50546 moveto
+P$3c
+164084 50546 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+164665 50546 moveto
+P$3c
+164584 50546 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+171525 50807 moveto
+P$3b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+172165 50546 moveto
+P$3c
+172084 50546 moveto
+P$3d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+172665 50546 moveto
+P$3c
+172584 50546 moveto
+P$3e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+3960 53558 moveto
+P$e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+4462 53407 moveto
+P$f
+4371 53407 moveto
+P$g
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+11960 53558 moveto
+P$e
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+12306 53697 moveto
+P$h
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+20056 53697 moveto
+P$h
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+28195 53736 moveto
+P$i
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+36210 53558 moveto
+P$j
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+44145 53593 moveto
+P$k
+44060 53193 moveto
+P$l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+51987 53353 moveto
+P$m
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+60220 53533 moveto
+P$n
+60018 53708 moveto
+P$o
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+67848 53236 moveto
+P$p
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+76192 53241 moveto
+P$q
+76123 53560 moveto
+P$r
+76104 53241 moveto
+P$s
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+83782 53282 moveto
+P$t
+83993 53113 moveto
+P$u
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+91806 53697 moveto
+P$v
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+92462 53407 moveto
+P$f
+92371 53407 moveto
+P$g
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+99806 53697 moveto
+P$v
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+100306 53697 moveto
+P$h
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+107806 53697 moveto
+P$v
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+108445 53736 moveto
+P$i
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+115806 53697 moveto
+P$v
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+116460 53558 moveto
+P$j
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+123806 53697 moveto
+P$v
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+124395 53593 moveto
+P$k
+124310 53193 moveto
+P$l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+131806 53697 moveto
+P$v
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+132237 53353 moveto
+P$m
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+139806 53697 moveto
+P$v
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+140470 53533 moveto
+P$n
+140268 53708 moveto
+P$o
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+147806 53697 moveto
+P$v
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+148098 53236 moveto
+P$p
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+155806 53697 moveto
+P$v
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+156442 53241 moveto
+P$q
+156373 53560 moveto
+P$r
+156354 53241 moveto
+P$s
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+163806 53697 moveto
+P$v
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+164032 53282 moveto
+P$t
+164243 53113 moveto
+P$u
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+171945 53736 moveto
+P$w
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+172462 53407 moveto
+P$f
+172371 53407 moveto
+P$g
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+179945 53736 moveto
+P$w
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+180306 53697 moveto
+P$h
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+187945 53736 moveto
+P$w
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+188445 53736 moveto
+P$i
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+195945 53736 moveto
+P$w
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+196460 53558 moveto
+P$j
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+203945 53736 moveto
+P$w
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+204395 53593 moveto
+P$k
+204310 53193 moveto
+P$l
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+3720 52536 moveto
+P$0
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+4662 52305 moveto
+P$1
+4573 52305 moveto
+P$2
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+11603 52536 moveto
+P$3
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+12203 52405 moveto
+P$4
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+20020 52552 moveto
+P$5
+20376 52305 moveto
+P$6
+20482 52103 moveto
+P$7
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+27603 52536 moveto
+P$3
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+28209 52041 moveto
+P$8
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+35757 52243 moveto
+P$9
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+36475 52064 moveto
+P$a
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+43567 52360 moveto
+P$b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+44326 52068 moveto
+P$c
+44392 52302 moveto
+P$d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+51517 52360 moveto
+P$b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+52203 52405 moveto
+P$4
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+59720 52536 moveto
+P$0
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+60662 52305 moveto
+P$1
+60573 52305 moveto
+P$2
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+67603 52536 moveto
+P$3
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+68203 52405 moveto
+P$4
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+76020 52552 moveto
+P$5
+76376 52305 moveto
+P$6
+76482 52103 moveto
+P$7
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+83603 52536 moveto
+P$3
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+84209 52041 moveto
+P$8
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+91757 52243 moveto
+P$9
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+92475 52064 moveto
+P$a
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+99567 52360 moveto
+P$b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+100326 52068 moveto
+P$c
+100392 52302 moveto
+P$d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+107517 52360 moveto
+P$b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+108203 52405 moveto
+P$4
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+115720 52536 moveto
+P$0
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+116662 52305 moveto
+P$1
+116573 52305 moveto
+P$2
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+123603 52536 moveto
+P$3
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+124203 52405 moveto
+P$4
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+132020 52552 moveto
+P$5
+132376 52305 moveto
+P$6
+132482 52103 moveto
+P$7
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+139603 52536 moveto
+P$3
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+140209 52041 moveto
+P$8
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+147757 52243 moveto
+P$9
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+148475 52064 moveto
+P$a
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+155567 52360 moveto
+P$b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+156326 52068 moveto
+P$c
+156392 52302 moveto
+P$d
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+163517 52360 moveto
+P$b
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+164203 52405 moveto
+P$4
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+171720 52536 moveto
+P$0
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+172662 52305 moveto
+P$1
+172573 52305 moveto
+P$2
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+179603 52536 moveto
+P$3
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+180203 52405 moveto
+P$4
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+188020 52552 moveto
+P$5
+188376 52305 moveto
+P$6
+188482 52103 moveto
+P$7
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+195603 52536 moveto
+P$3
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+196209 52041 moveto
+P$8
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+203757 52243 moveto
+P$9
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+204475 52064 moveto
+P$a
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+4793 54395 moveto
+P$x
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+5420 54560 moveto
+P$y
+5457 54846 moveto
+P$z
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+5954 54620 moveto
+P$10
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+6812 55075 moveto
+P$11
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+7420 54560 moveto
+P$y
+7457 54846 moveto
+P$z
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+7970 54687 moveto
+P$12
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+8470 55140 moveto
+P$13
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+9648 55123 moveto
+P$14
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+10254 54726 moveto
+P$15
+10082 54726 moveto
+P$16
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+10848 55123 moveto
+P$14
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+11459 54909 moveto
+P$17
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+108556 54787 moveto
+P$18
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+109239 54559 moveto
+P$19
+109232 54618 moveto
+P$1a
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+109896 54832 moveto
+P$1b
+109521 54342 moveto
+P$1c
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+110420 54687 moveto
+P$12
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+111062 55075 moveto
+P$11
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+111670 54560 moveto
+P$y
+111707 54846 moveto
+P$z
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+112220 54687 moveto
+P$12
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+112720 55140 moveto
+P$13
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+113898 55123 moveto
+P$14
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+114504 54726 moveto
+P$15
+114332 54726 moveto
+P$16
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+115098 55123 moveto
+P$14
+fill
+0 setlinewidth
+[] 0 setdash
+0 0 0 setrgbcolor
+newpath
+115709 54909 moveto
+P$17
+fill
+grestore
+showpage
+%plantuml done
+%%EOF
diff --git a/20-implementierungsheft/assets/gantt.png b/20-implementierungsheft/assets/gantt.png
new file mode 100644
index 0000000..b1b7e17
--- /dev/null
+++ b/20-implementierungsheft/assets/gantt.png
Binary files differ
diff --git a/20-implementierungsheft/assets/help.png b/20-implementierungsheft/assets/help.png
new file mode 100644
index 0000000..39a1b84
--- /dev/null
+++ b/20-implementierungsheft/assets/help.png
Binary files differ
diff --git a/20-implementierungsheft/assets/lastupdate.png b/20-implementierungsheft/assets/lastupdate.png
new file mode 100644
index 0000000..e9b7f5c
--- /dev/null
+++ b/20-implementierungsheft/assets/lastupdate.png
Binary files differ
diff --git a/20-implementierungsheft/assets/loading.png b/20-implementierungsheft/assets/loading.png
new file mode 100644
index 0000000..cc95763
--- /dev/null
+++ b/20-implementierungsheft/assets/loading.png
Binary files differ
diff --git a/20-implementierungsheft/assets/logo.pdf b/20-implementierungsheft/assets/logo.pdf
new file mode 100644
index 0000000..91fd334
--- /dev/null
+++ b/20-implementierungsheft/assets/logo.pdf
Binary files differ
diff --git a/20-implementierungsheft/assets/logo.svg b/20-implementierungsheft/assets/logo.svg
new file mode 100644
index 0000000..1609066
--- /dev/null
+++ b/20-implementierungsheft/assets/logo.svg
@@ -0,0 +1,211 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ version="1.2"
+ width="87.589989mm"
+ height="52.16547mm"
+ viewBox="0 0 8758.9989 5216.547"
+ preserveAspectRatio="xMidYMid"
+ fill-rule="evenodd"
+ stroke-width="28.222"
+ stroke-linejoin="round"
+ xml:space="preserve"
+ id="svg206"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg">
+ <defs
+ class="ClipPathGroup"
+ id="defs8" />
+ <defs
+ id="defs51"><font
+ id="EmbeddedFont_1"
+ horiz-adv-x="2048"
+ horiz-origin-x="0"
+ horiz-origin-y="0"
+ vert-origin-x="512"
+ vert-origin-y="768"
+ vert-adv-y="1024">
+ <font-face
+ font-family="Noto Sans Display Light embedded"
+ units-per-em="2048"
+ font-weight="normal"
+ font-style="normal"
+ ascent="2170"
+ descent="609"
+ id="font-face10" />
+ <missing-glyph
+ horiz-adv-x="2048"
+ d="M 0,0 L 2047,0 2047,2047 0,2047 0,0 Z"
+ id="missing-glyph12" />
+ <glyph
+ unicode="y"
+ horiz-adv-x="927"
+ d="M 2,1089 L 127,1089 367,413 C 388,352 407,298 422,250 437,203 449,161 457,124 L 463,124 C 471,156 483,196 498,246 513,296 530,350 551,409 L 786,1089 913,1089 453,-193 C 418,-290 377,-364 328,-416 279,-468 213,-494 131,-494 107,-494 84,-493 63,-490 43,-487 25,-482 8,-476 L 8,-377 C 23,-383 40,-387 57,-391 75,-394 95,-396 117,-396 170,-396 214,-378 249,-342 284,-307 314,-252 340,-179 L 403,4 2,1089 Z"
+ id="glyph14" />
+ <glyph
+ unicode="t"
+ horiz-adv-x="610"
+ d="M 465,80 C 494,80 521,82 547,87 573,91 595,97 614,105 L 614,11 C 594,3 569,-5 541,-11 512,-17 481,-20 449,-20 363,-20 296,5 249,56 202,106 178,189 178,304 L 178,996 27,996 27,1061 178,1100 219,1350 295,1350 295,1090 608,1090 608,996 295,996 295,310 C 295,157 352,80 465,80 Z"
+ id="glyph16" />
+ <glyph
+ unicode="s"
+ horiz-adv-x="742"
+ d="M 817,289 C 817,191 782,115 713,61 643,7 545,-20 418,-20 347,-20 284,-14 228,-1 173,12 126,29 88,50 L 88,162 C 134,138 186,118 244,102 301,86 360,78 420,78 520,78 592,96 636,133 680,169 702,218 702,281 702,341 679,387 632,419 585,451 515,484 422,519 359,542 303,565 255,589 207,613 169,643 142,680 116,717 102,768 102,832 102,919 136,987 204,1037 271,1086 361,1110 473,1110 535,1110 592,1104 646,1092 700,1080 750,1063 795,1043 L 754,946 C 713,964 667,980 617,993 568,1006 518,1012 469,1012 388,1012 326,997 283,967 239,937 217,893 217,836 217,792 228,758 249,733 270,707 301,686 342,668 383,650 433,630 492,609 553,585 608,562 657,537 707,512 745,481 774,443 803,405 817,353 817,289 Z"
+ id="glyph18" />
+ <glyph
+ unicode="r"
+ horiz-adv-x="583"
+ d="M 596,1108 C 646,1108 692,1102 733,1091 L 717,983 C 674,995 632,1001 590,1001 497,1001 423,964 368,890 312,817 285,719 285,598 L 285,-1 168,-1 168,1089 266,1089 279,886 285,886 C 311,948 350,1000 402,1043 455,1086 520,1108 596,1108 Z"
+ id="glyph20" />
+ <glyph
+ unicode="o"
+ horiz-adv-x="927"
+ d="M 1030,547 C 1030,433 1012,333 976,248 940,164 887,98 818,51 749,4 665,-20 565,-20 471,-20 390,3 322,50 253,96 201,162 164,247 127,333 109,433 109,547 109,723 150,861 232,961 315,1061 429,1110 575,1110 672,1110 755,1087 822,1040 890,993 941,927 977,842 1012,757 1030,659 1030,547 Z M 229,547 C 229,407 257,294 312,208 368,123 453,80 567,80 685,80 771,123 826,209 882,295 909,408 909,547 909,637 898,717 875,787 851,856 815,911 766,951 717,990 653,1010 573,1010 459,1010 373,969 315,887 258,805 229,692 229,547 Z"
+ id="glyph22" />
+ <glyph
+ unicode="n"
+ horiz-adv-x="847"
+ d="M 633,1110 C 749,1110 838,1078 900,1014 962,950 993,850 993,713 L 993,1 877,1 877,705 C 877,809 854,885 810,935 766,985 701,1010 616,1010 395,1010 285,871 285,594 L 285,1 168,1 168,1090 262,1090 279,901 287,901 C 314,962 357,1011 416,1051 474,1091 547,1110 633,1110 Z"
+ id="glyph24" />
+ <glyph
+ unicode="m"
+ horiz-adv-x="1430"
+ d="M 1245,1110 C 1348,1110 1427,1080 1485,1018 1542,957 1571,860 1571,727 L 1571,1 1454,1 1454,723 C 1454,820 1434,892 1393,939 1352,986 1296,1010 1227,1010 1130,1010 1056,980 1005,919 953,858 928,764 928,637 L 928,1 811,1 811,723 C 811,820 791,892 750,939 709,986 653,1010 584,1010 487,1010 413,978 361,914 310,850 285,751 285,619 L 285,1 168,1 168,1090 262,1090 279,918 287,918 C 313,971 352,1016 403,1054 455,1092 521,1110 600,1110 675,1110 739,1093 791,1059 842,1025 879,975 899,908 L 907,908 C 936,972 980,1022 1038,1057 1097,1093 1166,1110 1245,1110 Z"
+ id="glyph26" />
+ <glyph
+ unicode="i"
+ horiz-adv-x="187"
+ d="M 227,1493 C 279,1493 305,1464 305,1405 305,1345 279,1315 227,1315 175,1315 150,1345 150,1405 150,1464 175,1493 227,1493 Z M 285,1090 L 285,0 168,0 168,1090 285,1090 Z"
+ id="glyph28" />
+ <glyph
+ unicode="h"
+ horiz-adv-x="847"
+ d="M 285,1059 C 285,1031 284,1003 283,977 281,951 279,926 276,901 L 285,901 C 312,962 355,1011 413,1051 471,1091 543,1110 629,1110 746,1110 836,1078 899,1014 962,950 993,850 993,713 L 993,1 877,1 877,705 C 877,809 854,885 810,935 766,985 701,1010 616,1010 395,1010 285,871 285,594 L 285,1 168,1 168,1557 285,1557 285,1059 Z"
+ id="glyph30" />
+ <glyph
+ unicode="f"
+ horiz-adv-x="689"
+ d="M 575,995 L 332,995 332,-1 213,-1 213,995 27,995 27,1058 213,1093 213,1202 C 213,1445 316,1566 522,1566 559,1566 593,1563 623,1557 653,1551 680,1544 705,1536 L 678,1439 C 655,1448 630,1454 603,1460 577,1465 550,1468 524,1468 456,1468 407,1447 377,1405 347,1362 332,1295 332,1202 L 332,1089 575,1089 575,995 Z"
+ id="glyph32" />
+ <glyph
+ unicode="e"
+ horiz-adv-x="874"
+ d="M 559,1110 C 646,1110 720,1089 779,1046 839,1003 883,944 913,869 943,794 958,708 958,611 L 958,531 229,531 C 231,386 262,275 325,198 387,121 476,82 592,82 656,82 712,88 759,100 806,111 858,130 915,156 L 915,50 C 865,25 814,7 764,-4 713,-15 655,-20 588,-20 434,-20 315,30 232,129 150,229 109,365 109,537 109,648 126,746 162,832 197,918 249,986 315,1036 382,1085 464,1110 559,1110 Z M 559,1012 C 465,1012 389,979 333,912 276,845 243,750 233,627 L 838,627 C 838,742 815,835 769,906 723,977 653,1012 559,1012 Z"
+ id="glyph34" />
+ <glyph
+ unicode="d"
+ horiz-adv-x="900"
+ d="M 535,-20 C 398,-20 293,27 219,120 145,214 109,352 109,535 109,722 147,865 224,963 301,1061 408,1110 545,1110 629,1110 698,1090 752,1050 805,1010 845,961 872,904 L 881,904 C 879,935 878,970 876,1009 873,1048 872,1084 872,1117 L 872,1557 989,1557 989,0 895,0 879,191 872,191 C 845,132 805,82 751,41 697,0 625,-20 535,-20 Z M 553,80 C 669,80 752,119 801,195 850,271 875,382 875,527 L 875,545 C 875,695 850,810 801,890 752,970 671,1010 559,1010 451,1010 369,969 313,886 257,804 229,686 229,533 229,385 256,273 309,196 363,119 444,80 553,80 Z"
+ id="glyph36" />
+ <glyph
+ unicode="c"
+ horiz-adv-x="768"
+ d="M 580,-20 C 429,-20 313,29 231,127 150,226 109,363 109,539 109,662 129,766 170,850 211,935 269,1000 343,1044 417,1088 504,1110 602,1110 651,1110 698,1106 742,1096 787,1087 825,1074 858,1057 L 825,957 C 791,972 754,984 714,993 673,1002 636,1006 600,1006 481,1006 390,964 326,881 261,798 229,685 229,541 229,405 258,294 314,210 371,126 459,84 580,84 630,84 678,90 723,101 768,112 809,125 846,142 L 846,37 C 812,20 773,6 729,-5 685,-15 636,-20 580,-20 Z"
+ id="glyph38" />
+ <glyph
+ unicode="a"
+ horiz-adv-x="822"
+ d="M 535,1108 C 651,1108 737,1078 795,1018 852,958 881,863 881,734 L 881,0 793,0 772,185 766,185 C 729,123 684,74 631,36 578,-1 503,-20 408,-20 311,-20 233,6 176,59 119,111 90,187 90,285 90,394 132,477 215,533 298,589 420,621 580,629 L 764,639 764,715 C 764,822 744,897 705,942 665,987 606,1010 528,1010 477,1010 426,1002 378,987 329,972 281,953 231,928 L 195,1022 C 242,1047 295,1067 352,1084 410,1100 470,1108 535,1108 Z M 594,543 C 466,536 370,512 307,470 244,429 213,367 213,285 213,217 232,165 271,131 310,96 363,78 430,78 535,78 617,111 676,176 735,240 764,330 764,445 L 764,551 594,543 Z"
+ id="glyph40" />
+ <glyph
+ unicode="S"
+ horiz-adv-x="875"
+ d="M 956,381 C 956,294 936,220 894,160 852,100 796,55 724,25 652,-5 571,-20 479,-20 396,-20 324,-14 262,-2 201,11 147,26 102,46 L 102,162 C 152,142 209,124 273,109 338,94 409,87 485,87 589,87 673,110 738,158 803,206 836,278 836,373 836,431 823,478 798,515 772,553 734,586 682,614 630,642 565,670 485,699 410,726 345,757 291,791 236,825 194,868 164,919 134,970 119,1035 119,1112 119,1192 138,1259 176,1314 214,1369 267,1411 333,1440 399,1469 474,1483 559,1483 626,1483 689,1476 750,1463 810,1449 868,1430 924,1405 L 883,1303 C 772,1352 663,1377 555,1377 462,1377 386,1354 328,1310 269,1266 240,1200 240,1114 240,1052 252,1001 278,964 303,926 340,895 389,869 438,843 498,817 567,791 648,762 717,731 775,698 833,664 878,623 909,573 941,523 956,459 956,381 Z"
+ id="glyph42" />
+ <glyph
+ unicode="P"
+ horiz-adv-x="848"
+ d="M 539,1462 C 869,1462 1034,1325 1034,1049 1034,908 992,798 907,718 823,638 690,598 510,598 L 311,598 311,0 193,0 193,1462 539,1462 Z M 528,1358 L 311,1358 311,702 498,702 C 629,702 730,727 803,776 875,825 911,914 911,1043 911,1152 880,1232 818,1282 756,1333 659,1358 528,1358 Z"
+ id="glyph44" />
+ <glyph
+ unicode="E"
+ horiz-adv-x="769"
+ d="M 950,0 L 193,0 193,1462 950,1462 950,1356 311,1356 311,821 913,821 913,715 311,715 311,107 950,107 950,0 Z"
+ id="glyph46" />
+ <glyph
+ unicode=" "
+ horiz-adv-x="503"
+ id="glyph48" />
+ </font></defs>
+ <defs
+ class="TextShapeIndex"
+ id="defs55" />
+ <defs
+ class="EmbeddedBulletChars"
+ id="defs87" />
+
+ <g
+ id="id10"
+ clip-path="none"
+ transform="translate(-700.00001,-2550)">
+
+ <text
+ class="SVGTextShape"
+ id="text151"
+ x="217.60002"
+ y="-56.506969"
+ style="letter-spacing:4.7625px;word-spacing:104.775px"><tspan
+ class="TextParagraph"
+ font-family="'Noto Sans Display Light', sans-serif"
+ font-size="494px"
+ font-weight="400"
+ id="tspan149"><tspan
+ class="TextPosition"
+ x="650.59998"
+ y="7647.4932"
+ id="tspan147"><tspan
+ fill="#808080"
+ stroke="none"
+ style="white-space:pre"
+ id="tspan145"
+ dx="2.1199999">Podcast Synchronisation made Efficient</tspan></tspan></tspan></text>
+ </g><g
+ id="g1277"
+ transform="translate(-700.00001,-2550)"><path
+ id="path131-3"
+ d="m 6694.0006,4763 c -559.5515,4.407 -980.3924,428.0893 -986.038,985.9863 18.2894,552.8957 454.3127,974.1166 989.0352,986.0379 v -235.0244 c -406.8751,-27.3888 -715.1078,-362.1649 -719.0259,-748.0163 12.7874,-421.0793 236.9242,-746.3999 750.0318,-749.98 895.0688,1.4728 1915.5158,0 2730.9957,0 V 4763 Z"
+ style="fill:#0084d1;fill-opacity:1"
+ clip-path="none" /><path
+ id="path131"
+ d="m 6685.0183,2562.996 c -559.5515,4.407 -980.3924,428.0893 -986.038,985.9863 18.2894,552.8957 454.3127,974.1167 989.0352,986.038 v -235.0244 c -406.8751,-27.3888 -715.1078,-362.165 -719.0259,-748.0164 12.7874,-421.0792 236.9242,-746.3998 750.0318,-749.98 895.0688,1.4728 1915.5158,0 2730.996,0 V 2562.996 Z"
+ style="fill:#0084d1;fill-opacity:1"
+ clip-path="none" /></g><g
+ id="g1263"
+ transform="translate(-700.00001,-2550)"><path
+ fill="none"
+ stroke="#069a2e"
+ stroke-width="265"
+ stroke-linejoin="round"
+ d="m 2793,5962 c 1283,0 429,-2762 1712,-2762"
+ id="path124" /><path
+ id="path110-6"
+ d="M 3198.0212,6550 V 6300.0411 H 2448.0411 V 6050.0305 5550.0094 H 2198.0305 V 6300.0411 6550 H 2448.0411 2698 Z"
+ style="fill:#069a2e;fill-opacity:1" /><path
+ id="path110"
+ d="m 4111.997,2550.0252 v 249.9589 h 749.9801 v 250.0106 500.0211 h 250.0106 v -750.0317 -249.9589 h -250.0106 -249.9589 z"
+ style="fill:#069a2e;fill-opacity:1" /></g>
+ <g
+ id="g1249"
+ transform="translate(-700.00001,-2550)"><path
+ fill="#ff8000"
+ stroke="none"
+ d="M 2215,4164 C 2412.6918,3832.6035 2379.3124,3383.7591 2135.4189,3084.8193 1956.8564,2857.4026 1671.3097,2718.8851 1382,2721 c 0,-52.6667 0,-105.3333 0,-158 -60.1303,-1.0792 190.6585,-1.2724 121.9814,2.7933 434.6311,30.3756 832.6257,336.7309 974.9655,748.2365 148.7336,402.6249 41.0263,883.7477 -266.0719,1183.8452 C 1996.6852,4716.1853 1689.0048,4838.6187 1382,4830 c 0,-61.6667 0,-123.3333 0,-185 338.199,2.9253 666.226,-186.816 833,-481 z"
+ id="path193" /><path
+ fill="#ff8000"
+ stroke="none"
+ d="m 1936,3979 c 175.8129,-283.3241 59.7943,-700.6319 -239.8255,-849.407 -94.2713,-50.9942 -201.887,-77.9344 -309.1745,-74.593 0,-57 0,-114 0,-171 396.3865,-24.0968 777.5367,297.6517 818.5878,693.1841 44.0348,337.5467 -149.4277,694.9971 -466.4953,826.9493 -110.1027,49.0687 -231.5272,73.543 -352.0925,67.8666 0,-61.6667 0,-123.3333 0,-185 220.6353,7.5804 440.8554,-115.3286 549,-308 z"
+ id="path186" /><path
+ fill="#ff8000"
+ stroke="none"
+ d="m 1659,3822 c 86.3933,-138.0398 18.2474,-344.669 -134.6962,-402.3205 C 1483.44,3402.2177 1438.3524,3394.2432 1394,3398 c 0,-56.6667 0,-113.3333 0,-170 223.1964,-19.6143 444.7886,153.3254 478.4886,375.1817 32.646,181.6951 -54.6854,381.4331 -217.3127,472.2205 -78.2316,46.131 -170.3991,69.3119 -261.1759,62.5978 0,-58.3333 0,-116.6667 0,-175 105.6736,9.5509 212.8962,-49.2218 265,-141 z"
+ id="path179" /><rect
+ class="BoundingBox"
+ stroke="none"
+ fill="none"
+ x="700"
+ y="2550"
+ width="501"
+ height="4001"
+ id="rect136"
+ style="fill:#ff8000;fill-opacity:1" /></g>
+
+</svg>
diff --git a/20-implementierungsheft/assets/navbar.png b/20-implementierungsheft/assets/navbar.png
new file mode 100644
index 0000000..dd9f8e8
--- /dev/null
+++ b/20-implementierungsheft/assets/navbar.png
Binary files differ
diff --git a/20-implementierungsheft/assets/password-margin.png b/20-implementierungsheft/assets/password-margin.png
new file mode 100644
index 0000000..d9d4fa3
--- /dev/null
+++ b/20-implementierungsheft/assets/password-margin.png
Binary files differ
diff --git a/20-implementierungsheft/assets/password.png b/20-implementierungsheft/assets/password.png
new file mode 100644
index 0000000..68248a0
--- /dev/null
+++ b/20-implementierungsheft/assets/password.png
Binary files differ
diff --git a/20-implementierungsheft/assets/passwordinput.png b/20-implementierungsheft/assets/passwordinput.png
new file mode 100644
index 0000000..2419828
--- /dev/null
+++ b/20-implementierungsheft/assets/passwordinput.png
Binary files differ
diff --git a/20-implementierungsheft/assets/passwordvalidator.png b/20-implementierungsheft/assets/passwordvalidator.png
new file mode 100644
index 0000000..b089f7c
--- /dev/null
+++ b/20-implementierungsheft/assets/passwordvalidator.png
Binary files differ
diff --git a/20-implementierungsheft/assets/progresstime.png b/20-implementierungsheft/assets/progresstime.png
new file mode 100644
index 0000000..6877a97
--- /dev/null
+++ b/20-implementierungsheft/assets/progresstime.png
Binary files differ
diff --git a/20-implementierungsheft/assets/subscription.png b/20-implementierungsheft/assets/subscription.png
new file mode 100644
index 0000000..58a84f9
--- /dev/null
+++ b/20-implementierungsheft/assets/subscription.png
Binary files differ
diff --git a/20-implementierungsheft/implementierungsheft.tex b/20-implementierungsheft/implementierungsheft.tex
new file mode 100644
index 0000000..ed54d59
--- /dev/null
+++ b/20-implementierungsheft/implementierungsheft.tex
@@ -0,0 +1,98 @@
+% \documentclass[a4paper, UTF8, 12pt]{article}
+% \documentclass[a4paper, UTF8, 12pt]{scrbook}
+\documentclass[parskip=half, a4paper, 12pt]{scrartcl}
+
+\usepackage[german]{babel}
+\usepackage[dvipsnames]{xcolor}
+% \usepackage{tikz}
+% \usetikzlibrary{positioning}
+% \usetikzlibrary{calc}
+% \usetikzlibrary{arrows}
+% \usetikzlibrary{intersections}
+% \usepackage{tikz-uml}
+% \usepackage{pgf-umlsd}
+% \usepgflibrary{arrows} % for pgf-umlsd
+% \tikzumlset{fill usecase=white}
+\usepackage[margin=2.5cm]{geometry}
+\usepackage{csquotes}
+\usepackage[T1]{fontenc}
+\usepackage{amsmath}
+\usepackage{pdflscape}
+\usepackage{graphicx}
+\usepackage{caption}
+\usepackage{subcaption}
+\usepackage{float}
+\usepackage{enumitem}
+% \usepackage{textpos}
+\usepackage{hyperref}
+\usepackage{fancyhdr}
+% \usepackage{multicol}
+\usepackage{rest-api}
+\usepackage{wrapfig}
+\usepackage{textcomp}
+\usepackage{ulem}
+\usepackage{fourier}
+\usepackage{array}
+\usepackage{makecell}
+
+
+\hypersetup{
+% ‘texdoc hyperref‘ for options
+ pdftitle={
+ PSE\textsuperscript{2}
+ - Podcast Synchronisation made Efficient Pflichtenheft
+ },
+ bookmarks=true,
+}
+\usepackage{csquotes}
+\usepackage[toc]{glossaries}
+\usepackage{lastpage}
+
+\renewcommand\theadalign{bc}
+\renewcommand\theadfont{\bfseries}
+\renewcommand\theadgape{\Gape[4pt]}
+\renewcommand\cellgape{\Gape[4pt]}
+
+\include{sections/glossar}
+
+\title{Pflichtenheft}
+\author{KIT Students et al}
+\date{2.12.2022}
+
+\pagestyle{fancy}
+\setkomafont{pageheadfoot}{\footnotesize\scshape}
+\fancyhead{} % clear all header fields
+% \fancyhead[L]{Pflichtenheft}
+\fancyhead[L]{PSE\textsuperscript{2} - Podcast Synchronisation made Efficient}
+% \fancyhead[R]{2.12.2022}
+\fancyfoot{} % clear all footer fields
+\fancyfoot[R]{\thepage{} / \pageref{LastPage}}
+\fancyfoot[L]{Praxis der Softwareentwicklung}
+\fancyfoot[C]{}
+
+\begin{document}
+
+\include{titlepage}
+\setcounter{page}{1}
+
+\tableofcontents
+
+\include{sections/einleitung}
+
+\include{sections/methodology}
+
+\include{sections/frontend}
+\newpage
+
+\include{sections/changes}
+
+\include{sections/timeline}
+
+\include{sections/features}
+
+\include{sections/tests}
+
+\printglossaries
+% \glsaddall
+
+\end{document}
diff --git a/20-implementierungsheft/sections/anforderungsanalyse.tex b/20-implementierungsheft/sections/anforderungsanalyse.tex
new file mode 100644
index 0000000..9af8d4d
--- /dev/null
+++ b/20-implementierungsheft/sections/anforderungsanalyse.tex
@@ -0,0 +1,185 @@
+\newcommand{\newrequirementlist}[1]{
+ % https://www.overleaf.com/learn/latex/Lists#Creating_a_new_list_with_enumitem
+ \newlist{#1list}{enumerate}{1}
+ \setlist[#1list, 1]
+ {
+ before=\leavevmode,
+ label=\upshape\textlangle #1\arabic*\textrangle,
+ ref=\upshape\textlangle #1\arabic*\textrangle,
+ resume=#1list
+ }
+}
+
+\newrequirementlist{RM}
+\newrequirementlist{RS}
+\newrequirementlist{RC}
+\newrequirementlist{RW}
+
+\section{Anforderungsanalyse}
+
+\subsection{ Musskriterien }\label{r:musskriterien}
+
+Musskriterien: unabdingbare Leistungen der Software.
+
+\subsubsection*{ Funktionale Anforderungen }
+
+\begin{RMlist}
+ \item\label{r:login} Der Benutzer kann sich im Webfrontend mit einer
+ E-Mail-Adresse und einem Pass\-wort erstmalig registrieren und bei
+ abgeschlossener Registrierung fortan mit denselben Informationen
+ anmelden.
+ Für eine erfolgreiche Registrierung muss die angegebene
+ E-Mail-Adresse zuerst verifiziert werden.\\
+ \item\label{r:store} Die Liste der \Glspl{abo} eines Benutzers sowie
+ der zeitliche Fortschritt beim Anhören(/Ansehen) von jeder begonnen
+ \Gls{episode} werden für jeden Benutzer gespeichert.
+ \item\label{r:sync} Die Liste der \Glspl{abo} eines Benutzers
+ sowie der zeitliche Fortschritt beim Anhören(/Ansehen) von jeder
+ begonnenen \Gls{episode} wird automatisch über alle von einem Benutzer
+ verknüpften \Gls{podcatcher} aktualisiert.
+ Dabei sind der zu synchronisierende Stand der \Glspl{abo} und der
+ zeitliche Fortschritt jeweils definiert als derjenige Stand, der
+ zeitlich am kürzesten zurückliegt.\\
+ \item\label{r:ui} Das Webfrontend bietet dem Benutzer eine graphische
+ Benutzeroberfläche zur Navigation und zur Ansteuerung einzelner
+ Funktionalitäten.\\
+ \item\label{r:reset-pw} Der Benutzer kann sein Passwort ändern und es
+ gibt eine ,,Passwort vergessen''-Funktion.
+ So kann ein angemeldeter Benutzer sein Passwort direkt im Webfrontend
+ ändern.
+ Im nicht angemeldeten Zustand kann der Benutzer sein Passwort über
+ die registrierte E-Mail-Adresse zurücksetzen.\\
+ \item\label{r:show-podcasts} Das Webfrontend bietet dem Benutzer die
+ Möglichkeit, sich die Liste seiner \Glspl{abo} anzeigen zu
+ lassen.
+ Die dabei dargestellten Informationen beinhalten den Namen des
+ \Glspl{abo} und eine gerundete Angabe darüber, wie lange es her ist,
+ dass der Benutzer das letzte Mal eine \Gls{episode} dieses \Glspl{abo}
+ konsumiert hat.\\
+\end{RMlist}
+
+\subsubsection*{ Nicht-funktionale Anforderungen }
+
+\begin{RMlist}
+ \item\label{r:requests} Der Synchronisations-Server kann mindestens
+ 50 Anfragen pro Sekunde verarbeiten.\\
+ \item\label{r:desktop-first} Das Webfrontend ist primär für
+ Desktop-Benutzer ausgelegt.
+ \item\label{r:gpodder} Der Datenaustausch erfolgt über die Gpodder
+ \Gls{rest-api} unter Verwendung des Datenformats \Gls{json}.
+ \item\label{r:persistent-storage} Die Speicherung der Daten eines
+ Benutzers \ref{r:store} über den Synchronisations-Server erfolgt
+ persistent in einer \Gls{db}. Diese Daten des Benutzers sind die
+ Liste seiner \Glspl{abo} und der zeitliche Fortschritt beim Anhören
+ (/Ansehen) aller begonnenen \Glspl{episode}.
+ \item\label{r:api-extension} Die \Gls{gpodder} wird um Funktionalitäten
+ zur verbesserten Kommunikation zwischen Front- und Backend erweitert
+ (siehe \ref{r:login}).\\
+\end{RMlist}
+
+
+\subsection{ Sollkriterien }\label{r:sollkriterien}
+
+Sollkriterien: erstrebenswerte Leistungen.
+
+\subsubsection*{ Funktionale Anforderungen }
+
+\begin{RSlist}
+ \item\label{r:man} Das Webfrontend bietet die Möglichkeit eine nicht
+ ausgefüllte Benutzeranleitung für das Synchronisieren von \Glspl{podcast}
+ anzuzeigen.\\
+ \item\label{r:delete-acc} Der Benutzer kann seinen Account löschen.
+ Daraufhin werden alle auf diesen Benutzer bezogenen Daten gelöscht.\\
+\end{RSlist}
+
+\subsubsection*{ Nicht-funktionale Anforderungen }
+
+\begin{RSlist}
+ \item\label{r:backend-libs} Das Backend wird in \Gls{java} unter Verwendung des
+ quelloffenen Frameworks \Gls{spring} implementiert. Weiter wird für die
+ \Gls{db} das relationale Open-Source Datenbankverwaltungssystem MariaDB
+ eingesetzt.
+ \item\label{r:ui-libs} Die Weboberfläche wird mithilfe der
+ \Gls{ui-lib} React oder des Webframeworks Vue in JavaScript und
+ mit dem Frontend-CSS-Framework Bootstrap entwickelt.
+ \item\label{r:ui-source}
+ Verwendete \Glspl{ui-lib} werden von einem \Gls{packagemanager}, wie dem Node
+ Package Manager (npm) bezogen. Ein \Gls{bundler}, wie vite oder Webpack,
+ stellt ein minimiertes Skript von den Teilen der Bibliotheken zusammen,
+ die vom Code verwendet werden. Das minimierte Skript wird dann auf einem
+ eigenen Server für die Weboberfläche bereitgestellt.
+ \item\label{r:spa} Die Weboberfläche wird als \Gls{spa}
+ entworfen und aktualisiert dynamisch ihren Inhalt, sobald es eine
+ Antwort auf eine Anfrage an die \Gls{gpodder} \ref{r:api-compat} erhält.
+ \item\label{r:parse-metadata} Das Backend kann die Metadaten von
+ \Gls{podcast} aus
+ deren \Gls{rss}-Feeds (XML-Dateien) für die Anzeige im Webfrontend
+ \ref{r:show-podcasts} parsen.
+ \item\label{r:pw-requirements} Verwendete Passwörter müssen mindestens 8 Zeichen,
+ ein Sonderzeichen, eine Zahl sowie einen Klein- und einen Großbuchstaben
+ enthalten.
+ Diese Anforderungen gelten also insbesondere für über die Funktionen
+ \ref{r:login} und \ref{r:reset-pw} neu gewählte Passwörter.\\
+ \item\label{r:save-pw} Passwörter werden sicher mittels \Gls{salt-hash}
+ gespeichert.
+ \item\label{r:session} Im Webfrontend angemeldete Benutzer bleiben dort
+ angemeldet. Hierfür wird eine Kombination aus einem \Gls{session-token} und
+ einem \Gls{cookie} verwendet.\\
+\end{RSlist}
+
+\subsection{ Kannkriterien }
+
+Kannkriterien: Leistungen, die enthalten sein können.
+
+\subsubsection*{ Funktionale Anforderungen }
+
+\begin{RClist}
+ \item\label{r:subscribe} Ein Benutzer kann über die Weboberfläche einen
+ abonnierten \Gls{podcast} über einen generierten Link teilen.
+ Öffnet nun ein anderer Nutzer den Link wird dieser zur Weboberfläche
+ weitergeleitet und mit einem Pop-up gefragt, ob dieser den
+ \Gls{podcast} abonnieren
+ möchte, falls noch nicht geschehen.
+ Akzeptiert der Nutzer, so wird der \Gls{podcast} zur Liste der
+ \Glspl{abo} des
+ Nutzers hinzugefügt.
+ Gegebenenfalls muss sich der Benutzer dafür zuerst anmelden.
+ Der Link setzt sich dabei unter anderem aus der URL des Webfrontends oder
+ einem \Gls{pseudoprotocol} und dem \Gls{podcast}-Link des Providers zusammen.
+ \item\label{r:unsubscribe} Das Webfrontend bietet dem Benutzer die Möglichkeit,
+ \Glspl{abo} zu entfernen beziehungsweise \Glspl{podcast} zu deabonnieren.
+ \item\label{r:import} Das Importieren und Exportieren aller benutzerbezogenen
+ Daten wird unterstützt (siehe \ref{r:dsgvo}).
+ \item\label{r:import-other} Das Umsiedeln von anderen \Gls{gpodder}-Plattformen und
+ damit insbesondere der damit verbundene Datenimport wird unterstützt.
+ \item\label{r:api-compat} Die Weboberfläche ist kompatibel mit beliebigen
+ \Glspl{gpodder}.
+ \item\label{r:responsive} Die Weboberfläche ist \gls{responsive}.
+ \item\label{r:admin} Es gibt Administrator Benutzerkonten. Eine angestrebte
+ Funktionalität dieser privilegierten Konten ist das Einsehen von Statistiken,
+ wie der Anzahl von Benutzern, und dem Abruf der Metadaten eines
+ \Glspl{abo}.
+\end{RClist}
+
+\subsubsection*{ Nicht-funktionale Anforderungen }
+
+\begin{RClist}
+ \item\label{r:login-provider} Die Anmeldung im Webfrontend kann mit dem
+ offenen Protokoll \Gls{oauth} 2.0 über Google, Apple oder Facebook erfolgen.
+ Die bei der Verknüpfung eines \Gls{podcatcher}s mit dem Synchronisationsserver
+ geforderten Anmeldedaten werden dann automatisch für den betreffenden
+ Benutzer generiert.
+ Diese kann er im Webfrontend einsehen.
+ \item\label{r:live-update} Im Webfrontend angemeldete Benutzer bleiben dort
+ angemeldet, wenn das Backend ein Update bekommt.
+ \item\label{r:language} Die Benutzeroberfläche kann in mehreren Sprachen
+ angezeigt werden, wobei neben der standardmäßig deutschen
+ Benutzeroberfläche die zusätzliche Bereitstellung einer englischen
+ Version gegenüber anderen Fremdsprachen priorisiert angestrebt wird.
+ \item\label{r:dsgvo} Der Umgang mit personenbezogenen Daten ist konform mit
+ der \\\Gls{dsgvo} der Europäischen Union.
+ \item\label{r:docker} Die Benutzung von \Gls{docker} vereinfacht das Deployment auf
+ einen Server, da Abhängigkeiten bereits im \Gls{docker}-Image enthalten sind.
+ Außerdem bleibt bei einer Kompromittierung der Software das Host-System
+ durch Virtualisierung der Container sicher.\\
+\end{RClist}
diff --git a/20-implementierungsheft/sections/apidoc.tex b/20-implementierungsheft/sections/apidoc.tex
new file mode 100644
index 0000000..0cce48c
--- /dev/null
+++ b/20-implementierungsheft/sections/apidoc.tex
@@ -0,0 +1,191 @@
+\newenvironment{urlParameter}
+{
+ \newcommand{\urlParamItem}[2]
+ {
+ \rowcolor{\methodLightColor} ##1 & ##2 \\
+ }
+ \newcommand{\noUrlParameter}[1]
+ {
+ \small{\textit{##1}}
+ }
+ %\vspace{-0.61em}
+
+ \arrayrulecolor{\methodColor}
+
+ \begin{tabularx}{\textwidth}{X}
+ \rowcolor{\methodLightColor!20}
+ \textbf{URL-Parameter} \\ \hline
+ \end{tabularx}
+
+ \tabularx{\textwidth}{l X}
+}
+
+\newenvironment{pathParameter}
+{
+ \newcommand{\pathParamItem}[2]
+ {
+ \rowcolor{\methodLightColor} ##1 & ##2 \\
+ }
+ \newcommand{\noPathParameter}[1]
+ {
+ \small{\textit{##1}}
+ }
+ %\vspace{-0.61em}
+
+ \arrayrulecolor{\methodColor}
+
+ \begin{tabularx}{\textwidth}{X}
+ \rowcolor{\methodLightColor!20}
+ \textbf{Pfad-Parameter} \\ \hline
+ \end{tabularx}
+
+ \tabularx{\textwidth}{l X}
+}
+
+\newenvironment{jsonKeys}
+{
+ \newcommand{\jsonKeyItem}[2]
+ {
+ \rowcolor{\methodLightColor} ##1 & ##2 \\
+ }
+ \newcommand{\nojsonKeys}[1]
+ {
+ \small{\textit{##1}}
+ }
+ %\vspace{-0.61em}
+
+ \arrayrulecolor{\methodColor}
+
+ \begin{tabularx}{\textwidth}{X}
+ \rowcolor{\methodLightColor!20}
+ \textbf{Json-Keys} \\ \hline
+ \end{tabularx}
+
+ \tabularx{\textwidth}{l X}
+}
+
+\section{\Gls{api}}
+
+\subsection{Authentication API}\label{a:auth}
+
+\subsubsection{Registrierung}\label{a:register}
+
+\begin{apiRoute}{post}{/api/2/auth/register.json}
+ {Registriert einen Nutzer mit einer E-Mail-Adresse und Passwort.
+
+ Versendet E-Mail mit Bestätigungslink an die angegebene E-Mail-Adresse.}
+ \begin{routeRequest}{application/json}
+ \begin{routeRequestBody}
+{
+ username: "jeff"
+ email: "jeff@example.com",
+ password: "MyNameIsJeff"
+}
+ \end{routeRequestBody}
+ \end{routeRequest}
+ \begin{routeResponse}{application/json}
+ \begin{routeResponseItem}{200}
+ {OK: Nutzer wurde erfolgreich angelegt und E-Mail versendet.}
+ \end{routeResponseItem}
+
+ \begin{routeResponseItem}{400}
+ {Bad Request: Fehler beim Parsen oder Eingabe nicht anforderungsgemäß.}
+ \end{routeResponseItem}
+ \end{routeResponse}
+\end{apiRoute}
+
+Es wird nun sowohl ein Benutzername als auch eine E-Mail-Adresse für einen Nutzer gespeichert.
+Der Benutzername wird in der Folge für die Authentifizierung und die Zuordnung der Anfragen verwendet.
+Die E-Mail-Adresse wird vor dem Speichern mit einem festen Geheimschlüssel gesalted und gehashed.
+Sie ist zum Ableich der bei der bei (ref an forgot) anzugebenden E-Mail-Adresse
+
+\newpage
+\subsubsection{E-Mail verifizieren}\label{a:resetpassword}
+
+\begin{apiRoute}{get}{/api/2/auth/\{username\}/verify.json}
+ {Verifiziere die bei der Registrierung angegebene E-Mail-Adresse durch diese, per E-Mail versendete, URL.}
+ \begin{pathParameter}
+ \pathParamItem{username}{Nutzername des betreffenden Nutzers}
+ \end{pathParameter}
+ \begin{urlParameter}
+ \urlParamItem{token}{JSON-Web-Token (24h gültig)}
+ \end{urlParameter}
+ \begin{routeResponse}{application/json}
+ \begin{routeResponseItem}{200}
+ {OK: Der Benutzer wurde erfolgreich aktiviert und kann sich nun anmelden.}
+ \end{routeResponseItem}
+
+ \begin{routeResponseItem}{400}
+ {Bad Request: Der Nutzer mit dem angegebenen Namen ist bereits verifiziert. }
+ \end{routeResponseItem}
+
+ \begin{routeResponseItem}{401}
+ {Unauthorized: Der JWT ist ungültig. }
+ \end{routeResponseItem}
+
+ \begin{routeResponseItem}{404}
+ {Not Found: Es exisitiert kein Nutzer mit dem angegebenen Benutzernamen. }
+ \end{routeResponseItem}
+ \end{routeResponse}
+\end{apiRoute}
+
+Dieser Endpunkt wurde zur Verifizierung der bei der Registrierung angegebenen E-Mail-Adresse hinzugefügt.
+Nach der Registrierung wird dem Benutzer eine E-Mail mit der URL dieses Endpunkts (inklusive Benutzernamen und JWT)
+zugesendet. Klickt der Benutzer auf den Link wird die Anfrage im Backend verarbeitet und der Nutzer automatisch
+zum Webfrontend weitergeleitet. Erst nach der Verifizierung der E-Mail-Adresse ist die Registrierung vollständig
+abgeschlossen und der Account aktiviert - nun kann sich der Nutzer anmelden.
+
+\newpage
+\subsubsection{Passwort vergessen}\label{a:forgot}
+
+\begin{apiRoute}{post}{/api/2/auth/\{email\}/forgot.json}
+ {Sende eine E-Mail zum Zurücksetzen des Passworts.}
+ \begin{pathParameter}
+ \pathParamItem{email}{E-Mail-Adresse des betreffenden Nutzers}
+ \end{pathParameter}
+ \begin{routeResponse}{application/json}
+ \begin{routeResponseItem}{200}
+ {OK: E-Mail wurde erfolgreich versendet.}
+ \end{routeResponseItem}
+
+ \begin{routeResponseItem}{404}
+ {Not Found: Es exisitiert kein Nutzer mit der angegeben E-Mail-Adresse.}
+ \end{routeResponseItem}
+ \end{routeResponse}
+\end{apiRoute}
+
+Die E-Mail-Adresse des Benutzers, der sein Passwort vergessen hat, wird nicht mehr im Request-Body
+als \GLS{json}-Payload, sondern als Pfadvariable in der URL übergeben.
+
+\subsubsection{Passwort zurücksetzen}\label{a:resetpassword}
+
+\begin{apiRoute}{put}{/api/2/auth/\{username\}/resetpassword.json}
+ {Passwort des gegebenen Nutzers ändern nachdem dieser sein Passwort
+ vergessen hat. }
+ \begin{pathParameter}
+ \pathParamItem{username}{Nutzername des betreffenden Nutzers}
+ \end{pathParameter}
+ \begin{urlParameter}
+ \urlParamItem{token}{JSON-Web-Token}
+ \end{urlParameter}
+ \begin{routeRequest}{application/json}
+ \begin{routeRequestBody}
+{
+ password: "APasswordIWontForgetAgain"
+}
+ \end{routeRequestBody}
+ \end{routeRequest}
+ \begin{routeResponse}{application/json}
+ \begin{routeResponseItem}{200}
+ {OK: Das Passwort wurde erfolgreich geändert.}
+ \end{routeResponseItem}
+
+ \begin{routeResponseItem}{400}
+ {Bad Request: Fehler beim Parsen der Anfragen. }
+ \end{routeResponseItem}
+
+ \begin{routeResponseItem}{401}
+ {Unauthorized: JWT ist ungültig. }
+ \end{routeResponseItem}
+ \end{routeResponse}
+\end{apiRoute} \ No newline at end of file
diff --git a/20-implementierungsheft/sections/aufbau.tex b/20-implementierungsheft/sections/aufbau.tex
new file mode 100644
index 0000000..41a5839
--- /dev/null
+++ b/20-implementierungsheft/sections/aufbau.tex
@@ -0,0 +1,47 @@
+\section{Aufbau}
+
+\begin{landscape}
+
+\subsection{Klassendiagramm Backend}
+Das Klassendiagramm zeigt alle für den Entwurf relevanten Klassen des Backends mit ihren öffentlichen Methoden.
+Weiter zeigt das Diagramm die Aufteilung der Klassen in Pakete sowie schemenhaft dargestellte Verbindungen zu \Gls{db} und Webserver.
+
+% \input{assets/diagrams/classdiagram.latex}
+\includegraphics[width=\linewidth]{assets/diagrams/classdiagram}
+\end{landscape}
+
+\subsection{Sequenzdiagramme}
+
+\subsubsection{Authentication \Gls{api}}
+\subsubsection*{Registrierung \scriptsize{(\ref{a:register})}}
+\includegraphics[width=\textwidth]{assets/diagrams/sequencediagram-register}
+\subsubsection*{Passwort vergessen und zurücksetzen \scriptsize{(\ref{a:forgot}, \ref{a:resetpassword})}}
+\includegraphics[width=\textwidth]{assets/diagrams/sequencediagram-forgotAndResetPW}
+
+\subsubsection{Subscriptions \Gls{api}}
+\subsubsection*{Abonnements hochladen \scriptsize{(\ref{a:uploadSubs})}}
+\includegraphics[width=\textwidth]{assets/diagrams/sequencediagram-uploadSubscriptions}
+
+\subsubsection*{Abrufen aller Abonnements \scriptsize{(\ref{a:getSubs})}}
+\includegraphics[width=\textwidth]{assets/diagrams/sequencediagram-getSubscriptions}
+
+\subsubsection{Episode Actions \Gls{api}}
+\subsubsection*{Episode Actions hochladen \scriptsize{(\ref{a:uploadEpisodeActions})}}
+\includegraphics[width=\textwidth]{assets/diagrams/sequencediagram-uploadEpisodeActions}
+
+\subsubsection*{Abrufen aller Episode Actions seit einem Zeitpunkt \scriptsize{(\ref{a:getEpisodeActions})}}
+\includegraphics[width=\textwidth]{assets/diagrams/sequencediagram-getEpisodeActionsOfPodcastSince}
+
+\subsubsection*{Abrufen aller Episode Actions \scriptsize{(\ref{a:getEpisodeActions})}}
+\includegraphics[width=\textwidth]{assets/diagrams/sequencediagram-getEpisodeActions}
+
+\subsection{Komponentendiagramm Backend}
+\includegraphics[width=\textwidth]{assets/diagrams/backendComponentDiagram}
+
+\subsection{Verteilungsdiagram}
+\includegraphics[width=\textwidth]{assets/diagrams/deployment}
+
+\subsection{\Gls{db}-Modell}
+
+\includegraphics[width=\textwidth]{assets/diagrams/db}
+
diff --git a/20-implementierungsheft/sections/backend.tex b/20-implementierungsheft/sections/backend.tex
new file mode 100644
index 0000000..19efd65
--- /dev/null
+++ b/20-implementierungsheft/sections/backend.tex
@@ -0,0 +1,28 @@
+\section{Backend}
+
+Für das Backend wird das \Gls{java}-Framework \Gls{spring} verwendet. Neben seiner Modularität,
+bietet es viele Funktionen, die unter
+anderem die Entwicklung von Backend-Anwendungen vereinfachen.
+Darunter fällt zum Beispiel die Unterstützung von Dependency Injection, dessen
+Vorteile bereits beschrieben wurden.
+Außerdem unterstützt \Gls{java} \Gls{spring} intern eine Verwaltung von \Glspl{db}, sodass
+sich nicht mit dem \Gls{SQL}-Code an sich befasst werden muss.
+Auch bezüglich Authentifizierung und Sicherheit bietet \Gls{spring} eigene Funktionalitäten.
+
+Zusätzlich dazu wird als Build-System für das \Gls{java}-\Gls{spring}-Backend Maven verwendet.
+Maven hilft dabei alle Abhängigkeiten des Projekts zu verwalten und automatisiert
+den Build Prozess.
+Durch die zusätzliche Unterstützung von Versionskontrollsystemen und der Kompatibilität
+zu vielen Continuous Integration-Tools wird außerdem die Entwicklung in einem Team erleichtert
+und optimiert. Denn dadurch können Build- und Deployment-Prozesse automatisiert werden.
+Außerdem bietet Maven Bibliotheken zum Testen sowie zur Generierung von Dokumentationen an.
+
+Vom Backend benötigte Abhängigkeiten:
+\begin{itemize}
+ \item \Gls{spring} Web
+ \item \Gls{spring} Security
+ \item \Gls{spring} Mail Sender
+ \item \Gls{spring} Data JPA
+ \item Lombok
+ \item Rome (\Gls{rss} parsing/fetching)
+\end{itemize} \ No newline at end of file
diff --git a/20-implementierungsheft/sections/changes.tex b/20-implementierungsheft/sections/changes.tex
new file mode 100644
index 0000000..20df017
--- /dev/null
+++ b/20-implementierungsheft/sections/changes.tex
@@ -0,0 +1,241 @@
+\newenvironment{urlParameter}
+{
+ \newcommand{\urlParamItem}[2]
+ {
+ \rowcolor{\methodLightColor} ##1 & ##2 \\
+ }
+ \newcommand{\noUrlParameter}[1]
+ {
+ \small{\textit{##1}}
+ }
+ %\vspace{-0.61em}
+
+ \arrayrulecolor{\methodColor}
+
+ \begin{tabularx}{\textwidth}{X}
+ \rowcolor{\methodLightColor!20}
+ \textbf{URL-Parameter} \\ \hline
+ \end{tabularx}
+
+ \tabularx{\textwidth}{l X}
+}
+
+\newenvironment{pathParameter}
+{
+ \newcommand{\pathParamItem}[2]
+ {
+ \rowcolor{\methodLightColor} ##1 & ##2 \\
+ }
+ \newcommand{\noPathParameter}[1]
+ {
+ \small{\textit{##1}}
+ }
+ %\vspace{-0.61em}
+
+ \arrayrulecolor{\methodColor}
+
+ \begin{tabularx}{\textwidth}{X}
+ \rowcolor{\methodLightColor!20}
+ \textbf{Pfad-Parameter} \\ \hline
+ \end{tabularx}
+
+ \tabularx{\textwidth}{l X}
+}
+
+\newenvironment{jsonKeys}
+{
+ \newcommand{\jsonKeyItem}[2]
+ {
+ \rowcolor{\methodLightColor} ##1 & ##2 \\
+ }
+ \newcommand{\nojsonKeys}[1]
+ {
+ \small{\textit{##1}}
+ }
+ %\vspace{-0.61em}
+
+ \arrayrulecolor{\methodColor}
+
+ \begin{tabularx}{\textwidth}{X}
+ \rowcolor{\methodLightColor!20}
+ \textbf{Json-Keys} \\ \hline
+ \end{tabularx}
+
+ \tabularx{\textwidth}{l X}
+}
+
+
+\section{Änderungen zum Entwurfsheft}
+
+Im Folgenden werden die Änderungen zum Entwurfsheft aufgelistet und erläutert warum diese
+Änderungen gemacht wurden.
+
+
+\subsection{Kompatibilität mit \Glspl{podcatcher}}
+
+Um die Kompatibilität mit \Glspl{podcatcher} - insbesondere AntennaPod und Kasts - sicherzustellen, mussten einige Änderungen vorgenommen werden.
+
+\subsubsection*{Speicherung von Benutzernamen und E-Mail-Adressen}
+
+AntennaPod erlaubt bei der Verknüpfung mit einem Synchronisations-Server nur die Anmeldung mit einem Benutzername, der keine E-Mail-Adresse ist.
+Deshalb werden nun sowohl ein Benutzername als auch eine E-Mail-Adresse für jeden Nutzer gespeichert.
+Der Benutzername wird dabei unverschlüsselt gespeichert.
+Er wird zur Authentifizierung sowie für die Zuordnung der Anfragen verwendet.
+Die E-Mail-Adresse hingegen, wird vor der Speicherung mit einem festen Geheimschlüssel gesalted und anschließend gehashed.
+Sie existiert lediglich um bei einer Passwort-vergessen-Anfrage denjenigen Nutzer zu finden, zu dem die übergebene E-Mail-Adresse gehört, beziehungsweise dessen Existenz zu überprüfen.
+Diese Änderung impliziert eine Anpassung des Formats, in dem Registrierungsanfragen als \GLS{json}-Payload übergeben werden.
+Wie in der folgenden aktualisierten Spezifikation zu sehen existiert nun ein zusätzliches \GLS{json}-Attribut namens \enquote{username}.
+\newline
+
+\begin{apiRoute}{post}{/api/2/auth/register.json}
+ {Registriert einen Nutzer mit einer E-Mail-Adresse und Passwort.
+
+ Versendet E-Mail mit Bestätigungslink an die angegebene E-Mail-Adresse.}
+ \begin{routeRequest}{application/json}
+ \begin{routeRequestBody}
+{
+ "username": "jeff",
+ "email": "jeff@example.com",
+ "password": "MyNameIsJeff"
+}
+ \end{routeRequestBody}
+ \end{routeRequest}
+ \begin{routeResponse}{application/json}
+ \begin{routeResponseItem}{200}
+ {OK: Nutzer wurde erfolgreich angelegt und E-Mail versendet.}
+ \end{routeResponseItem}
+
+ \begin{routeResponseItem}{400}
+ {Bad Request: Fehler beim Parsen oder Eingabe nicht anforderungsgemäß.}
+ \end{routeResponseItem}
+ \end{routeResponse}
+\end{apiRoute}
+
+\subsubsection*{Device API}
+
+Beim Einrichten eines Synchronisations-Servers rufen sowohl AntennaPod als auch Kasts statt einem anfänglichen Login sofort den List-Devices-Endpunkt der \gls{gpodder}.net API auf.
+Dieser Endpunkt wurde entsprechend hinzugefügt.
+Da jedoch explizit keine Unterscheidung von Geräten bei der Synchronisation unterstützt wird, wird dieser intern wie ein Login-Aufruf behandelt.
+\newline
+
+\begin{apiRoute}{get}{/api/2/devices/\{username\}.json}
+ {Gegebenen Nutzer des gegebenen Geräts mithilfe HTTP Basic Auth einloggen oder Gültigkeit des im \enquote{sessionid} \Gls{cookie} gespeicherten JWTs bestätigen.
+
+ Gibt außerdem eine Liste mit einem Dummy-Device zurück, damit die Einrichtung der Synchronisation mit AntennaPod und Kasts möglich ist.}
+ \begin{pathParameter}
+ \pathParamItem{username}{Nutzername des einzuloggenden Nutzers}
+ \end{pathParameter}
+ \begin{routeResponse}{application/json}
+ \begin{routeResponseItem}{200}
+ {OK: Der Benutzer wurde erfolgreich mittles HTTP Basic Auth oder JWT eingeloggt und das \enquote{sessionid} Cookie wurde auf ein gültiges JWT gesetzt.}
+ \newline
+ \begin{routeResponseItemBody}
+[
+ {
+ "id": "dummy",
+ "caption": "device",
+ "type": "other",
+ "subscriptions": 0
+ }
+]
+ \end{routeResponseItemBody}
+ \end{routeResponseItem}
+
+ \begin{routeResponseItem}{401}
+ {Unauthorized: Es liegen falsche Anmeldedaten oder ein ungültiges JWT vor.}
+ \end{routeResponseItem}
+ \end{routeResponse}
+ \begin{jsonKeys}
+ \jsonKeyItem{id}{Geräte-ID}
+ \jsonKeyItem{caption}{Ein für Menschen lesbarer Name für das Gerät}
+ \jsonKeyItem{type}{Typ des Geräts - mögliche Typen: desktop, laptop, mobile, server, other}
+ \jsonKeyItem{subscriptions}{Anzahl der Subscriptions auf dem Gerät}
+ \end{jsonKeys}
+\end{apiRoute}
+
+\newpage
+\subsection{Verifizierung der E-Mail-Adresse}
+
+Dieser Endpunkt wurde zur Verifizierung der bei der Registrierung angegebenen E-Mail-Adresse hinzugefügt.
+Nach der Registrierung wird dem Benutzer eine E-Mail mit der URL dieses Endpunkts (inklusive Benutzernamen und JWT)
+zugesendet. Klickt der Benutzer auf den Link wird die Anfrage im Backend verarbeitet und der Nutzer automatisch
+zum Webfrontend weitergeleitet. Erst nach der Verifizierung der E-Mail-Adresse ist die Registrierung vollständig
+abgeschlossen und der Account aktiviert - nun kann sich der Nutzer anmelden.
+\newline
+
+\begin{apiRoute}{get}{/api/2/auth/\{username\}/verify.json}
+ {Verifiziere die bei der Registrierung angegebene E-Mail-Adresse durch diese, per E-Mail versendete, URL.}
+ \begin{pathParameter}
+ \pathParamItem{username}{Nutzername des betreffenden Nutzers}
+ \end{pathParameter}
+ \begin{urlParameter}
+ \urlParamItem{token}{JSON-Web-Token (24h gültig)}
+ \end{urlParameter}
+ \begin{routeResponse}{application/json}
+ \begin{routeResponseItem}{200}
+ {OK: Der Benutzer wurde erfolgreich aktiviert und kann sich nun anmelden.}
+ \end{routeResponseItem}
+
+ \begin{routeResponseItem}{400}
+ {Bad Request: Der Nutzer mit dem angegebenen Namen ist bereits verifiziert. }
+ \end{routeResponseItem}
+
+ \begin{routeResponseItem}{401}
+ {Unauthorized: Der JWT ist ungültig. }
+ \end{routeResponseItem}
+
+ \begin{routeResponseItem}{404}
+ {Not Found: Es exisitiert kein Nutzer mit dem angegebenen Benutzernamen. }
+ \end{routeResponseItem}
+ \end{routeResponse}
+\end{apiRoute}
+
+
+\newpage
+\subsection{RSSParser}
+
+Das primäre Ziel beim Entwurf des RSSParsers war es den Rest der Anwendung nicht
+aufzuhalten, da das fetchen und parsen länger dauert. Daher soll der RSSParser asynchron
+ausgeführt werden.
+Damit das für die Implementierung verwendete Framework \Gls{spring} dies unterstützt müssen
+mehr Bedingungen erfüllt sein als im Entwurf berücksichtigt wurden, weshalb dieser abgeändert werden musste.
+
+Unter anderem können nur Komponenten die von \Gls{spring} verwaltet werden asynchron ausgeführt werden.
+Weiter können nur öffentliche Methoden von \Gls{spring} als asynchron erkannt werden und bei
+dem Aufruf einer asynchronen Methode muss die Klasse gewechselt werden damit diese asynchron
+ausgeführt wird.
+
+Um diese Bedingungen zu erfüllen ruft der SubscriptionService oder der EpisodeActionService
+die Validate Methode des RSSParsers mit der Subscription die überprüft werden
+soll auf. Dies geschieht asynchron nach dem \enquote{Fire and Forget} Prinzip. Daher können
+die Services unmittelbar weiter arbeiten und dem Nutzer so möglichst schnell eine Antwort
+liefern.
+
+Die Validate Methode fragt den aktuellen \GLS{rss}-Feed der Subscription ab und parsed diesen.
+Erfüllt der Feed die von Apple und Google für \Glspl{podcast} definierten Anforderungen
+werden die Informationen aus dem Feed gespeichert. Dabei werden nur die \Glspl{episode} gespeichert,
+die von mindestens einem Nutzer gehört wurden. Ist der Feed der Subscription nicht
+valide wird die Subscription gelöscht. Um das Löschen und Speichern ausführen zu können
+hält der Parser Referenzen auf das SubscriptionDao und EpisodeDao.
+
+Die im Entwurfsheft definierten Getter werden nicht mehr oder nur
+noch als private Hilfsmethoden benötigt.
+
+\subsection{Reduzierte Datenzugriffsschicht}
+
+Mithilfe von JPA Repositories können Datenbankzugriffe und Abfragen ohne weitere Logik in den DAO-Schnittstellen einfach implementiert werden.
+Wird beispielsweise nach einem \Gls{abo} anhand einer URL gesucht, so wird eine Methode der Form \textit{Optional<Subscription> findByUrl(String url)} in der SubscriptionDao deklariert.
+Um die Implementierung dieser Abfrage kümmert sich JPA.
+
+Damit fallen alle ursprünglich geplanten DAO-Implementierungen weg, was für eine bessere Übersicht in der Datenzugriffsschicht sorgt.
+\newpage
+
+\begin{landscape}
+
+\subsection{Überarbeitetes Klassendiagramm des Backends}
+Das Klassendiagramm zeigt alle den überarbeiteten Entwurf des Backends.
+Weiter zeigt das Diagramm die Aufteilung der Klassen in Pakete sowie schemenhaft dargestellte Verbindungen zu \Gls{db} und Webserver.
+
+% \input{assets/diagrams/classdiagram.latex}
+\includegraphics[width=\linewidth]{assets/diagrams/class_after}
+\end{landscape} \ No newline at end of file
diff --git a/20-implementierungsheft/sections/einleitung.tex b/20-implementierungsheft/sections/einleitung.tex
new file mode 100644
index 0000000..5f6080d
--- /dev/null
+++ b/20-implementierungsheft/sections/einleitung.tex
@@ -0,0 +1,11 @@
+\section{Einleitung}
+
+Im vorangegangenen Pflichtenheft und Entwurfsheft wurde zuerst abstrahiert
+die Idee des Podcast Synchronisationsservers beschrieben und die Ziele in Form von
+Anforderungen definiert. Dabei soll sowohl ein Backend mit \Gls{db} als auch ein Frontend
+zur Dateneinsicht und Verwaltung entstehen. Dann wurde die Implementierung diese Projekts
+mittels eines Entwurfs geplant.
+
+In diesem Dokument wird die Implementierung des entworfenen Produkts dokumentiert.
+Dabei wird auf Probleme und Änderungen gegenüber dem Pflichtenheft und Entwurfsheft eingegangen,
+die Testfälle erläutert und der geplante und tatsächliche zeitliche Ablauf der Implementierung dokumentiert. \ No newline at end of file
diff --git a/20-implementierungsheft/sections/features.tex b/20-implementierungsheft/sections/features.tex
new file mode 100644
index 0000000..0ccf47e
--- /dev/null
+++ b/20-implementierungsheft/sections/features.tex
@@ -0,0 +1,43 @@
+\section{Implementierte Muss-, Soll- und Kannkriterien}
+
+Nachdem nun die vorgenommenen Änderungen des Entwurfs behandelt wurden, geht es nun zu der eigentlichen Frage:
+Was wurde umgesetzt?
+
+In der folgenden Tabelle werden alle im Pflichtenheft vorgestellten und im Entwurfsheft überarbeiteten Kriterien mit der Kriterienbezeichnung, einer kleinen Zusammenfassung und einer Info, ob die Kriterien implementiert wurden, aufgelistet.
+
+\begin{tabular}{l|c|c}
+ Bezeichner & Zusammenfassung & Implementiert\\\hline
+ RM1 & \makecell{Registrierung, Bestätigung und Anmeldung\\ eines Accounts über das Frontend} & Ja\\
+ RM2 & Speichern von \Glspl{abo} und \Glspl{episode} auf dem Server & Ja\\
+ RM3 & Synchronisierung zwischen \Glspl{podcatcher} & Ja\\
+ RM4 & Eine Weboberfläche & Ja\\
+ RM5 & Möglichkeit das eigene Passwort zu ändern / zurückzusetzen & Ja\\
+ RM6 & \Gls{abo}liste in der Weboberfläche & Ja\\
+ RM7 & 50 Anfragen / Sekunde bearbeiten & Zu testen\\
+ RM8 & Primäre Auslegung des Webfrontends für Desktop-Nutzer & Ja\\
+ RM9 & Unterstützung der \gls{gpodder}.net \Gls{rest-api} & Ja\\
+ RM10 & Das Nutzen einer \Gls{db} zur Speicherung von Daten & Ja\\
+ RM11 & Erweiterte \GLS{api} für Kommunikation zwischen Front- und Backend & Ja\\\hline
+ RS1 & Eine Anleitung (Platzhalter) & Ja\\
+ RS2 & Die Möglichkeit einen Account zu löschen & Ja\\
+ RS3 & \Gls{spring} für das Backend und MariaDB als \Gls{db} & Ja\\
+ RS4 & Vue.js und Bootstrap für das Frontend & Ja\\
+ RS5 & npm und vite für das Frontend & Ja\\
+ RS6 & \makecell{Eine \Gls{spa} als Frontend\\mit dynamischer Aktualisierung} & Ja\\
+ RS7 & Ein \GLS{rss}-Parser um Daten aus einem \GLS{rss}-Feed zu lesen & Ja\\
+ RS8 & Mindestanforderungen an ein Passwort & Ja\\
+ RS9 & \Gls{salt-hash} für Verschlüsselung der Personenbezogenen Daten & Ja\\
+ RS10 & Nutzer bleibt über JWT angemeldet und authentifiziert & Ja\\\hline
+ RC1 & Abonnierten \Gls{podcast} in Weboberfläche über Link teilen und hinzufügen & Ja\\
+ RC2 & \Glspl{abo} in Weboberfläche deabonnieren & Nein\\
+ RC3 & Importieren und Exportieren aller benutzerbezogenen Daten & Ja\\
+ RC4 & Umsiedeln von anderen \Gls{gpodder}-Plattformen & Ja\\
+ RC5 & Kompatible Weboberfläche für beliebige \gls{gpodder}.net APIs & Entfernt\\
+ RC6 & \Gls{responsive} designte Weboberfläche & Ja\\
+ RC7 & Administratorkonten mit privilegierten Funktionen & Nein\\
+ RC8 & \Gls{oauth} 2.0 im Webfrontend & Nein\\
+ RC9 & Bei Ausfall des Backends im Frontend angemeldet bleiben & Ja\\
+ RC10 & Mehrsprachige Weboberfläche & Ja\\
+ RC11 & Erfüllung der DSGVO & Teils\\
+ RC12 & \Gls{docker} für einfaches Deployment und Sicherheit & Ja
+\end{tabular} \ No newline at end of file
diff --git a/20-implementierungsheft/sections/features.tex.orig b/20-implementierungsheft/sections/features.tex.orig
new file mode 100644
index 0000000..78839cf
--- /dev/null
+++ b/20-implementierungsheft/sections/features.tex.orig
@@ -0,0 +1,82 @@
+\section{Implementierte Muss-, Soll- und Kannkriterien}
+
+Nachdem nun die vorgenommenen Änderungen des Entwurfs behandelt wurden, geht es nun zu der eigentlichen Frage:
+Was wurde umgesetzt?
+
+In der folgenden Tabelle werden alle im Pflichtenheft vorgestellten und im Entwurfsheft überarbeiteten Kriterien mit der Kriterienbezeichnung, einer kleinen Zusammenfassung und einer Info, ob die Kriterien implementiert wurden, aufgelistet.
+
+\hspace{-1cm}
+\begin{tabular}{l|c|c}
+<<<<<<< HEAD
+ Bezeichner & Zusammenfassung & Implementiert\\\hline
+ \textlangle RM1 \textrangle & \makecell{Registrierung, Bestätigung und Anmeldung\\ eines Accounts über das Frontend} & Ja\\
+ \textlangle RM2 \textrangle & Speichern von Abonnements und Episoden auf dem Server & Ja\\
+ \textlangle RM3 \textrangle & Synchronisierung zwischen Podcatchern & Ja\\
+ \textlangle RM4 \textrangle & Eine Weboberfläche & Ja\\
+ \textlangle RM5 \textrangle & Möglichkeit das eigene Passwort zu ändern / zurückzusetzen & Ja\\
+ \textlangle RM6 \textrangle & Abonnementliste in der Weboberfläche & Ja\\
+ \textlangle RM7 \textrangle & 50 Anfragen / Sekunde bearbeiten & Zu testen\\
+ \textlangle RM8 \textrangle & Primäre Auslegung des Webfrontends für Desktop-Nutzer & Ja\\
+ \textlangle RM9 \textrangle & Unterstützung der gpodder.net RESTful-API & Ja\\
+ \textlangle RM10\textrangle & Das Nutzen einer Datenbank zur Speicherung von Daten & Ja\\
+ \textlangle RM11\textrangle & Erweiterte API für Kommunikation zwischen Front- und Backend & Ja\\\hline\hline
+ \textlangle RS1 \textrangle & Eine Anleitung (Platzhalter) & Ja\\
+ \textlangle RS2 \textrangle & Die Möglichkeit einen Account zu löschen & Ja\\
+ \textlangle RS3 \textrangle & Spring für das Backend und MariaDB als Datenbank & Ja\\
+ \textlangle RS4 \textrangle & Vue.js und Bootstrap für das Frontend & Ja\\
+ \textlangle RS5 \textrangle & npm und vite für das Frontend & Ja\\
+ \textlangle RS6 \textrangle & \makecell{Eine Single-Page-Application als Frontend\\mit dynamischer Aktualisierung} & Ja\\
+ \textlangle RS7 \textrangle & Ein RSS-Parser um Daten aus einem RSS-Feed zu lesen & Ja\\
+ \textlangle RS8 \textrangle & Mindestanforderungen an ein Passwort & Ja\\
+ \textlangle RS9 \textrangle & Salting und Hashing für Verschlüsselung der Personenbezogenen Daten & Ja\\
+ \textlangle RS10\textrangle & Nutzer bleibt über JWT angemeldet und authentifiziert & Ja\\\hline\hline
+ \textlangle RC1 \textrangle & Abonnierten Podcast in Weboberfläche über Link teilen und hinzufügen & Ja\\
+ \textlangle RC2 \textrangle & Abonnements in Weboberfläche deabonnieren & Nein\\
+ \textlangle RC3 \textrangle & Importieren und Exportieren aller benutzerbezogenen Daten & Ja\\
+ \textlangle RC4 \textrangle & Umsiedeln von anderen Gpodder-Plattformen & Ja\\
+ \textlangle RC5 \textrangle & Kompatible Weboberfläche für beliebige gpodder.net APIs & Entfernt\\
+ \textlangle RC6 \textrangle & Responsive designte Weboberfläche & Ja\\
+ \textlangle RC7 \textrangle & Administratorkonten mit privilegierten Funktionen & Nein\\
+ \textlangle RC8 \textrangle & OAuth 2.0 im Webfrontend & Nein\\
+ \textlangle RC9 \textrangle & Bei Ausfall des Backends im Frontend angemeldet bleiben & Ja\\
+ \textlangle RC10\textrangle & Mehrsprachige Weboberfläche & Ja\\
+ \textlangle RC11\textrangle & Erfüllung der DSGVO & Teils\\
+ \textlangle RC12\textrangle & Docker für einfaches Deployment und Sicherheit & Ja
+\end{tabular}
+=======
+ Bezeichner & Zusammenfassung & Implementiert\\\hline
+ RM1 & \makecell{Registrierung, Bestätigung und Anmeldung\\ eines Accounts über das Frontend} & Ja\\
+ RM2 & Speichern von \Glspl{abo} und \Glspl{episode} auf dem Server & Ja\\
+ RM3 & Synchronisierung zwischen \Glspl{podcatcher} & Ja\\
+ RM4 & Eine Weboberfläche & Ja\\
+ RM5 & Möglichkeit das eigene Passwort zu ändern / zurückzusetzen & Ja\\
+ RM6 & \Gls{abo}liste in der Weboberfläche & Ja\\
+ RM7 & 50 Anfragen / Sekunde bearbeiten & Zu testen\\
+ RM8 & Primäre Auslegung des Webfrontends für Desktop-Nutzer & Ja\\
+ RM9 & Unterstützung der \gls{gpodder}.net \Gls{rest-api} & Ja\\
+ RM10 & Das Nutzen einer \Gls{db} zur Speicherung von Daten & Ja\\
+ RM11 & Erweiterte \GLS{api} für Kommunikation zwischen Front- und Backend & Ja\\\hline
+ RS1 & Eine Anleitung (Platzhalter) & Ja\\
+ RS2 & Die Möglichkeit einen Account zu löschen & Ja\\
+ RS3 & \Gls{spring} für das Backend und MariaDB als \Gls{db} & Ja\\
+ RS4 & Vue.js und Bootstrap für das Frontend & Ja\\
+ RS5 & npm und vite für das Frontend & Ja\\
+ RS6 & \makecell{Eine \Gls{spa} als Frontend\\mit dynamischer Aktualisierung} & Ja\\
+ RS7 & Ein \GLS{rss}-Parser um Daten aus einem \GLS{rss}-Feed zu lesen & Ja\\
+ RS8 & Mindestanforderungen an ein Passwort & Ja\\
+ RS9 & \Gls{salt-hash} für Verschlüsselung der Personenbezogenen Daten & Ja\\
+ RS10 & Nutzer bleibt über JWT angemeldet und authentifiziert & Ja\\\hline
+ RC1 & Abonnierten \Gls{podcast} in Weboberfläche über Link teilen und hinzufügen & Ja\\
+ RC2 & \Glspl{abo} in Weboberfläche deabonnieren & Nein\\
+ RC3 & Importieren und Exportieren aller benutzerbezogenen Daten & Ja\\
+ RC4 & Umsiedeln von anderen \Gls{gpodder}-Plattformen & Ja\\
+ RC5 & Kompatible Weboberfläche für beliebige \gls{gpodder}.net APIs & Entfernt\\
+ RC6 & \Gls{responsive} designte Weboberfläche & Ja\\
+ RC7 & Administratorkonten mit privilegierten Funktionen & Nein\\
+ RC8 & \Gls{oauth} 2.0 im Webfrontend & Nein\\
+ RC9 & Bei Ausfall des Backends im Frontend angemeldet bleiben & Ja\\
+ RC10 & Mehrsprachige Weboberfläche & Ja\\
+ RC11 & Erfüllung der DSGVO & Teils\\
+ RC12 & \Gls{docker} für einfaches Deployment und Sicherheit & Ja
+\end{tabular}
+>>>>>>> main
diff --git a/20-implementierungsheft/sections/frontend.tex b/20-implementierungsheft/sections/frontend.tex
new file mode 100644
index 0000000..ae5be0e
--- /dev/null
+++ b/20-implementierungsheft/sections/frontend.tex
@@ -0,0 +1,196 @@
+\section{Weboberfläche}
+
+Die Weboberfläche wird mit dem Frontend-Web-Framework Vue.js erstellt. Mit Vue
+werden wiederverwendbare, auf Datenänderungen reagierende Komponenten erstellt.
+Die Komponenten nutzen ein fertiges Aussehen von dem Frontend-CSS-Framework
+Bootstrap. Außerdem werden Icons der freien Schriftart fontawesome
+verwendet.
+
+An der generellen Struktur und wichtigen Komponenten hat sich in der
+Implementierung nichts großes zum Entwurf geändert. Einige Komponenten konnten
+in der Implementierung allerdings abstrahiert werden, sodass weniger Code
+dupliziert werden musste. Dazu gehören zum Beispiel die Komponenten, welche ein
+Eingabefeld bereit stellen.
+
+Durch eine gute Arbeitsteilung blieb genug Zeit, um auch einige Kann-Kriterien
+zu implementieren, weshalb ein paar Abhängigkeiten hinzugekommen sind. So werden
+jszip und file-saver benötigt, um das Kann-Kriterium RC3 umzusetzen, durch
+welches man Nutzerdaten im- und exportieren kann.
+
+Pinia konnten wir als Abhängigkeit entfernen, weil Vue von sich aus genügend
+Funktionalität bietet die Nutzerdaten global allen Komponenten bereit zu
+stellen.
+
+Anfangs überlegten wir den Wrapper \texttt{bootstrap-vue} zu verwenden, welcher
+Bootstrap-HTML-Strukturen als Vue-Komponenten bereit stellt. Dies hätte des
+Vorteil, dass man nur jene Komponenten importieren müsste, die man auch
+benötigt. Es stellte sich heraus, dass \texttt{vue-bootstrap} nicht mit neusten
+Version Vue3 kompatibel ist, weshalb wir uns entschieden Bootstrap wie gewohnt
+komplett einzubinden.
+
+Während der Implementierung sind wir auf die Bibliothek \texttt{VueUse}
+gestoßen, mit der man die Abhängigkeit \texttt{file-saver} und mehrere eigene
+Wrapper für Browser-\Gls{api}s ersetzen könnte. So kann man das \Gls{dashboard} auch in
+Zukunft noch weiter verbessern.
+
+Vom Frontend benötigte Abhängigkeiten:
+\begin{itemize}
+ \item vite
+ \item vue
+ \item vue-router
+ \item \textcolor{red}{\sout{Pinia} wird durch globale Vue-Interne \texttt{ref} ersetzt}
+ \item bootstrap
+ \item fontawesome
+ \item vue-i18n (Support für mehrere Sprachen)
+ \item \textcolor{Green}{dayjs (Rechnen und formatieren von Zeiten)}
+ \item \textcolor{Green}{jszip (erstellen von Im-/Exports)}
+ \item \textcolor{Green}{file-saver (Abstraktion für Datei-Speichern-Dialog)}
+\end{itemize}
+
+\subsection{Komponentendiagramm Web-Frontend}
+\includegraphics[width=\textwidth]{assets/diagrams/componentdiagram}
+
+\subsection{Hinzugefügte Komponenten}
+
+% PasswordInput
+% PasswordValidator
+% FloatingLabelInput
+% Loading
+% ErrorLog
+% ProgressTime
+
+\begin{minipage}{.7\linewidth}
+
+\subsubsection*{FloatingLabelInput}
+
+\begin{description}
+\item[Tag] \texttt{<FloatingLabelInput type label>}
+\item[Props] \mbox{} \\
+ \emph{type} \mbox{} Beschreibt den Inhalt des Eingabefelder. Handelt es sich
+ um eine E-Mail, ein Passwort oder nur Text? \\
+ \emph{label} \mbox{} Das Label wird als Platzhalter und kleine Überschrift
+ angezeigt.
+\item[Beschreibung] Abstrahiert eine HTML-Struktur von Bootstrap, um ein schönes
+ Eingabefeld anzuzeigen.
+\end{description}
+\end{minipage}
+\begin{minipage}{.3\linewidth}
+ \begin{figure}[H]
+ \includegraphics[width=\textwidth]{assets/floatinglabelinput.png}
+ \end{figure}
+\end{minipage}
+
+
+\vspace{.5cm}
+
+\begin{minipage}{.7\linewidth}
+
+\subsubsection*{PasswordInput}
+
+\begin{description}
+\item[Tag] \texttt{<PasswordInput type label>}
+\item[Props] \mbox{} \\
+ \emph{label} \mbox{} Das Label wird als Platzhalter und kleine Überschrift
+ angezeigt.
+\item[Beschreibung] Erweitert den FloatingLabelInput um einen Knopf mit dem die
+ Sichtbarkeit des Eingabefeldes gewechselt werden kann. Dabei wird intern der
+ Typ des Eingabefeldes zwischen Text and Passwort gewechselt.
+\end{description}
+\end{minipage}
+\begin{minipage}{.3\linewidth}
+ \begin{figure}[H]
+ \includegraphics[width=\textwidth]{assets/passwordinput.png}
+ \end{figure}
+\end{minipage}
+
+
+\vspace{.5cm}
+
+\begin{minipage}{.7\linewidth}
+
+\subsubsection*{PasswordValidator}
+
+\begin{description}
+\item[Tag] \texttt{<PasswordValidator>}
+\item[Beschreibung] Besteht aus zwei PasswordInputs und überprüft diese auf
+ Gleichheit und Kriterien für eine gutes Passwort.
+\end{description}
+\end{minipage}
+\begin{minipage}{.3\linewidth}
+ \begin{figure}[H]
+ \includegraphics[width=\textwidth]{assets/passwordvalidator.png}
+ \end{figure}
+\end{minipage}
+
+
+\vspace{.5cm}
+
+\begin{minipage}{.7\linewidth}
+
+\subsubsection*{Loading}
+
+\begin{description}
+\item[Tag] \texttt{<Loading waitingFor>...<Loading/>}
+\item[Props] \mbox{} \\
+ \emph{waitingFor} \mbox{} Eine Referenz auf eine Bedingung wann die Kinder
+ der Komponente gezeigt werden sollen.
+\item[Beschreibung] Zeigt solange ein Ladesymbol an, bis die Bedingung in
+ \texttt{waitingFor} erfüllt ist und stattdessen die Kinder der Komponente
+ gezeigt werden.
+\end{description}
+\end{minipage}
+\begin{minipage}{.3\linewidth}
+ \begin{figure}[H]
+ \includegraphics[width=\textwidth]{assets/loading.png}
+ \end{figure}
+\end{minipage}
+
+
+\vspace{.5cm}
+
+\begin{minipage}{.7\linewidth}
+
+\subsubsection*{ProgressTime}
+
+\begin{description}
+\item[Tag] \texttt{<ProgressTime unix>}
+\item[Props] \mbox{} \\
+ \emph{unix} \mbox{} Anzahl an Sekunden.
+\item[Beschreibung] Nimmt eine Anzahl an Sekunden und gibt an wie viele Stunden,
+ Minuten und Sekunden die Anzahl entspricht.
+\end{description}
+\end{minipage}
+\begin{minipage}{.3\linewidth}
+ \begin{figure}[H]
+ \includegraphics[width=\textwidth]{assets/progresstime.png}
+ \end{figure}
+\end{minipage}
+
+
+\vspace{.5cm}
+
+\begin{minipage}{.7\linewidth}
+
+\subsubsection*{ErrorLog}
+
+\begin{description}
+\item[Tag] \texttt{<ErrorLog>}
+\item[Beschreibung] Zeigt eine Liste von Warnungen an, welche aus einem globalen
+ Zustandsspeicher geladen werden.
+\end{description}
+\end{minipage}
+\begin{minipage}{.3\linewidth}
+ \begin{figure}[H]
+ \includegraphics[width=\textwidth]{assets/errorlog.png}
+ \end{figure}
+\end{minipage}
+
+
+\vspace{.5cm}
+
+\subsubsection*{Dashboard/FormLayout}
+
+\begin{description}
+\item[Tag] \texttt{<DashboardLayout> <FormLayout>}
+\item[Beschreibung] Fügt den Kindern einen Seitenabstand hinzu.
+\end{description}
diff --git a/20-implementierungsheft/sections/glossar.tex b/20-implementierungsheft/sections/glossar.tex
new file mode 100644
index 0000000..9caad87
--- /dev/null
+++ b/20-implementierungsheft/sections/glossar.tex
@@ -0,0 +1,371 @@
+\makeglossaries
+
+\newglossaryentry{spa}
+{
+ name=Single-Page-Application,
+ description={
+ ist ein Webseiten-Modell, bei welchem dem Nutzer nur ein Webdokument
+ bereitgestellt wird. Mit einem Skript wird der Inhalt der Seite
+ dynamisch mit Daten einer API befüllt. Außerdem verwaltet die Seite
+ (nicht der Server), welcher Inhalt bei welchem Pfad angezeigt wird. Dies
+ erzeugt geringere Serverlast und eine bessere Nutzererfahrung, da die
+ Seitenstruktur beim Laden von neuen Inhalten erhalten bleibt}
+}
+
+\newglossaryentry{packagemanager}
+{
+ name=Paketmanager,
+ description={
+ ist ein Programm, welches Pakete und dessen Abhängigkeiten verwaltet,
+ installiert, entfernt und aktualisiert. Pakete können andere Programme,
+ Plugins oder Software-Bibliotheken sein}
+}
+
+\newglossaryentry{bundler}
+{
+ name=Bundler,
+ description={
+ ist ein Programm, welches genutzte Teile von Abhängigkeiten eines
+ Software-Projekts in passender Reihenfolge zusammensucht und daraus
+ Dateien erstellt, die für den Nutzer bereitgestellt werden können. Dabei
+ kann der Bundler mit zusätzlichen Modulen Dateien erzeugen, die
+ rückwärtskompatibel oder für den Nutzer schwerer einsehbar sind}
+}
+
+\newglossaryentry{java}
+{
+ name=Java,
+ description={
+ ist eine objekt-orientierte interpretierte kompilierte
+ Programmiersprache, welche plattformunabhängig auf einer virtuellen
+ Maschine ausgeführt wird}
+}
+
+\newglossaryentry{db}
+{
+ name=Datenbank,
+ plural=Datenbanken,
+ description={
+ ist ein System um Daten persistent zu speichern und effizient zu
+ verwalten. Am meisten verbreitet sind relationale Datenbanken, welche
+ Daten in Tabellen mit Referenzen zu Einträgen anderer Tabellen
+ speichern. Programme können dann über eine Anfragesprache (Structured
+ Query Language - \Gls{SQL}) komplexe Operationen auf den Daten ausführen}
+}
+
+\newglossaryentry{docker}
+{
+ name=Docker,
+ description={
+ ist ein Programm, das virtualisierte Container ausführt. Ein Programm in
+ so einem Container läuft in seiner eigenen virtuellen Umgebung, wodurch
+ das Host-System sicher bleibt. Zudem lassen sich die Container leicht
+ auf andere Systeme verteilen}
+}
+
+% RESTfull-API, JSON, RSS-Feed, Salting and Hasing, OAuth, Cookie, Garbage
+% Collection, DSGVO, Podcast, Podcatcher, Episode, Gpodder,
+
+\newglossaryentry{podcatcher}
+{
+ name=Podcatcher,
+ plural=Podcatchern,
+ description={
+ ist ein Programm, über welches man Podcasts entdecken, abonnieren und
+ Episoden von Podcasts hören kann. Mit einem Account auf einer Plattform,
+ welche eine Gpodder-API zur Verfügung stellt, können Ereignisse, die von
+ einem Nutzer ausgehen, auf anderen Podcatchern des Nutzers
+ synchronisiert werden}
+}
+
+\newglossaryentry{podcast}
+{
+ name=Podcast,
+ description={
+ ist ein RSS-Feed, dessen Einträge die Episoden darstellen}
+}
+
+\newglossaryentry{episode}
+{
+ name=Episode,
+ plural=Episoden,
+ description={
+ ist ein Eintrag in einem Podcast. Eine URL in dem Eintrag zeigt auf eine
+ Medien-Datei, welche vom Podcatcher abgespielt werden kann}
+}
+
+\newglossaryentry{rest-api}
+{
+ name=RESTful-API,
+ description={
+ ist ein Schnittstellenentwurf über das Hypertext Transfer Protocol
+ (HTTP), bei dem die Schnittstellen strukturiert als Pfad an einem
+ Endpunkt erreichbar sind. Mittels verschiedener HTTP-Methoden können an
+ der Schnittstelle Daten abgefragt (GET), gesendet (PUT), gelöscht
+ (DELETE) oder geändert (POST) werden. Die Daten, die über die
+ Schnittstelle gesendet werden liegen meist im JSON-Format vor}
+}
+
+
+\newglossaryentry{gpodder}
+{
+ name=Gpodder-API,
+ description={
+ wird von gpodder.net benutzt und entwickelt. Die API wird als
+ Schnittstelle zwischen Podcatchern und Podcast Synchronisationsservern
+ verwendet. Weitere Details sind unter
+ "https://gpoddernet.readthedocs.io/en/latest/api/" zu finden}
+}
+
+\newglossaryentry{json}
+{
+ name=JSON,
+ description={
+ (JavaScript Object Notation) ist ein Datenformat und wird zur
+ Übertragung von Strukturen und Daten eingesetzt. JSON besteht dabei aus
+ grundlegenden Datentypen sowie Objekten mit Schlüssel-Wert Paaren und
+ Listen}
+}
+
+\newglossaryentry{oauth}
+{
+ name=OAuth,
+ description={
+ (Open Authorization) ist ein offenes Protokoll, welches es Nutzern
+ ermöglicht, sich mit bereits bestehenden Accounts bei anderen Diensten
+ zu registrieren. Dabei werden benötigte Daten für die Registrierung über
+ die bereitgestellte Schnittstelle zur Verfügung gestellt}
+}
+
+\newglossaryentry{garbage-collection}
+{
+ name=Garbage Collection,
+ description={
+ ist eine automatische Speicherbereinigung, welche nicht mehr benötigten
+ Speicherplatz wieder freigibt. Die Bereinigung kann dabei in determinierten
+ Zeitintervallen erfolgen oder durch bestimmte Ereignisse ausgelöst
+ werden}
+}
+
+\newglossaryentry{salt-hash}
+{
+ name=Salting und Hashing,
+ description={
+ ist eine Methode um Passwörter so zu kodieren, dass sie nicht als
+ Klartext gespeichert werden und auch sicher vor Hash-Wörterbüchern sind.
+ Dafür wird dem Passwort ein bekanntes Wort, der Salt, angefügt, bevor
+ aus dem kompletten Wort eine Prüfsumme, ein Hash, generiert wird. Beim
+ Anmelden wird die Prüfsumme der Anmeldung mit der bekannten
+ Prüfsumme des Passworts verglichen}
+}
+
+\newglossaryentry{rss}
+{
+ name=RSS,
+ description={
+ (Really Simple Syndication) zeigt strukturiert Listen von Nachrichten
+ an. Die Änderungen werden im XML-Format in sogenannte RSS-Dateien
+ geschrieben, welche über einen Link abgerufen werden können}
+}
+
+\newglossaryentry{dsgvo}
+{
+ name=Datenschutz-Grundverordnung,
+ description={
+ (DSGVO) ist eine im europäischen Wirtschaftsraum
+ geltende Verordnung. Sie sorgt für eine Reglementierung bei der
+ Verarbeitung personenbezogener Daten. Unter anderem muss einsehbar sein,
+ welche Daten von Nutzern erhoben werden. Außerdem muss für einen Nutzer
+ die Möglichkeit bestehen, seine erhobenen Daten abrufen zu können}
+}
+
+\newglossaryentry{push-pull}
+{
+ name=Push und Pull,
+ description={
+ sind Methoden, um Daten auszutauschen. Bei der Pull-Methode
+ stellt Akteur A einem Akteur B eine Anfrage auf Daten und erhält diese
+ als Antwort. Damit Akteur A und B immer auf dem selben Stand sind, muss
+ Akteur A chronisch Anfragen an Akteur B stellen. Im Gegensatz dazu steht
+ die Push-Methode, bei der Akteur B den Akteuren mitteilt, dass er neue
+ Änderungen hat. Dafür muss Akteur B allerdings wissen mit welchen
+ anderen Akteuren er in Verbindung steht und diese Verbindung aufrecht
+ erhalten}
+}
+
+\newglossaryentry{ui-lib}
+{
+ name=UI-Bibliothek,
+ plural=UI-Bibliotheken,
+ description={
+ kümmert sich um das Layout einer Webseite. Dabei unterscheidet man
+ zwischen Design-Bibliotheken (wie Bootstrap), welche fertige
+ UI-Komponenten bereitstellen, und Layout-Bibliotheken (wie Vue oder
+ React.js), welche die Komponenten basierend auf Daten dynamisch
+ anzeigen}
+}
+
+\newglossaryentry{responsive}
+{
+ name=Responsive,
+ description={
+ Design ist ein Design-Prinzip für Webseiten, bei dem die selbe Webseite ihre
+ Komponenten dynamisch der Bildschirmbreite anpasst}
+}
+
+\newglossaryentry{pseudoprotocol}
+{
+ name=Pseudoprotokoll,
+ description={
+ ist ein URL-Schema, auf das Webseiten hören können, wenn sie sich das
+ URL-Schema im Browser anmelden. Bekannt Pseudoprotokolle sind:
+ ,,mailto:'', ,,tel:'' oder ,,irc:''}
+}
+
+\newglossaryentry{dashboard}
+{
+ name=Dashboard,
+ description={
+ ist die erste Seite auf der man landet, wenn man angemeldet ist}
+}
+
+\newglossaryentry{abo}
+{
+ name=Abonnement,
+ description={
+ ist ein abonnierter Podcast}
+}
+
+\newglossaryentry{discovery}
+{
+ name=Discovery,
+ description={
+ ist ein Feature der Gpodder-API, welches dem Nutzer eine Reihe von
+ Podcasts zum abonnieren anbietet}
+}
+
+\newglossaryentry{session-token}
+{
+ name=Session-Token,
+ description={
+ ist ein Wort, dass vom Client gespeichert wird solange der Nutzer
+ eingeloggt ist und bei jeder Anfrage an den Server mitgeschickt wird.
+ Der Server kann den Session-Token einem Nutzer zuordnen und so mit
+ nutzerspezifischen Daten antworten}
+}
+
+\newglossaryentry{cookie}
+{
+ name=Cookie,
+ description={
+ ist ein kleiner webseitenspezifischer Speicher im Browser, welcher vom
+ Server und von der Webseite gesetzt werden kann und bei jeder weiteren
+ Anfrage an den Server mitgesendet wird. Cookies bleiben entweder
+ temporär im Browserspeicher, bis der Browser geschlossen wird oder
+ permanent, bis ein optionales Verfallsdatum erreicht ist}
+}
+
+\newglossaryentry{uiComponent}
+{
+ name=UI-Komponente,
+ plural=UI-Komponenten,
+ description={
+ In Vue.js werden die grafischen Elemente einer Webseite in einzelne
+ Komponenten zerteilt.
+ Diese reagieren automatisch auf Änderungen und können ohne Neuladen
+ der Seite ihr Aussehen verändern und somit Änderungen direkt anzeigen}
+}
+
+\newglossaryentry{spring}
+{
+ name=Spring,
+ description={
+ Ein Java-Framework, welches die Entwicklung von Web-Applikationen erleichtert.
+ Dazu wird eine Reihe von Werkzeugsets zur Verfügung gestellt.
+ Unter anderem sind das Spring Web für das Erstellen von Webanwendungen,
+ Spring Security für die Verwaltung von Benutzerauthentifizierungen und
+ Spring Data JPA für die Arbeit mit relationalen Datenbanken
+ }
+}
+
+\newglossaryentry{api}
+{
+ name=API,
+ plural=APIs,
+ description={
+ Eine Schnittstelle, welche es ermöglicht auf Funktionalitäten einer Anwendung
+ zuzugreifen. APIs für Webanwendungen heißen WebAPIs.
+ Ein Beispiel für eine WebAPI ist die REST-API
+ }
+}
+
+\newglossaryentry{business}
+{
+ name=Geschäftslogik,
+ description={
+ Eine Schicht in der Anwendungsentwicklung, in der die Art und Weise, wie das
+ Programm auf Eingaben reagiert, wie Daten verarbeitet und wie sie gespeichert
+ werden sollen, festgelegt ist
+ }
+}
+
+\newglossaryentry{solid}
+{
+ name=SOLID,
+ description={
+ Eine Sammlung an Prinzipien, welche zu gutem objektorientierten Design führen soll.
+ Jedes Prinzip steht für einen Buchstaben in SOLID:
+ \textbf{S}ingle-Responsibility Prinzip,
+ \textbf{O}pen-Closed Prinzip,
+ \textbf{L}iskovsches Substitutionsprinzip,
+ \textbf{I}nterface Segregation Prinzip und
+ \textbf{D}ependency Inversion Prinzip
+ }
+}
+
+\newglossaryentry{crud}
+{
+ name=CRUD,
+ description={
+ CRUD steht für \textbf{C}reate, \textbf{R}ead, \textbf{U}pdate und \textbf{D}elete.
+ Hierbei handelt es sich um die grundlegenden Funktionen einer Anwendung,
+ die mit einer Datenbank arbeitet.
+ Hierbei können Daten angelegt, abgerufen, aktualisiert und gelöscht werden.
+ Auch in Web-Applikationen ist CRUD mit HTTP über die Anfragen POST, GET, PUT und DELETE
+ vertreten
+ }
+}
+
+\newglossaryentry{SQL}
+{
+ name=SQL,
+ description={
+ SQL (Structured Query Language) ist eine Sprache, die einen strukturierten Zugriff auf Datenbanken ermöglicht.
+ Daten können hierbei hinzugefügt, abgefragt, geändert und gelöscht werden.
+ Das besondere hierbei ist der strukturierte Zugriff auf Daten, indem explizit Daten mit bestimmten Kriterien und
+ Relationen ausgewählt und bearbeitet werden können.
+ SQL wird fast von allen verbreiteten Datenbanksystemen unterstützt
+ }
+}
+
+\newglossaryentry{Base64}
+{
+ name=Base64,
+ description={
+ Mithilfe von Base64 können 8-Bit-Binärdaten in eine ASCII-Zeichenkette
+ kodiert werden. So werden zum Beispiel E-Mail-Anhänge versendet
+ }
+}
+
+\newglossaryentry{JSONP}
+{
+ name=JSONP,
+ description={
+ JSONP ermöglicht die Übertragung von JSON-Daten zwischen verschiedenen Domains.
+ Dies wäre durch die Same-Origin-Policy nicht möglich.
+ JSONP nutzt allerdings die Tatsache aus,
+ dass sich Skripte domainübergreifend übertragen lassen.
+ Dazu werden die JSON-Daten als Argument einer übergebenen Funktion über
+ ein Skript-Element eingebunden
+ }
+}
diff --git a/20-implementierungsheft/sections/methodology.tex b/20-implementierungsheft/sections/methodology.tex
new file mode 100644
index 0000000..87b8176
--- /dev/null
+++ b/20-implementierungsheft/sections/methodology.tex
@@ -0,0 +1,16 @@
+\section{Integrationsstrategie}
+
+Bei der Implementierung wurde nach dem Outside-In Prinzip vorangegangenen.
+Dabei handelt es sich um eine inkrementelle und vorgehensorientierte Integrationsstrategie.
+Sie versucht die Vorteile des Top-Down und des Bottom-Up Prinzips zu vereinen und die jeweiligen
+Nachteile zu mindern.
+
+Bei der Outside-In Integration wird gleichzeitig auf höchster und niedrigster logischer
+Ebene mit der Implementation begonnen. Das passt gut zu der gewählten Systemarchitektur.
+Es wird sowohl frühzeitig die \Gls{db} eingebunden als auch das Frontend und die
+Controller implementiert. Dafür wird erst später an der Service-Schicht gearbeitet.
+Dieses Vorgehen wurde gewählt um die frühe Verfügbarkeit von testbaren Endpunkten zu haben.
+Somit können das Front- und Backend schon nach kurzer Zeit miteinander Integriert werden,
+wenn auch ohne funktionierende Serviceschicht. Außerdem wird für lange Zeit an verschiedenen
+Punkten gearbeitet, sodass der Prozess dank des vorrausgegangenen Entwurfs gut auf das ganze
+Team parallelisierbar ist.
diff --git a/20-implementierungsheft/sections/tests.tex b/20-implementierungsheft/sections/tests.tex
new file mode 100644
index 0000000..cdbf163
--- /dev/null
+++ b/20-implementierungsheft/sections/tests.tex
@@ -0,0 +1,21 @@
+\section{Testfälle}
+
+Für die Erstellung der Testfälle wurde die SpringBoot Testumgebung verwendet und
+diese durch JUnit Testfälle ergänzt.
+
+Für das Testen wurde eine BaseTest Klasse erstellt, die grundlegende Funktionalität
+einiger Kern Komponenten sicherstellt. Weiter Initialisiert sie die Anwendungsumgebung auf
+der alle weiteren Tests aufbauen.
+
+Die Unit Tests erweitern diese BaseTest Klasse und können daher von gewisser Grundfunktionalität
+ausgehen, die durch den BaseTest abgedeckt ist. Dadurch müssen nicht große Teile der
+Anwendung durch Mock Objekte simuliert werden.
+
+Grundsätzlich wurde beim Entwurf der Testfälle nach dem Inside-Out-Prinzip vorangegangenen.
+Die bisher geschriebenen Testfälle haben dabei nicht das Ziel Korrektheit zu garantieren,
+sondern einen gewissen Qualitätsstandart zu sichern und gleichzeitig genug
+Arbeitspunkte bereit zu stellen um im ganzen Team an diesem Projekt parallel arbeite zu können.
+
+Zusätzlich wurden bei der Implementierung auf ausgiebig getestete Annotationen von Spring und
+Lombok zurückgegriffen die helfen die Anzahl an Fehlern bei standardisierten
+\enquote{Boilerplater-Code} Aufgaben zu vermeiden. \ No newline at end of file
diff --git a/20-implementierungsheft/sections/timeline.tex b/20-implementierungsheft/sections/timeline.tex
new file mode 100644
index 0000000..7fa084d
--- /dev/null
+++ b/20-implementierungsheft/sections/timeline.tex
@@ -0,0 +1,7 @@
+\section{Zeitlicher Verlauf}
+
+\subsection{Plan}
+\includegraphics[width=\textwidth]{assets/diagrams/gantt-plan}
+
+\subsection{Realität}
+\includegraphics[width=\textwidth]{assets/diagrams/gantt-reality}
diff --git a/20-implementierungsheft/titlepage.tex b/20-implementierungsheft/titlepage.tex
new file mode 100644
index 0000000..4e7e707
--- /dev/null
+++ b/20-implementierungsheft/titlepage.tex
@@ -0,0 +1,75 @@
+%% Encoding: UTF-8 %%
+
+%% titlepage.tex
+
+\def\usesf{}
+\let\usesf\sffamily % diese Zeile auskommentieren für normalen TeX Font
+
+\begin{titlepage}
+
+\setlength{\unitlength}{1pt}
+\begin{picture}(00,0)(70,770)
+ \includegraphics[width=\paperwidth]{assets/KIT_Deckblatt.pdf}
+\end{picture}
+
+\thispagestyle{empty}
+
+\begin{center}
+\hbox{}
+\vfill
+\includegraphics[width=.5\textwidth]{assets/logo.pdf}
+\vskip 1cm
+{\usesf
+ {\huge\bfseries PSE\textsuperscript{2} - Podcast Synchronisation \\
+ made Efficient\\
+ Implementierungsheft \par}
+\vskip 1.8cm
+{\Large Wintersemester 2022/2023\\}
+%von\\[2mm]
+\vskip 1.5cm
+
+% {\large\bfseries Vorname Nachname\\}
+% \vskip 1.2cm
+Praxis der Softwareentwicklung \\
+Prof. Dr.-Ing. Gregor Snelting \\
+Fakultät für Informatik\\
+Karlsruher Institut für Technologie\\
+\vskip 1.5cm
+\begin{tabular}{p{20mm}l}
+Autoren:
+& Daniel Hönlinger \\
+& Gero Beckmann \\
+& Immanuel Reitz \\
+& Julius Friesen \\
+& Lukas Schmidheissler \\
+\\
+Betreuer: & M.Sc. Hans-Peter Lehmann \\
+ & M.Sc. Daniel Seemaier
+\end{tabular}
+}
+\end{center}
+\vfill
+
+%\begin{textblock}{10}[0,0](4,15)
+% \includegraphics[width=.3\textwidth]{logos/logo.pdf}
+%\end{textblock}
+
+% \begin{textblock}{8}[0,0](14,14)
+% \includegraphics[width=.3\textwidth]{logos/KASTEL_logo.pdf}
+% \end{textblock}
+
+\end{titlepage}
+
+% \thispagestyle{empty}
+% \ \vfill
+% \begin{flushleft}
+% Copyright $\copyright$ ITI und Verfasser 201?\\
+% \ \\
+% Institut für Theoretische Informatik
+% Fakultät für Informatik\\
+% Karlsruher Institut für Technologie\\
+% Am Fasanengarten 5\\
+% 76131 Karlsruhe
+% \end{flushleft}
+% \newpage
+
diff --git a/21-implementierungsheft-kolloquium/.gitignore b/21-implementierungsheft-kolloquium/.gitignore
new file mode 100644
index 0000000..e20d538
--- /dev/null
+++ b/21-implementierungsheft-kolloquium/.gitignore
@@ -0,0 +1,302 @@
+## Core latex/pdflatex auxiliary files:
+*.aux
+*.lof
+*.log
+*.lot
+*.fls
+*.out
+*.toc
+*.fmt
+*.fot
+*.cb
+*.cb2
+.*.lb
+
+## Intermediate documents:
+*.dvi
+*.xdv
+*-converted-to.*
+# these rules might exclude image files for figures etc.
+# *.ps
+*.eps
+*.pdf
+# !assets/*.pdf
+
+## Generated if empty string is given at "Please type another file name for output:"
+.pdf
+
+## Bibliography auxiliary files (bibtex/biblatex/biber):
+*.bbl
+*.bcf
+*.blg
+*-blx.aux
+*-blx.bib
+*.run.xml
+
+## Build tool auxiliary files:
+*.fdb_latexmk
+*.synctex
+*.synctex(busy)
+*.synctex.gz
+*.synctex.gz(busy)
+*.pdfsync
+
+## Build tool directories for auxiliary files
+# latexrun
+latex.out/
+
+## Auxiliary and intermediate files from other packages:
+# algorithms
+*.alg
+*.loa
+
+# achemso
+acs-*.bib
+
+# amsthm
+*.thm
+
+# beamer
+*.nav
+*.pre
+*.snm
+*.vrb
+
+# changes
+*.soc
+
+# comment
+*.cut
+
+# cprotect
+*.cpt
+
+# elsarticle (documentclass of Elsevier journals)
+*.spl
+
+# endnotes
+*.ent
+
+# fixme
+*.lox
+
+# feynmf/feynmp
+*.mf
+*.mp
+*.t[1-9]
+*.t[1-9][0-9]
+*.tfm
+
+#(r)(e)ledmac/(r)(e)ledpar
+*.end
+*.?end
+*.[1-9]
+*.[1-9][0-9]
+*.[1-9][0-9][0-9]
+*.[1-9]R
+*.[1-9][0-9]R
+*.[1-9][0-9][0-9]R
+*.eledsec[1-9]
+*.eledsec[1-9]R
+*.eledsec[1-9][0-9]
+*.eledsec[1-9][0-9]R
+*.eledsec[1-9][0-9][0-9]
+*.eledsec[1-9][0-9][0-9]R
+
+# glossaries
+*.acn
+*.acr
+*.glg
+*.glo
+*.gls
+*.glsdefs
+*.lzo
+*.lzs
+*.slg
+*.slo
+*.sls
+
+# uncomment this for glossaries-extra (will ignore makeindex's style files!)
+*.ist
+
+# gnuplot
+*.gnuplot
+*.table
+
+# gnuplottex
+*-gnuplottex-*
+
+# gregoriotex
+*.gaux
+*.glog
+*.gtex
+
+# htlatex
+*.4ct
+*.4tc
+*.idv
+*.lg
+*.trc
+*.xref
+
+# hyperref
+*.brf
+
+# knitr
+*-concordance.tex
+# TODO Uncomment the next line if you use knitr and want to ignore its generated tikz files
+# *.tikz
+*-tikzDictionary
+
+# listings
+*.lol
+
+# luatexja-ruby
+*.ltjruby
+
+# makeidx
+*.idx
+*.ilg
+*.ind
+
+# minitoc
+*.maf
+*.mlf
+*.mlt
+*.mtc[0-9]*
+*.slf[0-9]*
+*.slt[0-9]*
+*.stc[0-9]*
+
+# minted
+_minted*
+*.pyg
+
+# morewrites
+*.mw
+
+# newpax
+*.newpax
+
+# nomencl
+*.nlg
+*.nlo
+*.nls
+
+# pax
+*.pax
+
+# pdfpcnotes
+*.pdfpc
+
+# sagetex
+*.sagetex.sage
+*.sagetex.py
+*.sagetex.scmd
+
+# scrwfile
+*.wrt
+
+# svg
+svg-inkscape/
+
+# sympy
+*.sout
+*.sympy
+sympy-plots-for-*.tex/
+
+# pdfcomment
+*.upa
+*.upb
+
+# pythontex
+*.pytxcode
+pythontex-files-*/
+
+# tcolorbox
+*.listing
+
+# thmtools
+*.loe
+
+# TikZ & PGF
+*.dpth
+*.md5
+*.auxlock
+
+# titletoc
+*.ptc
+
+# todonotes
+*.tdo
+
+# vhistory
+*.hst
+*.ver
+
+# easy-todo
+*.lod
+
+# xcolor
+*.xcp
+
+# xmpincl
+*.xmpi
+
+# xindy
+*.xdy
+
+# xypic precompiled matrices and outlines
+*.xyc
+*.xyd
+
+# endfloat
+*.ttt
+*.fff
+
+# Latexian
+TSWLatexianTemp*
+
+## Editors:
+# WinEdt
+*.bak
+*.sav
+
+# Texpad
+.texpadtmp
+
+# LyX
+*.lyx~
+
+# Kile
+*.backup
+
+# gummi
+.*.swp
+
+# KBibTeX
+*~[0-9]*
+
+# TeXnicCenter
+*.tps
+
+# auto folder when using emacs and auctex
+./auto/*
+*.el
+
+# expex forward references with \gathertags
+*-tags.tex
+
+# standalone packages
+*.sta
+
+# Makeindex log files
+*.lpz
+
+# xwatermark package
+*.xwm
+
+# REVTeX puts footnotes in the bibliography by default, unless the nofootinbib
+# option is specified. Footnotes are the stored in a file with suffix Notes.bib.
+# Uncomment the next line to have this generated file ignored.
+#*Notes.bib
diff --git a/21-implementierungsheft-kolloquium/.gitlab-ci.yml b/21-implementierungsheft-kolloquium/.gitlab-ci.yml
new file mode 100644
index 0000000..c4ad5e0
--- /dev/null
+++ b/21-implementierungsheft-kolloquium/.gitlab-ci.yml
@@ -0,0 +1,37 @@
+plantuml:
+ stage: .pre
+ image:
+ name: eclipse-temurin:17-alpine
+ entrypoint: [""]
+ script:
+ - java -jar plantuml.jar -tpdf assets/diagrams/*.puml
+ - java -jar plantuml.jar -teps assets/*.puml
+ artifacts:
+ paths:
+ - assets
+
+tex:
+ stage: build
+ image: texlive/texlive
+ script:
+ - mkdir public
+ - make tex
+ - mv *.pdf public
+ artifacts:
+ paths:
+ - public
+ dependencies:
+ - plantuml
+
+pages:
+ stage: deploy
+ script:
+ - echo Hello, World!
+ artifacts:
+ paths:
+ - public
+ rules:
+ - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
+ dependencies:
+ - tex
+
diff --git a/21-implementierungsheft-kolloquium/CHANGELOG.md b/21-implementierungsheft-kolloquium/CHANGELOG.md
new file mode 100644
index 0000000..7671a41
--- /dev/null
+++ b/21-implementierungsheft-kolloquium/CHANGELOG.md
@@ -0,0 +1,34 @@
+# Changelog
+Alle Änderungen an diesem Projekt werden in dieser Datei dokumentiert.
+Die Versionsnummern folgt der Syntax in `sdqbeamer.cls`.
+
+## [2022-05-03 v3.1.3]
+- Die Breite des Gruppennamens in der Fußzeile kann nun über `\groupnamewidth{}` gesteuert werden
+- FIX: zweizeilige Fußzeilen haben nun gleichmäßigen vertikalen Abstand (Issue #16 in Gitlab)
+
+## [2021-08-10 v3.1.2]
+- FIX: framesubtitle wird nun angezeigt (Issue #6 in Gitlab)
+
+## [2020-12-08 v3.1.1]
+- FIX: Titelbild (Issue #4 in Gitlab)
+
+## [2020-12-07 v3.1]
+- Umgebung ``contentblock`` (farbloser Block mit fetter Überschrift) hinzugefügt
+- Farbboxen (``greenblock``, ``blueblock``, …) hinzugefügt
+- Abstufungen der KIT-Farben in 10er-Schritten entsprechend der Gestaltungsrichtlinien eingeführt
+- FIX: Navigationspunkte für Subsections in eine Zeile gesetzt, um vertikal Platz zu sparen
+- FIX: ``inputenc`` an den Anfang von ``sdqbeamer.cls`` verschoben
+
+## [2020-11-16 v3.0]
+- Seitenformat 16:10 hinzugefügt
+- Umstellung auf KIT-Design vom 1. August 2020
+ - Anpassung auf neues Farbschema und Maße
+ - neues Titelbild aus der KIT-Bildwelt
+- Neue Optionen:
+ - durch `smallfoot` und `bigfoot` kann die Schriftgröße der Fußzeile gesteuert werden
+ - durch `navbarkit` kann eine Fußzeile nach KIT-Vorgaben erzwungen werden
+- Deutsch (`de`) ist nun die Standard-Option
+- Ordner `templates` wurde gelöscht und die Inhalte in `sdqbeamer.cls` integriert
+- Globale Größe auf 10 pt verringert (vorher: 11 pt), da der beschreibbare Bereich im Vergleich zur 2009er Version kleiner geworden ist
+- SDQ-spezifische Logos und Titelbilder entfernt. Diese sind ab sofort im Branch »sdq« verfügbar.
+- Fix: Zeilenumbruch bei Titel in der Fußzeile repariert \ No newline at end of file
diff --git a/21-implementierungsheft-kolloquium/Makefile b/21-implementierungsheft-kolloquium/Makefile
new file mode 100644
index 0000000..3e1e58a
--- /dev/null
+++ b/21-implementierungsheft-kolloquium/Makefile
@@ -0,0 +1,19 @@
+MAIN = presentation
+FLAGS = -pdf
+
+all: clean compile
+compile: diagram tex
+clean: clean-diagram clean-tex
+
+dev:
+ latexmk $(FLAGS) -pvc $(MAIN)
+tex:
+ latexmk $(FLAGS) $(MAIN)
+diagram:
+ java -jar plantuml.jar -tpdf assets/diagrams/*.puml
+ java -jar plantuml.jar -teps assets/*.puml
+clean-tex:
+ latexmk -C
+clean-diagram:
+ find assets/diagrams -type f -not -name '*.puml' -delete
+
diff --git a/21-implementierungsheft-kolloquium/README.md b/21-implementierungsheft-kolloquium/README.md
new file mode 100644
index 0000000..6a5e9ea
--- /dev/null
+++ b/21-implementierungsheft-kolloquium/README.md
@@ -0,0 +1,118 @@
+LaTeX-Vorlage für Präsentationen
+================================
+
+Das vorliegende Paket dient als Vorlage für Präsentationen im [Corporate Design des KIT](https://intranet.kit.edu/gestaltungsrichtlinien.php) (Fassung vom 1. August 2020).
+
+Es wird an der Forschungsgruppe [DSiS](https://dsis.kastel.kit.edu) an der KIT-Fakultät für Informatik entwickelt und basiert auf [LaTeX Beamer](https://ctan.org/pkg/beamer).
+
+Autor: [Dr.-Ing. Erik Burger](https://dsis.kastel.kit.edu/staff_erik_burger.php)
+mit Beiträgen von Christian Hammer, Klaus Krogmann und Maximilian Schambach
+
+Siehe https://sdqweb.ipd.kit.edu/wiki/Dokumentvorlagen
+
+Hinweise, Verbesserungsvorschläge
+=================================
+
+Bitte verwenden Sie das [Issue-Tracking-System von Gitlab](https://git.scc.kit.edu/i43/dokumentvorlagen/praesentationen/beamer/-/issues), um auf Probleme mit der Vorlage hinzuweisen oder Erweiterungswünsche zu äußern. Sie können gerne auch eine Änderung per Merge-Request vorschlagen.
+
+Verwendung
+==========
+
+Optionen der Dokumentklasse `sdqbeamer`
+-----------------------------------------
+Durch die folgenden Optionen kann das Seitenverhältnis der Folien bestimmt werden:
+
+| Seitenverhältnis | Option |
+| ---------------- | ------------------- |
+| 16:9 | `16:9` (Standard) |
+| 16:10 | `16:10` |
+| 4:3 | `4:3` |
+
+Die Schriftgröße in der Fußzeile ist standardmäßig größer gewählt, als in den Gestaltungsrichtlinien vorgegeben. Diese Vorgabe kann durch die Option `smallfoot` erzwungen werden.
+
+| Schriftgröße Fußzeile | Option |
+| ----------------------| -------------------- |
+| etwas größer (12pt) | `bigfoot` (Standard) |
+| KIT-Vorgabe (9pt) | `smallfoot` |
+
+Die Plazierung der Navigationsleiste kann durch folgende Optionen beeinflußt werden:
+
+| Position | Option | Bemerkung |
+| ------------------------ | ---------------- | ------------------------------------------ |
+| oberhalb der Trennlinie | `navbarinline` | Standard |
+| unterhalb der Trennlinie | `navbarinfooter` | keine Subsection-Punkte, Größe `smallfoot` |
+| Seitenleiste links | `navbarside` | keine Subsection-Punkte |
+| keine Navigationsleiste | `navbaroff` | |
+| KIT-Vorgabe | `navbarkit` | entspricht `navbaroff` und `smallfoot` |
+
+Als Sprache sind Deutsch und Englisch verfügbar. Durch die Sprachwahl werden automatisch die passenden Logos und Formate (z.B. Datum) gewählt.
+
+| Sprache | |
+| -------- |---------------- |
+| Deutsch | `de` (Standard) |
+| Englisch | `en` |
+
+Beispiel: `\documentclass[de,16:9,navbarinline]{sdqbeamer}`
+
+Titelbild
+---------
+
+Das Bild auf der Titelfolie kann mit dem Befehl
+
+`\titleimage{myimage}` (ohne Dateiendung)
+
+gesetzt werden. Um ein eigenes Bild zu verwenden, bitte die Datei (z.B. `myimage.jpg`) ins `logos/`-Verzeichnis legen und den Befehl anpassen. Mitgeliefert wird ein generisches Bild aus der KIT-Bildwelt (https://intranet.kit.edu/gestaltungsrichtlinien.php) in der Datei `logos/banner_2020_kit.jpg`. Falls kein Titelbild eingefügt werden soll, bitte `\titleimage{}` setzen.
+
+Für 16:9-Folien sollte das Verhältnis des Bildes 160:37 betragen, für 4:3-Folien 63:20. Es können auch breitere Bilder verwendet werden, da das Titelbild auf die Höhe des Rahmens skaliert und zentriert wird.
+
+Logo und Name Abteilung/KIT-Fakultät/Institut
+---------------------------------------------
+
+Das Logo rechts oben auf der Titelfolie kann mit dem folgenden Befehl gesetzt werden:
+
+`\grouplogo{mylogo}` (ohne Dateiendung)
+
+Um ein eigenes Logo zu verwenden, bitte die Datei (z.B. `mylogo.pdf`) in das Verzeichnis `logos/` legen und den Befehl anpassen. Falls kein Logo eingefügt werden soll, bitte `\grouplogo{}` setzen.
+
+Der Gruppenname kann mit folgendem Befehl gesetzt werden:
+
+`\groupname{Software Design and Quality}`
+
+Der Gruppenname erscheint in der Fußzeile rechts unten. Lange Namen werden in zwei Zeilen umgebrochen. Falls der Gruppenname leer gelassen wird (`\groupname{}`), wird die volle Breite der Fußzeile für Autornamen und Titel verwendet.
+
+Die Standardbreite des Gruppennamens sind 50 mm. Sie kann mit
+
+`\groupnamewidth{80mm}`
+
+verändert werden, wodurch sich auch die Breite des Textfeldes mit Autor und Titel entsprechend ändert. Umbrüche sind mit `\\` möglich. Statt zweizeiliger Fußzeilen empfiehlt sich eventuell die Option `smallfoot`.
+
+LaTeX allgemein
+---------------
+Siehe https://sdqweb.ipd.kit.edu/wiki/LaTeX
+
+Dateistruktur
+============
+`presentation.tex`
+------------------
+Hauptdatei des LaTeX-Dokuments.
+
+`presentation.bib`
+-------------
+Beispieldatei für BibTeX-Referenzen
+https://sdqweb.ipd.kit.edu/wiki/BibTeX-Literaturlisten
+
+`sdqbeamer.cls`
+-----------------
+Dokumentklasse für Präsentationen im KIT-Design.
+
+`logos/`
+--------
+In diesem Verzeichnis befinden das KIT-Logo als PDF sowie das Hintergrundbild der Titelfolie als JPG.
+
+`CHANGELOG.md`
+--------------
+Dokumentation der Änderungen in den jeweiligen Versionen.
+
+`README.md`
+-----------
+Dieser Text.
diff --git a/21-implementierungsheft-kolloquium/assets/.gitignore b/21-implementierungsheft-kolloquium/assets/.gitignore
new file mode 100644
index 0000000..16252a4
--- /dev/null
+++ b/21-implementierungsheft-kolloquium/assets/.gitignore
@@ -0,0 +1,3 @@
+diagrams/*
+!diagrams/*.puml
+
diff --git a/21-implementierungsheft-kolloquium/assets/.gitingnore b/21-implementierungsheft-kolloquium/assets/.gitingnore
new file mode 100644
index 0000000..16252a4
--- /dev/null
+++ b/21-implementierungsheft-kolloquium/assets/.gitingnore
@@ -0,0 +1,3 @@
+diagrams/*
+!diagrams/*.puml
+
diff --git a/21-implementierungsheft-kolloquium/assets/commits-dashboard.png b/21-implementierungsheft-kolloquium/assets/commits-dashboard.png
new file mode 100644
index 0000000..89672d6
--- /dev/null
+++ b/21-implementierungsheft-kolloquium/assets/commits-dashboard.png
Binary files differ
diff --git a/21-implementierungsheft-kolloquium/assets/commits-server.png b/21-implementierungsheft-kolloquium/assets/commits-server.png
new file mode 100644
index 0000000..a9d1a5c
--- /dev/null
+++ b/21-implementierungsheft-kolloquium/assets/commits-server.png
Binary files differ
diff --git a/21-implementierungsheft-kolloquium/assets/contributors-dashboard.png b/21-implementierungsheft-kolloquium/assets/contributors-dashboard.png
new file mode 100644
index 0000000..3621c31
--- /dev/null
+++ b/21-implementierungsheft-kolloquium/assets/contributors-dashboard.png
Binary files differ
diff --git a/21-implementierungsheft-kolloquium/assets/contributors-server.png b/21-implementierungsheft-kolloquium/assets/contributors-server.png
new file mode 100644
index 0000000..500bb43
--- /dev/null
+++ b/21-implementierungsheft-kolloquium/assets/contributors-server.png
Binary files differ
diff --git a/21-implementierungsheft-kolloquium/assets/diagrams/backendComponentDiagram.puml b/21-implementierungsheft-kolloquium/assets/diagrams/backendComponentDiagram.puml
new file mode 100644
index 0000000..e382351
--- /dev/null
+++ b/21-implementierungsheft-kolloquium/assets/diagrams/backendComponentDiagram.puml
@@ -0,0 +1,61 @@
+@startuml
+' skinparam linetype ortho
+
+'#########################################################################
+'SubscriptionsAPI
+component SubscriptionsAPI {
+
+ component SubscriptionService
+ component SubscriptionController
+ component SubscriptionDataAccessLayer
+
+ portout "Webserver" as wSub
+ portin "Database" as dSub
+ }
+
+dSub --0)- SubscriptionDataAccessLayer
+SubscriptionDataAccessLayer --0)- SubscriptionService
+SubscriptionService --0)- SubscriptionController
+SubscriptionController --0)- wSub
+
+'#########################################################################
+
+
+'#########################################################################
+'EpisodeActionsAPI
+
+component EpisodeActionsAPI {
+ component EpisodeActionService
+ component EpisodeActionController
+ component EpisodeActionDataAccessLayer
+
+ portout "Webserver" as wEpisode
+ portin "Database" as dEpisode
+}
+
+dEpisode --0)- EpisodeActionDataAccessLayer
+EpisodeActionController --0)- wEpisode
+EpisodeActionDataAccessLayer --0)- EpisodeActionService
+EpisodeActionService --0)- EpisodeActionController
+
+'#########################################################################
+
+
+'#########################################################################
+'AuthenticationAPI
+
+component AuthenticationAPI {
+ component AuthenticationService
+ component AuthenticationController
+ component AuthenticationDataAccessLayer
+
+ portout "Webserver" as wAuth
+ portin "Database" as dAuth
+}
+
+dAuth --0)- AuthenticationDataAccessLayer
+AuthenticationController --0)- wAuth
+AuthenticationDataAccessLayer --0)- AuthenticationService
+AuthenticationService --0)- AuthenticationController
+
+@enduml
diff --git a/21-implementierungsheft-kolloquium/assets/diagrams/classdiagram-authentication.puml b/21-implementierungsheft-kolloquium/assets/diagrams/classdiagram-authentication.puml
new file mode 100644
index 0000000..a2b3518
--- /dev/null
+++ b/21-implementierungsheft-kolloquium/assets/diagrams/classdiagram-authentication.puml
@@ -0,0 +1,112 @@
+@startuml
+
+package authenticationAPI <<Frame>> {
+ package authenticationDataAccessLayer <<Frame>> {
+ ' interface AuthenticationDao {
+ ' String login(String username)
+ ' int logout(String username)
+ ' }
+
+ ' class AuthenticationDataAccessService <<@Respository>> {
+ ' <<create>> AuthenticationDataAccessService(JpaTemplate jpaTemplate)
+ ' String login(String username)
+ ' int logout(String username)
+ ' }
+
+ interface UserDetailsManager {
+ void createUser(UserDetails userDetails)
+ void changePassword(String oldPassword, String newPassword)
+ void deleteUser(String username)
+ void updateUser(UserDetails user)
+ boolean userExists(String username)
+ }
+ note left
+ Aus org.springframework.security.provisioning
+ - liefert Methoden zum Erstellen neuer User
+ und zum Aktualisieren bestehender.
+ end note
+
+ class JdbcUserDetailsManager <<@Repository>> {
+ <<create>> JdbcUserDetailsManager(DataSource dataSource)
+ void createUser(UserDetails user)
+ void changePassword(String oldPassword, String newPassword)
+ void deleteUser(String username)
+ void updateUser(UserDetails user)
+ boolean userExists(String username)
+ }
+ note right
+ User Management Service aus dem Paket
+ org.springframework.security.provisioning
+ der CRUD Operationen für User bereitstellt.
+ Hier sind nur die relevanten Methoden modelliert.
+ end note
+ }
+
+ package authenticationService <<Frame>> {
+ class AuthenticationService <<@Service>> {
+ --
+ <<create>> AuthenticationService(UserDetailsManager userDetailsManager)
+ List<String> verifyLogin(String username)
+ int logout(String username)
+ int forgotPassword(ForgotPasswordRequest forgotPasswordRequest)
+ .. via JdbcUserDetailsManager ..
+ int resetPassword(String username, RequestWithPassword requestWithPassword)
+ int registerUser(UserDetails user)
+ int changePassword(String username, ChangePasswordRequest changePasswordRequest)
+ int deleteUser(String username, RequestWithPassword requestWithPassword)
+ }
+
+ class JavaMailSenderImpl {}
+ note left
+ Aus org.springframework.mail.javamail.
+ Implementierung des JavaMailSender Interfaces,
+ welches das MailSender Interface durch Unterstützung
+ von MIME Nachrichten erweitert.
+ Das MailSender Interface definiert dabei eine
+ Strategie zum Versenden einfacher Mails.
+ Unterstützt sowohl JavaMail MimeMessages und
+ Spring SimpleMailMessages.
+ end note
+ }
+
+ package authenticationController <<Frame>> {
+ class AuthenticationController <<@Controller>> {
+ <<create>> AuthenticationController(AuthenticationService authenticationService)
+ ResponseEntity<List<String>> verifyLogin(String username)
+ ResponseEntity<Integer> logout(String username)
+ ResponseEntity<Integer> forgotPassword(ForgotPasswordRequest forgotPasswordRequest)
+ ResponseEntity<Integer> resetPassword(String username, RequestWithPassword requestWithPassword)
+ ResponseEntity<Integer> registerUser(UserDetails user)
+ ResponseEntity<Integer> changePassword(String username, ChangePasswordRequest changePasswordRequest)
+ ResponseEntity<Integer> deleteUser(String username, RequestWithPassword requestWithPassword)
+ }
+
+ class ChangePasswordRequest {
+ <<create>> ChangePasswordRequest(String oldPassword, String newPassword)
+ String getOldPassword()
+ String getNewPassword()
+ }
+
+ class ForgotPasswordRequest {
+ <<create>> ForgotPasswordRequest(String email)
+ String getEmail()
+ }
+
+ class RequestWithPassword {
+ <<create>> ResetPasswordRequest(String password)
+ String getPassword()
+ }
+ }
+}
+
+' User <.. AuthenticationDataAccessService: DB
+' User <.. JdbcUserDetailsManager: DB
+UserDetailsManager <.. AuthenticationService: <<use>>
+' AuthenticationDao <.. AuthenticationService: <<use>>
+AuthenticationService --o AuthenticationController
+' AuthenticationDao <|. AuthenticationDataAccessService: <<realize>>
+UserDetailsManager <|. JdbcUserDetailsManager: <<realize>>
+JavaMailSenderImpl <. AuthenticationService: <<use>>
+
+@enduml
+
diff --git a/21-implementierungsheft-kolloquium/assets/diagrams/classdiagram-episode-actions.puml b/21-implementierungsheft-kolloquium/assets/diagrams/classdiagram-episode-actions.puml
new file mode 100644
index 0000000..7a4530e
--- /dev/null
+++ b/21-implementierungsheft-kolloquium/assets/diagrams/classdiagram-episode-actions.puml
@@ -0,0 +1,84 @@
+@startuml
+
+package episodeActionsAPI <<Frame>> {
+ package episodeActionDataAccessLayer <<Frame>> {
+ class EpisodeActionDataAccessService <<@Repository>> {
+ <<create>> EpisodeActionDataAccessService (JpaTemplate jpaTemplate)
+ long addEpisodeActions(String username, List<EpisodeActionPost> episodeActionPosts)
+ List<EpisodeActionPost> getEpisodeActions(String username)
+ List<EpisodeActionPost> getEpisodeActionsOfPodcast(String username, String podcastURL)
+ List<EpisodeActionPost> getEpisodeActionsSince(String username, LocalDateTime since)
+ List<EpisodeActionPost> getEpisodeActionsOfPodcastSince(String username, String podcastURL, LocalDateTime since)
+ }
+
+ interface EpisodeActionDao {
+ long addEpisodeActions(String username, List<EpisodeActionPost> episodeActionPosts)
+ List<EpisodeActionPost> getEpisodeActions(String username)
+ List<EpisodeActionPost> getEpisodeActionsOfPodcast(String username, String podcastURL)
+ List<EpisodeActionPost> getEpisodeActionsSince(String username, LocalDateTime since)
+ List<EpisodeActionPost> getEpisodeActionsOfPodcastSince(String username, String podcastURL, LocalDateTime since)
+ }
+ }
+
+ package episodeActionService <<Frame>> {
+ class EpisodeActionService <<@Service>> {
+ <<create>> EpisodeActionService (EpisodeActionDao episodeActionDao)
+ LocalDateTime addEpisodeActions(String username, List<EpisodeActionPosts> episodeActionPosts)
+ List<EpisodeActionPost> getEpisodeActions(String username)
+ List<EpisodeActionPost> getEpisodeActionsOfPodcast(String username, String podcastURL)
+ List<EpisodeActionPost> getEpisodeActionsSince(String username, LocalDateTime since)
+ List<EpisodeActionPost> getEpisodeActionsOfPodcastSince(String username, String podcastURL, LocalDateTime since)
+ }
+ }
+
+ package episodeActionController <<Frame>> {
+ class EpisodeActionController <<@Controller>>{
+ <<create>> EpisodeActionController (EpisodeActionService episodeActionService)
+ ResponseEntity<EpisodeActionPostResponse> addEpisodeActions(String username, EpisodeActionPostRequest episodeActionPostRequest)
+ ResponseEntity<EpisodeActionGetResponse> getEpisodeActions(String username, String deviceID, boolean aggregated)
+ ResponseEntity<EpisodeActionGetResponse> getEpisodeActionsOfPodcast(String username, String podcastURL, String deviceID, boolean aggregated)
+ ResponseEntity<EpisodeActionGetResponse> getEpisodeActionsSince(String username, String deviceID, long since, boolean aggregated)
+ ResponseEntity<EpisodeActionGetResponse> getEpisodeActionsOfPodcastSince(String username, String podcastURL, String deviceID, long since, boolean aggregated)
+ }
+
+ class EpisodeActionPostResponse {
+ <<create>> EpisodeActionPostResponse(List<Pair<String, String>> updateURLs)
+ long getTimestamp()
+ List<Pair<String, String>> getUpdatedURLs()
+ }
+
+ class EpisodeActionPost {
+ <<create>> EpisodeActionPost(String podcastURL, String episodeURL, Action action, LocalDateTime timestamp, int started, int position)
+ String getPodcastURL()
+ String getEpisodeURL()
+ int getGUID()
+ Action getAction()
+ LocalDateTime getTimestamp()
+ int getStarted()
+ int getPosition()
+ EpisodeAction getEpisodeAction()
+ }
+
+ class EpisodeActionPostRequest {
+ <<create>> EpisodeActionPostRequest(List<EpisodeActionPost> episodeActionPosts)
+ List<EpisodeActionPost> getEpisodeActionPosts()
+ }
+
+ class EpisodeActionGetResponse {
+ <<create>> EpisodeActionGetResponse(List<EpisodeActionPost> episodeActionPosts)
+ List<EpisodeActionPost> getEpisodeActionPosts()
+ long getTimestamp()
+ }
+ }
+}
+
+EpisodeActionPost -o EpisodeActionGetResponse
+EpisodeActionPost -o EpisodeActionPostRequest
+' EpisodeAction <.. EpisodeActionDataAccessService: DB
+' Episode <.. EpisodeActionDataAccessService: DB
+EpisodeActionDao <.. EpisodeActionService: <<use>>
+EpisodeActionService --o EpisodeActionController
+EpisodeActionDao <|. EpisodeActionDataAccessService: <<realize>>
+
+@enduml
+
diff --git a/21-implementierungsheft-kolloquium/assets/diagrams/classdiagram-model.puml b/21-implementierungsheft-kolloquium/assets/diagrams/classdiagram-model.puml
new file mode 100644
index 0000000..72ad49f
--- /dev/null
+++ b/21-implementierungsheft-kolloquium/assets/diagrams/classdiagram-model.puml
@@ -0,0 +1,109 @@
+@startuml
+
+package model <<Frame>> {
+ class Subscription {
+ <<create>> Subscription(String url, String title)
+ int getID()
+ String getURL()
+ long getLastActionTimestamp()
+ String getTitle()
+ }
+
+ class SubscriptionAction {
+ <<create>> SubscriptionAction(int userID, int subscriptionID)
+ int getID()
+ int getUserID()
+ int getSubscriptionID()
+ long getTimestamp()
+ boolean getAdded()
+ }
+
+ class Episode {
+ <<create>> Episode(int subscriptionID, int id, String url, String title, String thumbnailURL, int total)
+ int getSubscriptionID()
+ int getID()
+ int getGUID()
+ String getURL()
+ String getTitle()
+ int getTotal()
+ }
+
+ enum Action {
+ Download
+ Play
+ Delete
+ New
+ Flattr
+ String getJsonProperty()
+ }
+
+ class EpisodeAction {
+ <<create>> EpisodeAction(Action action, LocalDateTime timestamp, int started, int position)
+ int getEpisodeID()
+ Action getAction()
+ long getTimestamp()
+ int getStarted()
+ int getPosition()
+ void setEpisodeID()
+ EpisodeActionPost getEpisodeActionPost(String podcastURL, String episodeURL)
+ }
+
+ interface UserDetails {
+ String getUsername()
+ String getPassword()
+ Collection<Authority> getAuthorities()
+ boolean isAccountExpired()
+ boolean isAccountLocked()
+ boolean isCredentialsNonExpired()
+ boolean isEnabled()
+ }
+ note left
+ Aus org.springframework.security.core.userdetails.
+ Wird für die Schnittstelle UserDetailsManager benötigt.
+ Stellt wichtige Informationen eines Users bereit.
+ Diese werden nur indirekt von Spring Security
+ benutzt, indem sie vorher in Authentication Objekten
+ gekapselt werden.
+ end note
+
+ class User {
+ --
+ <<create>> User(String username, String password)
+ int getID()
+ String getSessionToken()
+ boolean getEmailIsValidated()
+ .. interface methods ..
+ String getUsername()
+ String getPassword()
+ Collection<Authority> getAuthorities()
+ boolean isAccountExpired()
+ boolean isAccountLocked()
+ boolean isCredentialsNonExpired()
+ boolean isEnabled()
+ }
+
+ interface GrantedAuthority {
+ String getAuthority()
+ }
+ note right
+ Aus org.springframework.security.core.
+ Wird für die Schnittstelle UserDetails benötigt.
+ Repräsentiert eine Autorisierung, die einem
+ Authentication Objekt gewährt wird.
+ end note
+
+ class Authority {
+ <<create>> Authority()
+ String getAuthority()
+ }
+}
+
+Subscription <. SubscriptionAction: ID
+Action <-- EpisodeAction
+EpisodeAction .> Episode: ID
+UserDetails <|.. User: <<realize>>
+User -> Authority
+GrantedAuthority <|.. Authority: <<realize>>
+
+@enduml
+
diff --git a/21-implementierungsheft-kolloquium/assets/diagrams/classdiagram-subscriptions.puml b/21-implementierungsheft-kolloquium/assets/diagrams/classdiagram-subscriptions.puml
new file mode 100644
index 0000000..432f185
--- /dev/null
+++ b/21-implementierungsheft-kolloquium/assets/diagrams/classdiagram-subscriptions.puml
@@ -0,0 +1,75 @@
+@startuml
+
+package subscriptionsAPI <<Frame>> {
+ package subscriptionDataAccessLayer <<Frame>> {
+ class SubscriptionDataAccessService <<@Repository>> {
+ <<create>> SubscriptionDataAccessService(JpaTemplate jpaTemplate)
+ int uploadSubscriptions(String username, List<SubscriptionAction> subscriptions)
+ List<String> getSubscriptions(String username)
+ List<String> getSubscriptionsSince(String username, LocalDateTime time)
+ int addSubscriptions(String username, List<SubscriptionAction> addedSubscriptions)
+ int removeSubscriptions(String username, List<SubscriptionAction> removedSubscriptions)
+ List<SubscriptionTitles> getTitles(String username)
+ }
+
+ interface SubscriptionDao {
+ int uploadSubscriptions(String username, List<SubscriptionAction> subscriptions)
+ List<String> getSubscriptions(String username)
+ List<String> getSubscriptionsSince(String username, LocalDateTime time)
+ int addSubscriptions(String username, List<SubscriptionAction> addedSubscriptions)
+ int removeSubscriptions(String username, List<SubscriptionAction> removedSubscriptions)
+ List<SubscriptionTitles> getTitles(String username)
+ }
+ }
+
+ package subscriptionService <<Frame>> {
+ class SubscriptionService <<@Service>> {
+ <<create>> SubscriptionService(SubscriptionDao subscriptionDao)
+ int uploadSubscriptions(String username, List<SubscriptionAction> subscriptions)
+ List<String> getSubscriptions(String username)
+ List<String> getSubscriptionsSince(String username, LocalDateTime time)
+ int addSubscriptions(String username, List<SubscriptionAction> addedSubscriptions)
+ int removeSubscriptions(String username, List<SubscriptionAction> removedSubscriptions)
+ List<SubscriptionTitles> getTitles(String username)
+ }
+ }
+
+ package subscriptionController <<Frame>> {
+ class SubscriptionController <<@Controller>>{
+ ' @Autowired
+ <<create>> SubscriptionController(SubscriptionService subscriptionService)
+ ' @GetMapping
+ ResponseEntity<List<String>> getSubscriptions(String username, String deviceID, String functionJSONP)
+ ' @PutMapping
+ ResponseEntity<String> uploadSubscriptions(String username, String deviceID, List<String> subscriptions)
+ ' @PostMapping
+ ResponseEntity<SubscriptionDelta> applySubscriptionDelta(String username, String deviceID, SubscriptionDelta delta)
+ ' @GetMapping
+ ResponseEntity<SubscriptionDelta> getSubscriptionDelta(String username, String deviceID, long since)
+ ResponseEntity<List<SubscriptionTitles>> getTitles(String username, String deviceID)
+ }
+
+ class SubscriptionTitles {
+ <<create>> SubscriptionTitles(Subscription subscription, List<EpisodeActionPost> episodeTitles)
+ Subscription getSubscription()
+ List<EpisodeActionPost> getEpisodesTitles()
+ }
+
+ class SubscriptionDelta {
+ <<create>> SubscriptionDelta(List<String> add, List<String> remove)
+ List<String> getRemove()
+ LocalDate getTimestamp()
+ List<List<String>> getUpdate_urls()
+ }
+ }
+
+}
+
+' Subscription <.. SubscriptionDataAccessService: DB
+' SubscriptionAction <.. SubscriptionDataAccessService: DB
+SubscriptionService --o SubscriptionController
+SubscriptionDao <.. SubscriptionService: <<use>>
+SubscriptionDao <|. SubscriptionDataAccessService: <<realize>>
+
+@enduml
+
diff --git a/21-implementierungsheft-kolloquium/assets/diagrams/classdiagram-util.puml b/21-implementierungsheft-kolloquium/assets/diagrams/classdiagram-util.puml
new file mode 100644
index 0000000..03dfc9a
--- /dev/null
+++ b/21-implementierungsheft-kolloquium/assets/diagrams/classdiagram-util.puml
@@ -0,0 +1,43 @@
+@startuml
+
+package util <<Frame>> {
+ class RSSParser {
+ <<create>> RSSParser(String subscriptionURL)
+ String getSubscriptionTitle()
+ List<Episode> getEpisodes()
+ Episode getEpisodeForURL(String episodeURL)
+ }
+ note bottom
+ Verwendet intern Spring um
+ HTTP-Anfragen zu erstellen.
+ end note
+
+ class CleanCronJob {
+ <<create>> CleanCronJob(JdbcUserDetailsManager jdbcUserDetailsManager)
+ void cleanInvalidUsers()
+ }
+ note bottom
+ Hintergrundservice, der in periodischen Abständen
+ Nutzer, die ihre E-Mail-Adresse nicht nach 24 Stunden
+ bestätigt haben, wieder aus der Datenbank löscht.
+ (Auf die Assoziation zu JdbcUserDetailsManager wird
+ im Sinne der Übersichtlichkeit verzichtet.)
+ end note
+
+ class ResponseEntity<T> {
+ <<create>> ResponseEntity(T body, HttpStatusCode status)
+ T getBody()
+ HttpStatusCode getStatusCode()
+ }
+ note bottom
+ Aus org.springframework.http.
+ Erweitert die Klasse HttpEntity, welche
+ ein HTTP Anfrage- oder Antwort-Objekt
+ repräsentiert, durch einen HttpStatusCode.
+ Wird von den Controller-Methoden als
+ Rückgabewert verwendet.
+ end note
+}
+
+@enduml
+
diff --git a/21-implementierungsheft-kolloquium/assets/diagrams/classdiagram.puml b/21-implementierungsheft-kolloquium/assets/diagrams/classdiagram.puml
new file mode 100644
index 0000000..f833aa2
--- /dev/null
+++ b/21-implementierungsheft-kolloquium/assets/diagrams/classdiagram.puml
@@ -0,0 +1,68 @@
+@startuml
+' skinparam linetype ortho
+' skinparam groupInheritance 2
+allowmixing
+
+!include classdiagram-authentication.puml
+!include classdiagram-episode-actions.puml
+!include classdiagram-model.puml
+!include classdiagram-subscriptions.puml
+!include classdiagram-util.puml
+
+class SecurityConfigurationBasicAuth {
+ <<create>> SecurityConfigurationBasicAuth()
+ PasswordEncoder encoder()
+ UserDetailsManager userDetailsService()
+ SecuryFilterChain fiterChain(HTTPSecurity http) throws Excpetion
+}
+note top
+ Erstellt einen Servlet Filter (springSecurityFilterChain)
+ der für die gesamte Sicherheit zuständig ist (Schutz der URLs,
+ Validierung von Anmeldedaten, Weiterleitung zur Anmeldung, etc.).
+end note
+
+class PSEApplication {
+ <<create>> PSEApplication()
+ void main(String[] args)
+}
+
+database Datenbank
+Datenbank <-[hidden]d- subscriptionsAPI
+Datenbank <-[hidden]d- episodeActionsAPI
+Datenbank <-[hidden]d- authenticationAPI
+() SQL as SQLSub
+() SQL as SQLAuth
+() SQL as SQLEpisode
+
+Datenbank -- SQLSub
+Datenbank -- SQLAuth
+Datenbank -- SQLEpisode
+
+Subscription --o SubscriptionTitles
+EpisodeActionPost -o SubscriptionTitles
+UserDetailsManager <.. SecurityConfigurationBasicAuth: <<use>>
+
+SubscriptionController ..o PSEApplication
+AuthenticationController ..o PSEApplication
+EpisodeActionController ..o PSEApplication
+SecurityConfigurationBasicAuth ..o PSEApplication
+
+PSEApplication --() HTTP
+
+SQLSub )-- SubscriptionDataAccessService: JPA
+' SQLAuth )-- AuthenticationDataAccessService: JPA
+SQLAuth )-- JdbcUserDetailsManager: JDBC
+SQLEpisode )-- EpisodeActionDataAccessService: JPA
+
+RSSParser <. SubscriptionDataAccessService: <<use>>
+RSSParser <. EpisodeActionDataAccessService: <<use>>
+' JdbcUserDetailsManager <-- CleanCronJob
+
+model .o Datenbank: ORM (User, SubscriptionAction, Subscription, EpisodeAction, Episode)
+' Datenbank o.. Subscription: ORM
+' Datenbank o.. SubscriptionAction: ORM
+' Datenbank o.. Episode: ORM
+' Datenbank o.. EpisodeAction: ORM
+' Datenbank o.. User: ORM
+
+@enduml
diff --git a/21-implementierungsheft-kolloquium/assets/diagrams/componentdiagram.puml b/21-implementierungsheft-kolloquium/assets/diagrams/componentdiagram.puml
new file mode 100644
index 0000000..dea4a1d
--- /dev/null
+++ b/21-implementierungsheft-kolloquium/assets/diagrams/componentdiagram.puml
@@ -0,0 +1,53 @@
+@startuml
+
+[App] as app
+[VueRouter] as router
+[NavbarComponent] as navbar
+[LoginPage] as login_page
+[SubscriptionsPage] as abo_page
+[EpisodesPage] as episodes_page
+[SettingsPage] as settings_page
+[ForgotPasswordPage] as forgot_page
+[ResetPasswordPage] as reset_page
+note top
+ Wird in der E-Mail zum Zurücksetzen des Passworts mit dem JWT-Token verlinkt.
+ Sendet das alte und neue Passwort und den JWT an die API.
+end note
+[RegistrationPage] as registration_page
+
+[SubscriptionComponent] as sub
+[EpisodeComponent] as episode
+[LastUpdateComponent] as last_update
+[PasswordValidatorComponent] as password
+
+app --> router
+
+app --> navbar
+router --> login_page
+router --> forgot_page
+router --> reset_page
+router --> registration_page
+router --> abo_page
+router --> episodes_page
+router --> settings_page
+
+navbar -[hidden] router
+
+episodes_page -[hidden] abo_page
+login_page -[hidden] forgot_page
+registration_page -[hidden] reset_page
+abo_page -[hidden] settings_page
+forgot_page -[hidden] episodes_page
+' forgot_page -[hidden] settings_page
+
+abo_page --> sub
+episodes_page --> episode
+
+sub --> last_update
+episode --> last_update
+
+settings_page --> password
+reset_page --> password
+registration_page --> password
+
+@enduml
diff --git a/21-implementierungsheft-kolloquium/assets/diagrams/db.puml b/21-implementierungsheft-kolloquium/assets/diagrams/db.puml
new file mode 100644
index 0000000..bdefaea
--- /dev/null
+++ b/21-implementierungsheft-kolloquium/assets/diagrams/db.puml
@@ -0,0 +1,78 @@
+@startuml
+' Type Symbol
+' Zero or One |o--
+' Exactly One ||--
+' Zero or Many }o--
+' One or Many }|--
+
+skinparam linetype ortho
+
+entity User {
+ * int id <<unique>>
+ * <u>String email</u>
+ * String password
+ * boolean verified
+ * long created_at
+}
+
+entity SubscriptionAction {
+ * int id <<unique>>
+ * <u>int user_id</u>
+ * long timestamp
+ * int subscription_id
+ * boolean added
+}
+
+entity Subscription {
+ * int id <<unique>>
+ * <u>String url</u>
+ * long timestamp
+ * String title
+}
+
+entity Episode {
+ * int id <<unique>>
+ * <u>int guid <<unique>></u>
+ * <u>String url</u>
+ * String title
+ * int total
+ * int subscription_id
+}
+note right
+ Wenn der Client eine GUID aus dem Feed mitsendet, wird
+ diese statt der URL verwendet um die Episode zu finden.
+ So wird die Episode auch noch gefunden, nachdem sich
+ die URL geändert hat.
+end note
+note bottom of Episode
+ Wenn für die Episoden-URL einer EpisodeAction noch keine Episode in der Datenbank steht,
+ dann schreibe dafür ein Dummy-Objekt in Datenbank und lade asynchron die Episoden der Subscription.
+ Ersetze dann die Dummy-Objekte durch die Episoden und setze den Timestamp der Subscription auf
+ die aktuelle Zeit.
+ Um DoS-Angriffe auf den Backend-Server abzuwenden, können die Episoden einer Subscription erst
+ nach einer Stunde erneut gefetched werden. Bis dahin werden für EpisodeActions, die sich auf noch
+ nicht geladene Episoden beziehen, nur Dummy-Objekte für die Episoden in die Datenbank geschrieben.
+ Es sei noch darauf hingewiesen, dass diese Dummy-Episoden bei Anfragen nicht mit ausgegeben werden.
+end note
+
+entity EpisodeAction {
+ * int id <<unique>>
+ * <u>int user_id</u>
+ * int episode_id
+ * long timestamp
+ * int action
+ * int started
+ * int position
+}
+note right
+ Speichere für jede Episode
+ nur letzte Play-Action.
+endnote
+
+User ||--o{ EpisodeAction
+User ||--o{ SubscriptionAction
+SubscriptionAction }|--|| Subscription
+EpisodeAction }|--|| Episode
+Subscription ||-right-|{ Episode
+
+@enduml
diff --git a/21-implementierungsheft-kolloquium/assets/diagrams/deployment.puml b/21-implementierungsheft-kolloquium/assets/diagrams/deployment.puml
new file mode 100644
index 0000000..b8d0491
--- /dev/null
+++ b/21-implementierungsheft-kolloquium/assets/diagrams/deployment.puml
@@ -0,0 +1,59 @@
+@startuml
+
+node "<<device>> \nBackend Server" as backendServer{
+ database " <<database system>> \n MariaDB Server 10.6" as database {
+ rectangle rectangle1 [
+ <<schema>>
+ User
+ ]
+ rectangle rectangle2 [
+ <<schema>>
+ SubscriptionAction
+ ]
+ rectangle rectangle3 [
+ <<schema>>
+ EpisodeAction
+ ]
+ rectangle rectangle4 [
+ <<schema>>
+ Subscription
+ ]
+ rectangle rectangle5 [
+ <<schema>>
+ Episode
+ ]
+ }
+
+ node "<<framework>> \nJava Spring" as javaSpring{
+ node " <<device>> \n Tomcat Webserver"
+ }
+}
+
+node "<<device>> \nFrontend" as frontendServer {
+
+}
+
+node "<<device>> \nEndgerät" as terminal {
+ node "<<application>> \nBrowser" as browser
+ node "<<application>> \nPodcatcher" as podcatcher
+}
+
+backendServer "1" - "*" podcatcher
+
+node "<<device>> \nFrontend Server" as frontendServer{
+ node "<<framework>> \nVue.js" as vuejs {
+
+ }
+}
+
+podcatcher -[hidden] browser
+
+backendServer - "1" frontendServer
+
+database "1" -- "1" javaSpring
+
+browser "*" -- frontendServer
+
+
+
+@enduml
diff --git a/21-implementierungsheft-kolloquium/assets/diagrams/sequencediagram-forgotAndResetPW.puml b/21-implementierungsheft-kolloquium/assets/diagrams/sequencediagram-forgotAndResetPW.puml
new file mode 100644
index 0000000..603130c
--- /dev/null
+++ b/21-implementierungsheft-kolloquium/assets/diagrams/sequencediagram-forgotAndResetPW.puml
@@ -0,0 +1,41 @@
+@startuml
+
+skinparam ParticipantPadding 30
+
+participant AuthenticationController << (C, #ADD1B2) @Controller >>
+-> AuthenticationController: ""POST /api/2/auth/forgot.json"" \n//@RequestBody ForgotPasswordRequest forgotPasswordRequest// \n\n-> forgotPassword(//forgotPasswordRequest//)
+activate AuthenticationController
+participant AuthenticationService << (C, #ADD1B2) @Service >>
+AuthenticationController -> AuthenticationService: forgotPassword(//forgotPasswordRequest//)
+activate AuthenticationService
+participant JavaMailSenderImpl << (C, #ADD1B2) >>
+AuthenticationService -> JavaMailSenderImpl: create link to reset password with JWT as URL parameter \n-> send(SimpleMailMessage simpleMessage) with link
+activate JavaMailSenderImpl
+<<- JavaMailSenderImpl: sends email with link containing a JWT to reset password
+JavaMailSenderImpl --> AuthenticationService
+deactivate JavaMailSenderImpl
+AuthenticationService --> AuthenticationController: int indicating status
+deactivate AuthenticationService
+<-- AuthenticationController: ResponseEntity<Integer> indicating status \n\n-> ""HTTP status code""
+deactivate AuthenticationController
+||60||
+-> AuthenticationController: ""PUT /api/2/auth/{username}/resetpassword.json"" \n//@RequestParam String jwt// \n//@RequestBody ResetPasswordRequest resetPasswordRequest// \n\n-> login user (""username"") via JWT (//jwt//) \n-> resetPassword(""username"", //resetPasswordRequest//)
+activate AuthenticationController
+AuthenticationController -> AuthenticationService: resetPassword(""username"", //resetPasswordRequest//)
+activate AuthenticationService
+participant JdbcUserDetailsManager << (C, #ADD1B2) @Repository >>
+AuthenticationService -> JdbcUserDetailsManager: String oldPassword = //resetPasswordRequest//.getOldPassword() \nString newPassword = //resetPasswordRequest//.getNewPassword() \n-> changePassword(newPassword, oldPassword)
+activate JdbcUserDetailsManager
+database Database
+JdbcUserDetailsManager -> Database: change password of logged in user
+activate Database
+Database --> JdbcUserDetailsManager
+deactivate Database
+JdbcUserDetailsManager --> AuthenticationService: int indicating status
+deactivate JdbcUserDetailsManager
+AuthenticationService --> AuthenticationController: int indicating status
+deactivate AuthenticationService
+<-- AuthenticationController: ResponseEntity<Integer> indicating status \n\n-> ""HTTP status code""
+deactivate AuthenticationController
+
+@enduml \ No newline at end of file
diff --git a/21-implementierungsheft-kolloquium/assets/diagrams/sequencediagram-getEpisodeActions.puml b/21-implementierungsheft-kolloquium/assets/diagrams/sequencediagram-getEpisodeActions.puml
new file mode 100644
index 0000000..47497d5
--- /dev/null
+++ b/21-implementierungsheft-kolloquium/assets/diagrams/sequencediagram-getEpisodeActions.puml
@@ -0,0 +1,38 @@
+@startuml
+
+' title =**Get All Episode Actions**
+
+participant EpisodeActionController << (C, #ADD1B2) @Controller >>
+-> EpisodeActionController: ""GET /api/2/episodes/{username}.json"" \n//@RequestParam("device") String deviceID// \n//@RequestParam("aggregated") boolean aggregated// \n\n-> getEpisodeActions(""username"", //deviceID//, //aggregated//)
+note right
+ Die Parameter //deviceID// und //aggregated// werden ignoriert,
+ da nicht zwischen Geräten unterschieden und für jede
+ Episode sowieso nur die letzte Play-Action gespeichert
+ wird. Dies gilt für alle GET-Anfragen der Episode Actions API.
+end note
+activate EpisodeActionController
+participant EpisodeActionService << (C, #ADD1B2) @Service >>
+EpisodeActionController -> EpisodeActionService: getEpisodeActions(""username"")
+activate EpisodeActionService
+participant EpisodeActionDataAccessService << (C, #ADD1B2) @Repository >>
+EpisodeActionService -> EpisodeActionDataAccessService: getEpisodeActions(""username"")
+activate EpisodeActionDataAccessService
+EpisodeActionDataAccessService -> EpisodeActionDataAccessService: getEpisodeActionsSince(""username"", \nLocalDateTime.MIN.toEpochSecond(ZoneOffset.UTC))
+database Database
+activate EpisodeActionDataAccessService
+EpisodeActionDataAccessService -> Database: get all EpisodeActions for all subscribed podcasts
+activate Database
+Database --> EpisodeActionDataAccessService: List<EpisodeAction> selectedEpisodeActions \n-> then remove all older than LocalDateTime.MIN (none)
+EpisodeActionDataAccessService -> Database: join EpisodeActions in selectedEpisodeActions with episodeURL of Episode
+Database --> EpisodeActionDataAccessService
+deactivate Database
+EpisodeActionDataAccessService --> EpisodeActionDataAccessService: List<EpisodeActionPost> episodeActionPosts
+deactivate EpisodeActionDataAccessService
+EpisodeActionDataAccessService --> EpisodeActionService: List<EpisodeActionPost> episodeActionPosts
+deactivate EpisodeActionDataAccessService
+EpisodeActionService --> EpisodeActionController: List<EpisodeActionPost> episodeActionPosts
+deactivate EpisodeActionService
+<-- EpisodeActionController: ResponseEntity<EpisodeActionGetResponse> response \n\n-> ""HTTP status code"" \n-> ""JSON""
+deactivate EpisodeActionController
+
+@enduml \ No newline at end of file
diff --git a/21-implementierungsheft-kolloquium/assets/diagrams/sequencediagram-getEpisodeActionsOfPodcastSince.puml b/21-implementierungsheft-kolloquium/assets/diagrams/sequencediagram-getEpisodeActionsOfPodcastSince.puml
new file mode 100644
index 0000000..d8797d1
--- /dev/null
+++ b/21-implementierungsheft-kolloquium/assets/diagrams/sequencediagram-getEpisodeActionsOfPodcastSince.puml
@@ -0,0 +1,32 @@
+@startuml
+
+' title =**Get Episode Actions of Podcast Since**
+
+participant EpisodeActionController << (C, #ADD1B2) @Controller >>
+-> EpisodeActionController: ""GET /api/2/episodes/{username}.json"" \n//@RequestParam("podcast") String podcastURL// \n//@RequestParam("device") String deviceID// \n//@RequestParam("since") long since// \n//@RequestParam("aggregated") boolean aggregated// \n\n-> getEpisodeActionsOfPodcastSince(""username"", //podcastURL//, //deviceID//, //since//, //aggregated//)
+note right
+ Die Parameter //deviceID// und //aggregated// werden ignoriert.
+ Siehe Notiz in Sequenzdiagramm **Get All Episode Actions**.
+end note
+activate EpisodeActionController
+participant EpisodeActionService << (C, #ADD1B2) @Service >>
+EpisodeActionController -> EpisodeActionService: getEpisodeActionsOfPodcastSince(""username"", //podcastURL//, //since//)
+activate EpisodeActionService
+participant EpisodeActionDataAccessService << (C, #ADD1B2) @Repository >>
+EpisodeActionService -> EpisodeActionDataAccessService: getEpisodeActionsOfPodcastSince(""username"", //podcastURL//, //since//)
+activate EpisodeActionDataAccessService
+database Database
+EpisodeActionDataAccessService -> Database: get all EpisodeActions the given podcast (//podcastURL//)
+activate Database
+Database --> EpisodeActionDataAccessService: List<EpisodeAction> selectedEpisodeActions \n-> then remove all older than //since//
+EpisodeActionDataAccessService -> Database: join EpisodeActions in selectedEpisodeActions with episodeURL of Episode
+Database --> EpisodeActionDataAccessService
+deactivate Database
+EpisodeActionDataAccessService --> EpisodeActionService: List<EpisodeActionPost> episodeActionPosts
+deactivate EpisodeActionDataAccessService
+EpisodeActionService --> EpisodeActionController: List<EpisodeActionPost> episodeActionPosts
+deactivate EpisodeActionService
+<-- EpisodeActionController: ResponseEntity<EpisodeActionGetResponse> response \n\n-> ""HTTP status code"" \n-> ""JSON""
+deactivate EpisodeActionController
+
+@enduml \ No newline at end of file
diff --git a/21-implementierungsheft-kolloquium/assets/diagrams/sequencediagram-getSubscriptions.puml b/21-implementierungsheft-kolloquium/assets/diagrams/sequencediagram-getSubscriptions.puml
new file mode 100644
index 0000000..4d8ab90
--- /dev/null
+++ b/21-implementierungsheft-kolloquium/assets/diagrams/sequencediagram-getSubscriptions.puml
@@ -0,0 +1,38 @@
+@startuml
+
+' title =**Get All Subscriptions**
+
+participant SubscriptionController << (C, #ADD1B2) @Controller >>
+-> SubscriptionController: ""GET /subscriptions/{username}.json"" \n"" /subscriptions/{username}/{deviceid}.json"" \n//@RequestParam("jsonp") String functionJSONP// \n\n-> getSubscriptions(""username"", ""deviceid"", //functionJSONP//)
+activate SubscriptionController
+note right
+ Die Parameter ""deviceid"" und
+ //functionJSONP// werden ignoriert,
+ da nicht zwischen Geräten unterschieden
+ und JSONP nicht unterstützt wird.
+end note
+participant SubscriptionService << (C, #ADD1B2) @Service >>
+SubscriptionController -> SubscriptionService: getSubscriptions(""username"")
+activate SubscriptionService
+participant SubscriptionDataAccessService << (C, #ADD1B2) @Repository >>
+SubscriptionService -> SubscriptionDataAccessService: getSubscriptions(""username"")
+activate SubscriptionDataAccessService
+SubscriptionDataAccessService -> SubscriptionDataAccessService: getSubscriptionsSince(""username"", LocalDateTime.MIN)
+database Database
+activate SubscriptionDataAccessService
+SubscriptionDataAccessService -> Database: get all Subscriptions for ""username""
+activate Database
+Database --> SubscriptionDataAccessService: List<Subscription> subscriptions
+SubscriptionDataAccessService -> Database: get Podcasts from Subscriptions
+Database --> SubscriptionDataAccessService: List<Podcast> subscribedPodcasts
+deactivate Database
+SubscriptionDataAccessService --> SubscriptionDataAccessService: List<String> podcastURLs
+deactivate SubscriptionDataAccessService
+SubscriptionDataAccessService --> SubscriptionService: List<String> podcastURLs
+deactivate SubscriptionDataAccessService
+SubscriptionService --> SubscriptionController: List<String> podcastURLs
+deactivate SubscriptionService
+<-- SubscriptionController: ResponseEntity<List<String>> podcastURLs \n \n-> ""HTTP status code"" \n-> ""JSON""
+deactivate SubscriptionController
+
+@enduml \ No newline at end of file
diff --git a/21-implementierungsheft-kolloquium/assets/diagrams/sequencediagram-register.puml b/21-implementierungsheft-kolloquium/assets/diagrams/sequencediagram-register.puml
new file mode 100644
index 0000000..b7b7aa1
--- /dev/null
+++ b/21-implementierungsheft-kolloquium/assets/diagrams/sequencediagram-register.puml
@@ -0,0 +1,26 @@
+@startuml
+
+' title =**Register**
+
+participant AuthenticationController << (C, #ADD1B2) @Controller >>
+-> AuthenticationController: ""POST /api/2/auth/register.json"" \n//@RequestBody UserDetails user// \n\n-> registerUser(//user//)
+activate AuthenticationController
+participant AuthenticationService << (C, #ADD1B2) @Service >>
+AuthenticationController -> AuthenticationService: registerUser(//user//)
+activate AuthenticationService
+participant JdbcUserDetailsManager << (C, #ADD1B2) @Repository >>
+AuthenticationService -> JdbcUserDetailsManager: createUser(//user//)
+activate JdbcUserDetailsManager
+database Database
+JdbcUserDetailsManager -> Database: create new User with given UserDetails (//user//)
+activate Database
+Database --> JdbcUserDetailsManager
+deactivate Database
+JdbcUserDetailsManager --> AuthenticationService: int indicating status
+deactivate JdbcUserDetailsManager
+AuthenticationService --> AuthenticationController: int indicating status
+deactivate AuthenticationService
+<-- AuthenticationController: ResponseEntity<Integer> indicating status \n\n-> ""HTTP status code""
+deactivate AuthenticationController
+
+@enduml \ No newline at end of file
diff --git a/21-implementierungsheft-kolloquium/assets/diagrams/sequencediagram-uploadEpisodeActions.puml b/21-implementierungsheft-kolloquium/assets/diagrams/sequencediagram-uploadEpisodeActions.puml
new file mode 100644
index 0000000..d3dac57
--- /dev/null
+++ b/21-implementierungsheft-kolloquium/assets/diagrams/sequencediagram-uploadEpisodeActions.puml
@@ -0,0 +1,38 @@
+@startuml
+
+' title =**Upload Episode Actions**
+
+participant EpisodeActionController << (C, #ADD1B2) @Controller >>
+-> EpisodeActionController: ""POST /api/2/episodes/{username}.json"" \n//@RequestBody EpisodeActionPostRequest episodeActionPostRequest// \n\n-> addEpisodeActions(""username"", //episodeActionPostRequest//)
+activate EpisodeActionController
+participant EpisodeActionService << (C, #ADD1B2) @Service >>
+EpisodeActionController -> EpisodeActionService: addEpisodeActions(""username"", \nepisodeActionPosts = //episodeActionPostRequest//.getEpisodeActionPosts())
+activate EpisodeActionService
+participant EpisodeActionDataAccessService << (C, #ADD1B2) @Repository >>
+EpisodeActionService -> EpisodeActionDataAccessService: addEpisodeActions(""username"", episodeActionPosts)
+database Database
+activate EpisodeActionDataAccessService
+loop for each EpisodeActionPost in episodeActionPosts -> episodeAction = episodeActionPost.getEpisodeAction()
+opt episodeAction.getAction().equals(Action.PLAY)
+EpisodeActionDataAccessService -> Database: set episodeID field of episodeAction for this ""username"" via podcastURL and episodeURL
+activate Database
+Database --> EpisodeActionDataAccessService
+EpisodeActionDataAccessService -> Database: get last EpisodeAction with this episodeID if present
+Database --> EpisodeActionDataAccessService: Optional<EpisodeAction> lastEpisodeAction
+opt lastEpisodeAction.isPresent()
+EpisodeActionDataAccessService -> Database: replace lastEpisodeAction with episodeAction
+else else
+EpisodeActionDataAccessService -> Database: add episodeAction to DB as new entry
+end
+Database --> EpisodeActionDataAccessService
+deactivate Database
+end
+end
+EpisodeActionDataAccessService --> EpisodeActionService: long latestTimestamp
+deactivate EpisodeActionDataAccessService
+EpisodeActionService --> EpisodeActionController: LocalDateTime timestamp = LocalDateTime.ofEpochSecond(latestTimestamp, 0, ZoneOffset.UTC)
+deactivate EpisodeActionService
+<-- EpisodeActionController: ResponseEntity<EpisodeActionPostResponse> \n(with empty list for updateURLs) \n\n-> ""HTTP status code"" \n-> ""JSON""
+deactivate EpisodeActionController
+
+@enduml \ No newline at end of file
diff --git a/21-implementierungsheft-kolloquium/assets/diagrams/sequencediagram-uploadSubscriptions.puml b/21-implementierungsheft-kolloquium/assets/diagrams/sequencediagram-uploadSubscriptions.puml
new file mode 100644
index 0000000..1edc8cf
--- /dev/null
+++ b/21-implementierungsheft-kolloquium/assets/diagrams/sequencediagram-uploadSubscriptions.puml
@@ -0,0 +1,32 @@
+@startuml
+
+' title =**Upload Subscriptions**
+
+participant SubscriptionController << (C, #ADD1B2) @Controller >>
+-> SubscriptionController: ""PUT /subscriptions/{username}/{deviceid}.json"" \n//@RequestBody List<String> subscriptions// \n\n-> uploadSubscriptions(""username"", ""deviceid"", //subscriptions//)
+activate SubscriptionController
+participant SubscriptionService << (C, #ADD1B2) @Service >>
+SubscriptionController -> SubscriptionService: uploadSubscriptions(""username"", //subscriptions//)
+activate SubscriptionService
+participant SubscriptionDataAccessService << (C, #ADD1B2) @Repository >>
+SubscriptionService -> SubscriptionDataAccessService: uploadSubscriptions(""username"", //subscriptions//)
+activate SubscriptionDataAccessService
+database Database
+SubscriptionDataAccessService -> Database: delete all subsciptions of ""username""
+activate Database
+Database --> SubscriptionDataAccessService
+SubscriptionDataAccessService -> SubscriptionDataAccessService: addSubscriptions(""username"", //subscriptions//)
+activate SubscriptionDataAccessService
+SubscriptionDataAccessService -> Database: upload all subscriptions (//subscriptions//) for ""username""
+Database --> SubscriptionDataAccessService
+deactivate Database
+SubscriptionDataAccessService --> SubscriptionDataAccessService: int indicating status
+deactivate SubscriptionDataAccessService
+SubscriptionDataAccessService --> SubscriptionService: int indicating status
+deactivate SubscriptionDataAccessService
+SubscriptionService --> SubscriptionController: int indicating status
+deactivate SubscriptionService
+<-- SubscriptionController: ResponseEntity<String> with empty String for success \n\n-> ""HTTP status code"" \n-> ""JSON""
+deactivate SubscriptionController
+
+@enduml \ No newline at end of file
diff --git a/21-implementierungsheft-kolloquium/assets/episode.png b/21-implementierungsheft-kolloquium/assets/episode.png
new file mode 100644
index 0000000..c0db4a2
--- /dev/null
+++ b/21-implementierungsheft-kolloquium/assets/episode.png
Binary files differ
diff --git a/21-implementierungsheft-kolloquium/assets/gantt-plan.puml b/21-implementierungsheft-kolloquium/assets/gantt-plan.puml
new file mode 100644
index 0000000..0e90aa2
--- /dev/null
+++ b/21-implementierungsheft-kolloquium/assets/gantt-plan.puml
@@ -0,0 +1,31 @@
+@startgantt
+
+printscale daily zoom 5
+project starts on 2023-01-30
+
+-- Backend --
+[Controller-Schicht] on {Immanuel} lasts 2 days
+[Service-Schicht (Daten durchreichen)] on {Daniel} lasts 2 days
+[Authentifizierung] on {Gero} lasts 4 days
+[Model-Paket] on {Daniel} lasts 1 days
+[Datenbank aufsetzen] on {Immanuel} lasts 4 days
+[Util-Paket (RSSParser)] on {Daniel} {Lukas} lasts 6 days
+[DataAccess-Schicht] on {Immanuel} {Julius} lasts 8 days
+[Service-Schicht (Geschäftslogik)] on {Daniel} {Immanuel} lasts 8 days
+[Util-Paket (CleanCronJob)] on {Julius} lasts 2 days
+-- Frontend --
+[Komponenten] on {Gero} {Julius} {Lukas} lasts 15 days
+[API-Anbindung] on {Gero} {Lukas} lasts 4 days
+
+'Backend
+[Service-Schicht (Daten durchreichen)] starts at [Controller-Schicht]'s end
+[Datenbank aufsetzen] starts at [Model-Paket]'s end
+[Authentifizierung] starts at [Controller-Schicht]'s end
+[DataAccess-Schicht] starts at [Datenbank aufsetzen]'s end
+[Util-Paket (RSSParser)] starts at [Datenbank aufsetzen]'s end
+[Service-Schicht (Geschäftslogik)] starts at [DataAccess-Schicht]'s end
+[Util-Paket (CleanCronJob)] starts at [DataAccess-Schicht]'s end
+'Frontend
+[API-Anbindung] starts at [DataAccess-Schicht]'s end
+
+@endgantt \ No newline at end of file
diff --git a/21-implementierungsheft-kolloquium/assets/gantt-reality.puml b/21-implementierungsheft-kolloquium/assets/gantt-reality.puml
new file mode 100644
index 0000000..f726c56
--- /dev/null
+++ b/21-implementierungsheft-kolloquium/assets/gantt-reality.puml
@@ -0,0 +1,39 @@
+@startgantt
+
+printscale daily zoom 5
+project starts on 2023-01-30
+
+-- Backend --
+[Controller-Schicht] on {Immanuel} lasts 3 days
+[Model-Paket] on {Daniel} lasts 3 days
+[Datenbank aufsetzen] on {Immanuel} lasts 6 days
+[Util-Paket (RSSParser)] on {Daniel} {Lukas} lasts 32 days
+[DAO-Interfaces] on {Julius} {Immanuel} lasts 6 days
+[Authentifizierung] on {Immanuel} lasts 13 days
+[Service-Schicht mit Datenzugriff] on {Julius} lasts 14 days
+[Util-Paket (CleanCronJob)] on {Daniel} lasts 2 days
+[Docker] on {Daniel} lasts 12 days
+[EMailService] on {Gero} lasts 1 days
+-- Frontend --
+[Komponenten] on {Gero} {Julius} lasts 15 days
+[Mehrsprachigkeit] on {Lukas} lasts 5 days
+[Router] on {Gero} lasts 1 days
+[API-Anbindung] on {Gero} {Lukas} lasts 28 days
+[Error-Handling] on {Gero} lasts 5 days
+
+'Backend
+[Datenbank aufsetzen] starts at [Model-Paket]'s end
+[Util-Paket (RSSParser)] starts at [Datenbank aufsetzen]'s end
+[DAO-Interfaces] starts at [Datenbank aufsetzen]'s end
+[Authentifizierung] starts at [DAO-Interfaces]'s end
+[Service-Schicht mit Datenzugriff] starts at [DAO-Interfaces]'s end
+[Util-Paket (CleanCronJob)] starts at [DAO-Interfaces]'s end
+[Docker] starts at [Util-Paket (CleanCronJob)]'s end
+[EMailService] starts 2023-02-14
+'Frontend
+[Mehrsprachigkeit] starts 2023-02-01
+[Router] starts at [Mehrsprachigkeit]'s end
+[API-Anbindung] starts at [Router]'s end
+[Error-Handling] starts 2023-02-05
+
+@endgantt \ No newline at end of file
diff --git a/21-implementierungsheft-kolloquium/assets/help.png b/21-implementierungsheft-kolloquium/assets/help.png
new file mode 100644
index 0000000..39a1b84
--- /dev/null
+++ b/21-implementierungsheft-kolloquium/assets/help.png
Binary files differ
diff --git a/21-implementierungsheft-kolloquium/assets/lastupdate.png b/21-implementierungsheft-kolloquium/assets/lastupdate.png
new file mode 100644
index 0000000..e9b7f5c
--- /dev/null
+++ b/21-implementierungsheft-kolloquium/assets/lastupdate.png
Binary files differ
diff --git a/21-implementierungsheft-kolloquium/assets/logo.svg b/21-implementierungsheft-kolloquium/assets/logo.svg
new file mode 100644
index 0000000..1609066
--- /dev/null
+++ b/21-implementierungsheft-kolloquium/assets/logo.svg
@@ -0,0 +1,211 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ version="1.2"
+ width="87.589989mm"
+ height="52.16547mm"
+ viewBox="0 0 8758.9989 5216.547"
+ preserveAspectRatio="xMidYMid"
+ fill-rule="evenodd"
+ stroke-width="28.222"
+ stroke-linejoin="round"
+ xml:space="preserve"
+ id="svg206"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg">
+ <defs
+ class="ClipPathGroup"
+ id="defs8" />
+ <defs
+ id="defs51"><font
+ id="EmbeddedFont_1"
+ horiz-adv-x="2048"
+ horiz-origin-x="0"
+ horiz-origin-y="0"
+ vert-origin-x="512"
+ vert-origin-y="768"
+ vert-adv-y="1024">
+ <font-face
+ font-family="Noto Sans Display Light embedded"
+ units-per-em="2048"
+ font-weight="normal"
+ font-style="normal"
+ ascent="2170"
+ descent="609"
+ id="font-face10" />
+ <missing-glyph
+ horiz-adv-x="2048"
+ d="M 0,0 L 2047,0 2047,2047 0,2047 0,0 Z"
+ id="missing-glyph12" />
+ <glyph
+ unicode="y"
+ horiz-adv-x="927"
+ d="M 2,1089 L 127,1089 367,413 C 388,352 407,298 422,250 437,203 449,161 457,124 L 463,124 C 471,156 483,196 498,246 513,296 530,350 551,409 L 786,1089 913,1089 453,-193 C 418,-290 377,-364 328,-416 279,-468 213,-494 131,-494 107,-494 84,-493 63,-490 43,-487 25,-482 8,-476 L 8,-377 C 23,-383 40,-387 57,-391 75,-394 95,-396 117,-396 170,-396 214,-378 249,-342 284,-307 314,-252 340,-179 L 403,4 2,1089 Z"
+ id="glyph14" />
+ <glyph
+ unicode="t"
+ horiz-adv-x="610"
+ d="M 465,80 C 494,80 521,82 547,87 573,91 595,97 614,105 L 614,11 C 594,3 569,-5 541,-11 512,-17 481,-20 449,-20 363,-20 296,5 249,56 202,106 178,189 178,304 L 178,996 27,996 27,1061 178,1100 219,1350 295,1350 295,1090 608,1090 608,996 295,996 295,310 C 295,157 352,80 465,80 Z"
+ id="glyph16" />
+ <glyph
+ unicode="s"
+ horiz-adv-x="742"
+ d="M 817,289 C 817,191 782,115 713,61 643,7 545,-20 418,-20 347,-20 284,-14 228,-1 173,12 126,29 88,50 L 88,162 C 134,138 186,118 244,102 301,86 360,78 420,78 520,78 592,96 636,133 680,169 702,218 702,281 702,341 679,387 632,419 585,451 515,484 422,519 359,542 303,565 255,589 207,613 169,643 142,680 116,717 102,768 102,832 102,919 136,987 204,1037 271,1086 361,1110 473,1110 535,1110 592,1104 646,1092 700,1080 750,1063 795,1043 L 754,946 C 713,964 667,980 617,993 568,1006 518,1012 469,1012 388,1012 326,997 283,967 239,937 217,893 217,836 217,792 228,758 249,733 270,707 301,686 342,668 383,650 433,630 492,609 553,585 608,562 657,537 707,512 745,481 774,443 803,405 817,353 817,289 Z"
+ id="glyph18" />
+ <glyph
+ unicode="r"
+ horiz-adv-x="583"
+ d="M 596,1108 C 646,1108 692,1102 733,1091 L 717,983 C 674,995 632,1001 590,1001 497,1001 423,964 368,890 312,817 285,719 285,598 L 285,-1 168,-1 168,1089 266,1089 279,886 285,886 C 311,948 350,1000 402,1043 455,1086 520,1108 596,1108 Z"
+ id="glyph20" />
+ <glyph
+ unicode="o"
+ horiz-adv-x="927"
+ d="M 1030,547 C 1030,433 1012,333 976,248 940,164 887,98 818,51 749,4 665,-20 565,-20 471,-20 390,3 322,50 253,96 201,162 164,247 127,333 109,433 109,547 109,723 150,861 232,961 315,1061 429,1110 575,1110 672,1110 755,1087 822,1040 890,993 941,927 977,842 1012,757 1030,659 1030,547 Z M 229,547 C 229,407 257,294 312,208 368,123 453,80 567,80 685,80 771,123 826,209 882,295 909,408 909,547 909,637 898,717 875,787 851,856 815,911 766,951 717,990 653,1010 573,1010 459,1010 373,969 315,887 258,805 229,692 229,547 Z"
+ id="glyph22" />
+ <glyph
+ unicode="n"
+ horiz-adv-x="847"
+ d="M 633,1110 C 749,1110 838,1078 900,1014 962,950 993,850 993,713 L 993,1 877,1 877,705 C 877,809 854,885 810,935 766,985 701,1010 616,1010 395,1010 285,871 285,594 L 285,1 168,1 168,1090 262,1090 279,901 287,901 C 314,962 357,1011 416,1051 474,1091 547,1110 633,1110 Z"
+ id="glyph24" />
+ <glyph
+ unicode="m"
+ horiz-adv-x="1430"
+ d="M 1245,1110 C 1348,1110 1427,1080 1485,1018 1542,957 1571,860 1571,727 L 1571,1 1454,1 1454,723 C 1454,820 1434,892 1393,939 1352,986 1296,1010 1227,1010 1130,1010 1056,980 1005,919 953,858 928,764 928,637 L 928,1 811,1 811,723 C 811,820 791,892 750,939 709,986 653,1010 584,1010 487,1010 413,978 361,914 310,850 285,751 285,619 L 285,1 168,1 168,1090 262,1090 279,918 287,918 C 313,971 352,1016 403,1054 455,1092 521,1110 600,1110 675,1110 739,1093 791,1059 842,1025 879,975 899,908 L 907,908 C 936,972 980,1022 1038,1057 1097,1093 1166,1110 1245,1110 Z"
+ id="glyph26" />
+ <glyph
+ unicode="i"
+ horiz-adv-x="187"
+ d="M 227,1493 C 279,1493 305,1464 305,1405 305,1345 279,1315 227,1315 175,1315 150,1345 150,1405 150,1464 175,1493 227,1493 Z M 285,1090 L 285,0 168,0 168,1090 285,1090 Z"
+ id="glyph28" />
+ <glyph
+ unicode="h"
+ horiz-adv-x="847"
+ d="M 285,1059 C 285,1031 284,1003 283,977 281,951 279,926 276,901 L 285,901 C 312,962 355,1011 413,1051 471,1091 543,1110 629,1110 746,1110 836,1078 899,1014 962,950 993,850 993,713 L 993,1 877,1 877,705 C 877,809 854,885 810,935 766,985 701,1010 616,1010 395,1010 285,871 285,594 L 285,1 168,1 168,1557 285,1557 285,1059 Z"
+ id="glyph30" />
+ <glyph
+ unicode="f"
+ horiz-adv-x="689"
+ d="M 575,995 L 332,995 332,-1 213,-1 213,995 27,995 27,1058 213,1093 213,1202 C 213,1445 316,1566 522,1566 559,1566 593,1563 623,1557 653,1551 680,1544 705,1536 L 678,1439 C 655,1448 630,1454 603,1460 577,1465 550,1468 524,1468 456,1468 407,1447 377,1405 347,1362 332,1295 332,1202 L 332,1089 575,1089 575,995 Z"
+ id="glyph32" />
+ <glyph
+ unicode="e"
+ horiz-adv-x="874"
+ d="M 559,1110 C 646,1110 720,1089 779,1046 839,1003 883,944 913,869 943,794 958,708 958,611 L 958,531 229,531 C 231,386 262,275 325,198 387,121 476,82 592,82 656,82 712,88 759,100 806,111 858,130 915,156 L 915,50 C 865,25 814,7 764,-4 713,-15 655,-20 588,-20 434,-20 315,30 232,129 150,229 109,365 109,537 109,648 126,746 162,832 197,918 249,986 315,1036 382,1085 464,1110 559,1110 Z M 559,1012 C 465,1012 389,979 333,912 276,845 243,750 233,627 L 838,627 C 838,742 815,835 769,906 723,977 653,1012 559,1012 Z"
+ id="glyph34" />
+ <glyph
+ unicode="d"
+ horiz-adv-x="900"
+ d="M 535,-20 C 398,-20 293,27 219,120 145,214 109,352 109,535 109,722 147,865 224,963 301,1061 408,1110 545,1110 629,1110 698,1090 752,1050 805,1010 845,961 872,904 L 881,904 C 879,935 878,970 876,1009 873,1048 872,1084 872,1117 L 872,1557 989,1557 989,0 895,0 879,191 872,191 C 845,132 805,82 751,41 697,0 625,-20 535,-20 Z M 553,80 C 669,80 752,119 801,195 850,271 875,382 875,527 L 875,545 C 875,695 850,810 801,890 752,970 671,1010 559,1010 451,1010 369,969 313,886 257,804 229,686 229,533 229,385 256,273 309,196 363,119 444,80 553,80 Z"
+ id="glyph36" />
+ <glyph
+ unicode="c"
+ horiz-adv-x="768"
+ d="M 580,-20 C 429,-20 313,29 231,127 150,226 109,363 109,539 109,662 129,766 170,850 211,935 269,1000 343,1044 417,1088 504,1110 602,1110 651,1110 698,1106 742,1096 787,1087 825,1074 858,1057 L 825,957 C 791,972 754,984 714,993 673,1002 636,1006 600,1006 481,1006 390,964 326,881 261,798 229,685 229,541 229,405 258,294 314,210 371,126 459,84 580,84 630,84 678,90 723,101 768,112 809,125 846,142 L 846,37 C 812,20 773,6 729,-5 685,-15 636,-20 580,-20 Z"
+ id="glyph38" />
+ <glyph
+ unicode="a"
+ horiz-adv-x="822"
+ d="M 535,1108 C 651,1108 737,1078 795,1018 852,958 881,863 881,734 L 881,0 793,0 772,185 766,185 C 729,123 684,74 631,36 578,-1 503,-20 408,-20 311,-20 233,6 176,59 119,111 90,187 90,285 90,394 132,477 215,533 298,589 420,621 580,629 L 764,639 764,715 C 764,822 744,897 705,942 665,987 606,1010 528,1010 477,1010 426,1002 378,987 329,972 281,953 231,928 L 195,1022 C 242,1047 295,1067 352,1084 410,1100 470,1108 535,1108 Z M 594,543 C 466,536 370,512 307,470 244,429 213,367 213,285 213,217 232,165 271,131 310,96 363,78 430,78 535,78 617,111 676,176 735,240 764,330 764,445 L 764,551 594,543 Z"
+ id="glyph40" />
+ <glyph
+ unicode="S"
+ horiz-adv-x="875"
+ d="M 956,381 C 956,294 936,220 894,160 852,100 796,55 724,25 652,-5 571,-20 479,-20 396,-20 324,-14 262,-2 201,11 147,26 102,46 L 102,162 C 152,142 209,124 273,109 338,94 409,87 485,87 589,87 673,110 738,158 803,206 836,278 836,373 836,431 823,478 798,515 772,553 734,586 682,614 630,642 565,670 485,699 410,726 345,757 291,791 236,825 194,868 164,919 134,970 119,1035 119,1112 119,1192 138,1259 176,1314 214,1369 267,1411 333,1440 399,1469 474,1483 559,1483 626,1483 689,1476 750,1463 810,1449 868,1430 924,1405 L 883,1303 C 772,1352 663,1377 555,1377 462,1377 386,1354 328,1310 269,1266 240,1200 240,1114 240,1052 252,1001 278,964 303,926 340,895 389,869 438,843 498,817 567,791 648,762 717,731 775,698 833,664 878,623 909,573 941,523 956,459 956,381 Z"
+ id="glyph42" />
+ <glyph
+ unicode="P"
+ horiz-adv-x="848"
+ d="M 539,1462 C 869,1462 1034,1325 1034,1049 1034,908 992,798 907,718 823,638 690,598 510,598 L 311,598 311,0 193,0 193,1462 539,1462 Z M 528,1358 L 311,1358 311,702 498,702 C 629,702 730,727 803,776 875,825 911,914 911,1043 911,1152 880,1232 818,1282 756,1333 659,1358 528,1358 Z"
+ id="glyph44" />
+ <glyph
+ unicode="E"
+ horiz-adv-x="769"
+ d="M 950,0 L 193,0 193,1462 950,1462 950,1356 311,1356 311,821 913,821 913,715 311,715 311,107 950,107 950,0 Z"
+ id="glyph46" />
+ <glyph
+ unicode=" "
+ horiz-adv-x="503"
+ id="glyph48" />
+ </font></defs>
+ <defs
+ class="TextShapeIndex"
+ id="defs55" />
+ <defs
+ class="EmbeddedBulletChars"
+ id="defs87" />
+
+ <g
+ id="id10"
+ clip-path="none"
+ transform="translate(-700.00001,-2550)">
+
+ <text
+ class="SVGTextShape"
+ id="text151"
+ x="217.60002"
+ y="-56.506969"
+ style="letter-spacing:4.7625px;word-spacing:104.775px"><tspan
+ class="TextParagraph"
+ font-family="'Noto Sans Display Light', sans-serif"
+ font-size="494px"
+ font-weight="400"
+ id="tspan149"><tspan
+ class="TextPosition"
+ x="650.59998"
+ y="7647.4932"
+ id="tspan147"><tspan
+ fill="#808080"
+ stroke="none"
+ style="white-space:pre"
+ id="tspan145"
+ dx="2.1199999">Podcast Synchronisation made Efficient</tspan></tspan></tspan></text>
+ </g><g
+ id="g1277"
+ transform="translate(-700.00001,-2550)"><path
+ id="path131-3"
+ d="m 6694.0006,4763 c -559.5515,4.407 -980.3924,428.0893 -986.038,985.9863 18.2894,552.8957 454.3127,974.1166 989.0352,986.0379 v -235.0244 c -406.8751,-27.3888 -715.1078,-362.1649 -719.0259,-748.0163 12.7874,-421.0793 236.9242,-746.3999 750.0318,-749.98 895.0688,1.4728 1915.5158,0 2730.9957,0 V 4763 Z"
+ style="fill:#0084d1;fill-opacity:1"
+ clip-path="none" /><path
+ id="path131"
+ d="m 6685.0183,2562.996 c -559.5515,4.407 -980.3924,428.0893 -986.038,985.9863 18.2894,552.8957 454.3127,974.1167 989.0352,986.038 v -235.0244 c -406.8751,-27.3888 -715.1078,-362.165 -719.0259,-748.0164 12.7874,-421.0792 236.9242,-746.3998 750.0318,-749.98 895.0688,1.4728 1915.5158,0 2730.996,0 V 2562.996 Z"
+ style="fill:#0084d1;fill-opacity:1"
+ clip-path="none" /></g><g
+ id="g1263"
+ transform="translate(-700.00001,-2550)"><path
+ fill="none"
+ stroke="#069a2e"
+ stroke-width="265"
+ stroke-linejoin="round"
+ d="m 2793,5962 c 1283,0 429,-2762 1712,-2762"
+ id="path124" /><path
+ id="path110-6"
+ d="M 3198.0212,6550 V 6300.0411 H 2448.0411 V 6050.0305 5550.0094 H 2198.0305 V 6300.0411 6550 H 2448.0411 2698 Z"
+ style="fill:#069a2e;fill-opacity:1" /><path
+ id="path110"
+ d="m 4111.997,2550.0252 v 249.9589 h 749.9801 v 250.0106 500.0211 h 250.0106 v -750.0317 -249.9589 h -250.0106 -249.9589 z"
+ style="fill:#069a2e;fill-opacity:1" /></g>
+ <g
+ id="g1249"
+ transform="translate(-700.00001,-2550)"><path
+ fill="#ff8000"
+ stroke="none"
+ d="M 2215,4164 C 2412.6918,3832.6035 2379.3124,3383.7591 2135.4189,3084.8193 1956.8564,2857.4026 1671.3097,2718.8851 1382,2721 c 0,-52.6667 0,-105.3333 0,-158 -60.1303,-1.0792 190.6585,-1.2724 121.9814,2.7933 434.6311,30.3756 832.6257,336.7309 974.9655,748.2365 148.7336,402.6249 41.0263,883.7477 -266.0719,1183.8452 C 1996.6852,4716.1853 1689.0048,4838.6187 1382,4830 c 0,-61.6667 0,-123.3333 0,-185 338.199,2.9253 666.226,-186.816 833,-481 z"
+ id="path193" /><path
+ fill="#ff8000"
+ stroke="none"
+ d="m 1936,3979 c 175.8129,-283.3241 59.7943,-700.6319 -239.8255,-849.407 -94.2713,-50.9942 -201.887,-77.9344 -309.1745,-74.593 0,-57 0,-114 0,-171 396.3865,-24.0968 777.5367,297.6517 818.5878,693.1841 44.0348,337.5467 -149.4277,694.9971 -466.4953,826.9493 -110.1027,49.0687 -231.5272,73.543 -352.0925,67.8666 0,-61.6667 0,-123.3333 0,-185 220.6353,7.5804 440.8554,-115.3286 549,-308 z"
+ id="path186" /><path
+ fill="#ff8000"
+ stroke="none"
+ d="m 1659,3822 c 86.3933,-138.0398 18.2474,-344.669 -134.6962,-402.3205 C 1483.44,3402.2177 1438.3524,3394.2432 1394,3398 c 0,-56.6667 0,-113.3333 0,-170 223.1964,-19.6143 444.7886,153.3254 478.4886,375.1817 32.646,181.6951 -54.6854,381.4331 -217.3127,472.2205 -78.2316,46.131 -170.3991,69.3119 -261.1759,62.5978 0,-58.3333 0,-116.6667 0,-175 105.6736,9.5509 212.8962,-49.2218 265,-141 z"
+ id="path179" /><rect
+ class="BoundingBox"
+ stroke="none"
+ fill="none"
+ x="700"
+ y="2550"
+ width="501"
+ height="4001"
+ id="rect136"
+ style="fill:#ff8000;fill-opacity:1" /></g>
+
+</svg>
diff --git a/21-implementierungsheft-kolloquium/assets/navbar.png b/21-implementierungsheft-kolloquium/assets/navbar.png
new file mode 100644
index 0000000..dd9f8e8
--- /dev/null
+++ b/21-implementierungsheft-kolloquium/assets/navbar.png
Binary files differ
diff --git a/21-implementierungsheft-kolloquium/assets/password-margin.png b/21-implementierungsheft-kolloquium/assets/password-margin.png
new file mode 100644
index 0000000..d9d4fa3
--- /dev/null
+++ b/21-implementierungsheft-kolloquium/assets/password-margin.png
Binary files differ
diff --git a/21-implementierungsheft-kolloquium/assets/password.png b/21-implementierungsheft-kolloquium/assets/password.png
new file mode 100644
index 0000000..68248a0
--- /dev/null
+++ b/21-implementierungsheft-kolloquium/assets/password.png
Binary files differ
diff --git a/21-implementierungsheft-kolloquium/assets/subscription.png b/21-implementierungsheft-kolloquium/assets/subscription.png
new file mode 100644
index 0000000..58a84f9
--- /dev/null
+++ b/21-implementierungsheft-kolloquium/assets/subscription.png
Binary files differ
diff --git a/21-implementierungsheft-kolloquium/logos/banner_2020_kit.jpg b/21-implementierungsheft-kolloquium/logos/banner_2020_kit.jpg
new file mode 100644
index 0000000..70ae1d0
--- /dev/null
+++ b/21-implementierungsheft-kolloquium/logos/banner_2020_kit.jpg
Binary files differ
diff --git a/21-implementierungsheft-kolloquium/notizen b/21-implementierungsheft-kolloquium/notizen
new file mode 100644
index 0000000..70ac63b
--- /dev/null
+++ b/21-implementierungsheft-kolloquium/notizen
@@ -0,0 +1,40 @@
+Titelseite:
+- Begrüßung
+
+Einführung:
+- Podcast: RSS-Feed, Episoden, Audio/Video
+- Podcatcher: lokale Verwaltung von Podcasts, API Unterstützung,
+Abspielen von Episoden
+- Synchronisationsserver (das soll unser Produkt werden): Hörfortschritte,
+Abonnements, Discovery (bei AntennaPod z.B. iTunes)
+
+Zielsetzung:
+
+Synchronisation (die Art, die wir bei uns anwenden):
+- alle Aktionen werden auf den Server und infolge dessen auf alle Podcatcher
+übertragen
+
+Features:
+- Synchronisation: Abos, Hörfortschritt
+- Weboberfläche: Aboliste, Zuletzt gehört
+- Account-Verwaltung: Registrieren, Anmelden, Passwort ändern/zurücksetzen,
+Account löschen, Daten importieren/exportieren
+
+UI-Journey:
+- login.html:
+ - Sprache ändern
+ - OAuth (kann)
+ - Registrieren (muss): neues Fenster, E-Mail + 2-mal Passwort (sicher?),
+ vergeben? -> Fehler / Bestätigungslink per E-Mail (gültig 24h)
+ - Anmelden (muss): E-Mail + Passwort eingeben, Login merken,
+ login, Fehlermeldung oder Dashboard
+ - Passwort vergessen: neues Fenster, E-Mail eingeben, falls Account wird
+ Link versendet, 24h gültig, nach betätigen PW zweimal eingeben & bestätigen
+ (Anforderungen)
+
+- podcasts.html: Abonnements, Eisoden, Hörfortschritte
+
+- listening.html: Zuletzt gehörte Episoden, Hörfortschritt, Wann gehört
+
+- settings.html: PW ändern, Gpodder Import, pers. Daten imp./exp.,
+ Account löschen
diff --git a/21-implementierungsheft-kolloquium/presentation.tex b/21-implementierungsheft-kolloquium/presentation.tex
new file mode 100644
index 0000000..88cb357
--- /dev/null
+++ b/21-implementierungsheft-kolloquium/presentation.tex
@@ -0,0 +1,53 @@
+%% Beispiel-Präsentation mit LaTeX Beamer im KIT-Design
+%% entsprechend den Gestaltungsrichtlinien vom 1. August 2020
+%%
+%% Siehe https://sdqweb.ipd.kit.edu/wiki/Dokumentvorlagen
+
+%% Beispiel-Präsentation
+\documentclass[table]{sdqbeamer}
+
+\usepackage{calc}
+\usepackage{multicol}
+\usepackage{fontawesome5}
+\usepackage{ulem}
+
+%% Titelbild
+\titleimage{banner_2020_kit}
+
+%% Gruppenlogo
+\grouplogo{kitlogo_de_rgb}
+
+%% Gruppenname und Breite (Standard: 50 mm)
+\groupname{Praxis der Softwareentwicklung}
+%\groupnamewidth{50mm}
+
+% Beginn der Präsentation
+
+\title[Kolloquium Implementierung]{
+ PSE\textsuperscript{2} - Podcast Synchronisation made Efficient
+}
+\subtitle{Kolloquium Implementierung}
+\author[Lukas Schmidheissler]{Lukas Schmidheissler}
+
+\date[28.\,02.\,2023]{28. Februar 2023}
+
+\begin{document}
+
+%Titelseite
+\KITtitleframe
+
+%\include{slides/classdiagram}
+
+\include{slides/integrationstrategie}
+
+\include{slides/gantt}
+
+\include{slides/difficulties}
+
+\include{slides/changes}
+
+\include{slides/statistics}
+
+\include{slides/requirements}
+
+\end{document}
diff --git a/21-implementierungsheft-kolloquium/sdqbeamer.cls b/21-implementierungsheft-kolloquium/sdqbeamer.cls
new file mode 100644
index 0000000..1b9c2b8
--- /dev/null
+++ b/21-implementierungsheft-kolloquium/sdqbeamer.cls
@@ -0,0 +1,975 @@
+%% Vorlage für Präsentationen mit LaTeX Beamer im KIT-Design
+%% entsprechend den Gestaltungsrichtlinien vom 1. August 2020
+%%
+%% Siehe https://sdqweb.ipd.kit.edu/wiki/Dokumentvorlagen
+
+
+\NeedsTeXFormat{LaTeX2e}
+\ProvidesClass{sdqbeamer}[2022-05-03 v3.1.3 SDQ Beamer class]
+
+\RequirePackage[utf8]{inputenc}
+\RequirePackage[T1]{fontenc}
+
+\newif\ifsectionnavigation
+\newif\ifnavbarinfoot
+\newif\ifnavbarinline
+\newif\ifnavbarside
+\newif\iffourtothree
+\newif\ifsixteentonine
+\newif\ifsixteentoten
+\newif\ifgerman
+\newif\ifsmallfooterfont
+
+\def\kitslogan#1{\def\@kitslogan{#1}}
+\def\kitlogo#1{\def\@kitlogo{#1}}
+\def\groupname#1{\def\@groupname{#1}}
+\def\groupnamewidth#1{\def\@groupnamewidth{#1}}
+
+% siehe README.md
+\DeclareOption{de}{
+ \kitslogan{KIT -- Die Forschungsuniversität in der Helmholtz-Gemeinschaft}
+ \kitlogo{pse_logo}
+ \germantrue
+ \PassOptionsToPackage{autostyle}{csquotes}
+ }
+\DeclareOption{en}{
+ \kitslogan{KIT -- The Research University in the Helmholtz Association}
+ \kitlogo{kitlogo_en_rgb}
+ \germanfalse
+ }
+\DeclareOption{4:3}{
+ \fourtothreetrue
+ \sixteentoninefalse
+ \sixteentotenfalse
+}
+\DeclareOption{16:9}{
+ \fourtothreefalse
+ \sixteentoninetrue
+ \sixteentotenfalse
+}
+\DeclareOption{16:10}{
+ \fourtothreefalse
+ \sixteentoninefalse
+ \sixteentotentrue
+}
+\DeclareOption{navbarside}{
+ \sectionnavigationtrue
+ \navbarsidetrue
+ \navbarinlinefalse
+ \navbarinfootfalse
+}
+\DeclareOption{navbarinline}{
+ \sectionnavigationtrue
+ \navbarsidefalse
+ \navbarinlinetrue
+ \navbarinfootfalse
+}
+\DeclareOption{navbarinfooter}{
+ \sectionnavigationtrue
+ \navbarsidefalse
+ \navbarinlinefalse
+ \navbarinfoottrue
+}
+\DeclareOption{navbaroff}{
+ \sectionnavigationfalse
+}
+\DeclareOption{navbarkit}{
+ \sectionnavigationfalse
+ \smallfooterfonttrue
+}
+\DeclareOption{smallfoot}{
+ \smallfooterfonttrue
+}
+\DeclareOption{bigfoot}{
+ \smallfooterfontfalse
+}
+
+\ExecuteOptions{de,16:9,navbarinline,bigfoot}
+
+\DeclareOption*{\PassOptionsToClass{\CurrentOption}{beamer}}
+
+\ProcessOptions\relax
+
+\LoadClass[10pt,utf8]{beamer}
+
+% Babel-Paket wird nur bei deutscher Sprache benötigt
+\ifgerman
+ \RequirePackage[ngerman]{babel}
+\fi
+\RequirePackage{csquotes}
+\RequirePackage{hyperref}
+\RequirePackage[absolute,overlay]{textpos}
+
+%% ---------------
+%% | Typographie |
+%% ---------------
+
+\RequirePackage{microtype}
+
+\RequirePackage[scaled=.92]{helvet}
+\RequirePackage[scaled=.78]{beramono}
+\RequirePackage{libertineRoman}
+
+\setbeamerfont{title}{series=\bfseries,size=\Large}
+\setbeamerfont{frametitle}{series=\bfseries,size=\Large}
+\setbeamerfont{framesubtitle}{series=\bfseries,size=\normalsize}
+
+%% -----------------
+%% | Folien-Layout |
+%% -----------------
+
+% Seitenverhältnis
+%
+% Die Folien sind auf die Standardhöhe in LaTeX Beamer (9,6 cm) normiert.
+% Die Maße der KIT-Gestaltungsrichtlinien (Folienhöhe 14,3 cm) wurden durch
+% den Quotienten 1,5 geteilt.
+
+\RequirePackage{geometry}
+\iffourtothree
+ \geometry{papersize={12.8cm,9.6cm}}
+\fi
+\ifsixteentoten
+ \geometry{papersize={15.36cm,9.6cm}}
+\fi
+\ifsixteentonine
+ \geometry{papersize={17.07cm,9.6cm}}
+\fi
+
+% Ränder laut Gestaltungsrichtlinen; 3 mm -> 2 mm, 11 mm -> 7,3 mm
+\newlength{\kitoutermargin}
+\setlength{\kitoutermargin}{2mm}
+\newlength{\kitinnermargin}
+\setlength{\kitinnermargin}{7.3mm}
+\newlength{\kitbottommargin}
+\setlength{\kitbottommargin}{\kitinnermargin}
+
+% Ränder außen
+\setbeamersize{text margin left=\kitinnermargin,text margin right=\kitinnermargin}
+
+% keine Navigationssymbole
+\setbeamertemplate{navigation symbols}{}
+\setbeamercovered{invisible}
+\useinnertheme{rounded}
+\beamer@compresstrue % Miniframes (Navigations-Punkte) für Subsections immer in einer Zeile, ohne Umbrüche
+
+% Folientitel
+\setbeamertemplate{frametitle}{
+ \ifbeamer@plainframe\else%
+ % Unterkante Titeltext: 22,5 mm -> 15 mm von Seitenkopf
+ \begin{textblock*}{\dimexpr\paperwidth-30mm-2\kitinnermargin}[0,1](\kitinnermargin,15mm)%
+ \usebeamerfont{frametitle}\insertframetitle%
+ \ifx\insertframesubtitle\@empty\else\\[.1em]\fi
+ \usebeamerfont{framesubtitle}\insertframesubtitle%
+ \end{textblock*}%
+ \begin{textblock*}{20mm}[1,1](\dimexpr\paperwidth-\kitinnermargin\relax,15mm)%j
+ \includegraphics[width=20mm]{logos/\@kitlogo}%
+ \end{textblock*}%
+ \fi
+% Rand oben (ergibt Beginn des Textes bei 34 mm -> 22,7 mm)
+ \vspace {18mm}
+}
+
+%% Fußzeile
+\newlength{\kitbottom}
+ % Navbar in Footer: Schmale Fußzeile
+\ifnavbarinfoot
+ % Bei Navbar in Footer immer kleiner Font in der Fußzeile
+ \setbeamerfont{footer}{size=\fontsize{6pt}{7.2pt}\selectfont}
+ \setlength{\kitbottom}{4mm}
+\else
+ % Ansonsten kleiner Text nur, wenn "smallfoot" gewählt
+ \ifsmallfooterfont
+ \setbeamerfont{footer}{size=\fontsize{6pt}{7.2pt}\selectfont}
+ \else
+ \setbeamerfont{footer}{size=\scriptsize}
+ \fi
+ \setlength{\kitbottom}{\kitbottommargin}
+\fi
+\setbeamerfont{page number in head/foot}{series=\bfseries}
+
+\newlength{\kitbottomdepth}
+\newlength{\kitbottomheight}
+\newlength{\kitfootergroupwidth}
+
+\setbeamertemplate{footline}{%
+\setlength{\kitbottomdepth}{\dimexpr.5\kitbottom-.5em\relax}%
+\setlength{\kitbottomheight}{\dimexpr.5\kitbottom+.5em\relax}%
+ %% die "%" am Ende sind nötig, damit keine Abstände eingefügt werden
+ %
+ % Falls kein Gruppenname angegeben, die ganze Breite der Fußzeile für den Titel nutzen.
+ \ifdefined\@groupname%
+ \ifx\@groupname\empty%
+ \setlength{\kitfootergroupwidth}{0mm}%
+ \else%
+ % Falls die Breite des Gruppenlogos definiert ist, diese nehmen, sonst 50 mm
+ \ifdefined\@groupnamewidth%
+ \setlength{\kitfootergroupwidth}{\@groupnamewidth}%
+ \else%
+ \setlength{\kitfootergroupwidth}{50mm}%
+ \fi%
+ \fi%
+ \else
+ \setlength{\kitfootergroupwidth}{0mm}%
+ \fi
+ \usebeamerfont{footer}%
+ \ifsectionnavigation%
+ % Option "navbarinline"
+ \ifnavbarinline%
+ \begin{beamercolorbox}[wd=\paperwidth, leftskip=2mm, rightskip=2mm]{}
+ \insertnavigation{\dimexpr\paperwidth-4mm\relax}
+ \vspace{1mm}
+ \end{beamercolorbox}%
+ \fi%
+ % Option "navbarinfooter"
+ \ifnavbarinfoot%
+ % Punkte für Subsections deaktivieren
+ \setbeamertemplate{mini frames}{}%
+ \begin{beamercolorbox}[wd=\paperwidth, leftskip=1mm, rightskip=1mm]{}%
+ \insertsectionnavigationhorizontal{\dimexpr\paperwidth-\kitoutermargin\relax}{}{}
+ \end{beamercolorbox}%
+ \fi%
+ \fi%
+ \leavevmode%
+ \begin{beamercolorbox}[wd=13mm, ht=\kitbottomheight, dp=\kitbottomdepth, leftskip=4mm]{}
+ \usebeamerfont{page number in head/foot}%
+ \strut\insertframenumber{}/\inserttotalframenumber%
+ \end{beamercolorbox}%
+ \begin{beamercolorbox}[wd=20mm, ht=\kitbottomheight, dp=\kitbottomdepth]{}
+ \usebeamerfont{date in head/foot}%
+ \strut\insertshortdate%
+ \end{beamercolorbox}%
+ % Die Boxen mit dem Titel und dem Gruppennamen sind vertikal zentriert, damit auch zweizeilige Texte schön aussehen
+ % Daher müssen sie um \kitbottomdepth nach unten verschoben werden
+ \raisebox{-\kitbottomdepth}{
+ % Die Box hat daher auch Höhe \kitbottom und Tiefe 0mm
+ \begin{beamercolorbox}[wd=\dimexpr\paperwidth-37mm-\kitfootergroupwidth, ht=\kitbottom, dp=0mm]{}%
+ % Inhalt vertikal zentrieren; Anpassung um 1.5 pt, damit bei einzeiligem Inhalt genau die Baseline der Blöcke mit Seitenzahl und Datum getroffen wird
+ \vbox to\kitbottom{\vfill\vskip1.5pt%
+ \beamer@shortauthor\ifx\beamer@shortauthor\empty\else: \fi\beamer@shorttitle%
+ \vfill}%
+ \end{beamercolorbox}%
+ \ifdefined\@groupname%
+ \begin{beamercolorbox}[wd=\kitfootergroupwidth, ht=\kitbottom, dp=0mm, rightskip=\kitinnermargin]{}
+ \vbox to\kitbottom{\vfill\vskip1.5pt%
+ \raggedleft\@groupname%
+ \vfill}%
+ \end{beamercolorbox}%
+ \fi%
+ }%
+}
+
+%% Option "navbarside"
+\ifnavbarside
+\useoutertheme[height=0cm,width=3.5cm,left]{sidebar}
+
+\setbeamerfont{title in sidebar}{family=\sffamily,series=\mdseries,size={\fontsize{10pt}{11pt}}}
+\setbeamerfont{section in sidebar}{family=\sffamily,series=\mdseries,size={\fontsize{9pt}{9.9pt}}}
+\setbeamerfont{subsection in sidebar}{family=\sffamily,series=\mdseries,size={\fontsize{8pt}{8.8pt}}}
+
+\setbeamertemplate{sidebar \beamer@sidebarside}
+ {\vskip1.5cm%
+ \hskip6.5mm%
+ \advance\beamer@sidebarwidth by -5mm%
+ \insertverticalnavigation{\beamer@sidebarwidth}%
+ }%
+\fi
+
+%% Hintergrund
+\usebackgroundtemplate{
+ % Trennlinie nicht bei "plain"-Frames
+ \ifbeamer@plainframe\else\kitseparationline\fi
+}
+
+% Trennlinie
+\newcommand{\kitseparationline}{
+ \begin{pgfpicture}{0mm}{0mm}{\paperwidth}{\paperheight}
+ \pgfsetstrokecolor{black!15}
+ \pgfsetlinewidth{.5pt}
+ \pgfpathmoveto{\pgfpoint{\kitoutermargin}{\kitinnermargin}}
+ \pgfpathlineto{\pgfpoint{\paperwidth-\kitoutermargin}{\kitinnermargin}}
+ \pgfusepath{stroke}
+ \end{pgfpicture}%
+}
+
+
+%% --------------
+%% | Titelseite |
+%% --------------
+
+\def\titleimage#1{\def\@titleimage{#1}}
+\def\grouplogo#1{\def\@grouplogo{#1}}
+
+\newcommand{\KITtitleframe}{
+ \begin{frame}[plain]
+ \titlepage
+ \end{frame}
+}
+
+\newlength{\kittitleimageheight}
+\setbeamertemplate{title page}{
+ % From textpos documentation (https://ctan.org/pkg/textpos)
+ %
+ % \begin{textblock}{<hsize>}[<ho>,<vo>](<hpos>,<vpos>)
+ % The coordinates <ho> and <vo> are fractions of the width and height of the text
+ % box, respectively, and state that the box is to be placed so that the reference point
+ % (<ho>,<vo>) within the box is to be placed at the point (<hpos>,<vpos>) on the page.
+
+ % KIT-Logo
+ \begin{textblock*}{30mm}(\kitinnermargin,6.7mm)
+ \includegraphics[width=30mm]{logos/\@kitlogo}
+ \end{textblock*}
+
+ % Gruppenlogo
+ \ifdefined\@grouplogo
+ \ifx\@grouplogo\empty \else
+ \begin{textblock*}{20mm}(\dimexpr\paperwidth-24mm\relax,6.7mm)
+ \includegraphics[width=20mm,height=20mm,keepaspectratio]{logos/\@grouplogo}
+ \end{textblock*}
+ \fi % falls \grouplogo{} aufgerufen wird, kein Gruppenlogo einbinden
+ \else
+ \begin{textblock*}{20mm}(\dimexpr\paperwidth-24mm\relax,6.7mm)
+ \colorbox{kit-purple100!20}{\parbox[t][12mm][c]{19mm}{\color{kit-purple100}\scriptsize\centering
+ \ifgerman
+ Bitte Logo über \texttt{\textbackslash grouplogo\{\}} festlegen.
+ \else
+ Please set a logo using \texttt{\textbackslash grouplogo\{\}}.
+ \fi
+ }}
+ \end{textblock*}
+ \fi
+
+ % Titel
+ \begin{textblock*}{\dimexpr\paperwidth-8mm\relax}[0,.5](\kitinnermargin,28mm)
+ \usebeamerfont*{title}\inserttitle
+ \end{textblock*}
+
+ % Untertitel
+ \begin{textblock*}{\dimexpr\paperwidth-8mm\relax}(\kitinnermargin,36mm)
+ \small\textbf{\insertsubtitle}
+ \end{textblock*}
+
+ % Autor
+ \begin{textblock*}{\dimexpr\paperwidth-8mm\relax}(\kitinnermargin,41mm)
+ \small\insertauthor~\textbar~\insertdate
+ \end{textblock*}
+
+ % Titelbild
+ \setlength{\kittitleimageheight}{40mm}
+ \begin{textblock*}{\paperwidth}(\kitoutermargin,\dimexpr\paperheight-\kitbottommargin-\kittitleimageheight)
+ \begin{pgfpicture}{0mm}{0mm}{\paperwidth}{\kittitleimageheight}
+ % Clipping-Pfad um titelbild
+ \pgfsetstrokecolor{black!15}
+ \pgfsetlinewidth{1pt}
+ \pgfsetcornersarced{\pgfpoint{3mm}{3mm}}
+ \pgfpathmoveto{\pgfpoint{\paperwidth-2\kitoutermargin}{0mm}}
+ \pgfpathlineto{\pgfpoint{\paperwidth-2\kitoutermargin}{\kittitleimageheight}}
+ \pgfsetcornersarced{\pgfpointorigin}
+ \pgfpathlineto{\pgfpoint{0mm}{\kittitleimageheight}}
+ \pgfsetcornersarced{\pgfpoint{3mm}{3mm}}
+ \pgfpathlineto{\pgfpointorigin}
+ \pgfsetcornersarced{\pgfpointorigin}
+ \pgfpathclose
+ \pgfusepath{stroke,clip}
+ \pgfsetstrokecolor{black}
+
+ % Titelbild
+ \ifdefined\@titleimage
+ \ifx\@titleimage\empty \else%
+ \pgftext[at=\pgfpoint{.5\paperwidth}{0mm},center,bottom]{%
+ \includegraphics[height=40mm]{logos/\@titleimage}
+ }
+ \fi % Bei Aufruf von \titleimage{} leeren Rahmen anzeigen.
+ \else
+ \pgftext[at=\pgfpoint{.5\paperwidth}{.5\kittitleimageheight},center,base]{%
+ \colorbox{kit-purple100!20}{\parbox[c][\kittitleimageheight][c]{\paperwidth}{\color{kit-purple100}\centering Bitte Titelbild über \texttt{\textbackslash titleimage\{\}} festlegen.
+ }}%
+ }
+ \fi
+
+
+ \end{pgfpicture}%
+ \end{textblock*}
+
+
+ % KIT slogan
+ \begin{textblock*}{80mm}[0,.5](\kitoutermargin,\dimexpr\paperheight-.5\kitbottommargin)
+ \fontsize{5.5pt}{5.5pt}\selectfont\@kitslogan
+ \end{textblock*}
+
+ \begin{textblock*}{30mm}[1,.5](\dimexpr\paperwidth-\kitoutermargin\relax,\dimexpr\paperheight-.5\kitbottommargin)
+ \fontsize{11pt}{11pt}\selectfont\bfseries\raggedleft%
+ {\href{https://www.kit.edu}{www.kit.edu}}
+ \end{textblock*}
+
+}
+%% ---------------
+%% | /Titelseite |
+%% ---------------
+
+%% ----------
+%% | Farben |
+%% ----------
+%% KIT-Farbschema
+
+% KIT color green :
+\definecolor{kit-green}{RGB}{0, 150, 130}
+\definecolor{kit-green100}{RGB}{0, 150, 130}
+\definecolor{kit-green90}{rgb}{0.1, 0.6294, 0.5588}
+\definecolor{kit-green80}{rgb}{0.2, 0.6706, 0.6078}
+\definecolor{kit-green75}{rgb}{0.25, 0.6912, 0.6324}
+\definecolor{kit-green70}{rgb}{0.3, 0.7118, 0.6569}
+\definecolor{kit-green60}{rgb}{0.4, 0.7529, 0.7059}
+\definecolor{kit-green50}{rgb}{0.5, 0.7941, 0.7549}
+\definecolor{kit-green40}{rgb}{0.6, 0.8353, 0.8039}
+\definecolor{kit-green30}{rgb}{0.7, 0.8765, 0.8529}
+\definecolor{kit-green25}{rgb}{0.75, 0.8971, 0.8775}
+\definecolor{kit-green20}{rgb}{0.8, 0.9176, 0.902}
+\definecolor{kit-green15}{rgb}{0.85, 0.9382, 0.9265}
+\definecolor{kit-green10}{rgb}{0.9, 0.9588, 0.951}
+\definecolor{kit-green5}{rgb}{0.95, 0.9794, 0.9755}
+
+% KIT color blue:
+\definecolor{kit-blue}{RGB}{70, 100, 170}
+\definecolor{kit-blue100}{RGB}{70, 100, 170}
+\definecolor{kit-blue90}{rgb}{0.3471, 0.4529, 0.7}
+\definecolor{kit-blue80}{rgb}{0.4196, 0.5137, 0.7333}
+\definecolor{kit-blue75}{rgb}{0.4559, 0.5441, 0.75}
+\definecolor{kit-blue70}{rgb}{0.4922, 0.5745, 0.7667}
+\definecolor{kit-blue60}{rgb}{0.5647, 0.6353, 0.8}
+\definecolor{kit-blue50}{rgb}{0.6373, 0.6961, 0.8333}
+\definecolor{kit-blue40}{rgb}{0.7098, 0.7569, 0.8667}
+\definecolor{kit-blue30}{rgb}{0.7824, 0.8176, 0.9}
+\definecolor{kit-blue25}{rgb}{0.8186, 0.848, 0.9167}
+\definecolor{kit-blue20}{rgb}{0.8549, 0.8784, 0.9333}
+\definecolor{kit-blue15}{rgb}{0.8912, 0.9088, 0.95}
+\definecolor{kit-blue10}{rgb}{0.9275, 0.9392, 0.9667}
+\definecolor{kit-blue5}{rgb}{0.9637, 0.9696, 0.9833}
+
+% KIT color red :
+\definecolor{kit-red}{RGB}{162, 34, 35}
+\definecolor{kit-red100}{RGB}{162, 34, 35}
+\definecolor{kit-red90}{rgb}{0.6718, 0.22, 0.2235}
+\definecolor{kit-red80}{rgb}{0.7082, 0.3067, 0.3098}
+\definecolor{kit-red75}{rgb}{0.7265, 0.35, 0.3529}
+\definecolor{kit-red70}{rgb}{0.7447, 0.3933, 0.3961}
+\definecolor{kit-red60}{rgb}{0.7812, 0.48, 0.4824}
+\definecolor{kit-red50}{rgb}{0.8176, 0.5667, 0.5686}
+\definecolor{kit-red40}{rgb}{0.8541, 0.6533, 0.6549}
+\definecolor{kit-red30}{rgb}{0.8906, 0.74, 0.7412}
+\definecolor{kit-red25}{rgb}{0.9088, 0.7833, 0.7843}
+\definecolor{kit-red20}{rgb}{0.9271, 0.8267, 0.8275}
+\definecolor{kit-red15}{rgb}{0.9453, 0.87, 0.8706}
+\definecolor{kit-red10}{rgb}{0.9635, 0.9133, 0.9137}
+\definecolor{kit-red5}{rgb}{0.9818, 0.9567, 0.9569}
+
+% KIT color yellow :
+\definecolor{kit-yellow}{RGB}{252, 229, 0}
+\definecolor{kit-yellow100}{RGB}{252, 229, 0}
+\definecolor{kit-yellow90}{rgb}{0.9894, 0.9082, 0.1}
+\definecolor{kit-yellow80}{rgb}{0.9906, 0.9184, 0.2}
+\definecolor{kit-yellow75}{rgb}{0.9912, 0.9235, 0.25}
+\definecolor{kit-yellow70}{rgb}{0.9918, 0.9286, 0.3}
+\definecolor{kit-yellow60}{rgb}{0.9929, 0.9388, 0.4}
+\definecolor{kit-yellow50}{rgb}{0.9941, 0.949, 0.5}
+\definecolor{kit-yellow40}{rgb}{0.9953, 0.9592, 0.6}
+\definecolor{kit-yellow30}{rgb}{0.9965, 0.9694, 0.7}
+\definecolor{kit-yellow25}{rgb}{0.9971, 0.9745, 0.75}
+\definecolor{kit-yellow20}{rgb}{0.9976, 0.9796, 0.8}
+\definecolor{kit-yellow15}{rgb}{0.9982, 0.9847, 0.85}
+\definecolor{kit-yellow10}{rgb}{0.9988, 0.9898, 0.9}
+\definecolor{kit-yellow5}{rgb}{0.9994, 0.9949, 0.95}
+
+% KIT color orange :
+\definecolor{kit-orange}{RGB}{223, 155, 27}
+\definecolor{kit-orange100}{RGB}{223, 155, 27}
+\definecolor{kit-orange90}{rgb}{0.8871, 0.6471, 0.1953}
+\definecolor{kit-orange80}{rgb}{0.8996, 0.6863, 0.2847}
+\definecolor{kit-orange75}{rgb}{0.9059, 0.7059, 0.3294}
+\definecolor{kit-orange70}{rgb}{0.9122, 0.7255, 0.3741}
+\definecolor{kit-orange60}{rgb}{0.9247, 0.7647, 0.4635}
+\definecolor{kit-orange50}{rgb}{0.9373, 0.8039, 0.5529}
+\definecolor{kit-orange40}{rgb}{0.9498, 0.8431, 0.6424}
+\definecolor{kit-orange30}{rgb}{0.9624, 0.8824, 0.7318}
+\definecolor{kit-orange25}{rgb}{0.9686, 0.902, 0.7765}
+\definecolor{kit-orange20}{rgb}{0.9749, 0.9216, 0.8212}
+\definecolor{kit-orange15}{rgb}{0.9812, 0.9412, 0.8659}
+\definecolor{kit-orange10}{rgb}{0.9875, 0.9608, 0.9106}
+\definecolor{kit-orange5}{rgb}{0.9937, 0.9804, 0.9553}
+
+% KIT color lightgreen :
+\definecolor{kit-lightgreen}{RGB}{140, 182, 60}
+\definecolor{kit-lightgreen100}{RGB}{140, 182, 60}
+\definecolor{kit-lightgreen90}{rgb}{0.5941, 0.7424, 0.3118}
+\definecolor{kit-lightgreen80}{rgb}{0.6392, 0.771, 0.3882}
+\definecolor{kit-lightgreen75}{rgb}{0.6618, 0.7853, 0.4265}
+\definecolor{kit-lightgreen70}{rgb}{0.6843, 0.7996, 0.4647}
+\definecolor{kit-lightgreen60}{rgb}{0.7294, 0.8282, 0.5412}
+\definecolor{kit-lightgreen50}{rgb}{0.7745, 0.8569, 0.6176}
+\definecolor{kit-lightgreen40}{rgb}{0.8196, 0.8855, 0.6941}
+\definecolor{kit-lightgreen30}{rgb}{0.8647, 0.9141, 0.7706}
+\definecolor{kit-lightgreen25}{rgb}{0.8873, 0.9284, 0.8088}
+\definecolor{kit-lightgreen20}{rgb}{0.9098, 0.9427, 0.8471}
+\definecolor{kit-lightgreen15}{rgb}{0.9324, 0.9571, 0.8853}
+\definecolor{kit-lightgreen10}{rgb}{0.9549, 0.9714, 0.9235}
+\definecolor{kit-lightgreen5}{rgb}{0.9775, 0.9857, 0.9618}
+
+
+% KIT color purple :
+\definecolor{kit-purple}{RGB}{163, 16, 124}
+\definecolor{kit-purple100}{RGB}{163, 16, 124}
+\definecolor{kit-purple90}{rgb}{0.6753, 0.1565, 0.5376}
+\definecolor{kit-purple80}{rgb}{0.7114, 0.2502, 0.589}
+\definecolor{kit-purple75}{rgb}{0.7294, 0.2971, 0.6147}
+\definecolor{kit-purple70}{rgb}{0.7475, 0.3439, 0.6404}
+\definecolor{kit-purple60}{rgb}{0.7835, 0.4376, 0.6918}
+\definecolor{kit-purple50}{rgb}{0.8196, 0.5314, 0.7431}
+\definecolor{kit-purple40}{rgb}{0.8557, 0.6251, 0.7945}
+\definecolor{kit-purple30}{rgb}{0.8918, 0.7188, 0.8459}
+\definecolor{kit-purple25}{rgb}{0.9098, 0.7657, 0.8716}
+\definecolor{kit-purple20}{rgb}{0.9278, 0.8125, 0.8973}
+\definecolor{kit-purple15}{rgb}{0.9459, 0.8594, 0.9229}
+\definecolor{kit-purple10}{rgb}{0.9639, 0.9063, 0.9486}
+\definecolor{kit-purple5}{rgb}{0.982, 0.9531, 0.9743}
+
+% KIT color brown :
+\definecolor{kit-brown}{RGB}{167, 130, 46}
+\definecolor{kit-brown100}{RGB}{167, 130, 46}
+\definecolor{kit-brown90}{rgb}{0.6894, 0.5588, 0.2624}
+\definecolor{kit-brown80}{rgb}{0.7239, 0.6078, 0.3443}
+\definecolor{kit-brown75}{rgb}{0.7412, 0.6324, 0.3853}
+\definecolor{kit-brown70}{rgb}{0.7584, 0.6569, 0.4263}
+\definecolor{kit-brown60}{rgb}{0.7929, 0.7059, 0.5082}
+\definecolor{kit-brown50}{rgb}{0.8275, 0.7549, 0.5902}
+\definecolor{kit-brown40}{rgb}{0.862, 0.8039, 0.6722}
+\definecolor{kit-brown30}{rgb}{0.8965, 0.8529, 0.7541}
+\definecolor{kit-brown25}{rgb}{0.9137, 0.8775, 0.7951}
+\definecolor{kit-brown20}{rgb}{0.931, 0.902, 0.8361}
+\definecolor{kit-brown15}{rgb}{0.9482, 0.9265, 0.8771}
+\definecolor{kit-brown10}{rgb}{0.9655, 0.951, 0.918}
+\definecolor{kit-brown5}{rgb}{0.9827, 0.9755, 0.959}
+
+% KIT color cyan :
+\definecolor{kit-cyan}{RGB}{35, 161, 224}
+\definecolor{kit-cyan100}{RGB}{35, 161, 224}
+\definecolor{kit-cyan90}{rgb}{0.2235, 0.6682, 0.8906}
+\definecolor{kit-cyan80}{rgb}{0.3098, 0.7051, 0.9027}
+\definecolor{kit-cyan75}{rgb}{0.3529, 0.7235, 0.9088}
+\definecolor{kit-cyan70}{rgb}{0.3961, 0.742, 0.9149}
+\definecolor{kit-cyan60}{rgb}{0.4824, 0.7788, 0.9271}
+\definecolor{kit-cyan50}{rgb}{0.5686, 0.8157, 0.9392}
+\definecolor{kit-cyan40}{rgb}{0.6549, 0.8525, 0.9514}
+\definecolor{kit-cyan30}{rgb}{0.7412, 0.8894, 0.9635}
+\definecolor{kit-cyan25}{rgb}{0.7843, 0.9078, 0.9696}
+\definecolor{kit-cyan20}{rgb}{0.8275, 0.9263, 0.9757}
+\definecolor{kit-cyan15}{rgb}{0.8706, 0.9447, 0.9818}
+\definecolor{kit-cyan10}{rgb}{0.9137, 0.9631, 0.9878}
+\definecolor{kit-cyan5}{rgb}{0.9569, 0.9816, 0.9939}
+
+% KIT color gray :
+\definecolor{kit-gray}{RGB}{0, 0, 0}
+\definecolor{kit-gray100}{RGB}{0, 0, 0}
+\definecolor{kit-gray90}{rgb}{0.1, 0.1, 0.1}
+\definecolor{kit-gray80}{rgb}{0.2, 0.2, 0.2}
+\definecolor{kit-gray75}{rgb}{0.25, 0.25, 0.25}
+\definecolor{kit-gray70}{rgb}{0.3, 0.3, 0.3}
+\definecolor{kit-gray60}{rgb}{0.4, 0.4, 0.4}
+\definecolor{kit-gray50}{rgb}{0.5, 0.5, 0.5}
+\definecolor{kit-gray40}{rgb}{0.6, 0.6, 0.6}
+\definecolor{kit-gray30}{rgb}{0.7, 0.7, 0.7}
+\definecolor{kit-gray25}{rgb}{0.75, 0.75, 0.75}
+\definecolor{kit-gray20}{rgb}{0.8, 0.8, 0.8}
+\definecolor{kit-gray15}{rgb}{0.85, 0.85, 0.85}
+\definecolor{kit-gray10}{rgb}{0.9, 0.9, 0.9}
+\definecolor{kit-gray5}{rgb}{0.95, 0.95, 0.95}
+
+
+
+\setbeamercolor*{normal text}{fg=black}
+\setbeamercolor*{alerted text}{fg=kit-red100}
+\setbeamercolor*{example text}{fg=black}
+\setbeamercolor*{structure}{fg=black}
+
+\setbeamercolor*{palette primary}{fg=black,bg=black!15}
+\setbeamercolor*{palette secondary}{fg=black,bg=black!15}
+\setbeamercolor*{palette tertiary}{fg=black,bg=black!15}
+\setbeamercolor*{palette quaternary}{fg=black,bg=black!15}
+
+\setbeamercolor*{palette sidebar primary}{fg=black!75}
+\setbeamercolor*{palette sidebar secondary}{fg=black!75}
+\setbeamercolor*{palette sidebar tertiary}{fg=black!75}
+\setbeamercolor*{palette sidebar quaternary}{fg=black!75}
+
+\setbeamercolor*{item projected}{fg=white,bg=kit-green100}
+
+\setbeamercolor*{block title}{fg=white,bg=kit-green100}
+\setbeamercolor*{block title alerted}{use=alerted text,fg=white,bg=alerted text.fg!75!black}
+\setbeamercolor*{block title example}{fg=white,bg=kit-blue100}
+
+\setbeamercolor*{block body}{fg=black,bg=kit-green15}
+\setbeamercolor*{block body alerted}{parent=normal text,use=block title alerted,bg=block title alerted.bg!10!bg}
+\setbeamercolor*{block body example}{fg=black,bg=kit-blue15}
+
+\setbeamercolor*{separation line}{}
+\setbeamercolor*{fine separation line}{}
+
+\setbeamercolor*{background canvas}{bg=white}
+
+%% -----------
+%% | /Farben |
+%% -----------
+
+%% -----------------------------------
+%% | halbgerundete Aufzählungspunkte |
+%% -----------------------------------
+
+\newcommand{\itemizeColor}{kit-green100}
+
+% KIT-Aufzählungszeichen
+\newcommand{\KITmark}{%
+ \begin{pgfpicture}{0mm}{0mm}{1ex}{1ex}
+ {\pgfsetcornersarced{\pgfpoint{.3ex}{.3ex}}
+ \pgfpathmoveto{\pgfpoint{0cm}{1ex}}
+ \pgfpathlineto{\pgfpoint{1ex}{1ex}}
+ \pgfpathlineto{\pgfpoint{1ex}{0cm}}}
+ {\pgfsetcornersarced{\pgfpoint{.3ex}{.3ex}}
+ \pgfpathmoveto{\pgfpoint{1ex}{0cm}}
+ \pgfpathlineto{\pgfpointorigin}
+ \pgfpathlineto{\pgfpoint{0cm}{1ex}}}
+ \color{\itemizeColor}
+ \pgfusepath{fill}
+ \end{pgfpicture}%
+}
+
+% \setbeamertemplate{itemize items}{\raisebox{.2ex}{\KITmark}}
+\setbeamertemplate{itemize items}[square]
+\setbeamercolor{itemize item}{fg=kit-green100}
+
+%% ----------------------
+%% | Inhaltsverzeichnis |
+%% ----------------------
+
+\setbeamertemplate{section in toc}{\normalsize\textbf{\textcolor{kit-blue}{\inserttocsectionnumber.~\inserttocsection}}\par}
+\setbeamertemplate{subsection in toc}{\small\hspace{1.2em}\raisebox{.2ex}{\KITmark}\hspace{\labelsep}\inserttocsubsection\par}
+
+%% ------------------------------
+%% | halbgerundete Beamer-Boxen |
+%% ------------------------------
+
+\renewcommand\beamerboxesrounded[2][]{%
+ \global\let\beamer@firstlineitemizeunskip=\relax%
+ \vbox\bgroup%
+ \setkeys{beamerboxes}{upper=block title,lower=block body,width=\textwidth,shadow=false}%
+ \setkeys{beamerboxes}{#1}%
+ {%
+ \usebeamercolor{\bmb@lower}%
+ \globalcolorstrue%
+ \colorlet{lower.bg}{bg}%
+ }%
+ {%
+ \usebeamercolor{\bmb@upper}%
+ \globalcolorstrue%
+ \colorlet{upper.bg}{bg}%
+ }%
+ %
+ % Typeset head
+ %
+ \vskip4bp
+ \setbox\bmb@box=\hbox{%
+ \begin{minipage}[b]{\bmb@width}%
+ \usebeamercolor[fg]{\bmb@upper}%
+ #2%
+ \end{minipage}}%
+ \ifdim\wd\bmb@box=0pt%
+ \setbox\bmb@box=\hbox{}%
+ \ht\bmb@box=1.5pt%
+ \bmb@prevheight=-4.5pt%
+ \else%
+ \wd\bmb@box=\bmb@width%
+ \bmb@temp=\dp\bmb@box%
+ \ifdim\bmb@temp<1.5pt%
+ \bmb@temp=1.5pt%
+ \fi%
+ \setbox\bmb@box=\hbox{\raise\bmb@temp\hbox{\box\bmb@box}}%
+ \dp\bmb@box=0pt%
+ \bmb@prevheight=\ht\bmb@box%
+ \fi%
+ \bmb@temp=\bmb@width%
+ \bmb@dima=\bmb@temp\advance\bmb@dima by2.2bp%
+ \bmb@dimb=\bmb@temp\advance\bmb@dimb by4bp%
+ \hbox{%
+ \begin{pgfpicture}{0bp}{+-\ht\bmb@box}{0bp}{+-\ht\bmb@box}
+ \ifdim\wd\bmb@box=0pt%
+ \color{lower.bg}%
+ \else%
+ \color{upper.bg}%
+ \fi%
+ \pgfpathqmoveto{-4bp}{-1bp}
+ % Adaption for "KIT-Design"
+ \pgfpathlineto{\pgfpoint{-4bp}{3bp}}
+ %\pgfpathqcurveto{-4bp}{1.2bp}{-2.2bp}{3bp}{0bp}{3bp}
+ \pgfpathlineto{\pgfpoint{\bmb@temp}{3bp}}
+ \pgfpathcurveto%
+ {\pgfpoint{\bmb@dima}{3bp}}%
+ {\pgfpoint{\bmb@dimb}{1.2bp}}%
+ {\pgfpoint{\bmb@dimb}{-1bp}}%
+ \bmb@dima=-\ht\bmb@box%
+ \advance\bmb@dima by-2pt%
+ \pgfpathlineto{\pgfpoint{\bmb@dimb}{\bmb@dima}}
+ \pgfpathlineto{\pgfpoint{-4bp}{\bmb@dima}}
+ \pgfusepath{fill}
+ \end{pgfpicture}%
+ \copy\bmb@box%
+ }%
+ \nointerlineskip%
+ \vskip-1pt%
+ \ifdim\wd\bmb@box=0pt%
+ \else%
+ \hbox{%
+ \begin{pgfpicture}{0pt}{0pt}{\bmb@width}{6pt}
+ \bmb@dima=\bmb@width%
+ \advance\bmb@dima by8bp%
+ \pgfpathrectangle{\pgfpoint{-4bp}{-1bp}}{\pgfpoint{\bmb@dima}{8bp}}
+ \pgfusepath{clip}
+ {\pgftransformshift{\pgfpoint{-4bp}{0bp}}\pgftext[left,base]{\pgfuseshading{bmb@transition}}}%
+ \end{pgfpicture}%
+ }%
+ \nointerlineskip%
+ \vskip-0.5pt%
+ \fi%
+ \ifbmb@shadow%
+ \setbox\bmb@boxshadow=\hbox{\pgfuseshading{bmb@shadow}}%
+ \setbox\bmb@boxshadowball=\hbox{\pgfuseshading{bmb@shadowball}}%
+ \setbox\bmb@boxshadowballlarge=\hbox{\pgfuseshading{bmb@shadowballlarge}}%
+ \fi%
+ \setbox\bmb@colorbox=\hbox{{\pgfpicturetrue\pgfsetcolor{lower.bg}}}%
+ \setbox\bmb@box=\hbox\bgroup\begin{minipage}[b]{\bmb@width}%
+ \vskip2pt%
+ \usebeamercolor[fg]{\bmb@lower}%
+ \colorlet{beamerstructure}{upper.bg}%
+ \colorlet{structure}{upper.bg}%
+ %\color{.}%
+ }
+
+\def\endbeamerboxesrounded{%
+ \end{minipage}\egroup%
+ \wd\bmb@box=\bmb@width%
+ \bmb@temp=\dp\bmb@box%
+ \advance\bmb@temp by.5pt%
+ \setbox\bmb@box=\hbox{\raise\bmb@temp\hbox{\box\bmb@box}}%
+ \dp\bmb@box=0pt%
+ \bmb@temp=\wd\bmb@box%
+ \bmb@dima=\bmb@temp\advance\bmb@dima by2.2bp%
+ \bmb@dimb=\bmb@temp\advance\bmb@dimb by4bp%
+ \hbox{%
+ \begin{pgfpicture}{0bp}{0bp}{0bp}{0bp}
+ \ifbmb@shadow%
+ {\pgftransformshift{\pgfpoint{4bp}{-3bp}}\pgftext{\copy\bmb@boxshadowball}}
+ \begin{pgfscope}
+ {%
+ \advance\bmb@temp by-1bp%
+ \pgfpathrectangle{\pgfpoint{\bmb@temp}{-7bp}}{\pgfpoint{9bp}{9bp}}%
+ \pgfusepath{clip}
+ }%
+ {\pgftransformshift{\pgfpoint{\bmb@temp}{1bp}}\pgftext{\box\bmb@boxshadowballlarge}}
+ \end{pgfscope}
+ \begin{pgfscope}
+ \advance\bmb@temp by-4bp%
+ \pgfpathrectangle{\pgfpoint{4bp}{-7bp}}{\pgfpoint{\bmb@temp}{5bp}}
+ \pgfusepath{clip}
+ {\pgftransformshift{\pgfpoint{4bp}{-7bp}}\pgftext[left,base]{\copy\bmb@boxshadow}}%
+ \end{pgfscope}
+ \begin{pgfscope}
+ \advance\bmb@temp by 4bp%
+ \bmb@dima=\ht\bmb@box%
+ \advance\bmb@dima by\bmb@prevheight%
+ \advance\bmb@dima by 4bp%
+ \pgfpathrectangle{\pgfpoint{\bmb@temp}{1bp}}{\pgfpoint{4bp}{\bmb@dima}}
+ \pgfusepath{clip}
+ \advance\bmb@dima by-4bp%
+ {\pgftransformshift{\pgfpoint{\bmb@temp}{\bmb@dima}}\pgftext{\box\bmb@boxshadowball}}
+ \advance\bmb@dima by-1bp%
+ \pgfpathrectangle{\pgfpoint{\bmb@temp}{1bp}}{\pgfpoint{4bp}{\bmb@dima}}
+ \pgfusepath{clip}
+ \advance\bmb@temp by4bp%
+ {\pgftransformshift{\pgfpoint{\bmb@temp}{-3bp}}%
+ \pgftransformrotate{90}%
+ \pgftext[left,base]{\box\bmb@boxshadow}}%
+ \end{pgfscope}
+ \fi%
+ \unhbox\bmb@colorbox%
+ \pgfpathqmoveto{-4bp}{1bp}
+ \pgfpathqcurveto{-4bp}{-1.2bp}{-2.2bp}{-3bp}{0bp}{-3bp}
+ \pgfpathlineto{\pgfpoint{\the\bmb@dimb}{-3bp}}
+ {
+ \bmb@dima=\ht\bmb@box%
+ \pgfpathlineto{\pgfpoint{\bmb@dimb}{\bmb@dima}}
+ \pgfpathlineto{\pgfpoint{-4bp}{\bmb@dima}}
+ \pgfusepath{fill}
+ }
+ \ifbmb@shadow%
+ {
+ \color{black!50!bg}
+ \pgfsetlinewidth{0pt}
+ \pgfpathmoveto{\pgfpoint{\bmb@dimb}{-.5bp}}
+ \bmb@dima=\ht\bmb@box%
+ \advance\bmb@dima by\bmb@prevheight%
+ \advance\bmb@dima by 1bp%
+ \pgfpathlineto{\pgfpoint{\bmb@dimb}{\bmb@dima}}
+ \pgfusepath{stroke}
+ \bmb@temp=\bmb@dima
+ \advance\bmb@dima by 1bp%
+ \color{black!31!bg}
+ \pgfpathmoveto{\pgfpoint{\bmb@dimb}{\bmb@temp}}
+ \pgfpathlineto{\pgfpoint{\bmb@dimb}{\bmb@dima}}
+ \pgfusepath{stroke}
+ \advance\bmb@dima by 1bp%
+ \advance\bmb@temp by 1bp%
+ \color{black!19!bg}
+ \pgfpathmoveto{\pgfpoint{\bmb@dimb}{\bmb@temp}}
+ \pgfpathlineto{\pgfpoint{\bmb@dimb}{\bmb@dima}}
+ \pgfusepath{stroke}
+ \advance\bmb@dima by 1bp%
+ \advance\bmb@temp by 1bp%
+ \color{black!6!bg}
+ \pgfpathmoveto{\pgfpoint{\bmb@dimb}{\bmb@temp}}
+ \pgfpathlineto{\pgfpoint{\bmb@dimb}{\bmb@dima}}
+ \pgfusepath{stroke}
+ \advance\bmb@dima by 1.5bp%
+ \advance\bmb@temp by 1bp%
+ \color{bg}
+ \pgfpathmoveto{\pgfpoint{\bmb@dimb}{\bmb@temp}}
+ \pgfpathlineto{\pgfpoint{\bmb@dimb}{\bmb@dima}}
+ \pgfusepath{stroke}
+ }
+ \fi
+ \end{pgfpicture}%
+ \box\bmb@box%
+ }%
+ \ifbmb@shadow%
+ \vskip4bp minus 2bp%
+ \else%
+ \vskip2bp%
+ \fi%
+ \egroup% of \vbox\bgroup
+}
+
+
+%% -------------------------------
+%% | /halbgerundete Beamer-Boxen |
+%% -------------------------------
+
+
+%% ----------------------
+%% | Block-Definitionen |
+%% ----------------------
+
+% Content environment for structuring. Basically a headline followed by text
+\newenvironment<>{contentblock}[1]{\begingroup%
+ \setbeamertemplate{blocks}[default]
+ \setbeamercolor{block body}{fg=black,bg=}%
+ \setbeamercolor{block title}{fg=black,bg=}%
+ \setbeamerfont*{block title}{family=\sffamily,series=\bfseries,size=\large}
+ \begin{block}#2{#1}%
+ }{\end{block}%
+\endgroup}
+
+
+\newenvironment<>{greenblock}[1]{\begingroup%
+ \setbeamercolor{block body}{fg=black,bg=kit-green15}%
+ \setbeamercolor{block title}{fg=white,bg=kit-green100}%
+ \begin{block}#2{#1}%
+ }{\end{block}
+\endgroup}
+
+\newenvironment<>{blueblock}[1]{\begingroup%
+ \setbeamercolor{block body}{fg=black,bg=kit-blue15}%
+ \setbeamercolor{block title}{fg=white,bg=kit-blue100}%
+ \setbeamercolor{itemize item}{fg=kit-blue100}
+ \begin{block}#2{#1}%
+ }{\end{block}
+\endgroup}
+
+\newenvironment<>{redblock}[1]{\begingroup%
+ \setbeamercolor{block body}{fg=black,bg=kit-red15}%
+ \setbeamercolor{block title}{fg=white,bg=kit-red100}%
+ \setbeamercolor{itemize item}{fg=kit-red100}%
+ \begin{block}#2{#1}%
+ }{\end{block}%
+\endgroup}
+
+\newenvironment<>{brownblock}[1]{\begingroup%
+ \setbeamercolor{block body}{fg=black,bg=kit-brown15}%
+ \setbeamercolor{block title}{fg=white,bg=kit-brown100}%
+ \setbeamercolor{itemize item}{fg=kit-brown100}%
+ \begin{block}#2{#1}%
+ }{\end{block}%
+\endgroup}
+
+\newenvironment<>{purpleblock}[1]{\begingroup%
+ \setbeamercolor{block body}{fg=black,bg=kit-purple15}%
+ \setbeamercolor{block title}{fg=white,bg=kit-purple100}%
+ \setbeamercolor{itemize item}{fg=kit-purple100}%
+ \begin{block}#2{#1}%
+ }{\end{block}%
+\endgroup}
+
+\newenvironment<>{grayblock}[1]{\begingroup%
+ \setbeamercolor{block body}{fg=black,bg=kit-gray15}%
+ \setbeamercolor{block title}{fg=white,bg=kit-gray70}%
+ \setbeamercolor{itemize item}{fg=kit-gray70}%
+ \begin{block}#2{#1}%
+ }{\end{block}%
+\endgroup}
+
+\newenvironment<>{yellowblock}[1]{\begingroup%
+ \setbeamercolor{block body}{fg=black,bg=kit-yellow30}%
+ \setbeamercolor{block title}{fg=black,bg=kit-yellow100}%
+ \setbeamercolor{itemize item}{fg=kit-yellow100}%
+ \begin{block}#2{#1}%
+ }{\end{block}%
+\endgroup}
+
+\newenvironment<>{lightgreenblock}[1]{\begingroup%
+ \setbeamercolor{block body}{fg=black,bg=kit-lightgreen15}%
+ \setbeamercolor{block title}{fg=white,bg=kit-lightgreen100}%
+ \setbeamercolor{itemize item}{fg=kit-lightgreen100}%
+ \begin{block}#2{#1}%
+ }{\end{block}%
+\endgroup}
+
+\newenvironment<>{orangeblock}[1]{\begingroup%
+ \setbeamercolor{block body}{fg=black,bg=kit-orange15}%
+ \setbeamercolor{block title}{fg=white,bg=kit-orange100}%
+ \setbeamercolor{itemize item}{fg=kit-orange100}%
+ \begin{block}#2{#1}%
+ }{\end{block}%
+\endgroup}
+
+\newenvironment<>{cyanblock}[1]{\begingroup%
+ \setbeamercolor{block body}{fg=black,bg=kit-cyan15}%
+ \setbeamercolor{block title}{fg=white,bg=kit-cyan100}%
+ \setbeamercolor{itemize item}{fg=kit-cyan100}%
+ \begin{block}#2{#1}%
+ }{\end{block}%
+\endgroup}
+
+\newenvironment<>{maroonblock}[1]{\begingroup%
+\setbeamercolor{block body}{fg=black,bg=Maroon!15}%
+\setbeamercolor{block title}{fg=white,bg=Maroon}%
+ \setbeamercolor{itemize item}{fg=Maroon}%
+\begin{block}#2{#1}%
+}{\end{block}%
+\endgroup}
+%% ------------------------------
+%% | /Block-Definitionen |
+%% ------------------------------
+
+%% use this for setting the total page number
+\newcommand{\beginbackup}{
+ \newcounter{framenumbervorappendix}
+ \setcounter{framenumbervorappendix}{\value{framenumber}}
+}
+\newcommand{\backupend}{
+ \addtocounter{framenumbervorappendix}{-\value{framenumber}}
+ \addtocounter{framenumber}{\value{framenumbervorappendix}}
+}
diff --git a/21-implementierungsheft-kolloquium/slides/changes.tex b/21-implementierungsheft-kolloquium/slides/changes.tex
new file mode 100644
index 0000000..692c6ce
--- /dev/null
+++ b/21-implementierungsheft-kolloquium/slides/changes.tex
@@ -0,0 +1,84 @@
+\begin{frame}{Änderungen zum Entwurf}
+
+\vspace{-.4cm}
+\begin{orangeblock}{Kompatibilität}
+ \begin{minipage}{1.7cm}
+ \centering
+ \fontsize{23pt}{0pt}
+ \selectfont
+ \textcolor{orange}
+ \faPlug
+ \end{minipage}
+ \hspace{-.5cm}
+ \begin{minipage}{.7\textwidth}
+ \begin{itemize}
+ \item Benutzernamen und E-Mail-Adresse speichern
+ \item Device API
+ \end{itemize}
+ \end{minipage}
+\end{orangeblock}
+
+\begin{greenblock}{E-Mail-Verifizierung}
+ \begin{minipage}{1.7cm}
+ \centering
+ \fontsize{23pt}{0pt}
+ \selectfont
+ \textcolor{kit-green}
+ \faUserCheck
+ \end{minipage}
+ \hspace{-.5cm}
+ \begin{minipage}{.7\textwidth}
+ \begin{itemize}
+ \item Neuer Endpunkt zur Verifizierung der E-Mail-Adresse
+ \item Anmelden nur mit bestätigter E-Mail-Adresse
+ \end{itemize}
+ \end{minipage}
+\end{greenblock}
+
+\begin{blueblock}{RSS Parser}
+ \begin{minipage}{1.7cm}
+ \centering
+ \fontsize{23pt}{0pt}
+ \selectfont
+ \textcolor{kit-blue}
+ \faRssSquare
+ \end{minipage}
+ \hspace{-.5cm}
+ \begin{minipage}{.7\textwidth}
+ \begin{itemize}
+ \item Asynchroner RSS Parser nach \enquote{Fire and Forget} Prinzip
+ \item Speichern/Löschen über Referenzen in DAO-Schicht
+ \end{itemize}
+ \end{minipage}
+\end{blueblock}
+
+\begin{redblock}{Datenzugriffsschicht}
+ \begin{minipage}{1.7cm}
+ \centering
+ \fontsize{23pt}{0pt}
+ \selectfont
+ \textcolor{kit-red}
+ \faDatabase
+ \end{minipage}
+ \hspace{-.5cm}
+ \begin{minipage}{.7\textwidth}
+ \begin{itemize}
+ \item \sout{DAO-Implementierungen} (JPA-Repository)
+ \end{itemize}
+ \end{minipage}
+\end{redblock}
+
+%
+% Original
+%
+%\begin{itemize}
+% \item Kompatibilität mit Podcatchern \begin{itemize}
+% \item Speicherung von Benutzernamen und E-Mail-Adressen
+% \item Device API
+% \end{itemize}
+% \item Verifizierung der E-Mail-Adresse
+% \item RSSParser
+% \item Reduzierte Datenzugriffsschicht
+%\end{itemize}
+
+\end{frame}
diff --git a/21-implementierungsheft-kolloquium/slides/classdiagram.tex b/21-implementierungsheft-kolloquium/slides/classdiagram.tex
new file mode 100644
index 0000000..3186a53
--- /dev/null
+++ b/21-implementierungsheft-kolloquium/slides/classdiagram.tex
@@ -0,0 +1,36 @@
+\begin{frame}[t]{Einführung}
+ \centering
+ \includegraphics[width=\textwidth]{assets/diagrams/classdiagram}
+\end{frame}
+
+% sub
+% episode
+% auth
+% model
+% util
+
+\begin{frame}[t]{Subscriptions-API}
+ \centering
+ \includegraphics[width=\textwidth]{assets/diagrams/classdiagram-subscriptions}
+\end{frame}
+
+\begin{frame}[t]{EpisodeActions-API}
+ \centering
+ \includegraphics[width=\textwidth]{assets/diagrams/classdiagram-episode-actions}
+\end{frame}
+
+\begin{frame}[t]{Authentication-API}
+ \centering
+ \includegraphics[width=.75\textwidth]{assets/diagrams/classdiagram-authentication}
+\end{frame}
+
+\begin{frame}[t]{Model-Paket}
+ \centering
+ \includegraphics[width=\textwidth]{assets/diagrams/classdiagram-model}
+\end{frame}
+
+\begin{frame}[t]{Util-Paket}
+ \centering
+ \includegraphics[width=\textwidth]{assets/diagrams/classdiagram-util}
+\end{frame}
+
diff --git a/21-implementierungsheft-kolloquium/slides/components.tex b/21-implementierungsheft-kolloquium/slides/components.tex
new file mode 100644
index 0000000..5a6afe6
--- /dev/null
+++ b/21-implementierungsheft-kolloquium/slides/components.tex
@@ -0,0 +1,7 @@
+\begin{frame}[t]{Komponenten Backend}
+
+ \begin{figure}[h]
+ \includegraphics[width=0.7\textwidth]{assets/diagrams/backendComponentDiagram}
+ \end{figure}
+
+\end{frame} \ No newline at end of file
diff --git a/21-implementierungsheft-kolloquium/slides/difficulties.tex b/21-implementierungsheft-kolloquium/slides/difficulties.tex
new file mode 100644
index 0000000..d3e64dd
--- /dev/null
+++ b/21-implementierungsheft-kolloquium/slides/difficulties.tex
@@ -0,0 +1,34 @@
+\begin{frame}{Schwierigkeiten}
+
+ \begin{columns}[t]
+
+ \begin{column}{.5\textwidth}
+ \centering{\fontsize{30pt}{36pt}\selectfont\faDesktop}
+ \vspace{.2cm}
+ \begin{blueblock}{Dashboard}
+ \begin{itemize}
+ \item CORS Einschränkung
+ \item Error-Handling
+ \item Kommunikation zwischen Komponenten
+ \end{itemize}
+ \end{blueblock}
+ \end{column}
+
+ \begin{column}{.5\textwidth}
+ \centering{\fontsize{30pt}{36pt}\selectfont\faServer}
+ \vspace{.2cm}
+ \begin{orangeblock}{Server}
+ \begin{itemize}
+ \item Authentifizierung
+ \item API
+ \item EpisodeActionService (AntennaPod)
+ \end{itemize}
+ \end{orangeblock}
+ \end{column}
+
+
+ \end{columns}
+
+
+\end{frame}
+
diff --git a/21-implementierungsheft-kolloquium/slides/einführung.tex b/21-implementierungsheft-kolloquium/slides/einführung.tex
new file mode 100644
index 0000000..d818cd3
--- /dev/null
+++ b/21-implementierungsheft-kolloquium/slides/einführung.tex
@@ -0,0 +1,40 @@
+\begin{frame}[t]{Einführung}
+
+
+ \begin{columns}[t]
+ \begin{column}{.3\textwidth}
+ \centering{\fontsize{30pt}{36pt}\selectfont\faPodcast}
+ \vspace{.2cm}
+ \begin{block}{Podcast}
+ \begin{itemize}
+ \item RSS-Feed
+ \item Episoden
+ \item Audio/Video
+ \end{itemize}
+ \end{block}
+ \end{column}
+ \begin{column}{.3\textwidth}
+ \centering{\fontsize{30pt}{36pt}\selectfont\faArrowCircleDown}
+ \vspace{.2cm}
+ \begin{block}{Podcatcher}
+ \begin{itemize}
+ \item lokale Verwaltung von Podcasts
+ \item API Unterstützung
+ \item Abspielen von Episoden
+ \end{itemize}
+ \end{block}
+ \end{column}
+ \begin{column}{.3\textwidth}
+ \centering{\fontsize{30pt}{36pt}\selectfont\faSync}
+ \vspace{.2cm}
+ \begin{block}{Synchronisationsserver}
+ \begin{itemize}
+ \item Hörfortschritte
+ \item Abonnements
+ \item Discovery
+ \end{itemize}
+ \end{block}
+ \end{column}
+ \end{columns}
+
+\end{frame} \ No newline at end of file
diff --git a/21-implementierungsheft-kolloquium/slides/features.tex b/21-implementierungsheft-kolloquium/slides/features.tex
new file mode 100644
index 0000000..6ec435b
--- /dev/null
+++ b/21-implementierungsheft-kolloquium/slides/features.tex
@@ -0,0 +1,37 @@
+\begin{frame}{Features}
+\begin{columns}[t]
+\begin{column}{.3\textwidth}
+\centering{\fontsize{30pt}{36pt}\selectfont\faSync}
+\vspace{.2cm}
+\begin{block}{Synchronisation}
+\begin{itemize}
+ \item Abos
+ \item Hörfortschritt
+\end{itemize}
+\end{block}
+\end{column}
+\begin{column}{.3\textwidth}
+\centering{\fontsize{30pt}{36pt}\selectfont\faGlobe}
+\vspace{.2cm}
+\begin{block}{Weboberfläche}
+\begin{itemize}
+ \item Aboliste
+ \item Zuletzt gehört
+\end{itemize}
+\end{block}
+\end{column}
+\begin{column}{.3\textwidth}
+\centering{\fontsize{30pt}{36pt}\selectfont\faUser}
+\vspace{.2cm}
+\begin{block}{Account-Verwaltung}
+\begin{itemize}
+ \item Registrieren und Anmelden
+ \item Passwort ändern und zurücksetzen
+ \item Account löschen
+ \item Daten importieren/exportieren
+\end{itemize}
+\end{block}
+\end{column}
+\end{columns}
+\end{frame}
+
diff --git a/21-implementierungsheft-kolloquium/slides/gantt.tex b/21-implementierungsheft-kolloquium/slides/gantt.tex
new file mode 100644
index 0000000..31ed9b9
--- /dev/null
+++ b/21-implementierungsheft-kolloquium/slides/gantt.tex
@@ -0,0 +1,11 @@
+\begin{frame}{Geplanter Zeitplan}
+
+\includegraphics[width=\textwidth]{assets/gantt-plan.eps}
+
+\end{frame}
+\begin{frame}{Tatsächlicher Zeitplan}
+
+\includegraphics[width=\textwidth]{assets/gantt-reality.eps}
+
+\end{frame}
+
diff --git a/21-implementierungsheft-kolloquium/slides/integrationstrategie.tex b/21-implementierungsheft-kolloquium/slides/integrationstrategie.tex
new file mode 100644
index 0000000..0564b5f
--- /dev/null
+++ b/21-implementierungsheft-kolloquium/slides/integrationstrategie.tex
@@ -0,0 +1,82 @@
+\begin{frame}{Integrationsstrategie}
+
+\vspace{-.5cm}
+\begin{minipage}[t]{.47\textwidth}
+ \begin{orangeblock}{Top-Down}
+ \begin{minipage}{1.6cm}
+ \centering
+ \vspace{.15cm}
+ \fontsize{30pt}{36pt}
+ \selectfont
+ \faSortAmountDown
+ \vspace{.2cm}
+ \end{minipage}
+ \hspace{-.5cm}
+ \begin{minipage}{\textwidth - 1.4cm}
+ \begin{itemize}
+ \item Schnelle anschauliche Ergebnisse
+ \item Integration von Dashboard aus zum Server
+ \item spätes Zusammenspiel mit Backend
+ \item Aufwendige/Schwere Tests
+ \end{itemize}
+ \end{minipage}
+ \end{orangeblock}
+\end{minipage}
+\hfill
+\begin{minipage}[t]{.47\textwidth}
+ \begin{greenblock}{Bottom-Up}
+ \begin{minipage}{1.6cm}
+ \centering
+ \vspace{.2cm}
+ \fontsize{30pt}{36pt}
+ \selectfont
+ {\faSortAmountUp*}
+ \vspace{.25cm}
+ \end{minipage}
+ \hspace{-.5cm}
+ \begin{minipage}{\textwidth - 1.4cm}
+ \begin{itemize}
+ \item Integration von Datenbank aus zum Dashboard
+ \item viele einfache Tests sind erforderlich
+ \item spätes Zusammenspiel mit Frontend
+ \end{itemize}
+ \end{minipage}
+ \end{greenblock}
+\end{minipage}
+\vspace{.3cm}
+
+\begin{blueblock}{Outside-In}
+ \begin{minipage}{2cm}
+ \centering
+ \vspace{.2cm}
+ \fontsize{30pt}{36pt}
+ \selectfont
+ \faCompressArrows*
+ \vspace{.3cm}
+ \end{minipage}
+ \hspace{-.5cm}
+ \begin{minipage}{\textwidth - 2cm}
+ \begin{itemize}
+ \item Vereinigt Vorteile von Bottom-Up und Top-Down
+ \item Implementierung von Dashboard und Server gleichzeitig
+ \item Schnelle Tests + anschauliche Ergebnisse
+ \item Gut Parallelisierbar auf ganze Team
+ \end{itemize}
+ \end{minipage}
+\end{blueblock}
+
+% \begin{greenblock}{Outside-In Prinzip}
+% \begin{itemize}
+% \item Eine Kombination aus dem Bottom-Up und Top-Down Prinzip
+% \item Beginnt gleichzeitig auf höchster und niedrigster Logischer Ebene
+% \item Schrittweise Integration aus beiden Richtungen
+% \begin{itemize}
+% \item Model und Datenbank
+% \item Controller und Frontend
+% \end{itemize}
+% \item Frühzeitiges testen der Endpunkte und Unit Tests
+% \item Gut Parallelisierbar auf ganze Team
+% \end{itemize}
+% \end{greenblock}
+
+\end{frame}
diff --git a/21-implementierungsheft-kolloquium/slides/pattern.tex b/21-implementierungsheft-kolloquium/slides/pattern.tex
new file mode 100644
index 0000000..141954b
--- /dev/null
+++ b/21-implementierungsheft-kolloquium/slides/pattern.tex
@@ -0,0 +1,12 @@
+\begin{frame}{Entwurfsmuster}
+ \begin{columns}
+ \column{.5\textwidth}
+ \begin{greenblock}{Dependency Injection}
+ Standard (\texttt{block})
+ \end{greenblock}
+ \column{.5\textwidth}
+ \begin{blueblock}{Data Access Object (DAO)}
+ = \texttt{exampleblock}
+ \end{blueblock}
+ \end{columns}
+\end{frame} \ No newline at end of file
diff --git a/21-implementierungsheft-kolloquium/slides/requirements.tex b/21-implementierungsheft-kolloquium/slides/requirements.tex
new file mode 100644
index 0000000..e660bb9
--- /dev/null
+++ b/21-implementierungsheft-kolloquium/slides/requirements.tex
@@ -0,0 +1,58 @@
+\begin{frame}{Muss-Kriterien}
+\rowcolors{1}{kit-orange60}{kit-orange30}
+\begin{tabular}{ >{\bfseries}l l l}
+ \rowcolor{kit-orange}
+ Bezeichner & Zusammenfassung & Implementiert\\\hline
+ \textlangle RM1 \textrangle & Registrierung, Bestätigung und Anmeldung eines Accounts über das Frontend & Ja\\
+ \textlangle RM2 \textrangle & Speichern von Abonnements und Episoden auf dem Server & Ja\\
+ \textlangle RM3 \textrangle & Synchronisierung zwischen Podcatchern & Ja\\
+ \textlangle RM4 \textrangle & Eine Weboberfläche & Ja\\
+ \textlangle RM5 \textrangle & Möglichkeit das eigene Passwort zu ändern / zurückzusetzen & Ja\\
+ \textlangle RM6 \textrangle & Abonnementliste in der Weboberfläche & Ja\\
+ \textlangle RM7 \textrangle & 50 Anfragen / Sekunde bearbeiten & Zu testen\\
+ \textlangle RM8 \textrangle & Primäre Auslegung des Webfrontends für Desktop-Nutzer & Ja\\
+ \textlangle RM9 \textrangle & Unterstützung der gpodder.net RESTful-API & Ja\\
+ \textlangle RM10\textrangle & Das Nutzen einer Datenbank zur Speicherung von Daten & Ja\\
+ \textlangle RM11\textrangle & Erweiterte API für Kommunikation zwischen Front- und Backend & Ja
+\end{tabular}
+\end{frame}
+
+\begin{frame}{Soll-Kriterien}
+\rowcolors{1}{kit-green60}{kit-green30}
+\begin{tabular}{ >{\bfseries}l l l}
+ \rowcolor{kit-green}
+ Bezeichner & Zusammenfassung & Implementiert\\\hline
+ \textlangle RS1 \textrangle & Eine Anleitung (Platzhalter) & Ja\\
+ \textlangle RS2 \textrangle & Die Möglichkeit einen Account zu löschen & Ja\\
+ \textlangle RS3 \textrangle & Spring für das Backend und MariaDB als Datenbank & Ja\\
+ \textlangle RS4 \textrangle & Vue.js und Bootstrap für das Frontend & Ja\\
+ \textlangle RS5 \textrangle & npm und vite für das Frontend & Ja\\
+ \textlangle RS6 \textrangle & Eine Single-Page-Application als Frontend mit dynamischer Aktualisierung & Ja\\
+ \textlangle RS7 \textrangle & Ein RSS-Parser um Daten aus einem RSS-Feed zu lesen & Ja\\
+ \textlangle RS8 \textrangle & Mindestanforderungen an ein Passwort & Ja\\
+ \textlangle RS9 \textrangle & Salting und Hashing für Verschlüsselung der Personenbezogenen Daten & Ja\\
+ \textlangle RS10\textrangle & Nutzer bleibt über JWT angemeldet und authentifiziert & Ja
+\end{tabular}
+\end{frame}
+
+\begin{frame}{Kann-Kriterien}
+
+\rowcolors{1}{kit-blue60}{kit-blue30}
+\begin{tabular}{ >{\bfseries}l l l }
+ \rowcolor{kit-blue}
+ Bezeichner & Zusammenfassung & Implementiert\\\hline
+ \textlangle RC1 \textrangle & Abonnierten Podcast in Weboberfläche über Link teilen und hinzufügen & Ja\\
+ \textlangle RC2 \textrangle & Abonnements in Weboberfläche deabonnieren & Nein\\
+ \textlangle RC3 \textrangle & Importieren und Exportieren aller benutzerbezogenen Daten & Ja\\
+ \textlangle RC4 \textrangle & Umsiedeln von anderen Gpodder-Plattformen & Ja\\
+ \textlangle RC5 \textrangle & Kompatible Weboberfläche für beliebige gpodder.net APIs & Entfernt\\
+ \textlangle RC6 \textrangle & Responsive designte Weboberfläche & Ja\\
+ \textlangle RC7 \textrangle & Administratorkonten mit privilegierten Funktionen & Nein\\
+ \textlangle RC8 \textrangle & OAuth 2.0 im Webfrontend & Nein\\
+ \textlangle RC9 \textrangle & Bei Ausfall des Backends im Frontend angemeldet bleiben & Ja\\
+ \textlangle RC10\textrangle & Mehrsprachige Weboberfläche & Ja\\
+ \textlangle RC11\textrangle & Erfüllung der DSGVO & Teils\\
+ \textlangle RC12\textrangle & Docker für einfaches Deployment und Sicherheit & Ja
+\end{tabular}
+\end{frame}
+
diff --git a/21-implementierungsheft-kolloquium/slides/statistics.tex b/21-implementierungsheft-kolloquium/slides/statistics.tex
new file mode 100644
index 0000000..ed9b143
--- /dev/null
+++ b/21-implementierungsheft-kolloquium/slides/statistics.tex
@@ -0,0 +1,85 @@
+\begin{frame}{Statistiken}
+
+\begin{columns}[t]
+ \begin{column}{.4\textwidth}
+ \begin{orangeblock}{Dashboard}
+ \centering
+ \begin{minipage}{.2\textwidth}
+ \centering
+ \vspace{.15cm}
+ \fontsize{30pt}{36pt}
+ \selectfont
+ \faDesktop
+ \vspace{.2cm}
+ \end{minipage}
+ \begin{tabular}{l l}
+ \textbf{SLOC} & 2020 Zeilen \\
+ \textbf{Commits} & 191 \\
+ \textbf{Dateien} & 38
+ \end{tabular}
+ \end{orangeblock}
+ \end{column}
+
+ \begin{column}{.4\textwidth}
+ \begin{greenblock}{Server}
+ \centering
+ \begin{minipage}{.2\textwidth}
+ \centering
+ \vspace{.2cm}
+ \fontsize{30pt}{36pt}
+ \selectfont
+ \faServer
+ \vspace{.25cm}
+ \end{minipage}
+ \begin{tabular}{l l}
+ \textbf{SLOC} & 3812 Zeilen \\
+ \textbf{Commits} & 305 \\
+ \textbf{Dateien} & 60
+ \end{tabular}
+ \end{greenblock}
+ \end{column}
+\end{columns}
+\vspace{.3cm}
+
+\centering
+\begin{minipage}{.9\textwidth}
+ \begin{blueblock}{Insgesamt}
+ \centering
+ \begin{minipage}{.5\textwidth}
+ \centering
+ \begin{minipage}{.2\textwidth}
+ \centering
+ \vspace{.2cm}
+ \fontsize{30pt}{36pt}
+ \selectfont
+ \faChartLine
+ \vspace{.3cm}
+ \end{minipage}
+ \begin{tabular}{l l}
+ \textbf{SLOC} & 5832 Zeilen \\
+ \textbf{Commits} & 486 \\
+ \textbf{Dateien} & 98
+ \end{tabular}
+
+ \end{minipage}
+ \end{blueblock}
+ \small SLOC und Anzahl der Dateien würden basierend der Inhalte des
+ Quellordners \texttt{src/} berechnet und beinhalten keine automatisch
+ generierten Dateien.
+\end{minipage}
+\end{frame}
+
+\begin{frame}{Zeitlicher Verlauf der Commits}
+ \textbf{Dashboard}
+ \includegraphics[width=\textwidth]{assets/commits-dashboard.png}
+ \textbf{Server}
+ \includegraphics[width=\textwidth]{assets/commits-server.png}
+\end{frame}
+
+\begin{frame}{Commit-Verteilung Server}
+ \includegraphics[width=\textwidth]{assets/contributors-server.png}
+\end{frame}
+
+\begin{frame}{Commit-Verteilung Dashboard}
+ \includegraphics[width=\textwidth]{assets/contributors-dashboard.png}
+\end{frame}
diff --git a/21-implementierungsheft-kolloquium/slides/synchronisation.tex b/21-implementierungsheft-kolloquium/slides/synchronisation.tex
new file mode 100644
index 0000000..0849279
--- /dev/null
+++ b/21-implementierungsheft-kolloquium/slides/synchronisation.tex
@@ -0,0 +1,36 @@
+\begin{frame}{Synchronisation}
+
+ \tikzstyle{line} = [draw, -latex']
+
+ \begin{figure}[H]
+
+ \begin{tikzpicture}
+
+ \tikzset{focus/.style={rectangle, minimum width = 1cm, minimum height = 0.5cm, rounded corners, draw}};
+ \tikzset{hyperfocus/.style={rectangle, minimum width = 1cm, minimum height = 0.5cm, draw}};
+
+ \node[hyperfocus, text width = 2.6cm, fill = green!25](s){Synchronisations-\\\quad \quad Server};
+ \node[focus, left = 3cm of s, text width = 3.1cm, orange](p1){\quad \underline{p1:Podcatcher}
+ \begin{itemize}
+ \vspace{0.2cm}
+ \item Abonnements
+ \item Hörfortschritt
+ \vspace{0.1cm}
+ \end{itemize}};
+ \node[focus, above = 1.8cm of s, orange](p2){p2};
+ \node[focus, right = 2.5cm of s, orange](p3){p3};
+ \node[below = 1.7cm of s](p4){\textbf{...}};
+ \umlactor[left = 2.7cm of p2, blue!60]{Benutzer};
+
+ \draw[] (p1) -- (s);
+ \draw[] (p2) -- (s);
+ \draw[] (s) -- (p3);
+ \draw[] (s) -- (p4);
+ \path [line, thick, blue!60] (Benutzer) -- node [text width=2.5cm, midway, above=0.1cm, align=center] {Podcast abonnieren} (p2);
+ \path [line, thick, blue!60] (Benutzer) -| node [text width=2.5cm, midway, above=0.1cm, align=center] {Episode anhören} (p1);
+
+ \end{tikzpicture}
+
+ \end{figure}
+
+\end{frame} \ No newline at end of file
diff --git a/21-implementierungsheft-kolloquium/slides/zielsetzung.tex b/21-implementierungsheft-kolloquium/slides/zielsetzung.tex
new file mode 100644
index 0000000..84e1064
--- /dev/null
+++ b/21-implementierungsheft-kolloquium/slides/zielsetzung.tex
@@ -0,0 +1,39 @@
+\begin{frame}{Zielsetzung}
+
+\begin{figure}[H]
+
+\raggedright
+
+\begin{tikzpicture}
+
+\tikzset{focus/.style={rectangle, minimum width=1cm, minimum height=0.5cm, rounded corners=7pt, draw}};
+
+\tikzset{hyperfocus/.style={rectangle, minimum width=1cm, minimum height=0.5cm, draw}};
+
+\node[hyperfocus] (main) {gPodder};
+\node[focus, right = 2cm of main] (sync) {Synchronisation};
+\node[above = of sync] (share) {Inhalt teilen};
+\node[above = 0.5cm of share] (discover) {Podcasts entdecken};
+\node[text width = 3cm, below = of sync] (create) {Listen erstellen und teilen};
+\node[text width = 3cm, below = 0.5cm of create] (popular) {Publisher:\\ Was ist beliebt?};
+
+\node[hyperfocus, right = 3cm of sync, text width = 4cm] (PSE) {\underline{PSE\textsuperscript{2}}\begin{itemize}
+ \item Schlankes Design
+ \item Effizient
+ \item Intuitiv
+\end{itemize}
+};
+
+\draw[] (main) -- (sync);
+\draw[] (main) -- (share);
+\draw[] (main) |- (discover);
+\draw[] (main) -- (create);
+\draw[] (main) |- (popular);
+\draw[stealth-, thick] (sync.east) -- ($(PSE.north west) + (0, -0.3)$);
+
+
+\end{tikzpicture}
+
+\end{figure}
+
+\end{frame} \ No newline at end of file
diff --git a/21-implementierungsheft-kolloquium/tikz-uml.sty b/21-implementierungsheft-kolloquium/tikz-uml.sty
new file mode 100644
index 0000000..c6e8e0d
--- /dev/null
+++ b/21-implementierungsheft-kolloquium/tikz-uml.sty
@@ -0,0 +1,5377 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Start of tikz-uml.sty
+%
+% Some macros for UML Diagrams.
+% Home page of project :
+% Author: Nicolas Kielbasiewicz
+% Style from :
+% Fixed by Nicolas Kielbasiewicz (nicolas.kielbasiewicz@ensta-paristech.fr) in march 2016 to compile with pgf 3.00
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+\NeedsTeXFormat{LaTeX2e}[1995/12/01]%
+\ProvidesPackage{tikz-uml}[2011/01/26]%
+%
+\RequirePackage{etoolbox}%
+\RequirePackage{ifthen}%
+\RequirePackage{tikz}%
+\RequirePackage{xstring}%
+\RequirePackage{calc}%
+\RequirePackage{pgfopts}%
+\usetikzlibrary{backgrounds,arrows,shapes,fit,shadows,decorations.markings}%
+%
+\def\tikzumlPackageLayersNum{3}%
+\pgfkeys{/tikzuml/options/.cd, packageLayers/.initial=3}%
+\pgfkeys{/tikzuml/options/.cd, packageLayers/.store in=\tikzumlPackageLayersNum}%
+\def\tikzumlStateLayersNum{3}%
+\pgfkeys{/tikzuml/options/.cd, stateLayers/.initial=3}%
+\pgfkeys{/tikzuml/options/.cd, stateLayers/.store in=\tikzumlStateLayersNum}%
+\def\tikzumlFragmentLayersNum{3}%
+\pgfkeys{/tikzuml/options/.cd, fragmentLayers/.initial=3}%
+\pgfkeys{/tikzuml/options/.cd, fragmentLayers/.store in=\tikzumlFragmentLayersNum}%
+\def\tikzumlComponentLayersNum{3}%
+\pgfkeys{/tikzuml/options/.cd, componentLayers/.initial=3}%
+\pgfkeys{/tikzuml/options/.cd, componentLayers/.store in=\tikzumlComponentLayersNum}%
+%
+\ProcessPgfOptions{/tikzuml/options}%
+%
+\def\pgfsetlayersArg{background}%
+\pgfdeclarelayer{background}%
+\newcounter{tikzumlPackageLayers}%
+\loop \pgfdeclarelayer{package\thetikzumlPackageLayers}%
+ \xdef\pgfsetlayersArg{\pgfsetlayersArg,package\thetikzumlPackageLayers}%
+ \ifnum\tikzumlPackageLayersNum>\thetikzumlPackageLayers%
+ \stepcounter{tikzumlPackageLayers}%
+\repeat%
+%
+\newcounter{tikzumlFragmentLayers}%
+\loop \pgfdeclarelayer{fragment\thetikzumlFragmentLayers}%
+ \xdef\pgfsetlayersArg{\pgfsetlayersArg,fragment\thetikzumlFragmentLayers}%
+ \ifnum\tikzumlFragmentLayersNum>\thetikzumlFragmentLayers%
+ \stepcounter{tikzumlFragmentLayers}%
+\repeat%
+%
+\newcounter{tikzumlStateLayers}%
+\loop \pgfdeclarelayer{state\thetikzumlStateLayers}%
+ \xdef\pgfsetlayersArg{\pgfsetlayersArg,state\thetikzumlStateLayers}%
+ \ifnum\tikzumlStateLayersNum>\thetikzumlStateLayers%
+ \stepcounter{tikzumlStateLayers}%
+\repeat%
+%
+\newcounter{tikzumlComponentLayers}%
+\loop \pgfdeclarelayer{component\thetikzumlComponentLayers}%
+ \xdef\pgfsetlayersArg{\pgfsetlayersArg,component\thetikzumlComponentLayers}%
+ \ifnum\tikzumlComponentLayersNum>\thetikzumlComponentLayers%
+ \stepcounter{tikzumlComponentLayers}%
+\repeat%
+%
+\pgfdeclarelayer{lifelines}%
+\pgfdeclarelayer{activity}%
+\pgfdeclarelayer{connections}%
+\xdef\pgfsetlayersArg{\pgfsetlayersArg,lifelines,activity,connections,main}%
+\pgfsetlayers{\pgfsetlayersArg}%
+%
+\pgfkeys{/tikzuml/.cd, text/.initial=black, draw/.initial=black, font/.initial=\small,%
+ x/.initial=0, y/.initial=0,%
+ package type/.initial=tikzumlEmpty, fill package/.initial=blue!20,%
+ class width/.initial=10ex, simple interface width/.initial=4ex, class type/.initial=class, fill class/.initial=yellow!20, fill template/.initial=yellow!2,%
+ narynode width/.initial=6ex,%
+ relation geometry/.initial=--, relation angle1/.initial=-30, relation angle2/.initial=30, relation loopsize/.initial=3em, relation weight/.initial=0.5, relation pos1/.initial=0.2, relation pos2/.initial=0.8, relation pos stereo/.initial=0.5,%
+ note width/.initial=3cm, fill note/.initial=green!20,%
+ fill system/.initial=white,%
+ fill usecase/.initial=blue!20,%
+ actor below/.initial=0.5cm,%
+ state join width/.initial=3ex,%
+ state decision width/.initial=3ex,%
+ state initial width/.initial=5ex,%
+ state final width/.initial=5.5ex,%
+ state enter width/.initial=5ex,%
+ state exit width/.initial=5ex,%
+ state end width/.initial=5ex,%
+ state history width/.initial=5ex,%
+ state deep history width/.initial=5ex,%
+ state width/.initial=8ex, fill state/.initial=yellow!20,%
+ object stereo/.initial=object, fill object/.initial=yellow!20,%
+ call dt/.initial=tikzumlEmpty, call padding/.initial=2, call type/.initial=synchron, fill call/.initial=white,%
+ fragment type/.initial=opt, fragment inner xsep/.initial=1, fragment inner ysep/.initial=1, fill fragment/.initial= none,%
+ create call dt/.initial=4,%
+ component width/.initial=8ex, fill component/.initial= yellow!20,%
+ required interface distance/.initial=2.5cm, required interface width/.initial=1em, required interface padding/.initial=1cm,%
+ provided interface distance/.initial=3cm, provided interface width/.initial=1em, provided interface padding/.initial=1cm,%
+ port width/.initial=1ex, fill port/.initial= yellow!20,%
+ fill assembly connector/.initial= white,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \errmessage{TIKZUML ERROR : in tikzuml global, invalid option \keyname}%
+ }%
+}%
+%
+\pgfkeys{/tikzuml/.cd, text/.get=\tikzumlDefaultTextColor, draw/.get=\tikzumlDefaultDrawColor, font/.get=\tikzumlDefaultFont,%
+ x/.get=\tikzumlDefaultX, y/.get=\tikzumlDefaultY,%
+ package type/.get=\tikzumlPackageDefaultType, fill package/.get=\tikzumlPackageDefaultFillColor,%
+ class width/.get=\tikzumlClassDefaultWidth, simple interface width/.get=\tikzumlSimpleInterfaceDefaultWidth, class type/.get=\tikzumlClassDefaultType, fill class/.get=\tikzumlClassDefaultFillColor, fill template/.get=\tikzumlClassTemplateFillColorDefaultFillColor,%
+ narynode width/.get=\tikzumlNaryNodeDefaultWidth,%
+ relation geometry/.get=\tikzumlRelationDefaultGeometry, relation angle1/.get=\tikzumlRelationDefaultAngleO, relation angle2/.get=\tikzumlRelationDefaultAngleT, relation loopsize/.get=\tikzumlRelationDefaultLoopSize, relation weight/.get=\tikzumlRelationDefaultWeight, relation pos1/.get=\tikzumlRelationDefaultPosO, relation pos2/.get=\tikzumlRelationDefaultPosT, relation pos stereo/.get=\tikzumlRelationDefaultPosStereo,%
+ note width/.get=\tikzumlNoteDefaultWidth, fill note/.get=\tikzumlNoteDefaultFillColor,%
+ fill system/.get=\tikzumlSystemDefaultFillColor,%
+ fill usecase/.get=\tikzumlUseCaseDefaultFillColor,%
+ actor below/.get=\tikzumlActorDefaultBelow,%
+ state join width/.get=\tikzumlStateJoinDefaultWidth,%
+ state decision width/.get=\tikzumlStateDecisionDefaultWidth,%
+ state initial width/.get=\tikzumlStateInitialDefaultWidth,%
+ state final width/.get=\tikzumlStateFinalDefaultWidth,%
+ state enter width/.get=\tikzumlStateEnterDefaultWidth,%
+ state exit width/.get=\tikzumlStateExitDefaultWidth,%
+ state end width/.get=\tikzumlStateEndDefaultWidth,%
+ state history width/.get=\tikzumlStateHistoryDefaultWidth,%
+ state deep history width/.get=\tikzumlStateDeepHistoryDefaultWidth,%
+ state width/.get=\tikzumlStateDefaultWidth, fill state/.get=\tikzumlStateDefaultFillColor,%
+ object stereo/.get=\tikzumlObjectDefaultStereo, fill object/.get=\tikzumlObjectDefaultFillColor,%
+ call dt/.get=\tikzumlCallDefaultDT, call padding/.get=\tikzumlCallDefaultPadding, call type/.get=\tikzumlCallDefaultType, fill call/.get=\tikzumlCallDefaultFillColor,%
+ fragment type/.get=\tikzumlFragmentDefaultType, fragment inner xsep/.get=\tikzumlFragmentDefaultXSep, fragment inner ysep/.get=\tikzumlFragmentDefaultYSep, fill fragment/.get=\tikzumlFragmentDefaultFillColor,%
+ create call dt/.get=\tikzumlCreateCallDefaultDT,%
+ component width/.get=\tikzumlComponentDefaultWidth, fill component/.get=\tikzumlComponentDefaultFillColor,%
+ required interface distance/.get=\tikzumlRequiredInterfaceDefaultDistance, required interface width/.get=\tikzumlRequiredInterfaceDefaultWidth, required interface padding/.get=\tikzumlRequiredInterfaceDefaultPadding,%
+ provided interface distance/.get=\tikzumlProvidedInterfaceDefaultDistance, provided interface width/.get=\tikzumlProvidedInterfaceDefaultWidth, provided interface padding/.get=\tikzumlProvidedInterfaceDefaultPadding,%
+ port width/.get=\tikzumlPortDefaultWidth, fill port/.get=\tikzumlPortDefaultFillColor,%
+ fill assembly connector/.get=\tikzumlAssemblyConnectorDefaultFillColor%
+}%
+%
+% utility : change default colors
+\newcommand{\tikzumlset}[1]{%
+ \pgfkeys{/tikzuml/.cd,#1}%
+ \pgfkeys{/tikzuml/.cd, text/.get=\tikzumlDefaultTextColor, draw/.get=\tikzumlDefaultDrawColor, font/.get=\tikzumlDefaultFont,%
+ x/.get=\tikzumlDefaultX, y/.get=\tikzumlDefaultY,%
+ package type/.get=\tikzumlPackageDefaultType, fill package/.get=\tikzumlPackageDefaultFillColor,%
+ class width/.get=\tikzumlClassDefaultWidth, simple interface width/.get=\tikzumlSimpleInterfaceDefaultWidth, class type/.get=\tikzumlClassDefaultType, fill class/.get=\tikzumlClassDefaultFillColor, fill template/.get=\tikzumlClassTemplateFillColorDefaultFillColor,%
+ narynode width/.get=\tikzumlNaryNodeWidth,%
+ relation geometry/.get=\tikzumlRelationDefaultGeometry, relation angle1/.get=\tikzumlRelationDefaultAngleO, relation angle2/.get=\tikzumlRelationDefaultAngleT, relation loopsize/.get=\tikzumlRelationDefaultLoopSize, relation weight/.get=\tikzumlRelationDefaultWeight, relation pos1/.get=\tikzumlRelationDefaultPosO, relation pos2/.get=\tikzumlRelationDefaultPosT, relation pos stereo/.get=\tikzumlRelationDefaultPosStereo,%
+ note width/.get=\tikzumlNoteDefaultWidth, fill note/.get=\tikzumlNoteDefaultFillColor,%
+ fill system/.get=\tikzumlSystemDefaultFillColor,%
+ fill usecase/.get=\tikzumlUseCaseDefaultFillColor,%
+ actor below/.get=\tikzumlActorDefaultBelow,%
+ state join width/.get=\tikzumlStateJoinDefaultWidth,%
+ state decision width/.get=\tikzumlStateDecisionDefaultWidth,%
+ state initial width/.get=\tikzumlStateInitialDefaultWidth,%
+ state final width/.get=\tikzumlStateFinalDefaultWidth,%
+ state enter width/.get=\tikzumlStateEnterDefaultWidth,%
+ state exit width/.get=\tikzumlStateExitDefaultWidth,%
+ state end width/.get=\tikzumlStateEndDefaultWidth,%
+ state history width/.get=\tikzumlStateHistoryDefaultWidth,%
+ state deep history width/.get=\tikzumlStateDeepHistoryDefaultWidth,%
+ state width/.get=\tikzumlStateDefaultWidth, fill state/.get=\tikzumlStateDefaultFillColor,%
+ object stereo/.get=\tikzumlObjectDefaultStereo, fill object/.get=\tikzumlObjectDefaultFillColor,%
+ call dt/.get=\tikzumlCallDefaultDT, call padding/.get=\tikzumlCallDefaultPadding, call type/.get=\tikzumlCallDefaultType, fill call/.get=\tikzumlCallDefaultFillColor,%
+ fragment type/.get=\tikzumlFragmentDefaultType, fragment inner xsep/.get=\tikzumlFragmentDefaultXSep, fragment inner ysep/.get=\tikzumlFragmentDefaultYSep, fill fragment/.get=\tikzumlFragmentDefaultFillColor,%
+ create call dt/.get=\tikzumlCreateCallDT,%
+ component width/.get=\tikzumlComponentDefaultWidth, fill component/.get=\tikzumlComponentDefaultFillColor,%
+ required interface distance/.get=\tikzumlRequiredInterfaceDefaultDistance, required interface width/.get=\tikzumlRequiredInterfaceDefaultWidth, required interface padding/.get=\tikzumlRequiredInterfaceDefaultPadding,%
+ provided interface distance/.get=\tikzumlProvidedInterfaceDefaultDistance, provided interface width/.get=\tikzumlProvidedInterfaceDefaultWidth, provided interface padding/.get=\tikzumlProvidedInterfaceDefaultPadding,%
+ port width/.get=\tikzumlPortDefaultWidth, fill port/.get=\tikzumlPortDefaultFillColor,%
+ fill assembly connector/.get=\tikzumlAssemblyConnectorDefaultFillColor%
+ }%
+}%
+%
+% define a point
+% arg : node/coordinates of the point
+\newcommand{\umlpoint}[1]{%
+ \begin{pgfonlayer}{connections}%
+ \node[tikzuml control nodes style] at (#1) {};%
+ \end{pgfonlayer}%
+}%
+%
+\newcommand{\tikzumlskipescape}[3][_]{%
+\begingroup%
+ \def\_{#1}\edef\x{\endgroup%
+ \def\noexpand\csname #3\endcsname{#2}}\x%
+}%
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% class diagrams %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+\pgfkeys{/tikzuml/relation/.cd, attr1/.style args={#1|#2}{arg1=#1, mult1=#2},%
+ attr2/.style args={#1|#2}{arg2=#1, mult2=#2},%
+ attr/.style args={#1|#2}{arg=#1, mult=#2},%
+ recursive/.style args={#1|#2|#3}{angle1=#1, angle2=#2, loopsize=#3},%
+ anchors/.style args={#1 and #2}{anchor1=#1, anchor2=#2},%
+ recursive direction/.style args={#1 to #2}{recursive direction start=#1, recursive direction end=#2}%
+}%
+%
+\pgfkeys{/tikzuml/note/.cd, anchors/.style args={#1 and #2}{anchor1=#1, anchor2=#2}}%
+%
+\tikzstyle{tikzuml simpleclass style}=[rectangle, minimum height=2em, node distance=2em]%
+\tikzstyle{tikzuml simpleinterface style}=[circle, minimum height=1em, node distance=1em]%
+\tikzstyle{tikzuml class style}=[rectangle split, rectangle split parts=3, rectangle split part align={center, left, left}, minimum height=2em, node distance=2em]%
+\tikzstyle{tikzuml narynode style}=[diamond]%
+\tikzstyle{tikzuml template style}=[dashed, inner ysep=0.5em, inner xsep=1ex]%
+\tikzstyle{tikzuml control nodes style}=[fill=black, inner sep=1.5pt, circle]%
+%
+\tikzstyle{tikzuml association style}=[color=\tikzumlDefaultDrawColor, -]%
+\tikzstyle{tikzuml bidirectional association style}=[color=\tikzumlDefaultDrawColor, angle45-angle45]%
+\tikzstyle{tikzuml unidirectional association style}=[color=\tikzumlDefaultDrawColor, -angle 45]%
+\tikzstyle{tikzuml aggregation style}=[color=\tikzumlDefaultDrawColor, open diamond-]%
+\tikzstyle{tikzuml unidirectional aggregation style}=[color=\tikzumlDefaultDrawColor, open diamond-angle 45]%
+\tikzstyle{tikzuml composition style}=[color=\tikzumlDefaultDrawColor, diamond-]%
+\tikzstyle{tikzuml unidirectional composition style}=[color=\tikzumlDefaultDrawColor, diamond-angle 45]%
+\tikzstyle{tikzuml nesting style}=[color=\tikzumlDefaultDrawColor]%
+\tikzstyle{tikzuml dependency style}=[color=\tikzumlDefaultDrawColor, -angle 45, dashed]%
+\tikzstyle{tikzuml import style}=[color=\tikzumlDefaultDrawColor, -angle 45, dashed]%
+\tikzstyle{tikzuml inherit style}=[color=\tikzumlDefaultDrawColor, -open triangle 45]%
+\tikzstyle{tikzuml implements style}=[color=\tikzumlDefaultDrawColor, -open triangle 45, dashed]%
+%
+\pgfkeys{/tikzuml/assemblyconnectorrelation/.cd, anchors/.style args={#1 and #2}{anchor1=#1, anchor2=#2}}%
+%
+\newcounter{tikzumlPackageClassNum}%
+\newcounter{tikzumlPackageSubPackageNum}%
+\newcounter{tikzumlRelationNum}%
+\setcounter{tikzumlRelationNum}{1}%
+\newcounter{tikzumlNoteNum}%
+\setcounter{tikzumlNoteNum}{1}%
+%
+\newcounter{pos}%
+\newcounter{posT}%
+\newcounter{posStereo}%
+%
+\newcounter{tikzumlPackageLevel}%
+\setcounter{tikzumlPackageLevel}{0}%
+%
+\newif\iftikzumlpackageSimpleStyle%
+\newif\iftikzumlclassSimpleStyle%
+\newif\iftikzumlclassCircleShape%
+\newif\iftikzumlpackageWithoutCoords%
+\newif\iftikzumlclassWithoutCoords%
+\newif\iftikzumlassocclassWithoutCoords%
+\newif\iftikzumlnoteWithoutCoords%
+%
+% define a uml package
+% arg : package name
+% optional : x, y: coordinates of the package
+% type: stereotype of the package
+% name: name of the package node
+% draw, fill, text: colors
+% style: to manage every default TikZ option
+% no coords: to tell that the package position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newenvironment{umlpackage}[2][]{%
+ \pgfkeys{/tikzuml/package/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, style/.style={},%
+ name/.initial=tikzumlEmpty, type/.initial=\tikzumlPackageDefaultType, draw/.initial=\tikzumlDefaultDrawColor,%
+ fill/.initial=\tikzumlPackageDefaultFillColor, text/.initial=\tikzumlDefaultTextColor,%
+ no coords/.is if=tikzumlpackageWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/package/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/package/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/package/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlpackage, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/package/.cd, #1}%
+ \pgfkeys{/tikzuml/package/.cd, x/.get=\tikzumlPackageXShift, y/.get=\tikzumlPackageYShift, name/.get=\tikzumlPackageName, type/.get=\tikzumlPackageTypeTmp,%
+ draw/.get=\tikzumlPackageDrawColor, fill/.get=\tikzumlPackageFillColor,%
+ text/.get=\tikzumlPackageTextColor%
+ }%
+ %
+
+ %
+ \ifthenelse{\equal{\tikzumlPackageTypeTmp}{tikzumlEmpty}}{%
+ \def\tikzumlPackageType{}%
+ }{%
+ \expandafter\def\expandafter\tikzumlPackageType\expandafter{$\ll$\tikzumlPackageTypeTmp$\gg$ \\}%
+ }%
+ %
+ \ifnum\thetikzumlPackageLevel>0%
+ \let\tikzumlPackage@nameold\tikzumlPackage@fitname%
+ \def\tikzumlPackage@name{#2}%
+ \begingroup%
+ \def\_{@}\edef\x{\endgroup%
+ \def\noexpand\tikzumlPackage@fitname{\tikzumlPackage@name}}\x%
+ \let\tikzumlPackage@parentold\tikzumlPackage@parent%
+ \edef\tikzumlPackage@parent{\tikzumlPackage@parentold @@\tikzumlPackage@nameold}%
+ \else%
+ \def\tikzumlPackage@parent{}%
+ \def\tikzumlPackage@name{#2}%
+ \begingroup%
+ \def\_{@}\edef\x{\endgroup%
+ \def\noexpand\tikzumlPackage@fitname{\tikzumlPackage@name}}\x%
+ \fi%
+ %
+ \let\tikzumlPackage@nodeNameold\tikzumlPackage@nodeName%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlPackage@nodeName{\tikzumlPackage@name}}\x%
+ %
+ \ifthenelse{\equal{\tikzumlPackageName}{tikzumlEmpty}}{}{%
+ \def\tikzumlPackage@nodeName{\tikzumlPackageName}%
+ }%
+ %
+ \StrSubstitute{\tikzumlPackage@nodeName}{.}{@POINT@}{\tikzumlPackage@nodeName}%
+ %
+ \expandafter\gdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{}%
+ %
+ \setcounter{tikzumlPackageClassNum}{0}%
+ \setcounter{tikzumlPackageSubPackageNum}{0}%
+ \stepcounter{tikzumlPackageLevel}%
+ %
+ \begin{scope}[xshift=\tikzumlPackageXShift cm, yshift=\tikzumlPackageYShift cm]%
+}{%
+ \addtocounter{tikzumlPackageLevel}{-1}%
+ \begin{pgfonlayer}{package\thetikzumlPackageLevel}%
+ %
+ % if contains no class, and not simple, one define a fictive node to enable the fit option
+ \ifnum\c@tikzumlPackageClassNum=0%
+ \ifnum\c@tikzumlPackageSubPackageNum=0%
+ \iftikzumlpackageWithoutCoords%
+ \node[inner sep=1.5ex, /tikzuml/package/style] (\tikzumlPackage@nodeName-root) {\phantom{\tikzumlPackage@nodeName}};%
+ \else%
+ \node[inner sep=1.5ex, /tikzuml/package/style] (\tikzumlPackage@nodeName-root) at (0,0) {\phantom{\tikzumlPackage@nodeName}};%
+ \fi%
+ \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{(\tikzumlPackage@nodeName-root)}%
+ \fi%
+ \fi%
+ %
+ \ifnum\c@tikzumlPackageLevel>0%
+ \def\tikzumlPackageFitTmp{\csname tikzumlPackageFit\tikzumlPackage@parent\endcsname}%
+ \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent\endcsname{\tikzumlPackageFitTmp (\tikzumlPackage@nodeName) (\tikzumlPackage@nodeName-caption)}%
+ \stepcounter{tikzumlPackageSubPackageNum}%
+ \fi%
+ %
+ \node[draw=\tikzumlPackageDrawColor, fill=\tikzumlPackageFillColor, text=\tikzumlPackageTextColor, font=\tikzumlDefaultFont, inner sep=1.5ex, /tikzuml/package/style, fit = \csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname] (\tikzumlPackage@nodeName) {};%
+ \node[draw=\tikzumlPackageDrawColor, fill=\tikzumlPackageFillColor, text=\tikzumlPackageTextColor, font=\tikzumlDefaultFont, minimum height=1.5em, outer ysep=-0.3, anchor=south west] (\tikzumlPackage@nodeName-caption) at (\tikzumlPackage@nodeName.north west) {\begin{tabular}{c} \tikzumlPackageType \textbf{\tikzumlPackage@name}\end{tabular}};%
+ \end{pgfonlayer}%
+ \end{scope}%
+}%
+%
+% shortcut to define an empty package
+\newcommand{\umlemptypackage}[2][]{\begin{umlpackage}[#1]{#2} \end{umlpackage}}%
+%
+% define a uml class
+% args : name of the class
+% attributes of the class
+% operations of the class
+% optional : x, y: coordinates of the class
+% width: of the class node
+% type: type of class (class, interface, typedef, enum)
+% tags: tagged values of class
+% template: template parameters
+% simple: if used, class is empty and drawn with a rectangle
+% circle: if used with simple, class is empty and drawn with a circle
+% draw, fill, fill template, and text: colors
+% style: to manage every default TikZ option
+% no coords: to tell that the class position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlclass}[4][]{%
+ \pgfkeys{/tikzuml/class/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlClassDefaultWidth, type/.initial=\tikzumlClassDefaultType,%
+ tags/.initial={}, style/.style={},%
+ template/.initial={}, name/.initial=tikzumlEmpty,%
+ draw/.initial=\tikzumlDefaultDrawColor,%
+ fill template/.initial=\tikzumlClassTemplateFillColorDefaultFillColor,%
+ fill/.initial=\tikzumlClassDefaultFillColor,%
+ text/.initial=\tikzumlDefaultTextColor,%
+ simple/.is if=tikzumlclassSimpleStyle, circle/.is if=tikzumlclassCircleShape, no coords/.is if=tikzumlclassWithoutCoords,%
+ simple=false, circle=false, no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/class/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/class/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/class/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlclass, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/class/.cd,#1}%
+ %
+ \iftikzumlclassSimpleStyle%
+ \iftikzumlclassCircleShape%
+ \pgfkeys{/tikzuml/class/.cd, width/.initial=\tikzumlSimpleInterfaceDefaultWidth}%
+ \fi%
+ \fi%
+ %
+ \pgfkeys{/tikzuml/class/.cd, x/.get=\tikzumlClassX, y/.get=\tikzumlClassY, width/.get=\tikzumlClassMinimumWidth,%
+ type/.get=\tikzumlClassTypeTmp, tags/.get=\tikzumlClassTagsTmp, template/.get=\tikzumlClassTemplateFillColorParam,%
+ name/.get=\tikzumlClassName,%
+ draw/.get=\tikzumlClassDrawColor, fill/.get=\tikzumlClassFillColor,%
+ text/.get=\tikzumlClassTextColor, fill template/.get=\tikzumlClassTemplateFillColor%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlClassTypeTmp}{class}\OR\equal{\tikzumlClassTypeTmp}{abstract}}{%
+ \def\tikzumlClassType{}%
+ }{%
+ \expandafter\def\expandafter\tikzumlClassType\expandafter{$\ll$\tikzumlClassTypeTmp$\gg$ \\}%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlClassTagsTmp}{}}{%
+ \def\tikzumlClassTags{}%
+ }{%
+ \def\tikzumlClassTags{\\ \{\tikzumlClassTagsTmp\}}%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlClassTemplateFillColorParam}{}}{%
+ \def\tikzumlClassVPadding{}%
+ \def\tikzumlClassHPadding{}%
+ }{%
+ \def\tikzumlClassVPadding{\vspace{0.1em} \\}%
+ \def\tikzumlClassHPadding{\hspace{0.5ex} $ $}%
+ }%
+ %
+ \def\tikzumlClassName{#2}%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlClassNodeName{\tikzumlClassName}}\x%
+ %
+ \ifthenelse{\equal{\tikzumlClassName}{tikzumlEmpty}}{}{%
+ \def\tikzumlClassNodeName{\tikzumlClassName}%
+ }%
+ %
+ \StrSubstitute{\tikzumlClassNodeName}{:}{@COLON@}[\tikzumlClassNodeName]%
+ \StrSubstitute{\tikzumlClassNodeName}{\_}{@UNDERSCORE@}[\tikzumlClassNodeName]%
+ %
+ \ifthenelse{\equal{\tikzumlClassTypeTmp}{abstract}}{%
+ \let\tikzumlClassNameOld\tikzumlClassName%
+ \def\tikzumlClassName{{\it \tikzumlClassNameOld}}%
+ }{}%
+ %
+ \def\tikzumlClassPos{\tikzumlClassX,\tikzumlClassY}%
+ \def\tikzumlClassAttributes{#3}%
+ \def\tikzumlClassOperations{#4}%
+ %
+ \iftikzumlclassSimpleStyle%
+ \iftikzumlclassWithoutCoords%
+ \iftikzumlclassCircleShape%
+ \node[tikzuml simpleinterface style, draw=\tikzumlClassDrawColor, fill=\tikzumlClassFillColor, text=\tikzumlClassTextColor, font=\tikzumlDefaultFont, minimum width=\tikzumlClassMinimumWidth, /tikzuml/class/style] (\tikzumlClassNodeName) {};%
+ \node[anchor=south] (\tikzumlClassNodeName-label) at (\tikzumlClassNodeName.north) {\begin{tabular}{c}\tikzumlClassVPadding \tikzumlClassType \tikzumlClassHPadding \textbf{\tikzumlClassName} \tikzumlClassHPadding \tikzumlClassTags \end{tabular}%
+ };%
+ \else%
+ \node[tikzuml simpleclass style, draw=\tikzumlClassDrawColor, fill=\tikzumlClassFillColor, text=\tikzumlClassTextColor, font=\tikzumlDefaultFont, minimum width=\tikzumlClassMinimumWidth, /tikzuml/class/style] (\tikzumlClassNodeName) {\begin{tabular}{c}\tikzumlClassVPadding \tikzumlClassType \tikzumlClassHPadding \textbf{\tikzumlClassName} \tikzumlClassHPadding \tikzumlClassTags \end{tabular}%
+ };%
+ \fi%
+ \else%
+ \iftikzumlclassCircleShape%
+ \node[tikzuml simpleinterface style, draw=\tikzumlClassDrawColor, fill=\tikzumlClassFillColor, text=\tikzumlClassTextColor, font=\tikzumlDefaultFont, minimum width=\tikzumlClassMinimumWidth, /tikzuml/class/style] (\tikzumlClassNodeName) at (\tikzumlClassPos) {};
+ \node[anchor=south] (\tikzumlClassNodeName-label) at (\tikzumlClassNodeName.north){\begin{tabular}{c}\tikzumlClassVPadding \tikzumlClassType \tikzumlClassHPadding \textbf{\tikzumlClassName} \tikzumlClassHPadding \tikzumlClassTags \end{tabular}%
+ };%
+ \else%
+ \node[tikzuml simpleclass style, draw=\tikzumlClassDrawColor, fill=\tikzumlClassFillColor, text=\tikzumlClassTextColor, font=\tikzumlDefaultFont, minimum width=\tikzumlClassMinimumWidth, /tikzuml/class/style] (\tikzumlClassNodeName) at (\tikzumlClassPos) {\begin{tabular}{c}\tikzumlClassVPadding \tikzumlClassType \tikzumlClassHPadding \textbf{\tikzumlClassName} \tikzumlClassHPadding \tikzumlClassTags \end{tabular}%
+ };%
+ \fi%
+ \fi%
+ \else%
+ \iftikzumlclassWithoutCoords%
+ \node[tikzuml class style, draw=\tikzumlClassDrawColor, fill=\tikzumlClassFillColor, text=\tikzumlClassTextColor, font=\tikzumlDefaultFont, minimum width=\tikzumlClassMinimumWidth, /tikzuml/class/style] (\tikzumlClassNodeName) {\begin{tabular}{c}\tikzumlClassVPadding \tikzumlClassType \tikzumlClassHPadding \textbf{\tikzumlClassName} \tikzumlClassHPadding \tikzumlClassTags \end{tabular}%
+ \nodepart{second}%
+ \begin{tabular}{l}%
+ \tikzumlClassAttributes%
+ \end{tabular}%
+ \nodepart{third}%
+ \begin{tabular}{l}%
+ \tikzumlClassOperations%
+ \end{tabular}%
+ };%
+ \else%
+ \node[tikzuml class style, draw=\tikzumlClassDrawColor, fill=\tikzumlClassFillColor, text=\tikzumlClassTextColor, font=\tikzumlDefaultFont, minimum width=\tikzumlClassMinimumWidth, /tikzuml/class/style] (\tikzumlClassNodeName) at (\tikzumlClassPos) {\begin{tabular}{c}\tikzumlClassVPadding \tikzumlClassType \tikzumlClassHPadding \textbf{\tikzumlClassName} \tikzumlClassHPadding \tikzumlClassTags \end{tabular}%
+ \nodepart{second}%
+ \begin{tabular}{l}%
+ \tikzumlClassAttributes%
+ \end{tabular}%
+ \nodepart{third}%
+ \begin{tabular}{l}%
+ \tikzumlClassOperations%
+ \end{tabular}%
+ };%
+ \fi%
+ \fi%
+ %
+ \ifthenelse{\equal{\tikzumlClassTemplateFillColorParam}{}}{}{%
+ \draw (\tikzumlClassNodeName.north east) node[tikzuml template style, name=\tikzumlClassNodeName-template, draw=\tikzumlClassDrawColor, fill=\tikzumlClassTemplateFillColor, text=\tikzumlClassTextColor, font=\tikzumlDefaultFont] {\tikzumlClassTemplateFillColorParam};%
+ }%
+ %
+ % add to fit
+ \ifnum\c@tikzumlPackageLevel>0%
+ \edef\tikzumlPackageFitOld{\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname}%
+ \ifthenelse{\equal{\tikzumlClassTemplateFillColorParam}{}}{%
+ \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{\tikzumlPackageFitOld (\tikzumlClassNodeName)}%
+ }{%
+ \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{\tikzumlPackageFitOld (\tikzumlClassNodeName) (\tikzumlClassNodeName-template)}%
+ }%
+ \stepcounter{tikzumlPackageClassNum}%
+ \fi%
+ \ifnum\c@tikzumlComponentLevel>0%
+ \def\tikzumlComponentFitTmp{\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname}%
+ \ifthenelse{\equal{\tikzumlClassTemplateFillColorParam}{}}{%
+ \expandafter\xdef\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname{\tikzumlComponentFitTmp (\tikzumlClassNodeName)}%
+ }{%
+ \expandafter\xdef\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname{\tikzumlComponentFitTmp (\tikzumlClassNodeName) (\tikzumlClassNodeName-template)}%
+ }%
+ \stepcounter{tikzumlComponentSubComponentNum}%
+ \fi%
+}%
+%
+% shortcuts for interface, enum and typedef environments
+\newcommand{\umlabstract}[4][]{%
+ \pgfkeys{/tikzuml/class/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{type}}{%
+ \errmessage{TIKZUML ERROR : in umlabstract, forbidden option type}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/class/.cd, #1}%
+ \umlclass[type=abstract,#1]{#2}{#3}{#4}%
+}%
+\newcommand{\umlinterface}[4][]{%
+ \pgfkeys{/tikzuml/class/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{type}}{%
+ \errmessage{TIKZUML ERROR : in umlinterface, forbidden option type}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/class/.cd, #1}%
+ \umlclass[type=interface,#1]{#2}{#3}{#4}%
+}%
+\newcommand{\umltypedef}[4][]{%
+ \pgfkeys{/tikzuml/class/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{type}}{%
+ \errmessage{TIKZUML ERROR : in umltypedef, forbidden option type}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/class/.cd, #1}%
+ \umlclass[type=typedef,#1]{#2}{#3}{#4}%
+}%
+\newcommand{\umlenum}[4][]{%
+ \pgfkeys{/tikzuml/class/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{type}}{%
+ \errmessage{TIKZUML ERROR : in umlenum, forbidden option type}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/class/.cd, #1}%
+ \umlclass[type=enum,#1]{#2}{#3}{#4}
+}%
+%
+% shortcut to define an empty class
+\newcommand{\umlemptyclass}[2][]{\umlclass[#1]{#2}{}{}}%
+\newcommand{\umlsimpleclass}[2][]{%
+ \pgfkeys{/tikzuml/class/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{simple}}{%
+ \errmessage{TIKZUML ERROR : in umlsimpleclass, forbidden option simple}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/class/.cd, #1}%
+ \umlemptyclass[simple, #1]{#2}%
+}%
+%
+\newcommand{\umlsimpleinterface}[2][]{%
+ \pgfkeys{/tikzuml/class/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{simple}}{%
+ \errmessage{TIKZUML ERROR : in umlsimpleinterface, forbidden option simple}%
+ }{%
+ \ifthenelse{\equal{\keyname}{circle}}{%
+ \errmessage{TIKZUML ERROR : in umlsimpleinterface, forbidden option circle}%
+ }{}%
+ }%
+ }%
+ }%
+ \pgfkeys{/tikzuml/class/.cd, #1}%
+ \umlsimpleclass[circle, #1]{#2}%
+}%
+% underline the text for static arg
+\newcommand{\umlstatic}[1]{\underline{#1}}%
+\newcommand{\umlvirt}[1]{\textit{#1}}%
+%
+% define node for n-ary association
+\newcommand{\umlNarynode}[2][]{%
+ \def\tikzumlNaryNodeAnchor{.north}
+ \def\tikzumlNaryNodeLabelPos{above}
+ \pgfkeys{/tikzuml/narynode/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlNaryNodeDefaultWidth, name/.initial=tikzumlEmpty,%
+ draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlClassDefaultFillColor,%
+ text/.initial=\tikzumlDefaultTextColor, style/.style={},%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}}{%
+ \def\tikzumlNaryNodeAnchor{.north}%
+ \def\tikzumlNaryNodeLabelPos{above}%
+ }{%
+ \ifthenelse{\equal{\keyname}{above left}}{%
+ \def\tikzumlNaryNodeAnchor{.north west}%
+ \def\tikzumlNaryNodeLabelPos{above left}%
+ }{%
+ \ifthenelse{\equal{\keyname}{left}}{%
+ \def\tikzumlNaryNodeAnchor{.west}%
+ \def\tikzumlNaryNodeLabelPos{left}%
+ }{%
+ \ifthenelse{\equal{\keyname}{below left}}{%
+ \def\tikzumlNaryNodeAnchor{.south west}%
+ \def\tikzumlNaryNodeLabelPos{below left}%
+ }{%
+ \ifthenelse{\equal{\keyname}{below}}{%
+ \def\tikzumlNaryNodeAnchor{.south}%
+ \def\tikzumlNaryNodeLabelPos{below}%
+ }{%
+ \ifthenelse{\equal{\keyname}{below right}}{%
+ \def\tikzumlNaryNodeAnchor{.south east}%
+ \def\tikzumlNaryNodeLabelPos{below right}%
+ }{%
+ \ifthenelse{\equal{\keyname}{right}}{%
+ \def\tikzumlNaryNodeAnchor{.east}%
+ \def\tikzumlNaryNodeLabelPos{right}%
+ }{%
+ \ifthenelse{\equal{\keyname}{above right}}{%
+ \def\tikzumlNaryNodeAnchor{.north east}%
+ \def\tikzumlNaryNodeLabelPos{above right}%
+ }{%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/narynode/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/narynode/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlNarynode, invalid option \keyname}%
+ }%
+ }%
+ }%
+ }%
+ }%
+ }%
+ }%
+ }%
+ }%
+ }%
+ \pgfkeys{/tikzuml/narynode/.cd,#1}%
+ \pgfkeys{/tikzuml/narynode/.cd, x/.get=\tikzumlNaryNodeX, y/.get=\tikzumlNaryNodeY, width/.get=\tikzumlNaryNodeMinimumWidth,%
+ name/.get=\tikzumlNaryNodeName,%
+ draw/.get=\tikzumlNaryNodeDrawColor, fill/.get=\tikzumlNaryNodeFillColor,%
+ text/.get=\tikzumlNaryNodeTextColor%
+ }%
+ %
+ \def\tikzumlNaryName{#2}%
+ %
+ \ifthenelse{\equal{\tikzumlNaryNodeName}{tikzumlEmpty}}{%
+ \edef\tikzumlNaryNodeName{\tikzumlNaryName}%
+ }{%
+ \edef\tikzumlNaryNodeName{\tikzumlNaryNodeName}%
+ }%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlNaryNode@nodeName{\tikzumlNaryNodeName}}\x%
+ %
+ \StrSubstitute{\tikzumlNaryNode@nodeName}{:}{@COLON@}[\tikzumlNaryNode@nodeName]%
+ \StrSubstitute{\tikzumlNaryNode@nodeName}{\_}{@UNDERSCORE@}[\tikzumlNaryNode@nodeName]%
+ %
+ \def\tikzumlNarynodePos{\tikzumlNaryNodeX,\tikzumlNaryNodeY}%
+ %
+ \node[tikzuml narynode style, draw=\tikzumlNaryNodeDrawColor, fill=\tikzumlNaryNodeFillColor, text=\tikzumlNaryNodeTextColor, font=\tikzumlDefaultFont, minimum width=\tikzumlNaryNodeMinimumWidth, minimum height=\tikzumlNaryNodeMinimumWidth, /tikzuml/narynode/style] (\tikzumlNaryNode@nodeName) at (\tikzumlNarynodePos) {};%
+ \draw (\tikzumlNaryNode@nodeName\tikzumlNaryNodeAnchor) node[\tikzumlNaryNodeLabelPos] {\tikzumlNaryName};%
+ %
+ % add to fit
+ \ifnum\c@tikzumlPackageLevel>0%
+ \edef\tikzumlPackageFitOld{\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{\tikzumlPackageFitOld (\tikzumlNaryNode@nodeName)}%
+ \stepcounter{tikzumlPackageClassNum}%
+ \fi%
+}%
+%
+\newdimen\tikzumlNestingSymbolSize%
+%
+% main command to define a relation between two classes
+% args : src class
+% dest class
+% optional : geometry: geometry of the line
+% weight: barycentric weight of the middle part when geometry is a 3-line
+% arm1, arm2: lengths of first or last part when geometry id a 3-line
+% arg1, arg2, arg: name of the src/dest/dest side class type attribute defined by the relation
+% mult1, mult2, mult: multiplicity of the src/dest/dest side class type attribute defined by the relation
+% pos1, pos2, pos: position of the src/dest/dest side class type attribute defined by the relation
+% align1, align2, align: text justification of the src/dest/dest side class type attribute defined by the relation
+% anchor1, anchor2: src/dest anchors on linked classes
+% angle1, angle2, loopsize: start angle, end angle and size of the relation (only if recursive)
+% stereo: stereotype of the relation
+% pos stereo: position of the stereotype on the relation
+% style: style of the relation (association, aggregation, composition, inherit, ...)
+% name: rootname used for naming nodes of the relation
+% recursive mode: type of recursive arrow (transition for state diagrams, or default)
+% recursive direction start/end: when transition relation, start/end directions of the relation arrow
+\newcommand{\umlrelation}[3][]{%
+ \pgfkeys{/tikzuml/relation/.cd, geometry/.initial=\tikzumlRelationDefaultGeometry, weight/.initial=\tikzumlRelationDefaultWeight,%
+ arm1/.initial=auto, arm2/.initial=auto,%
+ arg1/.initial={}, arg2/.initial={}, arg/.initial={},%
+ mult1/.initial={}, mult2/.initial={}, mult/.initial={},%
+ pos1/.initial=\tikzumlRelationDefaultPosO, pos2/.initial=\tikzumlRelationDefaultPosT, pos/.initial=tikzumlEmpty,%
+ align1/.initial={}, align2/.initial={}, align/.initial={},%
+ anchor1/.initial=tikzumlEmpty, anchor2/.initial=tikzumlEmpty,%
+ angle1/.initial=\tikzumlRelationDefaultAngleO, angle2/.initial=\tikzumlRelationDefaultAngleT, loopsize/.initial=\tikzumlRelationDefaultLoopSize,%
+ stereo/.initial={}, pos stereo/.initial=\tikzumlRelationDefaultPosStereo,%
+ style/.initial=->, style2/.style={}, name/.initial=relation-\thetikzumlRelationNum,%
+ recursive mode/.initial=default, recursive direction start/.initial=right,%
+ recursive direction end/.initial=bottom,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{with port}%
+ \OR\equal{\keyname}{interface}%
+ \OR\equal{\keyname}{padding}%
+ \OR\equal{\keyname}{width}%
+ \OR\equal{\keyname}{first arm}%
+ \OR\equal{\keyname}{second arm}%
+ \OR\equal{\keyname}{middle arm}%
+ \OR\equal{\keyname}{last arm}%
+ \OR\equal{\keyname}{distance}}{}{%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/relation/.cd, style2/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/relation/.cd, style2/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlrelation, invalid option \keyname}%
+ }%
+ }%
+ }%
+ \pgfkeys{/tikzuml/relation/.cd,#1}%
+ \pgfkeys{/tikzuml/relation/.cd, geometry/.get=\tikzumlRelationGeometry, weight/.get=\tikzumlRelationWeight,%
+ arm1/.get=\tikzumlRelationArmO, arm2/.get=\tikzumlRelationArmT,%
+ arg1/.get=\tikzumlRelationAttrName, arg2/.get=\tikzumlRelationAttrNameTO, arg/.get=\tikzumlRelationAttrNameTT,%
+ mult1/.get=\tikzumlRelationMultiplicity, mult2/.get=\tikzumlRelationMultiplicityTO, mult/.get=\tikzumlRelationMultiplicityTT,%
+ pos1/.get=\tikzumlRelationPosition, pos2/.get=\tikzumlRelationPositionTO, pos/.get=\tikzumlRelationPositionTT,%
+ align1/.get=\tikzumlRelationAlign, align2/.get=\tikzumlRelationAlignTO, align/.get=\tikzumlRelationAlignTT,%
+ anchor1/.get=\tikzumlRelationSrcAnchor, anchor2/.get=\tikzumlRelationDestAnchor,%
+ angle1/.get=\tikzumlRelationStartAngle, angle2/.get=\tikzumlRelationEndAngle, loopsize/.get=\tikzumlRelationLoopSize,%
+ stereo/.get=\tikzumlRelationStereoType, pos stereo/.get=\tikzumlRelationPositionStereotype,%
+ style/.get=\tikzumlRelationStyle, name/.get=\tikzumlRelationName,%
+ recursive mode/.get=\tikzumlRelationRecursiveMode,%
+ recursive direction start/.get=\tikzumlRelationRecursiveDirectionStart,%
+ recursive direction end/.get=\tikzumlRelationRecursiveDirectionEnd%
+ }%
+ %
+ \def\tikzumlSrcClassName{#2}%
+ %
+ % managing \_ in class names for node names
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlSrcClassNodeName{\tikzumlSrcClassName}}\x%
+ %
+ \StrSubstitute{\tikzumlSrcClassNodeName}{:}{@COLON@}[\tikzumlSrcClassNodeName]%
+ \StrSubstitute{\tikzumlSrcClassNodeName}{\_}{@UNDERSCORE@}[\tikzumlSrcClassNodeName]%
+ %
+ \def\tikzumlDestClassName{#3}%
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlDestClassNodeName{\tikzumlDestClassName}}\x%
+ %
+ \StrSubstitute{\tikzumlDestClassNodeName}{:}{@COLON@}[\tikzumlDestClassNodeName]%
+ \StrSubstitute{\tikzumlDestClassNodeName}{\_}{@UNDERSCORE@}[\tikzumlDestClassNodeName]%
+ %
+ % managing alias keys
+ \def\tikzumlRelationAttrNameT{\tikzumlRelationAttrNameTO\tikzumlRelationAttrNameTT}%
+ \def\tikzumlRelationMultiplicityT{\tikzumlRelationMultiplicityTO\tikzumlRelationMultiplicityTT}%
+ \def\tikzumlRelationAlignT{\tikzumlRelationAlignTO\tikzumlRelationAlignTT}%
+ \def\posAttrName{}%
+ \def\posMultiplicity{}%
+ \def\posAttrNameT{}%
+ \def\posMultiplicityT{}%
+ %
+ \ifthenelse{\equal{\tikzumlRelationPositionTT}{tikzumlEmpty}}{%
+ \def\tikzumlRelationPositionT{\tikzumlRelationPositionTO}%
+ }{%
+ \def\tikzumlRelationPositionT{\tikzumlRelationPositionTT}%
+ }%
+ %
+ \def\attrAlign{}%
+ \def\multAlign{}%
+ \def\attrAlignT{}%
+ \def\multAlignT{}%
+ %
+ \ifthenelse{\equal{\tikzumlRelationAlign}{left}}{%
+ \def\attrAlign{above right}%
+ \def\multAlign{below right}%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationAlign}{right}}{%
+ \def\attrAlign{above left}%
+ \def\multAlign{below left}%
+ }{}%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlRelationAlignT}{left}}{%
+ \def\attrAlignT{above right}%
+ \def\multAlignT{below right}%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationAlignT}{right}}{%
+ \def\attrAlignT{above left}%
+ \def\multAlignT{below left}%
+ }{}%
+ }%
+ %
+ % def stereotype
+ \ifthenelse{\equal{\tikzumlRelationStereoType}{}}{%
+ \def\stereotype{}%
+ }{%
+ \def\stereotype{$\ll$\tikzumlRelationStereoType$\gg$}%
+ }%
+
+ % def anchors macros
+ \ifthenelse{\equal{\tikzumlRelationSrcAnchor}{tikzumlEmpty}}{%
+ \def\tikzumlRelationSrcAnchor{}%
+ }{%
+ \let\tikzumlRelationSrcAnchorold\tikzumlRelationSrcAnchor%
+ \def\tikzumlRelationSrcAnchor{.\tikzumlRelationSrcAnchorold}%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlRelationDestAnchor}{tikzumlEmpty}}{%
+ \def\tikzumlRelationDestAnchor{}%
+ }{%
+ \let\tikzumlRelationDestAnchorold\tikzumlRelationDestAnchor%
+ \def\tikzumlRelationDestAnchor{.\tikzumlRelationDestAnchorold}%
+ }%
+ %
+ \setcounter{pos}{100*\real{\tikzumlRelationPosition}}%
+ \setcounter{posT}{100*\real{\tikzumlRelationPositionT}}%
+ \setcounter{posStereo}{100*\real{\tikzumlRelationPositionStereotype}}%
+ %
+ \pgfmathsetmacro{\tikzumlRelationWeightT}{1.0-\tikzumlRelationWeight}%
+ %
+ %\newcounter{tikzumlControlNodesNum}%
+ %\setcounter{tikzumlControlNodesNum}{0}%
+ %
+ \node[inner sep=0] (\tikzumlRelationName-middle) at (barycentric cs:\tikzumlSrcClassNodeName=\tikzumlRelationWeightT,\tikzumlDestClassNodeName=\tikzumlRelationWeight) {};%
+ %
+ % straight line
+ \ifthenelse{\equal{\tikzumlRelationGeometry}{--}}%
+ {%
+ \ifthenelse{\equal{\tikzumlSrcClassNodeName}{\tikzumlDestClassNodeName}}{%
+ \def\arcNum{1}%
+ \def\arcNumT{1}%
+ %
+ \ifthenelse{\equal{\tikzumlRelationRecursiveMode}{default}}{%
+ \xdef\tikzumlLastArc{node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity}%
+ node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT}%
+ node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \xdef\tikzumlPath{(\tikzumlSrcClassNodeName) edge[in=\tikzumlRelationEndAngle, out=\tikzumlRelationStartAngle, distance=\tikzumlRelationLoopSize] \tikzumlLastArc%
+ node[midway, inner sep=0, name=\tikzumlRelationName-1, anchor=center] {} (\tikzumlDestClassNodeName) }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveMode}{transition}}{%
+ \xdef\tikzumlFirstArc{node[midway, inner sep=0, name=\tikzumlRelationName-1, anchor=center] {}}%
+ \xdef\tikzumlMidOneArc{node[midway, inner sep=0, name=\tikzumlRelationName-3, anchor=center] {}}%
+ %
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{\tikzumlRelationRecursiveDirectionEnd}}{%
+ \def\numArcs{3}%
+ \xdef\tikzumlLastArc{node[midway, inner sep=0, name=\tikzumlRelationName-5, anchor=center] {}}%
+ %
+ \begin{pgfonlayer}{connections}%
+ \draw (\tikzumlSrcClassNodeName) edge[in=\tikzumlRelationEndAngle, out=\tikzumlRelationStartAngle, distance=\tikzumlRelationLoopSize, draw=none] %
+ node[midway, inner sep=0, name=\tikzumlRelationName-tmp, anchor=center] {} (\tikzumlDestClassNodeName);%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}\OR\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{%
+ \node[inner sep=0, name=\tikzumlRelationName-2] at (\tikzumlSrcClassNodeName.\tikzumlRelationStartAngle -| \tikzumlRelationName-tmp) {};%
+ \node[inner sep=0, name=\tikzumlRelationName-4] at (\tikzumlDestClassNodeName.\tikzumlRelationEndAngle -| \tikzumlRelationName-tmp) {};%
+ }{%
+ \node[inner sep=0, name=\tikzumlRelationName-2] at (\tikzumlSrcClassNodeName.\tikzumlRelationStartAngle |- \tikzumlRelationName-tmp) {};%
+ \node[inner sep=0, name=\tikzumlRelationName-4] at (\tikzumlDestClassNodeName.\tikzumlRelationEndAngle |- \tikzumlRelationName-tmp) {};%
+ }%
+ \end{pgfonlayer}%
+ }{%
+ \def\numArcs{4}%
+ \xdef\tikzumlMidTwoArc{node[midway, inner sep=0, name=\tikzumlRelationName-5, anchor=center] {}}%
+ \xdef\tikzumlLastArc{node[midway, inner sep=0, name=\tikzumlRelationName-7, anchor=center] {}}%
+ %
+ \begin{pgfonlayer}{connections}%
+ \draw (\tikzumlSrcClassNodeName) edge[in=\tikzumlRelationEndAngle, out=\tikzumlRelationStartAngle, distance=\tikzumlRelationLoopSize, draw=none] %
+ node[midway, name=\tikzumlRelationName-4, anchor=center] {} (\tikzumlDestClassNodeName);%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}\OR\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{%
+ \node[inner sep=0, name=\tikzumlRelationName-2] at (\tikzumlSrcClassNodeName.\tikzumlRelationStartAngle -| \tikzumlRelationName-4) {};%
+ \node[inner sep=0, name=\tikzumlRelationName-6] at (\tikzumlDestClassNodeName.\tikzumlRelationEndAngle |- \tikzumlRelationName-4) {};%
+ }{%
+ \node[inner sep=0, name=\tikzumlRelationName-2] at (\tikzumlSrcClassNodeName.\tikzumlRelationStartAngle |- \tikzumlRelationName-4) {};%
+ \node[inner sep=0, name=\tikzumlRelationName-6] at (\tikzumlDestClassNodeName.\tikzumlRelationEndAngle -| \tikzumlRelationName-4) {};%
+ }%
+ \end{pgfonlayer}%
+ }%
+ %
+ \ifnum\numArcs=4%
+ \ifnum\theposStereo>300%
+ \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-300)/100}%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype}}%
+ \else%
+ \ifnum\theposStereo<100%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype}}%
+ \else%
+ \ifnum\theposStereo>200%
+ \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-200)/100}%
+ \xdef\tikzumlMidTwoArc{\tikzumlMidTwoArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype}}%
+ \else%
+ \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-100)/100}%
+ \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype}}%
+ \fi%
+ \fi%
+ \fi%
+ %
+ \ifthenelse{\thepos=300\OR\thepos=100}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{bottom}}{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{bottom}}{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{top}}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{left}}{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{left}}{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }%
+ }%
+ }%
+ }%
+ }{}%
+ %
+ \ifthenelse{\thepos=200}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{bottom}}{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{bottom}}{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{top}}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{left}}{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{left}}{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }%
+ }%
+ }%
+ }%
+ }{}%
+ %
+ \ifnum\thepos>300%
+ \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-300)/100}%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity}%
+ }%
+ \else%
+ \ifnum\thepos<100%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity}%
+ }%
+ \else%
+ \ifnum\thepos>200%
+ \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-200)/100}%
+ \xdef\tikzumlMidTwoArc{\tikzumlMidTwoArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity}%
+ }%
+ \else%
+ \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-100)/100}%
+ \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity}%
+ }%
+ \fi%
+ \fi%
+ \fi%
+ %
+ \ifthenelse{\theposT=300\OR\theposT=100}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{bottom}}{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{bottom}}{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{top}}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{left}}{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{left}}{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }%
+ }%
+ }%
+ }%
+ }{}%
+ \ifthenelse{\theposT=200}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{bottom}}{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicity{below right}%
+ }{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{bottom}}{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{top}}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{left}}{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{left}}{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }%
+ }%
+ }%
+ }%
+ }{}%
+ %
+ \ifnum\theposT>300%
+ \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-300)/100}%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT}%
+ }%
+ \else%
+ \ifnum\theposT<100%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT}%
+ }%
+ \else%
+ \ifnum\theposT>200%
+ \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-200)/100}%
+ \xdef\tikzumlMidTwoArc{\tikzumlMidTwoArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT}%
+ }%
+ \else%
+ \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-100)/100}%
+ \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT}%
+ }%
+ \fi%
+ \fi%
+ \fi%
+ \else%
+ \ifnum\theposStereo>200%
+ \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-200)/100}%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \else%
+ \ifnum\theposStereo<100%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \else%
+ \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-100)/100}%
+ \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \fi%
+ \fi%
+ %
+ \ifthenelse{\thepos=100}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}}{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{top}}{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }%
+ }{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }%
+ }%
+ }%
+ }%
+ }{}%
+ %
+ \ifthenelse{\thepos=200}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}}{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{top}}{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }%
+ }{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }%
+ }%
+ }%
+ }%
+ }{}%
+ %
+ \ifnum\thepos>200%
+ \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-200)/100}%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity}%
+ }%
+ \else%
+ \ifnum\thepos<100%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity}%
+ }%
+ \else%
+ \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-100)/100}%
+ \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity}%
+ }%
+ \fi%
+ \fi%
+ %
+ \ifthenelse{\theposT=100}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}}{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{top}}{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }%
+ }{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }%
+ }%
+ }%
+ }%
+ }{}%
+ %
+ \ifthenelse{\theposT=200}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}}{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{top}}{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }%
+ }{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }%
+ }%
+ }%
+ }%
+ }{}%
+ %
+ \ifnum\theposT>200%
+ \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-200)/100}%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT}%
+ }%
+ \else%
+ \ifnum\theposT<100%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT}%
+ }%
+ \else%
+ \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-100)/100}%
+ \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT}%
+ }%
+ \fi%
+ \fi%
+ \fi%
+ %
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{\tikzumlRelationRecursiveDirectionEnd}}{%
+ \xdef\tikzumlPath{(\tikzumlSrcClassNodeName.\tikzumlRelationStartAngle) -- \tikzumlFirstArc (\tikzumlRelationName-2.center) -- \tikzumlMidOneArc (\tikzumlRelationName-4.center) -- \tikzumlLastArc (\tikzumlDestClassNodeName.\tikzumlRelationEndAngle) }%
+ \ifnum\thetikzumlStateLevel>0%
+ \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitTmp (\tikzumlRelationName-1) (\tikzumlRelationName-2) (\tikzumlRelationName-3) (\tikzumlRelationName-4) (\tikzumlRelationName-5)}%
+ \fi%
+ }{%
+ \xdef\tikzumlPath{(\tikzumlSrcClassNodeName.\tikzumlRelationStartAngle) -- \tikzumlFirstArc (\tikzumlRelationName-2.center) -- \tikzumlMidOneArc (\tikzumlRelationName-4.center) -- \tikzumlMidTwoArc (\tikzumlRelationName-6.center) -- \tikzumlLastArc (\tikzumlDestClassNodeName.\tikzumlRelationEndAngle) }%
+ \ifnum\thetikzumlStateLevel>0%
+ \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitTmp (\tikzumlRelationName-1) (\tikzumlRelationName-2) (\tikzumlRelationName-3) (\tikzumlRelationName-4) (\tikzumlRelationName-5) (\tikzumlRelationName-6) (\tikzumlRelationName-7)}%
+ \fi%
+ }%
+ }{}%
+ }%
+ }{%
+ \def\arcNum{1}%
+ \def\arcNumT{1}%
+ %
+ \node[inner sep=0] (\tikzumlRelationName-1) at (\tikzumlRelationName-middle) {};%
+ \xdef\tikzumlLastArc{node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity}%
+ node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT}%
+ node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \xdef\tikzumlPath{(\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor) -- \tikzumlLastArc (\tikzumlDestClassNodeName\tikzumlRelationDestAnchor) }%
+ \ifnum\thetikzumlStateLevel>0%
+ \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitTmp (\tikzumlRelationName-1) }%
+ \fi%
+ }%
+ }{%
+ % first vertical then horizontal line
+ \ifthenelse{\equal{\tikzumlRelationGeometry}{|-}}%
+ {%
+ %\setcounter{tikzumlControlNodesNum}{1}%
+ %
+ \def\tikzumlFirstArc{node[midway, inner sep=0, name=\tikzumlRelationName-1, anchor=center] {} }%
+ \def\tikzumlLastArc{node[midway, inner sep=0, name=\tikzumlRelationName-3, anchor=center]{} }%
+ %
+ \begin{pgfonlayer}{connections}%
+ \node[inner sep=0] (\tikzumlRelationName-2) at (\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor |- \tikzumlDestClassNodeName\tikzumlRelationDestAnchor) {};%
+ \end{pgfonlayer}%
+ %
+ \ifnum\theposStereo>100%
+ \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-100)/100}%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \else%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \fi%
+ %
+ \ifnum\thepos>100%
+ \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-100)/100}%
+ \def\arcNum{2}%
+ \else%
+ \def\arcNum{1}%
+ \ifnum\thepos=100%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ \fi%
+ \fi%
+ %
+ \ifnum\arcNum=1%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }%
+ \fi%
+ \ifnum\arcNum=2%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }%
+ \fi%
+ %
+ \ifnum\theposT>100%
+ \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-100)/100}%
+ \def\arcNumT{2}%
+ \else%
+ \def\arcNumT{1}%
+ \ifnum\theposT=100%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ \fi%
+ \fi%
+ %
+ \ifnum\arcNumT=1%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }%
+ \fi%
+ \ifnum\arcNumT=2%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }%
+ \fi%
+ %
+ \xdef\tikzumlPath{(\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor) -- \tikzumlFirstArc (\tikzumlRelationName-2.base) -- \tikzumlLastArc (\tikzumlDestClassNodeName\tikzumlRelationDestAnchor) }%
+ \ifnum\thetikzumlStateLevel>0%
+ \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitTmp (\tikzumlRelationName-1) (\tikzumlRelationName-2) (\tikzumlRelationName-3) }%
+ \fi%
+ }{%
+ % first horizontal then vertical line
+ \ifthenelse{\equal{\tikzumlRelationGeometry}{-|}}%
+ {%
+ %\setcounter{tikzumlControlNodesNum}{1}%
+ %
+ \def\tikzumlFirstArc{node[midway, inner sep=0, name=\tikzumlRelationName-1, anchor=center]{} }%
+ \def\tikzumlLastArc{node[midway, inner sep=0, name=\tikzumlRelationName-3, anchor=center] {} }%
+ %
+ \begin{pgfonlayer}{connections}%
+ \node[inner sep=0] (\tikzumlRelationName-2) at (\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor -| \tikzumlDestClassNodeName\tikzumlRelationDestAnchor) {};%
+ \end{pgfonlayer}%
+ %
+ \ifnum\theposStereo>100%
+ \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-100)/100}%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \else%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \fi%
+ %
+ \ifnum\thepos>100%
+ \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-100)/100}%
+ \def\arcNum{2}%
+ \else%
+ \def\arcNum{1}%
+ \ifnum\thepos=100%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ \fi%
+ \fi%
+ %
+ \ifnum\arcNum=1%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }%
+ \fi%
+ \ifnum\arcNum=2%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }%
+ \fi%
+ %
+ \ifnum\theposT>100%
+ \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-100)/100}%
+ \def\arcNumT{2}%
+ \else%
+ \def\arcNumT{1}%
+ \ifnum\theposT=100%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ \fi%
+ \fi%
+ %
+ \ifnum\arcNumT=1%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }%
+ \fi%
+ \ifnum\arcNumT=2%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }%
+ \fi%
+ %
+ \xdef\tikzumlPath{(\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor) -- \tikzumlFirstArc (\tikzumlRelationName-2.base) -- \tikzumlLastArc (\tikzumlDestClassNodeName\tikzumlRelationDestAnchor) }%
+ \ifnum\thetikzumlStateLevel>0%
+ \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitTmp (\tikzumlRelationName-1) (\tikzumlRelationName-2) (\tikzumlRelationName-3) }%
+ \fi%
+ }{%
+ % first vertical, then horizontal, finally vertical line
+ \ifthenelse{\equal{\tikzumlRelationGeometry}{|-|}}%
+ {%
+ %\setcounter{tikzumlControlNodesNum}{2}%
+ %
+ \def\tikzumlFirstArc{node[midway, inner sep=0, name=\tikzumlRelationName-1, anchor=center] {} }%
+ \def\tikzumlLastArc{node[midway, inner sep=0, name=\tikzumlRelationName-5, anchor=center] {} }%
+ \def\tikzumlMidOneArc{ }%
+ %
+ \begin{pgfonlayer}{connections}%
+ %
+ \ifthenelse{\equal{\tikzumlRelationArmO}{auto}}{%
+ \ifthenelse{\equal{\tikzumlRelationArmT}{auto}}{%
+ \node[inner sep=0] (\tikzumlRelationName-3) at (\tikzumlRelationName-middle) {};%
+ \node[inner sep=0] (\tikzumlRelationName-2) at (\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor |- \tikzumlRelationName-3) {};%
+ \node[inner sep=0] (\tikzumlRelationName-4) at (\tikzumlRelationName-3 -| \tikzumlDestClassNodeName\tikzumlRelationDestAnchor) {};%
+ }{%
+ \draw (\tikzumlDestClassNodeName\tikzumlRelationDestAnchor)+(0,\tikzumlRelationArmT) node[inner sep=0, name=\tikzumlRelationName-4] {};%
+ \node[inner sep=0] (\tikzumlRelationName-2) at (\tikzumlRelationName-4 -| \tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor) {};%
+ \node[inner sep=0] (\tikzumlRelationName-3) at (barycentric cs:\tikzumlRelationName-2=0.5,\tikzumlRelationName-4=0.5) {};%
+ }%
+ }{%
+ \draw (\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor)+(0,\tikzumlRelationArmO) node[inner sep=0, name=\tikzumlRelationName-2] {};%
+ \node[inner sep=0] (\tikzumlRelationName-4) at (\tikzumlRelationName-2 -| \tikzumlDestClassNodeName\tikzumlRelationDestAnchor) {};%
+ \node[inner sep=0] (\tikzumlRelationName-3) at (barycentric cs:\tikzumlRelationName-2=0.5,\tikzumlRelationName-4=0.5) {};%
+ }%
+ \end{pgfonlayer}%
+ %
+ \ifnum\theposStereo>200%
+ \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-200)/100}%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \else%
+ \ifnum\theposStereo<100%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \else%
+ \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-100)/100}%
+ \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \fi%
+ \fi%
+ %
+ \ifthenelse{\thepos=200\OR\thepos=100}{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }{}%
+ %
+ \ifthenelse{\thepos>200}{%
+ \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-200)/100}%
+ \def\arcNum{3}%
+ }{%
+ \ifthenelse{\thepos<100}{%
+ \def\arcNum{1}%
+ }{%
+ \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-100)/100}%
+ \def\arcNum{2}%
+ }%
+ }%
+ %
+ \ifnum\arcNum=1%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }%
+ \fi%
+ \ifnum\arcNum=2%
+ \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }%
+ \fi%
+ \ifnum\arcNum=3%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }%
+ \fi%
+ %
+ \ifthenelse{\theposT=200\OR\theposT=100}{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }{}%
+ %
+ \ifthenelse{\theposT>200}{%
+ \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-200)/100}%
+ \def\arcNumT{3}%
+ }{%
+ \ifthenelse{\theposT<100}{%
+ \def\arcNumT{1}%
+ }{%
+ \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-100)/100}%
+ \def\arcNumT{2}%
+ }%
+ }%
+ %
+ \ifnum\arcNumT=1%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }%
+ \fi%
+ \ifnum\arcNumT=2%
+ \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }%
+ \fi%
+ \ifnum\arcNumT=3%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }%
+ \fi%
+ %
+ \xdef\tikzumlPath{(\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor) -- \tikzumlFirstArc (\tikzumlRelationName-2.base) -- \tikzumlMidOneArc (\tikzumlRelationName-4.base) -- \tikzumlLastArc (\tikzumlDestClassNodeName\tikzumlRelationDestAnchor) }%
+ \ifnum\thetikzumlStateLevel>0%
+ \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitTmp (\tikzumlRelationName-1) (\tikzumlRelationName-2) (\tikzumlRelationName-3) (\tikzumlRelationName-4) (\tikzumlRelationName-5) }%
+ \fi%
+ }{%
+ % first horizontal, then vertical, finally horizontal line
+ \ifthenelse{\equal{\tikzumlRelationGeometry}{-|-}}%
+ {%
+ %\setcounter{tikzumlControlNodesNum}{2}%
+ %
+ \def\tikzumlFirstArc{node[midway, inner sep=0, name=\tikzumlRelationName-1, anchor=center] {} }%
+ \def\tikzumlLastArc{node[midway, inner sep=0, name=\tikzumlRelationName-5, anchor=center] {} }%
+ \def\tikzumlMidOneArc{}%
+ %
+ \begin{pgfonlayer}{connections}%
+ %
+ \ifthenelse{\equal{\tikzumlRelationArmO}{auto}}{%
+ \ifthenelse{\equal{\tikzumlRelationArmT}{auto}}{%
+ \node[inner sep=0] (\tikzumlRelationName-3) at (\tikzumlRelationName-middle) {};%
+ \node[inner sep=0] (\tikzumlRelationName-2) at (\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor -| \tikzumlRelationName-3) {};%
+ \node[inner sep=0] (\tikzumlRelationName-4) at (\tikzumlRelationName-3 |- \tikzumlDestClassNodeName\tikzumlRelationDestAnchor) {};%
+ }{%
+ \draw (\tikzumlDestClassNodeName\tikzumlRelationDestAnchor)+(\tikzumlRelationArmT,0) node[inner sep=0, name=\tikzumlRelationName-4] {};%
+ \node[inner sep=0] (\tikzumlRelationName-2) at (\tikzumlRelationName-4 |- \tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor) {};%
+ \node[inner sep=0] (\tikzumlRelationName-3) at (barycentric cs:\tikzumlRelationName-2=0.5,\tikzumlRelationName-4=0.5) {};%
+ }%
+ }{%
+ \draw (\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor)+(\tikzumlRelationArmO,0) node[inner sep=0, name=\tikzumlRelationName-2] {};%
+ \node[inner sep=0] (\tikzumlRelationName-4) at (\tikzumlRelationName-2 |- \tikzumlDestClassNodeName\tikzumlRelationDestAnchor) {};%
+ \node[inner sep=0] (\tikzumlRelationName-3) at (barycentric cs:\tikzumlRelationName-2=0.5,\tikzumlRelationName-4=0.5) {};%
+ }%
+ \end{pgfonlayer}%
+ %
+ \ifnum\theposStereo>200%
+ \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-200)/100}%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \else%
+ \ifnum\theposStereo<100%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \else%
+ \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-100)/100}%
+ \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \fi%
+ \fi%
+ %
+ \ifthenelse{\thepos=200\OR\thepos=100}{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }{}%
+ %
+ \ifthenelse{\thepos>200}{%
+ \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-200)/100}%
+ \def\arcNum{3}%
+ }{%
+ \ifthenelse{\thepos<100}{%
+ \def\arcNum{1}%
+ }{%
+ \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-100)/100}%
+ \def\arcNum{2}%
+ }%
+ }%
+ %
+ \ifnum\arcNum=1%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }%
+ \fi%
+ \ifnum\arcNum=2%
+ \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }%
+ \fi%
+ \ifnum\arcNum=3%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }%
+ \fi%
+ %
+ \ifthenelse{\theposT=200\OR\theposT=100}{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }{}%
+ %
+ \ifthenelse{\theposT>200}{%
+ \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-200)/100}%
+ \def\arcNumT{3}%
+ }{%
+ \ifthenelse{\theposT<100}{%
+ \def\arcNumT{1}%
+ }{%
+ \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-100)/100}%
+ \def\arcNumT{2}%
+ }%
+ }%
+ %
+ \ifnum\arcNumT=1%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }%
+ \fi%
+ \ifnum\arcNumT=2%
+ \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }%
+ \fi%
+ \ifnum\arcNumT=3%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }%
+ \fi%
+ %
+ \xdef\tikzumlPath{(\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor) -- \tikzumlFirstArc (\tikzumlRelationName-2.base) -- \tikzumlMidOneArc (\tikzumlRelationName-4.base) -- \tikzumlLastArc (\tikzumlDestClassNodeName\tikzumlRelationDestAnchor) }%
+ \ifnum\thetikzumlStateLevel>0%
+ \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitTmp (\tikzumlRelationName-1) (\tikzumlRelationName-2) (\tikzumlRelationName-3) (\tikzumlRelationName-4) (\tikzumlRelationName-5) }%
+ \fi%
+ }{%
+ \errmessage{TIKZUML ERROR : Unknown geometry value !!! It should be in the following list : --, |-, -|, |-|, -|-}%
+ }%
+ }%
+ }%
+ }%
+ }%
+ %
+ \begin{pgfonlayer}{connections}%
+ \ifthenelse{\equal{\tikzumlRelationStyle}{tikzuml nesting style}}{%
+ \pgfarrowsdeclare{nested}{nested}{...}
+ {
+ \tikzumlNestingSymbolSize=0.2pt%
+ \advance\tikzumlNestingSymbolSize by .5\pgflinewidth%
+ \pgfsetdash{}{0pt} % do not dash
+ \pgfsetroundjoin % fix join
+ \pgfsetroundcap % fix cap
+ \pgfpathmoveto{\pgfpoint{-16*\tikzumlNestingSymbolSize}{0pt}}%
+ \pgfpatharc{180}{90}{8*\tikzumlNestingSymbolSize}%
+ \pgfpatharc{90}{0}{8*\tikzumlNestingSymbolSize}%
+ \pgfpatharc{0}{-90}{8*\tikzumlNestingSymbolSize}%
+ \pgfpatharc{-90}{-180}{8*\tikzumlNestingSymbolSize}%
+ \pgfpathmoveto{\pgfpoint{-8*\tikzumlNestingSymbolSize}{8*\tikzumlNestingSymbolSize}}%
+ \pgfpathlineto{\pgfpoint{-8*\tikzumlNestingSymbolSize}{-8*\tikzumlNestingSymbolSize}}%
+ \pgfusepathqstroke%
+ }%
+ \draw[auto, nested-, font=\tikzumlDefaultFont, \tikzumlRelationStyle, /tikzuml/relation/style2] \tikzumlPath ;%
+ }{
+ \draw[auto, font=\tikzumlDefaultFont, \tikzumlRelationStyle, /tikzuml/relation/style2] \tikzumlPath ;%
+ }
+ \end{pgfonlayer}%
+ %
+ \stepcounter{tikzumlRelationNum}%
+}%
+%
+% shortcuts of \umlrelation
+\newcommand{\umlHVrelation}[3][]{%
+ \pgfkeys{/tikzuml/HVrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlHVrelation, forbidden option geometry}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/HVrelation/.cd, #1}%
+ \umlrelation[geometry=-|, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlVHrelation}[3][]{%
+ \pgfkeys{/tikzuml/VHrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlVHrelation, forbidden option geometry}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/VHrelation/.cd, #1}%
+ \umlrelation[geometry=|-, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlHVHrelation}[3][]{%
+ \pgfkeys{/tikzuml/HVHrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlHVHrelation, forbidden option geometry}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/HVHrelation/.cd, #1}%
+ \umlrelation[geometry=-|-, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlVHVrelation}[3][]{%
+ \pgfkeys{/tikzuml/VHVrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlVHVrelation, forbidden option geometry}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/VHVrelation/.cd, #1}%
+ \umlrelation[geometry=|-|, #1]{#2}{#3}%
+}%
+%
+%
+% shortcuts for relations
+\newcommand{\umlinherit}[3][]{\umlrelation[style={tikzuml inherit style}, #1]{#2}{#3}}%
+\newcommand{\umlimpl}[3][]{\umlrelation[style={tikzuml implements style}, #1]{#2}{#3}}%
+\newcommand{\umlreal}[3][]{\umlrelation[style={tikzuml implements style}, #1]{#2}{#3}}%
+\newcommand{\umlassoc}[3][]{\umlrelation[style={tikzuml association style}, #1]{#2}{#3}}%
+\newcommand{\umlbiassoc}[3][]{\umlrelation[style={tikzuml bidirectional association style}, #1]{#2}{#3}}%
+\newcommand{\umluniassoc}[3][]{\umlrelation[style={tikzuml unidirectional association style}, #1]{#2}{#3}}%
+\newcommand{\umlaggreg}[3][]{\umlrelation[style={tikzuml aggregation style}, #1]{#2}{#3}}%
+\newcommand{\umluniaggreg}[3][]{\umlrelation[style={tikzuml unidirectional aggregation style}, #1]{#2}{#3}}%
+\newcommand{\umlcompo}[3][]{\umlrelation[style={tikzuml composition style}, #1]{#2}{#3}}%
+\newcommand{\umlunicompo}[3][]{\umlrelation[style={tikzuml unidirectional composition style}, #1]{#2}{#3}}%
+\newcommand{\umlimport}[3][]{\umlrelation[style={tikzuml import style}, #1]{#2}{#3}}%
+\newcommand{\umlnest}[3][]{\umlrelation[style={tikzuml nesting style}, #1]{#2}{#3}}%
+\newcommand{\umldep}[3][]{\umlrelation[style={tikzuml dependency style}, #1]{#2}{#3}}%
+\newcommand{\umlfriend}[3][]{%
+ \pgfkeys{/tikzuml/friendrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlfriend, forbidden option stereo}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/friendrelation/.cd, #1}%
+ \umlrelation[stereo=friend, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlHVinherit}[3][]{\umlHVrelation[style={tikzuml inherit style}, #1]{#2}{#3}}%
+\newcommand{\umlHVimpl}[3][]{\umlHVrelation[style={tikzuml implements style}, #1]{#2}{#3}}%
+\newcommand{\umlHVreal}[3][]{\umlHVrelation[style={tikzuml implements style}, #1]{#2}{#3}}%
+\newcommand{\umlHVassoc}[3][]{\umlHVrelation[style={tikzuml association style}, #1]{#2}{#3}}%
+\newcommand{\umlHVuniassoc}[3][]{\umlHVrelation[style={tikzuml unidirectional association style}, #1]{#2}{#3}}%
+\newcommand{\umlHVaggreg}[3][]{\umlHVrelation[style={tikzuml aggregation style}, #1]{#2}{#3}}%
+\newcommand{\umlHVuniaggreg}[3][]{\umlHVrelation[style={tikzuml unidirectional aggregation style}, #1]{#2}{#3}}%
+\newcommand{\umlHVcompo}[3][]{\umlHVrelation[style={tikzuml composition style}, #1]{#2}{#3}}%
+\newcommand{\umlHVunicompo}[3][]{\umlHVrelation[style={tikzuml unidirectional composition style}, #1]{#2}{#3}}%
+\newcommand{\umlHVimport}[3][]{\umlHVrelation[style={tikzuml import style}, #1]{#2}{#3}}%
+\newcommand{\umlHVnest}[3][]{\umlHVrelation[style={tikzuml nesting style}, #1]{#2}{#3}}%
+\newcommand{\umlHVdep}[3][]{\umlHVrelation[style={tikzuml dependency style}, #1]{#2}{#3}}%
+\newcommand{\umlHVfriend}[3][]{%
+ \pgfkeys{/tikzuml/friendrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlHVfriend, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlHVfriend, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/friendrelation/.cd, #1}%
+ \umlrelation[geometry=-|, stereo=friend, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlVHinherit}[3][]{\umlVHrelation[style={tikzuml inherit style}, #1]{#2}{#3}}%
+\newcommand{\umlVHimpl}[3][]{\umlVHrelation[style={tikzuml implements style}, #1]{#2}{#3}}%
+\newcommand{\umlVHreal}[3][]{\umlVHrelation[style={tikzuml implements style}, #1]{#2}{#3}}%
+\newcommand{\umlVHassoc}[3][]{\umlVHrelation[style={tikzuml association style}, #1]{#2}{#3}}%
+\newcommand{\umlVHuniassoc}[3][]{\umlVHrelation[style={tikzuml unidirectional association style}, #1]{#2}{#3}}%
+\newcommand{\umlVHaggreg}[3][]{\umlVHrelation[style={tikzuml aggregation style}, #1]{#2}{#3}}%
+\newcommand{\umlVHuniaggreg}[3][]{\umlVHrelation[style={tikzuml unidirectional aggregation style}, #1]{#2}{#3}}%
+\newcommand{\umlVHcompo}[3][]{\umlVHrelation[style={tikzuml composition style}, #1]{#2}{#3}}%
+\newcommand{\umlVHunicompo}[3][]{\umlVHrelation[style={tikzuml unidirectional composition style}, #1]{#2}{#3}}%
+\newcommand{\umlVHimport}[3][]{\umlVHrelation[style={tikzuml import style}, #1]{#2}{#3}}%
+\newcommand{\umlVHnest}[3][]{\umlVHrelation[style={tikzuml nesting style}, #1]{#2}{#3}}%
+\newcommand{\umlVHdep}[3][]{\umlVHrelation[style={tikzuml dependency style}, #1]{#2}{#3}}%
+\newcommand{\umlVHfriend}[3][]{%
+ \pgfkeys{/tikzuml/friendrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlVHfriend, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlVHfriend, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/friendrelation/.cd, #1}%
+ \umlrelation[geometry=|-, stereo=friend, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlHVHinherit}[3][]{\umlHVHrelation[style={tikzuml inherit style}, #1]{#2}{#3}}%
+\newcommand{\umlHVHimpl}[3][]{\umlHVHrelation[style={tikzuml implements style}, #1]{#2}{#3}}%
+\newcommand{\umlHVHreal}[3][]{\umlHVHrelation[style={tikzuml implements style}, #1]{#2}{#3}}%
+\newcommand{\umlHVHassoc}[3][]{\umlHVHrelation[style={tikzuml association style}, #1]{#2}{#3}}%
+\newcommand{\umlHVHuniassoc}[3][]{\umlHVHrelation[style={tikzuml unidirectional association style}, #1]{#2}{#3}}%
+\newcommand{\umlHVHaggreg}[3][]{\umlHVHrelation[style={tikzuml aggregation style}, #1]{#2}{#3}}%
+\newcommand{\umlHVHuniaggreg}[3][]{\umlHVHrelation[style={tikzuml unidirectional aggregation style}, #1]{#2}{#3}}%
+\newcommand{\umlHVHcompo}[3][]{\umlHVHrelation[style={tikzuml composition style}, #1]{#2}{#3}}%
+\newcommand{\umlHVHunicompo}[3][]{\umlHVHrelation[style={tikzuml unidirectional composition style}, #1]{#2}{#3}}%
+\newcommand{\umlHVHimport}[3][]{\umlHVHrelation[style={tikzuml import style}, #1]{#2}{#3}}%
+\newcommand{\umlHVHnest}[3][]{\umlHVHrelation[style={tikzuml nesting style}, #1]{#2}{#3}}%
+\newcommand{\umlHVHdep}[3][]{\umlHVHrelation[style={tikzuml dependency style}, #1]{#2}{#3}}%
+\newcommand{\umlHVHfriend}[3][]{%
+ \pgfkeys{/tikzuml/friendrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlHVHfriend, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlHVHfriend, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/friendrelation/.cd, #1}%
+ \umlrelation[geometry=-|-, stereo=friend, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlVHVinherit}[3][]{\umlVHVrelation[style={tikzuml inherit style}, #1]{#2}{#3}}%
+\newcommand{\umlVHVimpl}[3][]{\umlVHVrelation[style={tikzuml implements style}, #1]{#2}{#3}}%
+\newcommand{\umlVHVreal}[3][]{\umlVHVrelation[style={tikzuml implements style}, #1]{#2}{#3}}%
+\newcommand{\umlVHVassoc}[3][]{\umlVHVrelation[style={tikzuml association style}, #1]{#2}{#3}}%
+\newcommand{\umlVHVuniassoc}[3][]{\umlVHVrelation[style={tikzuml unidirectional association style}, #1]{#2}{#3}}%
+\newcommand{\umlVHVaggreg}[3][]{\umlVHVrelation[style={tikzuml aggregation style}, #1]{#2}{#3}}%
+\newcommand{\umlVHVuniaggreg}[3][]{\umlVHVrelation[style={tikzuml unidirectional aggregation style}, #1]{#2}{#3}}%
+\newcommand{\umlVHVcompo}[3][]{\umlVHVrelation[style={tikzuml composition style}, #1]{#2}{#3}}%
+\newcommand{\umlVHVunicompo}[3][]{\umlVHVrelation[style={tikzuml unidirectional composition style}, #1]{#2}{#3}}%
+\newcommand{\umlVHVimport}[3][]{\umlVHVrelation[style={tikzuml import style}, #1]{#2}{#3}}%
+\newcommand{\umlVHVnest}[3][]{\umlVHVrelation[style={tikzuml nesting style}, #1]{#2}{#3}}%
+\newcommand{\umlVHVdep}[3][]{\umlVHVrelation[style={tikzuml dependency style}, #1]{#2}{#3}}%
+\newcommand{\umlVHVfriend}[3][]{%
+ \pgfkeys{/tikzuml/friendrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlVHVfriend, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlVHVfriend, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/friendrelation/.cd, #1}%
+ \umlrelation[geometry=|-|, stereo=friend, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+%
+% define a node
+\newcommand{\umlnode}[2]{%
+ \node (#2) at (#1) {};%
+}%
+%
+% main command to define a relation between two classes through a control node
+% args : src class
+% control node
+% dest class
+% optional : arg1, arg2, arg: name of the src/dest/dest side class type attribute defined by the relation
+% mult1, mult2, mult: multiplicity of the src/dest/dest side class type attribute defined by the relation
+% pos1, pos2, pos: position of the src/dest/dest side class type attribute defined by the relation
+% align1, align2, align: text justification of the src/dest/dest side class type attribute defined by the relation
+% anchor1, anchor2: src/dest anchors on linked classes
+% stereo: stereotype of the relation
+% pos stereo: position of the stereotype on the relation
+% style: style of the relation (association, aggregation, composition, inherit, ...)
+% name: rootname used for naming nodes of the relation
+\newcommand{\umlCNrelation}[4][]{%
+ \pgfkeys{/tikzuml/relation/.cd, arg1/.initial={}, arg2/.initial={}, arg/.initial={},%
+ mult1/.initial={}, mult2/.initial={}, mult/.initial={},%
+ pos1/.initial=0.2, pos2/.initial=0.8, pos/.initial=tikzumlEmpty,%
+ align1/.initial={}, align2/.initial={}, align/.initial={},%
+ anchor1/.initial=tikzumlEmpty, anchor2/.initial=tikzumlEmpty,%
+ stereo/.initial={}, pos stereo/.initial=1,%
+ style/.initial=->, name/.initial=relation-\thetikzumlRelationNum,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \errmessage{TIKZUML ERROR : in umlCNrelation, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/relation/.cd,#1}%
+ \pgfkeys{/tikzuml/relation/.cd, arg1/.get=\tikzumlCNRelationAttrName, arg2/.get=\tikzumlCNRelationAttrNameTO, arg/.get=\tikzumlCNRelationAttrNameTT,%
+ mult1/.get=\tikzumlCNRelationMultiplicity, mult2/.get=\tikzumlCNRelationMultiplicityTO, mult/.get=\tikzumlCNRelationMultiplicityTT,%
+ pos1/.get=\tikzumlCNRelationPosition, pos2/.get=\tikzumlCNRelationPositionTO, pos/.get=\tikzumlCNRelationPositionTT,%
+ align1/.get=\tikzumlCNRelationAlign, align2/.get=\tikzumlCNRelationAlignTO, align/.get=\tikzumlCNRelationAlignTT,%
+ anchor1/.get=\tikzumlCNRelationSrcAnchor, anchor2/.get=\tikzumlCNRelationDestAnchor,%
+ stereo/.get=\tikzumlCNRelationStereoType, pos stereo/.get=\tikzumlCNRelationPositionStereotype,%
+ style/.get=\tikzumlCNRelationStyle, name/.get=\tikzumlCNRelationName%
+ }%
+ %
+ % managing \_ in class names for node names
+ \def\tikzumlSrcClassName{#2}%
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlSrcClassNodeName{\tikzumlSrcClassName}}\x%
+ %
+ \StrSubstitute{\tikzumlSrcClassNodeName}{:}{@COLON@}[\tikzumlSrcClassNodeName]%
+ \StrSubstitute{\tikzumlSrcClassNodeName}{\_}{@UNDERSCORE@}[\tikzumlSrcClassNodeName]%
+ %
+ \def\tikzumlDestClassName{#4}%
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlDestClassNodeName{\tikzumlDestClassName}}\x%
+ %
+ \StrSubstitute{\tikzumlDestClassNodeName}{:}{@COLON@}[\tikzumlDestClassNodeName]%
+ \StrSubstitute{\tikzumlDestClassNodeName}{\_}{@UNDERSCORE@}[\tikzumlDestClassNodeName]%
+ %
+ % managing alias keys
+ \def\tikzumlCNRelationAttrNameT{\tikzumlCNRelationAttrNameTO\tikzumlCNRelationAttrNameTT}%
+ \def\tikzumlCNRelationMultiplicityT{\tikzumlCNRelationMultiplicityTO\tikzumlCNRelationMultiplicityTT}%
+ \def\tikzumlCNRelationAlignT{\tikzumlCNRelationAlignTO\tikzumlCNRelationAlignTT}%
+ \def\orientationT{\orientationTO\orientationTT}%
+ %
+ \ifthenelse{\equal{\tikzumlCNRelationPositionTT}{tikzumlEmpty}}{%
+ \def\tikzumlCNRelationPositionT{\tikzumlCNRelationPositionTO}%
+ }{%
+ \def\tikzumlCNRelationPositionT{\tikzumlCNRelationPositionTT}%
+ }%
+ %
+ \def\attrAlign{}%
+ \def\multAlign{}%
+ \def\attrAlignT{}%
+ \def\multAlignT{}%
+ %
+ \ifthenelse{\equal{\tikzumlCNRelationAlign}{left}}{%
+ \def\attrAlign{above right}%
+ \def\multAlign{below right}%
+ }{%
+ \ifthenelse{\equal{\tikzumlCNRelationAlign}{right}}{%
+ \def\attrAlign{above left}%
+ \def\multAlign{below left}%
+ }{}%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlCNRelationAlignT}{left}}{%
+ \def\attrAlignT{above right}%
+ \def\multAlignT{below right}%
+ }{%
+ \ifthenelse{\equal{\tikzumlCNRelationAlignT}{right}}{%
+ \def\attrAlignT{above left}%
+ \def\multAlignT{below left}%
+ }{}%
+ }%
+ %
+ % def stereotype
+ \ifthenelse{\equal{\tikzumlCNRelationStereoType}{}}{%
+ \def\stereotype{}%
+ }{%
+ \def\stereotype{$\ll$\tikzumlCNRelationStereoType$\gg$}%
+ }%
+ %
+ % def anchors macros
+ \ifthenelse{\equal{\tikzumlCNRelationSrcAnchor}{tikzumlEmpty}}{%
+ \def\tikzumlCNRelationSrcAnchor{}%
+ }{%
+ \let\tikzumlCNRelationSrcAnchorold\tikzumlCNRelationSrcAnchor%
+ \def\tikzumlCNRelationSrcAnchor{.\tikzumlCNRelationSrcAnchorold}%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlCNRelationDestAnchor}{tikzumlEmpty}}{%
+ \def\tikzumlCNRelationDestAnchor{}%
+ }{%
+ \let\tikzumlCNRelationDestAnchorold\tikzumlCNRelationDestAnchor%
+ \def\tikzumlCNRelationDestAnchor{.\tikzumlCNRelationDestAnchorold}%
+ }%
+ %
+ \setcounter{pos}{100*\real{\tikzumlCNRelationPosition}}%
+ \setcounter{posT}{100*\real{\tikzumlCNRelationPositionT}}%
+ \setcounter{posStereo}{100*\real{\tikzumlCNRelationPositionStereotype}}%
+ %
+ % straight line
+ %\setcounter{tikzumlControlNodesNum}{1}%
+ %
+ \def\tikzumlFirstArc{node[midway, name=\tikzumlCNRelationName-1, anchor=center] {} }%
+ \def\tikzumlLastArc{node[midway, name=\tikzumlCNRelationName-3, anchor=center]{} }%
+ \def\posAttrName{}%
+ \def\posMultiplicity{}%
+ \def\posAttrNameT{}%
+ \def\posMultiplicityT{}%
+ %
+ \begin{pgfonlayer}{connections}%
+ \node (\tikzumlCNRelationName-2) at (#3) {};%
+ \end{pgfonlayer}%
+ %
+ \ifnum\theposStereo>100%
+ \pgfmathsetmacro{\tikzumlCNRelationPositionStereotype}{(\theposStereo-100)/100}%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlCNRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \else%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlCNRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \fi%
+ %
+ \ifnum\thepos>100%
+ \pgfmathsetmacro{\tikzumlCNRelationPosition}{(\thepos-100)/100}%
+ \def\arcNum{2}%
+ \else%
+ \def\arcNum{1}%
+ \ifnum\thepos=100%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ \fi%
+ \fi%
+ %
+ \ifnum\arcNum=1%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlCNRelationPosition, \posAttrName, \attrAlign] {\tikzumlCNRelationAttrName}%
+ node[pos=\tikzumlCNRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlCNRelationMultiplicity} }%
+ \fi%
+ \ifnum\arcNum=2%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlCNRelationPosition, \posAttrName, \attrAlign] {\tikzumlCNRelationAttrName}%
+ node[pos=\tikzumlCNRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlCNRelationMultiplicity} }%
+ \fi%
+ %
+ \ifnum\theposT>100%
+ \pgfmathsetmacro{\tikzumlCNRelationPositionT}{(\theposT-100)/100}%
+ \def\arcNumT{2}%
+ \else%
+ \def\arcNumT{1}%
+ \ifnum\theposT=100%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ \fi%
+ \fi%
+ %
+ \ifnum\arcNumT=1%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlCNRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlCNRelationAttrNameT}%
+ node[pos=\tikzumlCNRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlCNRelationMultiplicityT} }%
+ \fi%
+ \ifnum\arcNumT=2%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlCNRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlCNRelationAttrNameT}%
+ node[pos=\tikzumlCNRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlCNRelationMultiplicityT} }%
+ \fi%
+ %
+ \xdef\tikzumlPath{(\tikzumlSrcClassNodeName\tikzumlCNRelationSrcAnchor) -- \tikzumlFirstArc (\tikzumlCNRelationName-2.base) -- \tikzumlLastArc (\tikzumlDestClassNodeName\tikzumlCNRelationDestAnchor) }%
+
+ \begin{pgfonlayer}{connections}%
+ \ifthenelse{\equal{\tikzumlCNRelationStyle}{tikzuml nesting style}}{%
+ \pgfarrowsdeclare{nested}{nested}{...}
+ {
+ \tikzumlNestingSymbolSize=0.2pt%
+ \advance\tikzumlNestingSymbolSize by .5\pgflinewidth%
+ \pgfsetdash{}{0pt} % do not dash
+ \pgfsetroundjoin % fix join
+ \pgfsetroundcap % fix cap
+ \pgfpathmoveto{\pgfpoint{-16*\tikzumlNestingSymbolSize}{0pt}}%
+ \pgfpatharc{180}{90}{8*\tikzumlNestingSymbolSize}%
+ \pgfpatharc{90}{0}{8*\tikzumlNestingSymbolSize}%
+ \pgfpatharc{0}{-90}{8*\tikzumlNestingSymbolSize}%
+ \pgfpatharc{-90}{-180}{8*\tikzumlNestingSymbolSize}%
+ \pgfpathmoveto{\pgfpoint{-8*\tikzumlNestingSymbolSize}{8*\tikzumlNestingSymbolSize}}%
+ \pgfpathlineto{\pgfpoint{-8*\tikzumlNestingSymbolSize}{-8*\tikzumlNestingSymbolSize}}%
+ \pgfusepathqstroke%
+ }%
+ \draw[auto, \tikzumlCNRelationStyle, nested-, font=\tikzumlDefaultFont] \tikzumlPath ;%
+ }{
+ \draw[auto, \tikzumlCNRelationStyle, font=\tikzumlDefaultFont] \tikzumlPath ;%
+ }
+ \end{pgfonlayer}%
+ %
+ \stepcounter{tikzumlRelationNum}%
+}%
+%
+% shortcuts for cnrelations
+\newcommand{\umlCNinherit}[4][]{\umlCNrelation[style={tikzuml inherit style}, #1]{#2}{#3}{#4}}%
+\newcommand{\umlCNimpl}[4][]{\umlCNrelation[style={tikzuml implements style}, #1]{#2}{#3}{#4}}%
+\newcommand{\umlCNreal}[4][]{\umlCNrelation[style={tikzuml implements style}, #1]{#2}{#3}{#4}}%
+\newcommand{\umlCNassoc}[4][]{\umlCNrelation[style={tikzuml association style}, #1]{#2}{#3}{#4}}%
+\newcommand{\umlCNuniassoc}[4][]{\umlCNrelation[style={tikzuml unidirectional association style}, #1]{#2}{#3}{#4}}%
+\newcommand{\umlCNaggreg}[4][]{\umlCNrelation[style={tikzuml aggregation style}, #1]{#2}{#3}{#4}}%
+\newcommand{\umlCNuniaggreg}[4][]{\umlCNrelation[style={tikzuml unidirectional aggregation style}, #1]{#2}{#3}{#4}}%
+\newcommand{\umlCNcompo}[4][]{\umlCNrelation[style={tikzuml composition style}, #1]{#2}{#3}{#4}}%
+\newcommand{\umlCNunicompo}[4][]{\umlCNrelation[style={tikzuml unidirectional composition style}, #1]{#2}{#3}{#4}}%
+\newcommand{\umlCNimport}[4][]{\umlCNrelation[style={tikzuml import style}, #1]{#2}{#3}{#4}}%
+\newcommand{\umlCNnest}[4][]{\umlCNrelation[style={tikzuml nesting style}, #1]{#2}{#3}{#4}}%
+\newcommand{\umlCNdep}[4][]{\umlCNrelation[style={tikzuml dependency style}, #1]{#2}{#3}{#4}}%
+\newcommand{\umlCNfriend}[4][]{%
+ \pgfkeys{/tikzuml/friendrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlCNfriend, forbidden option stereo}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/friendrelation/.cd, #1}%
+ \umlCNrelation[stereo=friend, style={tikzuml dependency style}, #1]{#2}{#3}{#4}%
+}%
+%
+% define a note
+% arg : attached class
+% label of the note
+% optional : x,y: coordinates of the note
+% width: width of the note
+% geometry: geometry of the relation between the note and what it is about
+% weight: barycentric weight for a 3-line relation
+% arm: length of the first arm
+% anchor1, anchor2: anchors of the relation
+% draw, fill, text: colors
+% style: to manage every default TikZ option
+% no coords: to tell that the note position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlnote}[3][]{%
+ \pgfkeys{/tikzuml/note/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlNoteDefaultWidth,%
+ geometry/.initial=\tikzumlRelationDefaultGeometry,%
+ weight/.initial=\tikzumlRelationDefaultWeight, arm/.initial=auto, style/.style={},%
+ anchor1/.initial=tikzumlEmpty, anchor2/.initial=tikzumlEmpty,%
+ draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlNoteDefaultFillColor,%
+ text/.initial=\tikzumlDefaultTextColor,%
+ no coords/.is if=tikzumlnoteWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/note/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/note/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/note/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlnote, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/note/.cd, #1}%
+ \pgfkeys{/tikzuml/note/.cd, x/.get=\tikzumlNoteX, y/.get=\tikzumlNoteY, width/.get=\tikzumlNoteTextWidth,%
+ geometry/.get=\tikzumlNoteGeometry,%
+ weight/.get=\tikzumlNoteWeight, arm/.get=\tikzumlNoteArm,%
+ anchor1/.get=\tikzumlNoteSrcAnchor, anchor2/.get=\tikzumlNoteDestAnchor,%
+ draw/.get=\tikzumlNoteDrawColor, fill/.get=\tikzumlNoteFillColor,%
+ text/.get=\tikzumlNoteTextColor%
+ }%
+ %
+ \def\tikzumlClassName{#2}%
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlClassNodeName{\tikzumlClassName}}\x%
+ %
+ % def anchors macros
+ \ifthenelse{\equal{\tikzumlNoteSrcAnchor}{tikzumlEmpty}}{%
+ \def\tikzumlNoteSrcAnchor{}%
+ }{%
+ \let\tikzumlNoteSrcAnchorold\tikzumlNoteSrcAnchor%
+ \def\tikzumlNoteSrcAnchor{.\tikzumlNoteSrcAnchorold}%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlNoteDestAnchor}{tikzumlEmpty}}{%
+ \def\tikzumlNoteDestAnchor{}%
+ }{%
+ \let\tikzumlNoteDestAnchorold\tikzumlNoteDestAnchor%
+ \def\tikzumlNoteDestAnchor{.\tikzumlNoteDestAnchorold}%
+ }%
+ %
+ \iftikzumlnoteWithoutCoords%
+ \node[text=\tikzumlNoteTextColor, text width=\tikzumlNoteTextWidth, font=\tikzumlDefaultFont, outer sep=0, inner xsep=1ex, inner ysep=3ex, /tikzuml/note/style] (note-\thetikzumlNoteNum-coord) {#3};%
+ \else%
+ \node[text=\tikzumlNoteTextColor, text width=\tikzumlNoteTextWidth, font=\tikzumlDefaultFont, outer sep=0, inner xsep=1ex, inner ysep=3ex, /tikzuml/note/style] (note-\thetikzumlNoteNum-coord) at (\tikzumlNoteX, \tikzumlNoteY) {#3};%
+ \fi%
+ \draw (note-\thetikzumlNoteNum-coord.north east) node[name=note-\thetikzumlNoteNum-right-top, below=2ex, coordinate] {};%
+ \draw (note-\thetikzumlNoteNum-coord.north east) node[name=note-\thetikzumlNoteNum-top-right, left=2ex, coordinate] {};%
+ \draw[draw=\tikzumlNoteDrawColor, fill=\tikzumlNoteFillColor] (note-\thetikzumlNoteNum-coord.south west) -- (note-\thetikzumlNoteNum-coord.south east) -- (note-\thetikzumlNoteNum-right-top.base) -- (note-\thetikzumlNoteNum-top-right.base) -- (note-\thetikzumlNoteNum-coord.north west) -- cycle;%
+ \node[text=\tikzumlNoteTextColor, text width=\tikzumlNoteTextWidth, outer sep=0, inner xsep=1ex, inner ysep=3ex, font=\tikzumlDefaultFont] (note-\thetikzumlNoteNum) at (note-\thetikzumlNoteNum-coord) {#3};%
+ \draw[draw=\tikzumlNoteDrawColor] (note-\thetikzumlNoteNum-right-top) -| (note-\thetikzumlNoteNum-top-right);%
+ %
+ \pgfmathsetmacro{\tikzumlNoteWeightT}{1.0-\tikzumlNoteWeight}%
+ \node (note-\thetikzumlNoteNum-middle) at (barycentric cs:note-\thetikzumlNoteNum-coord=\tikzumlNoteWeight,\tikzumlClassNodeName=\tikzumlNoteWeightT) {};%
+ %
+ \ifthenelse{\equal{\tikzumlNoteGeometry}{--}%
+ \OR\equal{\tikzumlNoteGeometry}{-|}%
+ \OR\equal{\tikzumlNoteGeometry}{|-}}{%
+ \edef\tikzumlnotepath{\tikzumlNoteGeometry}
+ }{%
+ \ifthenelse{\equal{\tikzumlNoteGeometry}{-|-}}{%
+ \ifthenelse{\equal{\tikzumlNoteArm}{auto}}{%
+ \edef\tikzumlnotepath{-- (note-\thetikzumlNoteNum-coord\tikzumlNoteSrcAnchor -| note-\thetikzumlNoteNum-middle.center) -- (note-\thetikzumlNoteNum-middle.center) -- (note-\thetikzumlNoteNum-middle.center |- \tikzumlClassNodeName\tikzumlNoteDestAnchor) --}%
+ }{%
+ \draw (note-\thetikzumlNoteNum-coord\tikzumlNoteSrcAnchor)+(\tikzumlNoteArm,0) node[name=note-\thetikzumlNoteNum-tmp] {};
+ \edef\tikzumlnotepath{-- (note-\thetikzumlNoteNum-tmp.center) |-}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlNoteGeometry}{|-|}}{%
+ \ifthenelse{\equal{\tikzumlNoteArm}{auto}}{%
+ \edef\tikzumlnotepath{-- (note-\thetikzumlNoteNum-coord\tikzumlNoteSrcAnchor |- note-\thetikzumlNoteNum-middle.center) -- (note-\thetikzumlNoteNum-middle.center) -- (note-\thetikzumlNoteNum-middle.center -| \tikzumlClassNodeName\tikzumlNoteDestAnchor) --}%
+ }{%
+ \draw (note-\thetikzumlNoteNum-coord\tikzumlNoteSrcAnchor)+(0,\tikzumlNoteArm) node[name=note-\thetikzumlNoteNum-tmp] {};
+ \edef\tikzumlnotepath{-- (note-\thetikzumlNoteNum-tmp.center) -|}%
+ }%
+
+ }{%
+ \errmessage{TIKZUML ERROR : Unknown geometry value !!! It should be in the following list : --, |-, -|, |-|, -|-}%
+ }%
+ }%
+ }%
+ %
+ \begin{pgfonlayer}{connections}%
+ \draw[dashed] (note-\thetikzumlNoteNum-coord\tikzumlNoteSrcAnchor) \tikzumlnotepath (\tikzumlClassNodeName\tikzumlNoteDestAnchor);%
+ \end{pgfonlayer}%
+ %
+ \stepcounter{tikzumlNoteNum}%
+}%
+%
+% shortcuts for note with geometry
+\newcommand{\umlHVnote}[3][]{%
+ \pgfkeys{/tikzuml/note/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlHVnote, forbidden option geometry}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/note/.cd, #1}%
+ \umlnote[geometry=-|, #1]{#2}{#3}%
+}%
+\newcommand{\umlVHnote}[3][]{%
+ \pgfkeys{/tikzuml/note/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlVHnote, forbidden option geometry}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/note/.cd, #1}%
+ \umlnote[geometry=|-, #1]{#2}{#3}%
+}%
+\newcommand{\umlVHVnote}[3][]{%
+ \pgfkeys{/tikzuml/note/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlVHVnote, forbidden option geometry}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/note/.cd, #1}%
+ \umlnote[geometry=|-|, #1]{#2}{#3}%
+}%
+\newcommand{\umlHVHnote}[3][]{%
+ \pgfkeys{/tikzuml/note/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlHVHnote, forbidden option geometry}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/note/.cd, #1}%
+ \umlnote[geometry=-|-, #1]{#2}{#3}%
+}%
+%
+% define a uml association class (command)
+% args : name of the class
+% attributes of the class
+% operations of the class
+% optional : x,y: coordinates of the class
+% width: width of the class node
+% type: type of of class (class, interface, typedef, enum)
+% template: template parameters
+% name: name of the class node
+% geometry: geometry of the line
+% weight: barycentric weight of the middle part when geometry is a 3-line
+% arm: length of first part when geometry id a 3-line
+% anchor1, anchor2: src/dest anchors on linked classes
+% style: style of the association class (association, aggregation, composition, inherit, ...)
+% draw, fill, fill template, text: colors
+% style: to manage every default TikZ option
+% no coords: to tell that the class position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlassocclass}[5][]{%
+ \pgfkeys{/tikzuml/assocclass/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX,
+ width/.initial=\tikzumlClassDefaultWidth, type/.initial=\tikzumlClassDefaultType, style/.style={},%
+ template/.initial={}, name/.initial=tikzumlEmpty, geometry/.initial=\tikzumlRelationDefaultGeometry,%
+ weight/.initial=\tikzumlRelationDefaultWeight, arm/.initial=auto,%
+ anchor1/.initial=tikzumlEmpty, anchor2/.initial=tikzumlEmpty,%
+ draw/.initial=\tikzumlDefaultDrawColor,%
+ fill template/.initial=\tikzumlClassTemplateFillColorDefaultFillColor,%
+ fill/.initial=\tikzumlClassDefaultFillColor,%
+ text/.initial=\tikzumlDefaultTextColor,%
+ no coords/.is if=tikzumlassocclassWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/assocclass/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/assocclass/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/assocclass/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlassocclass, invalid option \keyname}%
+ }%
+ }%
+ %
+ \pgfkeys{/tikzuml/assocclass/.cd,#1}%
+ \pgfkeys{/tikzuml/assocclass/.cd, x/.get=\tikzumlAssocClassX, y/.get=\tikzumlAssocClassY,%
+ width/.get=\tikzumlAssocClassMinimumWidth, type/.get=\tikzumlAssocClassTypeTmp,%
+ template/.get=\tikzumlAssocClassTemplateParam,%
+ name/.get=\tikzumlAssocClassName, geometry/.get=\tikzumlAssocClassGeometry,%
+ weight/.get=\tikzumlAssocClassWeight, arm/.get=\tikzumlAssocClassArm,%
+ anchor1/.get=\tikzumlAssocClassSrcAnchor,%
+ anchor2/.get=\tikzumlAssocClassDestAnchor,%
+ draw/.get=\tikzumlAssocClassDrawColor, fill/.get=\tikzumlAssocClassFillColor,%
+ text/.get=\tikzumlAssocClassTextColor, fill template/.get=\tikzumlAssocClassTemplateFillColor%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlAssocClassTypeTmp}{class}\OR\equal{\tikzumlAssocClassTypeTmp}{abstract}}{%
+ \def\tikzumlAssocClassType{}%
+ }{%
+ \def\tikzumlAssocClassType{$\ll$\tikzumlAssocClassTypeTmp$\gg$ \\}%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlAssocClassTemplateParam}{}}{%
+ \def\tikzumlAssocClassVPadding{}%
+ \def\tikzumlAssocClassHPadding{}%
+ }{%
+ \def\tikzumlAssocClassVPadding{\vspace{0.1em} \\}%
+ \def\tikzumlAssocClassHPadding{\hspace{0.5ex} $ $}%
+ }%
+ %
+ \def\tikzumlAssocClassName{#2}%
+ \def\tikzumlAssocClassRelationName{#3}%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlAssocClassNodeName{\tikzumlAssocClassName}}\x%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlAssocClassRelationNodeName{\tikzumlAssocClassRelationName}}\x%
+ %
+ \ifthenelse{\equal{\tikzumlAssocClassName}{tikzumlEmpty}}{}{%
+ \def\tikzumlAssocClassNodeName{\tikzumlAssocClassName}%
+ }%
+ %
+ \StrSubstitute{\tikzumlAssocClassNodeName}{:}{@COLON@}[\tikzumlAssocClassNodeName]%
+ \StrSubstitute{\tikzumlAssocClassNodeName}{\_}{@UNDERSCORE@}[\tikzumlAssocClassNodeName]%
+ %
+ \ifthenelse{\equal{\tikzumlAssocClassTypeTmp}{abstract}}{%
+ \let\tikzumlAssocClassNameOld\tikzumlAssocClassName%
+ \def\tikzumlAssocClassName{{\it \tikzumlAssocClassNameOld}}%
+ }{}%
+ %
+ \def\tikzumlAssocClassPos{\tikzumlAssocClassX,\tikzumlAssocClassY}%
+ \def\tikzumlAssocClassAttributes{#4}%
+ \def\tikzumlAssocClassOperations{#5}%
+ %
+ % def anchors macros
+ \ifthenelse{\equal{\tikzumlAssocClassSrcAnchor}{tikzumlEmpty}}{%
+ \def\tikzumlAssocClassSrcAnchor{}%
+ }{%
+ \let\tikzumlAssocClassSrcAnchorold\tikzumlAssocClassSrcAnchor%
+ \def\tikzumlAssocClassSrcAnchor{.\tikzumlAssocClassSrcAnchorold}%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlAssocClassDestAnchor}{tikzumlEmpty}}{%
+ \def\tikzumlAssocClassDestAnchor{}%
+ }{%
+ \let\tikzumlAssocClassDestAnchorold\tikzumlAssocClassDestAnchor%
+ \def\tikzumlAssocClassDestAnchor{.\tikzumlAssocClassDestAnchorold}%
+ }%
+ %
+ \iftikzumlassocclassWithoutCoords%
+ \node[tikzuml class style, draw=\tikzumlAssocClassDrawColor, fill=\tikzumlAssocClassFillColor, text=\tikzumlAssocClassTextColor, font=\tikzumlDefaultFont, minimum width=\tikzumlAssocClassMinimumWidth, /tikzuml/assocclass/style] (\tikzumlAssocClassNodeName) {\begin{tabular}{c}\tikzumlAssocClassVPadding \tikzumlAssocClassType \tikzumlAssocClassHPadding \textbf{\tikzumlAssocClassName} \tikzumlAssocClassHPadding \end{tabular}%
+ \nodepart{second}%
+ \begin{tabular}{l}%
+ \tikzumlAssocClassAttributes%
+ \end{tabular}%
+ \nodepart{third}%
+ \begin{tabular}{l}%
+ \tikzumlAssocClassOperations%
+ \end{tabular}%
+ };%
+ \else%
+ \node[tikzuml class style, draw=\tikzumlAssocClassDrawColor, fill=\tikzumlAssocClassFillColor, text=\tikzumlAssocClassTextColor, font=\tikzumlDefaultFont, minimum width=\tikzumlAssocClassMinimumWidth, /tikzuml/assocclass/style] (\tikzumlAssocClassNodeName) at (\tikzumlAssocClassPos) {\begin{tabular}{c}\tikzumlAssocClassVPadding \tikzumlAssocClassType \tikzumlAssocClassHPadding \textbf{\tikzumlAssocClassName} \tikzumlAssocClassHPadding \end{tabular}%
+ \nodepart{second}%
+ \begin{tabular}{l}%
+ \tikzumlAssocClassAttributes%
+ \end{tabular}%
+ \nodepart{third}%
+ \begin{tabular}{l}%
+ \tikzumlAssocClassOperations%
+ \end{tabular}%
+ };%
+ \fi%
+ %
+ \ifthenelse{\equal{\tikzumlAssocClassTemplateParam}{}}{}{%
+ \draw (\tikzumlAssocClassNodeName.north east) node[tikzuml template style, name=\tikzumlAssocClassNodeName-template, draw=\tikzumlAssocClassDrawColor, fill=\tikzumlAssocClassTemplateFillColor, text=\tikzumlAssocClassTextColor, font=\tikzumlDefaultFont] {\tikzumlAssocClassTemplateParam};%
+ }%
+ %
+ \pgfmathsetmacro{\tikzumlAssocClassWeightT}{1.0-\tikzumlAssocClassWeight}
+ \node (\tikzumlAssocClassNodeName-middle) at (barycentric cs:\tikzumlAssocClassNodeName=\tikzumlAssocClassWeight,\tikzumlAssocClassRelationNodeName=\tikzumlAssocClassWeightT) {};%
+ %
+ \ifthenelse{\equal{\tikzumlAssocClassGeometry}{--}\OR\equal{\tikzumlAssocClassGeometry}{-|}\OR\equal{\tikzumlAssocClassGeometry}{|-}}{%
+ \edef\tikzumlassocclasspath{\tikzumlAssocClassGeometry}
+ }{%
+ \ifthenelse{\equal{\tikzumlAssocClassGeometry}{-|-}}{%
+ \ifthenelse{\equal{\tikzumlAssocClassArm}{auto}}{%
+ \edef\tikzumlassocclasspath{-- (\tikzumlAssocClassNodeName\tikzumlAssocClassSrcAnchor -| \tikzumlAssocClassNodeName-middle.center) -- (\tikzumlAssocClassNodeName-middle.center) -- (\tikzumlAssocClassNodeName-middle.center |- \tikzumlAssocClassRelationNodeName\tikzumlAssocClassDestAnchor) --}%
+ }{%
+ \draw (\tikzumlAssocClassNodeName\tikzumlAssocClassSrcAnchor)+(\tikzumlAssocClassArm,0) node[name=\tikzumlAssocClassNodeName-tmp] {};
+ \edef\tikzumlnotepath{-- (\tikzumlAssocClassNodeName-tmp.center) |-}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlAssocClassGeometry}{|-|}}{%
+ \ifthenelse{\equal{\tikzumlAssocClassArm}{auto}}{%
+ \edef\tikzumlassocclasspath{-- (\tikzumlAssocClassNodeName\tikzumlAssocClassSrcAnchor |- \tikzumlAssocClassNodeName-middle.center) -- (\tikzumlAssocClassNodeName-middle.center) -- (\tikzumlAssocClassNodeName-middle.center -| \tikzumlAssocClassRelationNodeName\tikzumlAssocClassDestAnchor) --}%
+ }{%
+ \draw (\tikzumlAssocClassNodeName\tikzumlAssocClassSrcAnchor)+(0,\tikzumlAssocClassArm) node[name=\tikzumlAssocClassNodeName-tmp] {};
+ \edef\tikzumlassocclasspath{-- (\thetikzumlAssocClassNodeName-tmp.center) -|}%
+ }%
+
+ }{%
+ \errmessage{TIKZUML ERROR : Unknown geometry value !!! It should be in the following list : --, |-, -|, |-|, -|-}%
+ }%
+ }%
+ }%
+ %
+ \begin{pgfonlayer}{connections}%
+ \draw[dashed] (\tikzumlAssocClassNodeName\tikzumlAssocClassSrcAnchor) \tikzumlassocclasspath (\tikzumlAssocClassRelationNodeName\tikzumlAssocClassDestAnchor);%
+ \end{pgfonlayer}%
+ %
+ % add to fit
+ \ifnum\c@tikzumlPackageLevel>0%
+ \edef\tikzumlPackageFitOld{\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname}%
+ \ifthenelse{\equal{\tikzumlAssocClassTemplateParam}{}}{%
+ \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{\tikzumlPackageFitOld (\tikzumlAssocClassNodeName)(\tikzumlAssocClassNodeName-middle)}%
+ }{%
+ \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{\tikzumlPackageFitOld (\tikzumlAssocClassNodeName) (\tikzumlAssocClassNodeName-template)(\tikzumlAssocClassNodeName-middle)}%
+ }%
+ \stepcounter{tikzumlPackageClassNum}%
+ \fi%
+}%
+%
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% use case diagrams %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+\tikzstyle{tikzuml usecase style}=[ellipse, text centered]%
+\tikzstyle{tikzuml actor style}=[ellipse, inner sep=0, outer sep=0]%
+%
+\newcounter{tikzumlSystemUseCaseNum}%
+\newcounter{tikzumlSystemLevel}%
+\newcounter{tikzumlUseCaseNum}%
+\newcounter{tikzumlActorNum}%
+%
+\newif\iftikzumlusecaseWithoutCoords%
+\newif\iftikzumlactorWithoutCoords%
+%
+% define a system
+% arg : name
+% optional : x, y: coordinates of the system
+% draw, fill, text: colors
+\newenvironment{umlsystem}[2][]{%
+ \gdef\tikzumlSystemFit{}%
+ \def\tikzumlSystemName{#2}%
+ \setcounter{tikzumlSystemUseCaseNum}{0}%
+ %
+ \pgfkeys{/tikzuml/system/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX,%
+ draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlSystemDefaultFillColor,%
+ text/.initial=\tikzumlDefaultTextColor,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \errmessage{TIKZUML ERROR : in umlsystem, invalid option \keyname}%
+ }%
+ }%
+ %
+ \pgfkeys{/tikzuml/system/.cd, #1}%
+ \pgfkeys{/tikzuml/system/.cd, x/.get=\tikzumlSystemXShift, y/.get=\tikzumlSystemYShift,%
+ draw/.get=\tikzumlSystemDrawColor, fill/.get=\tikzumlSystemFillColor,%
+ text/.get=\tikzumlSystemTextColor}%
+ %
+ \stepcounter{tikzumlSystemLevel}%
+ %
+ \begin{scope}[xshift=\tikzumlSystemXShift cm, yshift=\tikzumlSystemYShift cm]%
+}{%
+ \addtocounter{tikzumlSystemLevel}{-1}%
+ % if contains no usecase, one define a fictive node to enable the fit option
+ \ifnum\c@tikzumlSystemUseCaseNum=0%
+ \node[inner xsep=10ex, inner ysep=1em] (\tikzumlSystemName-root) at (0,0) {};%
+ \xdef\tikzumlSystemFit{(\tikzumlSystemName-root)}%
+ \fi%
+ %
+ \begin{pgfonlayer}{background}%
+ \node[inner ysep=1em, inner xsep=2ex, fit = \tikzumlSystemFit] (\tikzumlSystemName-tmp) {};%
+ \node[text=\tikzumlSystemTextColor, font=\tikzumlDefaultFont] (\tikzumlSystemName-caption-tmp) at (\tikzumlSystemName-tmp.north) {\tikzumlSystemName};%
+ \node[draw=\tikzumlSystemDrawColor, fill=\tikzumlSystemFillColor, text=\tikzumlSystemTextColor, font=\tikzumlDefaultFont, inner ysep=1em, inner xsep=2ex, fit = (\tikzumlSystemName-tmp) (\tikzumlSystemName-caption-tmp)] (\tikzumlSystemName) {};%
+ \node[text=\tikzumlSystemTextColor, font=\tikzumlDefaultFont] (\tikzumlSystemName-caption) at (\tikzumlSystemName-caption-tmp.north) {\tikzumlSystemName};%
+ \end{pgfonlayer}%
+ \end{scope}%
+ %
+}%
+%
+% define a use case
+% arg : label of the use case
+% optional : x, y: coordinates of the use case
+% name: name of the node
+% width: node width
+% draw, fill, text: colors
+% style: to manage every default TikZ option
+% no coords: to tell that the use case position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlusecase}[2][]{%
+ \stepcounter{tikzumlUseCaseNum}%
+ \pgfkeys{/tikzuml/usecase/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=auto,%
+ name/.initial=usecase-\thetikzumlUseCaseNum,%
+ draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlUseCaseDefaultFillColor,%
+ text/.initial=\tikzumlDefaultTextColor, style/.style={},%
+ no coords/.is if=tikzumlusecaseWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/usecase/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/usecase/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/usecase/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlusecase, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/usecase/.cd, #1}%
+ \pgfkeys{/tikzuml/usecase/.cd, x/.get=\tikzumlUseCaseX, y/.get=\tikzumlUseCaseY, width/.get=\tikzumlUseCaseTextWidth,%
+ name/.get=\tikzumlUseCaseName,%
+ draw/.get=\tikzumlUseCaseDrawColor, fill/.get=\tikzumlUseCaseFillColor,%
+ text/.get=\tikzumlUseCaseTextColor%
+ }%
+ %
+ \def\tikzumlUseCaseText{#2}%
+ %
+ \def\tikzumlUseCasePos{\tikzumlUseCaseX,\tikzumlUseCaseY}%
+ %
+ \ifthenelse{\equal{\tikzumlUseCaseTextWidth}{auto}}{%
+ \iftikzumlusecaseWithoutCoords%
+ \node[tikzuml usecase style, draw=\tikzumlUseCaseDrawColor, fill=\tikzumlUseCaseFillColor, text=\tikzumlUseCaseTextColor, font=\tikzumlDefaultFont, /tikzuml/usecase/style] (\tikzumlUseCaseName) {\tikzumlUseCaseText};%
+ \else%
+ \node[tikzuml usecase style, draw=\tikzumlUseCaseDrawColor, fill=\tikzumlUseCaseFillColor, text=\tikzumlUseCaseTextColor, font=\tikzumlDefaultFont, /tikzuml/usecase/style] (\tikzumlUseCaseName) at (\tikzumlUseCasePos) {\tikzumlUseCaseText};%
+ \fi%
+ }{%
+ \iftikzumlusecaseWithoutCoords%
+ \node[tikzuml usecase style, draw=\tikzumlUseCaseDrawColor, fill=\tikzumlUseCaseFillColor, text=\tikzumlUseCaseTextColor, font=\tikzumlDefaultFont, text width=\tikzumlUseCaseTextWidth, /tikzuml/usecase/style] (\tikzumlUseCaseName) {\tikzumlUseCaseText};%
+ \else%
+ \node[tikzuml usecase style, draw=\tikzumlUseCaseDrawColor, fill=\tikzumlUseCaseFillColor, text=\tikzumlUseCaseTextColor, font=\tikzumlDefaultFont, text width=\tikzumlUseCaseTextWidth, /tikzuml/usecase/style] (\tikzumlUseCaseName) at (\tikzumlUseCasePos) {\tikzumlUseCaseText};%
+ \fi%
+ }%
+ %
+ % add to fit
+ \ifnum\c@tikzumlSystemLevel>0%
+ \let\tikzumlSystemFitOld\tikzumlSystemFit%
+ \xdef\tikzumlSystemFit{\tikzumlSystemFitOld (\tikzumlUseCaseName)}%
+ \stepcounter{tikzumlSystemUseCaseNum}%
+ \fi%
+}%
+%
+% define the actor symbol
+% optional : global tikzpicture styles
+\newcommand{\picturedactor}[1]{%
+ \pgfkeys{/tikzuml/picactor/.cd, scale/.initial=1, .unknown/.code={}}%
+ \pgfkeys{/tikzuml/picactor/.cd,#1}%
+ \pgfkeys{/tikzuml/picactor/.cd, scale/.get=\tikzumlPicturedActorScale}%
+ %
+ \begin{tikzpicture}[#1]%
+ \coordinate (head) at (0,4ex);%
+ \coordinate (left-hand) at (-2ex,2ex);%
+ \coordinate (right-hand) at (2ex,2ex);%
+ \coordinate (left-foot) at (-2ex,-2ex);%
+ \coordinate (right-foot) at (2ex,-2ex);%
+ \coordinate (empty) at (0,-3ex);%
+ \draw (empty) (0,0) -- (head);%
+ \draw (left-hand) -- (right-hand);%
+ \draw (0,0) -- (left-foot) (0,0) -- (right-foot);%
+ \node[fill, draw, circle, inner sep=\tikzumlPicturedActorScale*0.3333ex, minimum size=\tikzumlPicturedActorScale*2ex, anchor=base] at (head) {};%
+ \end{tikzpicture}%
+}%
+%
+% define an actor
+% arg : var name
+% optional : x, y: coordinates of the actor
+% scale: scale factor of the actor symbol
+% below: distance between the actor symbol and its name below
+% draw, text: colors
+% style: to manage every default TikZ option
+% no coords: to tell that the actor position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlactor}[2][]{%
+ \stepcounter{tikzumlActorNum}%
+ \pgfkeys{/tikzuml/actor/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, scale/.initial=1, below/.initial=\tikzumlActorDefaultBelow,%
+ draw/.initial=\tikzumlDefaultDrawColor, text/.initial=\tikzumlDefaultTextColor,%
+ style/.style={},%
+ no coords/.is if=tikzumlactorWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/actor/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/actor/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/actor/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlactor, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/actor/.cd, #1}%
+ \pgfkeys{/tikzuml/actor/.cd,%
+ x/.get=\tikzumlActorX, y/.get=\tikzumlActorY, scale/.get=\tikzumlActorScale,%
+ below/.get=\tikzumlActorBelow,%
+ draw/.get=\tikzumlActorDrawColor, text/.get=\tikzumlActorTextColor}%
+ %
+ \def\tikzumlActorName{#2}%
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlActorNodeName{\tikzumlActorName}}\x%
+ %
+ \def\tikzumlActorPos{\tikzumlActorX,\tikzumlActorY}%
+ %
+ \iftikzumlactorWithoutCoords%
+ \node[tikzuml actor style, text=\tikzumlActorTextColor, font=\tikzumlDefaultFont, /tikzuml/actor/style] (\tikzumlActorNodeName) {\picturedactor{scale=\tikzumlActorScale, fill=white, draw=\tikzumlActorDrawColor, thick}};%
+ \else%
+ \node[tikzuml actor style, text=\tikzumlActorTextColor, font=\tikzumlDefaultFont, /tikzuml/actor/style] (\tikzumlActorNodeName) at (\tikzumlActorPos) {\picturedactor{scale=\tikzumlActorScale, fill=white, draw=\tikzumlActorDrawColor, thick}};%
+ \fi%
+ \node[text=\tikzumlActorTextColor, font=\tikzumlDefaultFont, below=\tikzumlActorScale*\tikzumlActorBelow] at (\tikzumlActorNodeName) {\tikzumlActorName};%
+ %
+}%
+
+% shortcuts for include and extend relation
+\newcommand{\umlinclude}[3][]{%
+ \pgfkeys{/tikzuml/includerelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlinclude, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlinclude, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/includerelation/.cd, #1}%
+ \umlrelation[stereo=include, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+\newcommand{\umlextend}[3][]{%
+ \pgfkeys{/tikzuml/extendrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlextend, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlextend, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/extendrelation/.cd, #1}%
+ \umlrelation[stereo=extend, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlHVinclude}[3][]{%
+ \pgfkeys{/tikzuml/includerelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlHVinclude, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlHVinclude, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/includerelation/.cd, #1}%
+ \umlrelation[geometry=-|, stereo=include, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+\newcommand{\umlHVextend}[3][]{%
+ \pgfkeys{/tikzuml/extendrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlHVextend, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlHVextend, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/extendrelation/.cd, #1}%
+ \umlrelation[geometry=-|, stereo=extend, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlVHinclude}[3][]{%
+ \pgfkeys{/tikzuml/includerelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlVHinclude, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlVHinclude, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/includerelation/.cd, #1}%
+ \umlrelation[geometry=|-, stereo=include, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+\newcommand{\umlVHextend}[3][]{%
+ \pgfkeys{/tikzuml/extendrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR :in umlVHextend, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlVHextend, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/extendrelation/.cd, #1}%
+ \umlrelation[geometry=|-, stereo=extend, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlHVHinclude}[3][]{%
+ \pgfkeys{/tikzuml/includerelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlHVHinclude, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlHVHinclude, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/includerelation/.cd, #1}%
+ \umlrelation[geometry=-|-, stereo=include, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+\newcommand{\umlHVHextend}[3][]{%
+ \pgfkeys{/tikzuml/extendrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlHVHextend, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlHVHextend, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/extendrelation/.cd, #1}%
+ \umlrelation[geometry=-|-, stereo=extend, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlVHVinclude}[3][]{%
+ \pgfkeys{/tikzuml/includerelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlVHVinclude, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlVHVinclude, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/includerelation/.cd, #1}%
+ \umlrelation[geometry=|-|, stereo=include, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+\newcommand{\umlVHVextend}[3][]{%
+ \pgfkeys{/tikzuml/extendrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlVHVextend, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlVHVextend, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/extendrelation/.cd, #1}%
+ \umlrelation[geometry=|-|, stereo=extend, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlCNinclude}[4][]{%
+ \pgfkeys{/tikzuml/includerelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlCNinclude, forbidden option stereo}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/includerelation/.cd, #1}%
+ \umlCNrelation[stereo=include, style={tikzuml dependency style}, #1]{#2}{#3}{#4}%
+}%
+\newcommand{\umlCNextend}[4][]{%
+ \pgfkeys{/tikzuml/extendrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlCNextend, forbidden option stereo}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/extendrelation/.cd, #1}%
+ \umlCNrelation[stereo=extend, style={tikzuml dependency style}, #1]{#2}{#3}{#4}%
+}%
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% state diagrams %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+\tikzstyle{tikzuml state style}=[rectangle split, rectangle split parts=2, rounded corners, inner xsep=1.5ex]%
+\tikzstyle{tikzuml transition style}=[color=\tikzumlDefaultDrawColor, rounded corners, -angle 45]%
+%
+\newcounter{tikzumlStateJoinNum}%
+\newcounter{tikzumlStateDecisionNum}%
+\newcounter{tikzumlStateInitialNum}%
+\newcounter{tikzumlStateFinalNum}%
+\newcounter{tikzumlStateEnterNum}%
+\newcounter{tikzumlStateExitNum}%
+\newcounter{tikzumlStateEndNum}%
+\newcounter{tikzumlStateHistoryNum}%
+\newcounter{tikzumlStateDeepHistoryNum}%
+\newcounter{tikzumlStateLevel}%
+\newcounter{tikzumlStateSubStateNum}%
+\newcounter{tikzumlStateText}%
+%
+\newif\iftikzumlstatejoinWithoutCoords%
+\newif\iftikzumlstatedecisionWithoutCoords%
+\newif\iftikzumlstateinitialWithoutCoords%
+\newif\iftikzumlstatefinalWithoutCoords%
+\newif\iftikzumlstateenterWithoutCoords%
+\newif\iftikzumlstateexitWithoutCoords%
+\newif\iftikzumlstateendWithoutCoords%
+\newif\iftikzumlstatehistoryWithoutCoords%
+\newif\iftikzumlstatedeephistoryWithoutCoords%
+\newif\iftikzumlstateWithoutCoords%
+%
+% define a uml join state
+% args : name of the state
+% optional : x,y: coordinates of the state
+% width: width of the state node
+% name: name of the state node
+% color: color of the join symbol
+% style: to manage every default TikZ option
+% no coords: to tell that the state position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlstatejoin}[1][]{%
+ \pgfkeys{/tikzuml/statejoin/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateJoinDefaultWidth,%
+ name/.initial=statejoin-\thetikzumlStateJoinNum,%
+ color/.initial=\tikzumlDefaultDrawColor, style/.style={},%
+ no coords/.is if=tikzumlstatejoinWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/statejoin/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/statejoin/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/statejoin/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlstatejoin, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/statejoin/.cd, #1}%
+ \pgfkeys{/tikzuml/statejoin/.cd, x/.get=\tikzumlStateJoinX, y/.get=\tikzumlStateJoinY, width/.get=\tikzumlStateJoinMinimumWidth,%
+ name/.get=\tikzumlStateJoinName, color/.get=\tikzumlStateJoinColor%
+ }%
+ %
+ \def\tikzumlStateJoinPos{\tikzumlStateJoinX,\tikzumlStateJoinY}%
+ %
+ \iftikzumlstatejoinWithoutCoords%
+ \node[circle, minimum size=\tikzumlStateJoinMinimumWidth, draw=\tikzumlStateJoinColor, fill=\tikzumlStateJoinColor, /tikzuml/statejoin/style] (\tikzumlStateJoinName) {};%
+ \else%
+ \node[circle, minimum size=\tikzumlStateJoinMinimumWidth, draw=\tikzumlStateJoinColor, fill=\tikzumlStateJoinColor, /tikzuml/statejoin/style] (\tikzumlStateJoinName) at (\tikzumlStateJoinPos) {};%
+ \fi%
+ %
+ % add to fit
+ \ifnum\c@tikzumlStateLevel>0%
+ \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlStateJoinName)}%
+ \stepcounter{tikzumlStateSubStateNum}%
+ \fi%
+ \stepcounter{tikzumlStateJoinNum}%
+}%
+%
+% define a uml decision state
+% args : name of the state
+% optional : x,y: coordinates of the state
+% width: width of the state node
+% name: name of the state node
+% color: color of the join symbol
+% style: to manage every default TikZ option
+% no coords: to tell that the state position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlstatedecision}[1][]{%
+ \pgfkeys{/tikzuml/statedecision/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateDecisionDefaultWidth,%
+ name/.initial=statedecision-\thetikzumlStateDecisionNum,%
+ color/.initial=\tikzumlDefaultDrawColor, style/.style={},%
+ no coords/.is if=tikzumlstatedecisionWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/statedecision/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/statedecision/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/statedecision/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlstatedecision, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/statedecision/.cd, #1}%
+ \pgfkeys{/tikzuml/statedecision/.cd, x/.get=\tikzumlStateDecisionX, y/.get=\tikzumlStateDecisionY, width/.get=\tikzumlStateDecisionMinimumWidth,%
+ name/.get=\tikzumlStateDecisionName, color/.get=\tikzumlStateDecisionColor%
+ }%
+ %
+ \def\tikzumlStateDecisionPos{\tikzumlStateDecisionX,\tikzumlStateDecisionY}%
+ %
+ \iftikzumlstatedecisionWithoutCoords%
+ \node[rectangle, rotate=45, minimum size=\tikzumlStateDecisionMinimumWidth, draw=\tikzumlStateDecisionColor, /tikzuml/statedecision/style] (\tikzumlStateDecisionName) {};%
+ \else%
+ \node[rectangle, rotate=45, minimum size=\tikzumlStateDecisionMinimumWidth, draw=\tikzumlStateDecisionColor, /tikzuml/statedecision/style] (\tikzumlStateDecisionName) at (\tikzumlStateDecisionPos) {};%
+ \fi%
+ %
+ % add to fit
+ \ifnum\c@tikzumlStateLevel>0%
+ \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlStateDecisionName)}%
+ \stepcounter{tikzumlStateSubStateNum}%
+ \fi%
+ \stepcounter{tikzumlStateDecisionNum}%
+}%
+%
+% define a uml initial state
+% args : name of the state
+% optional : x,y: coordinates of the state
+% width: width of the state node
+% name: name of the state node
+% entry, do, exit: entry/do/exit action of the state
+% color: color of the join symbol
+% style: to manage every default TikZ option
+% no coords: to tell that the state position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlstateinitial}[1][]{%
+ \pgfkeys{/tikzuml/stateinitial/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateInitialDefaultWidth,%
+ name/.initial=stateinitial-\thetikzumlStateInitialNum,%
+ color/.initial=\tikzumlDefaultDrawColor, style/.style={},%
+ no coords/.is if=tikzumlstateinitialWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/stateinitial/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/stateinitial/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/stateinitial/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlstateinitial, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/stateinitial/.cd, #1}%
+ \pgfkeys{/tikzuml/stateinitial/.cd, x/.get=\tikzumlStateInitialX, y/.get=\tikzumlStateInitialY, width/.get=\tikzumlStateInitialMinimumWidth,%
+ name/.get=\tikzumlStateInitialName, color/.get=\tikzumlStateInitialColor%
+ }%
+ %
+ \def\tikzumlStateInitialPos{\tikzumlStateInitialX,\tikzumlStateInitialY}%
+ %
+ \iftikzumlstateinitialWithoutCoords%
+ \node[circle, minimum size=\tikzumlStateInitialMinimumWidth, fill=\tikzumlStateInitialColor, /tikzuml/stateinitial/style] (\tikzumlStateInitialName) {};%
+ \else%
+ \node[circle, minimum size=\tikzumlStateInitialMinimumWidth, fill=\tikzumlStateInitialColor, /tikzuml/stateinitial/style] (\tikzumlStateInitialName) at (\tikzumlStateInitialPos) {};%
+ \fi%
+ %
+ % add to fit
+ \ifnum\c@tikzumlStateLevel>0%
+ \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlStateInitialName)}%
+ \stepcounter{tikzumlStateSubStateNum}%
+ \fi%
+ \stepcounter{tikzumlStateInitialNum}%
+}%
+%
+% define a uml final state
+% args : name of the state
+% optional : x,y: coordinates of the state
+% width: width of the state node
+% name: name of the state node
+% color: color of the join symbol
+% style: to manage every default TikZ option
+% no coords: to tell that the state position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlstatefinal}[1][]{%
+ \pgfkeys{/tikzuml/statefinal/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateFinalDefaultWidth,%
+ name/.initial=statefinal-\thetikzumlStateFinalNum,%
+ color/.initial=\tikzumlDefaultDrawColor, style/.style={},%
+ no coords/.is if=tikzumlstatefinalWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/statefinal/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/statefinal/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/statefinal/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlstatefinal, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/statefinal/.cd, #1}%
+ \pgfkeys{/tikzuml/statefinal/.cd, x/.get=\tikzumlStateFinalX, y/.get=\tikzumlStateFinalY, width/.get=\tikzumlStateFinalMinimumWidth,%
+ name/.get=\tikzumlStateFinalName, color/.get=\tikzumlStateFinalColor%
+ }%
+ %
+ \def\tikzumlStateFinalPos{\tikzumlStateFinalX,\tikzumlStateFinalY}%
+ %
+ \iftikzumlstatefinalWithoutCoords%
+ \node[circle, minimum size=\tikzumlStateFinalMinimumWidth, draw=\tikzumlStateFinalColor, fill=\tikzumlStateFinalColor, double, double distance=0.1cm, /tikzuml/statefinal/style] (\tikzumlStateFinalName) {};%
+ \else%
+ \node[circle, minimum size=\tikzumlStateFinalMinimumWidth, draw=\tikzumlStateFinalColor, fill=\tikzumlStateFinalColor, double, double distance=0.1cm, /tikzuml/statefinal/style] (\tikzumlStateFinalName) at (\tikzumlStateFinalPos) {};%
+ \fi%
+ %
+ % add to fit
+ \ifnum\c@tikzumlStateLevel>0%
+ \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlStateFinalName)}%
+ \stepcounter{tikzumlStateSubStateNum}%
+ \fi%
+ \stepcounter{tikzumlStateFinalNum}%
+}%
+%
+% define a uml enter state
+% args : name of the state
+% optional : x,y: coordinates of the state
+% width: width of the state node
+% name: name of the state node
+% color: color of the join symbol
+% style: to manage every default TikZ option
+% no coords: to tell that the state position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlstateenter}[1][]{%
+ \pgfkeys{/tikzuml/stateenter/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateEnterDefaultWidth,%
+ name/.initial=stateenter-\thetikzumlStateEnterNum,%
+ color/.initial=\tikzumlDefaultDrawColor, style/.style={},%
+ no coords/.is if=tikzumlstateenterWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/stateenter/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/stateenter/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/stateenter/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlstateenter, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/stateenter/.cd, #1}%
+ \pgfkeys{/tikzuml/stateenter/.cd, x/.get=\tikzumlStateEnterX, y/.get=\tikzumlStateEnterY, width/.get=\tikzumlStateEnterMinimumWidth,%
+ name/.get=\tikzumlStateEnterName, color/.get=\tikzumlStateEnterColor%
+ }%
+ %
+ \def\tikzumlStateEnterPos{\tikzumlStateEnterX,\tikzumlStateEnterY}%
+ %
+ \iftikzumlstateenterWithoutCoords%
+ \node[circle, minimum size=\tikzumlStateEnterMinimumWidth, draw=\tikzumlStateEnterColor, /tikzuml/stateenter/style] (\tikzumlStateEnterName) {};%
+ \else%
+ \node[circle, minimum size=\tikzumlStateEnterMinimumWidth, draw=\tikzumlStateEnterColor, /tikzuml/stateenter/style] (\tikzumlStateEnterName) at (\tikzumlStateEnterPos) {};%
+ \fi%
+ %
+ % add to fit
+ \ifnum\c@tikzumlStateLevel>0%
+ \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlStateEnterName)}%
+ \stepcounter{tikzumlStateSubStateNum}%
+ \fi%
+ \stepcounter{tikzumlStateEnterNum}%
+}%
+%
+% define a uml exit state
+% args : name of the state
+% optional : x,y: coordinates of the state
+% width: width of the state node
+% name: name of the state node
+% color: color of the join symbol
+% style: to manage every default TikZ option
+% no coords: to tell that the state position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlstateexit}[1][]{%
+ \pgfkeys{/tikzuml/stateexit/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateExitDefaultWidth,%
+ name/.initial=stateexit-\thetikzumlStateExitNum,%
+ color/.initial=\tikzumlDefaultDrawColor, style/.style={},%
+ no coords/.is if=tikzumlstateexitWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/stateexit/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/stateexit/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/stateexit/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlstateexit, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/stateexit/.cd, #1}%
+ \pgfkeys{/tikzuml/stateexit/.cd, x/.get=\tikzumlStateExitX, y/.get=\tikzumlStateExitY, width/.get=\tikzumlStateExitMinimumWidth,%
+ name/.get=\tikzumlStateExitName, color/.get=\tikzumlStateExitColor%
+ }%
+ %
+ \def\tikzumlStateExitPos{\tikzumlStateExitX,\tikzumlStateExitY}%
+ %
+ \iftikzumlstateexitWithoutCoords%
+ \node[circle, minimum size=\tikzumlStateExitMinimumWidth, draw=\tikzumlStateExitColor, /tikzuml/stateexit/style] (\tikzumlStateExitName) {};%
+ \else%
+ \node[circle, minimum size=\tikzumlStateExitMinimumWidth, draw=\tikzumlStateExitColor, /tikzuml/stateexit/style] (\tikzumlStateExitName) at (\tikzumlStateExitPos) {};%
+ \fi%
+ \draw[draw=\tikzumlStateExitColor] (\tikzumlStateExitName.north east) -- (\tikzumlStateExitName.south west) (\tikzumlStateExitName.north west) -- (\tikzumlStateExitName.south east);
+ %
+ % add to fit
+ \ifnum\c@tikzumlStateLevel>0%
+ \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlStateExitName)}%
+ \stepcounter{tikzumlStateSubStateNum}%
+ \fi%
+ \stepcounter{tikzumlStateExitNum}%
+}%
+%
+% define a uml end state
+% args : name of the state
+% optional : x,y: coordinates of the state
+% width: width of the state node
+% name: name of the state node
+% color: color of the join symbol
+% style: to manage every default TikZ option
+% no coords: to tell that the state position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlstateend}[1][]{%
+ \pgfkeys{/tikzuml/stateend/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateEndDefaultWidth,%
+ name/.initial=stateend-\thetikzumlStateEndNum,%
+ color/.initial=\tikzumlDefaultDrawColor, style/.style={},%
+ no coords/.is if=tikzumlstateendWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/stateend/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/stateend/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/stateend/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlstateend, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/stateend/.cd, #1}%
+ \pgfkeys{/tikzuml/stateend/.cd, x/.get=\tikzumlStateEndX, y/.get=\tikzumlStateEndY, width/.get=\tikzumlStateEndMinimumWidth,%
+ name/.get=\tikzumlStateEndName, color/.get=\tikzumlStateEndColor%
+ }%
+ %
+ \def\tikzumlStateEndPos{\tikzumlStateEndX,\tikzumlStateEndY}%
+ %
+ \iftikzumlstateendWithoutCoords%
+ \node[circle, minimum size=\tikzumlStateEndMinimumWidth, /tikzuml/stateend/style] (\tikzumlStateEndName) {};%
+ \else%
+ \node[circle, minimum size=\tikzumlStateEndMinimumWidth, /tikzuml/stateend/style] (\tikzumlStateEndName) at (\tikzumlStateEndPos) {};%
+ \fi%
+ \draw[draw=\tikzumlStateEndColor] (\tikzumlStateEndName.north east) -- (\tikzumlStateEndName.south west) (\tikzumlStateEndName.north west) -- (\tikzumlStateEndName.south east);
+ %
+ % add to fit
+ \ifnum\c@tikzumlStateLevel>0%
+ \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlStateEndName)}%
+ \stepcounter{tikzumlStateSubStateNum}%
+ \fi%
+ \stepcounter{tikzumlStateEndNum}%
+}%
+%
+\newcommand{\picturedhistory}[1]{%
+ \begin{tikzpicture}[#1]%
+ \draw[thick] (-0.1cm,-0.15cm) -- (-0.1cm,0.15cm)
+ (-0.1cm,0) -- (0.1cm,0)
+ (0.1cm,-0.15cm) -- (0.1cm,0.15cm);%
+ \end{tikzpicture}%
+}%
+%
+% define a uml history state
+% args : name of the state
+% optional : x,y: coordinates of the state
+% width: width of the state node
+% name: name of the state node
+% color: color of the join symbol
+% style: to manage every default TikZ option
+% no coords: to tell that the state position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlstatehistory}[1][]{%
+ \pgfkeys{/tikzuml/statehistory/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateHistoryDefaultWidth,%
+ name/.initial=statehistory-\thetikzumlStateHistoryNum,%
+ color/.initial=\tikzumlDefaultDrawColor, style/.style={},%
+ no coords/.is if=tikzumlstatehistoryWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/statehistory/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/statehistory/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/statehistory/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlstatehistory, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/statehistory/.cd, #1}%
+ \pgfkeys{/tikzuml/statehistory/.cd, x/.get=\tikzumlStateHistoryX, y/.get=\tikzumlStateHistoryY, width/.get=\tikzumlStateHistoryMinimumWidth,%
+ name/.get=\tikzumlStateHistoryName, color/.get=\tikzumlStateHistoryColor%
+ }%
+ %
+ \def\tikzumlStateHistoryPos{\tikzumlStateHistoryX,\tikzumlStateHistoryY}%
+ %
+ \iftikzumlstatehistoryWithoutCoords%
+ \node[circle, minimum size=\tikzumlStateHistoryMinimumWidth, draw=\tikzumlStateHistoryColor, /tikzuml/statehistory/style] (\tikzumlStateHistoryName) {\picturedhistory{draw=\tikzumlStateHistoryColor}};%
+ \else%
+ \node[circle, minimum size=\tikzumlStateHistoryMinimumWidth, draw=\tikzumlStateHistoryColor, /tikzuml/statehistory/style] (\tikzumlStateHistoryName) at (\tikzumlStateHistoryPos) {\picturedhistory{draw=\tikzumlStateHistoryColor}};%
+ \fi%
+ %
+ % add to fit
+ \ifnum\c@tikzumlStateLevel>0%
+ \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlStateHistoryName)}%
+ \stepcounter{tikzumlStateSubStateNum}%
+ \fi%
+ \stepcounter{tikzumlStateHistoryNum}%
+}%
+%
+\newcommand{\pictureddeephistory}[1]{%
+ \begin{tikzpicture}[#1]%
+ \draw[thick] (-0.1cm,-0.15cm) -- (-0.1cm,0.15cm)
+ (-0.1cm,0) -- (0.1cm,0)
+ (0.1cm,-0.15cm) -- (0.1cm,0.15cm)
+ (0.23cm,0.19cm) -- (0.23cm,0.11cm)
+ (0.20cm,0.17cm) -- (0.26cm,0.13cm)
+ (0.20cm,0.13cm) -- (0.26cm,0.17cm);%
+ \end{tikzpicture}%
+}%
+%
+% define a uml deep-history state
+% args : name of the state
+% optional : x,y: coordinates of the state
+% width: width of the state node
+% name: name of the state node
+% color: color of the join symbol
+% style: to manage every default TikZ option
+% no coords: to tell that the state position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlstatedeephistory}[1][]{%
+ \pgfkeys{/tikzuml/statedeephistory/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateDeepHistoryDefaultWidth,%
+ name/.initial=statedeephistory-\thetikzumlStateDeepHistoryNum,%
+ color/.initial=\tikzumlDefaultDrawColor, style/.style={},%
+ no coords/.is if=tikzumlstatedeephistoryWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/statedeephistory/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/statedeephistory/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/statedeephistory/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlstatedeephistory, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/statedeephistory/.cd, #1}%
+ \pgfkeys{/tikzuml/statedeephistory/.cd, x/.get=\tikzumlStateDeepHistoryX, y/.get=\tikzumlStateDeepHistoryY, width/.get=\tikzumlStateDeepHistoryMinimumWidth,%
+ name/.get=\tikzumlStateDeepHistoryName, color/.get=\tikzumlStateDeepHistoryColor%
+ }%
+ %
+ \def\tikzumlStateDeepHistoryPos{\tikzumlStateDeepHistoryX,\tikzumlStateDeepHistoryY}%
+ %
+ \iftikzumlstatedeephistoryWithoutCoords%
+ \node[circle, minimum size=\tikzumlStateDeepHistoryMinimumWidth, draw=\tikzumlStateDeepHistoryColor, /tikzuml/statedeephistory/style] (\tikzumlStateDeepHistoryName) {\pictureddeephistory{draw=\tikzumlStateDeepHistoryColor}};%
+ \else%
+ \node[circle, minimum size=\tikzumlStateDeepHistoryMinimumWidth, draw=\tikzumlStateDeepHistoryColor, /tikzuml/statedeephistory/style] (\tikzumlStateDeepHistoryName) at (\tikzumlStateDeepHistoryPos) {\pictureddeephistory{draw=\tikzumlStateDeepHistoryColor}};%
+ \fi%
+ %
+ % add to fit
+ \ifnum\c@tikzumlStateLevel>0%
+ \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlStateDeepHistoryName)}%
+ \stepcounter{tikzumlStateSubStateNum}%
+ \fi%
+ \stepcounter{tikzumlStateDeepHistoryNum}%
+}%
+%
+% define a uml state
+% args : name of the state
+% content of the state
+% optional : x,y: coordinates of the state
+% width: width of the state node
+% name: name of the state node
+% entry, do, exit: entry/do/exit action of the state
+% draw, fill, text: colors
+% style: to manage every default TikZ option
+% no coords: to tell that the state position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newenvironment{umlstate}[2][]{%
+ \ifnum\thetikzumlStateLevel>0%
+ \let\tikzumlState@nameold\tikzumlState@fitname%
+ \let\tikzumlState@parentold\tikzumlState@parent%
+ \edef\tikzumlState@parent{\tikzumlState@parentold @@\tikzumlState@nameold}%
+ \else%
+ \def\tikzumlState@parent{}%
+ \fi%
+ %
+ \stepcounter{tikzumlStateLevel}%
+ %
+ \pgfkeys{/tikzuml/state/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateDefaultWidth,%
+ name/.initial={},%
+ entry/.initial={}, do/.initial={}, exit/.initial={},%
+ draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlStateDefaultFillColor,%
+ text/.initial=\tikzumlDefaultTextColor, style/.style={},%
+ no coords/.is if=tikzumlstateWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/state/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/state/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/state/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ % \errmessage{TIKZUML ERROR : in umlstate, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/state/.cd, #1}%
+ \pgfkeys{/tikzuml/state/.cd, x/.get=\tikzumlStateXShift, y/.get=\tikzumlStateYShift, width/.get=\tikzumlStateMinimumWidth, name/.get=\tikzumlStateName,%
+ entry/.get=\tikzumlStateEntry, do/.get=\tikzumlStateDo, exit/.get=\tikzumlStateExit,%
+ draw/.get=\tikzumlStateDrawColor, fill/.get=\tikzumlStateFillColor,%
+ text/.get=\tikzumlStateTextColor%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlStateName}{}}{%
+ \edef\tikzumlState@name{#2}%
+ }{%
+ \edef\tikzumlState@name{\tikzumlStateName}%
+ }%
+ %
+ \begingroup%
+ \def\_{@}\edef\x{\endgroup%
+ \def\noexpand\tikzumlState@fitname{\tikzumlState@name}}\x%
+ %
+ \let\tikzumlState@nodeNameold\tikzumlState@nodeName%
+ \def\tikzumlState@caption{#2}%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlState@nodeName{\tikzumlState@name}}\x%
+ %
+ \expandafter\gdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{}%
+ %
+ \setcounter{tikzumlStateSubStateNum}{0}%
+ \setcounter{tikzumlStateText}{0}%
+ %
+ \def\tikzumlStateText{tikzumlEmpty}%
+ \begin{scope}[xshift=\tikzumlStateXShift cm, yshift=\tikzumlStateYShift cm]%
+}{%
+ %
+ \def\tikzumlstaterootlabel{\phantom{\tikzumlState@nodeName}}%
+ %
+ \def\tikzumlstaterootinnerysep{0.5ex}%
+ \def\tikzumlstatebodyinnerysep{2ex}%
+ %
+ \ifthenelse{\equal{\tikzumlStateEntry}{}}{}{%
+ \ifnum\c@tikzumlStateText=0%
+ \def\tikzumlStateText{entry/\tikzumlStateEntry}%
+ \else%
+ \let\tikzumlStateTextOld\tikzumlStateText%
+ \ifthenelse{\equal{\tikzumlStateText}{tikzumlEmpty}}{%
+ \def\tikzumlStateText{entry/\tikzumlStateEntry}%
+ }{%
+ \expandafter\def\expandafter\tikzumlStateText\expandafter{\tikzumlStateTextOld \\ entry/\tikzumlStateEntry}%
+ }%
+ \fi%
+ \setcounter{tikzumlStateText}{1}%
+ \ifnum\c@tikzumlStateSubStateNum=0%
+ \def\tikzumlstatebodyinnerysep{0}%
+ \def\tikzumlstaterootinnerysep{0}%
+ \fi%
+ }%
+ \ifthenelse{\equal{\tikzumlStateDo}{}}{}{%
+ \ifnum\c@tikzumlStateText=0%
+ \def\tikzumlStateText{do/\tikzumlStateDo}%
+ \else%
+ \let\tikzumlStateTextOld\tikzumlStateText%
+ \ifthenelse{\equal{\tikzumlStateText}{tikzumlEmpty}}{%
+ \def\tikzumlStateText{do/\tikzumlStateDo}%
+ }{%
+ \expandafter\def\expandafter\tikzumlStateText\expandafter{\tikzumlStateTextOld \\ do/\tikzumlStateDo}%
+ }%
+ \fi%
+ \setcounter{tikzumlStateText}{1}%
+ \ifnum\c@tikzumlStateSubStateNum=0%
+ \def\tikzumlstatebodyinnerysep{0}%
+ \def\tikzumlstaterootinnerysep{0}%
+ \fi%
+ }%
+ \ifthenelse{\equal{\tikzumlStateExit}{}}{}{%
+ \ifnum\c@tikzumlStateText=0%
+ \def\tikzumlStateText{exit/\tikzumlStateExit}%
+ \else%
+ \let\tikzumlStateTextOld\tikzumlStateText%
+ \ifthenelse{\equal{\tikzumlStateText}{tikzumlEmpty}}{%
+ \def\tikzumlStateText{exit/\tikzumlStateExit}%
+ }{%
+ \expandafter\def\expandafter\tikzumlStateText\expandafter{\tikzumlStateTextOld \\ exit/\tikzumlStateExit}%
+ }%
+ \fi%
+ \setcounter{tikzumlStateText}{1}%
+ \ifnum\c@tikzumlStateSubStateNum=0%
+ \def\tikzumlstatebodyinnerysep{0}%
+ \def\tikzumlstaterootinnerysep{0}%
+ \fi%
+ }%
+ %
+ \addtocounter{tikzumlStateLevel}{-1}%
+ \begin{pgfonlayer}{state\thetikzumlStateLevel}%
+ %
+ % if contains nothing, one define a fictive node to enable the fit option
+ \ifnum\c@tikzumlStateSubStateNum=0%
+ \iftikzumlstateWithoutCoords%
+ \node[inner ysep=\tikzumlstaterootinnerysep, minimum width=\tikzumlStateMinimumWidth, /tikzuml/state/style] (\tikzumlState@nodeName-root) {\tikzumlstaterootlabel};%
+ \else%
+ \node[inner ysep=\tikzumlstaterootinnerysep, minimum width=\tikzumlStateMinimumWidth, /tikzuml/state/style] (\tikzumlState@nodeName-root) at (0,0) {\tikzumlstaterootlabel};%
+ \fi%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{(\tikzumlState@nodeName-root)}%
+ \fi%
+ %
+ \ifnum\c@tikzumlStateLevel>0%
+ \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent\endcsname{\tikzumlStateFitTmp (\tikzumlState@nodeName-body) (\tikzumlState@nodeName-caption)}%
+ \stepcounter{tikzumlStateSubStateNum}%
+ \fi%
+ %
+ \node[inner xsep=2ex, inner ysep=\tikzumlstatebodyinnerysep, fit = \csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname, /tikzuml/state/style ] (\tikzumlState@nodeName-body) {};%
+ \def\tikzumlState@orig{body}%
+ \ifnum\c@tikzumlStateText=1%
+ \node[above=0] (\tikzumlState@nodeName-texttmp) at (\tikzumlState@nodeName-\tikzumlState@orig.north) {\begin{tabular}{l}\tikzumlStateText \end{tabular}};%
+ \def\tikzumlState@orig{texttmp}%
+ \fi%
+ \node[above] (\tikzumlState@nodeName-captiontmp) at (\tikzumlState@nodeName-\tikzumlState@orig.north) {\tikzumlState@caption};%
+ \ifnum\c@tikzumlStateText=1%
+ \node[rounded corners, draw=\tikzumlStateDrawColor, fill=\tikzumlStateFillColor, name=\tikzumlState@nodeName, fit=(\tikzumlState@nodeName-body) (\tikzumlState@nodeName-texttmp) (\tikzumlState@nodeName-captiontmp)] {};%
+ \else%
+ \node[rounded corners, draw=\tikzumlStateDrawColor, fill=\tikzumlStateFillColor, name=\tikzumlState@nodeName, fit=(\tikzumlState@nodeName-body) (\tikzumlState@nodeName-captiontmp)] {};%
+ \fi%
+ \ifnum\c@tikzumlStateText=1%
+ \node (\tikzumlState@nodeName-text) at (\tikzumlState@nodeName-texttmp) {\begin{tabular}{l}\tikzumlStateText \end{tabular}};%
+ \fi%
+ \node (\tikzumlState@nodeName-caption) at (\tikzumlState@nodeName-captiontmp) {\tikzumlState@caption};%
+ \draw (\tikzumlState@nodeName-caption.south -| \tikzumlState@nodeName.north west) -- (\tikzumlState@nodeName-caption.south -| \tikzumlState@nodeName.north east);%
+ \end{pgfonlayer}%
+ \end{scope}%
+}%
+%
+% shortcut for empty state
+\newcommand{\umlbasicstate}[2][]{\begin{umlstate}[#1]{#2}\end{umlstate}}%
+%
+% command to add text in a state, to be used inside umlstate environment
+\newcommand{\umlstatetext}[1]{%
+ \def\tikzumlStateText{#1}%
+ \setcounter{tikzumlStateText}{1}%
+}%
+%
+% shortcuts for state transitions macros
+\newcommand{\umltrans}[3][]{%
+ \ifthenelse{\equal{#2}{#3}}{%
+ \umlrelation[style={tikzuml transition style}, recursive mode=transition, #1]{#2}{#3}%
+ }{%
+ \umlrelation[style={tikzuml transition style}, #1]{#2}{#3}%
+ }%
+}%
+\newcommand{\umlHVtrans}[3][]{\umlHVrelation[style={tikzuml transition style}, #1]{#2}{#3}}%
+\newcommand{\umlVHtrans}[3][]{\umlVHrelation[style={tikzuml transition style}, #1]{#2}{#3}}%
+\newcommand{\umlVHVtrans}[3][]{\umlVHVrelation[style={tikzuml transition style}, #1]{#2}{#3}}%
+\newcommand{\umlHVHtrans}[3][]{\umlHVHrelation[style={tikzuml transition style}, #1]{#2}{#3}}%
+\newcommand{\umlCNtrans}[4][]{\umlCNrelation[style={tikzuml transition style}, #1]{#2}{#3}{#4}}%
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% sequence diagrams %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+\tikzstyle{tikzuml synchron-msg style}=[color=\tikzumlDefaultDrawColor, -triangle 45]%
+\tikzstyle{tikzuml asynchron-msg style}=[color=\tikzumlDefaultDrawColor, -angle 45]%
+\tikzstyle{tikzuml return-msg style}=[color=\tikzumlDefaultDrawColor, dashed, -angle 45]%
+\tikzstyle{tikzuml call return style}=[color=\tikzumlDefaultDrawColor, dashed, -angle 45]%
+\tikzstyle{tikzuml activity style}=[inner xsep=1ex, inner ysep=1ex]%
+%
+\newcounter{tikzumlObjectNum}%
+\newcounter{tikzumlCallLevel}%
+\newcounter{tikzumlCallNum}%
+\newcounter{tikzumlFragmentLevel}%
+\newcounter{tikzumlFragmentLevelNum}%
+\newcounter{tikzumlFragmentNum}%
+\newcounter{tikzumlFragmentPartNum}%
+\newcounter{tikzumlCallStartFragmentNum}%
+\newcounter{tikzumlCallEndFragmentNum}%
+%
+\newif\iftikzumlobjectNoDDots%
+\newif\iftikzumlcreatecallNoDDots%
+%
+% define a sequence diagram
+%
+\newenvironment{umlseqdiag}{%
+ \gdef\tikzumlInCreateCall{0}%
+ \setcounter{tikzumlObjectNum}{0}%
+ \setcounter{tikzumlCallLevel}{0}%
+ \setcounter{tikzumlCallNum}{0}%
+ \setcounter{tikzumlFragmentLevel}{0}%
+ \setcounter{tikzumlFragmentLevelNum}{0}%
+ \setcounter{tikzumlFragmentNum}{0}%
+ \setcounter{tikzumlFragmentPartNum}{0}%
+ \setcounter{tikzumlCallStartFragmentNum}{0}%
+ \setcounter{tikzumlCallEndFragmentNum}{0}%
+ %
+ \ifx \@umlactor \@empty
+ \newcommand{\umlactor}[2][]{%
+ \pgfkeys{/tikzuml/actorobj/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlactor, forbidden option stereo}%
+ }{}%
+ }%
+ }%
+ %
+ \pgfkeys{/tikzuml/actorobj/.cd, ##1}%
+ \umlobject[stereo=actor, ##1]{##2}%
+ }%
+ \else%
+ \renewcommand{\umlactor}[2][]{%
+ \pgfkeys{/tikzuml/actorobj/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlactor, forbidden option stereo}%
+ }{}%
+ }%
+ }%
+ %
+ \pgfkeys{/tikzuml/actorobj/.cd, ##1}%
+ \umlobject[stereo=actor, ##1]{##2}%
+ }%
+ \fi%
+ \begin{scope}[font=\tikzumlDefaultFont]%
+}{%
+ % draw lifelines of each object
+ \begin{pgfonlayer}{lifelines}%
+ \foreach \id in \tikzumlIdList {%
+ \draw (\csname tikzumlLastChild@\id \endcsname)+(0,-2.5ex) node[inner sep=0, name=end-\id] {};%
+ \draw[dotted] (\id) -- (end-\id);%
+ }%
+ \end{pgfonlayer}%
+ \end{scope}%
+}%
+%
+% define the database symbol
+% optional : global tikzpicture styles
+\newcommand{\pictureddatabase}[1]{%
+ \pgfkeys{/tikzuml/database/.cd, scale/.initial=1, .unknown/.code={}}%
+ \pgfkeys{/tikzuml/database/.cd,#1}%
+ \pgfkeys{/tikzuml/database/.cd, scale/.get=\tikzumlDatabaseScale}%
+ %
+ \begin{tikzpicture}[#1]%
+ \node[fill, draw, ellipse, minimum width=\tikzumlDatabaseScale*4ex, minimum height=\tikzumlDatabaseScale*2ex, inner sep=0] (bottom) at (0,-2ex) {};%
+ \node[fill, draw, ellipse, minimum width=\tikzumlDatabaseScale*4ex, minimum height=\tikzumlDatabaseScale*2ex, inner sep=0] (top) at (0,4ex) {};%
+ \fill (bottom.west) rectangle (top.east);%
+ \begin{scope}%
+ \clip (-3.5ex,-0.5ex) rectangle (3.5ex,2.5ex);%
+ \node[draw, dashed, ellipse, minimum width=\tikzumlDatabaseScale*4ex, minimum height=\tikzumlDatabaseScale*2ex, inner sep=0] (bottom2) at (0,-2ex) {};%
+ \end{scope}%
+ \node[draw, ellipse, minimum width=\tikzumlDatabaseScale*4ex, minimum height=\tikzumlDatabaseScale*2ex, inner sep=0] (top2) at (0,4ex) {};%
+ \draw (bottom.west) -- (top.west) (bottom.east) -- (top.east);%
+ \end{tikzpicture}%
+}%
+%
+% define the entity symbol
+% optional : global tikzpicture styles
+\newcommand{\picturedentity}[1]{%
+ \pgfkeys{/tikzuml/entity/.cd, scale/.initial=1, .unknown/.code={}}%
+ \pgfkeys{/tikzuml/entity/.cd,#1}%
+ \pgfkeys{/tikzuml/entity/.cd, scale/.get=\tikzumlEntityScale}%
+ %
+ \begin{tikzpicture}[#1]%
+ \node[fill, draw, circle, inner sep=0, minimum size=\tikzumlEntityScale*5ex] (center) at (0,0) {};%
+ \draw (center.south) node[coordinate, name=bottom] {};%
+ \draw (bottom)+(-2ex,0) node[coordinate, name=bottom-left] {};%
+ \draw (bottom)+(2ex,0) node[coordinate, name=bottom-right] {};%
+ \draw (center) -- (bottom);%
+ \draw (bottom-left) -- (bottom-right);%
+ \end{tikzpicture}%
+}%
+%
+% define the boundary symbol
+% optional : global tikzpicture styles
+\newcommand{\picturedboundary}[1]{%
+ \pgfkeys{/tikzuml/boundary/.cd, scale/.initial=1, .unknown/.code={}}%
+ \pgfkeys{/tikzuml/boundary/.cd,#1}%
+ \pgfkeys{/tikzuml/boundary/.cd, scale/.get=\tikzumlBoundaryScale}%
+ %
+ \begin{tikzpicture}[#1]
+ \node[fill, draw, circle, inner sep=0, minimum size=\tikzumlBoundaryScale*5ex] (center) at (0,0) {};
+ \draw (center.west)+(-0.8ex,0) node[coordinate, name=left] {};
+ \draw (left)+(0,0.2ex) node[coordinate, name=left-top] {};
+ \draw (left)+(0,-0.2ex) node[coordinate, name=left-bottom] {};
+ \draw (center) -- (left);
+ \draw (left-top) -- (left-bottom);
+ \end{tikzpicture}
+}%
+%
+% define the control symbol
+% optional : global tikzpicture styles
+\newcommand{\picturedcontrol}[1]{%
+ \pgfkeys{/tikzuml/control/.cd, scale/.initial=1, .unknown/.code={}}%
+ \pgfkeys{/tikzuml/control/.cd,#1}%
+ \pgfkeys{/tikzuml/control/.cd, scale/.get=\tikzumlControlScale}%
+ %
+ \begin{tikzpicture}[#1, decoration={markings, mark=at position 0.25 with {\arrow{>}}}]
+ \node[fill, draw, circle, inner sep=0, minimum size=\tikzumlControlScale*5ex, postaction={decorate}] (center) at (0,0) {};
+ \end{tikzpicture}
+}%
+%
+% define a uml object for a sequence diagram
+% args : name of the object
+% optional : x, y: coordinates of the object
+% stereo: stereotype of the object (object, actor, database, boundary, control, entity, multiobject)
+% class: class of the object
+% scale: scale factor of the object symbol
+% draw, fill, text; colors
+% no ddots: when used, disable printing of double dots
+\newcommand{\umlobject}[2][]{
+ \stepcounter{tikzumlObjectNum}%
+ %
+ \edef\tikzumlobject@ddot{:}%
+ \pgfkeys{/tikzuml/obj/.cd, x/.initial=tikzumlEmpty, y/.initial=\tikzumlDefaultX, stereo/.initial=\tikzumlObjectDefaultStereo,%
+ class/.initial={}, scale/.initial=1,%
+ draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlObjectDefaultFillColor,%
+ text/.initial=\tikzumlDefaultTextColor,%
+ no ddots/.is if=tikzumlobjectNoDDots,%
+ no ddots=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \errmessage{TIKZUML ERROR : in umlobject, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/obj/.cd, #1}%
+ \pgfkeys{/tikzuml/obj/.cd, x/.get=\tikzumlObjectX, y/.get=\tikzumlObjectY,%
+ stereo/.get=\tikzumlObjectStereo, class/.get=\tikzumlObjectClass,%
+ scale/.get=\tikzumlObjectScale,%
+ draw/.get=\tikzumlObjectDrawColor, fill/.get=\tikzumlObjectFillColor,%
+ text/.get=\tikzumlObjectTextColor%
+ }%
+ %
+ \iftikzumlobjectNoDDots%
+ \edef\tikzumlobject@ddot{}%
+ \fi%
+ %
+ \ifthenelse{\equal{\tikzumlObjectX}{tikzumlEmpty}}{%
+ \pgfmathsetmacro{\tikzumlObjectX}{4*(\thetikzumlObjectNum-1)}%
+ }{}%
+ %
+ \def\tikzumlObjectName{#2}%
+ \expandafter\xdef\csname tikzumlLastChild@\tikzumlObjectName \endcsname{\tikzumlObjectName}%
+ %
+ \ifnum\thetikzumlObjectNum=1%
+ \xdef\tikzumlIdList{\tikzumlObjectName}%
+ \else%
+ \let\tikzumlIdListOld\tikzumlIdList%
+ \expandafter\xdef\expandafter\tikzumlIdList\expandafter{\tikzumlIdListOld,\tikzumlObjectName}%
+ \fi%
+ %
+ \tikzstyle{tikzuml object box style}=[rectangle, text=\tikzumlObjectTextColor, font=\tikzumlDefaultFont]%
+ %
+ \ifthenelse{\equal{\tikzumlObjectStereo}{object}}{%
+ \tikzstyle{tikzuml object box style}+=[draw=\tikzumlObjectDrawColor, fill=\tikzumlObjectFillColor]%
+ }{%
+ \ifthenelse{\equal{\tikzumlObjectStereo}{multi}}{%
+ \tikzstyle{tikzuml object box style}+=[fill=\tikzumlObjectFillColor]%
+ }{}%
+ }%
+ %
+ \ifnum\tikzumlInCreateCall=1%
+ \draw (\tikzumlCreateCallObjectSrc -| \tikzumlObjectX,0) node[tikzuml object box style] (\tikzumlObjectName) {\tikzumlObjectName\tikzumlobject@ddot\tikzumlObjectClass};%
+ \else%
+ \node[tikzuml object box style] (\tikzumlObjectName) at (\tikzumlObjectX,\tikzumlObjectY) {\tikzumlObjectName\tikzumlobject@ddot\tikzumlObjectClass};%
+ \fi%
+ %
+ \ifthenelse{\equal{\tikzumlObjectStereo}{multi}}{%
+ \draw (\tikzumlObjectName.north east)+(0.4ex,0.4ex) node[name=\tikzumlObjectName-tr, coordinate] {};
+ \draw (\tikzumlObjectName.north west)+(0.4ex,0.4ex) node[name=\tikzumlObjectName-tl, coordinate] {};
+ \draw (\tikzumlObjectName.south east)+(0.4ex,0.4ex) node[name=\tikzumlObjectName-br, coordinate] {};
+ \draw (\tikzumlObjectName-tr)+(0.4ex,0.4ex) node[name=\tikzumlObjectName-ttr, coordinate] {};
+ \draw (\tikzumlObjectName-tl)+(0.4ex,0.4ex) node[name=\tikzumlObjectName-ttl, coordinate] {};
+ \draw (\tikzumlObjectName-br)+(0.4ex,0.4ex) node[name=\tikzumlObjectName-tbr, coordinate] {};
+ \fill[fill=\tikzumlObjectFillColor] (\tikzumlObjectName-ttl |- \tikzumlObjectName.north) -- (\tikzumlObjectName-ttl) -- (\tikzumlObjectName-ttr) -- (\tikzumlObjectName-tbr) -- (\tikzumlObjectName-tbr -| \tikzumlObjectName.east) -- (\tikzumlObjectName.north east) -- (\tikzumlObjectName-ttl |- \tikzumlObjectName.north);
+ \draw[draw=\tikzumlObjectDrawColor] (\tikzumlObjectName-ttl |- \tikzumlObjectName.north) -- (\tikzumlObjectName-ttl) -- (\tikzumlObjectName-ttr) -- (\tikzumlObjectName-tbr) -- (\tikzumlObjectName-tbr -| \tikzumlObjectName.east);
+ \fill[fill=\tikzumlObjectFillColor] (\tikzumlObjectName-tl |- \tikzumlObjectName.north) -- (\tikzumlObjectName-tl) -- (\tikzumlObjectName-tr) -- (\tikzumlObjectName-br) -- (\tikzumlObjectName-br -| \tikzumlObjectName.east) -- (\tikzumlObjectName.north east) -- (\tikzumlObjectName-tl |- \tikzumlObjectName.north);
+ \draw[draw=\tikzumlObjectDrawColor] (\tikzumlObjectName-tl |- \tikzumlObjectName.north) -- (\tikzumlObjectName-tl) -- (\tikzumlObjectName-tr) -- (\tikzumlObjectName-br) -- (\tikzumlObjectName-br -| \tikzumlObjectName.east);
+ \draw[draw=\tikzumlObjectDrawColor] (\tikzumlObjectName.north west) rectangle (\tikzumlObjectName.south east);
+ }{%
+ \ifthenelse{\equal{\tikzumlObjectStereo}{object}}{}{%
+ \node[above=1ex, name=\tikzumlObjectName-picture] at (\tikzumlObjectName) {\csname pictured\tikzumlObjectStereo \endcsname{draw=\tikzumlObjectDrawColor, fill=\tikzumlObjectFillColor, scale=\tikzumlObjectScale}};
+ }%
+ }%
+}%
+%
+% shortcuts for objects
+\newcommand{\umlbasicobject}[2][]{%
+ \pgfkeys{/tikzuml/basicobj/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{no ddots}}{%
+ \errmessage{TIKZUML ERROR : in umlbasicobject, forbidden option no ddots}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/basicobj/.cd, #1}%
+ \umlobject[no ddots, #1]{#2}%
+}%
+%
+\newcommand{\umldatabase}[2][]{%
+ \pgfkeys{/tikzuml/databaseobj/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umldatabase, forbidden option stereo}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/databaseobj/.cd, #1}%
+ \umlobject[stereo=database, #1]{#2}%
+}%
+\newcommand{\umlentity}[2][]{%
+ \pgfkeys{/tikzuml/entityobj/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlentity, forbidden option stereo}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/entityobj/.cd, #1}%
+ \umlobject[stereo=entity, #1]{#2}%
+}%
+\newcommand{\umlcontrol}[2][]{%
+ \pgfkeys{/tikzuml/controlobj/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlcontrol, forbidden option stereo}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/controlobj/.cd, #1}%
+ \umlobject[stereo=control, #1]{#2}%
+}%
+\newcommand{\umlboundary}[2][]{%
+ \pgfkeys{/tikzuml/boundaryobj/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlboundary, forbidden option stereo}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/boundaryobj/.cd, #1}%
+ \umlobject[stereo=boundary, #1]{#2}%
+}%
+\newcommand{\umlmulti}[2][]{%
+ \pgfkeys{/tikzuml/multiobj/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlmulti, forbidden option stereo}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/multiobj/.cd, #1}%
+ \umlobject[stereo=multi, #1]{#2}%
+}%
+%
+\newcounter{tikzumlSDNodeNum}%
+%
+% define a hidden node to lengthen lifeline of a object
+% args : object node
+% optional : dt: distance between the sdnode and the last call defined on the lifeline of the object
+% name: name of the sdnode
+\newcommand{\umlsdnode}[2][]{%
+ \pgfkeys{/tikzuml/sdnode/.cd, dt/.initial=0, name/.initial=tikzumlEmpty}%
+ \pgfkeys{/tikzuml/sdnode/.cd, #1}%
+ \pgfkeys{/tikzuml/sdnode/.cd, dt/.get=\tikzumlSDNodeDT, name/.get=\tikzumlSDNodeName}%
+ %
+ \ifthenelse{\equal{\tikzumlSDNodeName}{tikzumlEmpty}}{%
+ \expandafter\def\expandafter\tikzumlSDNode@nodeName{sdnode-\thetikzumlSDNodeNum}%
+ }{%
+ \expandafter\def\expandafter\tikzumlSDNode@nodeName{\tikzumlSDNodeName}%
+ }%
+ %
+ \stepcounter{tikzumlSDNodeNum}%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlSDNode@objnodeName{#2}}\x%
+ %
+ \draw (\expandafter\csname tikzumlLastChild@\tikzumlSDNode@objnodeName \endcsname)+(0,-\tikzumlSDNodeDT ex) node[name=\tikzumlSDNode@nodeName,coordinate] {};%
+ %
+ % update last node drawn on sender lifeline
+ \expandafter\xdef\csname tikzumlLastChild@\tikzumlSDNode@objnodeName \endcsname{\tikzumlSDNode@nodeName}%
+}%
+%
+\newlength{\tikzumlCall@xa}%
+\newlength{\tikzumlCall@xb}%
+%
+% define a uml operation call for sequence diagrams
+% args : call sender
+% call receiver
+% optional : dt: time delay from precedent event end
+% name: name of the call
+% op: operation name and input args
+% return: return value
+% type: type of the call (synchron, asynchron)
+% draw, fill, text: colors
+% padding: time padding from call start and to call end
+\newenvironment{umlcall}[3][]{%
+ \stepcounter{tikzumlCallNum}%
+ \def\tikzumlCallWithReturn{tikzumlFalse}%
+ \edef\tikzumlCall@lastchildNum{\thetikzumlCallNum}% for testing presence of sub-calls
+ \gdef\tikzumlCallBottom{0}%
+ %
+ \pgfkeys{/tikzuml/call/.cd, dt/.initial=\tikzumlCallDefaultDT, name/.initial={call-\thetikzumlCallNum},%
+ op/.initial={}, return/.initial={}, type/.initial=\tikzumlCallDefaultType,%
+ draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlCallDefaultFillColor,%
+ text/.initial=\tikzumlDefaultTextColor,%
+ padding/.initial=\tikzumlCallDefaultPadding,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{with return}}{%
+ \def\tikzumlCallWithReturn{tikzumlTrue}%
+ }{%
+ \errmessage{TIKZUML ERROR : in umlcall, invalid option \keyname}%
+ }%
+ }%
+ }%
+ \pgfkeys{/tikzuml/call/.cd, #1}%
+ \pgfkeys{/tikzuml/call/.cd, dt/.get=\tikzumlCallDT, name/.get=\tikzumlCallName, op/.get=\tikzumlCallOp,%
+ return/.get=\tikzumlCallReturn, type/.get=\tikzumlCallType,%
+ padding/.get=\tikzumlCallPadding,%
+ draw/.get=\tikzumlCallDrawColor, fill/.get=\tikzumlCallFillColor,%
+ text/.get=\tikzumlCallTextColor%
+ }%
+ %
+ \edef\tikzumlfillcall{\tikzumlCallFillColor}%
+ \edef\tikzumldrawcall{\tikzumlCallDrawColor}%
+ \edef\tikzumltextcall{\tikzumlCallTextColor}%
+ \edef\tikzumltypecall{\tikzumlCallType}%
+ %
+ \ifthenelse{\equal{\tikzumlCallDT}{tikzumlEmpty}}{%
+ \ifnum\thetikzumlCallNum=1%
+ \def\tikzumlCallDT{2}%
+ \def\tikzumlcallSrc{2}%
+ \else%
+ \def\tikzumlCallDT{2}%
+ \def\tikzumlcallSrc{1}%
+ \fi%
+ }{%
+ \def\tikzumlcallSrc{0}%
+ }%
+ %
+ \let\tikzumlCallStartNodeNameold\tikzumlCallStartNodeName%
+ \def\tikzumlCallStartNodeName{#2}%
+ \let\tikzumlCallEndNodeNameold\tikzumlCallEndNodeName%
+ \def\tikzumlCallEndNodeName{#3}%
+ \def\tikzumlcallheight{\tikzumlCallPadding}%
+ %
+ % managing time delays from previous/parent fragments
+ \ifnum\thetikzumlCallStartFragmentNum>0%
+ \let\tikzumlCallDTold\tikzumlCallDT%
+ \pgfmathparse{0.5*\tikzumlFragment@paddingy+\tikzumlCallDTold}%
+ \edef\tikzumlCallDT{\pgfmathresult}%
+ \addtocounter{tikzumlCallStartFragmentNum}{-1}
+ \fi%
+ \ifnum\thetikzumlCallEndFragmentNum>0%
+ \let\tikzumlCallDTold\tikzumlCallDT%
+ \pgfmathparse{0.5*\tikzumlFragment@paddingy+\tikzumlCallDTold}%
+ \edef\tikzumlCallDT{\pgfmathresult}%
+ \addtocounter{tikzumlCallEndFragmentNum}{-1}
+ \fi%
+ \ifnum\thetikzumlFragmentPartNum>0%
+ \let\tikzumlCallDTold\tikzumlCallDT%
+ \pgfmathparse{0.5*\tikzumlFragment@paddingy+\tikzumlCallDTold}%
+ \edef\tikzumlCallDT{\pgfmathresult}%
+ \fi%
+ %
+ % managing parent-child structure
+ \ifnum\thetikzumlCallLevel>0%
+ \let\tikzumlCall@nameold\tikzumlCall@name%
+ \edef\tikzumlCall@name{\tikzumlCallName}%
+ \let\tikzumlCall@parentold\tikzumlCall@parent%
+ \edef\tikzumlCall@parent{\tikzumlCall@parentold @@\tikzumlCall@nameold}%
+ \else%
+ \edef\tikzumlCall@parent{}%
+ \edef\tikzumlCall@parentold{}%
+ \edef\tikzumlCall@nameold{}
+ \edef\tikzumlCall@name{\tikzumlCallName}%
+ \fi%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlCall@nodeName{\tikzumlCall@name}}\x%
+ %
+ \let\tikzumlCall@nodeNameold\tikzumlCall@nodeName%
+ %
+ \def\tikzumlcallstyle{tikzuml \tikzumlCallType-msg style}%
+ %
+ % top node of activity period of call sender
+ \begin{pgfonlayer}{connections}%
+ \pgfmathparse{\tikzumlCallDT+\tikzumlcallSrc}%
+ \draw (\csname tikzumlLastChild@\tikzumlCallStartNodeName \endcsname)+(0,-\pgfmathresult ex) node[coordinate, name=tikzumlTmpNode] {};%
+ \node[tikzuml activity style] (st-\tikzumlCall@nodeName) at (\tikzumlCallStartNodeName |- tikzumlTmpNode) {};%
+ %
+ % update last node drawn on sender lifeline
+ \expandafter\xdef\csname tikzumlLastChild@\tikzumlCallStartNodeName \endcsname{st-\tikzumlCall@nodeName}%
+ %
+ % top node of activity period of call receiver
+ \ifstrequal{\tikzumlCallStartNodeName}{\tikzumlCallEndNodeName}{%
+ \draw (st-\tikzumlCall@nodeName)+(0,-0.75*\tikzumlCallPadding ex) node[coordinate, name=tikzumlTmpNode] {};%
+ \node[tikzuml activity style] (et-\tikzumlCall@nodeName) at (\tikzumlCallStartNodeName |- tikzumlTmpNode) {};%
+ }{%
+ \node[tikzuml activity style] (et-\tikzumlCall@nodeName) at (\tikzumlCallEndNodeName |- st-\tikzumlCall@nodeName) {};%
+ }%
+ %
+ % update last node drawn on receiver lifeline
+ \expandafter\xdef\csname tikzumlLastChild@\tikzumlCallEndNodeName \endcsname{et-\tikzumlCall@nodeName}%
+ \xdef\tikzumlCallBottomSrc{et-\tikzumlCall@nodeName}%
+ \end{pgfonlayer}%
+ %
+ \stepcounter{tikzumlCallLevel}%
+}{%
+ \addtocounter{tikzumlCallLevel}{-1}%
+ %
+ % bottom nodes of activity periods of call sender and receiver
+ \begin{pgfonlayer}{connections}%
+ \ifnum\tikzumlCall@lastchildNum=\thetikzumlCallNum%
+ %
+ % this test occurs a bug with latex package preview
+ \ifstrequal{\tikzumlCallStartNodeName}{\tikzumlCallEndNodeName}{%
+ \draw (\tikzumlCallBottomSrc)+(0,-\tikzumlCallPadding ex) node[coordinate, name=tikzumlTmpNode] {};%
+ \node[tikzuml activity style] (eb-\tikzumlCall@nodeName) at (\tikzumlCallEndNodeName |- tikzumlTmpNode) {};%
+ \draw (eb-\tikzumlCall@nodeName)+(0,-0.75*\tikzumlCallPadding ex) node[coordinate, name=tikzumlTmpNode] {};%
+ \node[tikzuml activity style] (sb-\tikzumlCall@nodeName) at (\tikzumlCallStartNodeName |- tikzumlTmpNode) {};%
+ }{%
+ \ifthenelse{\equal{\tikzumlCallReturn}{tikzumlEmpty}}{%
+ \pgfmathsetmacro{\tikzumlCallPaddingd}{0.5*\tikzumlCallPadding}%
+ }{%
+ \pgfmathsetmacro{\tikzumlCallPaddingd}{1.2*\tikzumlCallPadding}%
+ }%
+ \draw (\tikzumlCallBottomSrc)+(0,-\tikzumlCallPaddingd ex) node[coordinate, name=tikzumlTmpNode] {};%
+ \node[tikzuml activity style] (eb-\tikzumlCall@nodeName) at (\tikzumlCallEndNodeName |- tikzumlTmpNode) {};%
+ \node[tikzuml activity style] (sb-\tikzumlCall@nodeName) at (\tikzumlCallStartNodeName |- eb-\tikzumlCall@nodeName) {};%
+ }%
+ \xdef\tikzumlCallBottomSrc{sb-\tikzumlCall@nodeName}%
+ \else%
+ %
+ % managing time delays from previous/parent fragments
+ \ifnum\thetikzumlCallStartFragmentNum>0%
+ \let\tikzumlcallheightold\tikzumlCallPadding%
+ \pgfmathparse{\tikzumlcallheightold+0.5*\tikzumlFragment@paddingy}%
+ \edef\tikzumlcallheight{\pgfmathresult}%
+ \addtocounter{tikzumlCallStartFragmentNum}{-1}%
+ \fi%
+ \ifnum\thetikzumlCallEndFragmentNum>0%
+ \let\tikzumlcallheightold\tikzumlCallPadding%
+ \pgfmathparse{\tikzumlcallheightold+0.5*\tikzumlFragment@paddingy}%
+ \edef\tikzumlcallheight{\pgfmathresult}%
+ \addtocounter{tikzumlCallEndFragmentNum}{-1}%
+ \fi%
+ %
+ \ifstrequal{\tikzumlCallStartNodeName}{\tikzumlCallEndNodeName}{%
+ \draw (\tikzumlCallBottomSrc)+(0,-\tikzumlcallheight ex) node[coordinate, name=tikzumlTmpNode] {};%
+ \node[tikzuml activity style] (eb-\tikzumlCall@nodeName) at (\tikzumlCallEndNodeName |- tikzumlTmpNode) {};%
+ \draw (eb-\tikzumlCall@nodeName)+(0,-0.75*\tikzumlCallPadding ex) node[coordinate, name=tikzumlTmpNode] {};%
+ \node[tikzuml activity style] (sb-\tikzumlCall@nodeName) at (\tikzumlCallStartNodeName |- tikzumlTmpNode) {};%
+ }{%
+ \draw (\tikzumlCallBottomSrc)+(0,-\tikzumlcallheight ex) node[coordinate, name=tikzumlTmpNode] {};%
+ \node[tikzuml activity style] (eb-\tikzumlCall@nodeName) at (\tikzumlCallEndNodeName |- tikzumlTmpNode) {};%
+ \node[tikzuml activity style] (sb-\tikzumlCall@nodeName) at (\tikzumlCallStartNodeName |- eb-\tikzumlCall@nodeName) {};%
+ }%
+ %
+ \xdef\tikzumlCallBottomSrc{sb-\tikzumlCall@nodeName}%
+ \fi%
+ \end{pgfonlayer}%
+ %
+ % draw activity periods
+ \begin{pgfonlayer}{activity}%
+ \ifstrequal{\tikzumlCallStartNodeName}{\tikzumlCallEndNodeName}{%
+ % draw root activity period only
+ \ifnum\thetikzumlCallLevel=0%
+ \draw[draw=\tikzumldrawcall, fill=\tikzumlfillcall] (st-\tikzumlCall@nodeName.north west) rectangle (sb-\tikzumlCall@nodeName.south east);%
+ \else%
+ % draw root activity from inner call
+ \ifthenelse{\equal{\tikzumlCallStartNodeName}{\tikzumlCallEndNodeNameold}}{}{%
+ \draw[draw=\tikzumldrawcall, fill=\tikzumlfillcall] (st-\tikzumlCall@nodeName.north west) rectangle (sb-\tikzumlCall@nodeName.south east);%
+ }%
+ \fi%
+ }{%
+ % draw root activity period
+ \ifnum\thetikzumlCallLevel=0%
+ \draw[draw=\tikzumldrawcall, fill=\tikzumlfillcall] (st-\tikzumlCall@nodeName.north west) rectangle (sb-\tikzumlCall@nodeName.south east);%
+ \else%
+ % draw root activity from inner call
+ \ifthenelse{\equal{\tikzumlCallStartNodeName}{\tikzumlCallEndNodeNameold}}{}{%
+ \draw[draw=\tikzumldrawcall, fill=\tikzumlfillcall] (st-\tikzumlCall@nodeName.north west) rectangle (sb-\tikzumlCall@nodeName.south east);%
+ }%
+ \fi%
+ % draw receiver activity period
+ \draw[draw=\tikzumldrawcall, fill=\tikzumlfillcall] (et-\tikzumlCall@nodeName.north west) rectangle (eb-\tikzumlCall@nodeName.south east);%
+ }%
+ \end{pgfonlayer}%
+ \ifthenelse{\equal{\tikzumlCallDefaultFillColor}{\tikzumlCallFillColor}}{}{%
+ \fill[\tikzumlfillcall] (st-\tikzumlCall@nodeName.north west) rectangle (sb-\tikzumlCall@nodeName.south east);%
+ \draw[\tikzumldrawcall] (st-\tikzumlCall@nodeName.north west) rectangle (sb-\tikzumlCall@nodeName.south west) (st-\tikzumlCall@nodeName.north east) rectangle (sb-\tikzumlCall@nodeName.south east);%
+ }%
+ %
+ % update last nodes drawn on sender and receiver lifelines
+ \expandafter\xdef\csname tikzumlLastChild@\tikzumlCallEndNodeName \endcsname{eb-\tikzumlCall@nodeName}%
+ \expandafter\xdef\csname tikzumlLastChild@\tikzumlCallStartNodeName \endcsname{sb-\tikzumlCall@nodeName}%
+ %
+ % draw call arrows
+ \begin{pgfonlayer}{connections}%
+ \ifstrequal{\tikzumlCallStartNodeName}{\tikzumlCallEndNodeName}{%
+ \draw[\tikzumlcallstyle, \tikzumldrawcall] (st-\tikzumlCall@nodeName.east) -- ++(2.5*\tikzumlCallPadding ex,0) %
+ -- ++(0,-0.75*\tikzumlCallPadding ex) %
+ node[font=\tikzumlDefaultFont, text=\tikzumltextcall, midway, right, name=\tikzumlCall@nodeName-op] {\tikzumlCallOp} %
+ -- (et-\tikzumlCall@nodeName.east);%
+ %
+ % draw return arrow and update fit for parent fragment
+ \ifthenelse{\equal{\tikzumltypecall}{synchron}}{%
+ \ifthenelse{\NOT\equal{\tikzumlCallReturn}{}\OR\equal{\tikzumlCallWithReturn}{tikzumlTrue}}{%
+ \ifnum\c@tikzumlFragmentLevel>0%
+ \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname}%
+ \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{\tikzumlFragmentFitOld (st-\tikzumlCall@nodeName) (et-\tikzumlCall@nodeName) (eb-\tikzumlCall@nodeName) (sb-\tikzumlCall@nodeName) (\tikzumlCall@nodeName-op) (\tikzumlCall@nodeName-return)}%
+ \fi%
+ %
+ \draw[tikzuml call return style, \tikzumldrawcall] (eb-\tikzumlCall@nodeName.east) -- ++(2.5*\tikzumlCallPadding ex,0)
+ -- ++(0,-0.75*\tikzumlCallPadding ex) %
+ node[font=\tikzumlDefaultFont, text=\tikzumltextcall, midway, right, name=\tikzumlCall@nodeName-return] {\tikzumlCallReturn} %
+ -- (sb-\tikzumlCall@nodeName.east);%
+ }{%
+ \ifnum\c@tikzumlFragmentLevel>0%
+ \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname}%
+ \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{\tikzumlFragmentFitOld (st-\tikzumlCall@nodeName) (et-\tikzumlCall@nodeName) (eb-\tikzumlCall@nodeName) (sb-\tikzumlCall@nodeName) (\tikzumlCall@nodeName-op)}%
+ \fi%
+ }%
+ }{%
+ \ifnum\c@tikzumlFragmentLevel>0%
+ \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname}%
+ \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{\tikzumlFragmentFitOld (st-\tikzumlCall@nodeName) (et-\tikzumlCall@nodeName) (eb-\tikzumlCall@nodeName) (sb-\tikzumlCall@nodeName) (\tikzumlCall@nodeName-op)}%
+ \fi%
+ }%
+ }{%
+ % draw call arrows
+ \pgfextractx{\tikzumlCall@xa}{\pgfpointanchor{\tikzumlCallStartNodeName}{center}}%
+ \pgfextractx{\tikzumlCall@xb}{\pgfpointanchor{\tikzumlCallEndNodeName}{center}}%
+ %
+ \ifthenelse{\tikzumlCall@xb>\tikzumlCall@xa}{%
+ \draw[\tikzumlcallstyle, \tikzumldrawcall] (st-\tikzumlCall@nodeName.east) -- (et-\tikzumlCall@nodeName.west) %
+ node[font=\tikzumlDefaultFont, text=\tikzumltextcall, midway, above=-0.4ex, name=\tikzumlCall@nodeName-op] {\tikzumlCallOp};%
+ }{%
+ \draw[\tikzumlcallstyle, \tikzumldrawcall] (st-\tikzumlCall@nodeName.west) -- (et-\tikzumlCall@nodeName.east) %
+ node[font=\tikzumlDefaultFont, text=\tikzumltextcall, midway, above=-0.4ex, name=\tikzumlCall@nodeName-op] {\tikzumlCallOp};%
+ }%
+ %
+ % draw return arrow and update fit for parent fragment
+ \ifthenelse{\equal{\tikzumltypecall}{synchron}}{%
+ \ifthenelse{\NOT\equal{\tikzumlCallReturn}{}\OR\equal{\tikzumlCallWithReturn}{tikzumlTrue}}{%
+ \ifnum\c@tikzumlFragmentLevel>0%
+ \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname}%
+ \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{\tikzumlFragmentFitOld (st-\tikzumlCall@nodeName) (et-\tikzumlCall@nodeName) (eb-\tikzumlCall@nodeName) (sb-\tikzumlCall@nodeName) (\tikzumlCall@nodeName-op) (\tikzumlCall@nodeName-return)}%
+ \fi%
+ %
+ \ifthenelse{\tikzumlCall@xb>\tikzumlCall@xa}{%
+ \draw[tikzuml call return style, \tikzumldrawcall] (eb-\tikzumlCall@nodeName.west) -- (sb-\tikzumlCall@nodeName.east) %
+ node[font=\tikzumlDefaultFont, text=\tikzumltextcall, midway, above=-0.4ex, name=\tikzumlCall@nodeName-return] {\tikzumlCallReturn};%
+ }{%
+ \draw[tikzuml call return style, \tikzumldrawcall] (eb-\tikzumlCall@nodeName.east) -- (sb-\tikzumlCall@nodeName.west) %
+ node[font=\tikzumlDefaultFont, text=\tikzumltextcall, midway, above=-0.4ex, name=\tikzumlCall@nodeName-return] {\tikzumlCallReturn};%
+ }%
+ }{%
+ \ifnum\c@tikzumlFragmentLevel>0%
+ \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname}%
+ \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{\tikzumlFragmentFitOld (st-\tikzumlCall@nodeName) (et-\tikzumlCall@nodeName) (eb-\tikzumlCall@nodeName) (sb-\tikzumlCall@nodeName) (\tikzumlCall@nodeName-op)}%
+ \fi%
+ }%
+ }{%
+ \ifnum\c@tikzumlFragmentLevel>0%
+ \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname}%
+ \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{\tikzumlFragmentFitOld (st-\tikzumlCall@nodeName) (et-\tikzumlCall@nodeName) (eb-\tikzumlCall@nodeName) (sb-\tikzumlCall@nodeName) (\tikzumlCall@nodeName-op)}%
+ \fi%
+ }%
+ }%
+ \end{pgfonlayer}%
+}%
+%
+% alias for function self call
+\newenvironment{umlcallself}[2][]{\begin{umlcall}[#1]{#2}{#2} }{\end{umlcall}}%
+%
+% define a combined fragment
+% optional : name: name of fragment
+% type: type of fragment (opt, alt, break, loop, par, critical, ignore, consider, assert, neg, weak, strict, ref)
+% label: label of fragment (ex : condition for opt, iterator for loop, ...)
+% inner xsep, inner ysep: padding of the fragment box
+% draw, fill, text: colors
+\newenvironment{umlfragment}[1][]{%
+ % define a fragment separator
+ % optional : label of the fragment part (ex : else for alt)
+ \providecommand{\umlfpart}[1][]{%
+ \stepcounter{tikzumlFragmentPartNum}%
+ %
+ \node[outer sep=0, inner xsep=\tikzumlFragmentXSep ex, inner ysep=\tikzumlFragmentYSep ex, fit=\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname, name=\tikzumlFragment@name-Part-tmp] {};%
+ \node[anchor=east, name=\tikzumlFragment@name-PartType-\thetikzumlFragmentPartNum] at (\tikzumlFragment@name-Part-tmp.north west |- \tikzumlCallBottomSrc) {\phantom{\tikzumlFragmentType}};%
+ \draw (\tikzumlFragment@name-PartType-\thetikzumlFragmentPartNum.north west |- \tikzumlCallBottomSrc)+(0,-0.4*\tikzumlFragment@paddingy ex) node[name=\tikzumlFragment@name-PartWest-\thetikzumlFragmentPartNum] {};%
+ \draw (\tikzumlFragment@name-Part-tmp.north east |- \tikzumlCallBottomSrc)+(0,-0.4*\tikzumlFragment@paddingy ex) node[name=\tikzumlFragment@name-PartEast-\thetikzumlFragmentPartNum] {};%
+ \draw[dashed] (\tikzumlFragment@name-PartWest-\thetikzumlFragmentPartNum) -- (\tikzumlFragment@name-PartEast-\thetikzumlFragmentPartNum);
+ \draw (\tikzumlFragment@name-PartType-\thetikzumlFragmentPartNum)+(0,-0.4*\tikzumlFragment@paddingy ex) node[name=tikzumlTmpNode] {\phantom{\tikzumlFragmentType}};%
+ \node[anchor=north west] at (tikzumlTmpNode.south west) {[##1]};%
+ }%
+ %
+ \stepcounter{tikzumlFragmentNum}%
+ %
+ \pgfkeys{/tikzuml/fragment/.cd, name/.initial=fragment@\alph{tikzumlFragmentNum}, type/.initial=\tikzumlFragmentDefaultType,%
+ label/.initial=tikzumlEmpty,%
+ inner xsep/.initial=\tikzumlFragmentDefaultXSep, inner ysep/.initial=\tikzumlFragmentDefaultYSep,%
+ draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlFragmentDefaultFillColor,%
+ text/.initial=\tikzumlDefaultTextColor,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \errmessage{TIKZUML ERROR : in umlfragment, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/fragment/.cd, #1}%
+ \pgfkeys{/tikzuml/fragment/.cd, name/.get=\tikzumlFragmentName, type/.get=\tikzumlFragmentType,%
+ label/.get=\tikzumlFragmentLabel,%
+ inner xsep/.get=\tikzumlFragmentXSep, inner ysep/.get=\tikzumlFragmentYSep,%
+ draw/.get=\tikzumlFragmentDrawColor, fill/.get=\tikzumlFragmentFillColor,%
+ text/.get=\tikzumlFragmentTextColor%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlFragmentLabel}{tikzumlEmpty}}{%
+ \def\tikzumlFragmentLabel{}%
+ }{%
+ \let\tikzumlFragmentLabelold\tikzumlFragmentLabel%
+ \def\tikzumlFragmentLabel{[\tikzumlFragmentLabelold]}%
+ }%
+ %
+ \ifnum\thetikzumlFragmentLevel>0%
+ \let\tikzumlFragment@parentold\tikzumlFragment@parent%
+ \let\tikzumlFragment@nameold\tikzumlFragment@name%
+ \edef\tikzumlFragment@parent{\tikzumlFragment@nameold}%
+ \else%
+ \setcounter{tikzumlFragmentPartNum}{0}%
+ \edef\tikzumlFragment@parent{}%
+ \edef\tikzumlFragment@parentold{}%
+ \edef\tikzumlFragment@nameold{}%
+ \fi%
+ %
+ \edef\tikzumlFragment@name{\tikzumlFragmentName}%
+ \expandafter\gdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{}%
+ %
+ \stepcounter{tikzumlFragmentLevel}%
+ %
+ \ifnum\thetikzumlCallLevel>0%
+ \stepcounter{tikzumlCallStartFragmentNum}%
+ \fi%
+ %
+ \pgfmathparse{6*\tikzumlFragmentYSep}%
+ \xdef\tikzumlFragment@paddingy{\pgfmathresult}%
+ \if\c@tikzumlFragmentLevelNum=0%
+ \setcounter{tikzumlFragmentLevelNum}{\thetikzumlFragmentLevel}%
+ \fi%
+ %
+ % time delay adjustment for two consecutive fragments
+ \ifnum\thetikzumlCallEndFragmentNum>0%
+ \addtocounter{tikzumlCallEndFragmentNum}{-1}
+ \fi%
+}{%
+ %
+ \addtocounter{tikzumlFragmentLevel}{-1}%
+ %
+ \ifnum\thetikzumlFragmentLevel>0%
+ \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@parent \endcsname}%
+ \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@parent \endcsname{\tikzumlFragmentFitOld (\tikzumlFragment@name)}%
+ \fi%
+ %
+ % draw working fragment box
+ \begin{pgfonlayer}{fragment\thetikzumlFragmentLevel}%
+ \node[outer sep=0, inner xsep=\tikzumlFragmentXSep ex, inner ysep=\tikzumlFragmentYSep ex, fit=\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname, name=\tikzumlFragment@name-back] {};%
+ \end{pgfonlayer}%
+ %
+ % draw type and label
+ \node[text=\tikzumlFragmentTextColor, font=\tikzumlDefaultFont, anchor=north east, name=\tikzumlFragment@name-type] %
+ at (\tikzumlFragment@name-back.north west) {\tikzumlFragmentType};%
+ \node[text=\tikzumlFragmentTextColor, font=\tikzumlDefaultFont, anchor=north west, name=\tikzumlFragment@name-label] %
+ at (\tikzumlFragment@name-type.south west) {\tikzumlFragmentLabel};%
+ %
+ % draw final fragment box
+ \begin{pgfonlayer}{fragment\thetikzumlFragmentLevel}%
+ \node[draw=\tikzumlFragmentDrawColor, fill=\tikzumlFragmentFillColor, outer sep=0, inner sep=0, font=\tikzumlDefaultFont, fit=(\tikzumlFragment@name-back) (\tikzumlFragment@name-type) (\tikzumlFragment@name-label), name=\tikzumlFragment@name] {};%
+ \end{pgfonlayer}%
+ %
+ \draw[draw=\tikzumlFragmentDrawColor] (\tikzumlFragment@name.north west) rectangle (\tikzumlFragment@name.south east);%
+ \draw (\tikzumlFragment@name-type.south east)+(0,1ex) node[name=\tikzumlFragment@name-typetop, inner sep=0] {};%
+ \draw (\tikzumlFragment@name-type.south east)+(-1ex,0) node[name=\tikzumlFragment@name-typeleft, inner sep=0] {};%
+ \draw (\tikzumlFragment@name.north west) -| (\tikzumlFragment@name-typetop.center) -- (\tikzumlFragment@name-typeleft.center) -| (\tikzumlFragment@name.north west);%
+ %
+ \ifnum\thetikzumlCallLevel>0%
+ \stepcounter{tikzumlCallEndFragmentNum}%
+ \fi%
+}%
+%
+% define a constructor call
+% arg : call sender
+% name of constructed object
+% optional : x: coordinate of the new object
+% stereo: stereotype of the new object
+% class: class type of the new object
+% dt: time delay from last event
+% name: name of the call
+% draw, fill, text: colors
+% no ddots: when used, disable printing of double dots
+\newcommand{\umlcreatecall}[3][]{%
+ \stepcounter{tikzumlCallNum}%
+ \edef\tikzumlCall@lastchildNum{\thetikzumlCallNum}% for testing presence of sub-calls
+ \gdef\tikzumlInCreateCall{1}%
+ \pgfkeys{/tikzuml/createcall/.cd, x/.initial=tikzumlEmpty, stereo/.initial=\tikzumlObjectDefaultStereo, class/.initial={},%
+ dt/.initial=\tikzumlCreateCallDefaultDT, name/.initial=call-\thetikzumlCallNum,%
+ draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlCallDefaultFillColor,%
+ text/.initial=\tikzumlDefaultTextColor,%
+ draw obj/.initial=\tikzumlDefaultDrawColor, fill obj/.initial=\tikzumlObjectDefaultFillColor,%
+ text obj/.initial=\tikzumlDefaultTextColor,%
+ no ddots/.is if=tikzumlcreatecallNoDDots,%
+ no ddots=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \errmessage{TIKZUML ERROR : in umlcreatecall, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/createcall/.cd, #1}%
+ \pgfkeys{/tikzuml/createcall/.cd, x/.get=\tikzumlCreateCallX, stereo/.get=\tikzumlCreateCallStereo,%
+ class/.get=\tikzumlCreateCallClass,%
+ dt/.get=\tikzumlCreateCallDT, name/.get=\tikzumlCreateCallName,%
+ draw/.get=\tikzumlCreateCallDrawColor, fill/.get=\tikzumlCreateCallFillColor,%
+ text/.get=\tikzumlCreateCallTextColor,%
+ draw obj/.get=\tikzumlCreateCallObjectDrawColor, fill obj/.get=\tikzumlCreateCallObjectFillColor,%
+ text obj/.get=\tikzumlCreateCallObjectTextColor%
+ }%
+ %
+ \def\tikzumlCreateCallSrc@name{#2}%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlCreateCallSrc@nodeName{\tikzumlCreateCallSrc@name}}\x%
+ %
+ % managing time delays from previous/parent fragments
+ \ifnum\thetikzumlCallStartFragmentNum>0%
+ \let\tikzumlCreateCallDTold\tikzumlCreateCallDT%
+ \pgfmathparse{0.5*\tikzumlFragment@paddingy+\tikzumlCreateCallDTold}%
+ \edef\tikzumlCreateCallDT{\pgfmathresult}%
+ \addtocounter{tikzumlCallStartFragmentNum}{-1}
+ \fi%
+ \ifnum\thetikzumlCallEndFragmentNum>0%
+ \let\tikzumlCreateCallDTold\tikzumlCreateCallDT%
+ \pgfmathparse{0.5*\tikzumlFragment@paddingy+\tikzumlCreateCallDTold}%
+ \edef\tikzumlCreateCallDT{\pgfmathresult}%
+ \addtocounter{tikzumlCallEndFragmentNum}{-1}
+ \fi%
+ \ifnum\thetikzumlFragmentPartNum>0%
+ \let\tikzumlCreateCallDTold\tikzumlCreateCallDT%
+ \pgfmathparse{0.5*\tikzumlFragment@paddingy+\tikzumlCreateCallDTold}%
+ \edef\tikzumlCreateCallDT{\pgfmathresult}%
+ \fi%
+ %
+ % managing parent-child structure
+ \ifnum\thetikzumlCallLevel>0%
+ \let\tikzumlCall@nameold\tikzumlCall@name%
+ \def\tikzumlCall@name{\tikzumlCreateCallName}%
+ \let\tikzumlCall@parentold\tikzumlCall@parent%
+ \edef\tikzumlCall@parent{\tikzumlCall@parentold @@\tikzumlCall@nameold}%
+ \else%
+ \edef\tikzumlCall@parent{}%
+ \edef\tikzumlCall@parentold{}%
+ \edef\tikzumlCall@nameold{}
+ \edef\tikzumlCall@name{\tikzumlCreateCallName}%
+ \fi%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlCreateCall@nodeName{\tikzumlCall@name}}\x%
+ %
+ \draw (\csname tikzumlLastChild@\tikzumlCreateCallSrc@nodeName \endcsname)+(0,-\tikzumlCreateCallDT ex) node[name=st-\tikzumlCreateCall@nodeName, tikzuml activity style] {};%
+ %
+ \xdef\tikzumlCreateCallObjectSrc{st-\tikzumlCreateCall@nodeName}%
+ %
+ \iftikzumlcreatecallNoDDots%
+ \umlobject[x=\tikzumlCreateCallX, stereo=\tikzumlCreateCallStereo, class=\tikzumlCreateCallClass, draw=\tikzumlCreateCallObjectDrawColor, fill=\tikzumlCreateCallObjectFillColor, text=\tikzumlCreateCallObjectTextColor, no ddots]{#3}%
+ \else
+ \umlobject[x=\tikzumlCreateCallX, stereo=\tikzumlCreateCallStereo, class=\tikzumlCreateCallClass, draw=\tikzumlCreateCallObjectDrawColor, fill=\tikzumlCreateCallObjectFillColor, text=\tikzumlCreateCallObjectTextColor]{#3}%
+ \fi
+ %
+ \draw (\csname tikzumlLastChild@\tikzumlCreateCallSrc@nodeName \endcsname |- #3)+(0,-0.5*\tikzumlCreateCallDT ex) node[name=sb-\tikzumlCreateCall@nodeName, tikzuml activity style] {};%
+ %
+ \expandafter\xdef\csname tikzumlLastChild@\tikzumlCreateCallSrc@nodeName \endcsname{sb-\tikzumlCreateCall@nodeName}%
+ \xdef\tikzumlCallBottomSrc{sb-\tikzumlCreateCall@nodeName}%
+ %
+ \begin{pgfonlayer}{connections}%
+ \draw[tikzuml synchron-msg style, \tikzumlCreateCallDrawColor] (st-\tikzumlCreateCall@nodeName) -- (#3) node[midway, above, font=\tikzumlDefaultFont, text=\tikzumlCreateCallTextColor, name=\tikzumlCreateCall@nodeName-op] {create};%
+ \end{pgfonlayer}%
+ %
+ \ifnum\thetikzumlCallLevel=0%
+ \begin{pgfonlayer}{activity}%
+ \draw[draw=\tikzumlCreateCallDrawColor, fill=\tikzumlCreateCallFillColor] (st-\tikzumlCreateCall@nodeName.north west) rectangle (sb-\tikzumlCreateCall@nodeName.south east);%
+ \end{pgfonlayer}%
+ \fi%
+ % add to fit fragment
+ \ifnum\c@tikzumlFragmentLevel>0%
+ \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname}%
+ \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{\tikzumlFragmentFitOld (st-\tikzumlCreateCall@nodeName) (sb-\tikzumlCreateCall@nodeName) (\tikzumlCreateCall@nodeName-op) (#3) }%
+ \fi%
+}
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% component diagrams %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+\tikzstyle{tikzuml connector style}=[color=\tikzumlDefaultDrawColor, -]%
+%
+\newcounter{tikzumlComponentLevel}%
+\newcounter{tikzumlComponentSubComponentNum}%
+\newcounter{tikzumlConnectorNum}%
+\setcounter{tikzumlConnectorNum}{1}%
+%
+\newif\iftikzumlcomponentWithoutCoords%
+%
+\newcommand{\picturedcomponent}[1]{%
+ \pgfkeys{/tikzuml/component/picture/.cd, scale/.initial=1, .unknown/.code={}}%
+ \pgfkeys{/tikzuml/component/picture/.cd,#1}%
+ \pgfkeys{/tikzuml/component/picture/.cd, scale/.get=\tikzumlComponentScale}%
+ \begin{tikzpicture}[#1]%
+ \filldraw (0,0) rectangle (1ex,1.5ex);%
+ \filldraw (-0.2ex,0.4ex) rectangle (0.2ex,0.6ex);%
+ \filldraw (-0.2ex,0.9ex) rectangle (0.2ex,1.1ex);%
+ \end{tikzpicture}%
+}%
+%
+% define a uml component
+% args : name of the component
+% content of the component
+% optional args : x,y coordinates of the component
+% width of the component node
+\newenvironment{umlcomponent}[2][]{%
+ \ifnum\thetikzumlComponentLevel>0%
+ \let\tikzumlComponent@nameold\tikzumlComponent@fitname%
+ \let\tikzumlComponent@parentold\tikzumlComponent@parent%
+ \edef\tikzumlComponent@parent{\tikzumlComponent@parentold @@\tikzumlComponent@nameold}%
+ \else%
+ \def\tikzumlComponent@parent{}%
+ \fi%
+ %
+ \stepcounter{tikzumlComponentLevel}%
+ %
+ \pgfkeys{/tikzuml/component/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlComponentDefaultWidth, name/.initial={},%
+ draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlComponentDefaultFillColor,%
+ text/.initial=\tikzumlDefaultTextColor, style/.style={},%
+ no coords/.is if=tikzumlcomponentWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/component/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/component/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/component/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlcomponent, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/component/.cd, #1}%
+ \pgfkeys{/tikzuml/component/.cd, x/.get=\tikzumlComponentXShift, y/.get=\tikzumlComponentYShift,%
+ width/.get=\tikzumlComponentMinimumWidth, name/.get=\tikzumlComponentName,%
+ draw/.get=\tikzumlComponentDrawColor, fill/.get=\tikzumlComponentFillColor,%
+ text/.get=\tikzumlComponentTextColor%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlComponentName}{}}{%
+ \edef\tikzumlComponent@name{#2}%
+ }{%
+ \edef\tikzumlComponent@name{\tikzumlComponentName}%
+ }%
+ %
+ \begingroup%
+ \def\_{@}\edef\x{\endgroup%
+ \def\noexpand\tikzumlComponent@fitname{\tikzumlComponent@name}}\x%
+ %
+ \let\tikzumlComponent@nodeNameold\tikzumlComponent@nodeName%
+ \def\tikzumlComponent@caption{#2}%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlComponent@nodeName{\tikzumlComponent@name}}\x%
+ %
+ \expandafter\gdef\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname{}%
+ %
+ \setcounter{tikzumlComponentSubComponentNum}{0}%
+ %
+ \begin{scope}[xshift=\tikzumlComponentXShift cm, yshift=\tikzumlComponentYShift cm]%
+}{%
+ \addtocounter{tikzumlComponentLevel}{-1}%
+ \begin{pgfonlayer}{component\thetikzumlComponentLevel}%
+ %
+ % if contains nothing, one define a fictive node to enable the fit option
+ \ifnum\c@tikzumlComponentSubComponentNum=0%
+ \iftikzumlcomponentWithoutCoords%
+ \node[inner ysep=0.5ex, minimum width=\tikzumlComponentMinimumWidth, font=\tikzumlDefaultFont, /tikzuml/component/style] (\tikzumlComponent@nodeName-root) {\phantom{\tikzumlComponent@nodeName}};%
+ \else%
+ \node[inner ysep=0.5ex, minimum width=\tikzumlComponentMinimumWidth, font=\tikzumlDefaultFont, /tikzuml/component/style] (\tikzumlComponent@nodeName-root) at (0,0) {\phantom{\tikzumlComponent@nodeName}};%
+ \fi%
+ \expandafter\xdef\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname{(\tikzumlComponent@nodeName-root)}%
+ \fi%
+ %
+ \ifnum\c@tikzumlComponentLevel>0%
+ \def\tikzumlComponentFitTmp{\csname tikzumlComponentFit\tikzumlComponent@parent\endcsname}%
+ \expandafter\xdef\csname tikzumlComponentFit\tikzumlComponent@parent\endcsname{\tikzumlComponentFitTmp (\tikzumlComponent@nodeName-body) (\tikzumlComponent@nodeName-caption)}%
+ \stepcounter{tikzumlComponentSubComponentNum}%
+ \fi%
+ %
+ \node[inner sep=2ex, font=\tikzumlDefaultFont, fit = \csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname] (\tikzumlComponent@nodeName-body) {};%
+ \node[above, font=\tikzumlDefaultFont] (\tikzumlComponent@nodeName-captiontmp) at (\tikzumlComponent@nodeName-body.north) {\tikzumlComponent@caption};%
+ \node (\tikzumlComponent@nodeName-logotmp) at (\tikzumlComponent@nodeName-captiontmp.north -| \tikzumlComponent@nodeName-body.east) {\picturedcomponent{draw=\tikzumlComponentDrawColor, fill=\tikzumlComponentFillColor, font=\tikzumlDefaultFont} };%
+ \node[draw=\tikzumlComponentDrawColor, fill=\tikzumlComponentFillColor, name=\tikzumlComponent@nodeName, /tikzuml/component/style, fit=(\tikzumlComponent@nodeName-body) (\tikzumlComponent@nodeName-captiontmp)] {};%
+ \node[font=\tikzumlDefaultFont] (\tikzumlComponent@nodeName-caption) at (\tikzumlComponent@nodeName-captiontmp) {\tikzumlComponent@caption};%
+ \draw (\tikzumlComponent@nodeName-caption.north -| \tikzumlComponent@nodeName.east) node[font=\tikzumlDefaultFont, xshift=-1ex, below=-1ex, name=\tikzumlComponent@nodeName-logo] {\picturedcomponent{draw=\tikzumlComponentDrawColor, fill=\tikzumlComponentFillColor, font=\tikzumlDefaultFont} };%
+ \draw (\tikzumlComponent@nodeName-caption.south -| \tikzumlComponent@nodeName.north west) -- (\tikzumlComponent@nodeName-caption.south -| \tikzumlComponent@nodeName.north east);%
+ \coordinate (\tikzumlComponent@nodeName-west-port) at (\tikzumlComponent@nodeName.west);
+ \coordinate (\tikzumlComponent@nodeName-east-port) at (\tikzumlComponent@nodeName.east);
+ \coordinate (\tikzumlComponent@nodeName-south-port) at (\tikzumlComponent@nodeName.south);
+ \coordinate (\tikzumlComponent@nodeName-north-port) at (\tikzumlComponent@nodeName.north);
+ \end{pgfonlayer}%
+ \end{scope}%
+ %
+ % add to fit
+ \ifnum\c@tikzumlPackageLevel>0%
+ \edef\tikzumlPackageFitOld{\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{\tikzumlPackageFitOld (\tikzumlComponent@nodeName)}%
+ \stepcounter{tikzumlPackageClassNum}%
+ \fi%
+}%
+%
+% shortcut for empty component
+\newcommand{\umlbasiccomponent}[2][]{\begin{umlcomponent}[#1]{#2} \end{umlcomponent}}%
+%
+\newcommand{\umlrequiredinterface}[2][]{%
+ \def\tikzumlInterfaceWithPort{tikzumlFalse}%
+ \pgfkeys{/tikzuml/requiredinterfacerelation/.cd, interface/.initial={}, distance/.initial=\tikzumlRequiredInterfaceDefaultDistance,%
+ name/.initial=tikzumlEmpty, width/.initial=\tikzumlRequiredInterfaceDefaultWidth,%
+ padding/.initial=\tikzumlRequiredInterfaceDefaultPadding,%
+ draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlComponentDefaultFillColor,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{with port}}{%
+ \def\tikzumlInterfaceWithPort{tikzumlTrue}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/requiredinterfacerelation/.cd, #1}%
+ \pgfkeys{/tikzuml/requiredinterfacerelation/.cd, interface/.get=\tikzumlRequiredInterfaceLabel,%
+ distance/.get=\tikzumlRequiredInterfaceDistance,%
+ name/.get=\tikzumlRequiredInterfaceName,%
+ width/.get=\tikzumlRequiredInterfaceWidth,%
+ padding/.get=\tikzumlRequiredInterfacePadding,%
+ draw/.get=\tikzumlRequiredInterfaceDrawColor,%
+ fill/.get=\tikzumlRequiredInterfaceFillColor%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlRequiredInterfaceName}{tikzumlEmpty}}{%
+ \edef\tikzumlRequiredInterface@interfacename{#2-east-interface}%
+ \edef\tikzumlRequiredInterface@portname{#2-east-port}%
+ \edef\tikzumlRequiredInterface@paddingname{#2-east-padding}%
+ }{%
+ \edef\tikzumlRequiredInterface@interfacename{\tikzumlRequiredInterfaceName}%
+ \edef\tikzumlRequiredInterface@portname{\tikzumlRequiredInterfaceName-port}%
+ \edef\tikzumlRequiredInterface@paddingname{\tikzumlRequiredInterfaceName-padding}%
+ }%
+ %
+ \edef\tikzumlRequiredInterface@name{#2}%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlRequiredInterface@nodeName{\tikzumlRequiredInterface@name}}\x%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlRequiredInterface@interfacenodeName{\tikzumlRequiredInterface@interfacename}}\x%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlRequiredInterface@portnodeName{\tikzumlRequiredInterface@portname}}\x%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlRequiredInterface@paddingnodeName{\tikzumlRequiredInterface@paddingname}}\x%
+ %
+ \ifthenelse{\equal{\tikzumlInterfaceWithPort}{tikzumlTrue}}{%
+ \node[inner sep=0.5*\tikzumlRequiredInterfaceWidth, rectangle, draw=\tikzumlRequiredInterfaceDrawColor, fill=\tikzumlRequiredInterfaceFillColor] (\tikzumlRequiredInterface@portnodeName) at (\tikzumlRequiredInterface@nodeName.east) {};%
+ }{%
+ \node[inner sep=0] (\tikzumlRequiredInterface@nodeName-east-port) at (\tikzumlRequiredInterface@nodeName.east) {};%
+ }%
+ \begin{scope}%
+ \draw (\tikzumlRequiredInterface@nodeName)+(\tikzumlRequiredInterfaceDistance,0) node[inner sep=0, text width=\tikzumlRequiredInterfaceWidth, circle, name=\tikzumlRequiredInterface@interfacenodeName-tmp] {};%
+ \clip (\tikzumlRequiredInterface@interfacenodeName-tmp.north) rectangle (\tikzumlRequiredInterface@interfacenodeName-tmp.south -| \tikzumlRequiredInterface@interfacenodeName-tmp.west);%
+ \node[inner sep=0, text width=\tikzumlRequiredInterfaceWidth, circle, draw=\tikzumlRequiredInterfaceDrawColor] (\tikzumlRequiredInterface@interfacenodeName) at (\tikzumlRequiredInterface@interfacenodeName-tmp) {};%
+ \end{scope}%
+ \node[above] at (\tikzumlRequiredInterface@interfacenodeName.north) {\tikzumlRequiredInterfaceLabel};%
+ %
+ \umlrelation[style={tikzuml connector style}, #1]{\tikzumlRequiredInterface@portnodeName}{\tikzumlRequiredInterface@interfacenodeName}%
+ %
+ \draw (\tikzumlRequiredInterface@interfacenodeName)+(\tikzumlRequiredInterfacePadding,0) node[name=\tikzumlRequiredInterface@paddingnodeName] {};%
+ %
+ % add to fit
+ \ifnum\c@tikzumlComponentLevel>0%
+ \def\tikzumlComponentFitTmp{\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname{\tikzumlComponentFitTmp (\tikzumlRequiredInterface@paddingnodeName) (\tikzumlRequiredInterface@portnodeName) }%
+ \fi%
+}%
+%
+\newcommand{\umlprovidedinterface}[2][]{%
+ \def\tikzumlInterfaceWithPort{tikzumlFalse}%
+ \pgfkeys{/tikzuml/providedinterfacerelation/.cd, interface/.initial={}, distance/.initial=\tikzumlProvidedInterfaceDefaultDistance,%
+ name/.initial=tikzumlEmpty, width/.initial=\tikzumlProvidedInterfaceDefaultWidth,%
+ padding/.initial=\tikzumlProvidedInterfaceDefaultPadding,%
+ draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlComponentDefaultFillColor,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{with port}}{%
+ \def\tikzumlInterfaceWithPort{tikzumlTrue}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/providedinterfacerelation/.cd, #1}%
+ \pgfkeys{/tikzuml/providedinterfacerelation/.cd, interface/.get=\tikzumlProvidedInterfaceLabel,%
+ distance/.get=\tikzumlProvidedInterfaceDistance,%
+ name/.get=\tikzumlProvidedInterfaceName,%
+ width/.get=\tikzumlProvidedInterfaceWidth,%
+ padding/.get=\tikzumlProvidedInterfacePadding,%
+ draw/.get=\tikzumlProvidedInterfaceDrawColor,%
+ fill/.get=\tikzumlProvidedInterfaceFillColor%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlProvidedInterfaceName}{tikzumlEmpty}}{%
+ \edef\tikzumlProvidedInterface@interfacename{#2-west-interface}%
+ \edef\tikzumlProvidedInterface@portname{#2-west-port}%
+ \edef\tikzumlProvidedInterface@paddingname{#2-west-padding}%
+ }{%
+ \edef\tikzumlProvidedInterface@interfacename{\tikzumlProvidedInterfaceName}%
+ \edef\tikzumlProvidedInterface@portname{\tikzumlProvidedInterfaceName-port}%
+ \edef\tikzumlProvidedInterface@paddingname{\tikzumlProvidedInterfaceName-padding}%
+ }%
+ %
+ \edef\tikzumlProvidedInterface@name{#2}%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlProvidedInterface@nodeName{\tikzumlProvidedInterface@name}}\x%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlProvidedInterface@interfacenodeName{\tikzumlProvidedInterface@interfacename}}\x%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlProvidedInterface@portnodeName{\tikzumlProvidedInterface@portname}}\x%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlProvidedInterface@paddingnodeName{\tikzumlProvidedInterface@paddingname}}\x%
+ %
+ \ifthenelse{\equal{\tikzumlInterfaceWithPort}{tikzumlTrue}}{%
+ \node[inner sep=0.5*\tikzumlProvidedInterfaceWidth, rectangle, draw=\tikzumlProvidedInterfaceDrawColor, fill=\tikzumlProvidedInterfaceFillColor] (\tikzumlProvidedInterface@portnodeName) at (\tikzumlProvidedInterface@nodeName.west) {};%
+ }{%
+ \node[inner sep=0] (\tikzumlProvidedInterface@portnodeName) at (\tikzumlProvidedInterface@nodeName.west) {};%
+ }%
+ \draw (\tikzumlProvidedInterface@nodeName)+(-\tikzumlProvidedInterfaceDistance,0) node[inner sep=0, text width=\tikzumlProvidedInterfaceWidth, circle, draw=\tikzumlProvidedInterfaceDrawColor, fill=\tikzumlProvidedInterfaceFillColor, name=\tikzumlProvidedInterface@interfacenodeName] {};%
+ \node[above] at (\tikzumlProvidedInterface@interfacenodeName.north)
+ {\tikzumlProvidedInterfaceLabel};%
+ %
+ \umlrelation[style={tikzuml connector style}, #1]{\tikzumlProvidedInterface@portnodeName}{\tikzumlProvidedInterface@interfacenodeName}%
+ %
+ \draw (\tikzumlProvidedInterface@interfacenodeName)+(-\tikzumlProvidedInterfacePadding,0) node[name=\tikzumlProvidedInterface@paddingnodeName] {};%
+ %
+ % add to fit
+ \ifnum\thetikzumlComponentLevel>0%
+ \def\tikzumlComponentFitTmp{\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname{\tikzumlComponentFitTmp (\tikzumlProvidedInterface@paddingnodeName) (\tikzumlProvidedInterface@portnodeName) }%
+ \fi%
+}%
+%
+\newlength{\tikzuml@AC@xa}%
+\newlength{\tikzuml@AC@ya}%
+\newlength{\tikzuml@AC@xb}%
+\newlength{\tikzuml@AC@yb}%
+\newlength{\tikzuml@AC@xi}%
+\newlength{\tikzuml@AC@yi}%
+\newlength{\tikzuml@AC@xic}%
+\newlength{\tikzuml@AC@yic}%
+\newlength{\tikzuml@AC@xio}%
+\newlength{\tikzuml@AC@yio}%
+\newlength{\tikzuml@AC@AB}%
+\newlength{\tikzuml@AC@lambda}%
+\newlength{\tikzuml@AC@xtrc}%
+\newlength{\tikzuml@AC@ytrc}%
+\newlength{\tikzuml@AC@xtlc}%
+\newlength{\tikzuml@AC@ytlc}%
+\newlength{\tikzuml@AC@xblc}%
+\newlength{\tikzuml@AC@yblc}%
+\newlength{\tikzuml@AC@xbrc}%
+\newlength{\tikzuml@AC@ybrc}%
+\newlength{\tikzuml@AC@middleArm}%
+%
+\newcommand{\umlassemblyconnectorsymbol}[2]{%
+ \ifthenelse{\NOT\equal{\tikzumlAssemblyConnectorLabel}{}}{%
+ \edef\tikzuml@ACStart@name{#1}%
+ \edef\tikzuml@ACEnd@name{#2}%
+ \edef\tikzuml@AC@width{\tikzumlAssemblyConnectorWidth}%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzuml@ACStart@nodeName{\tikzuml@ACStart@name}}\x%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzuml@ACEnd@nodeName{\tikzuml@ACEnd@name}}\x%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzuml@ACInterface@nodeName{\tikzumlAssemblyConnectorSymbolName}}\x%
+ %
+ \pgfextractx{\tikzuml@AC@xa}{\pgfpointanchor{\tikzuml@ACStart@nodeName}{\tikzumlAssemblyConnectorStartAnchor}}%
+ \pgfextracty{\tikzuml@AC@ya}{\pgfpointanchor{\tikzuml@ACStart@nodeName}{\tikzumlAssemblyConnectorStartAnchor}}%
+ \pgfextractx{\tikzuml@AC@xb}{\pgfpointanchor{\tikzuml@ACEnd@nodeName}{\tikzumlAssemblyConnectorEndAnchor}}%
+ \pgfextracty{\tikzuml@AC@yb}{\pgfpointanchor{\tikzuml@ACEnd@nodeName}{\tikzumlAssemblyConnectorEndAnchor}}%
+ \pgfmathsetlength{\tikzuml@AC@xi}{0.5*\tikzuml@AC@xa+0.5*\tikzuml@AC@xb}%
+ \pgfmathsetlength{\tikzuml@AC@yi}{0.5*\tikzuml@AC@ya+0.5*\tikzuml@AC@yb}%
+ \pgfmathsetlength{\tikzuml@AC@AB}{veclen(\tikzuml@AC@xa-\tikzuml@AC@xb,\tikzuml@AC@ya-\tikzuml@AC@yb)}%
+ \pgfmathsetlength{\tikzuml@AC@lambda}{0.25*\tikzuml@AC@width/\tikzuml@AC@AB}%
+ \pgfmathsetlength{\tikzuml@AC@xic}{\tikzuml@AC@xi-\tikzuml@AC@lambda*(\tikzuml@AC@xb-\tikzuml@AC@xa)}%
+ \pgfmathsetlength{\tikzuml@AC@yic}{\tikzuml@AC@yi-\tikzuml@AC@lambda*(\tikzuml@AC@yb-\tikzuml@AC@ya)}%
+ \pgfmathsetlength{\tikzuml@AC@xio}{\tikzuml@AC@xi+\tikzuml@AC@lambda*(\tikzuml@AC@xb-\tikzuml@AC@xa)}%
+ \pgfmathsetlength{\tikzuml@AC@yio}{\tikzuml@AC@yi+\tikzuml@AC@lambda*(\tikzuml@AC@yb-\tikzuml@AC@ya)}%
+ \node[inner sep=0.5*\tikzuml@AC@width] (\tikzuml@ACInterface@nodeName-interface) at (\tikzuml@AC@xi,\tikzuml@AC@yi) {};%
+ \node[inner sep=0, text width=\tikzuml@AC@width, circle, draw=\tikzumlAssemblyConnectorDrawColor, fill=\tikzumlAssemblyConnectorFillColor] (\tikzuml@ACInterface@nodeName-io) at (\tikzuml@AC@xio,\tikzuml@AC@yio) {};%
+ \begin{scope}%
+ \pgfmathsetlength{\tikzuml@AC@xtrc}{\tikzuml@AC@xic-2*\tikzuml@AC@lambda*(\tikzuml@AC@yb-\tikzuml@AC@ya)}%
+ \pgfmathsetlength{\tikzuml@AC@ytrc}{\tikzuml@AC@yic+2*\tikzuml@AC@lambda*(\tikzuml@AC@xb-\tikzuml@AC@xa)}%
+ \pgfmathsetlength{\tikzuml@AC@xbrc}{\tikzuml@AC@xic+2*\tikzuml@AC@lambda*(\tikzuml@AC@yb-\tikzuml@AC@ya)}%
+ \pgfmathsetlength{\tikzuml@AC@ybrc}{\tikzuml@AC@yic-2*\tikzuml@AC@lambda*(\tikzuml@AC@xb-\tikzuml@AC@xa)}%
+ \pgfmathsetlength{\tikzuml@AC@xtlc}{\tikzuml@AC@xic-3*\tikzuml@AC@lambda*(\tikzuml@AC@yb-\tikzuml@AC@ya+\tikzuml@AC@xb-\tikzuml@AC@xa)}%
+ \pgfmathsetlength{\tikzuml@AC@ytlc}{\tikzuml@AC@yic+3*\tikzuml@AC@lambda*(\tikzuml@AC@xb-\tikzuml@AC@xa+\tikzuml@AC@ya-\tikzuml@AC@yb)}%
+ \pgfmathsetlength{\tikzuml@AC@xblc}{\tikzuml@AC@xic+3*\tikzuml@AC@lambda*(\tikzuml@AC@yb-\tikzuml@AC@ya+\tikzuml@AC@xa-\tikzuml@AC@xb)}%
+ \pgfmathsetlength{\tikzuml@AC@yblc}{\tikzuml@AC@yic-3*\tikzuml@AC@lambda*(\tikzuml@AC@xb-\tikzuml@AC@xa+\tikzuml@AC@yb-\tikzuml@AC@ya)}%
+ \coordinate (\tikzuml@ACInterface@nodeName-trc) at (\tikzuml@AC@xtrc,\tikzuml@AC@ytrc);%
+ \coordinate (\tikzuml@ACInterface@nodeName-brc) at (\tikzuml@AC@xbrc,\tikzuml@AC@ybrc);%
+ \coordinate (\tikzuml@ACInterface@nodeName-tlc) at (\tikzuml@AC@xtlc,\tikzuml@AC@ytlc);%
+ \coordinate (\tikzuml@ACInterface@nodeName-blc) at (\tikzuml@AC@xblc,\tikzuml@AC@yblc);%
+ \clip (\tikzuml@ACInterface@nodeName-trc) -- (\tikzuml@ACInterface@nodeName-tlc) -- (\tikzuml@ACInterface@nodeName-blc) -- (\tikzuml@ACInterface@nodeName-brc) -- cycle;%
+ \node[inner sep=0, text width=\tikzuml@AC@width, circle, draw=\tikzumlAssemblyConnectorDrawColor, fill=\tikzumlAssemblyConnectorFillColor] (\tikzuml@ACInterface@nodeName-ic) at (\tikzuml@AC@xic,\tikzuml@AC@yic) {};%
+ \end{scope}%
+ \node[above, font=\tikzumlDefaultFont] at (\tikzuml@ACInterface@nodeName-interface.north)
+ {\tikzumlAssemblyConnectorLabel};%
+ }{}%
+}%
+%
+\newcommand{\umlassemblyconnector}[3][]{%
+ \def\tikzumlAssemblyConnectorWithPort{tikzumlFalse}%
+ \def\tikzumlAssemblyConnectorFirstArm{tikzumlFalse}%
+ \def\tikzumlAssemblyConnectorSecondArm{tikzumlFalse}%
+ \def\tikzumlAssemblyConnectorMiddleArm{tikzumlFalse}%
+ \def\tikzumlAssemblyConnectorLastArm{tikzumlFalse}%
+ \pgfkeys{/tikzuml/assemblyconnectorrelation/.cd, geometry/.initial=--, interface/.initial={},%
+ arm1/.initial={auto}, arm2/.initial={auto},%
+ name/.initial=connector-\thetikzumlConnectorNum, width/.initial=1em,%
+ anchor1/.initial={}, anchor2/.initial={},%
+ draw/.initial=\tikzumlDefaultDrawColor,%
+ fill assembly connector/.initial=\tikzumlAssemblyConnectorDefaultFillColor,%
+ fill port/.initial=\tikzumlPortDefaultFillColor,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{with port}}{%
+ \def\tikzumlAssemblyConnectorWithPort{tikzumlTrue}%
+ }{%
+ \ifthenelse{\equal{\keyname}{first arm}}{%
+ \def\tikzumlAssemblyConnectorFirstArm{tikzumlTrue}%
+ }{%
+ \ifthenelse{\equal{\keyname}{second arm}}{%
+ \def\tikzumlAssemblyConnectorSecondArm{tikzumlTrue}%
+ }{%
+ \ifthenelse{\equal{\keyname}{middle arm}}{%
+ \def\tikzumlAssemblyConnectorMiddleArm{tikzumlTrue}%
+ }{%
+ \ifthenelse{\equal{\keyname}{last arm}}{%
+ \def\tikzumlAssemblyConnectorLastArm{tikzumlTrue}%
+ }{%
+ }%
+ }%
+ }%
+ }%
+ }%
+ }%
+ }%
+ \pgfkeys{/tikzuml/assemblyconnectorrelation/.cd, #1}%
+ \pgfkeys{/tikzuml/assemblyconnectorrelation/.cd, geometry/.get=\tikzumlAssemblyConnectorGeometry,%
+ name/.get=\tikzumlAssemblyConnectorName,%
+ interface/.get=\tikzumlAssemblyConnectorLabel,%
+ width/.get=\tikzumlAssemblyConnectorWidth,%
+ arm1/.get=\tikzumlAssemblyConnectorStartArm,%
+ arm2/.get=\tikzumlAssemblyConnectorEndArm,%
+ anchor1/.get=\tikzumlAssemblyConnectorStartAnchorTmp,%
+ anchor2/.get=\tikzumlAssemblyConnectorEndAnchorTmp,%
+ draw/.get=\tikzumlAssemblyConnectorDrawColor,%
+ fill assembly connector/.get=\tikzumlAssemblyConnectorFillColor,%
+ fill port/.get=\tikzumlAssemblyConnectorPortFillColor%
+ }%
+ %
+ \edef\tikzumlAssemblyConnectorStart@name{#2}%
+ \edef\tikzumlAssemblyConnectorEnd@name{#3}%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlAssemblyConnectorStart@nodeName{\tikzumlAssemblyConnectorStart@name}}\x%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlAssemblyConnectorEnd@nodeName{\tikzumlAssemblyConnectorEnd@name}}\x%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlAssemblyConnectorLabel@nodeName{\tikzumlAssemblyConnectorLabel}}\x%
+ %
+ \pgfextractx{\tikzuml@AC@xa}{\pgfpointanchor{\tikzumlAssemblyConnectorStart@nodeName}{center}}%
+ \pgfextracty{\tikzuml@AC@ya}{\pgfpointanchor{\tikzumlAssemblyConnectorStart@nodeName}{center}}%
+ \pgfextractx{\tikzuml@AC@xb}{\pgfpointanchor{\tikzumlAssemblyConnectorEnd@nodeName}{center}}%
+ \pgfextracty{\tikzuml@AC@yb}{\pgfpointanchor{\tikzumlAssemblyConnectorEnd@nodeName}{center}}%
+ %
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{--}}{%
+ \ifthenelse{\tikzuml@AC@xb>\tikzuml@AC@xa}{%
+ \def\tikzumlAssemblyConnectorStartAnchor{east}%
+ \def\tikzumlAssemblyConnectorEndAnchor{west}%
+ }{%
+ \def\tikzumlAssemblyConnectorStartAnchor{west}%
+ \def\tikzumlAssemblyConnectorEndAnchor{east}%
+ }
+ }{}%
+ %
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{-|}}{%
+ \ifthenelse{\tikzuml@AC@xb>\tikzuml@AC@xa}{%
+ \def\tikzumlAssemblyConnectorStartAnchor{east}%
+ }{%
+ \def\tikzumlAssemblyConnectorStartAnchor{west}%
+ }
+ \ifthenelse{\tikzuml@AC@yb>\tikzuml@AC@ya}{%
+ \def\tikzumlAssemblyConnectorEndAnchor{south}%
+ }{%
+ \def\tikzumlAssemblyConnectorEndAnchor{north}%
+ }
+ }{}%
+ %
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{|-}}{%
+ \ifthenelse{\tikzuml@AC@xb>\tikzuml@AC@xa}{%
+ \def\tikzumlAssemblyConnectorEndAnchor{west}%
+ }{%
+ \def\tikzumlAssemblyConnectorEndAnchor{east}%
+ }
+ \ifthenelse{\tikzuml@AC@yb>\tikzuml@AC@ya}{%
+ \def\tikzumlAssemblyConnectorStartAnchor{north}%
+ }{%
+ \def\tikzumlAssemblyConnectorStartAnchor{south}%
+ }
+ }{}%
+ %
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{-|-}}{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorStartArm}{auto}}{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorEndArm}{auto}}{%
+ \pgfmathsetlength{\tikzuml@AC@middleArm}{0.5 * \tikzuml@AC@xa + 0.5 * \tikzuml@AC@xb}%
+ }{%
+ \pgfmathsetlength{\tikzuml@AC@middleArm}{\tikzuml@AC@xb+\tikzumlAssemblyConnectorEndArm}%
+ }%
+ }{%
+ \pgfmathsetlength{\tikzuml@AC@middleArm}{\tikzuml@AC@xa+\tikzumlAssemblyConnectorStartArm}%
+ }%
+ \pgfmathparse{\tikzuml@AC@middleArm>\tikzuml@AC@xa}
+ \pgfmathparse{\tikzuml@AC@middleArm>\tikzuml@AC@xb}
+ \ifthenelse{\lengthtest{\tikzuml@AC@middleArm>\tikzuml@AC@xa}}{%
+ \def\tikzumlAssemblyConnectorStartAnchor{east}%
+ }{%
+ \def\tikzumlAssemblyConnectorStartAnchor{west}%
+ }
+ \ifthenelse{\lengthtest{\tikzuml@AC@middleArm>\tikzuml@AC@xb}}{%
+ \def\tikzumlAssemblyConnectorEndAnchor{east}%
+ }{%
+ \def\tikzumlAssemblyConnectorEndAnchor{west}%
+ }
+ }{}%
+ %
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{|-|}}{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorStartArm}{auto}}{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorEndArm}{auto}}{%
+ \pgfmathsetlength{\tikzuml@AC@middleArm}{0.5 * \tikzuml@AC@ya + 0.5 * \tikzuml@AC@yb}%
+ }{%
+ \pgfmathsetlength{\tikzuml@AC@middleArm}{\tikzuml@AC@yb+\tikzumlAssemblyConnectorEndArm}%
+ }%
+ }{%
+ \pgfmathsetlength{\tikzuml@AC@middleArm}{\tikzuml@AC@ya+\tikzumlAssemblyConnectorStartArm}%
+ }%
+ \ifthenelse{\tikzuml@AC@middleArm>\tikzuml@AC@ya}{%
+ \def\tikzumlAssemblyConnectorStartAnchor{north}%
+ }{%
+ \def\tikzumlAssemblyConnectorStartAnchor{south}%
+ }
+ \ifthenelse{\tikzuml@AC@middleArm>\tikzuml@AC@yb}{%
+ \def\tikzumlAssemblyConnectorEndAnchor{north}%
+ }{%
+ \def\tikzumlAssemblyConnectorEndAnchor{south}%
+ }
+ }{}%
+ %
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorStartAnchorTmp}{}}{%
+ }{%
+ \def\tikzumlAssemblyConnectorStartAnchor{\tikzumlAssemblyConnectorStartAnchorTmp}%
+ }%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorEndAnchorTmp}{}}{%
+ }{%
+ \def\tikzumlAssemblyConnectorEndAnchor{\tikzumlAssemblyConnectorEndAnchorTmp}%
+ }%
+ %
+ \node[inner sep=0] (\tikzumlAssemblyConnectorStart@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port-tmp) at (\tikzumlAssemblyConnectorStart@nodeName.\tikzumlAssemblyConnectorStartAnchor) {};%
+ \node[inner sep=0] (\tikzumlAssemblyConnectorEnd@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port-tmp) at (\tikzumlAssemblyConnectorEnd@nodeName.\tikzumlAssemblyConnectorEndAnchor) {};%
+ %
+ \umlrelation[style={tikzuml connector style}, #1]{\tikzumlAssemblyConnectorStart@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port-tmp}{\tikzumlAssemblyConnectorEnd@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port-tmp}%
+ %
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorWithPort}{tikzumlTrue}}{%
+ \node[inner sep=0.5*\tikzumlAssemblyConnectorWidth, rectangle, draw=\tikzumlAssemblyConnectorDrawColor, fill=\tikzumlAssemblyConnectorPortFillColor] (\tikzumlAssemblyConnectorStart@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port) at (\tikzumlAssemblyConnectorStart@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port-tmp) {};%
+ \node[inner sep=0.5*\tikzumlAssemblyConnectorWidth, rectangle, draw=\tikzumlAssemblyConnectorDrawColor, fill=\tikzumlAssemblyConnectorPortFillColor] (\tikzumlAssemblyConnectorEnd@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port) at (\tikzumlAssemblyConnectorEnd@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port-tmp) {};%
+ }{%
+ \node[inner sep=0] (\tikzumlAssemblyConnectorStart@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port) at (\tikzumlAssemblyConnectorStart@nodeName.\tikzumlAssemblyConnectorStartAnchor) {};%
+ \node[inner sep=0] (\tikzumlAssemblyConnectorEnd@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port) at (\tikzumlAssemblyConnectorEnd@nodeName.\tikzumlAssemblyConnectorEndAnchor) {};%
+ }%
+ %
+ \addtocounter{tikzumlRelationNum}{-1}%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorName}{connector-\thetikzumlConnectorNum}}{%
+ \edef\tikzumlAssemblyConnectorName{relation-\thetikzumlRelationNum}%
+ \edef\tikzumlAssemblyConnectorSymbolName{\tikzumlAssemblyConnectorLabel@nodeName}%
+ }{%
+ \edef\tikzumlAssemblyConnectorSymbolName{\tikzumlAssemblyConnectorName}%
+ }%
+ %
+ \stepcounter{tikzumlRelationNum}%
+ %
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{--}}{%
+ \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorStart@nodeName}{\tikzumlAssemblyConnectorEnd@nodeName}%
+ }{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{-|}}{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorFirstArm}{tikzumlTrue}}{%
+ \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorStart@nodeName}{\tikzumlAssemblyConnectorName-2}%
+ }{%
+ \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorName-2}{\tikzumlAssemblyConnectorEnd@nodeName}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{|-}}{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorFirstArm}{tikzumlTrue}}{%
+ \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorStart@nodeName}{\tikzumlAssemblyConnectorName-2}%
+ }{%
+ \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorName-2}{\tikzumlAssemblyConnectorEnd@nodeName}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{-|-}}{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorFirstArm}{tikzumlTrue}}{%
+ \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorStart@nodeName}{\tikzumlAssemblyConnectorName-2}%
+ }{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorLastArm}{tikzumlTrue}}{%
+ \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorName-4}{\tikzumlAssemblyConnectorEnd@nodeName}%
+ }{%
+ \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorName-2}{\tikzumlAssemblyConnectorName-4}%
+ }%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{|-|}}{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorFirstArm}{tikzumlTrue}}{%
+ \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorStart@nodeName}{\tikzumlAssemblyConnectorName-2}%
+ }{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorLastArm}{tikzumlTrue}}{%
+ \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorName-4}{\tikzumlAssemblyConnectorEnd@nodeName}%
+ }{%
+ \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorName-2}{\tikzumlAssemblyConnectorName-4}%
+ }%
+ }%
+ }{}%
+ }%
+ }%
+ }%
+ }%
+ \stepcounter{tikzumlConnectorNum}%
+}%
+%
+% shortcuts of \umlassemblyconnector
+\newcommand{\umlHVassemblyconnector}[3][]{%
+ \pgfkeys{/tikzuml/HVassemblyconnector/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlHVassemblyconnector, forbidden option geometry}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/HVassemblyconnector/.cd, #1}%
+ \umlassemblyconnector[geometry=-|, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlVHassemblyconnector}[3][]{%
+ \pgfkeys{/tikzuml/VHassemblyconnector/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlVHassemblyconnector, forbidden option geometry}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/VHassemblyconnector/.cd, #1}%
+ \umlassemblyconnector[geometry=|-, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlHVHassemblyconnector}[3][]{%
+ \pgfkeys{/tikzuml/HVHassemblyconnector/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlHVHassemblyconnector, forbidden option geometry}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/HVHassemblyconnector/.cd, #1}%
+ \umlassemblyconnector[geometry=-|-, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlVHVassemblyconnector}[3][]{%
+ \pgfkeys{/tikzuml/VHVassemblyconnector/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlVHVassemblyconnector, forbidden option geometry}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/VHVassemblyconnector/.cd, #1}%
+ \umlassemblyconnector[geometry=|-|, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlport}[3][]{%
+ \pgfkeys{/tikzuml/port/.cd, draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlPortDefaultFillColor,%
+ width/.initial=\tikzumlPortDefaultWidth,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \errmessage{TIKZUML ERROR : in umlport forbidden option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/port/.cd, #1}%
+ \pgfkeys{/tikzuml/port/.cd, width/.get=\tikzumlPortWidth,%
+ draw/.get=\tikzumlPortDrawColor, fill/.get=\tikzumlPortFillColor}%
+ \edef\tikzumlPort@name{#2}%
+ \edef\tikzumlPort@anchor{#3}%
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlPort@nodeName{\tikzumlPort@name}}\x%
+ %
+ \node[inner sep=0.5*\tikzumlPortWidth, rectangle, draw=\tikzumlPortDrawColor, fill=\tikzumlPortFillColor] (\tikzumlPort@nodeName-\tikzumlPort@anchor-port) at (\tikzumlPort@nodeName.\tikzumlPort@anchor) {};%
+}%
+%
+\newcommand{\umldelegateconnector}[3][]{%
+ \def\tikzumlDelegateConnectorWithStartPort{tikzumlFalse}%
+ \def\tikzumlDelegateConnectorWithEndPort{tikzumlFalse}%
+ \pgfkeys{/tikzuml/delegateconnector/.cd,
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umldelegateconnector, forbidden option stereo}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/delegateconnector/.cd, #1}%
+ \umlrelation[style={tikzuml connector style}, stereo=delegate, #1]{#2}{#3}%
+}%
+%
+% shortcuts of \umldelegateconnector
+\newcommand{\umlHVdelegateconnector}[3][]{%
+ \pgfkeys{/tikzuml/HVdelegateconnector/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}\OR\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlHVdelegateconnector, forbidden option \keyname}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/HVdelegateconnector/.cd, #1}%
+ \umldelegateconnector[geometry=-|, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlVHdelegateconnector}[3][]{%
+ \pgfkeys{/tikzuml/VHdelegateconnector/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}\OR\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlVHdelegateconnector, forbidden option \keyname}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/VHdelegateconnector/.cd, #1}%
+ \umldelegateconnector[geometry=|-, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlHVHdelegateconnector}[3][]{%
+ \pgfkeys{/tikzuml/HVHdelegateconnector/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}\OR\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlHVHdelegateconnector, forbidden option \keyname}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/HVHdelegateconnector/.cd, #1}%
+ \umldelegateconnector[geometry=-|-, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlVHVdelegateconnector}[3][]{%
+ \pgfkeys{/tikzuml/VHVdelegateconnector/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}\OR\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlVHVdelegateconnector, forbidden option \keyname}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/VHVdelegateconnector/.cd, #1}%
+ \umldelegateconnector[geometry=|-|, #1]{#2}{#3}%
+}%
+%%% End of tikz-uml.sty
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \ No newline at end of file
diff --git a/30-qualitaetsheft/.gitignore b/30-qualitaetsheft/.gitignore
new file mode 100644
index 0000000..b1b3dda
--- /dev/null
+++ b/30-qualitaetsheft/.gitignore
@@ -0,0 +1,305 @@
+## Core latex/pdflatex auxiliary files:
+*.aux
+*.lof
+*.log
+*.lot
+*.fls
+*.out
+*.toc
+*.fmt
+*.fot
+*.cb
+*.cb2
+.*.lb
+
+## Intermediate documents:
+*.dvi
+*.xdv
+*-converted-to.*
+# these rules might exclude image files for figures etc.
+# *.ps
+# *.eps
+*.pdf
+!assets/*.pdf
+
+## Generated if empty string is given at "Please type another file name for output:"
+.pdf
+
+## Bibliography auxiliary files (bibtex/biblatex/biber):
+*.bbl
+*.bcf
+*.blg
+*-blx.aux
+*-blx.bib
+*.run.xml
+
+## Build tool auxiliary files:
+*.fdb_latexmk
+*.synctex
+*.synctex(busy)
+*.synctex.gz
+*.synctex.gz(busy)
+*.pdfsync
+
+## Build tool directories for auxiliary files
+# latexrun
+latex.out/
+
+## Auxiliary and intermediate files from other packages:
+# algorithms
+*.alg
+*.loa
+
+# achemso
+acs-*.bib
+
+# amsthm
+*.thm
+
+# beamer
+*.nav
+*.pre
+*.snm
+*.vrb
+
+# changes
+*.soc
+
+# comment
+*.cut
+
+# cprotect
+*.cpt
+
+# elsarticle (documentclass of Elsevier journals)
+*.spl
+
+# endnotes
+*.ent
+
+# fixme
+*.lox
+
+# feynmf/feynmp
+*.mf
+*.mp
+*.t[1-9]
+*.t[1-9][0-9]
+*.tfm
+
+#(r)(e)ledmac/(r)(e)ledpar
+*.end
+*.?end
+*.[1-9]
+*.[1-9][0-9]
+*.[1-9][0-9][0-9]
+*.[1-9]R
+*.[1-9][0-9]R
+*.[1-9][0-9][0-9]R
+*.eledsec[1-9]
+*.eledsec[1-9]R
+*.eledsec[1-9][0-9]
+*.eledsec[1-9][0-9]R
+*.eledsec[1-9][0-9][0-9]
+*.eledsec[1-9][0-9][0-9]R
+
+# glossaries
+*.acn
+*.acr
+*.glg
+*.glo
+*.gls
+*.glsdefs
+*.lzo
+*.lzs
+*.slg
+*.slo
+*.sls
+
+# uncomment this for glossaries-extra (will ignore makeindex's style files!)
+*.ist
+
+# gnuplot
+*.gnuplot
+*.table
+
+# gnuplottex
+*-gnuplottex-*
+
+# gregoriotex
+*.gaux
+*.glog
+*.gtex
+
+# htlatex
+*.4ct
+*.4tc
+*.idv
+*.lg
+*.trc
+*.xref
+
+# hyperref
+*.brf
+
+# knitr
+*-concordance.tex
+# TODO Uncomment the next line if you use knitr and want to ignore its generated tikz files
+# *.tikz
+*-tikzDictionary
+
+# listings
+*.lol
+
+# luatexja-ruby
+*.ltjruby
+
+# makeidx
+*.idx
+*.ilg
+*.ind
+
+# minitoc
+*.maf
+*.mlf
+*.mlt
+*.mtc[0-9]*
+*.slf[0-9]*
+*.slt[0-9]*
+*.stc[0-9]*
+
+# minted
+_minted*
+*.pyg
+
+# morewrites
+*.mw
+
+# newpax
+*.newpax
+
+# nomencl
+*.nlg
+*.nlo
+*.nls
+
+# pax
+*.pax
+
+# pdfpcnotes
+*.pdfpc
+
+# sagetex
+*.sagetex.sage
+*.sagetex.py
+*.sagetex.scmd
+
+# scrwfile
+*.wrt
+
+# svg
+svg-inkscape/
+
+# sympy
+*.sout
+*.sympy
+sympy-plots-for-*.tex/
+
+# pdfcomment
+*.upa
+*.upb
+
+# pythontex
+*.pytxcode
+pythontex-files-*/
+
+# tcolorbox
+*.listing
+
+# thmtools
+*.loe
+
+# TikZ & PGF
+*.dpth
+*.md5
+*.auxlock
+
+# titletoc
+*.ptc
+
+# todonotes
+*.tdo
+
+# vhistory
+*.hst
+*.ver
+
+# easy-todo
+*.lod
+
+# xcolor
+*.xcp
+
+# xmpincl
+*.xmpi
+
+# xindy
+*.xdy
+
+# xypic precompiled matrices and outlines
+*.xyc
+*.xyd
+
+# endfloat
+*.ttt
+*.fff
+
+# Latexian
+TSWLatexianTemp*
+
+## Editors:
+# WinEdt
+*.bak
+*.sav
+
+# Texpad
+.texpadtmp
+
+# LyX
+*.lyx~
+
+# Kile
+*.backup
+
+# gummi
+.*.swp
+
+# KBibTeX
+*~[0-9]*
+
+# TeXnicCenter
+*.tps
+
+# auto folder when using emacs and auctex
+./auto/*
+*.el
+
+# expex forward references with \gathertags
+*-tags.tex
+
+# standalone packages
+*.sta
+
+# Makeindex log files
+*.lpz
+
+# xwatermark package
+*.xwm
+
+# REVTeX puts footnotes in the bibliography by default, unless the nofootinbib
+# option is specified. Footnotes are the stored in a file with suffix Notes.bib.
+# Uncomment the next line to have this generated file ignored.
+#*Notes.bib
+
+# Gannt Diagramm als EPS ignorieren
+assets/gantt.eps \ No newline at end of file
diff --git a/30-qualitaetsheft/.gitlab-ci.yml b/30-qualitaetsheft/.gitlab-ci.yml
new file mode 100644
index 0000000..27d0617
--- /dev/null
+++ b/30-qualitaetsheft/.gitlab-ci.yml
@@ -0,0 +1,36 @@
+plantuml:
+ stage: .pre
+ image:
+ name: plantuml/plantuml
+ entrypoint: [""]
+ script:
+ - java -jar plantuml.jar -tpdf assets/diagrams/*.puml
+ artifacts:
+ paths:
+ - assets
+
+tex:
+ stage: build
+ image: texlive/texlive
+ script:
+ - mkdir public
+ - make tex
+ - mv *.pdf public
+ artifacts:
+ paths:
+ - public
+ dependencies:
+ - plantuml
+
+pages:
+ stage: deploy
+ script:
+ - echo Hello, World!
+ artifacts:
+ paths:
+ - public
+ rules:
+ - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
+ dependencies:
+ - tex
+
diff --git a/30-qualitaetsheft/.latexmkrc b/30-qualitaetsheft/.latexmkrc
new file mode 100644
index 0000000..bec2b38
--- /dev/null
+++ b/30-qualitaetsheft/.latexmkrc
@@ -0,0 +1,7 @@
+# https://tex.stackexchange.com/questions/1226/how-to-make-latexmk-use-makeglossaries
+add_cus_dep('glo', 'gls', 0, 'makeglo2gls');
+add_cus_dep('acn', 'acr', 0, 'makeglo2gls');
+sub makeglo2gls {
+ system("makeglossaries $_[0]");
+}
+
diff --git a/30-qualitaetsheft/Makefile b/30-qualitaetsheft/Makefile
new file mode 100644
index 0000000..292ac93
--- /dev/null
+++ b/30-qualitaetsheft/Makefile
@@ -0,0 +1,18 @@
+MAIN = qualitaetsheft
+FLAGS = -pdf
+
+all: clean compile
+compile: diagram tex
+clean: clean-diagram clean-tex
+
+dev:
+ latexmk $(FLAGS) -pvc $(MAIN)
+tex:
+ latexmk $(FLAGS) $(MAIN)
+diagram:
+ java -jar plantuml.jar -tpdf assets/diagrams/*.puml
+clean-tex:
+ latexmk -C
+clean-diagram:
+ find assets/diagrams -type f -not -name '*.puml' -delete
+
diff --git a/30-qualitaetsheft/README.md b/30-qualitaetsheft/README.md
new file mode 100644
index 0000000..2c08f29
--- /dev/null
+++ b/30-qualitaetsheft/README.md
@@ -0,0 +1,31 @@
+# Entwurfsheft
+
+> Systemdesign und -spezifikation
+
+## Diagramme
+
+Installiere [PlantUML](https://plantuml.com/starting) (oder über einen Paketmanager).
+
+Arbeiten an Diagrammen mit Echtzeit-Vorschau (Anzeige wird beim Speichern der
+puml-Datei aktualisiert):
+```sh
+java -jar plantuml.jar -gui assets/classdiagram.puml
+
+# bzw (wenn zu PATH hinzugefügt oder Linux)
+plantuml -gui assets/classdiagram.puml
+```
+
+Bauen der Diagramme:
+```sh
+java -jar plantuml.jar -teps assets/*.puml
+
+# bzw (wenn zu PATH hinzugefügt oder Linux)
+plantuml -teps assets/*.puml
+
+# bzw über Makefile (Linux)
+make diagram
+
+# oder zum Erstellen von Diagrammen und LaTeX:
+make
+```
+
diff --git a/30-qualitaetsheft/assets/.gitignore b/30-qualitaetsheft/assets/.gitignore
new file mode 100644
index 0000000..16252a4
--- /dev/null
+++ b/30-qualitaetsheft/assets/.gitignore
@@ -0,0 +1,3 @@
+diagrams/*
+!diagrams/*.puml
+
diff --git a/30-qualitaetsheft/assets/ChangedPassword.PNG b/30-qualitaetsheft/assets/ChangedPassword.PNG
new file mode 100644
index 0000000..254bf66
--- /dev/null
+++ b/30-qualitaetsheft/assets/ChangedPassword.PNG
Binary files differ
diff --git a/30-qualitaetsheft/assets/KIT_Deckblatt.pdf b/30-qualitaetsheft/assets/KIT_Deckblatt.pdf
new file mode 100644
index 0000000..7de8ed4
--- /dev/null
+++ b/30-qualitaetsheft/assets/KIT_Deckblatt.pdf
Binary files differ
diff --git a/30-qualitaetsheft/assets/WrongUser.PNG b/30-qualitaetsheft/assets/WrongUser.PNG
new file mode 100644
index 0000000..16614d4
--- /dev/null
+++ b/30-qualitaetsheft/assets/WrongUser.PNG
Binary files differ
diff --git a/30-qualitaetsheft/assets/coverage/authenticationService.png b/30-qualitaetsheft/assets/coverage/authenticationService.png
new file mode 100644
index 0000000..4ad91e1
--- /dev/null
+++ b/30-qualitaetsheft/assets/coverage/authenticationService.png
Binary files differ
diff --git a/30-qualitaetsheft/assets/coverage/episodeActionService.png b/30-qualitaetsheft/assets/coverage/episodeActionService.png
new file mode 100644
index 0000000..c81f26f
--- /dev/null
+++ b/30-qualitaetsheft/assets/coverage/episodeActionService.png
Binary files differ
diff --git a/30-qualitaetsheft/assets/coverage/server.png b/30-qualitaetsheft/assets/coverage/server.png
new file mode 100644
index 0000000..d28917a
--- /dev/null
+++ b/30-qualitaetsheft/assets/coverage/server.png
Binary files differ
diff --git a/30-qualitaetsheft/assets/coverage/subscriptionsService.png b/30-qualitaetsheft/assets/coverage/subscriptionsService.png
new file mode 100644
index 0000000..fdb7c9b
--- /dev/null
+++ b/30-qualitaetsheft/assets/coverage/subscriptionsService.png
Binary files differ
diff --git a/30-qualitaetsheft/assets/coverage/util.png b/30-qualitaetsheft/assets/coverage/util.png
new file mode 100644
index 0000000..823cd9e
--- /dev/null
+++ b/30-qualitaetsheft/assets/coverage/util.png
Binary files differ
diff --git a/30-qualitaetsheft/assets/lasttest/goodSpecsApdex.png b/30-qualitaetsheft/assets/lasttest/goodSpecsApdex.png
new file mode 100644
index 0000000..17a7031
--- /dev/null
+++ b/30-qualitaetsheft/assets/lasttest/goodSpecsApdex.png
Binary files differ
diff --git a/30-qualitaetsheft/assets/lasttest/goodSpecsResponse.png b/30-qualitaetsheft/assets/lasttest/goodSpecsResponse.png
new file mode 100644
index 0000000..ca737f4
--- /dev/null
+++ b/30-qualitaetsheft/assets/lasttest/goodSpecsResponse.png
Binary files differ
diff --git a/30-qualitaetsheft/assets/lasttest/goodSpecsTable.png b/30-qualitaetsheft/assets/lasttest/goodSpecsTable.png
new file mode 100644
index 0000000..c247933
--- /dev/null
+++ b/30-qualitaetsheft/assets/lasttest/goodSpecsTable.png
Binary files differ
diff --git a/30-qualitaetsheft/assets/lasttest/minimumSpecsApdex.png b/30-qualitaetsheft/assets/lasttest/minimumSpecsApdex.png
new file mode 100644
index 0000000..f326e01
--- /dev/null
+++ b/30-qualitaetsheft/assets/lasttest/minimumSpecsApdex.png
Binary files differ
diff --git a/30-qualitaetsheft/assets/lasttest/minimumSpecsResponse.png b/30-qualitaetsheft/assets/lasttest/minimumSpecsResponse.png
new file mode 100644
index 0000000..c6d27ff
--- /dev/null
+++ b/30-qualitaetsheft/assets/lasttest/minimumSpecsResponse.png
Binary files differ
diff --git a/30-qualitaetsheft/assets/lasttest/minimumSpecsTable.png b/30-qualitaetsheft/assets/lasttest/minimumSpecsTable.png
new file mode 100644
index 0000000..db077cd
--- /dev/null
+++ b/30-qualitaetsheft/assets/lasttest/minimumSpecsTable.png
Binary files differ
diff --git a/30-qualitaetsheft/assets/logo.pdf b/30-qualitaetsheft/assets/logo.pdf
new file mode 100644
index 0000000..91fd334
--- /dev/null
+++ b/30-qualitaetsheft/assets/logo.pdf
Binary files differ
diff --git a/30-qualitaetsheft/assets/logo.svg b/30-qualitaetsheft/assets/logo.svg
new file mode 100644
index 0000000..1609066
--- /dev/null
+++ b/30-qualitaetsheft/assets/logo.svg
@@ -0,0 +1,211 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ version="1.2"
+ width="87.589989mm"
+ height="52.16547mm"
+ viewBox="0 0 8758.9989 5216.547"
+ preserveAspectRatio="xMidYMid"
+ fill-rule="evenodd"
+ stroke-width="28.222"
+ stroke-linejoin="round"
+ xml:space="preserve"
+ id="svg206"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg">
+ <defs
+ class="ClipPathGroup"
+ id="defs8" />
+ <defs
+ id="defs51"><font
+ id="EmbeddedFont_1"
+ horiz-adv-x="2048"
+ horiz-origin-x="0"
+ horiz-origin-y="0"
+ vert-origin-x="512"
+ vert-origin-y="768"
+ vert-adv-y="1024">
+ <font-face
+ font-family="Noto Sans Display Light embedded"
+ units-per-em="2048"
+ font-weight="normal"
+ font-style="normal"
+ ascent="2170"
+ descent="609"
+ id="font-face10" />
+ <missing-glyph
+ horiz-adv-x="2048"
+ d="M 0,0 L 2047,0 2047,2047 0,2047 0,0 Z"
+ id="missing-glyph12" />
+ <glyph
+ unicode="y"
+ horiz-adv-x="927"
+ d="M 2,1089 L 127,1089 367,413 C 388,352 407,298 422,250 437,203 449,161 457,124 L 463,124 C 471,156 483,196 498,246 513,296 530,350 551,409 L 786,1089 913,1089 453,-193 C 418,-290 377,-364 328,-416 279,-468 213,-494 131,-494 107,-494 84,-493 63,-490 43,-487 25,-482 8,-476 L 8,-377 C 23,-383 40,-387 57,-391 75,-394 95,-396 117,-396 170,-396 214,-378 249,-342 284,-307 314,-252 340,-179 L 403,4 2,1089 Z"
+ id="glyph14" />
+ <glyph
+ unicode="t"
+ horiz-adv-x="610"
+ d="M 465,80 C 494,80 521,82 547,87 573,91 595,97 614,105 L 614,11 C 594,3 569,-5 541,-11 512,-17 481,-20 449,-20 363,-20 296,5 249,56 202,106 178,189 178,304 L 178,996 27,996 27,1061 178,1100 219,1350 295,1350 295,1090 608,1090 608,996 295,996 295,310 C 295,157 352,80 465,80 Z"
+ id="glyph16" />
+ <glyph
+ unicode="s"
+ horiz-adv-x="742"
+ d="M 817,289 C 817,191 782,115 713,61 643,7 545,-20 418,-20 347,-20 284,-14 228,-1 173,12 126,29 88,50 L 88,162 C 134,138 186,118 244,102 301,86 360,78 420,78 520,78 592,96 636,133 680,169 702,218 702,281 702,341 679,387 632,419 585,451 515,484 422,519 359,542 303,565 255,589 207,613 169,643 142,680 116,717 102,768 102,832 102,919 136,987 204,1037 271,1086 361,1110 473,1110 535,1110 592,1104 646,1092 700,1080 750,1063 795,1043 L 754,946 C 713,964 667,980 617,993 568,1006 518,1012 469,1012 388,1012 326,997 283,967 239,937 217,893 217,836 217,792 228,758 249,733 270,707 301,686 342,668 383,650 433,630 492,609 553,585 608,562 657,537 707,512 745,481 774,443 803,405 817,353 817,289 Z"
+ id="glyph18" />
+ <glyph
+ unicode="r"
+ horiz-adv-x="583"
+ d="M 596,1108 C 646,1108 692,1102 733,1091 L 717,983 C 674,995 632,1001 590,1001 497,1001 423,964 368,890 312,817 285,719 285,598 L 285,-1 168,-1 168,1089 266,1089 279,886 285,886 C 311,948 350,1000 402,1043 455,1086 520,1108 596,1108 Z"
+ id="glyph20" />
+ <glyph
+ unicode="o"
+ horiz-adv-x="927"
+ d="M 1030,547 C 1030,433 1012,333 976,248 940,164 887,98 818,51 749,4 665,-20 565,-20 471,-20 390,3 322,50 253,96 201,162 164,247 127,333 109,433 109,547 109,723 150,861 232,961 315,1061 429,1110 575,1110 672,1110 755,1087 822,1040 890,993 941,927 977,842 1012,757 1030,659 1030,547 Z M 229,547 C 229,407 257,294 312,208 368,123 453,80 567,80 685,80 771,123 826,209 882,295 909,408 909,547 909,637 898,717 875,787 851,856 815,911 766,951 717,990 653,1010 573,1010 459,1010 373,969 315,887 258,805 229,692 229,547 Z"
+ id="glyph22" />
+ <glyph
+ unicode="n"
+ horiz-adv-x="847"
+ d="M 633,1110 C 749,1110 838,1078 900,1014 962,950 993,850 993,713 L 993,1 877,1 877,705 C 877,809 854,885 810,935 766,985 701,1010 616,1010 395,1010 285,871 285,594 L 285,1 168,1 168,1090 262,1090 279,901 287,901 C 314,962 357,1011 416,1051 474,1091 547,1110 633,1110 Z"
+ id="glyph24" />
+ <glyph
+ unicode="m"
+ horiz-adv-x="1430"
+ d="M 1245,1110 C 1348,1110 1427,1080 1485,1018 1542,957 1571,860 1571,727 L 1571,1 1454,1 1454,723 C 1454,820 1434,892 1393,939 1352,986 1296,1010 1227,1010 1130,1010 1056,980 1005,919 953,858 928,764 928,637 L 928,1 811,1 811,723 C 811,820 791,892 750,939 709,986 653,1010 584,1010 487,1010 413,978 361,914 310,850 285,751 285,619 L 285,1 168,1 168,1090 262,1090 279,918 287,918 C 313,971 352,1016 403,1054 455,1092 521,1110 600,1110 675,1110 739,1093 791,1059 842,1025 879,975 899,908 L 907,908 C 936,972 980,1022 1038,1057 1097,1093 1166,1110 1245,1110 Z"
+ id="glyph26" />
+ <glyph
+ unicode="i"
+ horiz-adv-x="187"
+ d="M 227,1493 C 279,1493 305,1464 305,1405 305,1345 279,1315 227,1315 175,1315 150,1345 150,1405 150,1464 175,1493 227,1493 Z M 285,1090 L 285,0 168,0 168,1090 285,1090 Z"
+ id="glyph28" />
+ <glyph
+ unicode="h"
+ horiz-adv-x="847"
+ d="M 285,1059 C 285,1031 284,1003 283,977 281,951 279,926 276,901 L 285,901 C 312,962 355,1011 413,1051 471,1091 543,1110 629,1110 746,1110 836,1078 899,1014 962,950 993,850 993,713 L 993,1 877,1 877,705 C 877,809 854,885 810,935 766,985 701,1010 616,1010 395,1010 285,871 285,594 L 285,1 168,1 168,1557 285,1557 285,1059 Z"
+ id="glyph30" />
+ <glyph
+ unicode="f"
+ horiz-adv-x="689"
+ d="M 575,995 L 332,995 332,-1 213,-1 213,995 27,995 27,1058 213,1093 213,1202 C 213,1445 316,1566 522,1566 559,1566 593,1563 623,1557 653,1551 680,1544 705,1536 L 678,1439 C 655,1448 630,1454 603,1460 577,1465 550,1468 524,1468 456,1468 407,1447 377,1405 347,1362 332,1295 332,1202 L 332,1089 575,1089 575,995 Z"
+ id="glyph32" />
+ <glyph
+ unicode="e"
+ horiz-adv-x="874"
+ d="M 559,1110 C 646,1110 720,1089 779,1046 839,1003 883,944 913,869 943,794 958,708 958,611 L 958,531 229,531 C 231,386 262,275 325,198 387,121 476,82 592,82 656,82 712,88 759,100 806,111 858,130 915,156 L 915,50 C 865,25 814,7 764,-4 713,-15 655,-20 588,-20 434,-20 315,30 232,129 150,229 109,365 109,537 109,648 126,746 162,832 197,918 249,986 315,1036 382,1085 464,1110 559,1110 Z M 559,1012 C 465,1012 389,979 333,912 276,845 243,750 233,627 L 838,627 C 838,742 815,835 769,906 723,977 653,1012 559,1012 Z"
+ id="glyph34" />
+ <glyph
+ unicode="d"
+ horiz-adv-x="900"
+ d="M 535,-20 C 398,-20 293,27 219,120 145,214 109,352 109,535 109,722 147,865 224,963 301,1061 408,1110 545,1110 629,1110 698,1090 752,1050 805,1010 845,961 872,904 L 881,904 C 879,935 878,970 876,1009 873,1048 872,1084 872,1117 L 872,1557 989,1557 989,0 895,0 879,191 872,191 C 845,132 805,82 751,41 697,0 625,-20 535,-20 Z M 553,80 C 669,80 752,119 801,195 850,271 875,382 875,527 L 875,545 C 875,695 850,810 801,890 752,970 671,1010 559,1010 451,1010 369,969 313,886 257,804 229,686 229,533 229,385 256,273 309,196 363,119 444,80 553,80 Z"
+ id="glyph36" />
+ <glyph
+ unicode="c"
+ horiz-adv-x="768"
+ d="M 580,-20 C 429,-20 313,29 231,127 150,226 109,363 109,539 109,662 129,766 170,850 211,935 269,1000 343,1044 417,1088 504,1110 602,1110 651,1110 698,1106 742,1096 787,1087 825,1074 858,1057 L 825,957 C 791,972 754,984 714,993 673,1002 636,1006 600,1006 481,1006 390,964 326,881 261,798 229,685 229,541 229,405 258,294 314,210 371,126 459,84 580,84 630,84 678,90 723,101 768,112 809,125 846,142 L 846,37 C 812,20 773,6 729,-5 685,-15 636,-20 580,-20 Z"
+ id="glyph38" />
+ <glyph
+ unicode="a"
+ horiz-adv-x="822"
+ d="M 535,1108 C 651,1108 737,1078 795,1018 852,958 881,863 881,734 L 881,0 793,0 772,185 766,185 C 729,123 684,74 631,36 578,-1 503,-20 408,-20 311,-20 233,6 176,59 119,111 90,187 90,285 90,394 132,477 215,533 298,589 420,621 580,629 L 764,639 764,715 C 764,822 744,897 705,942 665,987 606,1010 528,1010 477,1010 426,1002 378,987 329,972 281,953 231,928 L 195,1022 C 242,1047 295,1067 352,1084 410,1100 470,1108 535,1108 Z M 594,543 C 466,536 370,512 307,470 244,429 213,367 213,285 213,217 232,165 271,131 310,96 363,78 430,78 535,78 617,111 676,176 735,240 764,330 764,445 L 764,551 594,543 Z"
+ id="glyph40" />
+ <glyph
+ unicode="S"
+ horiz-adv-x="875"
+ d="M 956,381 C 956,294 936,220 894,160 852,100 796,55 724,25 652,-5 571,-20 479,-20 396,-20 324,-14 262,-2 201,11 147,26 102,46 L 102,162 C 152,142 209,124 273,109 338,94 409,87 485,87 589,87 673,110 738,158 803,206 836,278 836,373 836,431 823,478 798,515 772,553 734,586 682,614 630,642 565,670 485,699 410,726 345,757 291,791 236,825 194,868 164,919 134,970 119,1035 119,1112 119,1192 138,1259 176,1314 214,1369 267,1411 333,1440 399,1469 474,1483 559,1483 626,1483 689,1476 750,1463 810,1449 868,1430 924,1405 L 883,1303 C 772,1352 663,1377 555,1377 462,1377 386,1354 328,1310 269,1266 240,1200 240,1114 240,1052 252,1001 278,964 303,926 340,895 389,869 438,843 498,817 567,791 648,762 717,731 775,698 833,664 878,623 909,573 941,523 956,459 956,381 Z"
+ id="glyph42" />
+ <glyph
+ unicode="P"
+ horiz-adv-x="848"
+ d="M 539,1462 C 869,1462 1034,1325 1034,1049 1034,908 992,798 907,718 823,638 690,598 510,598 L 311,598 311,0 193,0 193,1462 539,1462 Z M 528,1358 L 311,1358 311,702 498,702 C 629,702 730,727 803,776 875,825 911,914 911,1043 911,1152 880,1232 818,1282 756,1333 659,1358 528,1358 Z"
+ id="glyph44" />
+ <glyph
+ unicode="E"
+ horiz-adv-x="769"
+ d="M 950,0 L 193,0 193,1462 950,1462 950,1356 311,1356 311,821 913,821 913,715 311,715 311,107 950,107 950,0 Z"
+ id="glyph46" />
+ <glyph
+ unicode=" "
+ horiz-adv-x="503"
+ id="glyph48" />
+ </font></defs>
+ <defs
+ class="TextShapeIndex"
+ id="defs55" />
+ <defs
+ class="EmbeddedBulletChars"
+ id="defs87" />
+
+ <g
+ id="id10"
+ clip-path="none"
+ transform="translate(-700.00001,-2550)">
+
+ <text
+ class="SVGTextShape"
+ id="text151"
+ x="217.60002"
+ y="-56.506969"
+ style="letter-spacing:4.7625px;word-spacing:104.775px"><tspan
+ class="TextParagraph"
+ font-family="'Noto Sans Display Light', sans-serif"
+ font-size="494px"
+ font-weight="400"
+ id="tspan149"><tspan
+ class="TextPosition"
+ x="650.59998"
+ y="7647.4932"
+ id="tspan147"><tspan
+ fill="#808080"
+ stroke="none"
+ style="white-space:pre"
+ id="tspan145"
+ dx="2.1199999">Podcast Synchronisation made Efficient</tspan></tspan></tspan></text>
+ </g><g
+ id="g1277"
+ transform="translate(-700.00001,-2550)"><path
+ id="path131-3"
+ d="m 6694.0006,4763 c -559.5515,4.407 -980.3924,428.0893 -986.038,985.9863 18.2894,552.8957 454.3127,974.1166 989.0352,986.0379 v -235.0244 c -406.8751,-27.3888 -715.1078,-362.1649 -719.0259,-748.0163 12.7874,-421.0793 236.9242,-746.3999 750.0318,-749.98 895.0688,1.4728 1915.5158,0 2730.9957,0 V 4763 Z"
+ style="fill:#0084d1;fill-opacity:1"
+ clip-path="none" /><path
+ id="path131"
+ d="m 6685.0183,2562.996 c -559.5515,4.407 -980.3924,428.0893 -986.038,985.9863 18.2894,552.8957 454.3127,974.1167 989.0352,986.038 v -235.0244 c -406.8751,-27.3888 -715.1078,-362.165 -719.0259,-748.0164 12.7874,-421.0792 236.9242,-746.3998 750.0318,-749.98 895.0688,1.4728 1915.5158,0 2730.996,0 V 2562.996 Z"
+ style="fill:#0084d1;fill-opacity:1"
+ clip-path="none" /></g><g
+ id="g1263"
+ transform="translate(-700.00001,-2550)"><path
+ fill="none"
+ stroke="#069a2e"
+ stroke-width="265"
+ stroke-linejoin="round"
+ d="m 2793,5962 c 1283,0 429,-2762 1712,-2762"
+ id="path124" /><path
+ id="path110-6"
+ d="M 3198.0212,6550 V 6300.0411 H 2448.0411 V 6050.0305 5550.0094 H 2198.0305 V 6300.0411 6550 H 2448.0411 2698 Z"
+ style="fill:#069a2e;fill-opacity:1" /><path
+ id="path110"
+ d="m 4111.997,2550.0252 v 249.9589 h 749.9801 v 250.0106 500.0211 h 250.0106 v -750.0317 -249.9589 h -250.0106 -249.9589 z"
+ style="fill:#069a2e;fill-opacity:1" /></g>
+ <g
+ id="g1249"
+ transform="translate(-700.00001,-2550)"><path
+ fill="#ff8000"
+ stroke="none"
+ d="M 2215,4164 C 2412.6918,3832.6035 2379.3124,3383.7591 2135.4189,3084.8193 1956.8564,2857.4026 1671.3097,2718.8851 1382,2721 c 0,-52.6667 0,-105.3333 0,-158 -60.1303,-1.0792 190.6585,-1.2724 121.9814,2.7933 434.6311,30.3756 832.6257,336.7309 974.9655,748.2365 148.7336,402.6249 41.0263,883.7477 -266.0719,1183.8452 C 1996.6852,4716.1853 1689.0048,4838.6187 1382,4830 c 0,-61.6667 0,-123.3333 0,-185 338.199,2.9253 666.226,-186.816 833,-481 z"
+ id="path193" /><path
+ fill="#ff8000"
+ stroke="none"
+ d="m 1936,3979 c 175.8129,-283.3241 59.7943,-700.6319 -239.8255,-849.407 -94.2713,-50.9942 -201.887,-77.9344 -309.1745,-74.593 0,-57 0,-114 0,-171 396.3865,-24.0968 777.5367,297.6517 818.5878,693.1841 44.0348,337.5467 -149.4277,694.9971 -466.4953,826.9493 -110.1027,49.0687 -231.5272,73.543 -352.0925,67.8666 0,-61.6667 0,-123.3333 0,-185 220.6353,7.5804 440.8554,-115.3286 549,-308 z"
+ id="path186" /><path
+ fill="#ff8000"
+ stroke="none"
+ d="m 1659,3822 c 86.3933,-138.0398 18.2474,-344.669 -134.6962,-402.3205 C 1483.44,3402.2177 1438.3524,3394.2432 1394,3398 c 0,-56.6667 0,-113.3333 0,-170 223.1964,-19.6143 444.7886,153.3254 478.4886,375.1817 32.646,181.6951 -54.6854,381.4331 -217.3127,472.2205 -78.2316,46.131 -170.3991,69.3119 -261.1759,62.5978 0,-58.3333 0,-116.6667 0,-175 105.6736,9.5509 212.8962,-49.2218 265,-141 z"
+ id="path179" /><rect
+ class="BoundingBox"
+ stroke="none"
+ fill="none"
+ x="700"
+ y="2550"
+ width="501"
+ height="4001"
+ id="rect136"
+ style="fill:#ff8000;fill-opacity:1" /></g>
+
+</svg>
diff --git a/30-qualitaetsheft/assets/notifications.png b/30-qualitaetsheft/assets/notifications.png
new file mode 100644
index 0000000..1a5b81d
--- /dev/null
+++ b/30-qualitaetsheft/assets/notifications.png
Binary files differ
diff --git a/30-qualitaetsheft/assets/select-subscriptions.png b/30-qualitaetsheft/assets/select-subscriptions.png
new file mode 100644
index 0000000..0595397
--- /dev/null
+++ b/30-qualitaetsheft/assets/select-subscriptions.png
Binary files differ
diff --git a/30-qualitaetsheft/assets/sources/checkstyle-after-processed.txt b/30-qualitaetsheft/assets/sources/checkstyle-after-processed.txt
new file mode 100644
index 0000000..8bb59fa
--- /dev/null
+++ b/30-qualitaetsheft/assets/sources/checkstyle-after-processed.txt
@@ -0,0 +1 @@
+1 (design) HideUtilityClassConstructor
diff --git a/30-qualitaetsheft/assets/sources/checkstyle-after.txt b/30-qualitaetsheft/assets/sources/checkstyle-after.txt
new file mode 100644
index 0000000..cec00d5
--- /dev/null
+++ b/30-qualitaetsheft/assets/sources/checkstyle-after.txt
@@ -0,0 +1,22 @@
+[INFO] Scanning for projects...
+[INFO]
+[INFO] -----------------------< org.pse-squared:server >-----------------------
+[INFO] Building server 0.0.1-SNAPSHOT
+[INFO] --------------------------------[ jar ]---------------------------------
+[INFO]
+[INFO] --- maven-checkstyle-plugin:3.2.1:check (default-cli) @ server ---
+[INFO] There is 1 error reported by Checkstyle 9.3 with sun_checks.xml ruleset.
+[ERROR] src/main/java/org/psesquared/server/ServerApplication.java:[12,1] (design) HideUtilityClassConstructor: Hilfsklassen sollten keinen Standard-Konstruktur und keinen als public deklarierten Konstruktor haben.
+[INFO] ------------------------------------------------------------------------
+[INFO] BUILD FAILURE
+[INFO] ------------------------------------------------------------------------
+[INFO] Total time: 14.432 s
+[INFO] Finished at: 2023-03-18T08:30:11+01:00
+[INFO] ------------------------------------------------------------------------
+[ERROR] Failed to execute goal org.apache.maven.plugins:maven-checkstyle-plugin:3.2.1:check (default-cli) on project server: You have 1 Checkstyle violation. -> [Help 1]
+[ERROR]
+[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
+[ERROR] Re-run Maven using the -X switch to enable full debug logging.
+[ERROR]
+[ERROR] For more information about the errors and possible solutions, please read the following articles:
+[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException
diff --git a/30-qualitaetsheft/assets/sources/checkstyle-before-processed.txt b/30-qualitaetsheft/assets/sources/checkstyle-before-processed.txt
new file mode 100644
index 0000000..3a5af1a
--- /dev/null
+++ b/30-qualitaetsheft/assets/sources/checkstyle-before-processed.txt
@@ -0,0 +1,23 @@
+285 (sizes) LineLength
+143 (misc) FinalParameters
+101 (javadoc) JavadocVariable
+83 (javadoc) JavadocStyle
+43 (design) DesignForExtension
+39 (javadoc) MissingJavadocMethod
+26 (regexp) RegexpSingleline
+15 (whitespace) WhitespaceAround
+13 (javadoc) JavadocPackage
+10 (whitespace) OperatorWrap
+10 (javadoc) JavadocType
+7 (imports) AvoidStarImport
+6 (coding) MagicNumber
+4 (javadoc) JavadocMethod
+3 (coding) HiddenField
+2 (javadoc) InvalidJavadocPosition
+2 (design) HideUtilityClassConstructor
+2 (blocks) RightCurly
+1 (whitespace) WhitespaceAfter
+1 (whitespace) FileTabCharacter
+1 (misc) NewlineAtEndOfFile
+1 (misc) ArrayTypeStyle
+1 (imports) UnusedImports
diff --git a/30-qualitaetsheft/assets/sources/checkstyle-before.txt b/30-qualitaetsheft/assets/sources/checkstyle-before.txt
new file mode 100644
index 0000000..abc9f4f
--- /dev/null
+++ b/30-qualitaetsheft/assets/sources/checkstyle-before.txt
@@ -0,0 +1,820 @@
+[INFO] Scanning for projects...
+[INFO]
+[INFO] -----------------------< org.pse-squared:server >-----------------------
+[INFO] Building server 0.0.1-SNAPSHOT
+[INFO] --------------------------------[ jar ]---------------------------------
+[INFO]
+[INFO] --- maven-checkstyle-plugin:3.2.1:check (default-cli) @ server ---
+[INFO] There are 799 errors reported by Checkstyle 9.3 with sun_checks.xml ruleset.
+[ERROR] src/main/java/org/psesquared/server/config/AuthenticationValidatorInterceptor.java:[1] (javadoc) JavadocPackage: Es fehlt eine package-info.java.
+[ERROR] src/main/java/org/psesquared/server/config/AuthenticationValidatorInterceptor.java:[15,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/config/AuthenticationValidatorInterceptor.java:[16,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/config/AuthenticationValidatorInterceptor.java:[17,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/config/AuthenticationValidatorInterceptor.java:[18,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/config/AuthenticationValidatorInterceptor.java:[20,5] (design) DesignForExtension: Klasse 'AuthenticationValidatorInterceptor' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'preHandle' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'AuthenticationValidatorInterceptor' final oder die Methode 'preHandle' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/config/AuthenticationValidatorInterceptor.java:[21,30] (misc) FinalParameters: Der Parameter request sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/config/AuthenticationValidatorInterceptor.java:[22,13] (misc) FinalParameters: Der Parameter response sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/config/AuthenticationValidatorInterceptor.java:[23,13] (misc) FinalParameters: Der Parameter handler sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/config/AuthenticationValidatorInterceptor.java:[25] (sizes) LineLength: Zeile ist 81 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/config/AuthenticationValidatorInterceptor.java:[26] (sizes) LineLength: Zeile ist 113 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/config/AuthenticationValidatorInterceptor.java:[44,48] (misc) FinalParameters: Der Parameter request sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/config/AuthenticationValidatorInterceptor.java:[45] (sizes) LineLength: Zeile ist 117 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/config/AuthenticationValidatorInterceptor.java:[46] (sizes) LineLength: Zeile ist 101 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/config/AuthenticationValidatorInterceptor.java:[49] (sizes) LineLength: Zeile ist 90 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/config/SecurityConfigProperties.java:[6] (sizes) LineLength: Zeile ist 87 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/config/SecurityConfigProperties.java:[6,86] (whitespace) WhitespaceAround: Nach '{' fehlt ein Leerzeichen.
+[ERROR] src/main/java/org/psesquared/server/config/SecurityConfigProperties.java:[6,87] (whitespace) WhitespaceAround: Vor '}' fehlt ein Leerzeichen.
+[ERROR] src/main/java/org/psesquared/server/config/EMailConfigProperties.java:[6] (sizes) LineLength: Zeile ist 108 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/config/EMailConfigProperties.java:[6,107] (whitespace) WhitespaceAround: Nach '{' fehlt ein Leerzeichen.
+[ERROR] src/main/java/org/psesquared/server/config/EMailConfigProperties.java:[6,108] (whitespace) WhitespaceAround: Vor '}' fehlt ein Leerzeichen.
+[ERROR] src/main/java/org/psesquared/server/config/SecurityConfig.java:[22,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/config/SecurityConfig.java:[23,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/config/SecurityConfig.java:[24] (sizes) LineLength: Zeile ist 82 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/config/SecurityConfig.java:[24,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/config/SecurityConfig.java:[25] (sizes) LineLength: Zeile ist 97 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/config/SecurityConfig.java:[25,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/config/SecurityConfig.java:[27,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/config/SecurityConfig.java:[28,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/config/SecurityConfig.java:[30,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/config/SecurityConfig.java:[30,5] (design) DesignForExtension: Klasse 'SecurityConfig' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'securityFilterChain' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'SecurityConfig' final oder die Methode 'securityFilterChain' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/config/SecurityConfig.java:[31] (sizes) LineLength: Zeile ist 88 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/config/SecurityConfig.java:[31,52] (misc) FinalParameters: Der Parameter http sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/config/SecurityConfig.java:[48] (sizes) LineLength: Zeile ist 91 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/config/SecurityConfig.java:[56,5] (design) DesignForExtension: Klasse 'SecurityConfig' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'corsConfigurationSource' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'SecurityConfig' final oder die Methode 'corsConfigurationSource' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/config/SecurityConfig.java:[63] (sizes) LineLength: Zeile ist 87 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[3,23] (imports) AvoidStarImport: Stern-Importe der Form '.*' sollten vermieden werden - io.jsonwebtoken.*.
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[21,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[22] (sizes) LineLength: Zeile ist 92 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[22,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[24,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[26,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[26,5] (design) DesignForExtension: Klasse 'JwtService' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'extractUsername' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'JwtService' final oder die Methode 'extractUsername' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[26,35] (misc) FinalParameters: Der Parameter token sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[30,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[30,5] (design) DesignForExtension: Klasse 'JwtService' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'extractClaim' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'JwtService' final oder die Methode 'extractClaim' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[30,31] (misc) FinalParameters: Der Parameter token sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[30,45] (misc) FinalParameters: Der Parameter claimsResolver sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[36] (regexp) RegexpSingleline: Line has trailing spaces.
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[41] (sizes) LineLength: Zeile ist 122 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[41,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[41,5] (design) DesignForExtension: Klasse 'JwtService' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'generateTokenString' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'JwtService' final oder die Methode 'generateTokenString' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[41,39] (misc) FinalParameters: Der Parameter additionalClaims sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[41,77] (misc) FinalParameters: Der Parameter userDetails sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[41,102] (misc) FinalParameters: Der Parameter tokenLifespan sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[46] (sizes) LineLength: Zeile ist 84 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[51,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[51,5] (design) DesignForExtension: Klasse 'JwtService' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'generateAccessTokenString' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'JwtService' final oder die Methode 'generateAccessTokenString' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[53] (sizes) LineLength: Zeile ist 95 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[56,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[56,5] (design) DesignForExtension: Klasse 'JwtService' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'generateUrlTokenString' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'JwtService' final oder die Methode 'generateUrlTokenString' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[57] (sizes) LineLength: Zeile ist 92 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[60,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[60,5] (design) DesignForExtension: Klasse 'JwtService' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'isTokenValid' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'JwtService' final oder die Methode 'isTokenValid' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[60,33] (misc) FinalParameters: Der Parameter token sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[60,47] (misc) FinalParameters: Der Parameter userDetails sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[62] (sizes) LineLength: Zeile ist 84 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[65,36] (misc) FinalParameters: Der Parameter token sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[69,36] (misc) FinalParameters: Der Parameter token sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[73,37] (misc) FinalParameters: Der Parameter token sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[88] (sizes) LineLength: Zeile ist 91 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/config/JwtAuthenticationFilter.java:[26,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/config/JwtAuthenticationFilter.java:[27,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/config/JwtAuthenticationFilter.java:[28] (sizes) LineLength: Zeile ist 82 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/config/JwtAuthenticationFilter.java:[28,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/config/JwtAuthenticationFilter.java:[29] (sizes) LineLength: Zeile ist 97 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/config/JwtAuthenticationFilter.java:[29,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/config/JwtAuthenticationFilter.java:[30,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/config/JwtAuthenticationFilter.java:[32,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/config/JwtAuthenticationFilter.java:[33,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/config/JwtAuthenticationFilter.java:[35,5] (design) DesignForExtension: Klasse 'JwtAuthenticationFilter' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'doFilterInternal' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'JwtAuthenticationFilter' final oder die Methode 'doFilterInternal' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/config/JwtAuthenticationFilter.java:[36,37] (misc) FinalParameters: Der Parameter request sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/config/JwtAuthenticationFilter.java:[37,37] (misc) FinalParameters: Der Parameter response sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/config/JwtAuthenticationFilter.java:[38,37] (misc) FinalParameters: Der Parameter filterChain sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/config/JwtAuthenticationFilter.java:[45] (sizes) LineLength: Zeile ist 96 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/config/JwtAuthenticationFilter.java:[54] (sizes) LineLength: Zeile ist 81 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/config/JwtAuthenticationFilter.java:[54,38] (misc) FinalParameters: Der Parameter cookie sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/config/JwtAuthenticationFilter.java:[54,53] (misc) FinalParameters: Der Parameter request sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/config/JwtAuthenticationFilter.java:[68] (sizes) LineLength: Zeile ist 95 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/config/JwtAuthenticationFilter.java:[69,13] (whitespace) WhitespaceAfter: Nach 'if' fehlt ein Leerzeichen.
+[ERROR] src/main/java/org/psesquared/server/config/JwtAuthenticationFilter.java:[70] (sizes) LineLength: Zeile ist 104 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/config/JwtAuthenticationFilter.java:[76] (sizes) LineLength: Zeile ist 82 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/config/ApplicationConfig.java:[32] (sizes) LineLength: Zeile ist 98 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/config/ApplicationConfig.java:[32,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/config/ApplicationConfig.java:[34,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/config/ApplicationConfig.java:[36,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/config/ApplicationConfig.java:[36,5] (design) DesignForExtension: Klasse 'ApplicationConfig' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'userDetailsService' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'ApplicationConfig' final oder die Methode 'userDetailsService' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/config/ApplicationConfig.java:[39] (sizes) LineLength: Zeile ist 94 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/config/ApplicationConfig.java:[42,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/config/ApplicationConfig.java:[42,5] (design) DesignForExtension: Klasse 'ApplicationConfig' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'authenticationProvider' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'ApplicationConfig' final oder die Methode 'authenticationProvider' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/config/ApplicationConfig.java:[44] (sizes) LineLength: Zeile ist 81 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/config/ApplicationConfig.java:[50,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/config/ApplicationConfig.java:[50,5] (design) DesignForExtension: Klasse 'ApplicationConfig' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'passwordEncoder' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'ApplicationConfig' final oder die Methode 'passwordEncoder' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/config/ApplicationConfig.java:[55,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/config/ApplicationConfig.java:[55,5] (design) DesignForExtension: Klasse 'ApplicationConfig' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'authenticationManager' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'ApplicationConfig' final oder die Methode 'authenticationManager' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/config/ApplicationConfig.java:[56] (sizes) LineLength: Zeile ist 109 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/config/ApplicationConfig.java:[56,56] (misc) FinalParameters: Der Parameter config sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/config/ApplicationConfig.java:[60,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/config/ApplicationConfig.java:[60,5] (design) DesignForExtension: Klasse 'ApplicationConfig' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'corsConfigurer' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'ApplicationConfig' final oder die Methode 'corsConfigurer' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/config/ApplicationConfig.java:[64,41] (misc) FinalParameters: Der Parameter registry sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/config/ApplicationConfig.java:[73,5] (design) DesignForExtension: Klasse 'ApplicationConfig' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'addInterceptors' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'ApplicationConfig' final oder die Methode 'addInterceptors' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/config/ApplicationConfig.java:[74,33] (misc) FinalParameters: Der Parameter registry sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/model/Subscription.java:[1] (javadoc) JavadocPackage: Es fehlt eine package-info.java.
+[ERROR] src/main/java/org/psesquared/server/model/Subscription.java:[24] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/Subscription.java:[33] (sizes) LineLength: Zeile ist 105 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/model/Subscription.java:[36] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/Subscription.java:[45] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/Subscription.java:[51] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/Subscription.java:[57] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/Subscription.java:[63,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/model/Subscription.java:[68] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/Subscription.java:[75,9] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/model/Subscription.java:[75,9] (design) DesignForExtension: Klasse 'Subscription' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'addEpisode' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'Subscription' final oder die Methode 'addEpisode' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/model/Subscription.java:[75,32] (misc) FinalParameters: Der Parameter episode sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/model/Role.java:[3] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/Role.java:[8] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/Role.java:[12] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/Role.java:[17,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/model/EpisodeAction.java:[22] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/EpisodeAction.java:[33] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/EpisodeAction.java:[42] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/EpisodeAction.java:[49] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/EpisodeAction.java:[56] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/EpisodeAction.java:[64] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/EpisodeAction.java:[73] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/EpisodeAction.java:[80] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/EpisodeAction.java:[88] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/EpisodeAction.java:[92] (javadoc) JavadocMethod: @return-Tag sollte vorhanden sein und eine Beschreibung haben.
+[ERROR] src/main/java/org/psesquared/server/model/EpisodeAction.java:[93] (sizes) LineLength: Zeile ist 81 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/model/EpisodeAction.java:[98] (sizes) LineLength: Zeile ist 95 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/model/SubscriptionAction.java:[16] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/SubscriptionAction.java:[27] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/SubscriptionAction.java:[36] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/SubscriptionAction.java:[42] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/SubscriptionAction.java:[50] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/SubscriptionAction.java:[56] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/User.java:[6,27] (imports) AvoidStarImport: Stern-Importe der Form '.*' sollten vermieden werden - jakarta.persistence.*.
+[ERROR] src/main/java/org/psesquared/server/model/User.java:[15] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/User.java:[26] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/User.java:[35] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/User.java:[44] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/User.java:[52] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/User.java:[59] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/User.java:[66] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/User.java:[74] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/User.java:[81] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/User.java:[88] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/User.java:[95,5] (design) DesignForExtension: Klasse 'User' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'getAuthorities' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'User' final oder die Methode 'getAuthorities' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/model/User.java:[100,5] (design) DesignForExtension: Klasse 'User' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'isAccountNonExpired' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'User' final oder die Methode 'isAccountNonExpired' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/model/User.java:[105,5] (design) DesignForExtension: Klasse 'User' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'isAccountNonLocked' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'User' final oder die Methode 'isAccountNonLocked' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/model/User.java:[110,5] (design) DesignForExtension: Klasse 'User' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'isCredentialsNonExpired' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'User' final oder die Methode 'isCredentialsNonExpired' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/model/Action.java:[5] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/Action.java:[7] (regexp) RegexpSingleline: Line has trailing spaces.
+[ERROR] src/main/java/org/psesquared/server/model/Action.java:[10] (regexp) RegexpSingleline: Line has trailing spaces.
+[ERROR] src/main/java/org/psesquared/server/model/Action.java:[11,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/model/Action.java:[12,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/model/Action.java:[13,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/model/Action.java:[14,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/model/Action.java:[15,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/model/Action.java:[17,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/model/Episode.java:[19] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/Episode.java:[30] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/Episode.java:[38] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/Episode.java:[44] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/Episode.java:[50] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/Episode.java:[56] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/Episode.java:[62] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/Episode.java:[68] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/util/UpdateURLsWrapper.java:[1] (javadoc) JavadocPackage: Es fehlt eine package-info.java.
+[ERROR] src/main/java/org/psesquared/server/util/UpdateURLsWrapper.java:[10] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/util/UpdateURLsWrapper.java:[15,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/util/UpdateURLsWrapper.java:[16,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/util/UpdateURLsWrapper.java:[18] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/util/UpdateURLsWrapper.java:[26,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/util/UpdateURLsWrapper.java:[26,5] (design) DesignForExtension: Klasse 'UpdateURLsWrapper' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'getTimestamp' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'UpdateURLsWrapper' final oder die Methode 'getTimestamp' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/util/UpdateURLsWrapper.java:[30,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/util/UpdateURLsWrapper.java:[30,5] (design) DesignForExtension: Klasse 'UpdateURLsWrapper' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'getUpdateURLs' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'UpdateURLsWrapper' final oder die Methode 'getUpdateURLs' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/util/Scheduler.java:[10] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/util/Scheduler.java:[16,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/util/Scheduler.java:[19] (sizes) LineLength: Zeile ist 137 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/util/Scheduler.java:[24] (sizes) LineLength: Zeile ist 126 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/util/Scheduler.java:[24,112] (coding) MagicNumber: Die magische Zahl '24' sollte als Konstante definiert werden.
+[ERROR] src/main/java/org/psesquared/server/util/Scheduler.java:[24,117] (coding) MagicNumber: Die magische Zahl '60' sollte als Konstante definiert werden.
+[ERROR] src/main/java/org/psesquared/server/util/Scheduler.java:[24,122] (coding) MagicNumber: Die magische Zahl '60' sollte als Konstante definiert werden.
+[ERROR] src/main/java/org/psesquared/server/util/RSSParser.java:[38,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/util/RSSParser.java:[40,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/util/RSSParser.java:[41,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/util/RSSParser.java:[43,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/util/RSSParser.java:[43,5] (design) DesignForExtension: Klasse 'RSSParser' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'validate' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'RSSParser' final oder die Methode 'validate' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/util/RSSParser.java:[44,5] (javadoc) InvalidJavadocPosition: Javadoc-Kommentar ist an der falschen Stelle platziert.
+[ERROR] src/main/java/org/psesquared/server/util/RSSParser.java:[48] (sizes) LineLength: Zeile ist 84 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/util/RSSParser.java:[51] (regexp) RegexpSingleline: Line has trailing spaces.
+[ERROR] src/main/java/org/psesquared/server/util/RSSParser.java:[54,26] (misc) FinalParameters: Der Parameter subscription sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/util/RSSParser.java:[66] (sizes) LineLength: Zeile ist 101 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/util/RSSParser.java:[73] (sizes) LineLength: Zeile ist 89 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/util/RSSParser.java:[87] (sizes) LineLength: Zeile ist 83 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/util/RSSParser.java:[87,56] (misc) FinalParameters: Der Parameter subscription sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/util/RSSParser.java:[126] (sizes) LineLength: Zeile ist 82 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/util/RSSParser.java:[126,34] (misc) FinalParameters: Der Parameter syndEntry sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/util/RSSParser.java:[126,55] (misc) FinalParameters: Der Parameter subscription sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/util/RSSParser.java:[158] (sizes) LineLength: Zeile ist 114 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/util/RSSParser.java:[161] (sizes) LineLength: Zeile ist 95 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/util/RSSParser.java:[161,45] (misc) FinalParameters: Der Parameter episodeURL sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/util/RSSParser.java:[161,64] (misc) FinalParameters: Der Parameter episodes sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/util/RSSParser.java:[168,5] (design) DesignForExtension: Klasse 'RSSParser' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'saveEpisodes' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'RSSParser' final oder die Methode 'saveEpisodes' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/util/RSSParser.java:[169,33] (misc) FinalParameters: Der Parameter episodes sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/util/RSSParser.java:[173,5] (design) DesignForExtension: Klasse 'RSSParser' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'deleteEpisodes' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'RSSParser' final oder die Methode 'deleteEpisodes' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/util/RSSParser.java:[174,35] (misc) FinalParameters: Der Parameter episodes sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/util/RSSParser.java:[179,5] (design) DesignForExtension: Klasse 'RSSParser' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'saveSubscription' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'RSSParser' final oder die Methode 'saveSubscription' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/util/RSSParser.java:[180,37] (misc) FinalParameters: Der Parameter subscription sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/util/RSSParser.java:[184,5] (design) DesignForExtension: Klasse 'RSSParser' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'deleteSubscription' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'RSSParser' final oder die Methode 'deleteSubscription' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/util/RSSParser.java:[185,39] (misc) FinalParameters: Der Parameter subscription sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/util/RSSParser.java:[190,43] (misc) FinalParameters: Der Parameter time sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/util/RSSParser.java:[208,31] (misc) ArrayTypeStyle: Array-Klammern an ungültiger Position.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationResponse.java:[1] (javadoc) JavadocPackage: Es fehlt eine package-info.java.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationResponse.java:[7,1] (javadoc) JavadocType: Im Javadoc des Typs fehlt das Tag @param token.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationResponse.java:[7,52] (whitespace) WhitespaceAround: Nach '{' fehlt ein Leerzeichen.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationResponse.java:[7,53] (whitespace) WhitespaceAround: Vor '}' fehlt ein Leerzeichen.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[9,47] (imports) AvoidStarImport: Stern-Importe der Form '.*' sollten vermieden werden - org.springframework.web.bind.annotation.*.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[15] (sizes) LineLength: Zeile ist 98 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[23,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[25,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[26,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[29] (sizes) LineLength: Zeile ist 117 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[30] (sizes) LineLength: Zeile ist 109 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[31] (sizes) LineLength: Zeile ist 99 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[34] (sizes) LineLength: Zeile ist 91 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[41,36] (misc) FinalParameters: Der Parameter userInfo sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[46] (sizes) LineLength: Zeile ist 118 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[47] (sizes) LineLength: Zeile ist 101 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[51] (sizes) LineLength: Zeile ist 99 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[56] (regexp) RegexpSingleline: Line has trailing spaces.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[60,42] (misc) FinalParameters: Der Parameter username sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[61,42] (misc) FinalParameters: Der Parameter token sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[62] (sizes) LineLength: Zeile ist 81 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[62,42] (misc) FinalParameters: Der Parameter response sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[63] (sizes) LineLength: Zeile ist 86 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[69] (sizes) LineLength: Zeile ist 112 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[71] (sizes) LineLength: Zeile ist 85 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[74] (sizes) LineLength: Zeile ist 89 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[81,29] (misc) FinalParameters: Der Parameter username sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[82,29] (misc) FinalParameters: Der Parameter response sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[87] (sizes) LineLength: Zeile ist 120 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[89] (sizes) LineLength: Zeile ist 85 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[92] (sizes) LineLength: Zeile ist 90 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[99,30] (misc) FinalParameters: Der Parameter username sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[100,30] (misc) FinalParameters: Der Parameter response sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[100,68] (whitespace) WhitespaceAround: Vor '{' fehlt ein Leerzeichen.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[105] (sizes) LineLength: Zeile ist 119 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[108] (sizes) LineLength: Zeile ist 83 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[115,38] (misc) FinalParameters: Der Parameter email sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[119,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[119,5] (design) DesignForExtension: Klasse 'AuthenticationController' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'resetPassword' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'AuthenticationController' final oder die Methode 'resetPassword' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[120,37] (misc) FinalParameters: Der Parameter username sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[121,37] (misc) FinalParameters: Der Parameter token sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[122,37] (misc) FinalParameters: Der Parameter requestBody sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[123] (sizes) LineLength: Zeile ist 81 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[126,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[126,5] (design) DesignForExtension: Klasse 'AuthenticationController' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'changePassword' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'AuthenticationController' final oder die Methode 'changePassword' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[127,38] (misc) FinalParameters: Der Parameter username sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[128] (sizes) LineLength: Zeile ist 86 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[128,38] (misc) FinalParameters: Der Parameter requestBody sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[132,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[132,5] (design) DesignForExtension: Klasse 'AuthenticationController' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'deleteUser' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'AuthenticationController' final oder die Methode 'deleteUser' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[133,34] (misc) FinalParameters: Der Parameter username sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[134,34] (misc) FinalParameters: Der Parameter requestBody sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[138,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[138,5] (design) DesignForExtension: Klasse 'AuthenticationController' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'getDeviceList' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'AuthenticationController' final oder die Methode 'getDeviceList' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[139] (sizes) LineLength: Zeile ist 91 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[139,62] (misc) FinalParameters: Der Parameter username sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[140] (sizes) LineLength: Zeile ist 101 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[140,62] (misc) FinalParameters: Der Parameter response sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[142] (sizes) LineLength: Zeile ist 107 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/ForgotPasswordRequest.java:[5] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/ForgotPasswordRequest.java:[8] (sizes) LineLength: Zeile ist 83 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/ForgotPasswordRequest.java:[8,1] (javadoc) JavadocType: Im Javadoc des Typs fehlt das Tag @param email.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/ForgotPasswordRequest.java:[8,82] (whitespace) WhitespaceAround: Nach '{' fehlt ein Leerzeichen.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/ForgotPasswordRequest.java:[8,83] (whitespace) WhitespaceAround: Vor '}' fehlt ein Leerzeichen.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/DeviceWrapper.java:[3,8] (imports) UnusedImports: Nicht verwendeter Import - jakarta.servlet.http.HttpServletResponse.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/DeviceWrapper.java:[14] (sizes) LineLength: Zeile ist 88 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/DeviceWrapper.java:[16,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/DeviceWrapper.java:[17,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/DeviceWrapper.java:[18,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/DeviceWrapper.java:[19,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/DeviceWrapper.java:[21,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/ChangePasswordRequest.java:[5] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/ChangePasswordRequest.java:[9] (sizes) LineLength: Zeile ist 106 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/ChangePasswordRequest.java:[9,1] (javadoc) JavadocType: Im Javadoc des Typs fehlt das Tag @param newPassword.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/ChangePasswordRequest.java:[9,1] (javadoc) JavadocType: Im Javadoc des Typs fehlt das Tag @param oldPassword.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/ChangePasswordRequest.java:[10] (sizes) LineLength: Zeile ist 84 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/UserInfoRequest.java:[9,1] (javadoc) JavadocType: Im Javadoc des Typs fehlt das Tag @param email.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/UserInfoRequest.java:[9,1] (javadoc) JavadocType: Im Javadoc des Typs fehlt das Tag @param password.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/UserInfoRequest.java:[9,1] (javadoc) JavadocType: Im Javadoc des Typs fehlt das Tag @param username.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/UserInfoRequest.java:[11,79] (whitespace) WhitespaceAround: Nach '{' fehlt ein Leerzeichen.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/UserInfoRequest.java:[11,80] (whitespace) WhitespaceAround: Vor '}' fehlt ein Leerzeichen.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/PasswordRequest.java:[9,1] (javadoc) JavadocType: Im Javadoc des Typs fehlt das Tag @param password.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/PasswordRequest.java:[9,79] (whitespace) WhitespaceAround: Nach '{' fehlt ein Leerzeichen.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/PasswordRequest.java:[9,80] (whitespace) WhitespaceAround: Vor '}' fehlt ein Leerzeichen.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[1] (javadoc) JavadocPackage: Es fehlt eine package-info.java.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[6,59] (imports) AvoidStarImport: Stern-Importe der Form '.*' sollten vermieden werden - org.psesquared.server.authentication_api.controller.*.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[25,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[26,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[27,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[28,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[29,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[30,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[32,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[33,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[34,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[35,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[36,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[37,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[39,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[39,5] (design) DesignForExtension: Klasse 'AuthenticationService' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'registerUser' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'AuthenticationService' final oder die Methode 'registerUser' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[39,36] (misc) FinalParameters: Der Parameter userInfo sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[55] (sizes) LineLength: Zeile ist 91 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[56] (sizes) LineLength: Zeile ist 85 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[66] (sizes) LineLength: Zeile ist 81 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[75,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[75,5] (design) DesignForExtension: Klasse 'AuthenticationService' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'verifyRegistration' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'AuthenticationService' final oder die Methode 'verifyRegistration' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[75,42] (misc) FinalParameters: Der Parameter username sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[75,59] (misc) FinalParameters: Der Parameter token sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[95,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[95,5] (design) DesignForExtension: Klasse 'AuthenticationService' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'login' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'AuthenticationService' final oder die Methode 'login' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[95,29] (misc) FinalParameters: Der Parameter username sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[96,36] (misc) FinalParameters: Der Parameter response sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[110,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[110,5] (design) DesignForExtension: Klasse 'AuthenticationService' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'logout' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'AuthenticationService' final oder die Methode 'logout' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[110,30] (misc) FinalParameters: Der Parameter username sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[111,30] (misc) FinalParameters: Der Parameter response sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[112,58] (whitespace) WhitespaceAround: Vor '{' fehlt ein Leerzeichen.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[122,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[122,5] (design) DesignForExtension: Klasse 'AuthenticationService' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'forgotPassword' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'AuthenticationService' final oder die Methode 'forgotPassword' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[122,38] (misc) FinalParameters: Der Parameter email sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[124] (sizes) LineLength: Zeile ist 95 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[128,11] (whitespace) WhitespaceAround: Nach 'catch' fehlt ein Leerzeichen.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[133,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[133,5] (design) DesignForExtension: Klasse 'AuthenticationService' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'resetPassword' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'AuthenticationService' final oder die Methode 'resetPassword' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[133,37] (misc) FinalParameters: Der Parameter username sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[134,31] (misc) FinalParameters: Der Parameter token sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[135,31] (misc) FinalParameters: Der Parameter requestBody sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[144] (sizes) LineLength: Zeile ist 81 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[153,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[153,5] (design) DesignForExtension: Klasse 'AuthenticationService' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'changePassword' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'AuthenticationService' final oder die Methode 'changePassword' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[153,38] (misc) FinalParameters: Der Parameter username sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[154,38] (misc) FinalParameters: Der Parameter requestBody sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[158] (sizes) LineLength: Zeile ist 89 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[168,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[168,5] (design) DesignForExtension: Klasse 'AuthenticationService' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'deleteUser' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'AuthenticationService' final oder die Methode 'deleteUser' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[168,34] (misc) FinalParameters: Der Parameter username sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[169,34] (misc) FinalParameters: Der Parameter requestBody sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[173] (sizes) LineLength: Zeile ist 86 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[183,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[183,5] (design) DesignForExtension: Klasse 'AuthenticationService' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'deleteInvalidUsersOlderThan' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'AuthenticationService' final oder die Methode 'deleteInvalidUsersOlderThan' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[183,45] (misc) FinalParameters: Der Parameter timestamp sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[184] (sizes) LineLength: Zeile ist 81 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/ResourceReader.java:[8,1] (design) HideUtilityClassConstructor: Hilfsklassen sollten keinen Standard-Konstruktur und keinen als public deklarierten Konstruktor haben.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/ResourceReader.java:[9] (sizes) LineLength: Zeile ist 83 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/ResourceReader.java:[9,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/ResourceReader.java:[9,43] (misc) FinalParameters: Der Parameter path sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/ResourceReader.java:[10] (sizes) LineLength: Zeile ist 95 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[16,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[17,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[18,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[20,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[23,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[24] (sizes) LineLength: Zeile ist 110 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[25,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[26] (sizes) LineLength: Zeile ist 102 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[28,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[29] (sizes) LineLength: Zeile ist 82 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[29,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[30] (sizes) LineLength: Zeile ist 85 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[30,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[32,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[33,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[34,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[35,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[37] (sizes) LineLength: Zeile ist 83 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[37,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[37,83] (whitespace) OperatorWrap: '+' sollte in einer neuen Zeile stehen.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[41] (sizes) LineLength: Zeile ist 83 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[41,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[41,83] (whitespace) OperatorWrap: '+' sollte in einer neuen Zeile stehen.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[46] (sizes) LineLength: Zeile ist 119 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[47] (sizes) LineLength: Zeile ist 134 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[52,27] (misc) FinalParameters: Der Parameter to sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[52,38] (misc) FinalParameters: Der Parameter mailSubject sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[52,58] (misc) FinalParameters: Der Parameter body sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[52,65] (javadoc) JavadocMethod: Erwartetes Tag @param für 'body'.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[53] (sizes) LineLength: Zeile ist 87 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[62] (sizes) LineLength: Zeile ist 90 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[62,43] (misc) FinalParameters: Der Parameter template sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[62,60] (misc) FinalParameters: Der Parameter user sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[62,78] (misc) FinalParameters: Der Parameter url sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[69] (sizes) LineLength: Zeile ist 81 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[71] (sizes) LineLength: Zeile ist 115 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[76] (sizes) LineLength: Zeile ist 82 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[79,58] (whitespace) OperatorWrap: '+' sollte in einer neuen Zeile stehen.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[80,54] (whitespace) OperatorWrap: '+' sollte in einer neuen Zeile stehen.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[81,33] (whitespace) OperatorWrap: '+' sollte in einer neuen Zeile stehen.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[82,32] (whitespace) OperatorWrap: '+' sollte in einer neuen Zeile stehen.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[83,43] (whitespace) OperatorWrap: '+' sollte in einer neuen Zeile stehen.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[84,33] (whitespace) OperatorWrap: '+' sollte in einer neuen Zeile stehen.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[85,29] (whitespace) OperatorWrap: '+' sollte in einer neuen Zeile stehen.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[91] (sizes) LineLength: Zeile ist 89 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[92] (sizes) LineLength: Zeile ist 112 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[95,34] (misc) FinalParameters: Der Parameter to sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[95,41] (javadoc) JavadocMethod: Erwartetes Tag @param für 'to'.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[95,45] (misc) FinalParameters: Der Parameter userDetails sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[97] (sizes) LineLength: Zeile ist 89 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[103] (sizes) LineLength: Zeile ist 102 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[104] (sizes) LineLength: Zeile ist 118 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[107,35] (misc) FinalParameters: Der Parameter to sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[107,42] (javadoc) JavadocMethod: Erwartetes Tag @param für 'to'.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[107,46] (misc) FinalParameters: Der Parameter userDetails sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[109] (sizes) LineLength: Zeile ist 90 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EncryptionService.java:[16,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EncryptionService.java:[18,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EncryptionService.java:[21] (sizes) LineLength: Zeile ist 96 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EncryptionService.java:[26,36] (misc) FinalParameters: Der Parameter email sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EncryptionService.java:[29] (sizes) LineLength: Zeile ist 81 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EncryptionService.java:[34] (sizes) LineLength: Zeile ist 85 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EncryptionService.java:[34,53] (coding) MagicNumber: Die magische Zahl '0xff' sollte als Konstante definiert werden.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EncryptionService.java:[34,61] (coding) MagicNumber: Die magische Zahl '0x100' sollte als Konstante definiert werden.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EncryptionService.java:[34,68] (coding) MagicNumber: Die magische Zahl '16' sollte als Konstante definiert werden.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EncryptionService.java:[44] (sizes) LineLength: Zeile ist 118 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EncryptionService.java:[49] (sizes) LineLength: Zeile ist 82 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/InputCheckService.java:[14,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/InputCheckService.java:[15,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/InputCheckService.java:[16,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/InputCheckService.java:[24] (sizes) LineLength: Zeile ist 101 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/InputCheckService.java:[44] (sizes) LineLength: Zeile ist 124 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/InputCheckService.java:[49] (sizes) LineLength: Zeile ist 174 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/InputCheckService.java:[59] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/InputCheckService.java:[60] (sizes) LineLength: Zeile ist 93 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/InputCheckService.java:[63] (sizes) LineLength: Zeile ist 96 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/InputCheckService.java:[65] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/InputCheckService.java:[66] (sizes) LineLength: Zeile ist 93 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/InputCheckService.java:[67] (sizes) LineLength: Zeile ist 177 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/InputCheckService.java:[69] (sizes) LineLength: Zeile ist 157 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/InputCheckService.java:[71] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/InputCheckService.java:[72] (sizes) LineLength: Zeile ist 82 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/InputCheckService.java:[73] (sizes) LineLength: Zeile ist 94 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/InputCheckService.java:[77] (sizes) LineLength: Zeile ist 91 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/InputCheckService.java:[79,37] (misc) FinalParameters: Der Parameter username sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/InputCheckService.java:[87] (sizes) LineLength: Zeile ist 114 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/InputCheckService.java:[89] (sizes) LineLength: Zeile ist 91 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/InputCheckService.java:[91,34] (misc) FinalParameters: Der Parameter email sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/InputCheckService.java:[93] (sizes) LineLength: Zeile ist 81 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/InputCheckService.java:[101] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/InputCheckService.java:[102] (sizes) LineLength: Zeile ist 82 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/InputCheckService.java:[106] (sizes) LineLength: Zeile ist 104 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/InputCheckService.java:[107] (sizes) LineLength: Zeile ist 106 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/InputCheckService.java:[109] (sizes) LineLength: Zeile ist 91 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/InputCheckService.java:[111,37] (misc) FinalParameters: Der Parameter password sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/data_access/AuthenticationDao.java:[1] (javadoc) JavadocPackage: Es fehlt eine package-info.java.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/data_access/AuthenticationDao.java:[18] (sizes) LineLength: Zeile ist 82 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/data_access/AuthenticationDao.java:[27] (sizes) LineLength: Zeile ist 81 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/data_access/AuthenticationDao.java:[40] (sizes) LineLength: Zeile ist 96 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/data_access/AuthenticationDao.java:[42] (sizes) LineLength: Zeile ist 97 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[1] (javadoc) JavadocPackage: Es fehlt eine package-info.java.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[7,47] (imports) AvoidStarImport: Stern-Importe der Form '.*' sollten vermieden werden - org.springframework.web.bind.annotation.*.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[12] (sizes) LineLength: Zeile ist 98 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[21,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[24] (sizes) LineLength: Zeile ist 82 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[25] (regexp) RegexpSingleline: Line has trailing spaces.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[31] (sizes) LineLength: Zeile ist 93 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[31,64] (misc) FinalParameters: Der Parameter username sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[32] (sizes) LineLength: Zeile ist 121 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[32,64] (misc) FinalParameters: Der Parameter episodeActionPosts sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[37] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[38] (sizes) LineLength: Zeile ist 113 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[39] (regexp) RegexpSingleline: Line has trailing spaces.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[40] (sizes) LineLength: Zeile ist 82 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[41] (sizes) LineLength: Zeile ist 91 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[44] (sizes) LineLength: Zeile ist 102 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[44,71] (misc) FinalParameters: Der Parameter username sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[45] (sizes) LineLength: Zeile ist 127 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[49] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[50] (sizes) LineLength: Zeile ist 112 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[51] (regexp) RegexpSingleline: Line has trailing spaces.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[52] (sizes) LineLength: Zeile ist 82 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[54] (sizes) LineLength: Zeile ist 91 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[57] (sizes) LineLength: Zeile ist 109 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[57,80] (misc) FinalParameters: Der Parameter username sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[58] (sizes) LineLength: Zeile ist 103 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[58,59] (misc) FinalParameters: Der Parameter podcastURL sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[59] (sizes) LineLength: Zeile ist 148 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[63] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[64] (sizes) LineLength: Zeile ist 116 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[65] (regexp) RegexpSingleline: Line has trailing spaces.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[66] (sizes) LineLength: Zeile ist 82 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[67] (sizes) LineLength: Zeile ist 89 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[68] (sizes) LineLength: Zeile ist 91 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[71] (sizes) LineLength: Zeile ist 105 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[71,76] (misc) FinalParameters: Der Parameter username sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[72] (sizes) LineLength: Zeile ist 95 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[72,60] (misc) FinalParameters: Der Parameter since sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[73] (sizes) LineLength: Zeile ist 139 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[77] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[78] (sizes) LineLength: Zeile ist 132 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[79] (regexp) RegexpSingleline: Line has trailing spaces.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[80] (sizes) LineLength: Zeile ist 82 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[82] (sizes) LineLength: Zeile ist 89 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[83] (sizes) LineLength: Zeile ist 91 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[86] (sizes) LineLength: Zeile ist 114 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[86,85] (misc) FinalParameters: Der Parameter username sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[87] (sizes) LineLength: Zeile ist 106 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[87,64] (misc) FinalParameters: Der Parameter podcastURL sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[88] (sizes) LineLength: Zeile ist 99 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[88,64] (misc) FinalParameters: Der Parameter since sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[89] (sizes) LineLength: Zeile ist 160 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionGetResponse.java:[13,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionGetResponse.java:[14,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionGetResponse.java:[19,37] (misc) FinalParameters: Der Parameter actions sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionGetResponse.java:[19,61] (coding) HiddenField: Die Variable 'actions' verbirgt ein Feld.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionGetResponse.java:[24,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionGetResponse.java:[24,5] (design) DesignForExtension: Klasse 'EpisodeActionGetResponse' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'getActions' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'EpisodeActionGetResponse' final oder die Methode 'getActions' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionGetResponse.java:[28,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionGetResponse.java:[28,5] (design) DesignForExtension: Klasse 'EpisodeActionGetResponse' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'getTimestamp' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'EpisodeActionGetResponse' final oder die Methode 'getTimestamp' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionPost.java:[14] (sizes) LineLength: Zeile ist 94 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionPost.java:[22,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionPost.java:[26,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionPost.java:[30,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionPost.java:[32,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionPost.java:[34,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionPost.java:[36,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[1] (javadoc) JavadocPackage: Es fehlt eine package-info.java.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[30,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[32,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[34,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[36,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[38,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[40,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[42,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[44] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[45] (sizes) LineLength: Zeile ist 84 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[50] (sizes) LineLength: Zeile ist 82 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[53] (sizes) LineLength: Zeile ist 96 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[53,35] (misc) FinalParameters: Der Parameter username sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[53,52] (misc) FinalParameters: Der Parameter episodeActionPosts sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[55] (sizes) LineLength: Zeile ist 106 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[59,68] (misc) FinalParameters: Der Parameter user sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[60,13] (misc) FinalParameters: Der Parameter episodeActionPosts sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[63] (sizes) LineLength: Zeile ist 90 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[68] (sizes) LineLength: Zeile ist 108 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[68,60] (misc) FinalParameters: Der Parameter user sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[68,71] (misc) FinalParameters: Der Parameter episodeActionPost sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[75] (sizes) LineLength: Zeile ist 89 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[82] (sizes) LineLength: Zeile ist 109 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[83] (sizes) LineLength: Zeile ist 81 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[87] (sizes) LineLength: Zeile ist 102 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[96] (sizes) LineLength: Zeile ist 81 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[96,44] (misc) FinalParameters: Der Parameter episodeActionPost sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[103,9] (blocks) RightCurly: '}' an Position 9 sollte in der gleichen Zeile stehen wie der nächste Teil der Multi-Block-Anweisung (eine Anweisung, die mehrere Blöcke enthält: if/else-if/else, do/while oder try/catch/finally).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[112,9] (blocks) RightCurly: '}' an Position 9 sollte in der gleichen Zeile stehen wie der nächste Teil der Multi-Block-Anweisung (eine Anweisung, die mehrere Blöcke enthält: if/else-if/else, do/while oder try/catch/finally).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[120,35] (misc) FinalParameters: Der Parameter episodeActionPost sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[125] (sizes) LineLength: Zeile ist 105 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[134] (sizes) LineLength: Zeile ist 93 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[134,46] (misc) FinalParameters: Der Parameter user sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[134,57] (misc) FinalParameters: Der Parameter episodeActions sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[140] (sizes) LineLength: Zeile ist 85 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[140,45] (misc) FinalParameters: Der Parameter user sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[140,56] (misc) FinalParameters: Der Parameter episodeAction sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[141] (sizes) LineLength: Zeile ist 106 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[149] (sizes) LineLength: Zeile ist 91 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[149,51] (misc) FinalParameters: Der Parameter user sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[149,62] (misc) FinalParameters: Der Parameter episodeAction sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[150] (sizes) LineLength: Zeile ist 96 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[153] (sizes) LineLength: Zeile ist 84 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[159] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[163] (sizes) LineLength: Zeile ist 82 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[164] (sizes) LineLength: Zeile ist 83 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[166,54] (misc) FinalParameters: Der Parameter username sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[167] (sizes) LineLength: Zeile ist 91 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[175] (sizes) LineLength: Zeile ist 84 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[177] (sizes) LineLength: Zeile ist 83 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[179] (sizes) LineLength: Zeile ist 99 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[179,63] (misc) FinalParameters: Der Parameter username sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[179,80] (misc) FinalParameters: Der Parameter podcastURL sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[180] (sizes) LineLength: Zeile ist 115 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[185] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[186] (sizes) LineLength: Zeile ist 82 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[189] (sizes) LineLength: Zeile ist 82 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[192] (sizes) LineLength: Zeile ist 83 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[194] (sizes) LineLength: Zeile ist 88 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[194,59] (misc) FinalParameters: Der Parameter username sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[194,76] (misc) FinalParameters: Der Parameter since sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[195] (sizes) LineLength: Zeile ist 114 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[196] (sizes) LineLength: Zeile ist 118 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[201] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[202] (sizes) LineLength: Zeile ist 83 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[206] (sizes) LineLength: Zeile ist 84 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[210] (sizes) LineLength: Zeile ist 83 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[212] (sizes) LineLength: Zeile ist 116 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[212,68] (misc) FinalParameters: Der Parameter username sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[212,85] (misc) FinalParameters: Der Parameter podcastURL sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[212,104] (misc) FinalParameters: Der Parameter since sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[213] (sizes) LineLength: Zeile ist 114 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[215] (sizes) LineLength: Zeile ist 114 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[220] (sizes) LineLength: Zeile ist 108 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[220,72] (misc) FinalParameters: Der Parameter episodeActions sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/data_access/EpisodeActionDao.java:[1] (javadoc) JavadocPackage: Es fehlt eine package-info.java.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/data_access/EpisodeActionDao.java:[16] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/data_access/EpisodeActionDao.java:[22] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/data_access/EpisodeActionDao.java:[30] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/data_access/EpisodeActionDao.java:[31] (sizes) LineLength: Zeile ist 82 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/data_access/EpisodeActionDao.java:[36] (sizes) LineLength: Zeile ist 82 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/data_access/EpisodeActionDao.java:[38] (sizes) LineLength: Zeile ist 97 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/data_access/EpisodeActionDao.java:[40] (sizes) LineLength: Zeile ist 84 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/data_access/EpisodeActionDao.java:[40,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/data_access/EpisodeActionDao.java:[42] (sizes) LineLength: Zeile ist 85 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/data_access/EpisodeActionDao.java:[42,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/data_access/EpisodeActionDao.java:[44] (sizes) LineLength: Zeile ist 99 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/data_access/EpisodeActionDao.java:[44,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/data_access/EpisodeActionDao.java:[46] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/data_access/EpisodeActionDao.java:[50] (sizes) LineLength: Zeile ist 84 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/data_access/EpisodeActionDao.java:[54] (sizes) LineLength: Zeile ist 113 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/data_access/EpisodeActionDao.java:[56] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/data_access/EpisodeActionDao.java:[57] (sizes) LineLength: Zeile ist 83 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/data_access/EpisodeActionDao.java:[60] (sizes) LineLength: Zeile ist 84 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/data_access/EpisodeActionDao.java:[64] (sizes) LineLength: Zeile ist 82 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/data_access/EpisodeActionDao.java:[67] (sizes) LineLength: Zeile ist 112 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/data_access/EpisodeActionDao.java:[72,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/data_access/EpisodeDao.java:[9] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/data_access/EpisodeDao.java:[15] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/data_access/EpisodeDao.java:[23] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/data_access/EpisodeDao.java:[31] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/data_access/EpisodeDao.java:[39] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionTitles.java:[1] (javadoc) JavadocPackage: Es fehlt eine package-info.java.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionTitles.java:[9] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionTitles.java:[12] (sizes) LineLength: Zeile ist 110 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionTitles.java:[12,1] (javadoc) JavadocType: Im Javadoc des Typs fehlt das Tag @param episodes.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionTitles.java:[12,1] (javadoc) JavadocType: Im Javadoc des Typs fehlt das Tag @param subscription.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[7,47] (imports) AvoidStarImport: Stern-Importe der Form '.*' sollten vermieden werden - org.springframework.web.bind.annotation.*.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[12] (sizes) LineLength: Zeile ist 96 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[13] (sizes) LineLength: Zeile ist 97 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[20,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[22,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[25] (sizes) LineLength: Zeile ist 81 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[27] (regexp) RegexpSingleline: Line has trailing spaces.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[29] (sizes) LineLength: Zeile ist 127 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[30] (sizes) LineLength: Zeile ist 111 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[34] (sizes) LineLength: Zeile ist 84 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[34,55] (misc) FinalParameters: Der Parameter username sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[35,48] (misc) FinalParameters: Der Parameter deviceID sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[36] (sizes) LineLength: Zeile ist 89 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[36,48] (misc) FinalParameters: Der Parameter subscriptions sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[43] (regexp) RegexpSingleline: Line has trailing spaces.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[44] (sizes) LineLength: Zeile ist 88 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[45] (sizes) LineLength: Zeile ist 113 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[47] (sizes) LineLength: Zeile ist 102 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[48] (sizes) LineLength: Zeile ist 88 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[50] (sizes) LineLength: Zeile ist 103 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[51] (sizes) LineLength: Zeile ist 87 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[51,58] (misc) FinalParameters: Der Parameter username sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[52] (sizes) LineLength: Zeile ist 98 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[52,51] (misc) FinalParameters: Der Parameter deviceID sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[53] (sizes) LineLength: Zeile ist 122 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[53,51] (misc) FinalParameters: Der Parameter functionJSONP sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[54] (sizes) LineLength: Zeile ist 84 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[59] (sizes) LineLength: Zeile ist 128 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[61] (regexp) RegexpSingleline: Line has trailing spaces.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[62] (sizes) LineLength: Zeile ist 92 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[63] (sizes) LineLength: Zeile ist 121 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[64] (sizes) LineLength: Zeile ist 92 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[65] (regexp) RegexpSingleline: Line has trailing spaces.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[65] (sizes) LineLength: Zeile ist 100 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[68] (sizes) LineLength: Zeile ist 98 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[68,69] (misc) FinalParameters: Der Parameter username sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[69] (sizes) LineLength: Zeile ist 98 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[69,69] (misc) FinalParameters: Der Parameter deviceID sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[70] (sizes) LineLength: Zeile ist 107 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[70,69] (misc) FinalParameters: Der Parameter delta sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[76] (sizes) LineLength: Zeile ist 94 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[77] (regexp) RegexpSingleline: Line has trailing spaces.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[78] (sizes) LineLength: Zeile ist 92 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[79] (sizes) LineLength: Zeile ist 120 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[80] (sizes) LineLength: Zeile ist 81 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[81] (sizes) LineLength: Zeile ist 105 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[84] (sizes) LineLength: Zeile ist 96 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[84,67] (misc) FinalParameters: Der Parameter username sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[85] (sizes) LineLength: Zeile ist 96 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[85,67] (misc) FinalParameters: Der Parameter deviceID sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[86] (sizes) LineLength: Zeile ist 102 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[86,67] (misc) FinalParameters: Der Parameter since sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[87] (sizes) LineLength: Zeile ist 92 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[93] (sizes) LineLength: Zeile ist 97 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[94] (regexp) RegexpSingleline: Line has trailing spaces.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[95] (sizes) LineLength: Zeile ist 82 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[96] (sizes) LineLength: Zeile ist 100 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[99] (sizes) LineLength: Zeile ist 94 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[99,63] (misc) FinalParameters: Der Parameter username sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[100] (sizes) LineLength: Zeile ist 88 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionDelta.java:[10] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionDelta.java:[11] (sizes) LineLength: Zeile ist 114 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionDelta.java:[16,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionDelta.java:[20,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionDelta.java:[24,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionDelta.java:[28] (sizes) LineLength: Zeile ist 84 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionDelta.java:[29] (sizes) LineLength: Zeile ist 89 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionDelta.java:[31,30] (misc) FinalParameters: Der Parameter add sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionDelta.java:[31,43] (coding) HiddenField: Die Variable 'add' verbirgt ein Feld.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionDelta.java:[31,48] (misc) FinalParameters: Der Parameter remove sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionDelta.java:[31,61] (coding) HiddenField: Die Variable 'remove' verbirgt ein Feld.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionDelta.java:[37] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionDelta.java:[39] (regexp) RegexpSingleline: Line has trailing spaces.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionDelta.java:[46] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionDelta.java:[48] (regexp) RegexpSingleline: Line has trailing spaces.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionDelta.java:[55] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionDelta.java:[57] (regexp) RegexpSingleline: Line has trailing spaces.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[1] (javadoc) JavadocPackage: Es fehlt eine package-info.java.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[12,35] (imports) AvoidStarImport: Stern-Importe der Form '.*' sollten vermieden werden - org.psesquared.server.model.*.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[28,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[29,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[31,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[33,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[35,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[37,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[47] (regexp) RegexpSingleline: Line has trailing spaces.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[49] (sizes) LineLength: Zeile ist 84 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[52] (sizes) LineLength: Zeile ist 87 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[52,36] (misc) FinalParameters: Der Parameter username sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[52,53] (misc) FinalParameters: Der Parameter subscriptionStrings sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[60] (sizes) LineLength: Zeile ist 85 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[65] (sizes) LineLength: Zeile ist 118 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[67] (sizes) LineLength: Zeile ist 84 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[70] (sizes) LineLength: Zeile ist 98 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[71] (sizes) LineLength: Zeile ist 85 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[76] (sizes) LineLength: Zeile ist 102 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[80] (sizes) LineLength: Zeile ist 99 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[89] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[90] (sizes) LineLength: Zeile ist 82 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[92] (regexp) RegexpSingleline: Line has trailing spaces.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[97,42] (misc) FinalParameters: Der Parameter username sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[98] (sizes) LineLength: Zeile ist 118 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[106] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[108] (regexp) RegexpSingleline: Line has trailing spaces.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[109] (sizes) LineLength: Zeile ist 84 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[110] (sizes) LineLength: Zeile ist 82 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[114] (sizes) LineLength: Zeile ist 81 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[114,39] (misc) FinalParameters: Der Parameter username sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[114,56] (misc) FinalParameters: Der Parameter delta sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[121,56] (whitespace) OperatorWrap: '&&' sollte in einer neuen Zeile stehen.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[122] (sizes) LineLength: Zeile ist 112 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[125] (sizes) LineLength: Zeile ist 93 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[132] (sizes) LineLength: Zeile ist 100 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[139] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[142] (regexp) RegexpSingleline: Line has trailing spaces.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[143] (sizes) LineLength: Zeile ist 84 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[145] (sizes) LineLength: Zeile ist 82 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[147] (sizes) LineLength: Zeile ist 82 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[149,51] (misc) FinalParameters: Der Parameter username sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[149,68] (misc) FinalParameters: Der Parameter since sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[154] (sizes) LineLength: Zeile ist 81 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[167] (sizes) LineLength: Zeile ist 82 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[169] (regexp) RegexpSingleline: Line has trailing spaces.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[172] (sizes) LineLength: Zeile ist 82 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[175,47] (misc) FinalParameters: Der Parameter username sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[176] (sizes) LineLength: Zeile ist 118 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[189] (sizes) LineLength: Zeile ist 109 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/data_access/SubscriptionActionDao.java:[1] (javadoc) JavadocPackage: Es fehlt eine package-info.java.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/data_access/SubscriptionActionDao.java:[12] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/data_access/SubscriptionActionDao.java:[16] (sizes) LineLength: Zeile ist 88 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/data_access/SubscriptionActionDao.java:[34] (sizes) LineLength: Zeile ist 83 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/data_access/SubscriptionActionDao.java:[37] (sizes) LineLength: Zeile ist 97 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/data_access/SubscriptionActionDao.java:[45] (sizes) LineLength: Zeile ist 84 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/data_access/SubscriptionActionDao.java:[49] (sizes) LineLength: Zeile ist 109 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/data_access/SubscriptionActionDao.java:[54] (sizes) LineLength: Zeile ist 81 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/data_access/SubscriptionActionDao.java:[60] (sizes) LineLength: Zeile ist 83 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/data_access/SubscriptionActionDao.java:[63] (sizes) LineLength: Zeile ist 82 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/data_access/SubscriptionActionDao.java:[64] (sizes) LineLength: Zeile ist 82 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/data_access/SubscriptionActionDao.java:[68] (sizes) LineLength: Zeile ist 104 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/data_access/SubscriptionActionDao.java:[70] (regexp) RegexpSingleline: Line has trailing spaces.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/data_access/SubscriptionDao.java:[10] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/data_access/SubscriptionDao.java:[16,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/data_access/SubscriptionDao.java:[17,5] (javadoc) InvalidJavadocPosition: Javadoc-Kommentar ist an der falschen Stelle platziert.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/data_access/SubscriptionDao.java:[25] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/data_access/SubscriptionDao.java:[26] (sizes) LineLength: Zeile ist 81 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/ServerApplication.java:[1] (javadoc) JavadocPackage: Es fehlt eine package-info.java.
+[ERROR] src/main/java/org/psesquared/server/ServerApplication.java:[9] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/ServerApplication.java:[12,1] (design) HideUtilityClassConstructor: Hilfsklassen sollten keinen Standard-Konstruktur und keinen als public deklarierten Konstruktor haben.
+[ERROR] src/main/java/org/psesquared/server/ServerApplication.java:[13] (sizes) LineLength: Zeile ist 95 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/ServerApplication.java:[16] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/ServerApplication.java:[16,1] (whitespace) FileTabCharacter: Die Datei enthält Tabulatorzeichen (dies ist das erste Vorkommen).
+[ERROR] src/main/java/org/psesquared/server/ServerApplication.java:[18] (regexp) RegexpSingleline: Line has trailing spaces.
+[ERROR] src/main/java/org/psesquared/server/ServerApplication.java:[21,33] (misc) FinalParameters: Der Parameter args sollte als 'final' deklariert sein.
+[ERROR] src/main/resources/security.properties:[1] (misc) NewlineAtEndOfFile: Datei endet nicht mit einem Zeilenumbruch.
+[INFO] ------------------------------------------------------------------------
+[INFO] BUILD FAILURE
+[INFO] ------------------------------------------------------------------------
+[INFO] Total time: 13.946 s
+[INFO] Finished at: 2023-03-18T08:10:57+01:00
+[INFO] ------------------------------------------------------------------------
+[ERROR] Failed to execute goal org.apache.maven.plugins:maven-checkstyle-plugin:3.2.1:check (default-cli) on project server: You have 799 Checkstyle violations. -> [Help 1]
+[ERROR]
+[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
+[ERROR] Re-run Maven using the -X switch to enable full debug logging.
+[ERROR]
+[ERROR] For more information about the errors and possible solutions, please read the following articles:
+[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException
diff --git a/30-qualitaetsheft/assets/sources/linter-dashboard-after-processed.txt b/30-qualitaetsheft/assets/sources/linter-dashboard-after-processed.txt
new file mode 100644
index 0000000..cab82f3
--- /dev/null
+++ b/30-qualitaetsheft/assets/sources/linter-dashboard-after-processed.txt
@@ -0,0 +1 @@
+1 warning vue/no-v-html
diff --git a/30-qualitaetsheft/assets/sources/linter-dashboard-after.txt b/30-qualitaetsheft/assets/sources/linter-dashboard-after.txt
new file mode 100644
index 0000000..f9bda3b
--- /dev/null
+++ b/30-qualitaetsheft/assets/sources/linter-dashboard-after.txt
@@ -0,0 +1,10 @@
+
+> pse-dashboard@0.0.0 lint
+> eslint 'src/**/*.{js,vue}'
+
+
+/home/gero/documents/uni/pse/pse-dashboard/src/components/HelpModal.vue
+ 25:21 warning 'v-html' directive can lead to XSS attack vue/no-v-html
+
+✖ 1 problem (0 errors, 1 warning)
+
diff --git a/30-qualitaetsheft/assets/sources/linter-dashboard-before-processed.txt b/30-qualitaetsheft/assets/sources/linter-dashboard-before-processed.txt
new file mode 100644
index 0000000..150ea46
--- /dev/null
+++ b/30-qualitaetsheft/assets/sources/linter-dashboard-before-processed.txt
@@ -0,0 +1,22 @@
+26 error vue/html-indent
+17 error vue/script-indent
+6 error vue/require-v-for-key
+5 error vue/multi-word-component-names
+1 error vue/valid-v-for
+1 error vue/valid-template-root
+125 warning vue/max-attributes-per-line
+34 warning vue/attributes-order
+26 warning vue/singleline-html-element-content-newline
+12 warning vue/require-default-prop
+12 warning vue/html-self-closing
+11 warning vue/first-attribute-linebreak
+10 warning vue/html-closing-bracket-newline
+8 warning vue/multiline-html-element-content-newline
+5 warning vue/html-closing-bracket-spacing
+3 warning vue/require-prop-types
+3 warning vue/attribute-hyphenation
+2 warning vue/html-self-closing
+1 warning vue/v-on-event-hyphenation
+1 warning vue/no-v-html
+1 warning vue/mustache-interpolation-spacing
+
diff --git a/30-qualitaetsheft/assets/sources/linter-dashboard-before.txt b/30-qualitaetsheft/assets/sources/linter-dashboard-before.txt
new file mode 100644
index 0000000..04a8317
--- /dev/null
+++ b/30-qualitaetsheft/assets/sources/linter-dashboard-before.txt
@@ -0,0 +1,358 @@
+
+> pse-dashboard@0.0.0 lint
+> eslint 'src/**/*.{js,vue}'
+
+
+/home/gero/documents/uni/pse/pse-dashboard/src/components/Episode.vue
+ 1:1 error Component name "Episode" should always be multi-word vue/multi-word-component-names
+ 5:5 warning Prop 'action' requires default value to be set vue/require-default-prop
+ 5:5 warning Prop "action" should define at least its type vue/require-prop-types
+ 20:17 warning 'class' should be on a new line vue/max-attributes-per-line
+ 20:69 warning 'aria-current' should be on a new line vue/max-attributes-per-line
+ 23:67 warning 'style' should be on a new line vue/max-attributes-per-line
+ 38:51 warning 'style' should be on a new line vue/max-attributes-per-line
+ 39:17 warning Require self-closing on HTML elements (<div>) vue/html-self-closing
+ 39:43 warning ':style' should be on a new line vue/max-attributes-per-line
+
+/home/gero/documents/uni/pse/pse-dashboard/src/components/ErrorLog.vue
+ 14:1 error Expected indentation of 8 spaces but found 4 spaces vue/html-indent
+ 15:1 error Expected indentation of 12 spaces but found 8 spaces vue/html-indent
+ 15:9 error Elements in iteration expect to have 'v-bind:key' directives vue/require-v-for-key
+ 15:14 warning Expected a linebreak before this attribute vue/first-attribute-linebreak
+ 15:43 warning 'class' should be on a new line vue/max-attributes-per-line
+ 16:29 warning ':class' should be on a new line vue/max-attributes-per-line
+ 16:58 warning Expected 1 line break before closing bracket, but no line breaks found vue/html-closing-bracket-newline
+ 17:1 error Expected indentation of 16 spaces but found 12 spaces vue/html-indent
+ 17:13 warning Require self-closing on HTML elements (<button>) vue/html-self-closing
+ 17:35 warning 'class' should be on a new line vue/max-attributes-per-line
+ 17:53 warning '@click' should be on a new line vue/max-attributes-per-line
+ 18:1 error Expected indentation of 16 spaces but found 12 spaces vue/html-indent
+ 18:13 warning Require self-closing on HTML elements (<i>) vue/html-self-closing
+ 18:37 warning ':class' should be on a new line vue/max-attributes-per-line
+ 19:1 error Expected indentation of 12 spaces but found 8 spaces vue/html-indent
+ 20:1 error Expected indentation of 8 spaces but found 4 spaces vue/html-indent
+
+/home/gero/documents/uni/pse/pse-dashboard/src/components/FloatingLabelInput.vue
+ 7:5 warning Prop 'label' requires default value to be set vue/require-default-prop
+ 8:5 warning Prop 'modelValue' requires default value to be set vue/require-default-prop
+ 15:16 warning Expected a linebreak before this attribute vue/first-attribute-linebreak
+ 15:29 warning 'class' should be on a new line vue/max-attributes-per-line
+ 15:50 warning Attribute ":id" should go before "class" vue/attributes-order
+ 15:50 warning ':id' should be on a new line vue/max-attributes-per-line
+ 15:62 warning ':value' should be on a new line vue/max-attributes-per-line
+ 16:1 error Expected indentation of 15 spaces but found 12 spaces vue/html-indent
+ 17:1 error Expected indentation of 15 spaces but found 12 spaces vue/html-indent
+ 17:13 warning Attribute ":placeholder" should go before "@input" vue/attributes-order
+ 17:34 warning Attribute "required" should go before "@input" vue/attributes-order
+ 17:34 warning 'required' should be on a new line vue/max-attributes-per-line
+ 17:42 warning Expected 1 line break before closing bracket, but no line breaks found vue/html-closing-bracket-newline
+
+/home/gero/documents/uni/pse/pse-dashboard/src/components/FormLayout.vue
+ 9:35 warning 'src' should be on a new line vue/max-attributes-per-line
+ 9:60 warning 'alt' should be on a new line vue/max-attributes-per-line
+ 9:67 warning 'width' should be on a new line vue/max-attributes-per-line
+ 9:79 warning 'height' should be on a new line vue/max-attributes-per-line
+
+/home/gero/documents/uni/pse/pse-dashboard/src/components/Help.vue
+ 1:1 error Component name "Help" should always be multi-word vue/multi-word-component-names
+ 4:29 warning Attribute "id" should go before "class" vue/attributes-order
+ 4:29 warning 'id' should be on a new line vue/max-attributes-per-line
+ 9:45 warning Expected 1 line break after opening tag (`<h5>`), but no line breaks found vue/singleline-html-element-content-newline
+ 9:69 warning Expected 1 line break before closing tag (`</h5>`), but no line breaks found vue/singleline-html-element-content-newline
+ 10:21 warning Require self-closing on HTML elements (<button>) vue/html-self-closing
+ 10:43 warning 'class' should be on a new line vue/max-attributes-per-line
+ 10:61 warning 'data-bs-dismiss' should be on a new line vue/max-attributes-per-line
+ 14:41 warning 'v-html' should be on a new line vue/max-attributes-per-line
+ 14:41 warning 'v-html' directive can lead to XSS attack vue/no-v-html
+ 18:43 warning 'class' should be on a new line vue/max-attributes-per-line
+ 18:69 warning 'data-bs-dismiss' should be on a new line vue/max-attributes-per-line
+ 18:93 warning Expected 1 line break after opening tag (`<button>`), but no line breaks found vue/singleline-html-element-content-newline
+ 18:118 warning Expected 1 line break before closing tag (`</button>`), but no line breaks found vue/singleline-html-element-content-newline
+
+/home/gero/documents/uni/pse/pse-dashboard/src/components/LastUpdate.vue
+ 12:5 warning Prop 'iso' requires default value to be set vue/require-default-prop
+ 13:5 warning Prop 'unix' requires default value to be set vue/require-default-prop
+ 36:1 error Expected indentation of 4 spaces but found 0 spaces vue/html-indent
+
+/home/gero/documents/uni/pse/pse-dashboard/src/components/Loading.vue
+ 1:1 error Component name "Loading" should always be multi-word vue/multi-word-component-names
+ 9:30 warning Attribute "v-else" should go before "class" vue/attributes-order
+ 9:30 warning 'v-else' should be on a new line vue/max-attributes-per-line
+
+/home/gero/documents/uni/pse/pse-dashboard/src/components/LogEntry.vue
+ 3:1 error The template requires child element vue/valid-template-root
+ 3:1 warning Require self-closing on HTML elements (<template>) vue/html-self-closing
+
+/home/gero/documents/uni/pse/pse-dashboard/src/components/Navbar.vue
+ 1:1 error Component name "Navbar" should always be multi-word vue/multi-word-component-names
+ 6:32 warning Expected 1 line break after opening tag (`<div>`), but 2 line breaks found vue/multiline-html-element-content-newline
+ 9:47 warning 'to' should be on a new line vue/max-attributes-per-line
+ 10:1 error Expected indentation of 16 spaces but found 20 spaces vue/html-indent
+ 10:50 warning 'alt' should be on a new line vue/max-attributes-per-line
+ 10:57 warning 'width' should be on a new line vue/max-attributes-per-line
+ 10:69 warning 'height' should be on a new line vue/max-attributes-per-line
+ 14:44 warning 'type' should be on a new line vue/max-attributes-per-line
+ 14:58 warning 'data-bs-toggle' should be on a new line vue/max-attributes-per-line
+ 14:84 warning 'data-bs-target' should be on a new line vue/max-attributes-per-line
+ 15:17 warning Require self-closing on HTML elements (<span>) vue/html-self-closing
+ 17:51 warning Attribute "id" should go before "class" vue/attributes-order
+ 17:51 warning 'id' should be on a new line vue/max-attributes-per-line
+ 17:65 warning Expected 1 line break after opening tag (`<div>`), but 2 line breaks found vue/multiline-html-element-content-newline
+ 21:49 warning 'class' should be on a new line vue/max-attributes-per-line
+ 23:62 warning 'class' should be on a new line vue/max-attributes-per-line
+ 28:57 warning 'class' should be on a new line vue/max-attributes-per-line
+ 40:61 warning 'href' should be on a new line vue/max-attributes-per-line
+ 40:70 warning 'role' should be on a new line vue/max-attributes-per-line
+ 40:84 warning 'data-bs-toggle' should be on a new line vue/max-attributes-per-line
+ 41:29 warning Require self-closing on HTML elements (<i>) vue/html-self-closing
+ 44:29 error Elements in iteration expect to have 'v-bind:key' directives vue/require-v-for-key
+ 45:58 warning ':class' should be on a new line vue/max-attributes-per-line
+ 45:100 warning '@click' should be on a new line vue/max-attributes-per-line
+ 51:24 warning Expected a linebreak before this attribute vue/first-attribute-linebreak
+ 51:33 warning 'class' should be on a new line vue/max-attributes-per-line
+ 52:1 error Expected indentation of 23 spaces but found 24 spaces vue/html-indent
+ 52:48 warning 'data-bs-target' should be on a new line vue/max-attributes-per-line
+ 52:70 warning Expected 1 line break before closing bracket, but no line breaks found vue/html-closing-bracket-newline
+ 55:50 warning 'class' should be on a new line vue/max-attributes-per-line
+ 56:37 warning 'class' should be on a new line vue/max-attributes-per-line
+ 56:70 warning 'role' should be on a new line vue/max-attributes-per-line
+ 56:84 warning 'data-bs-toggle' should be on a new line vue/max-attributes-per-line
+ 57:64 warning Require self-closing on HTML elements (<i>) vue/html-self-closing
+ 60:61 warning 'class' should be on a new line vue/max-attributes-per-line
+ 60:83 warning Expected 1 line break after opening tag (`<router-link>`), but no line breaks found vue/singleline-html-element-content-newline
+ 60:111 warning Expected 1 line break before closing tag (`</router-link>`), but no line breaks found vue/singleline-html-element-content-newline
+ 62:58 warning '@click' should be on a new line vue/max-attributes-per-line
+ 62:82 warning Attribute "class" should go before "@click" vue/attributes-order
+ 62:82 warning 'class' should be on a new line vue/max-attributes-per-line
+ 62:104 warning Expected 1 line break after opening tag (`<router-link>`), but no line breaks found vue/singleline-html-element-content-newline
+ 62:130 warning Expected 1 line break before closing tag (`</router-link>`), but no line breaks found vue/singleline-html-element-content-newline
+
+/home/gero/documents/uni/pse/pse-dashboard/src/components/PasswordInput.vue
+ 6:5 warning Prop 'modelValue' requires default value to be set vue/require-default-prop
+ 7:5 warning Prop 'label' requires default value to be set vue/require-default-prop
+ 14:29 warning Expected a linebreak before this attribute vue/first-attribute-linebreak
+ 15:1 error Expected indentation of 28 spaces but found 8 spaces vue/html-indent
+ 15:24 warning ':modelValue' should be on a new line vue/max-attributes-per-line
+ 15:24 warning Attribute ':modelValue' must be hyphenated vue/attribute-hyphenation
+ 15:49 warning '@update:modelValue' should be on a new line vue/max-attributes-per-line
+ 15:49 warning v-on event '@update:modelValue' must be hyphenated vue/v-on-event-hyphenation
+ 16:1 error Expected indentation of 32 spaces but found 8 spaces vue/html-indent
+ 16:46 warning Expected 1 line break before closing bracket, but no line breaks found vue/html-closing-bracket-newline
+ 19:13 warning Disallow self-closing on HTML void elements (<input/>) vue/html-self-closing
+ 19:36 warning 'class' should be on a new line vue/max-attributes-per-line
+ 19:54 warning 'autocomplete' should be on a new line vue/max-attributes-per-line
+ 19:73 warning Attribute "v-model" should go before "autocomplete" vue/attributes-order
+ 19:73 warning 'v-model' should be on a new line vue/max-attributes-per-line
+ 19:100 warning Expected a space before '/>', but not found vue/html-closing-bracket-spacing
+ 20:27 warning ':class' should be on a new line vue/max-attributes-per-line
+
+/home/gero/documents/uni/pse/pse-dashboard/src/components/PasswordValidator.vue
+ 6:14 warning Prop "modelValue" should define at least its type vue/require-prop-types
+ 16:1 error Expected indentation of 4 spaces but found 8 spaces vue/script-indent
+ 17:1 error Expected indentation of 0 spaces but found 8 spaces vue/script-indent
+ 21:1 error Expected indentation of 4 spaces but found 8 spaces vue/script-indent
+ 22:1 error Expected indentation of 0 spaces but found 8 spaces vue/script-indent
+ 26:1 error Expected indentation of 4 spaces but found 8 spaces vue/script-indent
+ 27:1 error Expected indentation of 4 spaces but found 8 spaces vue/script-indent
+ 32:1 error Expected indentation of 4 spaces but found 8 spaces vue/script-indent
+ 33:1 error Expected indentation of 4 spaces but found 8 spaces vue/script-indent
+ 34:1 error Expected indentation of 0 spaces but found 8 spaces vue/script-indent
+ 38:1 error Expected indentation of 4 spaces but found 8 spaces vue/script-indent
+ 39:1 error Expected indentation of 4 spaces but found 8 spaces vue/script-indent
+ 40:1 error Expected indentation of 0 spaces but found 8 spaces vue/script-indent
+ 44:1 error Expected indentation of 4 spaces but found 8 spaces vue/script-indent
+ 45:1 error Expected indentation of 4 spaces but found 8 spaces vue/script-indent
+ 46:1 error Expected indentation of 4 spaces but found 8 spaces vue/script-indent
+ 47:1 error Expected indentation of 4 spaces but found 8 spaces vue/script-indent
+ 48:1 error Expected indentation of 4 spaces but found 8 spaces vue/script-indent
+ 72:49 warning Attribute "v-model" should go before ":label" vue/attributes-order
+ 72:49 warning 'v-model' should be on a new line vue/max-attributes-per-line
+ 75:58 warning Attribute "v-model" should go before ":label" vue/attributes-order
+ 75:58 warning 'v-model' should be on a new line vue/max-attributes-per-line
+ 81:9 error Elements in iteration expect to have 'v-bind:key' directives vue/require-v-for-key
+ 81:50 warning 'class' should be on a new line vue/max-attributes-per-line
+ 82:1 error Expected indentation of 12 spaces but found 11 spaces vue/html-indent
+
+/home/gero/documents/uni/pse/pse-dashboard/src/components/ProgressTime.vue
+ 8:5 warning Prop 'unix' requires default value to be set vue/require-default-prop
+ 16:1 error Expected indentation of 4 spaces but found 0 spaces vue/html-indent
+
+/home/gero/documents/uni/pse/pse-dashboard/src/components/Subscription.vue
+ 1:1 error Component name "Subscription" should always be multi-word vue/multi-word-component-names
+ 6:5 warning Prop 'sub' requires default value to be set vue/require-default-prop
+ 6:5 warning Prop "sub" should define at least its type vue/require-prop-types
+ 58:14 warning Expected a linebreak before this attribute vue/first-attribute-linebreak
+ 58:52 warning 'data-bs-toggle' should be on a new line vue/max-attributes-per-line
+ 59:1 error Expected indentation of 13 spaces but found 8 spaces vue/html-indent
+ 59:39 warning Expected 1 line break before closing bracket, but no line breaks found vue/html-closing-bracket-newline
+ 61:13 warning Require self-closing on HTML elements (<i>) vue/html-self-closing
+ 61:67 warning 'style' should be on a new line vue/max-attributes-per-line
+ 63:69 warning Expected 1 line break after opening tag (`<div>`), but 2 line breaks found vue/multiline-html-element-content-newline
+ 67:38 warning Expected 1 line break after opening tag (`<h6>`), but no line breaks found vue/singleline-html-element-content-newline
+ 67:64 warning Expected 1 line break before closing tag (`</h6>`), but no line breaks found vue/singleline-html-element-content-newline
+ 77:29 warning Expected a linebreak before this attribute vue/first-attribute-linebreak
+ 78:1 error Expected indentation of 28 spaces but found 20 spaces vue/html-indent
+ 78:44 warning 'data-bs-target' should be on a new line vue/max-attributes-per-line
+ 79:1 error Expected indentation of 28 spaces but found 20 spaces vue/html-indent
+ 85:60 warning '@click' should be on a new line vue/max-attributes-per-line
+ 93:32 warning 'class' should be on a new line vue/max-attributes-per-line
+ 93:49 warning 'data-bs-parent' should be on a new line vue/max-attributes-per-line
+ 96:21 error Elements in iteration expect to have 'v-bind:key' directives vue/require-v-for-key
+
+/home/gero/documents/uni/pse/pse-dashboard/src/views/EpisodesView.vue
+ 22:29 warning Expected 1 line break after opening tag (`<h1>`), but no line breaks found vue/singleline-html-element-content-newline
+ 22:74 warning Expected 1 line break before closing tag (`</h1>`), but no line breaks found vue/singleline-html-element-content-newline
+ 24:18 warning Attribute ':waitingFor' must be hyphenated vue/attribute-hyphenation
+ 26:17 error Custom elements in iteration require 'v-bind:key' directives vue/valid-v-for
+ 26:61 warning ':action' should be on a new line vue/max-attributes-per-line
+
+/home/gero/documents/uni/pse/pse-dashboard/src/views/ForgotPasswordView.vue
+ 21:39 warning Expected 1 line break after opening tag (`<h1>`), but no line breaks found vue/singleline-html-element-content-newline
+ 21:78 warning Expected 1 line break before closing tag (`</h1>`), but no line breaks found vue/singleline-html-element-content-newline
+ 25:46 warning Attribute "v-model" should go before "type" vue/attributes-order
+ 25:46 warning 'v-model' should be on a new line vue/max-attributes-per-line
+ 25:62 warning ':label' should be on a new line vue/max-attributes-per-line
+ 28:35 warning 'class' should be on a new line vue/max-attributes-per-line
+
+/home/gero/documents/uni/pse/pse-dashboard/src/views/LoginView.vue
+ 26:39 warning Expected 1 line break after opening tag (`<h1>`), but no line breaks found vue/singleline-html-element-content-newline
+ 26:71 warning Expected 1 line break before closing tag (`</h1>`), but no line breaks found vue/singleline-html-element-content-newline
+ 28:39 warning Expected 1 line break after opening tag (`<form>`), but 2 line breaks found vue/multiline-html-element-content-newline
+ 31:62 warning Attribute "v-model" should go before ":label" vue/attributes-order
+ 31:62 warning 'v-model' should be on a new line vue/max-attributes-per-line
+ 34:57 warning Attribute "v-model" should go before ":label" vue/attributes-order
+ 34:57 warning 'v-model' should be on a new line vue/max-attributes-per-line
+ 41:52 warning 'value' should be on a new line vue/max-attributes-per-line
+ 41:72 warning Attribute "v-model" should go before "value" vue/attributes-order
+ 41:72 warning 'v-model' should be on a new line vue/max-attributes-per-line
+ 56:35 warning 'class' should be on a new line vue/max-attributes-per-line
+ 66:17 warning Expected 1 line break before closing tag (`</form>`), but 2 line breaks found vue/multiline-html-element-content-newline
+ 71:41 warning Expected 1 line break after opening tag (`<p>`), but no line breaks found vue/singleline-html-element-content-newline
+ 71:52 warning Expected 1 line break before closing tag (`</p>`), but no line breaks found vue/singleline-html-element-content-newline
+
+/home/gero/documents/uni/pse/pse-dashboard/src/views/RegistrationView.vue
+ 38:39 warning Expected 1 line break after opening tag (`<h1>`), but no line breaks found vue/singleline-html-element-content-newline
+ 38:71 warning Expected 1 line break before closing tag (`</h1>`), but no line breaks found vue/singleline-html-element-content-newline
+ 42:52 warning 'type' should be on a new line vue/max-attributes-per-line
+ 42:64 warning ':label' should be on a new line vue/max-attributes-per-line
+ 45:49 warning 'type' should be on a new line vue/max-attributes-per-line
+ 45:62 warning ':label' should be on a new line vue/max-attributes-per-line
+ 51:35 warning 'class' should be on a new line vue/max-attributes-per-line
+
+/home/gero/documents/uni/pse/pse-dashboard/src/views/ResetPasswordView.vue
+ 9:5 warning Prop 'token' requires default value to be set vue/require-default-prop
+ 10:5 warning Prop 'username' requires default value to be set vue/require-default-prop
+ 41:43 warning Expected 1 line break after opening tag (`<h1>`), but no line breaks found vue/singleline-html-element-content-newline
+ 41:77 warning Expected 1 line break before closing tag (`</h1>`), but no line breaks found vue/singleline-html-element-content-newline
+ 47:35 warning 'class' should be on a new line vue/max-attributes-per-line
+
+/home/gero/documents/uni/pse/pse-dashboard/src/views/SettingsView.vue
+ 176:29 warning Expected 1 line break after opening tag (`<h1>`), but no line breaks found vue/singleline-html-element-content-newline
+ 176:57 warning Expected 1 line break before closing tag (`</h1>`), but no line breaks found vue/singleline-html-element-content-newline
+ 179:52 warning Attribute "class" should go before "@submit.prevent" vue/attributes-order
+ 179:52 warning 'class' should be on a new line vue/max-attributes-per-line
+ 182:63 warning Attribute "v-model" should go before ":label" vue/attributes-order
+ 182:63 warning 'v-model' should be on a new line vue/max-attributes-per-line
+ 182:90 warning Expected a space before '/>', but not found vue/html-closing-bracket-spacing
+ 187:35 warning 'class' should be on a new line vue/max-attributes-per-line
+ 193:51 warning Attribute "class" should go before "@submit.prevent" vue/attributes-order
+ 193:51 warning 'class' should be on a new line vue/max-attributes-per-line
+ 196:1 error Expected indentation of 12 spaces but found 17 spaces vue/html-indent
+ 197:33 warning Expected a linebreak before this attribute vue/first-attribute-linebreak
+ 198:1 error Expected indentation of 32 spaces but found 16 spaces vue/html-indent
+ 198:17 warning Attribute "v-model" should go before ":label" vue/attributes-order
+ 198:42 warning Expected 1 line break before closing bracket, but no line breaks found vue/html-closing-bracket-newline
+ 198:42 warning Expected a space before '/>', but not found vue/html-closing-bracket-spacing
+ 200:1 error Expected indentation of 12 spaces but found 17 spaces vue/html-indent
+ 201:33 warning Expected a linebreak before this attribute vue/first-attribute-linebreak
+ 202:1 error Expected indentation of 32 spaces but found 16 spaces vue/html-indent
+ 202:17 warning Attribute "v-model" should go before ":label" vue/attributes-order
+ 202:42 warning Expected 1 line break before closing bracket, but no line breaks found vue/html-closing-bracket-newline
+ 205:57 warning Attribute "v-model" should go before ":label" vue/attributes-order
+ 205:57 warning 'v-model' should be on a new line vue/max-attributes-per-line
+ 205:82 warning Expected a space before '/>', but not found vue/html-closing-bracket-spacing
+ 207:35 warning 'class' should be on a new line vue/max-attributes-per-line
+ 215:31 warning 'class' should be on a new line vue/max-attributes-per-line
+ 218:13 warning Disallow self-closing on HTML void elements (<input/>) vue/html-self-closing
+ 218:20 warning Expected a linebreak before this attribute vue/first-attribute-linebreak
+ 218:32 warning Attribute "id" should go before "type" vue/attributes-order
+ 218:32 warning 'id' should be on a new line vue/max-attributes-per-line
+ 218:42 warning 'accept' should be on a new line vue/max-attributes-per-line
+ 218:72 warning 'hidden' should be on a new line vue/max-attributes-per-line
+ 219:1 error Expected indentation of 19 spaces but found 16 spaces vue/html-indent
+ 219:37 warning Expected 1 line break before closing bracket, but no line breaks found vue/html-closing-bracket-newline
+ 220:41 warning Attribute "class" should go before "@click" vue/attributes-order
+ 220:41 warning 'class' should be on a new line vue/max-attributes-per-line
+ 226:44 warning Attribute "class" should go before "@submit.prevent" vue/attributes-order
+ 226:44 warning 'class' should be on a new line vue/max-attributes-per-line
+ 229:57 warning Attribute "v-model" should go before ":label" vue/attributes-order
+ 229:57 warning 'v-model' should be on a new line vue/max-attributes-per-line
+ 229:81 warning Expected a space before '/>', but not found vue/html-closing-bracket-spacing
+ 231:35 warning 'class' should be on a new line vue/max-attributes-per-line
+
+/home/gero/documents/uni/pse/pse-dashboard/src/views/SubscriptionsView.vue
+ 9:5 warning Prop 'url' requires default value to be set vue/require-default-prop
+ 83:29 warning Expected 1 line break after opening tag (`<h1>`), but no line breaks found vue/singleline-html-element-content-newline
+ 83:66 warning Expected 1 line break before closing tag (`</h1>`), but no line breaks found vue/singleline-html-element-content-newline
+ 86:49 warning Attribute "class" should go before "@submit.prevent" vue/attributes-order
+ 86:49 warning 'class' should be on a new line vue/max-attributes-per-line
+ 87:72 warning Attribute "v-model" should go before ":label" vue/attributes-order
+ 87:72 warning 'v-model' should be on a new line vue/max-attributes-per-line
+ 88:45 warning 'type' should be on a new line vue/max-attributes-per-line
+ 93:18 warning Attribute ':waitingFor' must be hyphenated vue/attribute-hyphenation
+ 101:53 warning '@click' should be on a new line vue/max-attributes-per-line
+ 104:25 warning Expected a linebreak before this attribute vue/first-attribute-linebreak
+ 105:1 error Expected indentation of 24 spaces but found 16 spaces vue/html-indent
+ 106:1 error Expected indentation of 24 spaces but found 16 spaces vue/html-indent
+ 106:40 warning 'data-bs-target' should be on a new line vue/max-attributes-per-line
+ 106:69 warning Expected 1 line break before closing bracket, but no line breaks found vue/html-closing-bracket-newline
+ 111:21 error Elements in iteration expect to have 'v-bind:key' directives vue/require-v-for-key
+ 111:48 warning 'class' should be on a new line vue/max-attributes-per-line
+ 112:32 warning Expected a linebreak before this attribute vue/first-attribute-linebreak
+ 113:1 error Expected indentation of 31 spaces but found 24 spaces vue/html-indent
+ 113:41 warning ':value' should be on a new line vue/max-attributes-per-line
+ 113:54 warning Attribute "v-model" should go before ":value" vue/attributes-order
+ 113:54 warning 'v-model' should be on a new line vue/max-attributes-per-line
+ 113:84 warning Expected 1 line break before closing bracket, but no line breaks found vue/html-closing-bracket-newline
+ 114:50 warning '@unsubscribe' should be on a new line vue/max-attributes-per-line
+ 117:19 warning Expected 1 line break before closing tag (`</loading>`), but 2 line breaks found vue/multiline-html-element-content-newline
+ 123:24 warning Attribute "id" should go before "class" vue/attributes-order
+ 123:24 warning 'id' should be on a new line vue/max-attributes-per-line
+ 123:37 warning 'tabindex' should be on a new line vue/max-attributes-per-line
+ 125:40 warning Expected 1 line break after opening tag (`<div>`), but 2 line breaks found vue/multiline-html-element-content-newline
+ 132:21 warning Require self-closing on HTML elements (<button>) vue/html-self-closing
+ 132:43 warning 'class' should be on a new line vue/max-attributes-per-line
+ 132:61 warning 'data-bs-dismiss' should be on a new line vue/max-attributes-per-line
+ 132:85 warning 'aria-label' should be on a new line vue/max-attributes-per-line
+ 137:80 warning Attribute "v-model" should go before ":label" vue/attributes-order
+ 137:80 warning 'v-model' should be on a new line vue/max-attributes-per-line
+ 142:43 warning 'class' should be on a new line vue/max-attributes-per-line
+ 142:69 warning 'data-bs-dismiss' should be on a new line vue/max-attributes-per-line
+ 145:43 warning '@click' should be on a new line vue/max-attributes-per-line
+ 145:68 warning Attribute "data-bs-dismiss" should go before "@click" vue/attributes-order
+ 145:68 warning 'data-bs-dismiss' should be on a new line vue/max-attributes-per-line
+ 145:92 warning Attribute "class" should go before "@click" vue/attributes-order
+ 145:92 warning 'class' should be on a new line vue/max-attributes-per-line
+ 154:24 warning Attribute "id" should go before "class" vue/attributes-order
+ 154:24 warning 'id' should be on a new line vue/max-attributes-per-line
+ 154:41 warning 'tabindex' should be on a new line vue/max-attributes-per-line
+ 156:40 warning Expected 1 line break after opening tag (`<div>`), but 2 line breaks found vue/multiline-html-element-content-newline
+ 163:21 warning Require self-closing on HTML elements (<button>) vue/html-self-closing
+ 163:43 warning 'class' should be on a new line vue/max-attributes-per-line
+ 163:61 warning 'data-bs-dismiss' should be on a new line vue/max-attributes-per-line
+ 163:85 warning 'aria-label' should be on a new line vue/max-attributes-per-line
+ 168:80 warning 'role' should be on a new line vue/max-attributes-per-line
+ 169:25 warning Require self-closing on HTML elements (<i>) vue/html-self-closing
+ 176:25 error Elements in iteration expect to have 'v-bind:key' directives vue/require-v-for-key
+ 177:52 warning Expected 1 space before '}}', but not found vue/mustache-interpolation-spacing
+ 187:43 warning 'class' should be on a new line vue/max-attributes-per-line
+ 187:69 warning 'data-bs-dismiss' should be on a new line vue/max-attributes-per-line
+ 190:43 warning '@click' should be on a new line vue/max-attributes-per-line
+ 190:76 warning Attribute "data-bs-dismiss" should go before "@click" vue/attributes-order
+ 190:76 warning 'data-bs-dismiss' should be on a new line vue/max-attributes-per-line
+ 190:100 warning Attribute "class" should go before "@click" vue/attributes-order
+ 190:100 warning 'class' should be on a new line vue/max-attributes-per-line
+
+✖ 310 problems (56 errors, 254 warnings)
+ 43 errors and 194 warnings potentially fixable with the `--fix` option.
+
diff --git a/30-qualitaetsheft/assets/unsubscribe-podcasts.png b/30-qualitaetsheft/assets/unsubscribe-podcasts.png
new file mode 100644
index 0000000..3a25de6
--- /dev/null
+++ b/30-qualitaetsheft/assets/unsubscribe-podcasts.png
Binary files differ
diff --git a/30-qualitaetsheft/qualitaetsheft.tex b/30-qualitaetsheft/qualitaetsheft.tex
new file mode 100644
index 0000000..cb6eed1
--- /dev/null
+++ b/30-qualitaetsheft/qualitaetsheft.tex
@@ -0,0 +1,106 @@
+% \documentclass[a4paper, UTF8, 12pt]{article}
+% \documentclass[a4paper, UTF8, 12pt]{scrbook}
+\documentclass[parskip=half, a4paper, 12pt]{scrartcl}
+
+\usepackage[german]{babel}
+\usepackage[dvipsnames]{xcolor}
+\usepackage{tabularx}
+% \usepackage{tikz}
+% \usetikzlibrary{positioning}
+% \usetikzlibrary{calc}
+% \usetikzlibrary{arrows}
+% \usetikzlibrary{intersections}
+% \usepackage{tikz-uml}
+% \usepackage{pgf-umlsd}
+% \usepgflibrary{arrows} % for pgf-umlsd
+% \tikzumlset{fill usecase=white}
+\usepackage[margin=2.5cm]{geometry}
+\usepackage{csquotes}
+\usepackage[T1]{fontenc}
+\usepackage{amsmath}
+\usepackage{pdflscape}
+\usepackage{graphicx}
+\usepackage{caption}
+\usepackage{subcaption}
+\usepackage{float}
+\usepackage{enumitem}
+% \usepackage{textpos}
+\usepackage{hyperref}
+\usepackage{fancyhdr}
+% \usepackage{multicol}
+\usepackage{rest-api}
+\usepackage{wrapfig}
+\usepackage{textcomp}
+\usepackage{ulem}
+\usepackage{fourier}
+\usepackage{array}
+\usepackage{makecell}
+\usepackage{pgfplots, pgfplotstable}
+\usepgfplotslibrary{dateplot}
+\pgfplotsset{compat=newest}
+
+\hypersetup{
+% ‘texdoc hyperref‘ for options
+ pdftitle={
+ PSE\textsuperscript{2}
+ - Podcast Synchronisation made Efficient Pflichtenheft
+ },
+ bookmarks=true,
+}
+\usepackage{csquotes}
+\usepackage[toc]{glossaries}
+\usepackage{lastpage}
+
+\renewcommand\theadalign{bc}
+\renewcommand\theadfont{\bfseries}
+\renewcommand\theadgape{\Gape[4pt]}
+\renewcommand\cellgape{\Gape[4pt]}
+
+\include{sections/glossar}
+
+\title{Qualitätsheft}
+\author{KIT Students et al}
+\date{2.12.2022}
+
+\pagestyle{fancy}
+\setkomafont{pageheadfoot}{\footnotesize\scshape}
+\fancyhead{} % clear all header fields
+% \fancyhead[L]{Pflichtenheft}
+\fancyhead[L]{PSE\textsuperscript{2} - Podcast Synchronisation made Efficient}
+% \fancyhead[R]{2.12.2022}
+\fancyfoot{} % clear all footer fields
+\fancyfoot[R]{\thepage{} / \pageref{LastPage}}
+\fancyfoot[L]{Praxis der Softwareentwicklung}
+\fancyfoot[C]{}
+
+\begin{document}
+
+\include{titlepage}
+\setcounter{page}{1}
+
+\tableofcontents
+
+\include{sections/einleitung}
+\newpage
+
+\include{sections/changes}
+\newpage
+
+\include{sections/testfaelle}
+\newpage
+
+\include{sections/coverage}
+\newpage
+
+\include{sections/lasttest}
+\newpage
+
+\include{sections/problems}
+\newpage
+
+\include{sections/codestyle}
+
+\printglossaries
+% \glsaddall
+
+\end{document}
diff --git a/30-qualitaetsheft/sections/backend.tex b/30-qualitaetsheft/sections/backend.tex
new file mode 100644
index 0000000..19efd65
--- /dev/null
+++ b/30-qualitaetsheft/sections/backend.tex
@@ -0,0 +1,28 @@
+\section{Backend}
+
+Für das Backend wird das \Gls{java}-Framework \Gls{spring} verwendet. Neben seiner Modularität,
+bietet es viele Funktionen, die unter
+anderem die Entwicklung von Backend-Anwendungen vereinfachen.
+Darunter fällt zum Beispiel die Unterstützung von Dependency Injection, dessen
+Vorteile bereits beschrieben wurden.
+Außerdem unterstützt \Gls{java} \Gls{spring} intern eine Verwaltung von \Glspl{db}, sodass
+sich nicht mit dem \Gls{SQL}-Code an sich befasst werden muss.
+Auch bezüglich Authentifizierung und Sicherheit bietet \Gls{spring} eigene Funktionalitäten.
+
+Zusätzlich dazu wird als Build-System für das \Gls{java}-\Gls{spring}-Backend Maven verwendet.
+Maven hilft dabei alle Abhängigkeiten des Projekts zu verwalten und automatisiert
+den Build Prozess.
+Durch die zusätzliche Unterstützung von Versionskontrollsystemen und der Kompatibilität
+zu vielen Continuous Integration-Tools wird außerdem die Entwicklung in einem Team erleichtert
+und optimiert. Denn dadurch können Build- und Deployment-Prozesse automatisiert werden.
+Außerdem bietet Maven Bibliotheken zum Testen sowie zur Generierung von Dokumentationen an.
+
+Vom Backend benötigte Abhängigkeiten:
+\begin{itemize}
+ \item \Gls{spring} Web
+ \item \Gls{spring} Security
+ \item \Gls{spring} Mail Sender
+ \item \Gls{spring} Data JPA
+ \item Lombok
+ \item Rome (\Gls{rss} parsing/fetching)
+\end{itemize} \ No newline at end of file
diff --git a/30-qualitaetsheft/sections/changes.tex b/30-qualitaetsheft/sections/changes.tex
new file mode 100644
index 0000000..27188a7
--- /dev/null
+++ b/30-qualitaetsheft/sections/changes.tex
@@ -0,0 +1,67 @@
+\section{Änderungen zum Implementierungsheft}
+
+Zuallererst werden im Folgenden die Änderungen zum Implementierungsheft aufgelistet und es wird erläutert warum diese
+Änderungen gemacht wurden.
+
+\subsection{Kriterien}
+
+Zwei weitere Kriterien sind nun erfüllt. Diese sind:
+
+\begin{table}[h!]
+\begin{tabularx}{\textwidth}{l|X|c}
+Bezeichner & Zusammenfassung & Implementiert\\\hline
+\textlangle RM7 \textrangle & 50 Anfragen / Sekunde bearbeiten & Ja*\\\hline\hline
+\textlangle RC2 \textrangle & \Glspl{abo} in Weboberfläche deabonnieren & Ja
+\end{tabularx}
+\end{table}
+
+*nicht unter Mindestanforderungen - 2 Kerne, 2GB RAM, 12GB Speicher
+
+\subsection{Aussagekräftige Benachrichtigungen im Frontend}
+
+Zur Implementierungsphase wurden generische Fehlermeldungen angezeigt, falls
+eine Anfrage an den Server fehlschlug. Mit Fehlercodes können Nutzer nicht
+besonders viel anfangen, weshalb wir die Benachrichtigungen überarbeitet haben.
+
+Jetzt werden neben farbenfrohen Symbolen auch verständliche Meldungen angezeigt.
+Fehlermeldungen von Server-Anfragen zeigen dabei einen unterschiedlichen Text
+an, je nachdem welcher HTTP-Code zurück gegeben wurde oder ob der Server
+überhaupt erreichbar ist.
+
+\begin{figure}[h!]
+ \centering
+ \includegraphics[scale=0.5]{assets/notifications.png}
+ \caption{Eine Auswahl von Benachrichtigungen mit Symbol und Nachricht}
+\end{figure}
+
+\newpage
+\subsection{Deabonnieren von Podcasts}
+
+Eine der letzten offenen Kann-Kriterien war das Deabonnieren von Podcasts im
+Dashboard \textlangle RC2 \textrangle. Dies wurde nun nachgeholt. Dabei
+stehen dem Nutzer zwei Optionen zur Verfügung. Die Abonnements können einzeln
+über einen Knopf entfernt werden oder es können mehrere Abonnements mit
+Checkboxen ausgewählt und dann zusammen gelöscht werden.
+Ein weiterer Knopf ermöglicht das gleichzeitige Auswählen aller Abonnements.
+
+Mit beiden Optionen wird der Nutzer erst über die Folgen des Deabonnierens
+in einem Popup-Fenster informiert. Hierbei handelt es sich um den Verlust aller
+Hörfortschritte zu den Abonnements. Dabei wird auf dem Pop-Up zu jedem
+Abonnement auch die Anzahl der gehörten Episoden aufgelistet. Erst bei Bestätigung
+des Popups durch den Benutzer werden die Abonnements und Episoden vom Account entfernt.
+
+\begin{figure}[H]
+ \centering
+ \begin{minipage}{.47\textwidth}
+ \centering
+ \fbox{\includegraphics[width=\textwidth]{assets/select-subscriptions.png}}
+ \caption{Auswählen von Abonnements über Checkboxen}
+ \end{minipage}
+ \hspace{.5cm}
+ \begin{minipage}{.47\textwidth}
+ \centering
+ \includegraphics[width=\textwidth]{assets/unsubscribe-podcasts.png}
+ \caption{Übersicht und Bestätigung des Deabonnements}
+ \end{minipage}
+\end{figure}
+
diff --git a/30-qualitaetsheft/sections/codestyle.tex b/30-qualitaetsheft/sections/codestyle.tex
new file mode 100644
index 0000000..2eb7a0a
--- /dev/null
+++ b/30-qualitaetsheft/sections/codestyle.tex
@@ -0,0 +1,224 @@
+\section{Code-Stil}
+
+\subsection{Server}
+
+% Balkendiagram:
+% zwei Balken: vorher, nachher
+% eine Balken besteht aus verschiedenen Ebenen für jeden Linter Fehler
+\definecolor{error00}{RGB}{255, 0, 0}
+\definecolor{error01}{RGB}{204, 0, 0}
+\definecolor{error02}{RGB}{153, 0, 0}
+\definecolor{error03}{RGB}{102, 0, 0}
+\definecolor{error04}{RGB}{51, 0, 0}
+\definecolor{error05}{RGB}{25, 0, 0}
+
+\definecolor{warning00}{RGB}{255, 255, 0}
+\definecolor{warning01}{RGB}{255, 215, 0}
+\definecolor{warning02}{RGB}{139, 117, 0}
+\definecolor{warning03}{RGB}{238, 201, 0}
+\definecolor{warning04}{RGB}{255, 215, 0}
+\definecolor{warning05}{RGB}{238, 238, 0}
+\definecolor{warning06}{RGB}{139, 139, 0}
+\definecolor{warning07}{RGB}{255, 255, 0}
+\definecolor{warning08}{RGB}{238, 201, 0}
+\definecolor{warning09}{RGB}{205, 173, 0}
+\definecolor{warning10}{RGB}{205, 205, 0}
+\definecolor{warning11}{RGB}{205, 173, 0}
+\definecolor{warning12}{RGB}{238, 238, 0}
+\definecolor{warning13}{RGB}{139, 117, 0}
+\definecolor{warning14}{RGB}{139, 139, 0}
+
+\vspace{-2cm}
+\begin{tikzpicture}
+\begin{axis}[
+ title={Code-Stil-Anmerkungen durch Checkstyle Sun-Checks},
+ ybar stacked, ymin=0,
+ bar width=10mm,
+ symbolic x coords={Vorher,Nachher},
+ legend style={
+ at={(1.3,0.5)},
+ cells={anchor=west},
+ anchor=west
+ },
+ xtick=data,
+ xticklabel style={text width=2cm,align=center},
+ nodes near coords={}
+]
+
+\addplot [fill=error02] coordinates { ({Vorher}, 285 ) ({Nachher}, 0)}; % (sizes) LineLength
+\addplot [fill=error00] coordinates { ({Vorher}, 143 ) ({Nachher}, 0)}; % (misc) FinalParameters
+\addplot [fill=error03] coordinates { ({Vorher}, 101 ) ({Nachher}, 0)}; % (javadoc) JavadocVariable
+\addplot [fill=error04] coordinates { ({Vorher}, 83 ) ({Nachher}, 0)}; % (javadoc) JavadocStyle
+\addplot [fill=error02] coordinates { ({Vorher}, 43 ) ({Nachher}, 0)}; % (design) DesignForExtension
+\addplot [fill=error01] coordinates { ({Vorher}, 39 ) ({Nachher}, 0)}; % (javadoc) MissingJavadocMethod
+\addplot [fill=error01] coordinates { ({Vorher}, 26 ) ({Nachher}, 0)}; % (regexp) RegexpSingleline
+\addplot [fill=error02] coordinates { ({Vorher}, 15 ) ({Nachher}, 0)}; % (whitespace) WhitespaceAround
+\addplot [fill=error01] coordinates { ({Vorher}, 13 ) ({Nachher}, 0)}; % (javadoc) JavadocPackage
+\addplot [fill=error03] coordinates { ({Vorher}, 10 ) ({Nachher}, 0)}; % (whitespace) OperatorWrap
+\addplot [fill=error00] coordinates { ({Vorher}, 10 ) ({Nachher}, 0)}; % (javadoc) JavadocType
+\addplot [fill=error05] coordinates { ({Vorher}, 7 ) ({Nachher}, 0)}; % (imports) AvoidStarImport
+\addplot [fill=error05] coordinates { ({Vorher}, 6 ) ({Nachher}, 0)}; % (coding) MagicNumber
+\addplot [fill=error05] coordinates { ({Vorher}, 4 ) ({Nachher}, 0)}; % (javadoc) JavadocMethod
+\addplot [fill=error04] coordinates { ({Vorher}, 3 ) ({Nachher}, 0)}; % (coding) HiddenField
+\addplot [fill=error02] coordinates { ({Vorher}, 2 ) ({Nachher}, 0)}; % (javadoc) InvalidJavadocPosition
+\addplot [fill=error00] coordinates { ({Vorher}, 2 ) ({Nachher}, 0)}; % (blocks) RightCurly
+\addplot [fill=error03] coordinates { ({Vorher}, 1 ) ({Nachher}, 0)}; % (whitespace) WhitespaceAfter
+\addplot [fill=error04] coordinates { ({Vorher}, 1 ) ({Nachher}, 0)}; % (whitespace) FileTabCharacter
+\addplot [fill=error04] coordinates { ({Vorher}, 1 ) ({Nachher}, 0)}; % (misc) NewlineAtEndOfFile
+\addplot [fill=error01] coordinates { ({Vorher}, 1 ) ({Nachher}, 0)}; % (misc) ArrayTypeStyle
+\addplot [fill=error00] coordinates { ({Vorher}, 1 ) ({Nachher}, 0)}; % (imports) UnusedImports
+\addplot [fill=error03, point meta=y,nodes near coords,nodes near coords align={anchor=south}] coordinates { ({Vorher}, 2 ) ({Nachher}, 1)}; % (design) HideUtilityClassConstructor
+
+\legend{
+sizes: LineLength,
+misc: FinalParameters,
+javadoc: JavadocVariable,
+javadoc: JavadocStyle,
+design: DesignForExtension,
+javadoc: MissingJavadocMethod,
+regexp: RegexpSingleline,
+whitespace: WhitespaceAround,
+javadoc: JavadocPackage,
+whitespace: OperatorWrap,
+javadoc: JavadocType,
+imports: AvoidStarImport,
+coding: MagicNumber,
+javadoc: JavadocMethod,
+coding: HiddenField,
+javadoc: InvalidJavadocPosition,
+blocks: RightCurly,
+whitespace: WhitespaceAfter,
+whitespace: FileTabCharacter,
+misc: NewlineAtEndOfFile,
+misc: ArrayTypeStyle,
+imports: UnusedImports,
+design: HideUtilityClassConstructor,
+}
+\end{axis}
+\end{tikzpicture}
+
+\begin{tabularx}{\textwidth}{X | c | c}
+Regel & Vorher & Nacher \\ \hline
+sizes: LineLength & 285 & 0 \\
+misc: FinalParameters & 143 & 0 \\
+javadoc: JavadocVariable & 101 & 0 \\
+javadoc: JavadocStyle & 83 & 0 \\
+design: DesignForExtension & 43 & 0 \\
+javadoc: MissingJavadocMethod & 39 & 0 \\
+regexp: RegexpSingleline & 26 & 0 \\
+whitespace: WhitespaceAround & 15 & 0 \\
+javadoc: JavadocPackage & 13 & 0 \\
+whitespace: OperatorWrap & 10 & 0 \\
+javadoc: JavadocType & 10 & 0 \\
+imports: AvoidStarImport & 7 & 0 \\
+coding: MagicNumber & 6 & 0 \\
+javadoc: JavadocMethod & 4 & 0 \\
+coding: HiddenField & 3 & 0 \\
+javadoc: InvalidJavadocPosition & 2 & 0 \\
+blocks: RightCurly & 2 & 0 \\
+whitespace: WhitespaceAfter & 1 & 0 \\
+whitespace: FileTabCharacter & 1 & 0 \\
+misc: NewlineAtEndOfFile & 1 & 0 \\
+misc: ArrayTypeStyle & 1 & 0 \\
+imports: UnusedImports & 1 & 0 \\
+design: HideUtilityClassConstructor & 2 & 1 \\
+\end{tabularx}
+
+\subsection{Dashboard}
+
+\vspace{-1.5cm}
+\begin{tikzpicture}
+\begin{axis}[
+ title={Code-Stil-Anmerkungen durch ESLint},
+ ybar stacked, ymin=0,
+ bar width=10mm,
+ symbolic x coords={Vorher,Nachher},
+ legend style={
+ at={(1.1,0.5)},
+ cells={anchor=west},
+ anchor=west
+ },
+ xtick=data,
+ xticklabel style={text width=2cm,align=center},
+ nodes near coords={}
+]
+
+\addplot [fill=error00] coordinates { ({Vorher}, 26 ) ({Nachher}, 0)}; % error vue/html-indent
+\addplot [fill=error01] coordinates { ({Vorher}, 17 ) ({Nachher}, 0)}; % error vue/script-indent
+\addplot [fill=error02] coordinates { ({Vorher}, 6 ) ({Nachher}, 0)}; % error vue/require-v-for-key
+\addplot [fill=error03] coordinates { ({Vorher}, 5 ) ({Nachher}, 0)}; % error vue/multi-word-component-names
+\addplot [fill=error04] coordinates { ({Vorher}, 1 ) ({Nachher}, 0)}; % error vue/valid-v-for
+\addplot [fill=error05] coordinates { ({Vorher}, 1 ) ({Nachher}, 0)}; % error vue/valid-template-root
+\addplot [fill=warning00] coordinates { ({Vorher}, 125 ) ({Nachher}, 0)}; % warning vue/max-attributes-per-line
+\addplot [fill=warning01] coordinates { ({Vorher}, 34 ) ({Nachher}, 0)}; % warning vue/attributes-order
+\addplot [fill=warning02] coordinates { ({Vorher}, 26 ) ({Nachher}, 0)}; % warning vue/singleline-html-element-content-newline
+\addplot [fill=warning03] coordinates { ({Vorher}, 12 ) ({Nachher}, 0)}; % warning vue/require-default-prop
+\addplot [fill=warning04] coordinates { ({Vorher}, 12 ) ({Nachher}, 0)}; % warning vue/html-self-closing
+\addplot [fill=warning05] coordinates { ({Vorher}, 11 ) ({Nachher}, 0)}; % warning vue/first-attribute-linebreak
+\addplot [fill=warning06] coordinates { ({Vorher}, 10 ) ({Nachher}, 0)}; % warning vue/html-closing-bracket-newline
+\addplot [fill=warning07] coordinates { ({Vorher}, 8 ) ({Nachher}, 0)}; % warning vue/multiline-html-element-content-newline
+\addplot [fill=warning08] coordinates { ({Vorher}, 5 ) ({Nachher}, 0)}; % warning vue/html-closing-bracket-spacing
+\addplot [fill=warning09] coordinates { ({Vorher}, 3 ) ({Nachher}, 0)}; % warning vue/require-prop-types
+\addplot [fill=warning10] coordinates { ({Vorher}, 3 ) ({Nachher}, 0)}; % warning vue/attribute-hyphenation
+\addplot [fill=warning11] coordinates { ({Vorher}, 2 ) ({Nachher}, 0)}; % warning vue/html-self-closing
+\addplot [fill=warning12] coordinates { ({Vorher}, 1 ) ({Nachher}, 0)}; % warning vue/v-on-event-hyphenation
+\addplot [fill=warning13] coordinates { ({Vorher}, 1 ) ({Nachher}, 0)}; % warning vue/no-v-html
+\addplot +[fill=warning14, point meta=y,nodes near coords,nodes near coords align={anchor=south}]coordinates { ({Vorher}, 1 ) ({Nachher}, 1)}; % warning vue/mustache-interpolation-spacing
+
+
+\legend{
+error: html-indent,
+error: script-indent,
+error: require-v-for-key,
+error: multi-word-component-names,
+error: valid-v-for,
+error: valid-template-root,
+warning: max-attributes-per-line,
+warning: attributes-order,
+warning: singleline-html-element-content-newline,
+warning: require-default-prop,
+warning: html-self-closing,
+warning: first-attribute-linebreak,
+warning: html-closing-bracket-newline,
+warning: multiline-html-element-content-newline,
+warning: html-closing-bracket-spacing,
+warning: require-prop-types,
+warning: attribute-hyphenation,
+warning: html-self-closing,
+warning: v-on-event-hyphenation,
+warning: mustache-interpolation-spacing,
+warning: no-v-html,
+}
+\end{axis}
+\end{tikzpicture}
+
+\begin{tabularx}{\textwidth}{X | c | c}
+Regel & Vorher & Nachher \\ \hline
+error: html-indent & 26 & 0 \\
+error: script-indent & 17 & 0 \\
+error: require-v-for-key & 6 & 0 \\
+error: multi-word-component-names & 5 & 0 \\
+error: valid-v-for & 1 & 0 \\
+error: valid-template-root & 1 & 0 \\
+warning: max-attributes-per-line & 125 & 0 \\
+warning: attributes-order & 34 & 0 \\
+warning: singleline-html-element-content-newline & 26 & 0 \\
+warning: require-default-prop & 12 & 0 \\
+warning: html-self-closing & 12 & 0 \\
+warning: first-attribute-linebreak & 11 & 0 \\
+warning: html-closing-bracket-newline & 10 & 0 \\
+warning: multiline-html-element-content-newline & 8 & 0 \\
+warning: html-closing-bracket-spacing & 5 & 0 \\
+warning: require-prop-types & 3 & 0 \\
+warning: attribute-hyphenation & 3 & 0 \\
+warning: html-self-closing & 2 & 0 \\
+warning: v-on-event-hyphenation & 1 & 0 \\
+warning: mustache-interpolation-spacing & 1 & 0 \\
+warning: no-v-html & 1 & 1 \\
+\end{tabularx}
+
+Das Attribut \texttt{v-html} wird genutzt, um das Hilfe-Popup zu übersetzen. Die
+Übersetzungen für jede Sprache ist in einer separaten \texttt{HTML}-Datei gespeichert.
+Dies gibt dem Übersetzer einen großen Spielraum dafür, welche Inhalte in den Hilfe-Popups
+ausgegeben werden können.
+
diff --git a/30-qualitaetsheft/sections/coverage.tex b/30-qualitaetsheft/sections/coverage.tex
new file mode 100644
index 0000000..b8ba635
--- /dev/null
+++ b/30-qualitaetsheft/sections/coverage.tex
@@ -0,0 +1,59 @@
+\section{Codeabdeckung}
+
+\subsection{Einleitung}
+
+Die Codeabdeckung ist eine Methodik den Code weitflächig zu durchlaufen, um eine korrekte Verhaltensweise des Synchronisationsservers sicherzustellen.
+Die Knotenabdeckung stellt hierbei sicher, dass möglichst jede Instruktion im Code von mindestens einem Test durchlaufen wird.
+Die Zweigabdeckung stellt sicher, dass möglichst jeder Zweig (bspw. bei Verzweigungen) von mindestens einem Test durchlaufen wird.
+Schließlich gibt es noch die Pfadabdeckung, die sicherstellt, dass möglichst jeder Pfad von mindestens einem Test durchlaufen wird.
+
+In diesem Fall liegt der Fokus auf den ersten beiden Abdeckungen.
+Um die Codeabdeckung zu messen und zu dokumentieren, wurde das Tool JaCoCo verwendet.
+Viele Klassen des Projekts sind lediglich Model-Klassen oder dienen
+ausschließlich als Schicht zur Weiterleitung von Daten, weshalb
+diese bereits implizit abgedeckt sind.
+
+Zusätzlich werden durch das Tool Lombok, dem Framework Spring oder den JPA Repositories
+Methoden implizit eingebunden, welche dadurch nicht selbst implementiert werden müssen
+und bereits ausgiebig getestet sind.
+Dadurch ist eine explizite Abdeckung all dieser Methoden überflüssig,
+weshalb die Codeabdeckung nicht sonderlich hoch erscheint.
+
+In den Klassen erzielt, deren Funktionalität von Hand implementiert worden sind, ergibt sich wiederum mit den Tests eine hohe Codeabdeckung.
+
+\subsection{Insgesamte Abdeckung}
+\begin{figure}[h]
+ \centering
+ \includegraphics[width=\textwidth,height=\textheight,keepaspectratio]{assets/coverage/server.png}
+\end{figure}
+Model-Paket und Controller-Klassen sind implizit durch ServiceTests
+abgedeckt.
+
+
+\subsection{Authentication Service}
+\begin{figure}[h]
+ \centering
+ \includegraphics[width=\textwidth,height=\textheight,keepaspectratio]{assets/coverage/authenticationService.png}
+\end{figure}
+
+
+\subsection{Subscriptions Service}
+\begin{figure}[h]
+ \centering
+ \includegraphics[width=\textwidth,height=\textheight,keepaspectratio]{assets/coverage/subscriptionsService.png}
+\end{figure}
+
+\subsection{EpisodeAction Service}
+\begin{figure}[h]
+ \centering
+ \includegraphics[width=\textwidth,height=\textheight,keepaspectratio]{assets/coverage/episodeActionService.png}
+\end{figure}
+
+
+\subsection{Util Paket}
+\begin{figure}[h]
+ \centering
+ \includegraphics[width=\textwidth,height=\textheight,keepaspectratio]{assets/coverage/util.png}
+\end{figure}
+UpdateUrlsWrapper ist lediglich ein Platzhalter für die leere UpdateUrls Liste,
+welche zurückgeben wird, da diese Funktion nicht unterstützt wird. \ No newline at end of file
diff --git a/30-qualitaetsheft/sections/einleitung.tex b/30-qualitaetsheft/sections/einleitung.tex
new file mode 100644
index 0000000..b80d952
--- /dev/null
+++ b/30-qualitaetsheft/sections/einleitung.tex
@@ -0,0 +1,13 @@
+\section{Einleitung}
+
+Nach der Planung im Pflichten- und Entwurfsheft und der Implementierung im Implementierungsheft kommt im Qualitätssicherungsheft nun die Qualitätssicherung.
+In dieser wird die Implementierung ausgiebig getestet.
+Dabei werden unter anderem auch die im Pflichtenheft beschriebenen Testfälle abgearbeitet.
+
+Weitere Testfälle sorgen für eine möglichst große Knotenabdeckung des Codes. Dabei wird sichergestellt, dass alle Grundblöcke des Programms mindestens einmal durchlaufen werden.
+
+Ein Lasttest überprüft wie stark der Server belastet werden kann und wie sich die Last auf die Performance des Servers auswirkt.
+
+Es wird auch auf Probleme eingegangen, die während der Qualitätssicherung aufgefallen sind und wie gegen diese Probleme vorgegangen worden ist.
+
+Schließlich folgt noch ein Bericht über die Verbesserung des Code-Stils nach dem Checkstyle von Sun. \ No newline at end of file
diff --git a/30-qualitaetsheft/sections/frontend.tex b/30-qualitaetsheft/sections/frontend.tex
new file mode 100644
index 0000000..ae5be0e
--- /dev/null
+++ b/30-qualitaetsheft/sections/frontend.tex
@@ -0,0 +1,196 @@
+\section{Weboberfläche}
+
+Die Weboberfläche wird mit dem Frontend-Web-Framework Vue.js erstellt. Mit Vue
+werden wiederverwendbare, auf Datenänderungen reagierende Komponenten erstellt.
+Die Komponenten nutzen ein fertiges Aussehen von dem Frontend-CSS-Framework
+Bootstrap. Außerdem werden Icons der freien Schriftart fontawesome
+verwendet.
+
+An der generellen Struktur und wichtigen Komponenten hat sich in der
+Implementierung nichts großes zum Entwurf geändert. Einige Komponenten konnten
+in der Implementierung allerdings abstrahiert werden, sodass weniger Code
+dupliziert werden musste. Dazu gehören zum Beispiel die Komponenten, welche ein
+Eingabefeld bereit stellen.
+
+Durch eine gute Arbeitsteilung blieb genug Zeit, um auch einige Kann-Kriterien
+zu implementieren, weshalb ein paar Abhängigkeiten hinzugekommen sind. So werden
+jszip und file-saver benötigt, um das Kann-Kriterium RC3 umzusetzen, durch
+welches man Nutzerdaten im- und exportieren kann.
+
+Pinia konnten wir als Abhängigkeit entfernen, weil Vue von sich aus genügend
+Funktionalität bietet die Nutzerdaten global allen Komponenten bereit zu
+stellen.
+
+Anfangs überlegten wir den Wrapper \texttt{bootstrap-vue} zu verwenden, welcher
+Bootstrap-HTML-Strukturen als Vue-Komponenten bereit stellt. Dies hätte des
+Vorteil, dass man nur jene Komponenten importieren müsste, die man auch
+benötigt. Es stellte sich heraus, dass \texttt{vue-bootstrap} nicht mit neusten
+Version Vue3 kompatibel ist, weshalb wir uns entschieden Bootstrap wie gewohnt
+komplett einzubinden.
+
+Während der Implementierung sind wir auf die Bibliothek \texttt{VueUse}
+gestoßen, mit der man die Abhängigkeit \texttt{file-saver} und mehrere eigene
+Wrapper für Browser-\Gls{api}s ersetzen könnte. So kann man das \Gls{dashboard} auch in
+Zukunft noch weiter verbessern.
+
+Vom Frontend benötigte Abhängigkeiten:
+\begin{itemize}
+ \item vite
+ \item vue
+ \item vue-router
+ \item \textcolor{red}{\sout{Pinia} wird durch globale Vue-Interne \texttt{ref} ersetzt}
+ \item bootstrap
+ \item fontawesome
+ \item vue-i18n (Support für mehrere Sprachen)
+ \item \textcolor{Green}{dayjs (Rechnen und formatieren von Zeiten)}
+ \item \textcolor{Green}{jszip (erstellen von Im-/Exports)}
+ \item \textcolor{Green}{file-saver (Abstraktion für Datei-Speichern-Dialog)}
+\end{itemize}
+
+\subsection{Komponentendiagramm Web-Frontend}
+\includegraphics[width=\textwidth]{assets/diagrams/componentdiagram}
+
+\subsection{Hinzugefügte Komponenten}
+
+% PasswordInput
+% PasswordValidator
+% FloatingLabelInput
+% Loading
+% ErrorLog
+% ProgressTime
+
+\begin{minipage}{.7\linewidth}
+
+\subsubsection*{FloatingLabelInput}
+
+\begin{description}
+\item[Tag] \texttt{<FloatingLabelInput type label>}
+\item[Props] \mbox{} \\
+ \emph{type} \mbox{} Beschreibt den Inhalt des Eingabefelder. Handelt es sich
+ um eine E-Mail, ein Passwort oder nur Text? \\
+ \emph{label} \mbox{} Das Label wird als Platzhalter und kleine Überschrift
+ angezeigt.
+\item[Beschreibung] Abstrahiert eine HTML-Struktur von Bootstrap, um ein schönes
+ Eingabefeld anzuzeigen.
+\end{description}
+\end{minipage}
+\begin{minipage}{.3\linewidth}
+ \begin{figure}[H]
+ \includegraphics[width=\textwidth]{assets/floatinglabelinput.png}
+ \end{figure}
+\end{minipage}
+
+
+\vspace{.5cm}
+
+\begin{minipage}{.7\linewidth}
+
+\subsubsection*{PasswordInput}
+
+\begin{description}
+\item[Tag] \texttt{<PasswordInput type label>}
+\item[Props] \mbox{} \\
+ \emph{label} \mbox{} Das Label wird als Platzhalter und kleine Überschrift
+ angezeigt.
+\item[Beschreibung] Erweitert den FloatingLabelInput um einen Knopf mit dem die
+ Sichtbarkeit des Eingabefeldes gewechselt werden kann. Dabei wird intern der
+ Typ des Eingabefeldes zwischen Text and Passwort gewechselt.
+\end{description}
+\end{minipage}
+\begin{minipage}{.3\linewidth}
+ \begin{figure}[H]
+ \includegraphics[width=\textwidth]{assets/passwordinput.png}
+ \end{figure}
+\end{minipage}
+
+
+\vspace{.5cm}
+
+\begin{minipage}{.7\linewidth}
+
+\subsubsection*{PasswordValidator}
+
+\begin{description}
+\item[Tag] \texttt{<PasswordValidator>}
+\item[Beschreibung] Besteht aus zwei PasswordInputs und überprüft diese auf
+ Gleichheit und Kriterien für eine gutes Passwort.
+\end{description}
+\end{minipage}
+\begin{minipage}{.3\linewidth}
+ \begin{figure}[H]
+ \includegraphics[width=\textwidth]{assets/passwordvalidator.png}
+ \end{figure}
+\end{minipage}
+
+
+\vspace{.5cm}
+
+\begin{minipage}{.7\linewidth}
+
+\subsubsection*{Loading}
+
+\begin{description}
+\item[Tag] \texttt{<Loading waitingFor>...<Loading/>}
+\item[Props] \mbox{} \\
+ \emph{waitingFor} \mbox{} Eine Referenz auf eine Bedingung wann die Kinder
+ der Komponente gezeigt werden sollen.
+\item[Beschreibung] Zeigt solange ein Ladesymbol an, bis die Bedingung in
+ \texttt{waitingFor} erfüllt ist und stattdessen die Kinder der Komponente
+ gezeigt werden.
+\end{description}
+\end{minipage}
+\begin{minipage}{.3\linewidth}
+ \begin{figure}[H]
+ \includegraphics[width=\textwidth]{assets/loading.png}
+ \end{figure}
+\end{minipage}
+
+
+\vspace{.5cm}
+
+\begin{minipage}{.7\linewidth}
+
+\subsubsection*{ProgressTime}
+
+\begin{description}
+\item[Tag] \texttt{<ProgressTime unix>}
+\item[Props] \mbox{} \\
+ \emph{unix} \mbox{} Anzahl an Sekunden.
+\item[Beschreibung] Nimmt eine Anzahl an Sekunden und gibt an wie viele Stunden,
+ Minuten und Sekunden die Anzahl entspricht.
+\end{description}
+\end{minipage}
+\begin{minipage}{.3\linewidth}
+ \begin{figure}[H]
+ \includegraphics[width=\textwidth]{assets/progresstime.png}
+ \end{figure}
+\end{minipage}
+
+
+\vspace{.5cm}
+
+\begin{minipage}{.7\linewidth}
+
+\subsubsection*{ErrorLog}
+
+\begin{description}
+\item[Tag] \texttt{<ErrorLog>}
+\item[Beschreibung] Zeigt eine Liste von Warnungen an, welche aus einem globalen
+ Zustandsspeicher geladen werden.
+\end{description}
+\end{minipage}
+\begin{minipage}{.3\linewidth}
+ \begin{figure}[H]
+ \includegraphics[width=\textwidth]{assets/errorlog.png}
+ \end{figure}
+\end{minipage}
+
+
+\vspace{.5cm}
+
+\subsubsection*{Dashboard/FormLayout}
+
+\begin{description}
+\item[Tag] \texttt{<DashboardLayout> <FormLayout>}
+\item[Beschreibung] Fügt den Kindern einen Seitenabstand hinzu.
+\end{description}
diff --git a/30-qualitaetsheft/sections/glossar.tex b/30-qualitaetsheft/sections/glossar.tex
new file mode 100644
index 0000000..b664e58
--- /dev/null
+++ b/30-qualitaetsheft/sections/glossar.tex
@@ -0,0 +1,391 @@
+\makeglossaries
+
+\newglossaryentry{spa}
+{
+ name=Single-Page-Application,
+ description={
+ ist ein Webseiten-Modell, bei welchem dem Nutzer nur ein Webdokument
+ bereitgestellt wird. Mit einem Skript wird der Inhalt der Seite
+ dynamisch mit Daten einer API befüllt. Außerdem verwaltet die Seite
+ (nicht der Server), welcher Inhalt bei welchem Pfad angezeigt wird. Dies
+ erzeugt geringere Serverlast und eine bessere Nutzererfahrung, da die
+ Seitenstruktur beim Laden von neuen Inhalten erhalten bleibt}
+}
+
+\newglossaryentry{packagemanager}
+{
+ name=Paketmanager,
+ description={
+ ist ein Programm, welches Pakete und dessen Abhängigkeiten verwaltet,
+ installiert, entfernt und aktualisiert. Pakete können andere Programme,
+ Plugins oder Software-Bibliotheken sein}
+}
+
+\newglossaryentry{bundler}
+{
+ name=Bundler,
+ description={
+ ist ein Programm, welches genutzte Teile von Abhängigkeiten eines
+ Software-Projekts in passender Reihenfolge zusammensucht und daraus
+ Dateien erstellt, die für den Nutzer bereitgestellt werden können. Dabei
+ kann der Bundler mit zusätzlichen Modulen Dateien erzeugen, die
+ rückwärtskompatibel oder für den Nutzer schwerer einsehbar sind}
+}
+
+\newglossaryentry{java}
+{
+ name=Java,
+ description={
+ ist eine objekt-orientierte interpretierte kompilierte
+ Programmiersprache, welche plattformunabhängig auf einer virtuellen
+ Maschine ausgeführt wird}
+}
+
+\newglossaryentry{db}
+{
+ name=Datenbank,
+ plural=Datenbanken,
+ description={
+ ist ein System um Daten persistent zu speichern und effizient zu
+ verwalten. Am meisten verbreitet sind relationale Datenbanken, welche
+ Daten in Tabellen mit Referenzen zu Einträgen anderer Tabellen
+ speichern. Programme können dann über eine Anfragesprache (Structured
+ Query Language - \Gls{SQL}) komplexe Operationen auf den Daten ausführen}
+}
+
+\newglossaryentry{docker}
+{
+ name=Docker,
+ description={
+ ist ein Programm, das virtualisierte Container ausführt. Ein Programm in
+ so einem Container läuft in seiner eigenen virtuellen Umgebung, wodurch
+ das Host-System sicher bleibt. Zudem lassen sich die Container leicht
+ auf andere Systeme verteilen}
+}
+
+% RESTfull-API, JSON, RSS-Feed, Salting and Hasing, OAuth, Cookie, Garbage
+% Collection, DSGVO, Podcast, Podcatcher, Episode, Gpodder,
+
+\newglossaryentry{podcatcher}
+{
+ name=Podcatcher,
+ plural=Podcatchern,
+ description={
+ ist ein Programm, über welches man Podcasts entdecken, abonnieren und
+ Episoden von Podcasts hören kann. Mit einem Account auf einer Plattform,
+ welche eine Gpodder-API zur Verfügung stellt, können Ereignisse, die von
+ einem Nutzer ausgehen, auf anderen Podcatchern des Nutzers
+ synchronisiert werden}
+}
+
+\newglossaryentry{podcast}
+{
+ name=Podcast,
+ description={
+ ist ein RSS-Feed, dessen Einträge die Episoden darstellen}
+}
+
+\newglossaryentry{episode}
+{
+ name=Episode,
+ plural=Episoden,
+ description={
+ ist ein Eintrag in einem Podcast. Eine URL in dem Eintrag zeigt auf eine
+ Medien-Datei, welche vom Podcatcher abgespielt werden kann}
+}
+
+\newglossaryentry{rest-api}
+{
+ name=RESTful-API,
+ description={
+ ist ein Schnittstellenentwurf über das Hypertext Transfer Protocol
+ (HTTP), bei dem die Schnittstellen strukturiert als Pfad an einem
+ Endpunkt erreichbar sind. Mittels verschiedener HTTP-Methoden können an
+ der Schnittstelle Daten abgefragt (GET), gesendet (PUT), gelöscht
+ (DELETE) oder geändert (POST) werden. Die Daten, die über die
+ Schnittstelle gesendet werden liegen meist im JSON-Format vor}
+}
+
+
+\newglossaryentry{gpodder}
+{
+ name=Gpodder-API,
+ description={
+ wird von gpodder.net benutzt und entwickelt. Die API wird als
+ Schnittstelle zwischen Podcatchern und Podcast Synchronisationsservern
+ verwendet. Weitere Details sind unter
+ "https://gpoddernet.readthedocs.io/en/latest/api/" zu finden}
+}
+
+\newglossaryentry{json}
+{
+ name=JSON,
+ description={
+ (JavaScript Object Notation) ist ein Datenformat und wird zur
+ Übertragung von Strukturen und Daten eingesetzt. JSON besteht dabei aus
+ grundlegenden Datentypen sowie Objekten mit Schlüssel-Wert Paaren und
+ Listen}
+}
+
+\newglossaryentry{oauth}
+{
+ name=OAuth,
+ description={
+ (Open Authorization) ist ein offenes Protokoll, welches es Nutzern
+ ermöglicht, sich mit bereits bestehenden Accounts bei anderen Diensten
+ zu registrieren. Dabei werden benötigte Daten für die Registrierung über
+ die bereitgestellte Schnittstelle zur Verfügung gestellt}
+}
+
+\newglossaryentry{garbage-collection}
+{
+ name=Garbage Collection,
+ description={
+ ist eine automatische Speicherbereinigung, welche nicht mehr benötigten
+ Speicherplatz wieder freigibt. Die Bereinigung kann dabei in determinierten
+ Zeitintervallen erfolgen oder durch bestimmte Ereignisse ausgelöst
+ werden}
+}
+
+\newglossaryentry{salt-hash}
+{
+ name=Salting und Hashing,
+ description={
+ ist eine Methode um Passwörter so zu kodieren, dass sie nicht als
+ Klartext gespeichert werden und auch sicher vor Hash-Wörterbüchern sind.
+ Dafür wird dem Passwort ein bekanntes Wort, der Salt, angefügt, bevor
+ aus dem kompletten Wort eine Prüfsumme, ein Hash, generiert wird. Beim
+ Anmelden wird die Prüfsumme der Anmeldung mit der bekannten
+ Prüfsumme des Passworts verglichen}
+}
+
+\newglossaryentry{rss}
+{
+ name=RSS,
+ description={
+ (Really Simple Syndication) zeigt strukturiert Listen von Nachrichten
+ an. Die Änderungen werden im XML-Format in sogenannte RSS-Dateien
+ geschrieben, welche über einen Link abgerufen werden können}
+}
+
+\newglossaryentry{dsgvo}
+{
+ name=Datenschutz-Grundverordnung,
+ description={
+ (DSGVO) ist eine im europäischen Wirtschaftsraum
+ geltende Verordnung. Sie sorgt für eine Reglementierung bei der
+ Verarbeitung personenbezogener Daten. Unter anderem muss einsehbar sein,
+ welche Daten von Nutzern erhoben werden. Außerdem muss für einen Nutzer
+ die Möglichkeit bestehen, seine erhobenen Daten abrufen zu können}
+}
+
+\newglossaryentry{push-pull}
+{
+ name=Push und Pull,
+ description={
+ sind Methoden, um Daten auszutauschen. Bei der Pull-Methode
+ stellt Akteur A einem Akteur B eine Anfrage auf Daten und erhält diese
+ als Antwort. Damit Akteur A und B immer auf dem selben Stand sind, muss
+ Akteur A chronisch Anfragen an Akteur B stellen. Im Gegensatz dazu steht
+ die Push-Methode, bei der Akteur B den Akteuren mitteilt, dass er neue
+ Änderungen hat. Dafür muss Akteur B allerdings wissen mit welchen
+ anderen Akteuren er in Verbindung steht und diese Verbindung aufrecht
+ erhalten}
+}
+
+\newglossaryentry{ui-lib}
+{
+ name=UI-Bibliothek,
+ plural=UI-Bibliotheken,
+ description={
+ kümmert sich um das Layout einer Webseite. Dabei unterscheidet man
+ zwischen Design-Bibliotheken (wie Bootstrap), welche fertige
+ UI-Komponenten bereitstellen, und Layout-Bibliotheken (wie Vue oder
+ React.js), welche die Komponenten basierend auf Daten dynamisch
+ anzeigen}
+}
+
+\newglossaryentry{responsive}
+{
+ name=Responsive,
+ description={
+ Design ist ein Design-Prinzip für Webseiten, bei dem die selbe Webseite ihre
+ Komponenten dynamisch der Bildschirmbreite anpasst}
+}
+
+\newglossaryentry{pseudoprotocol}
+{
+ name=Pseudoprotokoll,
+ description={
+ ist ein URL-Schema, auf das Webseiten hören können, wenn sie sich das
+ URL-Schema im Browser anmelden. Bekannt Pseudoprotokolle sind:
+ ,,mailto:'', ,,tel:'' oder ,,irc:''}
+}
+
+\newglossaryentry{dashboard}
+{
+ name=Dashboard,
+ description={
+ ist die erste Seite auf der man landet, wenn man angemeldet ist}
+}
+
+\newglossaryentry{abo}
+{
+ name=Abonnement,
+ description={
+ ist ein abonnierter Podcast}
+}
+
+\newglossaryentry{discovery}
+{
+ name=Discovery,
+ description={
+ ist ein Feature der Gpodder-API, welches dem Nutzer eine Reihe von
+ Podcasts zum abonnieren anbietet}
+}
+
+\newglossaryentry{session-token}
+{
+ name=Session-Token,
+ description={
+ ist ein Wort, dass vom Client gespeichert wird solange der Nutzer
+ eingeloggt ist und bei jeder Anfrage an den Server mitgeschickt wird.
+ Der Server kann den Session-Token einem Nutzer zuordnen und so mit
+ nutzerspezifischen Daten antworten}
+}
+
+\newglossaryentry{cookie}
+{
+ name=Cookie,
+ description={
+ ist ein kleiner webseitenspezifischer Speicher im Browser, welcher vom
+ Server und von der Webseite gesetzt werden kann und bei jeder weiteren
+ Anfrage an den Server mitgesendet wird. Cookies bleiben entweder
+ temporär im Browserspeicher, bis der Browser geschlossen wird oder
+ permanent, bis ein optionales Verfallsdatum erreicht ist}
+}
+
+\newglossaryentry{uiComponent}
+{
+ name=UI-Komponente,
+ plural=UI-Komponenten,
+ description={
+ In Vue.js werden die grafischen Elemente einer Webseite in einzelne
+ Komponenten zerteilt.
+ Diese reagieren automatisch auf Änderungen und können ohne Neuladen
+ der Seite ihr Aussehen verändern und somit Änderungen direkt anzeigen}
+}
+
+\newglossaryentry{spring}
+{
+ name=Spring,
+ description={
+ Ein Java-Framework, welches die Entwicklung von Web-Applikationen erleichtert.
+ Dazu wird eine Reihe von Werkzeugsets zur Verfügung gestellt.
+ Unter anderem sind das Spring Web für das Erstellen von Webanwendungen,
+ Spring Security für die Verwaltung von Benutzerauthentifizierungen und
+ Spring Data JPA für die Arbeit mit relationalen Datenbanken
+ }
+}
+
+\newglossaryentry{api}
+{
+ name=API,
+ plural=APIs,
+ description={
+ Eine Schnittstelle, welche es ermöglicht auf Funktionalitäten einer Anwendung
+ zuzugreifen. APIs für Webanwendungen heißen WebAPIs.
+ Ein Beispiel für eine WebAPI ist die REST-API
+ }
+}
+
+\newglossaryentry{business}
+{
+ name=Geschäftslogik,
+ description={
+ Eine Schicht in der Anwendungsentwicklung, in der die Art und Weise, wie das
+ Programm auf Eingaben reagiert, wie Daten verarbeitet und wie sie gespeichert
+ werden sollen, festgelegt ist
+ }
+}
+
+\newglossaryentry{solid}
+{
+ name=SOLID,
+ description={
+ Eine Sammlung an Prinzipien, welche zu gutem objektorientierten Design führen soll.
+ Jedes Prinzip steht für einen Buchstaben in SOLID:
+ \textbf{S}ingle-Responsibility Prinzip,
+ \textbf{O}pen-Closed Prinzip,
+ \textbf{L}iskovsches Substitutionsprinzip,
+ \textbf{I}nterface Segregation Prinzip und
+ \textbf{D}ependency Inversion Prinzip
+ }
+}
+
+\newglossaryentry{crud}
+{
+ name=CRUD,
+ description={
+ CRUD steht für \textbf{C}reate, \textbf{R}ead, \textbf{U}pdate und \textbf{D}elete.
+ Hierbei handelt es sich um die grundlegenden Funktionen einer Anwendung,
+ die mit einer Datenbank arbeitet.
+ Hierbei können Daten angelegt, abgerufen, aktualisiert und gelöscht werden.
+ Auch in Web-Applikationen ist CRUD mit HTTP über die Anfragen POST, GET, PUT und DELETE
+ vertreten
+ }
+}
+
+\newglossaryentry{SQL}
+{
+ name=SQL,
+ description={
+ SQL (Structured Query Language) ist eine Sprache, die einen strukturierten Zugriff auf Datenbanken ermöglicht.
+ Daten können hierbei hinzugefügt, abgefragt, geändert und gelöscht werden.
+ Das besondere hierbei ist der strukturierte Zugriff auf Daten, indem explizit Daten mit bestimmten Kriterien und
+ Relationen ausgewählt und bearbeitet werden können.
+ SQL wird fast von allen verbreiteten Datenbanksystemen unterstützt
+ }
+}
+
+\newglossaryentry{Base64}
+{
+ name=Base64,
+ description={
+ Mithilfe von Base64 können 8-Bit-Binärdaten in eine ASCII-Zeichenkette
+ kodiert werden. So werden zum Beispiel E-Mail-Anhänge versendet
+ }
+}
+
+\newglossaryentry{JSONP}
+{
+ name=JSONP,
+ description={
+ JSONP ermöglicht die Übertragung von JSON-Daten zwischen verschiedenen Domains.
+ Dies wäre durch die Same-Origin-Policy nicht möglich.
+ JSONP nutzt allerdings die Tatsache aus,
+ dass sich Skripte domainübergreifend übertragen lassen.
+ Dazu werden die JSON-Daten als Argument einer übergebenen Funktion über
+ ein Skript-Element eingebunden
+ }
+}
+
+\newglossaryentry{Apdex}
+{
+ name=Apdex,
+ description={
+ Der Application Performance Index ist eine Methode zur Bewertung der
+ Benutzerfreundlichkeit von Anwendungen bezüglich ihrer Antwortszeiten.
+ Dabei gibt es die Stufen zufriedenstellend, tolerierbar und
+ frustrierend, welche analog von 1 absteigend bis 0 angegeben werden.
+ }
+}
+
+\newglossaryentry{Lasttest}
+{
+ name=Lasttest,
+ description={
+ ist ein Test, mit welchem man die Stabilität und Robustheit
+ eines Programms testen kann, indem man ihn einer großen Last aussetzt.
+ }
+}
diff --git a/30-qualitaetsheft/sections/lasttest.tex b/30-qualitaetsheft/sections/lasttest.tex
new file mode 100644
index 0000000..ed5d4a9
--- /dev/null
+++ b/30-qualitaetsheft/sections/lasttest.tex
@@ -0,0 +1,105 @@
+\section{\Glspl{Lasttest}}
+
+\subsection{Einleitung}
+
+\Glspl{Lasttest} sind sinnvoll, um das Verhalten eines Programmes unter großer Last
+zu testen um somit dessen Belastungsgrenze zu erreichen.
+Dadurch wird das Programm auf Stabilität getestet und man erhält
+einen Eindruck davon, wie performant das Programm ist.
+Auch kann durch die erhaltenen Ergebnisse abgeschätzt werden,
+welche Hardware für den erwarteten Einsatzzweck benötigt wird.
+
+\subsection{Verwendete Software}
+
+Da der \Gls{podcast}synchronisationsserver ein Webserver ist und über HTTP
+kommuniziert, wird das Tool \enquote{Apache JMeter} verwendet, um
+die \Glspl{Lasttest} durchzuführen.
+Mit diesem Tool kann mithilfe eines sogenannten Testplans
+systematisch HTTP Anfragen an den Server gestellt werden.
+Während dieser Testplan läuft, sammelt das Tool verschiedene Daten über die Performanz des Services,
+wie zum Beispiel die Anzahl der Anfragen, die pro Sekunde bearbeitet werden.
+Im Anschluss werden die Testergebnisse grafisch zur Verfügung gestellt.
+
+\subsection{Tests}
+Um zu testen, ob der Synchronisationsserver unter voller Belastung
+fehlerfrei arbeitet, wurden alle Schnittstellen, die die \Gls{podcatcher} zur
+Synchronisation nutzen, jeweils zum Testplan als eigene Threadgruppe
+hinzugefügt.
+Damit ist es möglich, alle relevanten Schnittstellen
+über einen längeren Zeitraum kontinuierlich zu belasten.
+So wird ausgeschlossen, dass es innerhalb des Programms zu gegenseitigen
+Interferenzen kommt, wenn alle Bereiche zur selben Zeit ausgelastet werden.
+Ein weiterer Vorteil des gleichzeitigen Belastens ist, dass
+Engpässe, welche das Programm ausbremsen, leichter identifiziert werden können.
+
+Um einen Performanzvergleich zwischen unterschiedlicher Hardware zu erhalten,
+wurden die Tests in gleicher Konfiguration einmal auf einem System,
+welches den im Pflichtenheft definierten Mindestanforderungen
+(2 Kerne und 2GB RAM) entspricht und
+einem besseren System (8 Kerne und 32GB RAM) getestet.
+
+\newpage
+
+\subsection{Testergebnisse}
+\subsubsection{Genaue Testwerte}
+\textit{2-Kern System:}
+\begin{figure}[h]
+ \centering
+ \includegraphics[width=\textwidth,height=\textheight,keepaspectratio]{assets/lasttest/minimumSpecsTable.png}
+\end{figure}
+
+\textit{8-Kern System:}
+\begin{figure}[h]
+ \centering
+ \includegraphics[width=\textwidth,height=\textheight,keepaspectratio]{assets/lasttest/goodSpecsTable.png}
+\end{figure}
+
+\subsection{Anfragen pro Sekunde}
+
+Aus den Testdaten ist ersichtlich, dass die im Pflichtenheft für den Synchronisationsserver
+als Musskriterium aufgeführte Eigenschaft, 50 Anfragen pro Sekunde bewältigen zu können,
+nicht für jede Hardwarekonfiguration möglich ist.
+Denn im Gegensatz zur 8-Kern CPU, welche durchschnittlich 88,93 Transaktionen pro Sekunde
+verarbeitet, sind mit den Mindestanforderungen durchschnittlich nur 10,85 Anfragen
+pro Sekunde möglich.
+
+\newpage
+\subsubsection{Application Performance Index}
+
+\textit{2-Kern System:}
+\begin{figure}[h]
+ \centering
+ \includegraphics[width=\textwidth,height=\textheight,keepaspectratio]{assets/lasttest/minimumSpecsApdex.png}
+\end{figure}
+
+\textit{8-Kern System:}
+\begin{figure}[h]
+ \centering
+ \includegraphics[width=\textwidth,height=\textheight,keepaspectratio]{assets/lasttest/goodSpecsApdex.png}
+\end{figure}
+
+\newpage
+
+Der Application Performance Index (kurz: \Gls{Apdex}) gibt an, wie benutzerfreundlich
+eine Webseite bezüglich ihrer Antwortzeiten bei Anfragen ist.
+Dabei stellt \enquote{1} die beste Nutzerfreundlichkeit dar und \enquote{0} die schlechteste.
+
+Verglichen mit den genauen Testwerten, ist ersichtlich, dass ein System mit den Mindestanforderungen zwar eine akzeptable Leistung erbringt, allerdings die vom \Gls{Apdex} definierte Frustrationsgrenze überschreiten kann:
+
+\textit{2-Kern System:}
+\begin{figure}[h]
+ \centering
+ \includegraphics[width=\textwidth,height=\textheight,keepaspectratio]{assets/lasttest/minimumSpecsResponse.png}
+\end{figure}
+
+\textit{8-Kern System:}
+\begin{figure}[h]
+ \centering
+ \includegraphics[width=\textwidth,height=\textheight,keepaspectratio]{assets/lasttest/goodSpecsResponse.png}
+\end{figure}
+
+Bei Ausführung des Synchronisationsservers auf einem 2-Kern System kann somit
+keine zufriedenstellende Nutzererfahrung garantiert werden, sobald der Server einer starken
+Last ausgesetzt ist.
+
+Um eine zufriedenstellende Erfahrung zu garantieren, ist bessere Hardware eine hinreichende Bedingung. \ No newline at end of file
diff --git a/30-qualitaetsheft/sections/problems.tex b/30-qualitaetsheft/sections/problems.tex
new file mode 100644
index 0000000..fb5bdcb
--- /dev/null
+++ b/30-qualitaetsheft/sections/problems.tex
@@ -0,0 +1,65 @@
+\section{Probleme}
+
+\vspace{-.2cm}
+In diesem Kapitel wird näher auf die Probleme eingegangen, die sich ergeben
+haben, aus welchem Grund sie sich ergeben haben und wie sie schließlich behoben
+wurden.
+
+\vspace{-.2cm}
+\subsection{Falsche Zeitangaben}
+
+\begin{description}
+
+\item[Beschreibung] Im Frontend wurden die Zeiten, wann eine
+\Gls{podcast}episode zuletzt gehört wurde und wann ein \Gls{podcast} abonniert
+worden ist, falsch angezeigt. Hierbei kann eine Aktion entweder zu weit in der
+Vergangenheit oder sogar in der Zukunft liegen.
+\item[Ursache] Die Bibliothek hat die Zeiten in der lokalen, statt der
+universellen Zeit berechnet. Aufgrund der Differenz zwischen Zeitzonen kam es
+hierbei zu größer werdenden Zeitabständen.
+\item[Behebung] Die Bibliotheksfunktionen wurden so angepasst, dass sie die
+Zeiten explizit nach der universellen Zeitzone (UTC) berechnet.
+
+\end{description}
+
+
+\subsection{AntennaPod Fehlermeldung}
+
+\begin{description}
+
+\item[Beschreibung] Beim Hochladen von \Gls{abo}änderungen gab AntennaPod einen Fehler aus.
+\item[Ursache] Es wurde bei der Übertragung ein Parameter mit falschem Parameternamen gesendet.
+Hierbei handelt es sich um den Parameter \texttt{updateURLs}.
+\item[Behebung] \texttt{updateURLs} wurde umbenannt zu
+\texttt{update\textunderscore urls}. Die
+geschah durch das Hinzufügen von \texttt{@JsonProperty(value =
+''update\textunderscore urls'')} in der \texttt{UpdateURLsWrapper} Klasse im
+\texttt{util} Paket.
+
+\end{description}
+
+\subsection{Doppelte Speicherung von EpisodeActions}
+
+\begin{description}
+
+\item[Beschreibung] Beim speichern von \Gls{episode}Actions ergab sich in
+manchen Fällen die Situation, dass \Gls{episode}Actions mehrfach gespeichert
+worden sind. Jede \Gls{episode} besitzt pro Benutzer eine \Gls{episode}Action.
+In diesem Fall gab es mehrere \Gls{episode}Actions pro Benutzer für je eine
+\Gls{episode}.
+\item[Ursache] Es werden alle \Gls{episode}Actions in der \Gls{db} gespeichert,
+die neuer als die aktuellste \Gls{episode}Action in der \Gls{db} sind. Nach
+einem Speichervorgang sollte die ältere \Gls{episode}Action gelöscht werden. Da
+\Gls{spring} jedoch aus Effizienzgründen nach diesem Schema mehrere Daten
+sammelt und erst dann abspeichert, wird nur einer der älteren Einträge gelöscht.
+Dadurch werden im Durchschnitt mehr \Gls{episode}Actions gespeichert, als
+\Gls{episode}Actions entfernt werden.
+\item[Behebung] Die empfangenen \Gls{episode}Actions werden vor dem Speichern in
+der \Gls{db} bereits nach den jeweils aktuellsten \Gls{episode}Actions für eine
+\Gls{episode} aussortiert. Damit wird letztlich nur eine \Gls{episode}Action in
+die \Gls{db} geschrieben und auch nur eine ältere \Gls{episode}Action zu der
+\Gls{episode} gelöscht, womit jede \Gls{episode} für jeden User weiterhin nur
+eine \Gls{episode}Action besitzt.
+
+\end{description}
+
diff --git a/30-qualitaetsheft/sections/testfaelle.tex b/30-qualitaetsheft/sections/testfaelle.tex
new file mode 100644
index 0000000..7d8669c
--- /dev/null
+++ b/30-qualitaetsheft/sections/testfaelle.tex
@@ -0,0 +1,182 @@
+\section{Testfälle}
+
+Dieses Kapitel befasst sich mit allen im Pflichtenheft genannten Tests für den Synchronisationsserver.
+Die Tests werden dabei aufgeteilt in Tests, die im Frontend stattfinden und Tests, die das Backend betreffen.
+
+\subsection{Frontend}
+
+Dieser Abschnitt enthält alle Tests, die das Frontend betreffen.
+
+\subsubsection{Registrierung}
+
+Eine Person möchte sich einen Account auf dem Server anlegen.
+
+\begin{table}[h!]
+\begin{tabularx}{\textwidth}{X|c}
+Teilschritt & Bestanden\\\hline
+Webseite aufrufen & Ja\\
+Registrierungsseite aufrufen & Ja\\
+Daten ohne Passwort zur Wiederholung eintragen & Ja\\
+Daten mit zweimal Passwort eingeben & Ja\\
+Registrierungslink drücken & Ja\\
+Registrierungslink abgelaufen & Ja\\
+Registrierungslink nach 24 Stunden anklicken & Ja\\
+Mit selber E-Mail nochmals registrieren & Ja
+\end{tabularx}
+\end{table}
+
+\subsubsection{Passwort Anforderungen}
+
+Es wird getestet, ob das eingegebene Passwort die Mindestanforderungen erfüllen muss, um akzeptiert zu werden.
+
+\begin{table}[h!]
+\begin{tabularx}{\textwidth}{X|c}
+Teilschritt & Bestanden\\\hline
+Passwort \enquote{test} nicht akzeptiert & Ja\\
+Passwort \enquote{Test123} nicht akzeptiert & Ja\\
+Passwort \enquote{TEST123?} nicht akzeptiert & Ja\\
+Passwort \enquote{Test123!?} akzeptiert & Ja
+\end{tabularx}
+\end{table}
+
+\newpage
+
+\subsubsection{Anmeldung}
+
+Der Benutzer ist registriert und möchte sich nun mit dem registrierten Account anmelden.
+Die Option \enquote{Angemeldet bleiben} wird nicht verwendet.
+Hierbei ist zu beachten, dass die Anmeldung seit der Implementierungsphase mit einem Benutzernamen statt der E-Mail Adresse erfolgt.
+
+\begin{table}[h!]
+\begin{tabularx}{\textwidth}{X|c}
+Teilschritt & Bestanden\\\hline
+Webseite aufrufen & Ja\\
+Ohne Eingabe \enquote{Anmelden} drücken & Ja\\
+Nur Nutzernamen eingeben und \enquote{Anmelden} drücken & Ja\\
+Nutzername und falsches Passwort eingeben, anschließend \enquote{Anmelden} drücken & Ja\\
+Nutzername und richtiges Passwort eingeben, anschließen \enquote{Anmelden} drücken & Ja\\
+\enquote{Angemeldet bleiben} Option testen & Ja\\
+\enquote{Angemeldet bleiben} Option deaktiviert testen & Ja
+\end{tabularx}
+\end{table}
+
+\subsubsection{Passwort ändern}
+
+Der Benutzer ist registriert, kennt seine Anmeldedaten und möchte nun das Passwort ändern.
+Der Benutzer ist zu Beginn bereits angemeldet.
+
+\begin{table}[h!]
+\begin{tabularx}{\textwidth}{X|c}
+Teilschritt & Bestanden\\\hline
+Zu \enquote{Einstellungen} Menü über das Profil wechseln & Ja\\
+Ohne Eingabe \enquote{Passwort ändern} drücken & Ja\\
+Falsches altes Passwort eingeben und \enquote{Passwort ändern} drücken & Ja\\
+\makecell[l]{Richtiges altes Passwort und neues Passwort, das nicht die Kriterien \\ erfüllt eingeben} & Ja\\
+Richtiges altes Passwort und akzeptiertes neues Passwort eingeben & Ja\\
+Der Benutzer kann sich abmelden & Ja\\
+Das alte Passwort wird beim Anmelden nicht mehr akzeptiert & Ja\\
+Der Benutzer kann sich mit dem neuen Passwort anmelden & Ja
+\end{tabularx}
+\end{table}
+
+\newpage
+
+\subsubsection{Passwort vergessen}
+
+Der Benutzer ist registriert, kennt die E-Mail Adresse jedoch nicht das Passwort mit dem er sich registriert hat.
+Ziel hierbei ist es das Passwort zurückzusetzen.
+
+\begin{table}[h!]
+\begin{tabularx}{\textwidth}{X|c}
+Teilschritt & Bestanden\\\hline
+Webseite aufrufen & Ja\\
+\enquote{Passwort vergessen} Seite aufrufen & Ja\\
+E-Mail Adresse eingeben und \enquote{Bestätigen} Knopf drücken & Ja\\
+Gesendeten Link innerhalb von 24 Stunden anklicken & Ja\\
+Auf \enquote{Passwort zurücksetzen} Seite neues nicht akzeptiertes Passwort eingeben & Ja\\
+Auf \enquote{Passwort zurücksetzen} Seite neues akzeptiertes Passwort eingeben & Ja\\
+Auf Anmeldeseite versuchen mit altem Passwort anzumelden & Ja\\
+Auf Anmeldeseite mit neuem Passwort anmelden & Ja\\
+Gesendeten Link nach 24 Stunden anklicken & Ja\\
+Nach Zurücksetzen vom Passwort erneut auf Link klicken & Nein (technisch bedingt)
+\end{tabularx}
+\end{table}
+
+\subsubsection{Account löschen}
+
+Der Benutzer ist registriert und möchte den Account löschen.
+Dazu ist der Benutzer zu Beginn bereits angemeldet und befindet sich in der Einstellungsseite des Profils.
+Es sei zu beachten, dass die Aktion den Account zu löschen in die Einstellungsseite verschoben wurde und nicht über eine extra Seite stattfindet.
+Auch verlangt die Aktion den Account zu löschen nur noch das Passwort.
+
+\begin{table}[h!]
+\begin{tabularx}{\textwidth}{X|c}
+Teilschritt & Bestanden\\\hline
+Ohne Eingabe \enquote{Account löschen} drücken & Ja\\
+Mit falschem Passwort als Eingabe \enquote{Account löschen} drücken & Ja\\
+Mit richtigem Passwort als Eingabe \enquote{Account löschen} drücken & Ja\\
+Versuchen sich mit gelöschtem Account anzumelden & Ja
+\end{tabularx}
+\end{table}
+
+\subsubsection{Anleitung ansehen}
+
+Der Benutzer ist registriert und angemeldet und möchte die Anleitung einsehen.
+
+\begin{table}[h!]
+\begin{tabularx}{\textwidth}{X|c}
+Teilschritt & Bestanden\\\hline
+Auf \enquote{Hilfe} Button im \Gls{dashboard} klicken & Ja
+\end{tabularx}
+\end{table}
+
+\newpage
+
+\subsection{Synchronisation}
+
+Die folgenden Tests betreffen das Synchronisationsfeature des Synchronisationsservers.
+Hierbei ist der Benutzer bereits auf dem Server registriert und bestätigt.
+Auch ist der Benutzer in allen Fällen auf einem \Gls{podcatcher}, der die \Gls{gpodder} unterstützt, über den registrierten Account angemeldet.
+
+\subsubsection{\Gls{podcast} abonnieren}
+
+Der Benutzer abonniert auf einem \Gls{podcatcher} einen \Gls{podcast} und möchte diesen auf einem anderen Gerät einsehen.
+
+\begin{table}[h!]
+\begin{tabularx}{\textwidth}{X|c}
+Teilschritt & Bestanden\\\hline
+Im \Gls{podcatcher} wird ein neuer \Gls{podcast} den \Glspl{abo} hinzugefügt & Ja\\
+Im \Gls{dashboard} des Servers wird der neu abonnierte \Gls{podcast} angezeigt & Ja\\
+\makecell[l]{Auf einem anderen synchronisierten Gerät wird der \\ neu abonnierte \Gls{podcast} angezeigt} & Ja
+\end{tabularx}
+\end{table}
+
+\subsubsection{\Gls{podcast} deabonnieren}
+
+Der Benutzer hat einen \Gls{podcast} abonniert und möchte diesen nun deabonnieren.
+
+\begin{table}[h!]
+\begin{tabularx}{\textwidth}{X|c}
+Teilschritt & Bestanden \\\hline
+Im Podcatcher wird ein abonnierter Podcast deabonniert & Ja\\
+\makecell[l]{Im Dashboard des Servers wurde der deabonnierte Podcast \\ aus der Abonnement Liste entfernt} & Ja\\
+\makecell[l]{Auf einem anderen synchronisierten Gerät wurde der Podcast\\ ebenfalls deabonniert} & Ja
+\end{tabularx}
+\end{table}
+
+\newpage
+
+\subsubsection{Episode anhören}
+
+Der Benutzer hört sich eine Episode eines abonnierten \Glspl{podcast} an.
+
+\begin{table}[h!]
+\begin{tabularx}{\textwidth}{X|c}
+Teilschritt & Bestanden \\\hline
+\makecell[l]{Eine Episode wird für eine beliebige Zeit lang angehört \\ und dann pausiert} & Ja\\
+\makecell[l]{Im Dashboard des Servers wird die zuletzt gehörte Episode \\ unter \enquote{Zuletzt gehört} angezeigt} & Ja\\
+\makecell[l]{Auf einem anderen synchronisierten Gerät kann die \\ Episode weitergehört werden} & Ja\\
+\makecell[l]{Stoppt man die Episode wieder wird der alte Zeitpunkt\\ vom neuen Zeitpunkt überschrieben} & Ja
+\end{tabularx}
+\end{table}
+ \ No newline at end of file
diff --git a/30-qualitaetsheft/sections/tests.tex b/30-qualitaetsheft/sections/tests.tex
new file mode 100644
index 0000000..cdbf163
--- /dev/null
+++ b/30-qualitaetsheft/sections/tests.tex
@@ -0,0 +1,21 @@
+\section{Testfälle}
+
+Für die Erstellung der Testfälle wurde die SpringBoot Testumgebung verwendet und
+diese durch JUnit Testfälle ergänzt.
+
+Für das Testen wurde eine BaseTest Klasse erstellt, die grundlegende Funktionalität
+einiger Kern Komponenten sicherstellt. Weiter Initialisiert sie die Anwendungsumgebung auf
+der alle weiteren Tests aufbauen.
+
+Die Unit Tests erweitern diese BaseTest Klasse und können daher von gewisser Grundfunktionalität
+ausgehen, die durch den BaseTest abgedeckt ist. Dadurch müssen nicht große Teile der
+Anwendung durch Mock Objekte simuliert werden.
+
+Grundsätzlich wurde beim Entwurf der Testfälle nach dem Inside-Out-Prinzip vorangegangenen.
+Die bisher geschriebenen Testfälle haben dabei nicht das Ziel Korrektheit zu garantieren,
+sondern einen gewissen Qualitätsstandart zu sichern und gleichzeitig genug
+Arbeitspunkte bereit zu stellen um im ganzen Team an diesem Projekt parallel arbeite zu können.
+
+Zusätzlich wurden bei der Implementierung auf ausgiebig getestete Annotationen von Spring und
+Lombok zurückgegriffen die helfen die Anzahl an Fehlern bei standardisierten
+\enquote{Boilerplater-Code} Aufgaben zu vermeiden. \ No newline at end of file
diff --git a/30-qualitaetsheft/titlepage.tex b/30-qualitaetsheft/titlepage.tex
new file mode 100644
index 0000000..284029b
--- /dev/null
+++ b/30-qualitaetsheft/titlepage.tex
@@ -0,0 +1,75 @@
+%% Encoding: UTF-8 %%
+
+%% titlepage.tex
+
+\def\usesf{}
+\let\usesf\sffamily % diese Zeile auskommentieren für normalen TeX Font
+
+\begin{titlepage}
+
+\setlength{\unitlength}{1pt}
+\begin{picture}(00,0)(70,770)
+ \includegraphics[width=\paperwidth]{assets/KIT_Deckblatt.pdf}
+\end{picture}
+
+\thispagestyle{empty}
+
+\begin{center}
+\hbox{}
+\vfill
+\includegraphics[width=.5\textwidth]{assets/logo.pdf}
+\vskip 1cm
+{\usesf
+ {\huge\bfseries PSE\textsuperscript{2} - Podcast Synchronisation \\
+ made Efficient\\
+ Qualitätssicherung \par}
+\vskip 1.8cm
+{\Large Wintersemester 2022/2023\\}
+%von\\[2mm]
+\vskip 1.5cm
+
+% {\large\bfseries Vorname Nachname\\}
+% \vskip 1.2cm
+Praxis der Softwareentwicklung \\
+Prof. Dr.-Ing. Gregor Snelting \\
+Fakultät für Informatik\\
+Karlsruher Institut für Technologie\\
+\vskip 1.5cm
+\begin{tabular}{p{20mm}l}
+Autoren:
+& Daniel Hönlinger \\
+& Gero Beckmann \\
+& Immanuel Reitz \\
+& Julius Friesen \\
+& Lukas Schmidheissler \\
+\\
+Betreuer: & M.Sc. Hans-Peter Lehmann \\
+ & M.Sc. Daniel Seemaier
+\end{tabular}
+}
+\end{center}
+\vfill
+
+%\begin{textblock}{10}[0,0](4,15)
+% \includegraphics[width=.3\textwidth]{logos/logo.pdf}
+%\end{textblock}
+
+% \begin{textblock}{8}[0,0](14,14)
+% \includegraphics[width=.3\textwidth]{logos/KASTEL_logo.pdf}
+% \end{textblock}
+
+\end{titlepage}
+
+% \thispagestyle{empty}
+% \ \vfill
+% \begin{flushleft}
+% Copyright $\copyright$ ITI und Verfasser 201?\\
+% \ \\
+% Institut für Theoretische Informatik
+% Fakultät für Informatik\\
+% Karlsruher Institut für Technologie\\
+% Am Fasanengarten 5\\
+% 76131 Karlsruhe
+% \end{flushleft}
+% \newpage
+
diff --git a/31-qualitaetsheft-kolloquium/.gitignore b/31-qualitaetsheft-kolloquium/.gitignore
new file mode 100644
index 0000000..595d70a
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/.gitignore
@@ -0,0 +1,303 @@
+## Core latex/pdflatex auxiliary files:
+*.aux
+*.lof
+*.log
+*.lot
+*.fls
+*.out
+*.toc
+*.fmt
+*.fot
+*.cb
+*.cb2
+.*.lb
+
+## Intermediate documents:
+*.dvi
+*.xdv
+*-converted-to.*
+# these rules might exclude image files for figures etc.
+# *.ps
+*.eps
+*.pdf
+# !assets/*.pdf
+!logos/*.pdf
+
+## Generated if empty string is given at "Please type another file name for output:"
+.pdf
+
+## Bibliography auxiliary files (bibtex/biblatex/biber):
+*.bbl
+*.bcf
+*.blg
+*-blx.aux
+*-blx.bib
+*.run.xml
+
+## Build tool auxiliary files:
+*.fdb_latexmk
+*.synctex
+*.synctex(busy)
+*.synctex.gz
+*.synctex.gz(busy)
+*.pdfsync
+
+## Build tool directories for auxiliary files
+# latexrun
+latex.out/
+
+## Auxiliary and intermediate files from other packages:
+# algorithms
+*.alg
+*.loa
+
+# achemso
+acs-*.bib
+
+# amsthm
+*.thm
+
+# beamer
+*.nav
+*.pre
+*.snm
+*.vrb
+
+# changes
+*.soc
+
+# comment
+*.cut
+
+# cprotect
+*.cpt
+
+# elsarticle (documentclass of Elsevier journals)
+*.spl
+
+# endnotes
+*.ent
+
+# fixme
+*.lox
+
+# feynmf/feynmp
+*.mf
+*.mp
+*.t[1-9]
+*.t[1-9][0-9]
+*.tfm
+
+#(r)(e)ledmac/(r)(e)ledpar
+*.end
+*.?end
+*.[1-9]
+*.[1-9][0-9]
+*.[1-9][0-9][0-9]
+*.[1-9]R
+*.[1-9][0-9]R
+*.[1-9][0-9][0-9]R
+*.eledsec[1-9]
+*.eledsec[1-9]R
+*.eledsec[1-9][0-9]
+*.eledsec[1-9][0-9]R
+*.eledsec[1-9][0-9][0-9]
+*.eledsec[1-9][0-9][0-9]R
+
+# glossaries
+*.acn
+*.acr
+*.glg
+*.glo
+*.gls
+*.glsdefs
+*.lzo
+*.lzs
+*.slg
+*.slo
+*.sls
+
+# uncomment this for glossaries-extra (will ignore makeindex's style files!)
+*.ist
+
+# gnuplot
+*.gnuplot
+*.table
+
+# gnuplottex
+*-gnuplottex-*
+
+# gregoriotex
+*.gaux
+*.glog
+*.gtex
+
+# htlatex
+*.4ct
+*.4tc
+*.idv
+*.lg
+*.trc
+*.xref
+
+# hyperref
+*.brf
+
+# knitr
+*-concordance.tex
+# TODO Uncomment the next line if you use knitr and want to ignore its generated tikz files
+# *.tikz
+*-tikzDictionary
+
+# listings
+*.lol
+
+# luatexja-ruby
+*.ltjruby
+
+# makeidx
+*.idx
+*.ilg
+*.ind
+
+# minitoc
+*.maf
+*.mlf
+*.mlt
+*.mtc[0-9]*
+*.slf[0-9]*
+*.slt[0-9]*
+*.stc[0-9]*
+
+# minted
+_minted*
+*.pyg
+
+# morewrites
+*.mw
+
+# newpax
+*.newpax
+
+# nomencl
+*.nlg
+*.nlo
+*.nls
+
+# pax
+*.pax
+
+# pdfpcnotes
+*.pdfpc
+
+# sagetex
+*.sagetex.sage
+*.sagetex.py
+*.sagetex.scmd
+
+# scrwfile
+*.wrt
+
+# svg
+svg-inkscape/
+
+# sympy
+*.sout
+*.sympy
+sympy-plots-for-*.tex/
+
+# pdfcomment
+*.upa
+*.upb
+
+# pythontex
+*.pytxcode
+pythontex-files-*/
+
+# tcolorbox
+*.listing
+
+# thmtools
+*.loe
+
+# TikZ & PGF
+*.dpth
+*.md5
+*.auxlock
+
+# titletoc
+*.ptc
+
+# todonotes
+*.tdo
+
+# vhistory
+*.hst
+*.ver
+
+# easy-todo
+*.lod
+
+# xcolor
+*.xcp
+
+# xmpincl
+*.xmpi
+
+# xindy
+*.xdy
+
+# xypic precompiled matrices and outlines
+*.xyc
+*.xyd
+
+# endfloat
+*.ttt
+*.fff
+
+# Latexian
+TSWLatexianTemp*
+
+## Editors:
+# WinEdt
+*.bak
+*.sav
+
+# Texpad
+.texpadtmp
+
+# LyX
+*.lyx~
+
+# Kile
+*.backup
+
+# gummi
+.*.swp
+
+# KBibTeX
+*~[0-9]*
+
+# TeXnicCenter
+*.tps
+
+# auto folder when using emacs and auctex
+./auto/*
+*.el
+
+# expex forward references with \gathertags
+*-tags.tex
+
+# standalone packages
+*.sta
+
+# Makeindex log files
+*.lpz
+
+# xwatermark package
+*.xwm
+
+# REVTeX puts footnotes in the bibliography by default, unless the nofootinbib
+# option is specified. Footnotes are the stored in a file with suffix Notes.bib.
+# Uncomment the next line to have this generated file ignored.
+#*Notes.bib
diff --git a/31-qualitaetsheft-kolloquium/.gitlab-ci.yml b/31-qualitaetsheft-kolloquium/.gitlab-ci.yml
new file mode 100644
index 0000000..c4ad5e0
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/.gitlab-ci.yml
@@ -0,0 +1,37 @@
+plantuml:
+ stage: .pre
+ image:
+ name: eclipse-temurin:17-alpine
+ entrypoint: [""]
+ script:
+ - java -jar plantuml.jar -tpdf assets/diagrams/*.puml
+ - java -jar plantuml.jar -teps assets/*.puml
+ artifacts:
+ paths:
+ - assets
+
+tex:
+ stage: build
+ image: texlive/texlive
+ script:
+ - mkdir public
+ - make tex
+ - mv *.pdf public
+ artifacts:
+ paths:
+ - public
+ dependencies:
+ - plantuml
+
+pages:
+ stage: deploy
+ script:
+ - echo Hello, World!
+ artifacts:
+ paths:
+ - public
+ rules:
+ - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
+ dependencies:
+ - tex
+
diff --git a/31-qualitaetsheft-kolloquium/CHANGELOG.md b/31-qualitaetsheft-kolloquium/CHANGELOG.md
new file mode 100644
index 0000000..7671a41
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/CHANGELOG.md
@@ -0,0 +1,34 @@
+# Changelog
+Alle Änderungen an diesem Projekt werden in dieser Datei dokumentiert.
+Die Versionsnummern folgt der Syntax in `sdqbeamer.cls`.
+
+## [2022-05-03 v3.1.3]
+- Die Breite des Gruppennamens in der Fußzeile kann nun über `\groupnamewidth{}` gesteuert werden
+- FIX: zweizeilige Fußzeilen haben nun gleichmäßigen vertikalen Abstand (Issue #16 in Gitlab)
+
+## [2021-08-10 v3.1.2]
+- FIX: framesubtitle wird nun angezeigt (Issue #6 in Gitlab)
+
+## [2020-12-08 v3.1.1]
+- FIX: Titelbild (Issue #4 in Gitlab)
+
+## [2020-12-07 v3.1]
+- Umgebung ``contentblock`` (farbloser Block mit fetter Überschrift) hinzugefügt
+- Farbboxen (``greenblock``, ``blueblock``, …) hinzugefügt
+- Abstufungen der KIT-Farben in 10er-Schritten entsprechend der Gestaltungsrichtlinien eingeführt
+- FIX: Navigationspunkte für Subsections in eine Zeile gesetzt, um vertikal Platz zu sparen
+- FIX: ``inputenc`` an den Anfang von ``sdqbeamer.cls`` verschoben
+
+## [2020-11-16 v3.0]
+- Seitenformat 16:10 hinzugefügt
+- Umstellung auf KIT-Design vom 1. August 2020
+ - Anpassung auf neues Farbschema und Maße
+ - neues Titelbild aus der KIT-Bildwelt
+- Neue Optionen:
+ - durch `smallfoot` und `bigfoot` kann die Schriftgröße der Fußzeile gesteuert werden
+ - durch `navbarkit` kann eine Fußzeile nach KIT-Vorgaben erzwungen werden
+- Deutsch (`de`) ist nun die Standard-Option
+- Ordner `templates` wurde gelöscht und die Inhalte in `sdqbeamer.cls` integriert
+- Globale Größe auf 10 pt verringert (vorher: 11 pt), da der beschreibbare Bereich im Vergleich zur 2009er Version kleiner geworden ist
+- SDQ-spezifische Logos und Titelbilder entfernt. Diese sind ab sofort im Branch »sdq« verfügbar.
+- Fix: Zeilenumbruch bei Titel in der Fußzeile repariert \ No newline at end of file
diff --git a/31-qualitaetsheft-kolloquium/Makefile b/31-qualitaetsheft-kolloquium/Makefile
new file mode 100644
index 0000000..3e1e58a
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/Makefile
@@ -0,0 +1,19 @@
+MAIN = presentation
+FLAGS = -pdf
+
+all: clean compile
+compile: diagram tex
+clean: clean-diagram clean-tex
+
+dev:
+ latexmk $(FLAGS) -pvc $(MAIN)
+tex:
+ latexmk $(FLAGS) $(MAIN)
+diagram:
+ java -jar plantuml.jar -tpdf assets/diagrams/*.puml
+ java -jar plantuml.jar -teps assets/*.puml
+clean-tex:
+ latexmk -C
+clean-diagram:
+ find assets/diagrams -type f -not -name '*.puml' -delete
+
diff --git a/31-qualitaetsheft-kolloquium/README.md b/31-qualitaetsheft-kolloquium/README.md
new file mode 100644
index 0000000..6a5e9ea
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/README.md
@@ -0,0 +1,118 @@
+LaTeX-Vorlage für Präsentationen
+================================
+
+Das vorliegende Paket dient als Vorlage für Präsentationen im [Corporate Design des KIT](https://intranet.kit.edu/gestaltungsrichtlinien.php) (Fassung vom 1. August 2020).
+
+Es wird an der Forschungsgruppe [DSiS](https://dsis.kastel.kit.edu) an der KIT-Fakultät für Informatik entwickelt und basiert auf [LaTeX Beamer](https://ctan.org/pkg/beamer).
+
+Autor: [Dr.-Ing. Erik Burger](https://dsis.kastel.kit.edu/staff_erik_burger.php)
+mit Beiträgen von Christian Hammer, Klaus Krogmann und Maximilian Schambach
+
+Siehe https://sdqweb.ipd.kit.edu/wiki/Dokumentvorlagen
+
+Hinweise, Verbesserungsvorschläge
+=================================
+
+Bitte verwenden Sie das [Issue-Tracking-System von Gitlab](https://git.scc.kit.edu/i43/dokumentvorlagen/praesentationen/beamer/-/issues), um auf Probleme mit der Vorlage hinzuweisen oder Erweiterungswünsche zu äußern. Sie können gerne auch eine Änderung per Merge-Request vorschlagen.
+
+Verwendung
+==========
+
+Optionen der Dokumentklasse `sdqbeamer`
+-----------------------------------------
+Durch die folgenden Optionen kann das Seitenverhältnis der Folien bestimmt werden:
+
+| Seitenverhältnis | Option |
+| ---------------- | ------------------- |
+| 16:9 | `16:9` (Standard) |
+| 16:10 | `16:10` |
+| 4:3 | `4:3` |
+
+Die Schriftgröße in der Fußzeile ist standardmäßig größer gewählt, als in den Gestaltungsrichtlinien vorgegeben. Diese Vorgabe kann durch die Option `smallfoot` erzwungen werden.
+
+| Schriftgröße Fußzeile | Option |
+| ----------------------| -------------------- |
+| etwas größer (12pt) | `bigfoot` (Standard) |
+| KIT-Vorgabe (9pt) | `smallfoot` |
+
+Die Plazierung der Navigationsleiste kann durch folgende Optionen beeinflußt werden:
+
+| Position | Option | Bemerkung |
+| ------------------------ | ---------------- | ------------------------------------------ |
+| oberhalb der Trennlinie | `navbarinline` | Standard |
+| unterhalb der Trennlinie | `navbarinfooter` | keine Subsection-Punkte, Größe `smallfoot` |
+| Seitenleiste links | `navbarside` | keine Subsection-Punkte |
+| keine Navigationsleiste | `navbaroff` | |
+| KIT-Vorgabe | `navbarkit` | entspricht `navbaroff` und `smallfoot` |
+
+Als Sprache sind Deutsch und Englisch verfügbar. Durch die Sprachwahl werden automatisch die passenden Logos und Formate (z.B. Datum) gewählt.
+
+| Sprache | |
+| -------- |---------------- |
+| Deutsch | `de` (Standard) |
+| Englisch | `en` |
+
+Beispiel: `\documentclass[de,16:9,navbarinline]{sdqbeamer}`
+
+Titelbild
+---------
+
+Das Bild auf der Titelfolie kann mit dem Befehl
+
+`\titleimage{myimage}` (ohne Dateiendung)
+
+gesetzt werden. Um ein eigenes Bild zu verwenden, bitte die Datei (z.B. `myimage.jpg`) ins `logos/`-Verzeichnis legen und den Befehl anpassen. Mitgeliefert wird ein generisches Bild aus der KIT-Bildwelt (https://intranet.kit.edu/gestaltungsrichtlinien.php) in der Datei `logos/banner_2020_kit.jpg`. Falls kein Titelbild eingefügt werden soll, bitte `\titleimage{}` setzen.
+
+Für 16:9-Folien sollte das Verhältnis des Bildes 160:37 betragen, für 4:3-Folien 63:20. Es können auch breitere Bilder verwendet werden, da das Titelbild auf die Höhe des Rahmens skaliert und zentriert wird.
+
+Logo und Name Abteilung/KIT-Fakultät/Institut
+---------------------------------------------
+
+Das Logo rechts oben auf der Titelfolie kann mit dem folgenden Befehl gesetzt werden:
+
+`\grouplogo{mylogo}` (ohne Dateiendung)
+
+Um ein eigenes Logo zu verwenden, bitte die Datei (z.B. `mylogo.pdf`) in das Verzeichnis `logos/` legen und den Befehl anpassen. Falls kein Logo eingefügt werden soll, bitte `\grouplogo{}` setzen.
+
+Der Gruppenname kann mit folgendem Befehl gesetzt werden:
+
+`\groupname{Software Design and Quality}`
+
+Der Gruppenname erscheint in der Fußzeile rechts unten. Lange Namen werden in zwei Zeilen umgebrochen. Falls der Gruppenname leer gelassen wird (`\groupname{}`), wird die volle Breite der Fußzeile für Autornamen und Titel verwendet.
+
+Die Standardbreite des Gruppennamens sind 50 mm. Sie kann mit
+
+`\groupnamewidth{80mm}`
+
+verändert werden, wodurch sich auch die Breite des Textfeldes mit Autor und Titel entsprechend ändert. Umbrüche sind mit `\\` möglich. Statt zweizeiliger Fußzeilen empfiehlt sich eventuell die Option `smallfoot`.
+
+LaTeX allgemein
+---------------
+Siehe https://sdqweb.ipd.kit.edu/wiki/LaTeX
+
+Dateistruktur
+============
+`presentation.tex`
+------------------
+Hauptdatei des LaTeX-Dokuments.
+
+`presentation.bib`
+-------------
+Beispieldatei für BibTeX-Referenzen
+https://sdqweb.ipd.kit.edu/wiki/BibTeX-Literaturlisten
+
+`sdqbeamer.cls`
+-----------------
+Dokumentklasse für Präsentationen im KIT-Design.
+
+`logos/`
+--------
+In diesem Verzeichnis befinden das KIT-Logo als PDF sowie das Hintergrundbild der Titelfolie als JPG.
+
+`CHANGELOG.md`
+--------------
+Dokumentation der Änderungen in den jeweiligen Versionen.
+
+`README.md`
+-----------
+Dieser Text.
diff --git a/31-qualitaetsheft-kolloquium/assets/.gitignore b/31-qualitaetsheft-kolloquium/assets/.gitignore
new file mode 100644
index 0000000..16252a4
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/assets/.gitignore
@@ -0,0 +1,3 @@
+diagrams/*
+!diagrams/*.puml
+
diff --git a/31-qualitaetsheft-kolloquium/assets/.gitingnore b/31-qualitaetsheft-kolloquium/assets/.gitingnore
new file mode 100644
index 0000000..16252a4
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/assets/.gitingnore
@@ -0,0 +1,3 @@
+diagrams/*
+!diagrams/*.puml
+
diff --git a/31-qualitaetsheft-kolloquium/assets/commits-dashboard.png b/31-qualitaetsheft-kolloquium/assets/commits-dashboard.png
new file mode 100644
index 0000000..89672d6
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/assets/commits-dashboard.png
Binary files differ
diff --git a/31-qualitaetsheft-kolloquium/assets/commits-server.png b/31-qualitaetsheft-kolloquium/assets/commits-server.png
new file mode 100644
index 0000000..a9d1a5c
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/assets/commits-server.png
Binary files differ
diff --git a/31-qualitaetsheft-kolloquium/assets/contributors-dashboard.png b/31-qualitaetsheft-kolloquium/assets/contributors-dashboard.png
new file mode 100644
index 0000000..3621c31
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/assets/contributors-dashboard.png
Binary files differ
diff --git a/31-qualitaetsheft-kolloquium/assets/contributors-server.png b/31-qualitaetsheft-kolloquium/assets/contributors-server.png
new file mode 100644
index 0000000..500bb43
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/assets/contributors-server.png
Binary files differ
diff --git a/31-qualitaetsheft-kolloquium/assets/coverage/authenticationService.png b/31-qualitaetsheft-kolloquium/assets/coverage/authenticationService.png
new file mode 100644
index 0000000..4ad91e1
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/assets/coverage/authenticationService.png
Binary files differ
diff --git a/31-qualitaetsheft-kolloquium/assets/coverage/episodeActionService.png b/31-qualitaetsheft-kolloquium/assets/coverage/episodeActionService.png
new file mode 100644
index 0000000..c81f26f
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/assets/coverage/episodeActionService.png
Binary files differ
diff --git a/31-qualitaetsheft-kolloquium/assets/coverage/server.png b/31-qualitaetsheft-kolloquium/assets/coverage/server.png
new file mode 100644
index 0000000..d28917a
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/assets/coverage/server.png
Binary files differ
diff --git a/31-qualitaetsheft-kolloquium/assets/coverage/subscriptionsService.png b/31-qualitaetsheft-kolloquium/assets/coverage/subscriptionsService.png
new file mode 100644
index 0000000..fdb7c9b
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/assets/coverage/subscriptionsService.png
Binary files differ
diff --git a/31-qualitaetsheft-kolloquium/assets/coverage/util.png b/31-qualitaetsheft-kolloquium/assets/coverage/util.png
new file mode 100644
index 0000000..823cd9e
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/assets/coverage/util.png
Binary files differ
diff --git a/31-qualitaetsheft-kolloquium/assets/diagrams/backendComponentDiagram.puml b/31-qualitaetsheft-kolloquium/assets/diagrams/backendComponentDiagram.puml
new file mode 100644
index 0000000..e382351
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/assets/diagrams/backendComponentDiagram.puml
@@ -0,0 +1,61 @@
+@startuml
+' skinparam linetype ortho
+
+'#########################################################################
+'SubscriptionsAPI
+component SubscriptionsAPI {
+
+ component SubscriptionService
+ component SubscriptionController
+ component SubscriptionDataAccessLayer
+
+ portout "Webserver" as wSub
+ portin "Database" as dSub
+ }
+
+dSub --0)- SubscriptionDataAccessLayer
+SubscriptionDataAccessLayer --0)- SubscriptionService
+SubscriptionService --0)- SubscriptionController
+SubscriptionController --0)- wSub
+
+'#########################################################################
+
+
+'#########################################################################
+'EpisodeActionsAPI
+
+component EpisodeActionsAPI {
+ component EpisodeActionService
+ component EpisodeActionController
+ component EpisodeActionDataAccessLayer
+
+ portout "Webserver" as wEpisode
+ portin "Database" as dEpisode
+}
+
+dEpisode --0)- EpisodeActionDataAccessLayer
+EpisodeActionController --0)- wEpisode
+EpisodeActionDataAccessLayer --0)- EpisodeActionService
+EpisodeActionService --0)- EpisodeActionController
+
+'#########################################################################
+
+
+'#########################################################################
+'AuthenticationAPI
+
+component AuthenticationAPI {
+ component AuthenticationService
+ component AuthenticationController
+ component AuthenticationDataAccessLayer
+
+ portout "Webserver" as wAuth
+ portin "Database" as dAuth
+}
+
+dAuth --0)- AuthenticationDataAccessLayer
+AuthenticationController --0)- wAuth
+AuthenticationDataAccessLayer --0)- AuthenticationService
+AuthenticationService --0)- AuthenticationController
+
+@enduml
diff --git a/31-qualitaetsheft-kolloquium/assets/diagrams/classdiagram-authentication.puml b/31-qualitaetsheft-kolloquium/assets/diagrams/classdiagram-authentication.puml
new file mode 100644
index 0000000..a2b3518
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/assets/diagrams/classdiagram-authentication.puml
@@ -0,0 +1,112 @@
+@startuml
+
+package authenticationAPI <<Frame>> {
+ package authenticationDataAccessLayer <<Frame>> {
+ ' interface AuthenticationDao {
+ ' String login(String username)
+ ' int logout(String username)
+ ' }
+
+ ' class AuthenticationDataAccessService <<@Respository>> {
+ ' <<create>> AuthenticationDataAccessService(JpaTemplate jpaTemplate)
+ ' String login(String username)
+ ' int logout(String username)
+ ' }
+
+ interface UserDetailsManager {
+ void createUser(UserDetails userDetails)
+ void changePassword(String oldPassword, String newPassword)
+ void deleteUser(String username)
+ void updateUser(UserDetails user)
+ boolean userExists(String username)
+ }
+ note left
+ Aus org.springframework.security.provisioning
+ - liefert Methoden zum Erstellen neuer User
+ und zum Aktualisieren bestehender.
+ end note
+
+ class JdbcUserDetailsManager <<@Repository>> {
+ <<create>> JdbcUserDetailsManager(DataSource dataSource)
+ void createUser(UserDetails user)
+ void changePassword(String oldPassword, String newPassword)
+ void deleteUser(String username)
+ void updateUser(UserDetails user)
+ boolean userExists(String username)
+ }
+ note right
+ User Management Service aus dem Paket
+ org.springframework.security.provisioning
+ der CRUD Operationen für User bereitstellt.
+ Hier sind nur die relevanten Methoden modelliert.
+ end note
+ }
+
+ package authenticationService <<Frame>> {
+ class AuthenticationService <<@Service>> {
+ --
+ <<create>> AuthenticationService(UserDetailsManager userDetailsManager)
+ List<String> verifyLogin(String username)
+ int logout(String username)
+ int forgotPassword(ForgotPasswordRequest forgotPasswordRequest)
+ .. via JdbcUserDetailsManager ..
+ int resetPassword(String username, RequestWithPassword requestWithPassword)
+ int registerUser(UserDetails user)
+ int changePassword(String username, ChangePasswordRequest changePasswordRequest)
+ int deleteUser(String username, RequestWithPassword requestWithPassword)
+ }
+
+ class JavaMailSenderImpl {}
+ note left
+ Aus org.springframework.mail.javamail.
+ Implementierung des JavaMailSender Interfaces,
+ welches das MailSender Interface durch Unterstützung
+ von MIME Nachrichten erweitert.
+ Das MailSender Interface definiert dabei eine
+ Strategie zum Versenden einfacher Mails.
+ Unterstützt sowohl JavaMail MimeMessages und
+ Spring SimpleMailMessages.
+ end note
+ }
+
+ package authenticationController <<Frame>> {
+ class AuthenticationController <<@Controller>> {
+ <<create>> AuthenticationController(AuthenticationService authenticationService)
+ ResponseEntity<List<String>> verifyLogin(String username)
+ ResponseEntity<Integer> logout(String username)
+ ResponseEntity<Integer> forgotPassword(ForgotPasswordRequest forgotPasswordRequest)
+ ResponseEntity<Integer> resetPassword(String username, RequestWithPassword requestWithPassword)
+ ResponseEntity<Integer> registerUser(UserDetails user)
+ ResponseEntity<Integer> changePassword(String username, ChangePasswordRequest changePasswordRequest)
+ ResponseEntity<Integer> deleteUser(String username, RequestWithPassword requestWithPassword)
+ }
+
+ class ChangePasswordRequest {
+ <<create>> ChangePasswordRequest(String oldPassword, String newPassword)
+ String getOldPassword()
+ String getNewPassword()
+ }
+
+ class ForgotPasswordRequest {
+ <<create>> ForgotPasswordRequest(String email)
+ String getEmail()
+ }
+
+ class RequestWithPassword {
+ <<create>> ResetPasswordRequest(String password)
+ String getPassword()
+ }
+ }
+}
+
+' User <.. AuthenticationDataAccessService: DB
+' User <.. JdbcUserDetailsManager: DB
+UserDetailsManager <.. AuthenticationService: <<use>>
+' AuthenticationDao <.. AuthenticationService: <<use>>
+AuthenticationService --o AuthenticationController
+' AuthenticationDao <|. AuthenticationDataAccessService: <<realize>>
+UserDetailsManager <|. JdbcUserDetailsManager: <<realize>>
+JavaMailSenderImpl <. AuthenticationService: <<use>>
+
+@enduml
+
diff --git a/31-qualitaetsheft-kolloquium/assets/diagrams/classdiagram-episode-actions.puml b/31-qualitaetsheft-kolloquium/assets/diagrams/classdiagram-episode-actions.puml
new file mode 100644
index 0000000..7a4530e
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/assets/diagrams/classdiagram-episode-actions.puml
@@ -0,0 +1,84 @@
+@startuml
+
+package episodeActionsAPI <<Frame>> {
+ package episodeActionDataAccessLayer <<Frame>> {
+ class EpisodeActionDataAccessService <<@Repository>> {
+ <<create>> EpisodeActionDataAccessService (JpaTemplate jpaTemplate)
+ long addEpisodeActions(String username, List<EpisodeActionPost> episodeActionPosts)
+ List<EpisodeActionPost> getEpisodeActions(String username)
+ List<EpisodeActionPost> getEpisodeActionsOfPodcast(String username, String podcastURL)
+ List<EpisodeActionPost> getEpisodeActionsSince(String username, LocalDateTime since)
+ List<EpisodeActionPost> getEpisodeActionsOfPodcastSince(String username, String podcastURL, LocalDateTime since)
+ }
+
+ interface EpisodeActionDao {
+ long addEpisodeActions(String username, List<EpisodeActionPost> episodeActionPosts)
+ List<EpisodeActionPost> getEpisodeActions(String username)
+ List<EpisodeActionPost> getEpisodeActionsOfPodcast(String username, String podcastURL)
+ List<EpisodeActionPost> getEpisodeActionsSince(String username, LocalDateTime since)
+ List<EpisodeActionPost> getEpisodeActionsOfPodcastSince(String username, String podcastURL, LocalDateTime since)
+ }
+ }
+
+ package episodeActionService <<Frame>> {
+ class EpisodeActionService <<@Service>> {
+ <<create>> EpisodeActionService (EpisodeActionDao episodeActionDao)
+ LocalDateTime addEpisodeActions(String username, List<EpisodeActionPosts> episodeActionPosts)
+ List<EpisodeActionPost> getEpisodeActions(String username)
+ List<EpisodeActionPost> getEpisodeActionsOfPodcast(String username, String podcastURL)
+ List<EpisodeActionPost> getEpisodeActionsSince(String username, LocalDateTime since)
+ List<EpisodeActionPost> getEpisodeActionsOfPodcastSince(String username, String podcastURL, LocalDateTime since)
+ }
+ }
+
+ package episodeActionController <<Frame>> {
+ class EpisodeActionController <<@Controller>>{
+ <<create>> EpisodeActionController (EpisodeActionService episodeActionService)
+ ResponseEntity<EpisodeActionPostResponse> addEpisodeActions(String username, EpisodeActionPostRequest episodeActionPostRequest)
+ ResponseEntity<EpisodeActionGetResponse> getEpisodeActions(String username, String deviceID, boolean aggregated)
+ ResponseEntity<EpisodeActionGetResponse> getEpisodeActionsOfPodcast(String username, String podcastURL, String deviceID, boolean aggregated)
+ ResponseEntity<EpisodeActionGetResponse> getEpisodeActionsSince(String username, String deviceID, long since, boolean aggregated)
+ ResponseEntity<EpisodeActionGetResponse> getEpisodeActionsOfPodcastSince(String username, String podcastURL, String deviceID, long since, boolean aggregated)
+ }
+
+ class EpisodeActionPostResponse {
+ <<create>> EpisodeActionPostResponse(List<Pair<String, String>> updateURLs)
+ long getTimestamp()
+ List<Pair<String, String>> getUpdatedURLs()
+ }
+
+ class EpisodeActionPost {
+ <<create>> EpisodeActionPost(String podcastURL, String episodeURL, Action action, LocalDateTime timestamp, int started, int position)
+ String getPodcastURL()
+ String getEpisodeURL()
+ int getGUID()
+ Action getAction()
+ LocalDateTime getTimestamp()
+ int getStarted()
+ int getPosition()
+ EpisodeAction getEpisodeAction()
+ }
+
+ class EpisodeActionPostRequest {
+ <<create>> EpisodeActionPostRequest(List<EpisodeActionPost> episodeActionPosts)
+ List<EpisodeActionPost> getEpisodeActionPosts()
+ }
+
+ class EpisodeActionGetResponse {
+ <<create>> EpisodeActionGetResponse(List<EpisodeActionPost> episodeActionPosts)
+ List<EpisodeActionPost> getEpisodeActionPosts()
+ long getTimestamp()
+ }
+ }
+}
+
+EpisodeActionPost -o EpisodeActionGetResponse
+EpisodeActionPost -o EpisodeActionPostRequest
+' EpisodeAction <.. EpisodeActionDataAccessService: DB
+' Episode <.. EpisodeActionDataAccessService: DB
+EpisodeActionDao <.. EpisodeActionService: <<use>>
+EpisodeActionService --o EpisodeActionController
+EpisodeActionDao <|. EpisodeActionDataAccessService: <<realize>>
+
+@enduml
+
diff --git a/31-qualitaetsheft-kolloquium/assets/diagrams/classdiagram-model.puml b/31-qualitaetsheft-kolloquium/assets/diagrams/classdiagram-model.puml
new file mode 100644
index 0000000..72ad49f
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/assets/diagrams/classdiagram-model.puml
@@ -0,0 +1,109 @@
+@startuml
+
+package model <<Frame>> {
+ class Subscription {
+ <<create>> Subscription(String url, String title)
+ int getID()
+ String getURL()
+ long getLastActionTimestamp()
+ String getTitle()
+ }
+
+ class SubscriptionAction {
+ <<create>> SubscriptionAction(int userID, int subscriptionID)
+ int getID()
+ int getUserID()
+ int getSubscriptionID()
+ long getTimestamp()
+ boolean getAdded()
+ }
+
+ class Episode {
+ <<create>> Episode(int subscriptionID, int id, String url, String title, String thumbnailURL, int total)
+ int getSubscriptionID()
+ int getID()
+ int getGUID()
+ String getURL()
+ String getTitle()
+ int getTotal()
+ }
+
+ enum Action {
+ Download
+ Play
+ Delete
+ New
+ Flattr
+ String getJsonProperty()
+ }
+
+ class EpisodeAction {
+ <<create>> EpisodeAction(Action action, LocalDateTime timestamp, int started, int position)
+ int getEpisodeID()
+ Action getAction()
+ long getTimestamp()
+ int getStarted()
+ int getPosition()
+ void setEpisodeID()
+ EpisodeActionPost getEpisodeActionPost(String podcastURL, String episodeURL)
+ }
+
+ interface UserDetails {
+ String getUsername()
+ String getPassword()
+ Collection<Authority> getAuthorities()
+ boolean isAccountExpired()
+ boolean isAccountLocked()
+ boolean isCredentialsNonExpired()
+ boolean isEnabled()
+ }
+ note left
+ Aus org.springframework.security.core.userdetails.
+ Wird für die Schnittstelle UserDetailsManager benötigt.
+ Stellt wichtige Informationen eines Users bereit.
+ Diese werden nur indirekt von Spring Security
+ benutzt, indem sie vorher in Authentication Objekten
+ gekapselt werden.
+ end note
+
+ class User {
+ --
+ <<create>> User(String username, String password)
+ int getID()
+ String getSessionToken()
+ boolean getEmailIsValidated()
+ .. interface methods ..
+ String getUsername()
+ String getPassword()
+ Collection<Authority> getAuthorities()
+ boolean isAccountExpired()
+ boolean isAccountLocked()
+ boolean isCredentialsNonExpired()
+ boolean isEnabled()
+ }
+
+ interface GrantedAuthority {
+ String getAuthority()
+ }
+ note right
+ Aus org.springframework.security.core.
+ Wird für die Schnittstelle UserDetails benötigt.
+ Repräsentiert eine Autorisierung, die einem
+ Authentication Objekt gewährt wird.
+ end note
+
+ class Authority {
+ <<create>> Authority()
+ String getAuthority()
+ }
+}
+
+Subscription <. SubscriptionAction: ID
+Action <-- EpisodeAction
+EpisodeAction .> Episode: ID
+UserDetails <|.. User: <<realize>>
+User -> Authority
+GrantedAuthority <|.. Authority: <<realize>>
+
+@enduml
+
diff --git a/31-qualitaetsheft-kolloquium/assets/diagrams/classdiagram-subscriptions.puml b/31-qualitaetsheft-kolloquium/assets/diagrams/classdiagram-subscriptions.puml
new file mode 100644
index 0000000..432f185
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/assets/diagrams/classdiagram-subscriptions.puml
@@ -0,0 +1,75 @@
+@startuml
+
+package subscriptionsAPI <<Frame>> {
+ package subscriptionDataAccessLayer <<Frame>> {
+ class SubscriptionDataAccessService <<@Repository>> {
+ <<create>> SubscriptionDataAccessService(JpaTemplate jpaTemplate)
+ int uploadSubscriptions(String username, List<SubscriptionAction> subscriptions)
+ List<String> getSubscriptions(String username)
+ List<String> getSubscriptionsSince(String username, LocalDateTime time)
+ int addSubscriptions(String username, List<SubscriptionAction> addedSubscriptions)
+ int removeSubscriptions(String username, List<SubscriptionAction> removedSubscriptions)
+ List<SubscriptionTitles> getTitles(String username)
+ }
+
+ interface SubscriptionDao {
+ int uploadSubscriptions(String username, List<SubscriptionAction> subscriptions)
+ List<String> getSubscriptions(String username)
+ List<String> getSubscriptionsSince(String username, LocalDateTime time)
+ int addSubscriptions(String username, List<SubscriptionAction> addedSubscriptions)
+ int removeSubscriptions(String username, List<SubscriptionAction> removedSubscriptions)
+ List<SubscriptionTitles> getTitles(String username)
+ }
+ }
+
+ package subscriptionService <<Frame>> {
+ class SubscriptionService <<@Service>> {
+ <<create>> SubscriptionService(SubscriptionDao subscriptionDao)
+ int uploadSubscriptions(String username, List<SubscriptionAction> subscriptions)
+ List<String> getSubscriptions(String username)
+ List<String> getSubscriptionsSince(String username, LocalDateTime time)
+ int addSubscriptions(String username, List<SubscriptionAction> addedSubscriptions)
+ int removeSubscriptions(String username, List<SubscriptionAction> removedSubscriptions)
+ List<SubscriptionTitles> getTitles(String username)
+ }
+ }
+
+ package subscriptionController <<Frame>> {
+ class SubscriptionController <<@Controller>>{
+ ' @Autowired
+ <<create>> SubscriptionController(SubscriptionService subscriptionService)
+ ' @GetMapping
+ ResponseEntity<List<String>> getSubscriptions(String username, String deviceID, String functionJSONP)
+ ' @PutMapping
+ ResponseEntity<String> uploadSubscriptions(String username, String deviceID, List<String> subscriptions)
+ ' @PostMapping
+ ResponseEntity<SubscriptionDelta> applySubscriptionDelta(String username, String deviceID, SubscriptionDelta delta)
+ ' @GetMapping
+ ResponseEntity<SubscriptionDelta> getSubscriptionDelta(String username, String deviceID, long since)
+ ResponseEntity<List<SubscriptionTitles>> getTitles(String username, String deviceID)
+ }
+
+ class SubscriptionTitles {
+ <<create>> SubscriptionTitles(Subscription subscription, List<EpisodeActionPost> episodeTitles)
+ Subscription getSubscription()
+ List<EpisodeActionPost> getEpisodesTitles()
+ }
+
+ class SubscriptionDelta {
+ <<create>> SubscriptionDelta(List<String> add, List<String> remove)
+ List<String> getRemove()
+ LocalDate getTimestamp()
+ List<List<String>> getUpdate_urls()
+ }
+ }
+
+}
+
+' Subscription <.. SubscriptionDataAccessService: DB
+' SubscriptionAction <.. SubscriptionDataAccessService: DB
+SubscriptionService --o SubscriptionController
+SubscriptionDao <.. SubscriptionService: <<use>>
+SubscriptionDao <|. SubscriptionDataAccessService: <<realize>>
+
+@enduml
+
diff --git a/31-qualitaetsheft-kolloquium/assets/diagrams/classdiagram-util.puml b/31-qualitaetsheft-kolloquium/assets/diagrams/classdiagram-util.puml
new file mode 100644
index 0000000..03dfc9a
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/assets/diagrams/classdiagram-util.puml
@@ -0,0 +1,43 @@
+@startuml
+
+package util <<Frame>> {
+ class RSSParser {
+ <<create>> RSSParser(String subscriptionURL)
+ String getSubscriptionTitle()
+ List<Episode> getEpisodes()
+ Episode getEpisodeForURL(String episodeURL)
+ }
+ note bottom
+ Verwendet intern Spring um
+ HTTP-Anfragen zu erstellen.
+ end note
+
+ class CleanCronJob {
+ <<create>> CleanCronJob(JdbcUserDetailsManager jdbcUserDetailsManager)
+ void cleanInvalidUsers()
+ }
+ note bottom
+ Hintergrundservice, der in periodischen Abständen
+ Nutzer, die ihre E-Mail-Adresse nicht nach 24 Stunden
+ bestätigt haben, wieder aus der Datenbank löscht.
+ (Auf die Assoziation zu JdbcUserDetailsManager wird
+ im Sinne der Übersichtlichkeit verzichtet.)
+ end note
+
+ class ResponseEntity<T> {
+ <<create>> ResponseEntity(T body, HttpStatusCode status)
+ T getBody()
+ HttpStatusCode getStatusCode()
+ }
+ note bottom
+ Aus org.springframework.http.
+ Erweitert die Klasse HttpEntity, welche
+ ein HTTP Anfrage- oder Antwort-Objekt
+ repräsentiert, durch einen HttpStatusCode.
+ Wird von den Controller-Methoden als
+ Rückgabewert verwendet.
+ end note
+}
+
+@enduml
+
diff --git a/31-qualitaetsheft-kolloquium/assets/diagrams/classdiagram.puml b/31-qualitaetsheft-kolloquium/assets/diagrams/classdiagram.puml
new file mode 100644
index 0000000..f833aa2
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/assets/diagrams/classdiagram.puml
@@ -0,0 +1,68 @@
+@startuml
+' skinparam linetype ortho
+' skinparam groupInheritance 2
+allowmixing
+
+!include classdiagram-authentication.puml
+!include classdiagram-episode-actions.puml
+!include classdiagram-model.puml
+!include classdiagram-subscriptions.puml
+!include classdiagram-util.puml
+
+class SecurityConfigurationBasicAuth {
+ <<create>> SecurityConfigurationBasicAuth()
+ PasswordEncoder encoder()
+ UserDetailsManager userDetailsService()
+ SecuryFilterChain fiterChain(HTTPSecurity http) throws Excpetion
+}
+note top
+ Erstellt einen Servlet Filter (springSecurityFilterChain)
+ der für die gesamte Sicherheit zuständig ist (Schutz der URLs,
+ Validierung von Anmeldedaten, Weiterleitung zur Anmeldung, etc.).
+end note
+
+class PSEApplication {
+ <<create>> PSEApplication()
+ void main(String[] args)
+}
+
+database Datenbank
+Datenbank <-[hidden]d- subscriptionsAPI
+Datenbank <-[hidden]d- episodeActionsAPI
+Datenbank <-[hidden]d- authenticationAPI
+() SQL as SQLSub
+() SQL as SQLAuth
+() SQL as SQLEpisode
+
+Datenbank -- SQLSub
+Datenbank -- SQLAuth
+Datenbank -- SQLEpisode
+
+Subscription --o SubscriptionTitles
+EpisodeActionPost -o SubscriptionTitles
+UserDetailsManager <.. SecurityConfigurationBasicAuth: <<use>>
+
+SubscriptionController ..o PSEApplication
+AuthenticationController ..o PSEApplication
+EpisodeActionController ..o PSEApplication
+SecurityConfigurationBasicAuth ..o PSEApplication
+
+PSEApplication --() HTTP
+
+SQLSub )-- SubscriptionDataAccessService: JPA
+' SQLAuth )-- AuthenticationDataAccessService: JPA
+SQLAuth )-- JdbcUserDetailsManager: JDBC
+SQLEpisode )-- EpisodeActionDataAccessService: JPA
+
+RSSParser <. SubscriptionDataAccessService: <<use>>
+RSSParser <. EpisodeActionDataAccessService: <<use>>
+' JdbcUserDetailsManager <-- CleanCronJob
+
+model .o Datenbank: ORM (User, SubscriptionAction, Subscription, EpisodeAction, Episode)
+' Datenbank o.. Subscription: ORM
+' Datenbank o.. SubscriptionAction: ORM
+' Datenbank o.. Episode: ORM
+' Datenbank o.. EpisodeAction: ORM
+' Datenbank o.. User: ORM
+
+@enduml
diff --git a/31-qualitaetsheft-kolloquium/assets/diagrams/componentdiagram.puml b/31-qualitaetsheft-kolloquium/assets/diagrams/componentdiagram.puml
new file mode 100644
index 0000000..dea4a1d
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/assets/diagrams/componentdiagram.puml
@@ -0,0 +1,53 @@
+@startuml
+
+[App] as app
+[VueRouter] as router
+[NavbarComponent] as navbar
+[LoginPage] as login_page
+[SubscriptionsPage] as abo_page
+[EpisodesPage] as episodes_page
+[SettingsPage] as settings_page
+[ForgotPasswordPage] as forgot_page
+[ResetPasswordPage] as reset_page
+note top
+ Wird in der E-Mail zum Zurücksetzen des Passworts mit dem JWT-Token verlinkt.
+ Sendet das alte und neue Passwort und den JWT an die API.
+end note
+[RegistrationPage] as registration_page
+
+[SubscriptionComponent] as sub
+[EpisodeComponent] as episode
+[LastUpdateComponent] as last_update
+[PasswordValidatorComponent] as password
+
+app --> router
+
+app --> navbar
+router --> login_page
+router --> forgot_page
+router --> reset_page
+router --> registration_page
+router --> abo_page
+router --> episodes_page
+router --> settings_page
+
+navbar -[hidden] router
+
+episodes_page -[hidden] abo_page
+login_page -[hidden] forgot_page
+registration_page -[hidden] reset_page
+abo_page -[hidden] settings_page
+forgot_page -[hidden] episodes_page
+' forgot_page -[hidden] settings_page
+
+abo_page --> sub
+episodes_page --> episode
+
+sub --> last_update
+episode --> last_update
+
+settings_page --> password
+reset_page --> password
+registration_page --> password
+
+@enduml
diff --git a/31-qualitaetsheft-kolloquium/assets/diagrams/db.puml b/31-qualitaetsheft-kolloquium/assets/diagrams/db.puml
new file mode 100644
index 0000000..bdefaea
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/assets/diagrams/db.puml
@@ -0,0 +1,78 @@
+@startuml
+' Type Symbol
+' Zero or One |o--
+' Exactly One ||--
+' Zero or Many }o--
+' One or Many }|--
+
+skinparam linetype ortho
+
+entity User {
+ * int id <<unique>>
+ * <u>String email</u>
+ * String password
+ * boolean verified
+ * long created_at
+}
+
+entity SubscriptionAction {
+ * int id <<unique>>
+ * <u>int user_id</u>
+ * long timestamp
+ * int subscription_id
+ * boolean added
+}
+
+entity Subscription {
+ * int id <<unique>>
+ * <u>String url</u>
+ * long timestamp
+ * String title
+}
+
+entity Episode {
+ * int id <<unique>>
+ * <u>int guid <<unique>></u>
+ * <u>String url</u>
+ * String title
+ * int total
+ * int subscription_id
+}
+note right
+ Wenn der Client eine GUID aus dem Feed mitsendet, wird
+ diese statt der URL verwendet um die Episode zu finden.
+ So wird die Episode auch noch gefunden, nachdem sich
+ die URL geändert hat.
+end note
+note bottom of Episode
+ Wenn für die Episoden-URL einer EpisodeAction noch keine Episode in der Datenbank steht,
+ dann schreibe dafür ein Dummy-Objekt in Datenbank und lade asynchron die Episoden der Subscription.
+ Ersetze dann die Dummy-Objekte durch die Episoden und setze den Timestamp der Subscription auf
+ die aktuelle Zeit.
+ Um DoS-Angriffe auf den Backend-Server abzuwenden, können die Episoden einer Subscription erst
+ nach einer Stunde erneut gefetched werden. Bis dahin werden für EpisodeActions, die sich auf noch
+ nicht geladene Episoden beziehen, nur Dummy-Objekte für die Episoden in die Datenbank geschrieben.
+ Es sei noch darauf hingewiesen, dass diese Dummy-Episoden bei Anfragen nicht mit ausgegeben werden.
+end note
+
+entity EpisodeAction {
+ * int id <<unique>>
+ * <u>int user_id</u>
+ * int episode_id
+ * long timestamp
+ * int action
+ * int started
+ * int position
+}
+note right
+ Speichere für jede Episode
+ nur letzte Play-Action.
+endnote
+
+User ||--o{ EpisodeAction
+User ||--o{ SubscriptionAction
+SubscriptionAction }|--|| Subscription
+EpisodeAction }|--|| Episode
+Subscription ||-right-|{ Episode
+
+@enduml
diff --git a/31-qualitaetsheft-kolloquium/assets/diagrams/deployment.puml b/31-qualitaetsheft-kolloquium/assets/diagrams/deployment.puml
new file mode 100644
index 0000000..b8d0491
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/assets/diagrams/deployment.puml
@@ -0,0 +1,59 @@
+@startuml
+
+node "<<device>> \nBackend Server" as backendServer{
+ database " <<database system>> \n MariaDB Server 10.6" as database {
+ rectangle rectangle1 [
+ <<schema>>
+ User
+ ]
+ rectangle rectangle2 [
+ <<schema>>
+ SubscriptionAction
+ ]
+ rectangle rectangle3 [
+ <<schema>>
+ EpisodeAction
+ ]
+ rectangle rectangle4 [
+ <<schema>>
+ Subscription
+ ]
+ rectangle rectangle5 [
+ <<schema>>
+ Episode
+ ]
+ }
+
+ node "<<framework>> \nJava Spring" as javaSpring{
+ node " <<device>> \n Tomcat Webserver"
+ }
+}
+
+node "<<device>> \nFrontend" as frontendServer {
+
+}
+
+node "<<device>> \nEndgerät" as terminal {
+ node "<<application>> \nBrowser" as browser
+ node "<<application>> \nPodcatcher" as podcatcher
+}
+
+backendServer "1" - "*" podcatcher
+
+node "<<device>> \nFrontend Server" as frontendServer{
+ node "<<framework>> \nVue.js" as vuejs {
+
+ }
+}
+
+podcatcher -[hidden] browser
+
+backendServer - "1" frontendServer
+
+database "1" -- "1" javaSpring
+
+browser "*" -- frontendServer
+
+
+
+@enduml
diff --git a/31-qualitaetsheft-kolloquium/assets/diagrams/sequencediagram-forgotAndResetPW.puml b/31-qualitaetsheft-kolloquium/assets/diagrams/sequencediagram-forgotAndResetPW.puml
new file mode 100644
index 0000000..603130c
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/assets/diagrams/sequencediagram-forgotAndResetPW.puml
@@ -0,0 +1,41 @@
+@startuml
+
+skinparam ParticipantPadding 30
+
+participant AuthenticationController << (C, #ADD1B2) @Controller >>
+-> AuthenticationController: ""POST /api/2/auth/forgot.json"" \n//@RequestBody ForgotPasswordRequest forgotPasswordRequest// \n\n-> forgotPassword(//forgotPasswordRequest//)
+activate AuthenticationController
+participant AuthenticationService << (C, #ADD1B2) @Service >>
+AuthenticationController -> AuthenticationService: forgotPassword(//forgotPasswordRequest//)
+activate AuthenticationService
+participant JavaMailSenderImpl << (C, #ADD1B2) >>
+AuthenticationService -> JavaMailSenderImpl: create link to reset password with JWT as URL parameter \n-> send(SimpleMailMessage simpleMessage) with link
+activate JavaMailSenderImpl
+<<- JavaMailSenderImpl: sends email with link containing a JWT to reset password
+JavaMailSenderImpl --> AuthenticationService
+deactivate JavaMailSenderImpl
+AuthenticationService --> AuthenticationController: int indicating status
+deactivate AuthenticationService
+<-- AuthenticationController: ResponseEntity<Integer> indicating status \n\n-> ""HTTP status code""
+deactivate AuthenticationController
+||60||
+-> AuthenticationController: ""PUT /api/2/auth/{username}/resetpassword.json"" \n//@RequestParam String jwt// \n//@RequestBody ResetPasswordRequest resetPasswordRequest// \n\n-> login user (""username"") via JWT (//jwt//) \n-> resetPassword(""username"", //resetPasswordRequest//)
+activate AuthenticationController
+AuthenticationController -> AuthenticationService: resetPassword(""username"", //resetPasswordRequest//)
+activate AuthenticationService
+participant JdbcUserDetailsManager << (C, #ADD1B2) @Repository >>
+AuthenticationService -> JdbcUserDetailsManager: String oldPassword = //resetPasswordRequest//.getOldPassword() \nString newPassword = //resetPasswordRequest//.getNewPassword() \n-> changePassword(newPassword, oldPassword)
+activate JdbcUserDetailsManager
+database Database
+JdbcUserDetailsManager -> Database: change password of logged in user
+activate Database
+Database --> JdbcUserDetailsManager
+deactivate Database
+JdbcUserDetailsManager --> AuthenticationService: int indicating status
+deactivate JdbcUserDetailsManager
+AuthenticationService --> AuthenticationController: int indicating status
+deactivate AuthenticationService
+<-- AuthenticationController: ResponseEntity<Integer> indicating status \n\n-> ""HTTP status code""
+deactivate AuthenticationController
+
+@enduml \ No newline at end of file
diff --git a/31-qualitaetsheft-kolloquium/assets/diagrams/sequencediagram-getEpisodeActions.puml b/31-qualitaetsheft-kolloquium/assets/diagrams/sequencediagram-getEpisodeActions.puml
new file mode 100644
index 0000000..47497d5
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/assets/diagrams/sequencediagram-getEpisodeActions.puml
@@ -0,0 +1,38 @@
+@startuml
+
+' title =**Get All Episode Actions**
+
+participant EpisodeActionController << (C, #ADD1B2) @Controller >>
+-> EpisodeActionController: ""GET /api/2/episodes/{username}.json"" \n//@RequestParam("device") String deviceID// \n//@RequestParam("aggregated") boolean aggregated// \n\n-> getEpisodeActions(""username"", //deviceID//, //aggregated//)
+note right
+ Die Parameter //deviceID// und //aggregated// werden ignoriert,
+ da nicht zwischen Geräten unterschieden und für jede
+ Episode sowieso nur die letzte Play-Action gespeichert
+ wird. Dies gilt für alle GET-Anfragen der Episode Actions API.
+end note
+activate EpisodeActionController
+participant EpisodeActionService << (C, #ADD1B2) @Service >>
+EpisodeActionController -> EpisodeActionService: getEpisodeActions(""username"")
+activate EpisodeActionService
+participant EpisodeActionDataAccessService << (C, #ADD1B2) @Repository >>
+EpisodeActionService -> EpisodeActionDataAccessService: getEpisodeActions(""username"")
+activate EpisodeActionDataAccessService
+EpisodeActionDataAccessService -> EpisodeActionDataAccessService: getEpisodeActionsSince(""username"", \nLocalDateTime.MIN.toEpochSecond(ZoneOffset.UTC))
+database Database
+activate EpisodeActionDataAccessService
+EpisodeActionDataAccessService -> Database: get all EpisodeActions for all subscribed podcasts
+activate Database
+Database --> EpisodeActionDataAccessService: List<EpisodeAction> selectedEpisodeActions \n-> then remove all older than LocalDateTime.MIN (none)
+EpisodeActionDataAccessService -> Database: join EpisodeActions in selectedEpisodeActions with episodeURL of Episode
+Database --> EpisodeActionDataAccessService
+deactivate Database
+EpisodeActionDataAccessService --> EpisodeActionDataAccessService: List<EpisodeActionPost> episodeActionPosts
+deactivate EpisodeActionDataAccessService
+EpisodeActionDataAccessService --> EpisodeActionService: List<EpisodeActionPost> episodeActionPosts
+deactivate EpisodeActionDataAccessService
+EpisodeActionService --> EpisodeActionController: List<EpisodeActionPost> episodeActionPosts
+deactivate EpisodeActionService
+<-- EpisodeActionController: ResponseEntity<EpisodeActionGetResponse> response \n\n-> ""HTTP status code"" \n-> ""JSON""
+deactivate EpisodeActionController
+
+@enduml \ No newline at end of file
diff --git a/31-qualitaetsheft-kolloquium/assets/diagrams/sequencediagram-getEpisodeActionsOfPodcastSince.puml b/31-qualitaetsheft-kolloquium/assets/diagrams/sequencediagram-getEpisodeActionsOfPodcastSince.puml
new file mode 100644
index 0000000..d8797d1
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/assets/diagrams/sequencediagram-getEpisodeActionsOfPodcastSince.puml
@@ -0,0 +1,32 @@
+@startuml
+
+' title =**Get Episode Actions of Podcast Since**
+
+participant EpisodeActionController << (C, #ADD1B2) @Controller >>
+-> EpisodeActionController: ""GET /api/2/episodes/{username}.json"" \n//@RequestParam("podcast") String podcastURL// \n//@RequestParam("device") String deviceID// \n//@RequestParam("since") long since// \n//@RequestParam("aggregated") boolean aggregated// \n\n-> getEpisodeActionsOfPodcastSince(""username"", //podcastURL//, //deviceID//, //since//, //aggregated//)
+note right
+ Die Parameter //deviceID// und //aggregated// werden ignoriert.
+ Siehe Notiz in Sequenzdiagramm **Get All Episode Actions**.
+end note
+activate EpisodeActionController
+participant EpisodeActionService << (C, #ADD1B2) @Service >>
+EpisodeActionController -> EpisodeActionService: getEpisodeActionsOfPodcastSince(""username"", //podcastURL//, //since//)
+activate EpisodeActionService
+participant EpisodeActionDataAccessService << (C, #ADD1B2) @Repository >>
+EpisodeActionService -> EpisodeActionDataAccessService: getEpisodeActionsOfPodcastSince(""username"", //podcastURL//, //since//)
+activate EpisodeActionDataAccessService
+database Database
+EpisodeActionDataAccessService -> Database: get all EpisodeActions the given podcast (//podcastURL//)
+activate Database
+Database --> EpisodeActionDataAccessService: List<EpisodeAction> selectedEpisodeActions \n-> then remove all older than //since//
+EpisodeActionDataAccessService -> Database: join EpisodeActions in selectedEpisodeActions with episodeURL of Episode
+Database --> EpisodeActionDataAccessService
+deactivate Database
+EpisodeActionDataAccessService --> EpisodeActionService: List<EpisodeActionPost> episodeActionPosts
+deactivate EpisodeActionDataAccessService
+EpisodeActionService --> EpisodeActionController: List<EpisodeActionPost> episodeActionPosts
+deactivate EpisodeActionService
+<-- EpisodeActionController: ResponseEntity<EpisodeActionGetResponse> response \n\n-> ""HTTP status code"" \n-> ""JSON""
+deactivate EpisodeActionController
+
+@enduml \ No newline at end of file
diff --git a/31-qualitaetsheft-kolloquium/assets/diagrams/sequencediagram-getSubscriptions.puml b/31-qualitaetsheft-kolloquium/assets/diagrams/sequencediagram-getSubscriptions.puml
new file mode 100644
index 0000000..4d8ab90
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/assets/diagrams/sequencediagram-getSubscriptions.puml
@@ -0,0 +1,38 @@
+@startuml
+
+' title =**Get All Subscriptions**
+
+participant SubscriptionController << (C, #ADD1B2) @Controller >>
+-> SubscriptionController: ""GET /subscriptions/{username}.json"" \n"" /subscriptions/{username}/{deviceid}.json"" \n//@RequestParam("jsonp") String functionJSONP// \n\n-> getSubscriptions(""username"", ""deviceid"", //functionJSONP//)
+activate SubscriptionController
+note right
+ Die Parameter ""deviceid"" und
+ //functionJSONP// werden ignoriert,
+ da nicht zwischen Geräten unterschieden
+ und JSONP nicht unterstützt wird.
+end note
+participant SubscriptionService << (C, #ADD1B2) @Service >>
+SubscriptionController -> SubscriptionService: getSubscriptions(""username"")
+activate SubscriptionService
+participant SubscriptionDataAccessService << (C, #ADD1B2) @Repository >>
+SubscriptionService -> SubscriptionDataAccessService: getSubscriptions(""username"")
+activate SubscriptionDataAccessService
+SubscriptionDataAccessService -> SubscriptionDataAccessService: getSubscriptionsSince(""username"", LocalDateTime.MIN)
+database Database
+activate SubscriptionDataAccessService
+SubscriptionDataAccessService -> Database: get all Subscriptions for ""username""
+activate Database
+Database --> SubscriptionDataAccessService: List<Subscription> subscriptions
+SubscriptionDataAccessService -> Database: get Podcasts from Subscriptions
+Database --> SubscriptionDataAccessService: List<Podcast> subscribedPodcasts
+deactivate Database
+SubscriptionDataAccessService --> SubscriptionDataAccessService: List<String> podcastURLs
+deactivate SubscriptionDataAccessService
+SubscriptionDataAccessService --> SubscriptionService: List<String> podcastURLs
+deactivate SubscriptionDataAccessService
+SubscriptionService --> SubscriptionController: List<String> podcastURLs
+deactivate SubscriptionService
+<-- SubscriptionController: ResponseEntity<List<String>> podcastURLs \n \n-> ""HTTP status code"" \n-> ""JSON""
+deactivate SubscriptionController
+
+@enduml \ No newline at end of file
diff --git a/31-qualitaetsheft-kolloquium/assets/diagrams/sequencediagram-register.puml b/31-qualitaetsheft-kolloquium/assets/diagrams/sequencediagram-register.puml
new file mode 100644
index 0000000..b7b7aa1
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/assets/diagrams/sequencediagram-register.puml
@@ -0,0 +1,26 @@
+@startuml
+
+' title =**Register**
+
+participant AuthenticationController << (C, #ADD1B2) @Controller >>
+-> AuthenticationController: ""POST /api/2/auth/register.json"" \n//@RequestBody UserDetails user// \n\n-> registerUser(//user//)
+activate AuthenticationController
+participant AuthenticationService << (C, #ADD1B2) @Service >>
+AuthenticationController -> AuthenticationService: registerUser(//user//)
+activate AuthenticationService
+participant JdbcUserDetailsManager << (C, #ADD1B2) @Repository >>
+AuthenticationService -> JdbcUserDetailsManager: createUser(//user//)
+activate JdbcUserDetailsManager
+database Database
+JdbcUserDetailsManager -> Database: create new User with given UserDetails (//user//)
+activate Database
+Database --> JdbcUserDetailsManager
+deactivate Database
+JdbcUserDetailsManager --> AuthenticationService: int indicating status
+deactivate JdbcUserDetailsManager
+AuthenticationService --> AuthenticationController: int indicating status
+deactivate AuthenticationService
+<-- AuthenticationController: ResponseEntity<Integer> indicating status \n\n-> ""HTTP status code""
+deactivate AuthenticationController
+
+@enduml \ No newline at end of file
diff --git a/31-qualitaetsheft-kolloquium/assets/diagrams/sequencediagram-uploadEpisodeActions.puml b/31-qualitaetsheft-kolloquium/assets/diagrams/sequencediagram-uploadEpisodeActions.puml
new file mode 100644
index 0000000..d3dac57
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/assets/diagrams/sequencediagram-uploadEpisodeActions.puml
@@ -0,0 +1,38 @@
+@startuml
+
+' title =**Upload Episode Actions**
+
+participant EpisodeActionController << (C, #ADD1B2) @Controller >>
+-> EpisodeActionController: ""POST /api/2/episodes/{username}.json"" \n//@RequestBody EpisodeActionPostRequest episodeActionPostRequest// \n\n-> addEpisodeActions(""username"", //episodeActionPostRequest//)
+activate EpisodeActionController
+participant EpisodeActionService << (C, #ADD1B2) @Service >>
+EpisodeActionController -> EpisodeActionService: addEpisodeActions(""username"", \nepisodeActionPosts = //episodeActionPostRequest//.getEpisodeActionPosts())
+activate EpisodeActionService
+participant EpisodeActionDataAccessService << (C, #ADD1B2) @Repository >>
+EpisodeActionService -> EpisodeActionDataAccessService: addEpisodeActions(""username"", episodeActionPosts)
+database Database
+activate EpisodeActionDataAccessService
+loop for each EpisodeActionPost in episodeActionPosts -> episodeAction = episodeActionPost.getEpisodeAction()
+opt episodeAction.getAction().equals(Action.PLAY)
+EpisodeActionDataAccessService -> Database: set episodeID field of episodeAction for this ""username"" via podcastURL and episodeURL
+activate Database
+Database --> EpisodeActionDataAccessService
+EpisodeActionDataAccessService -> Database: get last EpisodeAction with this episodeID if present
+Database --> EpisodeActionDataAccessService: Optional<EpisodeAction> lastEpisodeAction
+opt lastEpisodeAction.isPresent()
+EpisodeActionDataAccessService -> Database: replace lastEpisodeAction with episodeAction
+else else
+EpisodeActionDataAccessService -> Database: add episodeAction to DB as new entry
+end
+Database --> EpisodeActionDataAccessService
+deactivate Database
+end
+end
+EpisodeActionDataAccessService --> EpisodeActionService: long latestTimestamp
+deactivate EpisodeActionDataAccessService
+EpisodeActionService --> EpisodeActionController: LocalDateTime timestamp = LocalDateTime.ofEpochSecond(latestTimestamp, 0, ZoneOffset.UTC)
+deactivate EpisodeActionService
+<-- EpisodeActionController: ResponseEntity<EpisodeActionPostResponse> \n(with empty list for updateURLs) \n\n-> ""HTTP status code"" \n-> ""JSON""
+deactivate EpisodeActionController
+
+@enduml \ No newline at end of file
diff --git a/31-qualitaetsheft-kolloquium/assets/diagrams/sequencediagram-uploadSubscriptions.puml b/31-qualitaetsheft-kolloquium/assets/diagrams/sequencediagram-uploadSubscriptions.puml
new file mode 100644
index 0000000..1edc8cf
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/assets/diagrams/sequencediagram-uploadSubscriptions.puml
@@ -0,0 +1,32 @@
+@startuml
+
+' title =**Upload Subscriptions**
+
+participant SubscriptionController << (C, #ADD1B2) @Controller >>
+-> SubscriptionController: ""PUT /subscriptions/{username}/{deviceid}.json"" \n//@RequestBody List<String> subscriptions// \n\n-> uploadSubscriptions(""username"", ""deviceid"", //subscriptions//)
+activate SubscriptionController
+participant SubscriptionService << (C, #ADD1B2) @Service >>
+SubscriptionController -> SubscriptionService: uploadSubscriptions(""username"", //subscriptions//)
+activate SubscriptionService
+participant SubscriptionDataAccessService << (C, #ADD1B2) @Repository >>
+SubscriptionService -> SubscriptionDataAccessService: uploadSubscriptions(""username"", //subscriptions//)
+activate SubscriptionDataAccessService
+database Database
+SubscriptionDataAccessService -> Database: delete all subsciptions of ""username""
+activate Database
+Database --> SubscriptionDataAccessService
+SubscriptionDataAccessService -> SubscriptionDataAccessService: addSubscriptions(""username"", //subscriptions//)
+activate SubscriptionDataAccessService
+SubscriptionDataAccessService -> Database: upload all subscriptions (//subscriptions//) for ""username""
+Database --> SubscriptionDataAccessService
+deactivate Database
+SubscriptionDataAccessService --> SubscriptionDataAccessService: int indicating status
+deactivate SubscriptionDataAccessService
+SubscriptionDataAccessService --> SubscriptionService: int indicating status
+deactivate SubscriptionDataAccessService
+SubscriptionService --> SubscriptionController: int indicating status
+deactivate SubscriptionService
+<-- SubscriptionController: ResponseEntity<String> with empty String for success \n\n-> ""HTTP status code"" \n-> ""JSON""
+deactivate SubscriptionController
+
+@enduml \ No newline at end of file
diff --git a/31-qualitaetsheft-kolloquium/assets/episode.png b/31-qualitaetsheft-kolloquium/assets/episode.png
new file mode 100644
index 0000000..c0db4a2
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/assets/episode.png
Binary files differ
diff --git a/31-qualitaetsheft-kolloquium/assets/gantt-plan.puml b/31-qualitaetsheft-kolloquium/assets/gantt-plan.puml
new file mode 100644
index 0000000..0e90aa2
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/assets/gantt-plan.puml
@@ -0,0 +1,31 @@
+@startgantt
+
+printscale daily zoom 5
+project starts on 2023-01-30
+
+-- Backend --
+[Controller-Schicht] on {Immanuel} lasts 2 days
+[Service-Schicht (Daten durchreichen)] on {Daniel} lasts 2 days
+[Authentifizierung] on {Gero} lasts 4 days
+[Model-Paket] on {Daniel} lasts 1 days
+[Datenbank aufsetzen] on {Immanuel} lasts 4 days
+[Util-Paket (RSSParser)] on {Daniel} {Lukas} lasts 6 days
+[DataAccess-Schicht] on {Immanuel} {Julius} lasts 8 days
+[Service-Schicht (Geschäftslogik)] on {Daniel} {Immanuel} lasts 8 days
+[Util-Paket (CleanCronJob)] on {Julius} lasts 2 days
+-- Frontend --
+[Komponenten] on {Gero} {Julius} {Lukas} lasts 15 days
+[API-Anbindung] on {Gero} {Lukas} lasts 4 days
+
+'Backend
+[Service-Schicht (Daten durchreichen)] starts at [Controller-Schicht]'s end
+[Datenbank aufsetzen] starts at [Model-Paket]'s end
+[Authentifizierung] starts at [Controller-Schicht]'s end
+[DataAccess-Schicht] starts at [Datenbank aufsetzen]'s end
+[Util-Paket (RSSParser)] starts at [Datenbank aufsetzen]'s end
+[Service-Schicht (Geschäftslogik)] starts at [DataAccess-Schicht]'s end
+[Util-Paket (CleanCronJob)] starts at [DataAccess-Schicht]'s end
+'Frontend
+[API-Anbindung] starts at [DataAccess-Schicht]'s end
+
+@endgantt \ No newline at end of file
diff --git a/31-qualitaetsheft-kolloquium/assets/gantt-reality.puml b/31-qualitaetsheft-kolloquium/assets/gantt-reality.puml
new file mode 100644
index 0000000..f726c56
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/assets/gantt-reality.puml
@@ -0,0 +1,39 @@
+@startgantt
+
+printscale daily zoom 5
+project starts on 2023-01-30
+
+-- Backend --
+[Controller-Schicht] on {Immanuel} lasts 3 days
+[Model-Paket] on {Daniel} lasts 3 days
+[Datenbank aufsetzen] on {Immanuel} lasts 6 days
+[Util-Paket (RSSParser)] on {Daniel} {Lukas} lasts 32 days
+[DAO-Interfaces] on {Julius} {Immanuel} lasts 6 days
+[Authentifizierung] on {Immanuel} lasts 13 days
+[Service-Schicht mit Datenzugriff] on {Julius} lasts 14 days
+[Util-Paket (CleanCronJob)] on {Daniel} lasts 2 days
+[Docker] on {Daniel} lasts 12 days
+[EMailService] on {Gero} lasts 1 days
+-- Frontend --
+[Komponenten] on {Gero} {Julius} lasts 15 days
+[Mehrsprachigkeit] on {Lukas} lasts 5 days
+[Router] on {Gero} lasts 1 days
+[API-Anbindung] on {Gero} {Lukas} lasts 28 days
+[Error-Handling] on {Gero} lasts 5 days
+
+'Backend
+[Datenbank aufsetzen] starts at [Model-Paket]'s end
+[Util-Paket (RSSParser)] starts at [Datenbank aufsetzen]'s end
+[DAO-Interfaces] starts at [Datenbank aufsetzen]'s end
+[Authentifizierung] starts at [DAO-Interfaces]'s end
+[Service-Schicht mit Datenzugriff] starts at [DAO-Interfaces]'s end
+[Util-Paket (CleanCronJob)] starts at [DAO-Interfaces]'s end
+[Docker] starts at [Util-Paket (CleanCronJob)]'s end
+[EMailService] starts 2023-02-14
+'Frontend
+[Mehrsprachigkeit] starts 2023-02-01
+[Router] starts at [Mehrsprachigkeit]'s end
+[API-Anbindung] starts at [Router]'s end
+[Error-Handling] starts 2023-02-05
+
+@endgantt \ No newline at end of file
diff --git a/31-qualitaetsheft-kolloquium/assets/help.png b/31-qualitaetsheft-kolloquium/assets/help.png
new file mode 100644
index 0000000..39a1b84
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/assets/help.png
Binary files differ
diff --git a/31-qualitaetsheft-kolloquium/assets/lasttest/goodSpecsApdex.png b/31-qualitaetsheft-kolloquium/assets/lasttest/goodSpecsApdex.png
new file mode 100644
index 0000000..17a7031
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/assets/lasttest/goodSpecsApdex.png
Binary files differ
diff --git a/31-qualitaetsheft-kolloquium/assets/lasttest/goodSpecsResponse.png b/31-qualitaetsheft-kolloquium/assets/lasttest/goodSpecsResponse.png
new file mode 100644
index 0000000..ca737f4
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/assets/lasttest/goodSpecsResponse.png
Binary files differ
diff --git a/31-qualitaetsheft-kolloquium/assets/lasttest/goodSpecsTable.png b/31-qualitaetsheft-kolloquium/assets/lasttest/goodSpecsTable.png
new file mode 100644
index 0000000..c247933
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/assets/lasttest/goodSpecsTable.png
Binary files differ
diff --git a/31-qualitaetsheft-kolloquium/assets/lasttest/minimumSpecsApdex.png b/31-qualitaetsheft-kolloquium/assets/lasttest/minimumSpecsApdex.png
new file mode 100644
index 0000000..f326e01
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/assets/lasttest/minimumSpecsApdex.png
Binary files differ
diff --git a/31-qualitaetsheft-kolloquium/assets/lasttest/minimumSpecsResponse.png b/31-qualitaetsheft-kolloquium/assets/lasttest/minimumSpecsResponse.png
new file mode 100644
index 0000000..c6d27ff
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/assets/lasttest/minimumSpecsResponse.png
Binary files differ
diff --git a/31-qualitaetsheft-kolloquium/assets/lasttest/minimumSpecsTable.png b/31-qualitaetsheft-kolloquium/assets/lasttest/minimumSpecsTable.png
new file mode 100644
index 0000000..db077cd
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/assets/lasttest/minimumSpecsTable.png
Binary files differ
diff --git a/31-qualitaetsheft-kolloquium/assets/lastupdate.png b/31-qualitaetsheft-kolloquium/assets/lastupdate.png
new file mode 100644
index 0000000..e9b7f5c
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/assets/lastupdate.png
Binary files differ
diff --git a/31-qualitaetsheft-kolloquium/assets/logo.svg b/31-qualitaetsheft-kolloquium/assets/logo.svg
new file mode 100644
index 0000000..1609066
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/assets/logo.svg
@@ -0,0 +1,211 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ version="1.2"
+ width="87.589989mm"
+ height="52.16547mm"
+ viewBox="0 0 8758.9989 5216.547"
+ preserveAspectRatio="xMidYMid"
+ fill-rule="evenodd"
+ stroke-width="28.222"
+ stroke-linejoin="round"
+ xml:space="preserve"
+ id="svg206"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg">
+ <defs
+ class="ClipPathGroup"
+ id="defs8" />
+ <defs
+ id="defs51"><font
+ id="EmbeddedFont_1"
+ horiz-adv-x="2048"
+ horiz-origin-x="0"
+ horiz-origin-y="0"
+ vert-origin-x="512"
+ vert-origin-y="768"
+ vert-adv-y="1024">
+ <font-face
+ font-family="Noto Sans Display Light embedded"
+ units-per-em="2048"
+ font-weight="normal"
+ font-style="normal"
+ ascent="2170"
+ descent="609"
+ id="font-face10" />
+ <missing-glyph
+ horiz-adv-x="2048"
+ d="M 0,0 L 2047,0 2047,2047 0,2047 0,0 Z"
+ id="missing-glyph12" />
+ <glyph
+ unicode="y"
+ horiz-adv-x="927"
+ d="M 2,1089 L 127,1089 367,413 C 388,352 407,298 422,250 437,203 449,161 457,124 L 463,124 C 471,156 483,196 498,246 513,296 530,350 551,409 L 786,1089 913,1089 453,-193 C 418,-290 377,-364 328,-416 279,-468 213,-494 131,-494 107,-494 84,-493 63,-490 43,-487 25,-482 8,-476 L 8,-377 C 23,-383 40,-387 57,-391 75,-394 95,-396 117,-396 170,-396 214,-378 249,-342 284,-307 314,-252 340,-179 L 403,4 2,1089 Z"
+ id="glyph14" />
+ <glyph
+ unicode="t"
+ horiz-adv-x="610"
+ d="M 465,80 C 494,80 521,82 547,87 573,91 595,97 614,105 L 614,11 C 594,3 569,-5 541,-11 512,-17 481,-20 449,-20 363,-20 296,5 249,56 202,106 178,189 178,304 L 178,996 27,996 27,1061 178,1100 219,1350 295,1350 295,1090 608,1090 608,996 295,996 295,310 C 295,157 352,80 465,80 Z"
+ id="glyph16" />
+ <glyph
+ unicode="s"
+ horiz-adv-x="742"
+ d="M 817,289 C 817,191 782,115 713,61 643,7 545,-20 418,-20 347,-20 284,-14 228,-1 173,12 126,29 88,50 L 88,162 C 134,138 186,118 244,102 301,86 360,78 420,78 520,78 592,96 636,133 680,169 702,218 702,281 702,341 679,387 632,419 585,451 515,484 422,519 359,542 303,565 255,589 207,613 169,643 142,680 116,717 102,768 102,832 102,919 136,987 204,1037 271,1086 361,1110 473,1110 535,1110 592,1104 646,1092 700,1080 750,1063 795,1043 L 754,946 C 713,964 667,980 617,993 568,1006 518,1012 469,1012 388,1012 326,997 283,967 239,937 217,893 217,836 217,792 228,758 249,733 270,707 301,686 342,668 383,650 433,630 492,609 553,585 608,562 657,537 707,512 745,481 774,443 803,405 817,353 817,289 Z"
+ id="glyph18" />
+ <glyph
+ unicode="r"
+ horiz-adv-x="583"
+ d="M 596,1108 C 646,1108 692,1102 733,1091 L 717,983 C 674,995 632,1001 590,1001 497,1001 423,964 368,890 312,817 285,719 285,598 L 285,-1 168,-1 168,1089 266,1089 279,886 285,886 C 311,948 350,1000 402,1043 455,1086 520,1108 596,1108 Z"
+ id="glyph20" />
+ <glyph
+ unicode="o"
+ horiz-adv-x="927"
+ d="M 1030,547 C 1030,433 1012,333 976,248 940,164 887,98 818,51 749,4 665,-20 565,-20 471,-20 390,3 322,50 253,96 201,162 164,247 127,333 109,433 109,547 109,723 150,861 232,961 315,1061 429,1110 575,1110 672,1110 755,1087 822,1040 890,993 941,927 977,842 1012,757 1030,659 1030,547 Z M 229,547 C 229,407 257,294 312,208 368,123 453,80 567,80 685,80 771,123 826,209 882,295 909,408 909,547 909,637 898,717 875,787 851,856 815,911 766,951 717,990 653,1010 573,1010 459,1010 373,969 315,887 258,805 229,692 229,547 Z"
+ id="glyph22" />
+ <glyph
+ unicode="n"
+ horiz-adv-x="847"
+ d="M 633,1110 C 749,1110 838,1078 900,1014 962,950 993,850 993,713 L 993,1 877,1 877,705 C 877,809 854,885 810,935 766,985 701,1010 616,1010 395,1010 285,871 285,594 L 285,1 168,1 168,1090 262,1090 279,901 287,901 C 314,962 357,1011 416,1051 474,1091 547,1110 633,1110 Z"
+ id="glyph24" />
+ <glyph
+ unicode="m"
+ horiz-adv-x="1430"
+ d="M 1245,1110 C 1348,1110 1427,1080 1485,1018 1542,957 1571,860 1571,727 L 1571,1 1454,1 1454,723 C 1454,820 1434,892 1393,939 1352,986 1296,1010 1227,1010 1130,1010 1056,980 1005,919 953,858 928,764 928,637 L 928,1 811,1 811,723 C 811,820 791,892 750,939 709,986 653,1010 584,1010 487,1010 413,978 361,914 310,850 285,751 285,619 L 285,1 168,1 168,1090 262,1090 279,918 287,918 C 313,971 352,1016 403,1054 455,1092 521,1110 600,1110 675,1110 739,1093 791,1059 842,1025 879,975 899,908 L 907,908 C 936,972 980,1022 1038,1057 1097,1093 1166,1110 1245,1110 Z"
+ id="glyph26" />
+ <glyph
+ unicode="i"
+ horiz-adv-x="187"
+ d="M 227,1493 C 279,1493 305,1464 305,1405 305,1345 279,1315 227,1315 175,1315 150,1345 150,1405 150,1464 175,1493 227,1493 Z M 285,1090 L 285,0 168,0 168,1090 285,1090 Z"
+ id="glyph28" />
+ <glyph
+ unicode="h"
+ horiz-adv-x="847"
+ d="M 285,1059 C 285,1031 284,1003 283,977 281,951 279,926 276,901 L 285,901 C 312,962 355,1011 413,1051 471,1091 543,1110 629,1110 746,1110 836,1078 899,1014 962,950 993,850 993,713 L 993,1 877,1 877,705 C 877,809 854,885 810,935 766,985 701,1010 616,1010 395,1010 285,871 285,594 L 285,1 168,1 168,1557 285,1557 285,1059 Z"
+ id="glyph30" />
+ <glyph
+ unicode="f"
+ horiz-adv-x="689"
+ d="M 575,995 L 332,995 332,-1 213,-1 213,995 27,995 27,1058 213,1093 213,1202 C 213,1445 316,1566 522,1566 559,1566 593,1563 623,1557 653,1551 680,1544 705,1536 L 678,1439 C 655,1448 630,1454 603,1460 577,1465 550,1468 524,1468 456,1468 407,1447 377,1405 347,1362 332,1295 332,1202 L 332,1089 575,1089 575,995 Z"
+ id="glyph32" />
+ <glyph
+ unicode="e"
+ horiz-adv-x="874"
+ d="M 559,1110 C 646,1110 720,1089 779,1046 839,1003 883,944 913,869 943,794 958,708 958,611 L 958,531 229,531 C 231,386 262,275 325,198 387,121 476,82 592,82 656,82 712,88 759,100 806,111 858,130 915,156 L 915,50 C 865,25 814,7 764,-4 713,-15 655,-20 588,-20 434,-20 315,30 232,129 150,229 109,365 109,537 109,648 126,746 162,832 197,918 249,986 315,1036 382,1085 464,1110 559,1110 Z M 559,1012 C 465,1012 389,979 333,912 276,845 243,750 233,627 L 838,627 C 838,742 815,835 769,906 723,977 653,1012 559,1012 Z"
+ id="glyph34" />
+ <glyph
+ unicode="d"
+ horiz-adv-x="900"
+ d="M 535,-20 C 398,-20 293,27 219,120 145,214 109,352 109,535 109,722 147,865 224,963 301,1061 408,1110 545,1110 629,1110 698,1090 752,1050 805,1010 845,961 872,904 L 881,904 C 879,935 878,970 876,1009 873,1048 872,1084 872,1117 L 872,1557 989,1557 989,0 895,0 879,191 872,191 C 845,132 805,82 751,41 697,0 625,-20 535,-20 Z M 553,80 C 669,80 752,119 801,195 850,271 875,382 875,527 L 875,545 C 875,695 850,810 801,890 752,970 671,1010 559,1010 451,1010 369,969 313,886 257,804 229,686 229,533 229,385 256,273 309,196 363,119 444,80 553,80 Z"
+ id="glyph36" />
+ <glyph
+ unicode="c"
+ horiz-adv-x="768"
+ d="M 580,-20 C 429,-20 313,29 231,127 150,226 109,363 109,539 109,662 129,766 170,850 211,935 269,1000 343,1044 417,1088 504,1110 602,1110 651,1110 698,1106 742,1096 787,1087 825,1074 858,1057 L 825,957 C 791,972 754,984 714,993 673,1002 636,1006 600,1006 481,1006 390,964 326,881 261,798 229,685 229,541 229,405 258,294 314,210 371,126 459,84 580,84 630,84 678,90 723,101 768,112 809,125 846,142 L 846,37 C 812,20 773,6 729,-5 685,-15 636,-20 580,-20 Z"
+ id="glyph38" />
+ <glyph
+ unicode="a"
+ horiz-adv-x="822"
+ d="M 535,1108 C 651,1108 737,1078 795,1018 852,958 881,863 881,734 L 881,0 793,0 772,185 766,185 C 729,123 684,74 631,36 578,-1 503,-20 408,-20 311,-20 233,6 176,59 119,111 90,187 90,285 90,394 132,477 215,533 298,589 420,621 580,629 L 764,639 764,715 C 764,822 744,897 705,942 665,987 606,1010 528,1010 477,1010 426,1002 378,987 329,972 281,953 231,928 L 195,1022 C 242,1047 295,1067 352,1084 410,1100 470,1108 535,1108 Z M 594,543 C 466,536 370,512 307,470 244,429 213,367 213,285 213,217 232,165 271,131 310,96 363,78 430,78 535,78 617,111 676,176 735,240 764,330 764,445 L 764,551 594,543 Z"
+ id="glyph40" />
+ <glyph
+ unicode="S"
+ horiz-adv-x="875"
+ d="M 956,381 C 956,294 936,220 894,160 852,100 796,55 724,25 652,-5 571,-20 479,-20 396,-20 324,-14 262,-2 201,11 147,26 102,46 L 102,162 C 152,142 209,124 273,109 338,94 409,87 485,87 589,87 673,110 738,158 803,206 836,278 836,373 836,431 823,478 798,515 772,553 734,586 682,614 630,642 565,670 485,699 410,726 345,757 291,791 236,825 194,868 164,919 134,970 119,1035 119,1112 119,1192 138,1259 176,1314 214,1369 267,1411 333,1440 399,1469 474,1483 559,1483 626,1483 689,1476 750,1463 810,1449 868,1430 924,1405 L 883,1303 C 772,1352 663,1377 555,1377 462,1377 386,1354 328,1310 269,1266 240,1200 240,1114 240,1052 252,1001 278,964 303,926 340,895 389,869 438,843 498,817 567,791 648,762 717,731 775,698 833,664 878,623 909,573 941,523 956,459 956,381 Z"
+ id="glyph42" />
+ <glyph
+ unicode="P"
+ horiz-adv-x="848"
+ d="M 539,1462 C 869,1462 1034,1325 1034,1049 1034,908 992,798 907,718 823,638 690,598 510,598 L 311,598 311,0 193,0 193,1462 539,1462 Z M 528,1358 L 311,1358 311,702 498,702 C 629,702 730,727 803,776 875,825 911,914 911,1043 911,1152 880,1232 818,1282 756,1333 659,1358 528,1358 Z"
+ id="glyph44" />
+ <glyph
+ unicode="E"
+ horiz-adv-x="769"
+ d="M 950,0 L 193,0 193,1462 950,1462 950,1356 311,1356 311,821 913,821 913,715 311,715 311,107 950,107 950,0 Z"
+ id="glyph46" />
+ <glyph
+ unicode=" "
+ horiz-adv-x="503"
+ id="glyph48" />
+ </font></defs>
+ <defs
+ class="TextShapeIndex"
+ id="defs55" />
+ <defs
+ class="EmbeddedBulletChars"
+ id="defs87" />
+
+ <g
+ id="id10"
+ clip-path="none"
+ transform="translate(-700.00001,-2550)">
+
+ <text
+ class="SVGTextShape"
+ id="text151"
+ x="217.60002"
+ y="-56.506969"
+ style="letter-spacing:4.7625px;word-spacing:104.775px"><tspan
+ class="TextParagraph"
+ font-family="'Noto Sans Display Light', sans-serif"
+ font-size="494px"
+ font-weight="400"
+ id="tspan149"><tspan
+ class="TextPosition"
+ x="650.59998"
+ y="7647.4932"
+ id="tspan147"><tspan
+ fill="#808080"
+ stroke="none"
+ style="white-space:pre"
+ id="tspan145"
+ dx="2.1199999">Podcast Synchronisation made Efficient</tspan></tspan></tspan></text>
+ </g><g
+ id="g1277"
+ transform="translate(-700.00001,-2550)"><path
+ id="path131-3"
+ d="m 6694.0006,4763 c -559.5515,4.407 -980.3924,428.0893 -986.038,985.9863 18.2894,552.8957 454.3127,974.1166 989.0352,986.0379 v -235.0244 c -406.8751,-27.3888 -715.1078,-362.1649 -719.0259,-748.0163 12.7874,-421.0793 236.9242,-746.3999 750.0318,-749.98 895.0688,1.4728 1915.5158,0 2730.9957,0 V 4763 Z"
+ style="fill:#0084d1;fill-opacity:1"
+ clip-path="none" /><path
+ id="path131"
+ d="m 6685.0183,2562.996 c -559.5515,4.407 -980.3924,428.0893 -986.038,985.9863 18.2894,552.8957 454.3127,974.1167 989.0352,986.038 v -235.0244 c -406.8751,-27.3888 -715.1078,-362.165 -719.0259,-748.0164 12.7874,-421.0792 236.9242,-746.3998 750.0318,-749.98 895.0688,1.4728 1915.5158,0 2730.996,0 V 2562.996 Z"
+ style="fill:#0084d1;fill-opacity:1"
+ clip-path="none" /></g><g
+ id="g1263"
+ transform="translate(-700.00001,-2550)"><path
+ fill="none"
+ stroke="#069a2e"
+ stroke-width="265"
+ stroke-linejoin="round"
+ d="m 2793,5962 c 1283,0 429,-2762 1712,-2762"
+ id="path124" /><path
+ id="path110-6"
+ d="M 3198.0212,6550 V 6300.0411 H 2448.0411 V 6050.0305 5550.0094 H 2198.0305 V 6300.0411 6550 H 2448.0411 2698 Z"
+ style="fill:#069a2e;fill-opacity:1" /><path
+ id="path110"
+ d="m 4111.997,2550.0252 v 249.9589 h 749.9801 v 250.0106 500.0211 h 250.0106 v -750.0317 -249.9589 h -250.0106 -249.9589 z"
+ style="fill:#069a2e;fill-opacity:1" /></g>
+ <g
+ id="g1249"
+ transform="translate(-700.00001,-2550)"><path
+ fill="#ff8000"
+ stroke="none"
+ d="M 2215,4164 C 2412.6918,3832.6035 2379.3124,3383.7591 2135.4189,3084.8193 1956.8564,2857.4026 1671.3097,2718.8851 1382,2721 c 0,-52.6667 0,-105.3333 0,-158 -60.1303,-1.0792 190.6585,-1.2724 121.9814,2.7933 434.6311,30.3756 832.6257,336.7309 974.9655,748.2365 148.7336,402.6249 41.0263,883.7477 -266.0719,1183.8452 C 1996.6852,4716.1853 1689.0048,4838.6187 1382,4830 c 0,-61.6667 0,-123.3333 0,-185 338.199,2.9253 666.226,-186.816 833,-481 z"
+ id="path193" /><path
+ fill="#ff8000"
+ stroke="none"
+ d="m 1936,3979 c 175.8129,-283.3241 59.7943,-700.6319 -239.8255,-849.407 -94.2713,-50.9942 -201.887,-77.9344 -309.1745,-74.593 0,-57 0,-114 0,-171 396.3865,-24.0968 777.5367,297.6517 818.5878,693.1841 44.0348,337.5467 -149.4277,694.9971 -466.4953,826.9493 -110.1027,49.0687 -231.5272,73.543 -352.0925,67.8666 0,-61.6667 0,-123.3333 0,-185 220.6353,7.5804 440.8554,-115.3286 549,-308 z"
+ id="path186" /><path
+ fill="#ff8000"
+ stroke="none"
+ d="m 1659,3822 c 86.3933,-138.0398 18.2474,-344.669 -134.6962,-402.3205 C 1483.44,3402.2177 1438.3524,3394.2432 1394,3398 c 0,-56.6667 0,-113.3333 0,-170 223.1964,-19.6143 444.7886,153.3254 478.4886,375.1817 32.646,181.6951 -54.6854,381.4331 -217.3127,472.2205 -78.2316,46.131 -170.3991,69.3119 -261.1759,62.5978 0,-58.3333 0,-116.6667 0,-175 105.6736,9.5509 212.8962,-49.2218 265,-141 z"
+ id="path179" /><rect
+ class="BoundingBox"
+ stroke="none"
+ fill="none"
+ x="700"
+ y="2550"
+ width="501"
+ height="4001"
+ id="rect136"
+ style="fill:#ff8000;fill-opacity:1" /></g>
+
+</svg>
diff --git a/31-qualitaetsheft-kolloquium/assets/navbar.png b/31-qualitaetsheft-kolloquium/assets/navbar.png
new file mode 100644
index 0000000..dd9f8e8
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/assets/navbar.png
Binary files differ
diff --git a/31-qualitaetsheft-kolloquium/assets/password-margin.png b/31-qualitaetsheft-kolloquium/assets/password-margin.png
new file mode 100644
index 0000000..d9d4fa3
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/assets/password-margin.png
Binary files differ
diff --git a/31-qualitaetsheft-kolloquium/assets/password.png b/31-qualitaetsheft-kolloquium/assets/password.png
new file mode 100644
index 0000000..68248a0
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/assets/password.png
Binary files differ
diff --git a/31-qualitaetsheft-kolloquium/assets/sources/checkstyle-after-processed.txt b/31-qualitaetsheft-kolloquium/assets/sources/checkstyle-after-processed.txt
new file mode 100644
index 0000000..8bb59fa
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/assets/sources/checkstyle-after-processed.txt
@@ -0,0 +1 @@
+1 (design) HideUtilityClassConstructor
diff --git a/31-qualitaetsheft-kolloquium/assets/sources/checkstyle-after.txt b/31-qualitaetsheft-kolloquium/assets/sources/checkstyle-after.txt
new file mode 100644
index 0000000..cec00d5
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/assets/sources/checkstyle-after.txt
@@ -0,0 +1,22 @@
+[INFO] Scanning for projects...
+[INFO]
+[INFO] -----------------------< org.pse-squared:server >-----------------------
+[INFO] Building server 0.0.1-SNAPSHOT
+[INFO] --------------------------------[ jar ]---------------------------------
+[INFO]
+[INFO] --- maven-checkstyle-plugin:3.2.1:check (default-cli) @ server ---
+[INFO] There is 1 error reported by Checkstyle 9.3 with sun_checks.xml ruleset.
+[ERROR] src/main/java/org/psesquared/server/ServerApplication.java:[12,1] (design) HideUtilityClassConstructor: Hilfsklassen sollten keinen Standard-Konstruktur und keinen als public deklarierten Konstruktor haben.
+[INFO] ------------------------------------------------------------------------
+[INFO] BUILD FAILURE
+[INFO] ------------------------------------------------------------------------
+[INFO] Total time: 14.432 s
+[INFO] Finished at: 2023-03-18T08:30:11+01:00
+[INFO] ------------------------------------------------------------------------
+[ERROR] Failed to execute goal org.apache.maven.plugins:maven-checkstyle-plugin:3.2.1:check (default-cli) on project server: You have 1 Checkstyle violation. -> [Help 1]
+[ERROR]
+[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
+[ERROR] Re-run Maven using the -X switch to enable full debug logging.
+[ERROR]
+[ERROR] For more information about the errors and possible solutions, please read the following articles:
+[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException
diff --git a/31-qualitaetsheft-kolloquium/assets/sources/checkstyle-before-processed.txt b/31-qualitaetsheft-kolloquium/assets/sources/checkstyle-before-processed.txt
new file mode 100644
index 0000000..3a5af1a
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/assets/sources/checkstyle-before-processed.txt
@@ -0,0 +1,23 @@
+285 (sizes) LineLength
+143 (misc) FinalParameters
+101 (javadoc) JavadocVariable
+83 (javadoc) JavadocStyle
+43 (design) DesignForExtension
+39 (javadoc) MissingJavadocMethod
+26 (regexp) RegexpSingleline
+15 (whitespace) WhitespaceAround
+13 (javadoc) JavadocPackage
+10 (whitespace) OperatorWrap
+10 (javadoc) JavadocType
+7 (imports) AvoidStarImport
+6 (coding) MagicNumber
+4 (javadoc) JavadocMethod
+3 (coding) HiddenField
+2 (javadoc) InvalidJavadocPosition
+2 (design) HideUtilityClassConstructor
+2 (blocks) RightCurly
+1 (whitespace) WhitespaceAfter
+1 (whitespace) FileTabCharacter
+1 (misc) NewlineAtEndOfFile
+1 (misc) ArrayTypeStyle
+1 (imports) UnusedImports
diff --git a/31-qualitaetsheft-kolloquium/assets/sources/checkstyle-before.txt b/31-qualitaetsheft-kolloquium/assets/sources/checkstyle-before.txt
new file mode 100644
index 0000000..abc9f4f
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/assets/sources/checkstyle-before.txt
@@ -0,0 +1,820 @@
+[INFO] Scanning for projects...
+[INFO]
+[INFO] -----------------------< org.pse-squared:server >-----------------------
+[INFO] Building server 0.0.1-SNAPSHOT
+[INFO] --------------------------------[ jar ]---------------------------------
+[INFO]
+[INFO] --- maven-checkstyle-plugin:3.2.1:check (default-cli) @ server ---
+[INFO] There are 799 errors reported by Checkstyle 9.3 with sun_checks.xml ruleset.
+[ERROR] src/main/java/org/psesquared/server/config/AuthenticationValidatorInterceptor.java:[1] (javadoc) JavadocPackage: Es fehlt eine package-info.java.
+[ERROR] src/main/java/org/psesquared/server/config/AuthenticationValidatorInterceptor.java:[15,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/config/AuthenticationValidatorInterceptor.java:[16,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/config/AuthenticationValidatorInterceptor.java:[17,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/config/AuthenticationValidatorInterceptor.java:[18,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/config/AuthenticationValidatorInterceptor.java:[20,5] (design) DesignForExtension: Klasse 'AuthenticationValidatorInterceptor' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'preHandle' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'AuthenticationValidatorInterceptor' final oder die Methode 'preHandle' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/config/AuthenticationValidatorInterceptor.java:[21,30] (misc) FinalParameters: Der Parameter request sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/config/AuthenticationValidatorInterceptor.java:[22,13] (misc) FinalParameters: Der Parameter response sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/config/AuthenticationValidatorInterceptor.java:[23,13] (misc) FinalParameters: Der Parameter handler sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/config/AuthenticationValidatorInterceptor.java:[25] (sizes) LineLength: Zeile ist 81 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/config/AuthenticationValidatorInterceptor.java:[26] (sizes) LineLength: Zeile ist 113 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/config/AuthenticationValidatorInterceptor.java:[44,48] (misc) FinalParameters: Der Parameter request sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/config/AuthenticationValidatorInterceptor.java:[45] (sizes) LineLength: Zeile ist 117 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/config/AuthenticationValidatorInterceptor.java:[46] (sizes) LineLength: Zeile ist 101 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/config/AuthenticationValidatorInterceptor.java:[49] (sizes) LineLength: Zeile ist 90 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/config/SecurityConfigProperties.java:[6] (sizes) LineLength: Zeile ist 87 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/config/SecurityConfigProperties.java:[6,86] (whitespace) WhitespaceAround: Nach '{' fehlt ein Leerzeichen.
+[ERROR] src/main/java/org/psesquared/server/config/SecurityConfigProperties.java:[6,87] (whitespace) WhitespaceAround: Vor '}' fehlt ein Leerzeichen.
+[ERROR] src/main/java/org/psesquared/server/config/EMailConfigProperties.java:[6] (sizes) LineLength: Zeile ist 108 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/config/EMailConfigProperties.java:[6,107] (whitespace) WhitespaceAround: Nach '{' fehlt ein Leerzeichen.
+[ERROR] src/main/java/org/psesquared/server/config/EMailConfigProperties.java:[6,108] (whitespace) WhitespaceAround: Vor '}' fehlt ein Leerzeichen.
+[ERROR] src/main/java/org/psesquared/server/config/SecurityConfig.java:[22,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/config/SecurityConfig.java:[23,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/config/SecurityConfig.java:[24] (sizes) LineLength: Zeile ist 82 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/config/SecurityConfig.java:[24,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/config/SecurityConfig.java:[25] (sizes) LineLength: Zeile ist 97 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/config/SecurityConfig.java:[25,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/config/SecurityConfig.java:[27,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/config/SecurityConfig.java:[28,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/config/SecurityConfig.java:[30,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/config/SecurityConfig.java:[30,5] (design) DesignForExtension: Klasse 'SecurityConfig' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'securityFilterChain' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'SecurityConfig' final oder die Methode 'securityFilterChain' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/config/SecurityConfig.java:[31] (sizes) LineLength: Zeile ist 88 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/config/SecurityConfig.java:[31,52] (misc) FinalParameters: Der Parameter http sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/config/SecurityConfig.java:[48] (sizes) LineLength: Zeile ist 91 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/config/SecurityConfig.java:[56,5] (design) DesignForExtension: Klasse 'SecurityConfig' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'corsConfigurationSource' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'SecurityConfig' final oder die Methode 'corsConfigurationSource' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/config/SecurityConfig.java:[63] (sizes) LineLength: Zeile ist 87 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[3,23] (imports) AvoidStarImport: Stern-Importe der Form '.*' sollten vermieden werden - io.jsonwebtoken.*.
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[21,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[22] (sizes) LineLength: Zeile ist 92 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[22,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[24,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[26,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[26,5] (design) DesignForExtension: Klasse 'JwtService' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'extractUsername' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'JwtService' final oder die Methode 'extractUsername' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[26,35] (misc) FinalParameters: Der Parameter token sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[30,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[30,5] (design) DesignForExtension: Klasse 'JwtService' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'extractClaim' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'JwtService' final oder die Methode 'extractClaim' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[30,31] (misc) FinalParameters: Der Parameter token sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[30,45] (misc) FinalParameters: Der Parameter claimsResolver sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[36] (regexp) RegexpSingleline: Line has trailing spaces.
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[41] (sizes) LineLength: Zeile ist 122 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[41,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[41,5] (design) DesignForExtension: Klasse 'JwtService' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'generateTokenString' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'JwtService' final oder die Methode 'generateTokenString' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[41,39] (misc) FinalParameters: Der Parameter additionalClaims sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[41,77] (misc) FinalParameters: Der Parameter userDetails sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[41,102] (misc) FinalParameters: Der Parameter tokenLifespan sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[46] (sizes) LineLength: Zeile ist 84 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[51,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[51,5] (design) DesignForExtension: Klasse 'JwtService' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'generateAccessTokenString' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'JwtService' final oder die Methode 'generateAccessTokenString' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[53] (sizes) LineLength: Zeile ist 95 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[56,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[56,5] (design) DesignForExtension: Klasse 'JwtService' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'generateUrlTokenString' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'JwtService' final oder die Methode 'generateUrlTokenString' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[57] (sizes) LineLength: Zeile ist 92 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[60,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[60,5] (design) DesignForExtension: Klasse 'JwtService' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'isTokenValid' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'JwtService' final oder die Methode 'isTokenValid' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[60,33] (misc) FinalParameters: Der Parameter token sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[60,47] (misc) FinalParameters: Der Parameter userDetails sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[62] (sizes) LineLength: Zeile ist 84 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[65,36] (misc) FinalParameters: Der Parameter token sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[69,36] (misc) FinalParameters: Der Parameter token sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[73,37] (misc) FinalParameters: Der Parameter token sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/config/JwtService.java:[88] (sizes) LineLength: Zeile ist 91 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/config/JwtAuthenticationFilter.java:[26,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/config/JwtAuthenticationFilter.java:[27,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/config/JwtAuthenticationFilter.java:[28] (sizes) LineLength: Zeile ist 82 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/config/JwtAuthenticationFilter.java:[28,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/config/JwtAuthenticationFilter.java:[29] (sizes) LineLength: Zeile ist 97 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/config/JwtAuthenticationFilter.java:[29,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/config/JwtAuthenticationFilter.java:[30,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/config/JwtAuthenticationFilter.java:[32,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/config/JwtAuthenticationFilter.java:[33,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/config/JwtAuthenticationFilter.java:[35,5] (design) DesignForExtension: Klasse 'JwtAuthenticationFilter' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'doFilterInternal' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'JwtAuthenticationFilter' final oder die Methode 'doFilterInternal' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/config/JwtAuthenticationFilter.java:[36,37] (misc) FinalParameters: Der Parameter request sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/config/JwtAuthenticationFilter.java:[37,37] (misc) FinalParameters: Der Parameter response sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/config/JwtAuthenticationFilter.java:[38,37] (misc) FinalParameters: Der Parameter filterChain sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/config/JwtAuthenticationFilter.java:[45] (sizes) LineLength: Zeile ist 96 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/config/JwtAuthenticationFilter.java:[54] (sizes) LineLength: Zeile ist 81 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/config/JwtAuthenticationFilter.java:[54,38] (misc) FinalParameters: Der Parameter cookie sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/config/JwtAuthenticationFilter.java:[54,53] (misc) FinalParameters: Der Parameter request sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/config/JwtAuthenticationFilter.java:[68] (sizes) LineLength: Zeile ist 95 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/config/JwtAuthenticationFilter.java:[69,13] (whitespace) WhitespaceAfter: Nach 'if' fehlt ein Leerzeichen.
+[ERROR] src/main/java/org/psesquared/server/config/JwtAuthenticationFilter.java:[70] (sizes) LineLength: Zeile ist 104 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/config/JwtAuthenticationFilter.java:[76] (sizes) LineLength: Zeile ist 82 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/config/ApplicationConfig.java:[32] (sizes) LineLength: Zeile ist 98 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/config/ApplicationConfig.java:[32,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/config/ApplicationConfig.java:[34,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/config/ApplicationConfig.java:[36,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/config/ApplicationConfig.java:[36,5] (design) DesignForExtension: Klasse 'ApplicationConfig' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'userDetailsService' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'ApplicationConfig' final oder die Methode 'userDetailsService' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/config/ApplicationConfig.java:[39] (sizes) LineLength: Zeile ist 94 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/config/ApplicationConfig.java:[42,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/config/ApplicationConfig.java:[42,5] (design) DesignForExtension: Klasse 'ApplicationConfig' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'authenticationProvider' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'ApplicationConfig' final oder die Methode 'authenticationProvider' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/config/ApplicationConfig.java:[44] (sizes) LineLength: Zeile ist 81 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/config/ApplicationConfig.java:[50,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/config/ApplicationConfig.java:[50,5] (design) DesignForExtension: Klasse 'ApplicationConfig' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'passwordEncoder' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'ApplicationConfig' final oder die Methode 'passwordEncoder' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/config/ApplicationConfig.java:[55,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/config/ApplicationConfig.java:[55,5] (design) DesignForExtension: Klasse 'ApplicationConfig' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'authenticationManager' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'ApplicationConfig' final oder die Methode 'authenticationManager' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/config/ApplicationConfig.java:[56] (sizes) LineLength: Zeile ist 109 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/config/ApplicationConfig.java:[56,56] (misc) FinalParameters: Der Parameter config sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/config/ApplicationConfig.java:[60,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/config/ApplicationConfig.java:[60,5] (design) DesignForExtension: Klasse 'ApplicationConfig' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'corsConfigurer' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'ApplicationConfig' final oder die Methode 'corsConfigurer' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/config/ApplicationConfig.java:[64,41] (misc) FinalParameters: Der Parameter registry sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/config/ApplicationConfig.java:[73,5] (design) DesignForExtension: Klasse 'ApplicationConfig' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'addInterceptors' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'ApplicationConfig' final oder die Methode 'addInterceptors' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/config/ApplicationConfig.java:[74,33] (misc) FinalParameters: Der Parameter registry sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/model/Subscription.java:[1] (javadoc) JavadocPackage: Es fehlt eine package-info.java.
+[ERROR] src/main/java/org/psesquared/server/model/Subscription.java:[24] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/Subscription.java:[33] (sizes) LineLength: Zeile ist 105 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/model/Subscription.java:[36] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/Subscription.java:[45] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/Subscription.java:[51] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/Subscription.java:[57] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/Subscription.java:[63,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/model/Subscription.java:[68] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/Subscription.java:[75,9] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/model/Subscription.java:[75,9] (design) DesignForExtension: Klasse 'Subscription' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'addEpisode' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'Subscription' final oder die Methode 'addEpisode' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/model/Subscription.java:[75,32] (misc) FinalParameters: Der Parameter episode sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/model/Role.java:[3] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/Role.java:[8] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/Role.java:[12] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/Role.java:[17,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/model/EpisodeAction.java:[22] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/EpisodeAction.java:[33] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/EpisodeAction.java:[42] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/EpisodeAction.java:[49] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/EpisodeAction.java:[56] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/EpisodeAction.java:[64] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/EpisodeAction.java:[73] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/EpisodeAction.java:[80] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/EpisodeAction.java:[88] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/EpisodeAction.java:[92] (javadoc) JavadocMethod: @return-Tag sollte vorhanden sein und eine Beschreibung haben.
+[ERROR] src/main/java/org/psesquared/server/model/EpisodeAction.java:[93] (sizes) LineLength: Zeile ist 81 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/model/EpisodeAction.java:[98] (sizes) LineLength: Zeile ist 95 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/model/SubscriptionAction.java:[16] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/SubscriptionAction.java:[27] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/SubscriptionAction.java:[36] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/SubscriptionAction.java:[42] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/SubscriptionAction.java:[50] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/SubscriptionAction.java:[56] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/User.java:[6,27] (imports) AvoidStarImport: Stern-Importe der Form '.*' sollten vermieden werden - jakarta.persistence.*.
+[ERROR] src/main/java/org/psesquared/server/model/User.java:[15] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/User.java:[26] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/User.java:[35] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/User.java:[44] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/User.java:[52] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/User.java:[59] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/User.java:[66] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/User.java:[74] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/User.java:[81] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/User.java:[88] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/User.java:[95,5] (design) DesignForExtension: Klasse 'User' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'getAuthorities' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'User' final oder die Methode 'getAuthorities' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/model/User.java:[100,5] (design) DesignForExtension: Klasse 'User' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'isAccountNonExpired' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'User' final oder die Methode 'isAccountNonExpired' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/model/User.java:[105,5] (design) DesignForExtension: Klasse 'User' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'isAccountNonLocked' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'User' final oder die Methode 'isAccountNonLocked' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/model/User.java:[110,5] (design) DesignForExtension: Klasse 'User' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'isCredentialsNonExpired' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'User' final oder die Methode 'isCredentialsNonExpired' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/model/Action.java:[5] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/Action.java:[7] (regexp) RegexpSingleline: Line has trailing spaces.
+[ERROR] src/main/java/org/psesquared/server/model/Action.java:[10] (regexp) RegexpSingleline: Line has trailing spaces.
+[ERROR] src/main/java/org/psesquared/server/model/Action.java:[11,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/model/Action.java:[12,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/model/Action.java:[13,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/model/Action.java:[14,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/model/Action.java:[15,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/model/Action.java:[17,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/model/Episode.java:[19] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/Episode.java:[30] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/Episode.java:[38] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/Episode.java:[44] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/Episode.java:[50] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/Episode.java:[56] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/Episode.java:[62] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/model/Episode.java:[68] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/util/UpdateURLsWrapper.java:[1] (javadoc) JavadocPackage: Es fehlt eine package-info.java.
+[ERROR] src/main/java/org/psesquared/server/util/UpdateURLsWrapper.java:[10] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/util/UpdateURLsWrapper.java:[15,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/util/UpdateURLsWrapper.java:[16,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/util/UpdateURLsWrapper.java:[18] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/util/UpdateURLsWrapper.java:[26,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/util/UpdateURLsWrapper.java:[26,5] (design) DesignForExtension: Klasse 'UpdateURLsWrapper' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'getTimestamp' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'UpdateURLsWrapper' final oder die Methode 'getTimestamp' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/util/UpdateURLsWrapper.java:[30,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/util/UpdateURLsWrapper.java:[30,5] (design) DesignForExtension: Klasse 'UpdateURLsWrapper' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'getUpdateURLs' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'UpdateURLsWrapper' final oder die Methode 'getUpdateURLs' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/util/Scheduler.java:[10] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/util/Scheduler.java:[16,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/util/Scheduler.java:[19] (sizes) LineLength: Zeile ist 137 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/util/Scheduler.java:[24] (sizes) LineLength: Zeile ist 126 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/util/Scheduler.java:[24,112] (coding) MagicNumber: Die magische Zahl '24' sollte als Konstante definiert werden.
+[ERROR] src/main/java/org/psesquared/server/util/Scheduler.java:[24,117] (coding) MagicNumber: Die magische Zahl '60' sollte als Konstante definiert werden.
+[ERROR] src/main/java/org/psesquared/server/util/Scheduler.java:[24,122] (coding) MagicNumber: Die magische Zahl '60' sollte als Konstante definiert werden.
+[ERROR] src/main/java/org/psesquared/server/util/RSSParser.java:[38,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/util/RSSParser.java:[40,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/util/RSSParser.java:[41,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/util/RSSParser.java:[43,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/util/RSSParser.java:[43,5] (design) DesignForExtension: Klasse 'RSSParser' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'validate' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'RSSParser' final oder die Methode 'validate' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/util/RSSParser.java:[44,5] (javadoc) InvalidJavadocPosition: Javadoc-Kommentar ist an der falschen Stelle platziert.
+[ERROR] src/main/java/org/psesquared/server/util/RSSParser.java:[48] (sizes) LineLength: Zeile ist 84 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/util/RSSParser.java:[51] (regexp) RegexpSingleline: Line has trailing spaces.
+[ERROR] src/main/java/org/psesquared/server/util/RSSParser.java:[54,26] (misc) FinalParameters: Der Parameter subscription sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/util/RSSParser.java:[66] (sizes) LineLength: Zeile ist 101 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/util/RSSParser.java:[73] (sizes) LineLength: Zeile ist 89 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/util/RSSParser.java:[87] (sizes) LineLength: Zeile ist 83 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/util/RSSParser.java:[87,56] (misc) FinalParameters: Der Parameter subscription sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/util/RSSParser.java:[126] (sizes) LineLength: Zeile ist 82 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/util/RSSParser.java:[126,34] (misc) FinalParameters: Der Parameter syndEntry sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/util/RSSParser.java:[126,55] (misc) FinalParameters: Der Parameter subscription sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/util/RSSParser.java:[158] (sizes) LineLength: Zeile ist 114 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/util/RSSParser.java:[161] (sizes) LineLength: Zeile ist 95 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/util/RSSParser.java:[161,45] (misc) FinalParameters: Der Parameter episodeURL sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/util/RSSParser.java:[161,64] (misc) FinalParameters: Der Parameter episodes sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/util/RSSParser.java:[168,5] (design) DesignForExtension: Klasse 'RSSParser' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'saveEpisodes' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'RSSParser' final oder die Methode 'saveEpisodes' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/util/RSSParser.java:[169,33] (misc) FinalParameters: Der Parameter episodes sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/util/RSSParser.java:[173,5] (design) DesignForExtension: Klasse 'RSSParser' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'deleteEpisodes' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'RSSParser' final oder die Methode 'deleteEpisodes' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/util/RSSParser.java:[174,35] (misc) FinalParameters: Der Parameter episodes sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/util/RSSParser.java:[179,5] (design) DesignForExtension: Klasse 'RSSParser' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'saveSubscription' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'RSSParser' final oder die Methode 'saveSubscription' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/util/RSSParser.java:[180,37] (misc) FinalParameters: Der Parameter subscription sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/util/RSSParser.java:[184,5] (design) DesignForExtension: Klasse 'RSSParser' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'deleteSubscription' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'RSSParser' final oder die Methode 'deleteSubscription' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/util/RSSParser.java:[185,39] (misc) FinalParameters: Der Parameter subscription sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/util/RSSParser.java:[190,43] (misc) FinalParameters: Der Parameter time sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/util/RSSParser.java:[208,31] (misc) ArrayTypeStyle: Array-Klammern an ungültiger Position.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationResponse.java:[1] (javadoc) JavadocPackage: Es fehlt eine package-info.java.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationResponse.java:[7,1] (javadoc) JavadocType: Im Javadoc des Typs fehlt das Tag @param token.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationResponse.java:[7,52] (whitespace) WhitespaceAround: Nach '{' fehlt ein Leerzeichen.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationResponse.java:[7,53] (whitespace) WhitespaceAround: Vor '}' fehlt ein Leerzeichen.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[9,47] (imports) AvoidStarImport: Stern-Importe der Form '.*' sollten vermieden werden - org.springframework.web.bind.annotation.*.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[15] (sizes) LineLength: Zeile ist 98 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[23,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[25,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[26,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[29] (sizes) LineLength: Zeile ist 117 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[30] (sizes) LineLength: Zeile ist 109 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[31] (sizes) LineLength: Zeile ist 99 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[34] (sizes) LineLength: Zeile ist 91 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[41,36] (misc) FinalParameters: Der Parameter userInfo sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[46] (sizes) LineLength: Zeile ist 118 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[47] (sizes) LineLength: Zeile ist 101 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[51] (sizes) LineLength: Zeile ist 99 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[56] (regexp) RegexpSingleline: Line has trailing spaces.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[60,42] (misc) FinalParameters: Der Parameter username sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[61,42] (misc) FinalParameters: Der Parameter token sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[62] (sizes) LineLength: Zeile ist 81 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[62,42] (misc) FinalParameters: Der Parameter response sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[63] (sizes) LineLength: Zeile ist 86 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[69] (sizes) LineLength: Zeile ist 112 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[71] (sizes) LineLength: Zeile ist 85 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[74] (sizes) LineLength: Zeile ist 89 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[81,29] (misc) FinalParameters: Der Parameter username sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[82,29] (misc) FinalParameters: Der Parameter response sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[87] (sizes) LineLength: Zeile ist 120 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[89] (sizes) LineLength: Zeile ist 85 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[92] (sizes) LineLength: Zeile ist 90 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[99,30] (misc) FinalParameters: Der Parameter username sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[100,30] (misc) FinalParameters: Der Parameter response sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[100,68] (whitespace) WhitespaceAround: Vor '{' fehlt ein Leerzeichen.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[105] (sizes) LineLength: Zeile ist 119 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[108] (sizes) LineLength: Zeile ist 83 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[115,38] (misc) FinalParameters: Der Parameter email sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[119,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[119,5] (design) DesignForExtension: Klasse 'AuthenticationController' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'resetPassword' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'AuthenticationController' final oder die Methode 'resetPassword' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[120,37] (misc) FinalParameters: Der Parameter username sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[121,37] (misc) FinalParameters: Der Parameter token sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[122,37] (misc) FinalParameters: Der Parameter requestBody sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[123] (sizes) LineLength: Zeile ist 81 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[126,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[126,5] (design) DesignForExtension: Klasse 'AuthenticationController' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'changePassword' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'AuthenticationController' final oder die Methode 'changePassword' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[127,38] (misc) FinalParameters: Der Parameter username sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[128] (sizes) LineLength: Zeile ist 86 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[128,38] (misc) FinalParameters: Der Parameter requestBody sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[132,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[132,5] (design) DesignForExtension: Klasse 'AuthenticationController' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'deleteUser' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'AuthenticationController' final oder die Methode 'deleteUser' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[133,34] (misc) FinalParameters: Der Parameter username sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[134,34] (misc) FinalParameters: Der Parameter requestBody sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[138,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[138,5] (design) DesignForExtension: Klasse 'AuthenticationController' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'getDeviceList' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'AuthenticationController' final oder die Methode 'getDeviceList' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[139] (sizes) LineLength: Zeile ist 91 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[139,62] (misc) FinalParameters: Der Parameter username sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[140] (sizes) LineLength: Zeile ist 101 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[140,62] (misc) FinalParameters: Der Parameter response sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/AuthenticationController.java:[142] (sizes) LineLength: Zeile ist 107 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/ForgotPasswordRequest.java:[5] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/ForgotPasswordRequest.java:[8] (sizes) LineLength: Zeile ist 83 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/ForgotPasswordRequest.java:[8,1] (javadoc) JavadocType: Im Javadoc des Typs fehlt das Tag @param email.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/ForgotPasswordRequest.java:[8,82] (whitespace) WhitespaceAround: Nach '{' fehlt ein Leerzeichen.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/ForgotPasswordRequest.java:[8,83] (whitespace) WhitespaceAround: Vor '}' fehlt ein Leerzeichen.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/DeviceWrapper.java:[3,8] (imports) UnusedImports: Nicht verwendeter Import - jakarta.servlet.http.HttpServletResponse.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/DeviceWrapper.java:[14] (sizes) LineLength: Zeile ist 88 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/DeviceWrapper.java:[16,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/DeviceWrapper.java:[17,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/DeviceWrapper.java:[18,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/DeviceWrapper.java:[19,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/DeviceWrapper.java:[21,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/ChangePasswordRequest.java:[5] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/ChangePasswordRequest.java:[9] (sizes) LineLength: Zeile ist 106 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/ChangePasswordRequest.java:[9,1] (javadoc) JavadocType: Im Javadoc des Typs fehlt das Tag @param newPassword.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/ChangePasswordRequest.java:[9,1] (javadoc) JavadocType: Im Javadoc des Typs fehlt das Tag @param oldPassword.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/ChangePasswordRequest.java:[10] (sizes) LineLength: Zeile ist 84 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/UserInfoRequest.java:[9,1] (javadoc) JavadocType: Im Javadoc des Typs fehlt das Tag @param email.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/UserInfoRequest.java:[9,1] (javadoc) JavadocType: Im Javadoc des Typs fehlt das Tag @param password.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/UserInfoRequest.java:[9,1] (javadoc) JavadocType: Im Javadoc des Typs fehlt das Tag @param username.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/UserInfoRequest.java:[11,79] (whitespace) WhitespaceAround: Nach '{' fehlt ein Leerzeichen.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/UserInfoRequest.java:[11,80] (whitespace) WhitespaceAround: Vor '}' fehlt ein Leerzeichen.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/PasswordRequest.java:[9,1] (javadoc) JavadocType: Im Javadoc des Typs fehlt das Tag @param password.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/PasswordRequest.java:[9,79] (whitespace) WhitespaceAround: Nach '{' fehlt ein Leerzeichen.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/controller/PasswordRequest.java:[9,80] (whitespace) WhitespaceAround: Vor '}' fehlt ein Leerzeichen.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[1] (javadoc) JavadocPackage: Es fehlt eine package-info.java.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[6,59] (imports) AvoidStarImport: Stern-Importe der Form '.*' sollten vermieden werden - org.psesquared.server.authentication_api.controller.*.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[25,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[26,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[27,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[28,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[29,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[30,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[32,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[33,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[34,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[35,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[36,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[37,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[39,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[39,5] (design) DesignForExtension: Klasse 'AuthenticationService' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'registerUser' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'AuthenticationService' final oder die Methode 'registerUser' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[39,36] (misc) FinalParameters: Der Parameter userInfo sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[55] (sizes) LineLength: Zeile ist 91 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[56] (sizes) LineLength: Zeile ist 85 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[66] (sizes) LineLength: Zeile ist 81 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[75,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[75,5] (design) DesignForExtension: Klasse 'AuthenticationService' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'verifyRegistration' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'AuthenticationService' final oder die Methode 'verifyRegistration' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[75,42] (misc) FinalParameters: Der Parameter username sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[75,59] (misc) FinalParameters: Der Parameter token sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[95,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[95,5] (design) DesignForExtension: Klasse 'AuthenticationService' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'login' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'AuthenticationService' final oder die Methode 'login' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[95,29] (misc) FinalParameters: Der Parameter username sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[96,36] (misc) FinalParameters: Der Parameter response sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[110,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[110,5] (design) DesignForExtension: Klasse 'AuthenticationService' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'logout' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'AuthenticationService' final oder die Methode 'logout' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[110,30] (misc) FinalParameters: Der Parameter username sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[111,30] (misc) FinalParameters: Der Parameter response sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[112,58] (whitespace) WhitespaceAround: Vor '{' fehlt ein Leerzeichen.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[122,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[122,5] (design) DesignForExtension: Klasse 'AuthenticationService' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'forgotPassword' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'AuthenticationService' final oder die Methode 'forgotPassword' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[122,38] (misc) FinalParameters: Der Parameter email sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[124] (sizes) LineLength: Zeile ist 95 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[128,11] (whitespace) WhitespaceAround: Nach 'catch' fehlt ein Leerzeichen.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[133,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[133,5] (design) DesignForExtension: Klasse 'AuthenticationService' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'resetPassword' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'AuthenticationService' final oder die Methode 'resetPassword' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[133,37] (misc) FinalParameters: Der Parameter username sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[134,31] (misc) FinalParameters: Der Parameter token sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[135,31] (misc) FinalParameters: Der Parameter requestBody sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[144] (sizes) LineLength: Zeile ist 81 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[153,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[153,5] (design) DesignForExtension: Klasse 'AuthenticationService' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'changePassword' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'AuthenticationService' final oder die Methode 'changePassword' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[153,38] (misc) FinalParameters: Der Parameter username sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[154,38] (misc) FinalParameters: Der Parameter requestBody sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[158] (sizes) LineLength: Zeile ist 89 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[168,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[168,5] (design) DesignForExtension: Klasse 'AuthenticationService' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'deleteUser' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'AuthenticationService' final oder die Methode 'deleteUser' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[168,34] (misc) FinalParameters: Der Parameter username sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[169,34] (misc) FinalParameters: Der Parameter requestBody sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[173] (sizes) LineLength: Zeile ist 86 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[183,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[183,5] (design) DesignForExtension: Klasse 'AuthenticationService' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'deleteInvalidUsersOlderThan' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'AuthenticationService' final oder die Methode 'deleteInvalidUsersOlderThan' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[183,45] (misc) FinalParameters: Der Parameter timestamp sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/AuthenticationService.java:[184] (sizes) LineLength: Zeile ist 81 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/ResourceReader.java:[8,1] (design) HideUtilityClassConstructor: Hilfsklassen sollten keinen Standard-Konstruktur und keinen als public deklarierten Konstruktor haben.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/ResourceReader.java:[9] (sizes) LineLength: Zeile ist 83 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/ResourceReader.java:[9,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/ResourceReader.java:[9,43] (misc) FinalParameters: Der Parameter path sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/ResourceReader.java:[10] (sizes) LineLength: Zeile ist 95 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[16,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[17,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[18,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[20,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[23,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[24] (sizes) LineLength: Zeile ist 110 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[25,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[26] (sizes) LineLength: Zeile ist 102 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[28,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[29] (sizes) LineLength: Zeile ist 82 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[29,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[30] (sizes) LineLength: Zeile ist 85 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[30,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[32,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[33,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[34,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[35,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[37] (sizes) LineLength: Zeile ist 83 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[37,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[37,83] (whitespace) OperatorWrap: '+' sollte in einer neuen Zeile stehen.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[41] (sizes) LineLength: Zeile ist 83 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[41,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[41,83] (whitespace) OperatorWrap: '+' sollte in einer neuen Zeile stehen.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[46] (sizes) LineLength: Zeile ist 119 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[47] (sizes) LineLength: Zeile ist 134 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[52,27] (misc) FinalParameters: Der Parameter to sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[52,38] (misc) FinalParameters: Der Parameter mailSubject sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[52,58] (misc) FinalParameters: Der Parameter body sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[52,65] (javadoc) JavadocMethod: Erwartetes Tag @param für 'body'.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[53] (sizes) LineLength: Zeile ist 87 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[62] (sizes) LineLength: Zeile ist 90 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[62,43] (misc) FinalParameters: Der Parameter template sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[62,60] (misc) FinalParameters: Der Parameter user sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[62,78] (misc) FinalParameters: Der Parameter url sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[69] (sizes) LineLength: Zeile ist 81 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[71] (sizes) LineLength: Zeile ist 115 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[76] (sizes) LineLength: Zeile ist 82 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[79,58] (whitespace) OperatorWrap: '+' sollte in einer neuen Zeile stehen.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[80,54] (whitespace) OperatorWrap: '+' sollte in einer neuen Zeile stehen.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[81,33] (whitespace) OperatorWrap: '+' sollte in einer neuen Zeile stehen.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[82,32] (whitespace) OperatorWrap: '+' sollte in einer neuen Zeile stehen.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[83,43] (whitespace) OperatorWrap: '+' sollte in einer neuen Zeile stehen.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[84,33] (whitespace) OperatorWrap: '+' sollte in einer neuen Zeile stehen.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[85,29] (whitespace) OperatorWrap: '+' sollte in einer neuen Zeile stehen.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[91] (sizes) LineLength: Zeile ist 89 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[92] (sizes) LineLength: Zeile ist 112 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[95,34] (misc) FinalParameters: Der Parameter to sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[95,41] (javadoc) JavadocMethod: Erwartetes Tag @param für 'to'.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[95,45] (misc) FinalParameters: Der Parameter userDetails sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[97] (sizes) LineLength: Zeile ist 89 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[103] (sizes) LineLength: Zeile ist 102 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[104] (sizes) LineLength: Zeile ist 118 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[107,35] (misc) FinalParameters: Der Parameter to sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[107,42] (javadoc) JavadocMethod: Erwartetes Tag @param für 'to'.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[107,46] (misc) FinalParameters: Der Parameter userDetails sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EMailServiceImpl.java:[109] (sizes) LineLength: Zeile ist 90 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EncryptionService.java:[16,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EncryptionService.java:[18,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EncryptionService.java:[21] (sizes) LineLength: Zeile ist 96 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EncryptionService.java:[26,36] (misc) FinalParameters: Der Parameter email sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EncryptionService.java:[29] (sizes) LineLength: Zeile ist 81 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EncryptionService.java:[34] (sizes) LineLength: Zeile ist 85 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EncryptionService.java:[34,53] (coding) MagicNumber: Die magische Zahl '0xff' sollte als Konstante definiert werden.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EncryptionService.java:[34,61] (coding) MagicNumber: Die magische Zahl '0x100' sollte als Konstante definiert werden.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EncryptionService.java:[34,68] (coding) MagicNumber: Die magische Zahl '16' sollte als Konstante definiert werden.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EncryptionService.java:[44] (sizes) LineLength: Zeile ist 118 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/EncryptionService.java:[49] (sizes) LineLength: Zeile ist 82 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/InputCheckService.java:[14,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/InputCheckService.java:[15,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/InputCheckService.java:[16,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/InputCheckService.java:[24] (sizes) LineLength: Zeile ist 101 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/InputCheckService.java:[44] (sizes) LineLength: Zeile ist 124 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/InputCheckService.java:[49] (sizes) LineLength: Zeile ist 174 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/InputCheckService.java:[59] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/InputCheckService.java:[60] (sizes) LineLength: Zeile ist 93 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/InputCheckService.java:[63] (sizes) LineLength: Zeile ist 96 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/InputCheckService.java:[65] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/InputCheckService.java:[66] (sizes) LineLength: Zeile ist 93 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/InputCheckService.java:[67] (sizes) LineLength: Zeile ist 177 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/InputCheckService.java:[69] (sizes) LineLength: Zeile ist 157 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/InputCheckService.java:[71] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/InputCheckService.java:[72] (sizes) LineLength: Zeile ist 82 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/InputCheckService.java:[73] (sizes) LineLength: Zeile ist 94 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/InputCheckService.java:[77] (sizes) LineLength: Zeile ist 91 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/InputCheckService.java:[79,37] (misc) FinalParameters: Der Parameter username sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/InputCheckService.java:[87] (sizes) LineLength: Zeile ist 114 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/InputCheckService.java:[89] (sizes) LineLength: Zeile ist 91 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/InputCheckService.java:[91,34] (misc) FinalParameters: Der Parameter email sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/InputCheckService.java:[93] (sizes) LineLength: Zeile ist 81 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/InputCheckService.java:[101] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/InputCheckService.java:[102] (sizes) LineLength: Zeile ist 82 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/InputCheckService.java:[106] (sizes) LineLength: Zeile ist 104 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/InputCheckService.java:[107] (sizes) LineLength: Zeile ist 106 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/InputCheckService.java:[109] (sizes) LineLength: Zeile ist 91 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/service/InputCheckService.java:[111,37] (misc) FinalParameters: Der Parameter password sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/data_access/AuthenticationDao.java:[1] (javadoc) JavadocPackage: Es fehlt eine package-info.java.
+[ERROR] src/main/java/org/psesquared/server/authentication_api/data_access/AuthenticationDao.java:[18] (sizes) LineLength: Zeile ist 82 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/data_access/AuthenticationDao.java:[27] (sizes) LineLength: Zeile ist 81 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/data_access/AuthenticationDao.java:[40] (sizes) LineLength: Zeile ist 96 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/authentication_api/data_access/AuthenticationDao.java:[42] (sizes) LineLength: Zeile ist 97 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[1] (javadoc) JavadocPackage: Es fehlt eine package-info.java.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[7,47] (imports) AvoidStarImport: Stern-Importe der Form '.*' sollten vermieden werden - org.springframework.web.bind.annotation.*.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[12] (sizes) LineLength: Zeile ist 98 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[21,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[24] (sizes) LineLength: Zeile ist 82 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[25] (regexp) RegexpSingleline: Line has trailing spaces.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[31] (sizes) LineLength: Zeile ist 93 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[31,64] (misc) FinalParameters: Der Parameter username sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[32] (sizes) LineLength: Zeile ist 121 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[32,64] (misc) FinalParameters: Der Parameter episodeActionPosts sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[37] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[38] (sizes) LineLength: Zeile ist 113 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[39] (regexp) RegexpSingleline: Line has trailing spaces.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[40] (sizes) LineLength: Zeile ist 82 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[41] (sizes) LineLength: Zeile ist 91 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[44] (sizes) LineLength: Zeile ist 102 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[44,71] (misc) FinalParameters: Der Parameter username sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[45] (sizes) LineLength: Zeile ist 127 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[49] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[50] (sizes) LineLength: Zeile ist 112 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[51] (regexp) RegexpSingleline: Line has trailing spaces.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[52] (sizes) LineLength: Zeile ist 82 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[54] (sizes) LineLength: Zeile ist 91 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[57] (sizes) LineLength: Zeile ist 109 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[57,80] (misc) FinalParameters: Der Parameter username sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[58] (sizes) LineLength: Zeile ist 103 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[58,59] (misc) FinalParameters: Der Parameter podcastURL sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[59] (sizes) LineLength: Zeile ist 148 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[63] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[64] (sizes) LineLength: Zeile ist 116 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[65] (regexp) RegexpSingleline: Line has trailing spaces.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[66] (sizes) LineLength: Zeile ist 82 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[67] (sizes) LineLength: Zeile ist 89 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[68] (sizes) LineLength: Zeile ist 91 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[71] (sizes) LineLength: Zeile ist 105 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[71,76] (misc) FinalParameters: Der Parameter username sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[72] (sizes) LineLength: Zeile ist 95 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[72,60] (misc) FinalParameters: Der Parameter since sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[73] (sizes) LineLength: Zeile ist 139 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[77] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[78] (sizes) LineLength: Zeile ist 132 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[79] (regexp) RegexpSingleline: Line has trailing spaces.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[80] (sizes) LineLength: Zeile ist 82 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[82] (sizes) LineLength: Zeile ist 89 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[83] (sizes) LineLength: Zeile ist 91 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[86] (sizes) LineLength: Zeile ist 114 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[86,85] (misc) FinalParameters: Der Parameter username sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[87] (sizes) LineLength: Zeile ist 106 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[87,64] (misc) FinalParameters: Der Parameter podcastURL sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[88] (sizes) LineLength: Zeile ist 99 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[88,64] (misc) FinalParameters: Der Parameter since sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionController.java:[89] (sizes) LineLength: Zeile ist 160 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionGetResponse.java:[13,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionGetResponse.java:[14,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionGetResponse.java:[19,37] (misc) FinalParameters: Der Parameter actions sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionGetResponse.java:[19,61] (coding) HiddenField: Die Variable 'actions' verbirgt ein Feld.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionGetResponse.java:[24,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionGetResponse.java:[24,5] (design) DesignForExtension: Klasse 'EpisodeActionGetResponse' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'getActions' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'EpisodeActionGetResponse' final oder die Methode 'getActions' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionGetResponse.java:[28,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionGetResponse.java:[28,5] (design) DesignForExtension: Klasse 'EpisodeActionGetResponse' sieht wie zur Erweiterung entworfen aus (kann subclassed werden), aber die Methode 'getTimestamp' besitzt keinen Javadoc-Kommentar, der erklärt, wie Sie das sicher tun. Wenn die Klasse nicht für Erweiterungen ausgelegt ist, sollten sie die Klasse 'EpisodeActionGetResponse' final oder die Methode 'getTimestamp' static/final/abstract/empty machen oder die zugelassene Annotation für die Methode hinzufügen.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionPost.java:[14] (sizes) LineLength: Zeile ist 94 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionPost.java:[22,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionPost.java:[26,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionPost.java:[30,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionPost.java:[32,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionPost.java:[34,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/controller/EpisodeActionPost.java:[36,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[1] (javadoc) JavadocPackage: Es fehlt eine package-info.java.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[30,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[32,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[34,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[36,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[38,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[40,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[42,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[44] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[45] (sizes) LineLength: Zeile ist 84 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[50] (sizes) LineLength: Zeile ist 82 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[53] (sizes) LineLength: Zeile ist 96 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[53,35] (misc) FinalParameters: Der Parameter username sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[53,52] (misc) FinalParameters: Der Parameter episodeActionPosts sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[55] (sizes) LineLength: Zeile ist 106 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[59,68] (misc) FinalParameters: Der Parameter user sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[60,13] (misc) FinalParameters: Der Parameter episodeActionPosts sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[63] (sizes) LineLength: Zeile ist 90 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[68] (sizes) LineLength: Zeile ist 108 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[68,60] (misc) FinalParameters: Der Parameter user sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[68,71] (misc) FinalParameters: Der Parameter episodeActionPost sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[75] (sizes) LineLength: Zeile ist 89 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[82] (sizes) LineLength: Zeile ist 109 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[83] (sizes) LineLength: Zeile ist 81 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[87] (sizes) LineLength: Zeile ist 102 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[96] (sizes) LineLength: Zeile ist 81 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[96,44] (misc) FinalParameters: Der Parameter episodeActionPost sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[103,9] (blocks) RightCurly: '}' an Position 9 sollte in der gleichen Zeile stehen wie der nächste Teil der Multi-Block-Anweisung (eine Anweisung, die mehrere Blöcke enthält: if/else-if/else, do/while oder try/catch/finally).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[112,9] (blocks) RightCurly: '}' an Position 9 sollte in der gleichen Zeile stehen wie der nächste Teil der Multi-Block-Anweisung (eine Anweisung, die mehrere Blöcke enthält: if/else-if/else, do/while oder try/catch/finally).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[120,35] (misc) FinalParameters: Der Parameter episodeActionPost sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[125] (sizes) LineLength: Zeile ist 105 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[134] (sizes) LineLength: Zeile ist 93 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[134,46] (misc) FinalParameters: Der Parameter user sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[134,57] (misc) FinalParameters: Der Parameter episodeActions sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[140] (sizes) LineLength: Zeile ist 85 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[140,45] (misc) FinalParameters: Der Parameter user sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[140,56] (misc) FinalParameters: Der Parameter episodeAction sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[141] (sizes) LineLength: Zeile ist 106 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[149] (sizes) LineLength: Zeile ist 91 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[149,51] (misc) FinalParameters: Der Parameter user sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[149,62] (misc) FinalParameters: Der Parameter episodeAction sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[150] (sizes) LineLength: Zeile ist 96 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[153] (sizes) LineLength: Zeile ist 84 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[159] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[163] (sizes) LineLength: Zeile ist 82 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[164] (sizes) LineLength: Zeile ist 83 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[166,54] (misc) FinalParameters: Der Parameter username sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[167] (sizes) LineLength: Zeile ist 91 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[175] (sizes) LineLength: Zeile ist 84 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[177] (sizes) LineLength: Zeile ist 83 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[179] (sizes) LineLength: Zeile ist 99 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[179,63] (misc) FinalParameters: Der Parameter username sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[179,80] (misc) FinalParameters: Der Parameter podcastURL sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[180] (sizes) LineLength: Zeile ist 115 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[185] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[186] (sizes) LineLength: Zeile ist 82 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[189] (sizes) LineLength: Zeile ist 82 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[192] (sizes) LineLength: Zeile ist 83 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[194] (sizes) LineLength: Zeile ist 88 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[194,59] (misc) FinalParameters: Der Parameter username sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[194,76] (misc) FinalParameters: Der Parameter since sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[195] (sizes) LineLength: Zeile ist 114 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[196] (sizes) LineLength: Zeile ist 118 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[201] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[202] (sizes) LineLength: Zeile ist 83 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[206] (sizes) LineLength: Zeile ist 84 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[210] (sizes) LineLength: Zeile ist 83 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[212] (sizes) LineLength: Zeile ist 116 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[212,68] (misc) FinalParameters: Der Parameter username sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[212,85] (misc) FinalParameters: Der Parameter podcastURL sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[212,104] (misc) FinalParameters: Der Parameter since sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[213] (sizes) LineLength: Zeile ist 114 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[215] (sizes) LineLength: Zeile ist 114 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[220] (sizes) LineLength: Zeile ist 108 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/service/EpisodeActionService.java:[220,72] (misc) FinalParameters: Der Parameter episodeActions sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/data_access/EpisodeActionDao.java:[1] (javadoc) JavadocPackage: Es fehlt eine package-info.java.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/data_access/EpisodeActionDao.java:[16] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/data_access/EpisodeActionDao.java:[22] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/data_access/EpisodeActionDao.java:[30] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/data_access/EpisodeActionDao.java:[31] (sizes) LineLength: Zeile ist 82 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/data_access/EpisodeActionDao.java:[36] (sizes) LineLength: Zeile ist 82 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/data_access/EpisodeActionDao.java:[38] (sizes) LineLength: Zeile ist 97 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/data_access/EpisodeActionDao.java:[40] (sizes) LineLength: Zeile ist 84 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/data_access/EpisodeActionDao.java:[40,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/data_access/EpisodeActionDao.java:[42] (sizes) LineLength: Zeile ist 85 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/data_access/EpisodeActionDao.java:[42,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/data_access/EpisodeActionDao.java:[44] (sizes) LineLength: Zeile ist 99 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/data_access/EpisodeActionDao.java:[44,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/data_access/EpisodeActionDao.java:[46] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/data_access/EpisodeActionDao.java:[50] (sizes) LineLength: Zeile ist 84 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/data_access/EpisodeActionDao.java:[54] (sizes) LineLength: Zeile ist 113 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/data_access/EpisodeActionDao.java:[56] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/data_access/EpisodeActionDao.java:[57] (sizes) LineLength: Zeile ist 83 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/data_access/EpisodeActionDao.java:[60] (sizes) LineLength: Zeile ist 84 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/data_access/EpisodeActionDao.java:[64] (sizes) LineLength: Zeile ist 82 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/data_access/EpisodeActionDao.java:[67] (sizes) LineLength: Zeile ist 112 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/data_access/EpisodeActionDao.java:[72,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/data_access/EpisodeDao.java:[9] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/data_access/EpisodeDao.java:[15] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/data_access/EpisodeDao.java:[23] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/data_access/EpisodeDao.java:[31] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/episode_actions_api/data_access/EpisodeDao.java:[39] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionTitles.java:[1] (javadoc) JavadocPackage: Es fehlt eine package-info.java.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionTitles.java:[9] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionTitles.java:[12] (sizes) LineLength: Zeile ist 110 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionTitles.java:[12,1] (javadoc) JavadocType: Im Javadoc des Typs fehlt das Tag @param episodes.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionTitles.java:[12,1] (javadoc) JavadocType: Im Javadoc des Typs fehlt das Tag @param subscription.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[7,47] (imports) AvoidStarImport: Stern-Importe der Form '.*' sollten vermieden werden - org.springframework.web.bind.annotation.*.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[12] (sizes) LineLength: Zeile ist 96 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[13] (sizes) LineLength: Zeile ist 97 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[20,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[22,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[25] (sizes) LineLength: Zeile ist 81 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[27] (regexp) RegexpSingleline: Line has trailing spaces.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[29] (sizes) LineLength: Zeile ist 127 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[30] (sizes) LineLength: Zeile ist 111 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[34] (sizes) LineLength: Zeile ist 84 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[34,55] (misc) FinalParameters: Der Parameter username sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[35,48] (misc) FinalParameters: Der Parameter deviceID sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[36] (sizes) LineLength: Zeile ist 89 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[36,48] (misc) FinalParameters: Der Parameter subscriptions sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[43] (regexp) RegexpSingleline: Line has trailing spaces.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[44] (sizes) LineLength: Zeile ist 88 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[45] (sizes) LineLength: Zeile ist 113 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[47] (sizes) LineLength: Zeile ist 102 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[48] (sizes) LineLength: Zeile ist 88 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[50] (sizes) LineLength: Zeile ist 103 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[51] (sizes) LineLength: Zeile ist 87 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[51,58] (misc) FinalParameters: Der Parameter username sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[52] (sizes) LineLength: Zeile ist 98 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[52,51] (misc) FinalParameters: Der Parameter deviceID sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[53] (sizes) LineLength: Zeile ist 122 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[53,51] (misc) FinalParameters: Der Parameter functionJSONP sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[54] (sizes) LineLength: Zeile ist 84 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[59] (sizes) LineLength: Zeile ist 128 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[61] (regexp) RegexpSingleline: Line has trailing spaces.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[62] (sizes) LineLength: Zeile ist 92 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[63] (sizes) LineLength: Zeile ist 121 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[64] (sizes) LineLength: Zeile ist 92 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[65] (regexp) RegexpSingleline: Line has trailing spaces.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[65] (sizes) LineLength: Zeile ist 100 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[68] (sizes) LineLength: Zeile ist 98 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[68,69] (misc) FinalParameters: Der Parameter username sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[69] (sizes) LineLength: Zeile ist 98 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[69,69] (misc) FinalParameters: Der Parameter deviceID sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[70] (sizes) LineLength: Zeile ist 107 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[70,69] (misc) FinalParameters: Der Parameter delta sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[76] (sizes) LineLength: Zeile ist 94 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[77] (regexp) RegexpSingleline: Line has trailing spaces.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[78] (sizes) LineLength: Zeile ist 92 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[79] (sizes) LineLength: Zeile ist 120 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[80] (sizes) LineLength: Zeile ist 81 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[81] (sizes) LineLength: Zeile ist 105 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[84] (sizes) LineLength: Zeile ist 96 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[84,67] (misc) FinalParameters: Der Parameter username sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[85] (sizes) LineLength: Zeile ist 96 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[85,67] (misc) FinalParameters: Der Parameter deviceID sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[86] (sizes) LineLength: Zeile ist 102 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[86,67] (misc) FinalParameters: Der Parameter since sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[87] (sizes) LineLength: Zeile ist 92 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[93] (sizes) LineLength: Zeile ist 97 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[94] (regexp) RegexpSingleline: Line has trailing spaces.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[95] (sizes) LineLength: Zeile ist 82 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[96] (sizes) LineLength: Zeile ist 100 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[99] (sizes) LineLength: Zeile ist 94 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[99,63] (misc) FinalParameters: Der Parameter username sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionController.java:[100] (sizes) LineLength: Zeile ist 88 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionDelta.java:[10] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionDelta.java:[11] (sizes) LineLength: Zeile ist 114 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionDelta.java:[16,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionDelta.java:[20,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionDelta.java:[24,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionDelta.java:[28] (sizes) LineLength: Zeile ist 84 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionDelta.java:[29] (sizes) LineLength: Zeile ist 89 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionDelta.java:[31,30] (misc) FinalParameters: Der Parameter add sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionDelta.java:[31,43] (coding) HiddenField: Die Variable 'add' verbirgt ein Feld.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionDelta.java:[31,48] (misc) FinalParameters: Der Parameter remove sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionDelta.java:[31,61] (coding) HiddenField: Die Variable 'remove' verbirgt ein Feld.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionDelta.java:[37] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionDelta.java:[39] (regexp) RegexpSingleline: Line has trailing spaces.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionDelta.java:[46] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionDelta.java:[48] (regexp) RegexpSingleline: Line has trailing spaces.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionDelta.java:[55] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/controller/SubscriptionDelta.java:[57] (regexp) RegexpSingleline: Line has trailing spaces.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[1] (javadoc) JavadocPackage: Es fehlt eine package-info.java.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[12,35] (imports) AvoidStarImport: Stern-Importe der Form '.*' sollten vermieden werden - org.psesquared.server.model.*.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[28,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[29,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[31,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[33,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[35,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[37,5] (javadoc) JavadocVariable: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[47] (regexp) RegexpSingleline: Line has trailing spaces.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[49] (sizes) LineLength: Zeile ist 84 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[52] (sizes) LineLength: Zeile ist 87 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[52,36] (misc) FinalParameters: Der Parameter username sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[52,53] (misc) FinalParameters: Der Parameter subscriptionStrings sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[60] (sizes) LineLength: Zeile ist 85 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[65] (sizes) LineLength: Zeile ist 118 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[67] (sizes) LineLength: Zeile ist 84 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[70] (sizes) LineLength: Zeile ist 98 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[71] (sizes) LineLength: Zeile ist 85 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[76] (sizes) LineLength: Zeile ist 102 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[80] (sizes) LineLength: Zeile ist 99 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[89] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[90] (sizes) LineLength: Zeile ist 82 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[92] (regexp) RegexpSingleline: Line has trailing spaces.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[97,42] (misc) FinalParameters: Der Parameter username sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[98] (sizes) LineLength: Zeile ist 118 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[106] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[108] (regexp) RegexpSingleline: Line has trailing spaces.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[109] (sizes) LineLength: Zeile ist 84 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[110] (sizes) LineLength: Zeile ist 82 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[114] (sizes) LineLength: Zeile ist 81 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[114,39] (misc) FinalParameters: Der Parameter username sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[114,56] (misc) FinalParameters: Der Parameter delta sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[121,56] (whitespace) OperatorWrap: '&&' sollte in einer neuen Zeile stehen.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[122] (sizes) LineLength: Zeile ist 112 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[125] (sizes) LineLength: Zeile ist 93 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[132] (sizes) LineLength: Zeile ist 100 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[139] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[142] (regexp) RegexpSingleline: Line has trailing spaces.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[143] (sizes) LineLength: Zeile ist 84 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[145] (sizes) LineLength: Zeile ist 82 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[147] (sizes) LineLength: Zeile ist 82 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[149,51] (misc) FinalParameters: Der Parameter username sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[149,68] (misc) FinalParameters: Der Parameter since sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[154] (sizes) LineLength: Zeile ist 81 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[167] (sizes) LineLength: Zeile ist 82 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[169] (regexp) RegexpSingleline: Line has trailing spaces.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[172] (sizes) LineLength: Zeile ist 82 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[175,47] (misc) FinalParameters: Der Parameter username sollte als 'final' deklariert sein.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[176] (sizes) LineLength: Zeile ist 118 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/service/SubscriptionService.java:[189] (sizes) LineLength: Zeile ist 109 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/data_access/SubscriptionActionDao.java:[1] (javadoc) JavadocPackage: Es fehlt eine package-info.java.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/data_access/SubscriptionActionDao.java:[12] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/data_access/SubscriptionActionDao.java:[16] (sizes) LineLength: Zeile ist 88 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/data_access/SubscriptionActionDao.java:[34] (sizes) LineLength: Zeile ist 83 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/data_access/SubscriptionActionDao.java:[37] (sizes) LineLength: Zeile ist 97 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/data_access/SubscriptionActionDao.java:[45] (sizes) LineLength: Zeile ist 84 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/data_access/SubscriptionActionDao.java:[49] (sizes) LineLength: Zeile ist 109 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/data_access/SubscriptionActionDao.java:[54] (sizes) LineLength: Zeile ist 81 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/data_access/SubscriptionActionDao.java:[60] (sizes) LineLength: Zeile ist 83 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/data_access/SubscriptionActionDao.java:[63] (sizes) LineLength: Zeile ist 82 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/data_access/SubscriptionActionDao.java:[64] (sizes) LineLength: Zeile ist 82 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/data_access/SubscriptionActionDao.java:[68] (sizes) LineLength: Zeile ist 104 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/data_access/SubscriptionActionDao.java:[70] (regexp) RegexpSingleline: Line has trailing spaces.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/data_access/SubscriptionDao.java:[10] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/data_access/SubscriptionDao.java:[16,5] (javadoc) MissingJavadocMethod: Es fehlt ein Javadoc-Kommentar.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/data_access/SubscriptionDao.java:[17,5] (javadoc) InvalidJavadocPosition: Javadoc-Kommentar ist an der falschen Stelle platziert.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/data_access/SubscriptionDao.java:[25] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/subscriptions_api/data_access/SubscriptionDao.java:[26] (sizes) LineLength: Zeile ist 81 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/ServerApplication.java:[1] (javadoc) JavadocPackage: Es fehlt eine package-info.java.
+[ERROR] src/main/java/org/psesquared/server/ServerApplication.java:[9] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/ServerApplication.java:[12,1] (design) HideUtilityClassConstructor: Hilfsklassen sollten keinen Standard-Konstruktur und keinen als public deklarierten Konstruktor haben.
+[ERROR] src/main/java/org/psesquared/server/ServerApplication.java:[13] (sizes) LineLength: Zeile ist 95 Zeichen lang (Obergrenze ist 80).
+[ERROR] src/main/java/org/psesquared/server/ServerApplication.java:[16] (javadoc) JavadocStyle: Der erste Satz sollte mit einem Punkt enden.
+[ERROR] src/main/java/org/psesquared/server/ServerApplication.java:[16,1] (whitespace) FileTabCharacter: Die Datei enthält Tabulatorzeichen (dies ist das erste Vorkommen).
+[ERROR] src/main/java/org/psesquared/server/ServerApplication.java:[18] (regexp) RegexpSingleline: Line has trailing spaces.
+[ERROR] src/main/java/org/psesquared/server/ServerApplication.java:[21,33] (misc) FinalParameters: Der Parameter args sollte als 'final' deklariert sein.
+[ERROR] src/main/resources/security.properties:[1] (misc) NewlineAtEndOfFile: Datei endet nicht mit einem Zeilenumbruch.
+[INFO] ------------------------------------------------------------------------
+[INFO] BUILD FAILURE
+[INFO] ------------------------------------------------------------------------
+[INFO] Total time: 13.946 s
+[INFO] Finished at: 2023-03-18T08:10:57+01:00
+[INFO] ------------------------------------------------------------------------
+[ERROR] Failed to execute goal org.apache.maven.plugins:maven-checkstyle-plugin:3.2.1:check (default-cli) on project server: You have 799 Checkstyle violations. -> [Help 1]
+[ERROR]
+[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
+[ERROR] Re-run Maven using the -X switch to enable full debug logging.
+[ERROR]
+[ERROR] For more information about the errors and possible solutions, please read the following articles:
+[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException
diff --git a/31-qualitaetsheft-kolloquium/assets/sources/linter-dashboard-after-processed.txt b/31-qualitaetsheft-kolloquium/assets/sources/linter-dashboard-after-processed.txt
new file mode 100644
index 0000000..cab82f3
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/assets/sources/linter-dashboard-after-processed.txt
@@ -0,0 +1 @@
+1 warning vue/no-v-html
diff --git a/31-qualitaetsheft-kolloquium/assets/sources/linter-dashboard-after.txt b/31-qualitaetsheft-kolloquium/assets/sources/linter-dashboard-after.txt
new file mode 100644
index 0000000..f9bda3b
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/assets/sources/linter-dashboard-after.txt
@@ -0,0 +1,10 @@
+
+> pse-dashboard@0.0.0 lint
+> eslint 'src/**/*.{js,vue}'
+
+
+/home/gero/documents/uni/pse/pse-dashboard/src/components/HelpModal.vue
+ 25:21 warning 'v-html' directive can lead to XSS attack vue/no-v-html
+
+✖ 1 problem (0 errors, 1 warning)
+
diff --git a/31-qualitaetsheft-kolloquium/assets/sources/linter-dashboard-before-processed.txt b/31-qualitaetsheft-kolloquium/assets/sources/linter-dashboard-before-processed.txt
new file mode 100644
index 0000000..150ea46
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/assets/sources/linter-dashboard-before-processed.txt
@@ -0,0 +1,22 @@
+26 error vue/html-indent
+17 error vue/script-indent
+6 error vue/require-v-for-key
+5 error vue/multi-word-component-names
+1 error vue/valid-v-for
+1 error vue/valid-template-root
+125 warning vue/max-attributes-per-line
+34 warning vue/attributes-order
+26 warning vue/singleline-html-element-content-newline
+12 warning vue/require-default-prop
+12 warning vue/html-self-closing
+11 warning vue/first-attribute-linebreak
+10 warning vue/html-closing-bracket-newline
+8 warning vue/multiline-html-element-content-newline
+5 warning vue/html-closing-bracket-spacing
+3 warning vue/require-prop-types
+3 warning vue/attribute-hyphenation
+2 warning vue/html-self-closing
+1 warning vue/v-on-event-hyphenation
+1 warning vue/no-v-html
+1 warning vue/mustache-interpolation-spacing
+
diff --git a/31-qualitaetsheft-kolloquium/assets/sources/linter-dashboard-before.txt b/31-qualitaetsheft-kolloquium/assets/sources/linter-dashboard-before.txt
new file mode 100644
index 0000000..04a8317
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/assets/sources/linter-dashboard-before.txt
@@ -0,0 +1,358 @@
+
+> pse-dashboard@0.0.0 lint
+> eslint 'src/**/*.{js,vue}'
+
+
+/home/gero/documents/uni/pse/pse-dashboard/src/components/Episode.vue
+ 1:1 error Component name "Episode" should always be multi-word vue/multi-word-component-names
+ 5:5 warning Prop 'action' requires default value to be set vue/require-default-prop
+ 5:5 warning Prop "action" should define at least its type vue/require-prop-types
+ 20:17 warning 'class' should be on a new line vue/max-attributes-per-line
+ 20:69 warning 'aria-current' should be on a new line vue/max-attributes-per-line
+ 23:67 warning 'style' should be on a new line vue/max-attributes-per-line
+ 38:51 warning 'style' should be on a new line vue/max-attributes-per-line
+ 39:17 warning Require self-closing on HTML elements (<div>) vue/html-self-closing
+ 39:43 warning ':style' should be on a new line vue/max-attributes-per-line
+
+/home/gero/documents/uni/pse/pse-dashboard/src/components/ErrorLog.vue
+ 14:1 error Expected indentation of 8 spaces but found 4 spaces vue/html-indent
+ 15:1 error Expected indentation of 12 spaces but found 8 spaces vue/html-indent
+ 15:9 error Elements in iteration expect to have 'v-bind:key' directives vue/require-v-for-key
+ 15:14 warning Expected a linebreak before this attribute vue/first-attribute-linebreak
+ 15:43 warning 'class' should be on a new line vue/max-attributes-per-line
+ 16:29 warning ':class' should be on a new line vue/max-attributes-per-line
+ 16:58 warning Expected 1 line break before closing bracket, but no line breaks found vue/html-closing-bracket-newline
+ 17:1 error Expected indentation of 16 spaces but found 12 spaces vue/html-indent
+ 17:13 warning Require self-closing on HTML elements (<button>) vue/html-self-closing
+ 17:35 warning 'class' should be on a new line vue/max-attributes-per-line
+ 17:53 warning '@click' should be on a new line vue/max-attributes-per-line
+ 18:1 error Expected indentation of 16 spaces but found 12 spaces vue/html-indent
+ 18:13 warning Require self-closing on HTML elements (<i>) vue/html-self-closing
+ 18:37 warning ':class' should be on a new line vue/max-attributes-per-line
+ 19:1 error Expected indentation of 12 spaces but found 8 spaces vue/html-indent
+ 20:1 error Expected indentation of 8 spaces but found 4 spaces vue/html-indent
+
+/home/gero/documents/uni/pse/pse-dashboard/src/components/FloatingLabelInput.vue
+ 7:5 warning Prop 'label' requires default value to be set vue/require-default-prop
+ 8:5 warning Prop 'modelValue' requires default value to be set vue/require-default-prop
+ 15:16 warning Expected a linebreak before this attribute vue/first-attribute-linebreak
+ 15:29 warning 'class' should be on a new line vue/max-attributes-per-line
+ 15:50 warning Attribute ":id" should go before "class" vue/attributes-order
+ 15:50 warning ':id' should be on a new line vue/max-attributes-per-line
+ 15:62 warning ':value' should be on a new line vue/max-attributes-per-line
+ 16:1 error Expected indentation of 15 spaces but found 12 spaces vue/html-indent
+ 17:1 error Expected indentation of 15 spaces but found 12 spaces vue/html-indent
+ 17:13 warning Attribute ":placeholder" should go before "@input" vue/attributes-order
+ 17:34 warning Attribute "required" should go before "@input" vue/attributes-order
+ 17:34 warning 'required' should be on a new line vue/max-attributes-per-line
+ 17:42 warning Expected 1 line break before closing bracket, but no line breaks found vue/html-closing-bracket-newline
+
+/home/gero/documents/uni/pse/pse-dashboard/src/components/FormLayout.vue
+ 9:35 warning 'src' should be on a new line vue/max-attributes-per-line
+ 9:60 warning 'alt' should be on a new line vue/max-attributes-per-line
+ 9:67 warning 'width' should be on a new line vue/max-attributes-per-line
+ 9:79 warning 'height' should be on a new line vue/max-attributes-per-line
+
+/home/gero/documents/uni/pse/pse-dashboard/src/components/Help.vue
+ 1:1 error Component name "Help" should always be multi-word vue/multi-word-component-names
+ 4:29 warning Attribute "id" should go before "class" vue/attributes-order
+ 4:29 warning 'id' should be on a new line vue/max-attributes-per-line
+ 9:45 warning Expected 1 line break after opening tag (`<h5>`), but no line breaks found vue/singleline-html-element-content-newline
+ 9:69 warning Expected 1 line break before closing tag (`</h5>`), but no line breaks found vue/singleline-html-element-content-newline
+ 10:21 warning Require self-closing on HTML elements (<button>) vue/html-self-closing
+ 10:43 warning 'class' should be on a new line vue/max-attributes-per-line
+ 10:61 warning 'data-bs-dismiss' should be on a new line vue/max-attributes-per-line
+ 14:41 warning 'v-html' should be on a new line vue/max-attributes-per-line
+ 14:41 warning 'v-html' directive can lead to XSS attack vue/no-v-html
+ 18:43 warning 'class' should be on a new line vue/max-attributes-per-line
+ 18:69 warning 'data-bs-dismiss' should be on a new line vue/max-attributes-per-line
+ 18:93 warning Expected 1 line break after opening tag (`<button>`), but no line breaks found vue/singleline-html-element-content-newline
+ 18:118 warning Expected 1 line break before closing tag (`</button>`), but no line breaks found vue/singleline-html-element-content-newline
+
+/home/gero/documents/uni/pse/pse-dashboard/src/components/LastUpdate.vue
+ 12:5 warning Prop 'iso' requires default value to be set vue/require-default-prop
+ 13:5 warning Prop 'unix' requires default value to be set vue/require-default-prop
+ 36:1 error Expected indentation of 4 spaces but found 0 spaces vue/html-indent
+
+/home/gero/documents/uni/pse/pse-dashboard/src/components/Loading.vue
+ 1:1 error Component name "Loading" should always be multi-word vue/multi-word-component-names
+ 9:30 warning Attribute "v-else" should go before "class" vue/attributes-order
+ 9:30 warning 'v-else' should be on a new line vue/max-attributes-per-line
+
+/home/gero/documents/uni/pse/pse-dashboard/src/components/LogEntry.vue
+ 3:1 error The template requires child element vue/valid-template-root
+ 3:1 warning Require self-closing on HTML elements (<template>) vue/html-self-closing
+
+/home/gero/documents/uni/pse/pse-dashboard/src/components/Navbar.vue
+ 1:1 error Component name "Navbar" should always be multi-word vue/multi-word-component-names
+ 6:32 warning Expected 1 line break after opening tag (`<div>`), but 2 line breaks found vue/multiline-html-element-content-newline
+ 9:47 warning 'to' should be on a new line vue/max-attributes-per-line
+ 10:1 error Expected indentation of 16 spaces but found 20 spaces vue/html-indent
+ 10:50 warning 'alt' should be on a new line vue/max-attributes-per-line
+ 10:57 warning 'width' should be on a new line vue/max-attributes-per-line
+ 10:69 warning 'height' should be on a new line vue/max-attributes-per-line
+ 14:44 warning 'type' should be on a new line vue/max-attributes-per-line
+ 14:58 warning 'data-bs-toggle' should be on a new line vue/max-attributes-per-line
+ 14:84 warning 'data-bs-target' should be on a new line vue/max-attributes-per-line
+ 15:17 warning Require self-closing on HTML elements (<span>) vue/html-self-closing
+ 17:51 warning Attribute "id" should go before "class" vue/attributes-order
+ 17:51 warning 'id' should be on a new line vue/max-attributes-per-line
+ 17:65 warning Expected 1 line break after opening tag (`<div>`), but 2 line breaks found vue/multiline-html-element-content-newline
+ 21:49 warning 'class' should be on a new line vue/max-attributes-per-line
+ 23:62 warning 'class' should be on a new line vue/max-attributes-per-line
+ 28:57 warning 'class' should be on a new line vue/max-attributes-per-line
+ 40:61 warning 'href' should be on a new line vue/max-attributes-per-line
+ 40:70 warning 'role' should be on a new line vue/max-attributes-per-line
+ 40:84 warning 'data-bs-toggle' should be on a new line vue/max-attributes-per-line
+ 41:29 warning Require self-closing on HTML elements (<i>) vue/html-self-closing
+ 44:29 error Elements in iteration expect to have 'v-bind:key' directives vue/require-v-for-key
+ 45:58 warning ':class' should be on a new line vue/max-attributes-per-line
+ 45:100 warning '@click' should be on a new line vue/max-attributes-per-line
+ 51:24 warning Expected a linebreak before this attribute vue/first-attribute-linebreak
+ 51:33 warning 'class' should be on a new line vue/max-attributes-per-line
+ 52:1 error Expected indentation of 23 spaces but found 24 spaces vue/html-indent
+ 52:48 warning 'data-bs-target' should be on a new line vue/max-attributes-per-line
+ 52:70 warning Expected 1 line break before closing bracket, but no line breaks found vue/html-closing-bracket-newline
+ 55:50 warning 'class' should be on a new line vue/max-attributes-per-line
+ 56:37 warning 'class' should be on a new line vue/max-attributes-per-line
+ 56:70 warning 'role' should be on a new line vue/max-attributes-per-line
+ 56:84 warning 'data-bs-toggle' should be on a new line vue/max-attributes-per-line
+ 57:64 warning Require self-closing on HTML elements (<i>) vue/html-self-closing
+ 60:61 warning 'class' should be on a new line vue/max-attributes-per-line
+ 60:83 warning Expected 1 line break after opening tag (`<router-link>`), but no line breaks found vue/singleline-html-element-content-newline
+ 60:111 warning Expected 1 line break before closing tag (`</router-link>`), but no line breaks found vue/singleline-html-element-content-newline
+ 62:58 warning '@click' should be on a new line vue/max-attributes-per-line
+ 62:82 warning Attribute "class" should go before "@click" vue/attributes-order
+ 62:82 warning 'class' should be on a new line vue/max-attributes-per-line
+ 62:104 warning Expected 1 line break after opening tag (`<router-link>`), but no line breaks found vue/singleline-html-element-content-newline
+ 62:130 warning Expected 1 line break before closing tag (`</router-link>`), but no line breaks found vue/singleline-html-element-content-newline
+
+/home/gero/documents/uni/pse/pse-dashboard/src/components/PasswordInput.vue
+ 6:5 warning Prop 'modelValue' requires default value to be set vue/require-default-prop
+ 7:5 warning Prop 'label' requires default value to be set vue/require-default-prop
+ 14:29 warning Expected a linebreak before this attribute vue/first-attribute-linebreak
+ 15:1 error Expected indentation of 28 spaces but found 8 spaces vue/html-indent
+ 15:24 warning ':modelValue' should be on a new line vue/max-attributes-per-line
+ 15:24 warning Attribute ':modelValue' must be hyphenated vue/attribute-hyphenation
+ 15:49 warning '@update:modelValue' should be on a new line vue/max-attributes-per-line
+ 15:49 warning v-on event '@update:modelValue' must be hyphenated vue/v-on-event-hyphenation
+ 16:1 error Expected indentation of 32 spaces but found 8 spaces vue/html-indent
+ 16:46 warning Expected 1 line break before closing bracket, but no line breaks found vue/html-closing-bracket-newline
+ 19:13 warning Disallow self-closing on HTML void elements (<input/>) vue/html-self-closing
+ 19:36 warning 'class' should be on a new line vue/max-attributes-per-line
+ 19:54 warning 'autocomplete' should be on a new line vue/max-attributes-per-line
+ 19:73 warning Attribute "v-model" should go before "autocomplete" vue/attributes-order
+ 19:73 warning 'v-model' should be on a new line vue/max-attributes-per-line
+ 19:100 warning Expected a space before '/>', but not found vue/html-closing-bracket-spacing
+ 20:27 warning ':class' should be on a new line vue/max-attributes-per-line
+
+/home/gero/documents/uni/pse/pse-dashboard/src/components/PasswordValidator.vue
+ 6:14 warning Prop "modelValue" should define at least its type vue/require-prop-types
+ 16:1 error Expected indentation of 4 spaces but found 8 spaces vue/script-indent
+ 17:1 error Expected indentation of 0 spaces but found 8 spaces vue/script-indent
+ 21:1 error Expected indentation of 4 spaces but found 8 spaces vue/script-indent
+ 22:1 error Expected indentation of 0 spaces but found 8 spaces vue/script-indent
+ 26:1 error Expected indentation of 4 spaces but found 8 spaces vue/script-indent
+ 27:1 error Expected indentation of 4 spaces but found 8 spaces vue/script-indent
+ 32:1 error Expected indentation of 4 spaces but found 8 spaces vue/script-indent
+ 33:1 error Expected indentation of 4 spaces but found 8 spaces vue/script-indent
+ 34:1 error Expected indentation of 0 spaces but found 8 spaces vue/script-indent
+ 38:1 error Expected indentation of 4 spaces but found 8 spaces vue/script-indent
+ 39:1 error Expected indentation of 4 spaces but found 8 spaces vue/script-indent
+ 40:1 error Expected indentation of 0 spaces but found 8 spaces vue/script-indent
+ 44:1 error Expected indentation of 4 spaces but found 8 spaces vue/script-indent
+ 45:1 error Expected indentation of 4 spaces but found 8 spaces vue/script-indent
+ 46:1 error Expected indentation of 4 spaces but found 8 spaces vue/script-indent
+ 47:1 error Expected indentation of 4 spaces but found 8 spaces vue/script-indent
+ 48:1 error Expected indentation of 4 spaces but found 8 spaces vue/script-indent
+ 72:49 warning Attribute "v-model" should go before ":label" vue/attributes-order
+ 72:49 warning 'v-model' should be on a new line vue/max-attributes-per-line
+ 75:58 warning Attribute "v-model" should go before ":label" vue/attributes-order
+ 75:58 warning 'v-model' should be on a new line vue/max-attributes-per-line
+ 81:9 error Elements in iteration expect to have 'v-bind:key' directives vue/require-v-for-key
+ 81:50 warning 'class' should be on a new line vue/max-attributes-per-line
+ 82:1 error Expected indentation of 12 spaces but found 11 spaces vue/html-indent
+
+/home/gero/documents/uni/pse/pse-dashboard/src/components/ProgressTime.vue
+ 8:5 warning Prop 'unix' requires default value to be set vue/require-default-prop
+ 16:1 error Expected indentation of 4 spaces but found 0 spaces vue/html-indent
+
+/home/gero/documents/uni/pse/pse-dashboard/src/components/Subscription.vue
+ 1:1 error Component name "Subscription" should always be multi-word vue/multi-word-component-names
+ 6:5 warning Prop 'sub' requires default value to be set vue/require-default-prop
+ 6:5 warning Prop "sub" should define at least its type vue/require-prop-types
+ 58:14 warning Expected a linebreak before this attribute vue/first-attribute-linebreak
+ 58:52 warning 'data-bs-toggle' should be on a new line vue/max-attributes-per-line
+ 59:1 error Expected indentation of 13 spaces but found 8 spaces vue/html-indent
+ 59:39 warning Expected 1 line break before closing bracket, but no line breaks found vue/html-closing-bracket-newline
+ 61:13 warning Require self-closing on HTML elements (<i>) vue/html-self-closing
+ 61:67 warning 'style' should be on a new line vue/max-attributes-per-line
+ 63:69 warning Expected 1 line break after opening tag (`<div>`), but 2 line breaks found vue/multiline-html-element-content-newline
+ 67:38 warning Expected 1 line break after opening tag (`<h6>`), but no line breaks found vue/singleline-html-element-content-newline
+ 67:64 warning Expected 1 line break before closing tag (`</h6>`), but no line breaks found vue/singleline-html-element-content-newline
+ 77:29 warning Expected a linebreak before this attribute vue/first-attribute-linebreak
+ 78:1 error Expected indentation of 28 spaces but found 20 spaces vue/html-indent
+ 78:44 warning 'data-bs-target' should be on a new line vue/max-attributes-per-line
+ 79:1 error Expected indentation of 28 spaces but found 20 spaces vue/html-indent
+ 85:60 warning '@click' should be on a new line vue/max-attributes-per-line
+ 93:32 warning 'class' should be on a new line vue/max-attributes-per-line
+ 93:49 warning 'data-bs-parent' should be on a new line vue/max-attributes-per-line
+ 96:21 error Elements in iteration expect to have 'v-bind:key' directives vue/require-v-for-key
+
+/home/gero/documents/uni/pse/pse-dashboard/src/views/EpisodesView.vue
+ 22:29 warning Expected 1 line break after opening tag (`<h1>`), but no line breaks found vue/singleline-html-element-content-newline
+ 22:74 warning Expected 1 line break before closing tag (`</h1>`), but no line breaks found vue/singleline-html-element-content-newline
+ 24:18 warning Attribute ':waitingFor' must be hyphenated vue/attribute-hyphenation
+ 26:17 error Custom elements in iteration require 'v-bind:key' directives vue/valid-v-for
+ 26:61 warning ':action' should be on a new line vue/max-attributes-per-line
+
+/home/gero/documents/uni/pse/pse-dashboard/src/views/ForgotPasswordView.vue
+ 21:39 warning Expected 1 line break after opening tag (`<h1>`), but no line breaks found vue/singleline-html-element-content-newline
+ 21:78 warning Expected 1 line break before closing tag (`</h1>`), but no line breaks found vue/singleline-html-element-content-newline
+ 25:46 warning Attribute "v-model" should go before "type" vue/attributes-order
+ 25:46 warning 'v-model' should be on a new line vue/max-attributes-per-line
+ 25:62 warning ':label' should be on a new line vue/max-attributes-per-line
+ 28:35 warning 'class' should be on a new line vue/max-attributes-per-line
+
+/home/gero/documents/uni/pse/pse-dashboard/src/views/LoginView.vue
+ 26:39 warning Expected 1 line break after opening tag (`<h1>`), but no line breaks found vue/singleline-html-element-content-newline
+ 26:71 warning Expected 1 line break before closing tag (`</h1>`), but no line breaks found vue/singleline-html-element-content-newline
+ 28:39 warning Expected 1 line break after opening tag (`<form>`), but 2 line breaks found vue/multiline-html-element-content-newline
+ 31:62 warning Attribute "v-model" should go before ":label" vue/attributes-order
+ 31:62 warning 'v-model' should be on a new line vue/max-attributes-per-line
+ 34:57 warning Attribute "v-model" should go before ":label" vue/attributes-order
+ 34:57 warning 'v-model' should be on a new line vue/max-attributes-per-line
+ 41:52 warning 'value' should be on a new line vue/max-attributes-per-line
+ 41:72 warning Attribute "v-model" should go before "value" vue/attributes-order
+ 41:72 warning 'v-model' should be on a new line vue/max-attributes-per-line
+ 56:35 warning 'class' should be on a new line vue/max-attributes-per-line
+ 66:17 warning Expected 1 line break before closing tag (`</form>`), but 2 line breaks found vue/multiline-html-element-content-newline
+ 71:41 warning Expected 1 line break after opening tag (`<p>`), but no line breaks found vue/singleline-html-element-content-newline
+ 71:52 warning Expected 1 line break before closing tag (`</p>`), but no line breaks found vue/singleline-html-element-content-newline
+
+/home/gero/documents/uni/pse/pse-dashboard/src/views/RegistrationView.vue
+ 38:39 warning Expected 1 line break after opening tag (`<h1>`), but no line breaks found vue/singleline-html-element-content-newline
+ 38:71 warning Expected 1 line break before closing tag (`</h1>`), but no line breaks found vue/singleline-html-element-content-newline
+ 42:52 warning 'type' should be on a new line vue/max-attributes-per-line
+ 42:64 warning ':label' should be on a new line vue/max-attributes-per-line
+ 45:49 warning 'type' should be on a new line vue/max-attributes-per-line
+ 45:62 warning ':label' should be on a new line vue/max-attributes-per-line
+ 51:35 warning 'class' should be on a new line vue/max-attributes-per-line
+
+/home/gero/documents/uni/pse/pse-dashboard/src/views/ResetPasswordView.vue
+ 9:5 warning Prop 'token' requires default value to be set vue/require-default-prop
+ 10:5 warning Prop 'username' requires default value to be set vue/require-default-prop
+ 41:43 warning Expected 1 line break after opening tag (`<h1>`), but no line breaks found vue/singleline-html-element-content-newline
+ 41:77 warning Expected 1 line break before closing tag (`</h1>`), but no line breaks found vue/singleline-html-element-content-newline
+ 47:35 warning 'class' should be on a new line vue/max-attributes-per-line
+
+/home/gero/documents/uni/pse/pse-dashboard/src/views/SettingsView.vue
+ 176:29 warning Expected 1 line break after opening tag (`<h1>`), but no line breaks found vue/singleline-html-element-content-newline
+ 176:57 warning Expected 1 line break before closing tag (`</h1>`), but no line breaks found vue/singleline-html-element-content-newline
+ 179:52 warning Attribute "class" should go before "@submit.prevent" vue/attributes-order
+ 179:52 warning 'class' should be on a new line vue/max-attributes-per-line
+ 182:63 warning Attribute "v-model" should go before ":label" vue/attributes-order
+ 182:63 warning 'v-model' should be on a new line vue/max-attributes-per-line
+ 182:90 warning Expected a space before '/>', but not found vue/html-closing-bracket-spacing
+ 187:35 warning 'class' should be on a new line vue/max-attributes-per-line
+ 193:51 warning Attribute "class" should go before "@submit.prevent" vue/attributes-order
+ 193:51 warning 'class' should be on a new line vue/max-attributes-per-line
+ 196:1 error Expected indentation of 12 spaces but found 17 spaces vue/html-indent
+ 197:33 warning Expected a linebreak before this attribute vue/first-attribute-linebreak
+ 198:1 error Expected indentation of 32 spaces but found 16 spaces vue/html-indent
+ 198:17 warning Attribute "v-model" should go before ":label" vue/attributes-order
+ 198:42 warning Expected 1 line break before closing bracket, but no line breaks found vue/html-closing-bracket-newline
+ 198:42 warning Expected a space before '/>', but not found vue/html-closing-bracket-spacing
+ 200:1 error Expected indentation of 12 spaces but found 17 spaces vue/html-indent
+ 201:33 warning Expected a linebreak before this attribute vue/first-attribute-linebreak
+ 202:1 error Expected indentation of 32 spaces but found 16 spaces vue/html-indent
+ 202:17 warning Attribute "v-model" should go before ":label" vue/attributes-order
+ 202:42 warning Expected 1 line break before closing bracket, but no line breaks found vue/html-closing-bracket-newline
+ 205:57 warning Attribute "v-model" should go before ":label" vue/attributes-order
+ 205:57 warning 'v-model' should be on a new line vue/max-attributes-per-line
+ 205:82 warning Expected a space before '/>', but not found vue/html-closing-bracket-spacing
+ 207:35 warning 'class' should be on a new line vue/max-attributes-per-line
+ 215:31 warning 'class' should be on a new line vue/max-attributes-per-line
+ 218:13 warning Disallow self-closing on HTML void elements (<input/>) vue/html-self-closing
+ 218:20 warning Expected a linebreak before this attribute vue/first-attribute-linebreak
+ 218:32 warning Attribute "id" should go before "type" vue/attributes-order
+ 218:32 warning 'id' should be on a new line vue/max-attributes-per-line
+ 218:42 warning 'accept' should be on a new line vue/max-attributes-per-line
+ 218:72 warning 'hidden' should be on a new line vue/max-attributes-per-line
+ 219:1 error Expected indentation of 19 spaces but found 16 spaces vue/html-indent
+ 219:37 warning Expected 1 line break before closing bracket, but no line breaks found vue/html-closing-bracket-newline
+ 220:41 warning Attribute "class" should go before "@click" vue/attributes-order
+ 220:41 warning 'class' should be on a new line vue/max-attributes-per-line
+ 226:44 warning Attribute "class" should go before "@submit.prevent" vue/attributes-order
+ 226:44 warning 'class' should be on a new line vue/max-attributes-per-line
+ 229:57 warning Attribute "v-model" should go before ":label" vue/attributes-order
+ 229:57 warning 'v-model' should be on a new line vue/max-attributes-per-line
+ 229:81 warning Expected a space before '/>', but not found vue/html-closing-bracket-spacing
+ 231:35 warning 'class' should be on a new line vue/max-attributes-per-line
+
+/home/gero/documents/uni/pse/pse-dashboard/src/views/SubscriptionsView.vue
+ 9:5 warning Prop 'url' requires default value to be set vue/require-default-prop
+ 83:29 warning Expected 1 line break after opening tag (`<h1>`), but no line breaks found vue/singleline-html-element-content-newline
+ 83:66 warning Expected 1 line break before closing tag (`</h1>`), but no line breaks found vue/singleline-html-element-content-newline
+ 86:49 warning Attribute "class" should go before "@submit.prevent" vue/attributes-order
+ 86:49 warning 'class' should be on a new line vue/max-attributes-per-line
+ 87:72 warning Attribute "v-model" should go before ":label" vue/attributes-order
+ 87:72 warning 'v-model' should be on a new line vue/max-attributes-per-line
+ 88:45 warning 'type' should be on a new line vue/max-attributes-per-line
+ 93:18 warning Attribute ':waitingFor' must be hyphenated vue/attribute-hyphenation
+ 101:53 warning '@click' should be on a new line vue/max-attributes-per-line
+ 104:25 warning Expected a linebreak before this attribute vue/first-attribute-linebreak
+ 105:1 error Expected indentation of 24 spaces but found 16 spaces vue/html-indent
+ 106:1 error Expected indentation of 24 spaces but found 16 spaces vue/html-indent
+ 106:40 warning 'data-bs-target' should be on a new line vue/max-attributes-per-line
+ 106:69 warning Expected 1 line break before closing bracket, but no line breaks found vue/html-closing-bracket-newline
+ 111:21 error Elements in iteration expect to have 'v-bind:key' directives vue/require-v-for-key
+ 111:48 warning 'class' should be on a new line vue/max-attributes-per-line
+ 112:32 warning Expected a linebreak before this attribute vue/first-attribute-linebreak
+ 113:1 error Expected indentation of 31 spaces but found 24 spaces vue/html-indent
+ 113:41 warning ':value' should be on a new line vue/max-attributes-per-line
+ 113:54 warning Attribute "v-model" should go before ":value" vue/attributes-order
+ 113:54 warning 'v-model' should be on a new line vue/max-attributes-per-line
+ 113:84 warning Expected 1 line break before closing bracket, but no line breaks found vue/html-closing-bracket-newline
+ 114:50 warning '@unsubscribe' should be on a new line vue/max-attributes-per-line
+ 117:19 warning Expected 1 line break before closing tag (`</loading>`), but 2 line breaks found vue/multiline-html-element-content-newline
+ 123:24 warning Attribute "id" should go before "class" vue/attributes-order
+ 123:24 warning 'id' should be on a new line vue/max-attributes-per-line
+ 123:37 warning 'tabindex' should be on a new line vue/max-attributes-per-line
+ 125:40 warning Expected 1 line break after opening tag (`<div>`), but 2 line breaks found vue/multiline-html-element-content-newline
+ 132:21 warning Require self-closing on HTML elements (<button>) vue/html-self-closing
+ 132:43 warning 'class' should be on a new line vue/max-attributes-per-line
+ 132:61 warning 'data-bs-dismiss' should be on a new line vue/max-attributes-per-line
+ 132:85 warning 'aria-label' should be on a new line vue/max-attributes-per-line
+ 137:80 warning Attribute "v-model" should go before ":label" vue/attributes-order
+ 137:80 warning 'v-model' should be on a new line vue/max-attributes-per-line
+ 142:43 warning 'class' should be on a new line vue/max-attributes-per-line
+ 142:69 warning 'data-bs-dismiss' should be on a new line vue/max-attributes-per-line
+ 145:43 warning '@click' should be on a new line vue/max-attributes-per-line
+ 145:68 warning Attribute "data-bs-dismiss" should go before "@click" vue/attributes-order
+ 145:68 warning 'data-bs-dismiss' should be on a new line vue/max-attributes-per-line
+ 145:92 warning Attribute "class" should go before "@click" vue/attributes-order
+ 145:92 warning 'class' should be on a new line vue/max-attributes-per-line
+ 154:24 warning Attribute "id" should go before "class" vue/attributes-order
+ 154:24 warning 'id' should be on a new line vue/max-attributes-per-line
+ 154:41 warning 'tabindex' should be on a new line vue/max-attributes-per-line
+ 156:40 warning Expected 1 line break after opening tag (`<div>`), but 2 line breaks found vue/multiline-html-element-content-newline
+ 163:21 warning Require self-closing on HTML elements (<button>) vue/html-self-closing
+ 163:43 warning 'class' should be on a new line vue/max-attributes-per-line
+ 163:61 warning 'data-bs-dismiss' should be on a new line vue/max-attributes-per-line
+ 163:85 warning 'aria-label' should be on a new line vue/max-attributes-per-line
+ 168:80 warning 'role' should be on a new line vue/max-attributes-per-line
+ 169:25 warning Require self-closing on HTML elements (<i>) vue/html-self-closing
+ 176:25 error Elements in iteration expect to have 'v-bind:key' directives vue/require-v-for-key
+ 177:52 warning Expected 1 space before '}}', but not found vue/mustache-interpolation-spacing
+ 187:43 warning 'class' should be on a new line vue/max-attributes-per-line
+ 187:69 warning 'data-bs-dismiss' should be on a new line vue/max-attributes-per-line
+ 190:43 warning '@click' should be on a new line vue/max-attributes-per-line
+ 190:76 warning Attribute "data-bs-dismiss" should go before "@click" vue/attributes-order
+ 190:76 warning 'data-bs-dismiss' should be on a new line vue/max-attributes-per-line
+ 190:100 warning Attribute "class" should go before "@click" vue/attributes-order
+ 190:100 warning 'class' should be on a new line vue/max-attributes-per-line
+
+✖ 310 problems (56 errors, 254 warnings)
+ 43 errors and 194 warnings potentially fixable with the `--fix` option.
+
diff --git a/31-qualitaetsheft-kolloquium/assets/subscription.png b/31-qualitaetsheft-kolloquium/assets/subscription.png
new file mode 100644
index 0000000..58a84f9
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/assets/subscription.png
Binary files differ
diff --git a/31-qualitaetsheft-kolloquium/logos/banner_2020_kit.jpg b/31-qualitaetsheft-kolloquium/logos/banner_2020_kit.jpg
new file mode 100644
index 0000000..70ae1d0
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/logos/banner_2020_kit.jpg
Binary files differ
diff --git a/31-qualitaetsheft-kolloquium/logos/kitlogo_de_rgb.pdf b/31-qualitaetsheft-kolloquium/logos/kitlogo_de_rgb.pdf
new file mode 100644
index 0000000..ce31797
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/logos/kitlogo_de_rgb.pdf
Binary files differ
diff --git a/31-qualitaetsheft-kolloquium/logos/kitlogo_en_rgb.pdf b/31-qualitaetsheft-kolloquium/logos/kitlogo_en_rgb.pdf
new file mode 100644
index 0000000..dd59fa6
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/logos/kitlogo_en_rgb.pdf
Binary files differ
diff --git a/31-qualitaetsheft-kolloquium/logos/pse_logo.pdf b/31-qualitaetsheft-kolloquium/logos/pse_logo.pdf
new file mode 100644
index 0000000..91fd334
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/logos/pse_logo.pdf
Binary files differ
diff --git a/31-qualitaetsheft-kolloquium/notizen b/31-qualitaetsheft-kolloquium/notizen
new file mode 100644
index 0000000..70ac63b
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/notizen
@@ -0,0 +1,40 @@
+Titelseite:
+- Begrüßung
+
+Einführung:
+- Podcast: RSS-Feed, Episoden, Audio/Video
+- Podcatcher: lokale Verwaltung von Podcasts, API Unterstützung,
+Abspielen von Episoden
+- Synchronisationsserver (das soll unser Produkt werden): Hörfortschritte,
+Abonnements, Discovery (bei AntennaPod z.B. iTunes)
+
+Zielsetzung:
+
+Synchronisation (die Art, die wir bei uns anwenden):
+- alle Aktionen werden auf den Server und infolge dessen auf alle Podcatcher
+übertragen
+
+Features:
+- Synchronisation: Abos, Hörfortschritt
+- Weboberfläche: Aboliste, Zuletzt gehört
+- Account-Verwaltung: Registrieren, Anmelden, Passwort ändern/zurücksetzen,
+Account löschen, Daten importieren/exportieren
+
+UI-Journey:
+- login.html:
+ - Sprache ändern
+ - OAuth (kann)
+ - Registrieren (muss): neues Fenster, E-Mail + 2-mal Passwort (sicher?),
+ vergeben? -> Fehler / Bestätigungslink per E-Mail (gültig 24h)
+ - Anmelden (muss): E-Mail + Passwort eingeben, Login merken,
+ login, Fehlermeldung oder Dashboard
+ - Passwort vergessen: neues Fenster, E-Mail eingeben, falls Account wird
+ Link versendet, 24h gültig, nach betätigen PW zweimal eingeben & bestätigen
+ (Anforderungen)
+
+- podcasts.html: Abonnements, Eisoden, Hörfortschritte
+
+- listening.html: Zuletzt gehörte Episoden, Hörfortschritt, Wann gehört
+
+- settings.html: PW ändern, Gpodder Import, pers. Daten imp./exp.,
+ Account löschen
diff --git a/31-qualitaetsheft-kolloquium/presentation.tex b/31-qualitaetsheft-kolloquium/presentation.tex
new file mode 100644
index 0000000..8e198fb
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/presentation.tex
@@ -0,0 +1,62 @@
+%% Beispiel-Präsentation mit LaTeX Beamer im KIT-Design
+%% entsprechend den Gestaltungsrichtlinien vom 1. August 2020
+%%
+%% Siehe https://sdqweb.ipd.kit.edu/wiki/Dokumentvorlagen
+
+%% Beispiel-Präsentation
+\documentclass[table]{sdqbeamer}
+
+\usepackage{calc}
+\usepackage{multicol}
+\usepackage{fontawesome}
+\usepackage{ulem}
+\usepackage{pgfplots, pgfplotstable}
+\usepackage{tabularx}
+\usepgfplotslibrary{dateplot}
+\pgfplotsset{compat=newest}
+
+%% Titelbild
+\titleimage{banner_2020_kit}
+
+%% Gruppenlogo
+\grouplogo{kitlogo_de_rgb}
+
+%% Gruppenname und Breite (Standard: 50 mm)
+\groupname{Praxis der Softwareentwicklung}
+%\groupnamewidth{50mm}
+
+% Beginn der Präsentation
+
+\title[Kolloquium Qualitätssicherung]{
+ PSE\textsuperscript{2} - Podcast Synchronisation made Efficient
+}
+\subtitle{Kolloquium Qualitätssicherung}
+\author[Daniel Hönlinger]{Daniel Hönlinger}
+
+\date[23.\,03.\,2023]{23. März 2023}
+
+\begin{document}
+
+%Titelseite
+\KITtitleframe
+
+% Änderungen zum Pflichtenheft
+\include{slides/changes}
+
+% Testfälle aus dem Pflichtenheft
+\include{slides/testing}
+
+% Codeabdeckung
+\include{slides/coverage}
+
+% Lasttests
+\include{slides/performance}
+
+% Probleme
+\include{slides/problems}
+
+% Codestil
+\include{slides/codestyle}
+
+
+\end{document}
diff --git a/31-qualitaetsheft-kolloquium/sdqbeamer.cls b/31-qualitaetsheft-kolloquium/sdqbeamer.cls
new file mode 100644
index 0000000..1b9c2b8
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/sdqbeamer.cls
@@ -0,0 +1,975 @@
+%% Vorlage für Präsentationen mit LaTeX Beamer im KIT-Design
+%% entsprechend den Gestaltungsrichtlinien vom 1. August 2020
+%%
+%% Siehe https://sdqweb.ipd.kit.edu/wiki/Dokumentvorlagen
+
+
+\NeedsTeXFormat{LaTeX2e}
+\ProvidesClass{sdqbeamer}[2022-05-03 v3.1.3 SDQ Beamer class]
+
+\RequirePackage[utf8]{inputenc}
+\RequirePackage[T1]{fontenc}
+
+\newif\ifsectionnavigation
+\newif\ifnavbarinfoot
+\newif\ifnavbarinline
+\newif\ifnavbarside
+\newif\iffourtothree
+\newif\ifsixteentonine
+\newif\ifsixteentoten
+\newif\ifgerman
+\newif\ifsmallfooterfont
+
+\def\kitslogan#1{\def\@kitslogan{#1}}
+\def\kitlogo#1{\def\@kitlogo{#1}}
+\def\groupname#1{\def\@groupname{#1}}
+\def\groupnamewidth#1{\def\@groupnamewidth{#1}}
+
+% siehe README.md
+\DeclareOption{de}{
+ \kitslogan{KIT -- Die Forschungsuniversität in der Helmholtz-Gemeinschaft}
+ \kitlogo{pse_logo}
+ \germantrue
+ \PassOptionsToPackage{autostyle}{csquotes}
+ }
+\DeclareOption{en}{
+ \kitslogan{KIT -- The Research University in the Helmholtz Association}
+ \kitlogo{kitlogo_en_rgb}
+ \germanfalse
+ }
+\DeclareOption{4:3}{
+ \fourtothreetrue
+ \sixteentoninefalse
+ \sixteentotenfalse
+}
+\DeclareOption{16:9}{
+ \fourtothreefalse
+ \sixteentoninetrue
+ \sixteentotenfalse
+}
+\DeclareOption{16:10}{
+ \fourtothreefalse
+ \sixteentoninefalse
+ \sixteentotentrue
+}
+\DeclareOption{navbarside}{
+ \sectionnavigationtrue
+ \navbarsidetrue
+ \navbarinlinefalse
+ \navbarinfootfalse
+}
+\DeclareOption{navbarinline}{
+ \sectionnavigationtrue
+ \navbarsidefalse
+ \navbarinlinetrue
+ \navbarinfootfalse
+}
+\DeclareOption{navbarinfooter}{
+ \sectionnavigationtrue
+ \navbarsidefalse
+ \navbarinlinefalse
+ \navbarinfoottrue
+}
+\DeclareOption{navbaroff}{
+ \sectionnavigationfalse
+}
+\DeclareOption{navbarkit}{
+ \sectionnavigationfalse
+ \smallfooterfonttrue
+}
+\DeclareOption{smallfoot}{
+ \smallfooterfonttrue
+}
+\DeclareOption{bigfoot}{
+ \smallfooterfontfalse
+}
+
+\ExecuteOptions{de,16:9,navbarinline,bigfoot}
+
+\DeclareOption*{\PassOptionsToClass{\CurrentOption}{beamer}}
+
+\ProcessOptions\relax
+
+\LoadClass[10pt,utf8]{beamer}
+
+% Babel-Paket wird nur bei deutscher Sprache benötigt
+\ifgerman
+ \RequirePackage[ngerman]{babel}
+\fi
+\RequirePackage{csquotes}
+\RequirePackage{hyperref}
+\RequirePackage[absolute,overlay]{textpos}
+
+%% ---------------
+%% | Typographie |
+%% ---------------
+
+\RequirePackage{microtype}
+
+\RequirePackage[scaled=.92]{helvet}
+\RequirePackage[scaled=.78]{beramono}
+\RequirePackage{libertineRoman}
+
+\setbeamerfont{title}{series=\bfseries,size=\Large}
+\setbeamerfont{frametitle}{series=\bfseries,size=\Large}
+\setbeamerfont{framesubtitle}{series=\bfseries,size=\normalsize}
+
+%% -----------------
+%% | Folien-Layout |
+%% -----------------
+
+% Seitenverhältnis
+%
+% Die Folien sind auf die Standardhöhe in LaTeX Beamer (9,6 cm) normiert.
+% Die Maße der KIT-Gestaltungsrichtlinien (Folienhöhe 14,3 cm) wurden durch
+% den Quotienten 1,5 geteilt.
+
+\RequirePackage{geometry}
+\iffourtothree
+ \geometry{papersize={12.8cm,9.6cm}}
+\fi
+\ifsixteentoten
+ \geometry{papersize={15.36cm,9.6cm}}
+\fi
+\ifsixteentonine
+ \geometry{papersize={17.07cm,9.6cm}}
+\fi
+
+% Ränder laut Gestaltungsrichtlinen; 3 mm -> 2 mm, 11 mm -> 7,3 mm
+\newlength{\kitoutermargin}
+\setlength{\kitoutermargin}{2mm}
+\newlength{\kitinnermargin}
+\setlength{\kitinnermargin}{7.3mm}
+\newlength{\kitbottommargin}
+\setlength{\kitbottommargin}{\kitinnermargin}
+
+% Ränder außen
+\setbeamersize{text margin left=\kitinnermargin,text margin right=\kitinnermargin}
+
+% keine Navigationssymbole
+\setbeamertemplate{navigation symbols}{}
+\setbeamercovered{invisible}
+\useinnertheme{rounded}
+\beamer@compresstrue % Miniframes (Navigations-Punkte) für Subsections immer in einer Zeile, ohne Umbrüche
+
+% Folientitel
+\setbeamertemplate{frametitle}{
+ \ifbeamer@plainframe\else%
+ % Unterkante Titeltext: 22,5 mm -> 15 mm von Seitenkopf
+ \begin{textblock*}{\dimexpr\paperwidth-30mm-2\kitinnermargin}[0,1](\kitinnermargin,15mm)%
+ \usebeamerfont{frametitle}\insertframetitle%
+ \ifx\insertframesubtitle\@empty\else\\[.1em]\fi
+ \usebeamerfont{framesubtitle}\insertframesubtitle%
+ \end{textblock*}%
+ \begin{textblock*}{20mm}[1,1](\dimexpr\paperwidth-\kitinnermargin\relax,15mm)%j
+ \includegraphics[width=20mm]{logos/\@kitlogo}%
+ \end{textblock*}%
+ \fi
+% Rand oben (ergibt Beginn des Textes bei 34 mm -> 22,7 mm)
+ \vspace {18mm}
+}
+
+%% Fußzeile
+\newlength{\kitbottom}
+ % Navbar in Footer: Schmale Fußzeile
+\ifnavbarinfoot
+ % Bei Navbar in Footer immer kleiner Font in der Fußzeile
+ \setbeamerfont{footer}{size=\fontsize{6pt}{7.2pt}\selectfont}
+ \setlength{\kitbottom}{4mm}
+\else
+ % Ansonsten kleiner Text nur, wenn "smallfoot" gewählt
+ \ifsmallfooterfont
+ \setbeamerfont{footer}{size=\fontsize{6pt}{7.2pt}\selectfont}
+ \else
+ \setbeamerfont{footer}{size=\scriptsize}
+ \fi
+ \setlength{\kitbottom}{\kitbottommargin}
+\fi
+\setbeamerfont{page number in head/foot}{series=\bfseries}
+
+\newlength{\kitbottomdepth}
+\newlength{\kitbottomheight}
+\newlength{\kitfootergroupwidth}
+
+\setbeamertemplate{footline}{%
+\setlength{\kitbottomdepth}{\dimexpr.5\kitbottom-.5em\relax}%
+\setlength{\kitbottomheight}{\dimexpr.5\kitbottom+.5em\relax}%
+ %% die "%" am Ende sind nötig, damit keine Abstände eingefügt werden
+ %
+ % Falls kein Gruppenname angegeben, die ganze Breite der Fußzeile für den Titel nutzen.
+ \ifdefined\@groupname%
+ \ifx\@groupname\empty%
+ \setlength{\kitfootergroupwidth}{0mm}%
+ \else%
+ % Falls die Breite des Gruppenlogos definiert ist, diese nehmen, sonst 50 mm
+ \ifdefined\@groupnamewidth%
+ \setlength{\kitfootergroupwidth}{\@groupnamewidth}%
+ \else%
+ \setlength{\kitfootergroupwidth}{50mm}%
+ \fi%
+ \fi%
+ \else
+ \setlength{\kitfootergroupwidth}{0mm}%
+ \fi
+ \usebeamerfont{footer}%
+ \ifsectionnavigation%
+ % Option "navbarinline"
+ \ifnavbarinline%
+ \begin{beamercolorbox}[wd=\paperwidth, leftskip=2mm, rightskip=2mm]{}
+ \insertnavigation{\dimexpr\paperwidth-4mm\relax}
+ \vspace{1mm}
+ \end{beamercolorbox}%
+ \fi%
+ % Option "navbarinfooter"
+ \ifnavbarinfoot%
+ % Punkte für Subsections deaktivieren
+ \setbeamertemplate{mini frames}{}%
+ \begin{beamercolorbox}[wd=\paperwidth, leftskip=1mm, rightskip=1mm]{}%
+ \insertsectionnavigationhorizontal{\dimexpr\paperwidth-\kitoutermargin\relax}{}{}
+ \end{beamercolorbox}%
+ \fi%
+ \fi%
+ \leavevmode%
+ \begin{beamercolorbox}[wd=13mm, ht=\kitbottomheight, dp=\kitbottomdepth, leftskip=4mm]{}
+ \usebeamerfont{page number in head/foot}%
+ \strut\insertframenumber{}/\inserttotalframenumber%
+ \end{beamercolorbox}%
+ \begin{beamercolorbox}[wd=20mm, ht=\kitbottomheight, dp=\kitbottomdepth]{}
+ \usebeamerfont{date in head/foot}%
+ \strut\insertshortdate%
+ \end{beamercolorbox}%
+ % Die Boxen mit dem Titel und dem Gruppennamen sind vertikal zentriert, damit auch zweizeilige Texte schön aussehen
+ % Daher müssen sie um \kitbottomdepth nach unten verschoben werden
+ \raisebox{-\kitbottomdepth}{
+ % Die Box hat daher auch Höhe \kitbottom und Tiefe 0mm
+ \begin{beamercolorbox}[wd=\dimexpr\paperwidth-37mm-\kitfootergroupwidth, ht=\kitbottom, dp=0mm]{}%
+ % Inhalt vertikal zentrieren; Anpassung um 1.5 pt, damit bei einzeiligem Inhalt genau die Baseline der Blöcke mit Seitenzahl und Datum getroffen wird
+ \vbox to\kitbottom{\vfill\vskip1.5pt%
+ \beamer@shortauthor\ifx\beamer@shortauthor\empty\else: \fi\beamer@shorttitle%
+ \vfill}%
+ \end{beamercolorbox}%
+ \ifdefined\@groupname%
+ \begin{beamercolorbox}[wd=\kitfootergroupwidth, ht=\kitbottom, dp=0mm, rightskip=\kitinnermargin]{}
+ \vbox to\kitbottom{\vfill\vskip1.5pt%
+ \raggedleft\@groupname%
+ \vfill}%
+ \end{beamercolorbox}%
+ \fi%
+ }%
+}
+
+%% Option "navbarside"
+\ifnavbarside
+\useoutertheme[height=0cm,width=3.5cm,left]{sidebar}
+
+\setbeamerfont{title in sidebar}{family=\sffamily,series=\mdseries,size={\fontsize{10pt}{11pt}}}
+\setbeamerfont{section in sidebar}{family=\sffamily,series=\mdseries,size={\fontsize{9pt}{9.9pt}}}
+\setbeamerfont{subsection in sidebar}{family=\sffamily,series=\mdseries,size={\fontsize{8pt}{8.8pt}}}
+
+\setbeamertemplate{sidebar \beamer@sidebarside}
+ {\vskip1.5cm%
+ \hskip6.5mm%
+ \advance\beamer@sidebarwidth by -5mm%
+ \insertverticalnavigation{\beamer@sidebarwidth}%
+ }%
+\fi
+
+%% Hintergrund
+\usebackgroundtemplate{
+ % Trennlinie nicht bei "plain"-Frames
+ \ifbeamer@plainframe\else\kitseparationline\fi
+}
+
+% Trennlinie
+\newcommand{\kitseparationline}{
+ \begin{pgfpicture}{0mm}{0mm}{\paperwidth}{\paperheight}
+ \pgfsetstrokecolor{black!15}
+ \pgfsetlinewidth{.5pt}
+ \pgfpathmoveto{\pgfpoint{\kitoutermargin}{\kitinnermargin}}
+ \pgfpathlineto{\pgfpoint{\paperwidth-\kitoutermargin}{\kitinnermargin}}
+ \pgfusepath{stroke}
+ \end{pgfpicture}%
+}
+
+
+%% --------------
+%% | Titelseite |
+%% --------------
+
+\def\titleimage#1{\def\@titleimage{#1}}
+\def\grouplogo#1{\def\@grouplogo{#1}}
+
+\newcommand{\KITtitleframe}{
+ \begin{frame}[plain]
+ \titlepage
+ \end{frame}
+}
+
+\newlength{\kittitleimageheight}
+\setbeamertemplate{title page}{
+ % From textpos documentation (https://ctan.org/pkg/textpos)
+ %
+ % \begin{textblock}{<hsize>}[<ho>,<vo>](<hpos>,<vpos>)
+ % The coordinates <ho> and <vo> are fractions of the width and height of the text
+ % box, respectively, and state that the box is to be placed so that the reference point
+ % (<ho>,<vo>) within the box is to be placed at the point (<hpos>,<vpos>) on the page.
+
+ % KIT-Logo
+ \begin{textblock*}{30mm}(\kitinnermargin,6.7mm)
+ \includegraphics[width=30mm]{logos/\@kitlogo}
+ \end{textblock*}
+
+ % Gruppenlogo
+ \ifdefined\@grouplogo
+ \ifx\@grouplogo\empty \else
+ \begin{textblock*}{20mm}(\dimexpr\paperwidth-24mm\relax,6.7mm)
+ \includegraphics[width=20mm,height=20mm,keepaspectratio]{logos/\@grouplogo}
+ \end{textblock*}
+ \fi % falls \grouplogo{} aufgerufen wird, kein Gruppenlogo einbinden
+ \else
+ \begin{textblock*}{20mm}(\dimexpr\paperwidth-24mm\relax,6.7mm)
+ \colorbox{kit-purple100!20}{\parbox[t][12mm][c]{19mm}{\color{kit-purple100}\scriptsize\centering
+ \ifgerman
+ Bitte Logo über \texttt{\textbackslash grouplogo\{\}} festlegen.
+ \else
+ Please set a logo using \texttt{\textbackslash grouplogo\{\}}.
+ \fi
+ }}
+ \end{textblock*}
+ \fi
+
+ % Titel
+ \begin{textblock*}{\dimexpr\paperwidth-8mm\relax}[0,.5](\kitinnermargin,28mm)
+ \usebeamerfont*{title}\inserttitle
+ \end{textblock*}
+
+ % Untertitel
+ \begin{textblock*}{\dimexpr\paperwidth-8mm\relax}(\kitinnermargin,36mm)
+ \small\textbf{\insertsubtitle}
+ \end{textblock*}
+
+ % Autor
+ \begin{textblock*}{\dimexpr\paperwidth-8mm\relax}(\kitinnermargin,41mm)
+ \small\insertauthor~\textbar~\insertdate
+ \end{textblock*}
+
+ % Titelbild
+ \setlength{\kittitleimageheight}{40mm}
+ \begin{textblock*}{\paperwidth}(\kitoutermargin,\dimexpr\paperheight-\kitbottommargin-\kittitleimageheight)
+ \begin{pgfpicture}{0mm}{0mm}{\paperwidth}{\kittitleimageheight}
+ % Clipping-Pfad um titelbild
+ \pgfsetstrokecolor{black!15}
+ \pgfsetlinewidth{1pt}
+ \pgfsetcornersarced{\pgfpoint{3mm}{3mm}}
+ \pgfpathmoveto{\pgfpoint{\paperwidth-2\kitoutermargin}{0mm}}
+ \pgfpathlineto{\pgfpoint{\paperwidth-2\kitoutermargin}{\kittitleimageheight}}
+ \pgfsetcornersarced{\pgfpointorigin}
+ \pgfpathlineto{\pgfpoint{0mm}{\kittitleimageheight}}
+ \pgfsetcornersarced{\pgfpoint{3mm}{3mm}}
+ \pgfpathlineto{\pgfpointorigin}
+ \pgfsetcornersarced{\pgfpointorigin}
+ \pgfpathclose
+ \pgfusepath{stroke,clip}
+ \pgfsetstrokecolor{black}
+
+ % Titelbild
+ \ifdefined\@titleimage
+ \ifx\@titleimage\empty \else%
+ \pgftext[at=\pgfpoint{.5\paperwidth}{0mm},center,bottom]{%
+ \includegraphics[height=40mm]{logos/\@titleimage}
+ }
+ \fi % Bei Aufruf von \titleimage{} leeren Rahmen anzeigen.
+ \else
+ \pgftext[at=\pgfpoint{.5\paperwidth}{.5\kittitleimageheight},center,base]{%
+ \colorbox{kit-purple100!20}{\parbox[c][\kittitleimageheight][c]{\paperwidth}{\color{kit-purple100}\centering Bitte Titelbild über \texttt{\textbackslash titleimage\{\}} festlegen.
+ }}%
+ }
+ \fi
+
+
+ \end{pgfpicture}%
+ \end{textblock*}
+
+
+ % KIT slogan
+ \begin{textblock*}{80mm}[0,.5](\kitoutermargin,\dimexpr\paperheight-.5\kitbottommargin)
+ \fontsize{5.5pt}{5.5pt}\selectfont\@kitslogan
+ \end{textblock*}
+
+ \begin{textblock*}{30mm}[1,.5](\dimexpr\paperwidth-\kitoutermargin\relax,\dimexpr\paperheight-.5\kitbottommargin)
+ \fontsize{11pt}{11pt}\selectfont\bfseries\raggedleft%
+ {\href{https://www.kit.edu}{www.kit.edu}}
+ \end{textblock*}
+
+}
+%% ---------------
+%% | /Titelseite |
+%% ---------------
+
+%% ----------
+%% | Farben |
+%% ----------
+%% KIT-Farbschema
+
+% KIT color green :
+\definecolor{kit-green}{RGB}{0, 150, 130}
+\definecolor{kit-green100}{RGB}{0, 150, 130}
+\definecolor{kit-green90}{rgb}{0.1, 0.6294, 0.5588}
+\definecolor{kit-green80}{rgb}{0.2, 0.6706, 0.6078}
+\definecolor{kit-green75}{rgb}{0.25, 0.6912, 0.6324}
+\definecolor{kit-green70}{rgb}{0.3, 0.7118, 0.6569}
+\definecolor{kit-green60}{rgb}{0.4, 0.7529, 0.7059}
+\definecolor{kit-green50}{rgb}{0.5, 0.7941, 0.7549}
+\definecolor{kit-green40}{rgb}{0.6, 0.8353, 0.8039}
+\definecolor{kit-green30}{rgb}{0.7, 0.8765, 0.8529}
+\definecolor{kit-green25}{rgb}{0.75, 0.8971, 0.8775}
+\definecolor{kit-green20}{rgb}{0.8, 0.9176, 0.902}
+\definecolor{kit-green15}{rgb}{0.85, 0.9382, 0.9265}
+\definecolor{kit-green10}{rgb}{0.9, 0.9588, 0.951}
+\definecolor{kit-green5}{rgb}{0.95, 0.9794, 0.9755}
+
+% KIT color blue:
+\definecolor{kit-blue}{RGB}{70, 100, 170}
+\definecolor{kit-blue100}{RGB}{70, 100, 170}
+\definecolor{kit-blue90}{rgb}{0.3471, 0.4529, 0.7}
+\definecolor{kit-blue80}{rgb}{0.4196, 0.5137, 0.7333}
+\definecolor{kit-blue75}{rgb}{0.4559, 0.5441, 0.75}
+\definecolor{kit-blue70}{rgb}{0.4922, 0.5745, 0.7667}
+\definecolor{kit-blue60}{rgb}{0.5647, 0.6353, 0.8}
+\definecolor{kit-blue50}{rgb}{0.6373, 0.6961, 0.8333}
+\definecolor{kit-blue40}{rgb}{0.7098, 0.7569, 0.8667}
+\definecolor{kit-blue30}{rgb}{0.7824, 0.8176, 0.9}
+\definecolor{kit-blue25}{rgb}{0.8186, 0.848, 0.9167}
+\definecolor{kit-blue20}{rgb}{0.8549, 0.8784, 0.9333}
+\definecolor{kit-blue15}{rgb}{0.8912, 0.9088, 0.95}
+\definecolor{kit-blue10}{rgb}{0.9275, 0.9392, 0.9667}
+\definecolor{kit-blue5}{rgb}{0.9637, 0.9696, 0.9833}
+
+% KIT color red :
+\definecolor{kit-red}{RGB}{162, 34, 35}
+\definecolor{kit-red100}{RGB}{162, 34, 35}
+\definecolor{kit-red90}{rgb}{0.6718, 0.22, 0.2235}
+\definecolor{kit-red80}{rgb}{0.7082, 0.3067, 0.3098}
+\definecolor{kit-red75}{rgb}{0.7265, 0.35, 0.3529}
+\definecolor{kit-red70}{rgb}{0.7447, 0.3933, 0.3961}
+\definecolor{kit-red60}{rgb}{0.7812, 0.48, 0.4824}
+\definecolor{kit-red50}{rgb}{0.8176, 0.5667, 0.5686}
+\definecolor{kit-red40}{rgb}{0.8541, 0.6533, 0.6549}
+\definecolor{kit-red30}{rgb}{0.8906, 0.74, 0.7412}
+\definecolor{kit-red25}{rgb}{0.9088, 0.7833, 0.7843}
+\definecolor{kit-red20}{rgb}{0.9271, 0.8267, 0.8275}
+\definecolor{kit-red15}{rgb}{0.9453, 0.87, 0.8706}
+\definecolor{kit-red10}{rgb}{0.9635, 0.9133, 0.9137}
+\definecolor{kit-red5}{rgb}{0.9818, 0.9567, 0.9569}
+
+% KIT color yellow :
+\definecolor{kit-yellow}{RGB}{252, 229, 0}
+\definecolor{kit-yellow100}{RGB}{252, 229, 0}
+\definecolor{kit-yellow90}{rgb}{0.9894, 0.9082, 0.1}
+\definecolor{kit-yellow80}{rgb}{0.9906, 0.9184, 0.2}
+\definecolor{kit-yellow75}{rgb}{0.9912, 0.9235, 0.25}
+\definecolor{kit-yellow70}{rgb}{0.9918, 0.9286, 0.3}
+\definecolor{kit-yellow60}{rgb}{0.9929, 0.9388, 0.4}
+\definecolor{kit-yellow50}{rgb}{0.9941, 0.949, 0.5}
+\definecolor{kit-yellow40}{rgb}{0.9953, 0.9592, 0.6}
+\definecolor{kit-yellow30}{rgb}{0.9965, 0.9694, 0.7}
+\definecolor{kit-yellow25}{rgb}{0.9971, 0.9745, 0.75}
+\definecolor{kit-yellow20}{rgb}{0.9976, 0.9796, 0.8}
+\definecolor{kit-yellow15}{rgb}{0.9982, 0.9847, 0.85}
+\definecolor{kit-yellow10}{rgb}{0.9988, 0.9898, 0.9}
+\definecolor{kit-yellow5}{rgb}{0.9994, 0.9949, 0.95}
+
+% KIT color orange :
+\definecolor{kit-orange}{RGB}{223, 155, 27}
+\definecolor{kit-orange100}{RGB}{223, 155, 27}
+\definecolor{kit-orange90}{rgb}{0.8871, 0.6471, 0.1953}
+\definecolor{kit-orange80}{rgb}{0.8996, 0.6863, 0.2847}
+\definecolor{kit-orange75}{rgb}{0.9059, 0.7059, 0.3294}
+\definecolor{kit-orange70}{rgb}{0.9122, 0.7255, 0.3741}
+\definecolor{kit-orange60}{rgb}{0.9247, 0.7647, 0.4635}
+\definecolor{kit-orange50}{rgb}{0.9373, 0.8039, 0.5529}
+\definecolor{kit-orange40}{rgb}{0.9498, 0.8431, 0.6424}
+\definecolor{kit-orange30}{rgb}{0.9624, 0.8824, 0.7318}
+\definecolor{kit-orange25}{rgb}{0.9686, 0.902, 0.7765}
+\definecolor{kit-orange20}{rgb}{0.9749, 0.9216, 0.8212}
+\definecolor{kit-orange15}{rgb}{0.9812, 0.9412, 0.8659}
+\definecolor{kit-orange10}{rgb}{0.9875, 0.9608, 0.9106}
+\definecolor{kit-orange5}{rgb}{0.9937, 0.9804, 0.9553}
+
+% KIT color lightgreen :
+\definecolor{kit-lightgreen}{RGB}{140, 182, 60}
+\definecolor{kit-lightgreen100}{RGB}{140, 182, 60}
+\definecolor{kit-lightgreen90}{rgb}{0.5941, 0.7424, 0.3118}
+\definecolor{kit-lightgreen80}{rgb}{0.6392, 0.771, 0.3882}
+\definecolor{kit-lightgreen75}{rgb}{0.6618, 0.7853, 0.4265}
+\definecolor{kit-lightgreen70}{rgb}{0.6843, 0.7996, 0.4647}
+\definecolor{kit-lightgreen60}{rgb}{0.7294, 0.8282, 0.5412}
+\definecolor{kit-lightgreen50}{rgb}{0.7745, 0.8569, 0.6176}
+\definecolor{kit-lightgreen40}{rgb}{0.8196, 0.8855, 0.6941}
+\definecolor{kit-lightgreen30}{rgb}{0.8647, 0.9141, 0.7706}
+\definecolor{kit-lightgreen25}{rgb}{0.8873, 0.9284, 0.8088}
+\definecolor{kit-lightgreen20}{rgb}{0.9098, 0.9427, 0.8471}
+\definecolor{kit-lightgreen15}{rgb}{0.9324, 0.9571, 0.8853}
+\definecolor{kit-lightgreen10}{rgb}{0.9549, 0.9714, 0.9235}
+\definecolor{kit-lightgreen5}{rgb}{0.9775, 0.9857, 0.9618}
+
+
+% KIT color purple :
+\definecolor{kit-purple}{RGB}{163, 16, 124}
+\definecolor{kit-purple100}{RGB}{163, 16, 124}
+\definecolor{kit-purple90}{rgb}{0.6753, 0.1565, 0.5376}
+\definecolor{kit-purple80}{rgb}{0.7114, 0.2502, 0.589}
+\definecolor{kit-purple75}{rgb}{0.7294, 0.2971, 0.6147}
+\definecolor{kit-purple70}{rgb}{0.7475, 0.3439, 0.6404}
+\definecolor{kit-purple60}{rgb}{0.7835, 0.4376, 0.6918}
+\definecolor{kit-purple50}{rgb}{0.8196, 0.5314, 0.7431}
+\definecolor{kit-purple40}{rgb}{0.8557, 0.6251, 0.7945}
+\definecolor{kit-purple30}{rgb}{0.8918, 0.7188, 0.8459}
+\definecolor{kit-purple25}{rgb}{0.9098, 0.7657, 0.8716}
+\definecolor{kit-purple20}{rgb}{0.9278, 0.8125, 0.8973}
+\definecolor{kit-purple15}{rgb}{0.9459, 0.8594, 0.9229}
+\definecolor{kit-purple10}{rgb}{0.9639, 0.9063, 0.9486}
+\definecolor{kit-purple5}{rgb}{0.982, 0.9531, 0.9743}
+
+% KIT color brown :
+\definecolor{kit-brown}{RGB}{167, 130, 46}
+\definecolor{kit-brown100}{RGB}{167, 130, 46}
+\definecolor{kit-brown90}{rgb}{0.6894, 0.5588, 0.2624}
+\definecolor{kit-brown80}{rgb}{0.7239, 0.6078, 0.3443}
+\definecolor{kit-brown75}{rgb}{0.7412, 0.6324, 0.3853}
+\definecolor{kit-brown70}{rgb}{0.7584, 0.6569, 0.4263}
+\definecolor{kit-brown60}{rgb}{0.7929, 0.7059, 0.5082}
+\definecolor{kit-brown50}{rgb}{0.8275, 0.7549, 0.5902}
+\definecolor{kit-brown40}{rgb}{0.862, 0.8039, 0.6722}
+\definecolor{kit-brown30}{rgb}{0.8965, 0.8529, 0.7541}
+\definecolor{kit-brown25}{rgb}{0.9137, 0.8775, 0.7951}
+\definecolor{kit-brown20}{rgb}{0.931, 0.902, 0.8361}
+\definecolor{kit-brown15}{rgb}{0.9482, 0.9265, 0.8771}
+\definecolor{kit-brown10}{rgb}{0.9655, 0.951, 0.918}
+\definecolor{kit-brown5}{rgb}{0.9827, 0.9755, 0.959}
+
+% KIT color cyan :
+\definecolor{kit-cyan}{RGB}{35, 161, 224}
+\definecolor{kit-cyan100}{RGB}{35, 161, 224}
+\definecolor{kit-cyan90}{rgb}{0.2235, 0.6682, 0.8906}
+\definecolor{kit-cyan80}{rgb}{0.3098, 0.7051, 0.9027}
+\definecolor{kit-cyan75}{rgb}{0.3529, 0.7235, 0.9088}
+\definecolor{kit-cyan70}{rgb}{0.3961, 0.742, 0.9149}
+\definecolor{kit-cyan60}{rgb}{0.4824, 0.7788, 0.9271}
+\definecolor{kit-cyan50}{rgb}{0.5686, 0.8157, 0.9392}
+\definecolor{kit-cyan40}{rgb}{0.6549, 0.8525, 0.9514}
+\definecolor{kit-cyan30}{rgb}{0.7412, 0.8894, 0.9635}
+\definecolor{kit-cyan25}{rgb}{0.7843, 0.9078, 0.9696}
+\definecolor{kit-cyan20}{rgb}{0.8275, 0.9263, 0.9757}
+\definecolor{kit-cyan15}{rgb}{0.8706, 0.9447, 0.9818}
+\definecolor{kit-cyan10}{rgb}{0.9137, 0.9631, 0.9878}
+\definecolor{kit-cyan5}{rgb}{0.9569, 0.9816, 0.9939}
+
+% KIT color gray :
+\definecolor{kit-gray}{RGB}{0, 0, 0}
+\definecolor{kit-gray100}{RGB}{0, 0, 0}
+\definecolor{kit-gray90}{rgb}{0.1, 0.1, 0.1}
+\definecolor{kit-gray80}{rgb}{0.2, 0.2, 0.2}
+\definecolor{kit-gray75}{rgb}{0.25, 0.25, 0.25}
+\definecolor{kit-gray70}{rgb}{0.3, 0.3, 0.3}
+\definecolor{kit-gray60}{rgb}{0.4, 0.4, 0.4}
+\definecolor{kit-gray50}{rgb}{0.5, 0.5, 0.5}
+\definecolor{kit-gray40}{rgb}{0.6, 0.6, 0.6}
+\definecolor{kit-gray30}{rgb}{0.7, 0.7, 0.7}
+\definecolor{kit-gray25}{rgb}{0.75, 0.75, 0.75}
+\definecolor{kit-gray20}{rgb}{0.8, 0.8, 0.8}
+\definecolor{kit-gray15}{rgb}{0.85, 0.85, 0.85}
+\definecolor{kit-gray10}{rgb}{0.9, 0.9, 0.9}
+\definecolor{kit-gray5}{rgb}{0.95, 0.95, 0.95}
+
+
+
+\setbeamercolor*{normal text}{fg=black}
+\setbeamercolor*{alerted text}{fg=kit-red100}
+\setbeamercolor*{example text}{fg=black}
+\setbeamercolor*{structure}{fg=black}
+
+\setbeamercolor*{palette primary}{fg=black,bg=black!15}
+\setbeamercolor*{palette secondary}{fg=black,bg=black!15}
+\setbeamercolor*{palette tertiary}{fg=black,bg=black!15}
+\setbeamercolor*{palette quaternary}{fg=black,bg=black!15}
+
+\setbeamercolor*{palette sidebar primary}{fg=black!75}
+\setbeamercolor*{palette sidebar secondary}{fg=black!75}
+\setbeamercolor*{palette sidebar tertiary}{fg=black!75}
+\setbeamercolor*{palette sidebar quaternary}{fg=black!75}
+
+\setbeamercolor*{item projected}{fg=white,bg=kit-green100}
+
+\setbeamercolor*{block title}{fg=white,bg=kit-green100}
+\setbeamercolor*{block title alerted}{use=alerted text,fg=white,bg=alerted text.fg!75!black}
+\setbeamercolor*{block title example}{fg=white,bg=kit-blue100}
+
+\setbeamercolor*{block body}{fg=black,bg=kit-green15}
+\setbeamercolor*{block body alerted}{parent=normal text,use=block title alerted,bg=block title alerted.bg!10!bg}
+\setbeamercolor*{block body example}{fg=black,bg=kit-blue15}
+
+\setbeamercolor*{separation line}{}
+\setbeamercolor*{fine separation line}{}
+
+\setbeamercolor*{background canvas}{bg=white}
+
+%% -----------
+%% | /Farben |
+%% -----------
+
+%% -----------------------------------
+%% | halbgerundete Aufzählungspunkte |
+%% -----------------------------------
+
+\newcommand{\itemizeColor}{kit-green100}
+
+% KIT-Aufzählungszeichen
+\newcommand{\KITmark}{%
+ \begin{pgfpicture}{0mm}{0mm}{1ex}{1ex}
+ {\pgfsetcornersarced{\pgfpoint{.3ex}{.3ex}}
+ \pgfpathmoveto{\pgfpoint{0cm}{1ex}}
+ \pgfpathlineto{\pgfpoint{1ex}{1ex}}
+ \pgfpathlineto{\pgfpoint{1ex}{0cm}}}
+ {\pgfsetcornersarced{\pgfpoint{.3ex}{.3ex}}
+ \pgfpathmoveto{\pgfpoint{1ex}{0cm}}
+ \pgfpathlineto{\pgfpointorigin}
+ \pgfpathlineto{\pgfpoint{0cm}{1ex}}}
+ \color{\itemizeColor}
+ \pgfusepath{fill}
+ \end{pgfpicture}%
+}
+
+% \setbeamertemplate{itemize items}{\raisebox{.2ex}{\KITmark}}
+\setbeamertemplate{itemize items}[square]
+\setbeamercolor{itemize item}{fg=kit-green100}
+
+%% ----------------------
+%% | Inhaltsverzeichnis |
+%% ----------------------
+
+\setbeamertemplate{section in toc}{\normalsize\textbf{\textcolor{kit-blue}{\inserttocsectionnumber.~\inserttocsection}}\par}
+\setbeamertemplate{subsection in toc}{\small\hspace{1.2em}\raisebox{.2ex}{\KITmark}\hspace{\labelsep}\inserttocsubsection\par}
+
+%% ------------------------------
+%% | halbgerundete Beamer-Boxen |
+%% ------------------------------
+
+\renewcommand\beamerboxesrounded[2][]{%
+ \global\let\beamer@firstlineitemizeunskip=\relax%
+ \vbox\bgroup%
+ \setkeys{beamerboxes}{upper=block title,lower=block body,width=\textwidth,shadow=false}%
+ \setkeys{beamerboxes}{#1}%
+ {%
+ \usebeamercolor{\bmb@lower}%
+ \globalcolorstrue%
+ \colorlet{lower.bg}{bg}%
+ }%
+ {%
+ \usebeamercolor{\bmb@upper}%
+ \globalcolorstrue%
+ \colorlet{upper.bg}{bg}%
+ }%
+ %
+ % Typeset head
+ %
+ \vskip4bp
+ \setbox\bmb@box=\hbox{%
+ \begin{minipage}[b]{\bmb@width}%
+ \usebeamercolor[fg]{\bmb@upper}%
+ #2%
+ \end{minipage}}%
+ \ifdim\wd\bmb@box=0pt%
+ \setbox\bmb@box=\hbox{}%
+ \ht\bmb@box=1.5pt%
+ \bmb@prevheight=-4.5pt%
+ \else%
+ \wd\bmb@box=\bmb@width%
+ \bmb@temp=\dp\bmb@box%
+ \ifdim\bmb@temp<1.5pt%
+ \bmb@temp=1.5pt%
+ \fi%
+ \setbox\bmb@box=\hbox{\raise\bmb@temp\hbox{\box\bmb@box}}%
+ \dp\bmb@box=0pt%
+ \bmb@prevheight=\ht\bmb@box%
+ \fi%
+ \bmb@temp=\bmb@width%
+ \bmb@dima=\bmb@temp\advance\bmb@dima by2.2bp%
+ \bmb@dimb=\bmb@temp\advance\bmb@dimb by4bp%
+ \hbox{%
+ \begin{pgfpicture}{0bp}{+-\ht\bmb@box}{0bp}{+-\ht\bmb@box}
+ \ifdim\wd\bmb@box=0pt%
+ \color{lower.bg}%
+ \else%
+ \color{upper.bg}%
+ \fi%
+ \pgfpathqmoveto{-4bp}{-1bp}
+ % Adaption for "KIT-Design"
+ \pgfpathlineto{\pgfpoint{-4bp}{3bp}}
+ %\pgfpathqcurveto{-4bp}{1.2bp}{-2.2bp}{3bp}{0bp}{3bp}
+ \pgfpathlineto{\pgfpoint{\bmb@temp}{3bp}}
+ \pgfpathcurveto%
+ {\pgfpoint{\bmb@dima}{3bp}}%
+ {\pgfpoint{\bmb@dimb}{1.2bp}}%
+ {\pgfpoint{\bmb@dimb}{-1bp}}%
+ \bmb@dima=-\ht\bmb@box%
+ \advance\bmb@dima by-2pt%
+ \pgfpathlineto{\pgfpoint{\bmb@dimb}{\bmb@dima}}
+ \pgfpathlineto{\pgfpoint{-4bp}{\bmb@dima}}
+ \pgfusepath{fill}
+ \end{pgfpicture}%
+ \copy\bmb@box%
+ }%
+ \nointerlineskip%
+ \vskip-1pt%
+ \ifdim\wd\bmb@box=0pt%
+ \else%
+ \hbox{%
+ \begin{pgfpicture}{0pt}{0pt}{\bmb@width}{6pt}
+ \bmb@dima=\bmb@width%
+ \advance\bmb@dima by8bp%
+ \pgfpathrectangle{\pgfpoint{-4bp}{-1bp}}{\pgfpoint{\bmb@dima}{8bp}}
+ \pgfusepath{clip}
+ {\pgftransformshift{\pgfpoint{-4bp}{0bp}}\pgftext[left,base]{\pgfuseshading{bmb@transition}}}%
+ \end{pgfpicture}%
+ }%
+ \nointerlineskip%
+ \vskip-0.5pt%
+ \fi%
+ \ifbmb@shadow%
+ \setbox\bmb@boxshadow=\hbox{\pgfuseshading{bmb@shadow}}%
+ \setbox\bmb@boxshadowball=\hbox{\pgfuseshading{bmb@shadowball}}%
+ \setbox\bmb@boxshadowballlarge=\hbox{\pgfuseshading{bmb@shadowballlarge}}%
+ \fi%
+ \setbox\bmb@colorbox=\hbox{{\pgfpicturetrue\pgfsetcolor{lower.bg}}}%
+ \setbox\bmb@box=\hbox\bgroup\begin{minipage}[b]{\bmb@width}%
+ \vskip2pt%
+ \usebeamercolor[fg]{\bmb@lower}%
+ \colorlet{beamerstructure}{upper.bg}%
+ \colorlet{structure}{upper.bg}%
+ %\color{.}%
+ }
+
+\def\endbeamerboxesrounded{%
+ \end{minipage}\egroup%
+ \wd\bmb@box=\bmb@width%
+ \bmb@temp=\dp\bmb@box%
+ \advance\bmb@temp by.5pt%
+ \setbox\bmb@box=\hbox{\raise\bmb@temp\hbox{\box\bmb@box}}%
+ \dp\bmb@box=0pt%
+ \bmb@temp=\wd\bmb@box%
+ \bmb@dima=\bmb@temp\advance\bmb@dima by2.2bp%
+ \bmb@dimb=\bmb@temp\advance\bmb@dimb by4bp%
+ \hbox{%
+ \begin{pgfpicture}{0bp}{0bp}{0bp}{0bp}
+ \ifbmb@shadow%
+ {\pgftransformshift{\pgfpoint{4bp}{-3bp}}\pgftext{\copy\bmb@boxshadowball}}
+ \begin{pgfscope}
+ {%
+ \advance\bmb@temp by-1bp%
+ \pgfpathrectangle{\pgfpoint{\bmb@temp}{-7bp}}{\pgfpoint{9bp}{9bp}}%
+ \pgfusepath{clip}
+ }%
+ {\pgftransformshift{\pgfpoint{\bmb@temp}{1bp}}\pgftext{\box\bmb@boxshadowballlarge}}
+ \end{pgfscope}
+ \begin{pgfscope}
+ \advance\bmb@temp by-4bp%
+ \pgfpathrectangle{\pgfpoint{4bp}{-7bp}}{\pgfpoint{\bmb@temp}{5bp}}
+ \pgfusepath{clip}
+ {\pgftransformshift{\pgfpoint{4bp}{-7bp}}\pgftext[left,base]{\copy\bmb@boxshadow}}%
+ \end{pgfscope}
+ \begin{pgfscope}
+ \advance\bmb@temp by 4bp%
+ \bmb@dima=\ht\bmb@box%
+ \advance\bmb@dima by\bmb@prevheight%
+ \advance\bmb@dima by 4bp%
+ \pgfpathrectangle{\pgfpoint{\bmb@temp}{1bp}}{\pgfpoint{4bp}{\bmb@dima}}
+ \pgfusepath{clip}
+ \advance\bmb@dima by-4bp%
+ {\pgftransformshift{\pgfpoint{\bmb@temp}{\bmb@dima}}\pgftext{\box\bmb@boxshadowball}}
+ \advance\bmb@dima by-1bp%
+ \pgfpathrectangle{\pgfpoint{\bmb@temp}{1bp}}{\pgfpoint{4bp}{\bmb@dima}}
+ \pgfusepath{clip}
+ \advance\bmb@temp by4bp%
+ {\pgftransformshift{\pgfpoint{\bmb@temp}{-3bp}}%
+ \pgftransformrotate{90}%
+ \pgftext[left,base]{\box\bmb@boxshadow}}%
+ \end{pgfscope}
+ \fi%
+ \unhbox\bmb@colorbox%
+ \pgfpathqmoveto{-4bp}{1bp}
+ \pgfpathqcurveto{-4bp}{-1.2bp}{-2.2bp}{-3bp}{0bp}{-3bp}
+ \pgfpathlineto{\pgfpoint{\the\bmb@dimb}{-3bp}}
+ {
+ \bmb@dima=\ht\bmb@box%
+ \pgfpathlineto{\pgfpoint{\bmb@dimb}{\bmb@dima}}
+ \pgfpathlineto{\pgfpoint{-4bp}{\bmb@dima}}
+ \pgfusepath{fill}
+ }
+ \ifbmb@shadow%
+ {
+ \color{black!50!bg}
+ \pgfsetlinewidth{0pt}
+ \pgfpathmoveto{\pgfpoint{\bmb@dimb}{-.5bp}}
+ \bmb@dima=\ht\bmb@box%
+ \advance\bmb@dima by\bmb@prevheight%
+ \advance\bmb@dima by 1bp%
+ \pgfpathlineto{\pgfpoint{\bmb@dimb}{\bmb@dima}}
+ \pgfusepath{stroke}
+ \bmb@temp=\bmb@dima
+ \advance\bmb@dima by 1bp%
+ \color{black!31!bg}
+ \pgfpathmoveto{\pgfpoint{\bmb@dimb}{\bmb@temp}}
+ \pgfpathlineto{\pgfpoint{\bmb@dimb}{\bmb@dima}}
+ \pgfusepath{stroke}
+ \advance\bmb@dima by 1bp%
+ \advance\bmb@temp by 1bp%
+ \color{black!19!bg}
+ \pgfpathmoveto{\pgfpoint{\bmb@dimb}{\bmb@temp}}
+ \pgfpathlineto{\pgfpoint{\bmb@dimb}{\bmb@dima}}
+ \pgfusepath{stroke}
+ \advance\bmb@dima by 1bp%
+ \advance\bmb@temp by 1bp%
+ \color{black!6!bg}
+ \pgfpathmoveto{\pgfpoint{\bmb@dimb}{\bmb@temp}}
+ \pgfpathlineto{\pgfpoint{\bmb@dimb}{\bmb@dima}}
+ \pgfusepath{stroke}
+ \advance\bmb@dima by 1.5bp%
+ \advance\bmb@temp by 1bp%
+ \color{bg}
+ \pgfpathmoveto{\pgfpoint{\bmb@dimb}{\bmb@temp}}
+ \pgfpathlineto{\pgfpoint{\bmb@dimb}{\bmb@dima}}
+ \pgfusepath{stroke}
+ }
+ \fi
+ \end{pgfpicture}%
+ \box\bmb@box%
+ }%
+ \ifbmb@shadow%
+ \vskip4bp minus 2bp%
+ \else%
+ \vskip2bp%
+ \fi%
+ \egroup% of \vbox\bgroup
+}
+
+
+%% -------------------------------
+%% | /halbgerundete Beamer-Boxen |
+%% -------------------------------
+
+
+%% ----------------------
+%% | Block-Definitionen |
+%% ----------------------
+
+% Content environment for structuring. Basically a headline followed by text
+\newenvironment<>{contentblock}[1]{\begingroup%
+ \setbeamertemplate{blocks}[default]
+ \setbeamercolor{block body}{fg=black,bg=}%
+ \setbeamercolor{block title}{fg=black,bg=}%
+ \setbeamerfont*{block title}{family=\sffamily,series=\bfseries,size=\large}
+ \begin{block}#2{#1}%
+ }{\end{block}%
+\endgroup}
+
+
+\newenvironment<>{greenblock}[1]{\begingroup%
+ \setbeamercolor{block body}{fg=black,bg=kit-green15}%
+ \setbeamercolor{block title}{fg=white,bg=kit-green100}%
+ \begin{block}#2{#1}%
+ }{\end{block}
+\endgroup}
+
+\newenvironment<>{blueblock}[1]{\begingroup%
+ \setbeamercolor{block body}{fg=black,bg=kit-blue15}%
+ \setbeamercolor{block title}{fg=white,bg=kit-blue100}%
+ \setbeamercolor{itemize item}{fg=kit-blue100}
+ \begin{block}#2{#1}%
+ }{\end{block}
+\endgroup}
+
+\newenvironment<>{redblock}[1]{\begingroup%
+ \setbeamercolor{block body}{fg=black,bg=kit-red15}%
+ \setbeamercolor{block title}{fg=white,bg=kit-red100}%
+ \setbeamercolor{itemize item}{fg=kit-red100}%
+ \begin{block}#2{#1}%
+ }{\end{block}%
+\endgroup}
+
+\newenvironment<>{brownblock}[1]{\begingroup%
+ \setbeamercolor{block body}{fg=black,bg=kit-brown15}%
+ \setbeamercolor{block title}{fg=white,bg=kit-brown100}%
+ \setbeamercolor{itemize item}{fg=kit-brown100}%
+ \begin{block}#2{#1}%
+ }{\end{block}%
+\endgroup}
+
+\newenvironment<>{purpleblock}[1]{\begingroup%
+ \setbeamercolor{block body}{fg=black,bg=kit-purple15}%
+ \setbeamercolor{block title}{fg=white,bg=kit-purple100}%
+ \setbeamercolor{itemize item}{fg=kit-purple100}%
+ \begin{block}#2{#1}%
+ }{\end{block}%
+\endgroup}
+
+\newenvironment<>{grayblock}[1]{\begingroup%
+ \setbeamercolor{block body}{fg=black,bg=kit-gray15}%
+ \setbeamercolor{block title}{fg=white,bg=kit-gray70}%
+ \setbeamercolor{itemize item}{fg=kit-gray70}%
+ \begin{block}#2{#1}%
+ }{\end{block}%
+\endgroup}
+
+\newenvironment<>{yellowblock}[1]{\begingroup%
+ \setbeamercolor{block body}{fg=black,bg=kit-yellow30}%
+ \setbeamercolor{block title}{fg=black,bg=kit-yellow100}%
+ \setbeamercolor{itemize item}{fg=kit-yellow100}%
+ \begin{block}#2{#1}%
+ }{\end{block}%
+\endgroup}
+
+\newenvironment<>{lightgreenblock}[1]{\begingroup%
+ \setbeamercolor{block body}{fg=black,bg=kit-lightgreen15}%
+ \setbeamercolor{block title}{fg=white,bg=kit-lightgreen100}%
+ \setbeamercolor{itemize item}{fg=kit-lightgreen100}%
+ \begin{block}#2{#1}%
+ }{\end{block}%
+\endgroup}
+
+\newenvironment<>{orangeblock}[1]{\begingroup%
+ \setbeamercolor{block body}{fg=black,bg=kit-orange15}%
+ \setbeamercolor{block title}{fg=white,bg=kit-orange100}%
+ \setbeamercolor{itemize item}{fg=kit-orange100}%
+ \begin{block}#2{#1}%
+ }{\end{block}%
+\endgroup}
+
+\newenvironment<>{cyanblock}[1]{\begingroup%
+ \setbeamercolor{block body}{fg=black,bg=kit-cyan15}%
+ \setbeamercolor{block title}{fg=white,bg=kit-cyan100}%
+ \setbeamercolor{itemize item}{fg=kit-cyan100}%
+ \begin{block}#2{#1}%
+ }{\end{block}%
+\endgroup}
+
+\newenvironment<>{maroonblock}[1]{\begingroup%
+\setbeamercolor{block body}{fg=black,bg=Maroon!15}%
+\setbeamercolor{block title}{fg=white,bg=Maroon}%
+ \setbeamercolor{itemize item}{fg=Maroon}%
+\begin{block}#2{#1}%
+}{\end{block}%
+\endgroup}
+%% ------------------------------
+%% | /Block-Definitionen |
+%% ------------------------------
+
+%% use this for setting the total page number
+\newcommand{\beginbackup}{
+ \newcounter{framenumbervorappendix}
+ \setcounter{framenumbervorappendix}{\value{framenumber}}
+}
+\newcommand{\backupend}{
+ \addtocounter{framenumbervorappendix}{-\value{framenumber}}
+ \addtocounter{framenumber}{\value{framenumbervorappendix}}
+}
diff --git a/31-qualitaetsheft-kolloquium/slides/changes.tex b/31-qualitaetsheft-kolloquium/slides/changes.tex
new file mode 100644
index 0000000..e90113a
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/slides/changes.tex
@@ -0,0 +1,146 @@
+\begin{frame}{Änderungen zur Implementierung}
+
+%\vspace{-.4cm}
+%\begin{orangeblock}{Kompatibilität}
+% \begin{minipage}{1.7cm}
+% \centering
+% \fontsize{23pt}{0pt}
+% \selectfont
+% \textcolor{orange}
+% \faPlug
+% \end{minipage}
+% \hspace{-.5cm}
+% \begin{minipage}{.7\textwidth}
+% \begin{itemize}
+% \item Benutzernamen und E-Mail-Adresse speichern
+% \item Device API
+% \end{itemize}
+% \end{minipage}
+%\end{orangeblock}
+%
+%\begin{greenblock}{E-Mail-Verifizierung}
+% \begin{minipage}{1.7cm}
+% \centering
+% \fontsize{23pt}{0pt}
+% \selectfont
+% \textcolor{kit-green}
+% \faUserCheck
+% \end{minipage}
+% \hspace{-.5cm}
+% \begin{minipage}{.7\textwidth}
+% \begin{itemize}
+% \item Neuer Endpunkt zur Verifizierung der E-Mail-Adresse
+% \item Anmelden nur mit bestätigter E-Mail-Adresse
+% \end{itemize}
+% \end{minipage}
+%\end{greenblock}
+%
+%\begin{blueblock}{RSS Parser}
+% \begin{minipage}{1.7cm}
+% \centering
+% \fontsize{23pt}{0pt}
+% \selectfont
+% \textcolor{kit-blue}
+% \faRssSquare
+% \end{minipage}
+% \hspace{-.5cm}
+% \begin{minipage}{.7\textwidth}
+% \begin{itemize}
+% \item Asynchroner RSS Parser nach \enquote{Fire and Forget} Prinzip
+% \item Speichern/Löschen über Referenzen in DAO-Schicht
+% \end{itemize}
+% \end{minipage}
+%\end{blueblock}
+%
+%\begin{redblock}{Datenzugriffsschicht}
+% \begin{minipage}{1.7cm}
+% \centering
+% \fontsize{23pt}{0pt}
+% \selectfont
+% \textcolor{kit-red}
+% \faDatabase
+% \end{minipage}
+% \hspace{-.5cm}
+% \begin{minipage}{.7\textwidth}
+% \begin{itemize}
+% \item \sout{DAO-Implementierungen} (JPA-Repository)
+% \end{itemize}
+% \end{minipage}
+%\end{redblock}
+
+%
+% Original
+%
+%\begin{itemize}
+% \item Kompatibilität mit Podcatchern \begin{itemize}
+% \item Speicherung von Benutzernamen und E-Mail-Adressen
+% \item Device API
+% \end{itemize}
+% \item Verifizierung der E-Mail-Adresse
+% \item RSSParser
+% \item Reduzierte Datenzugriffsschicht
+%\end{itemize}
+
+%
+% Konzept
+%
+%\begin{itemize}
+% \item Neu erfüllte Kriterien \begin{itemize}
+% \item 50 Anfragen / Sekunde (bedingt)
+% \item Abonnements in Weboberfläche deabonnieren
+% \end{itemize}
+% \item Aussagekräftige Benachrichtigungen im Frontend
+%\end{itemize}
+
+\begin{orangeblock}{Performance}
+ \begin{minipage}{1.7cm}
+ \centering
+ \fontsize{23pt}{0pt}
+ \selectfont
+ \textcolor{orange}
+ \faTachometer
+ \end{minipage}
+ \hspace{-.5cm}
+ \begin{minipage}{.7\textwidth}
+ \begin{itemize}
+ \item 50 Anfragen / Sekunde bedingt möglich
+ \item Die Systemanforderungen für dieses Kriterium liegen über den Mindestanforderungen
+ \end{itemize}
+ \end{minipage}
+\end{orangeblock}
+
+\begin{redblock}{Deabonnieren in der Weboberfläche}
+ \begin{minipage}{1.7cm}
+ \centering
+ \fontsize{23pt}{0pt}
+ \selectfont
+ \textcolor{kit-red}
+ \faMinusCircle
+ \end{minipage}
+ \hspace{-.5cm}
+ \begin{minipage}{.7\textwidth}
+ \begin{itemize}
+ \item Deabonnieren von Podcasts im Dashboard nun möglich
+ \item Über Checkboxen auch mehrere auf einmal deabonnieren
+ \end{itemize}
+ \end{minipage}
+\end{redblock}
+
+\begin{blueblock}{Aussagekräftige Benachrichtigungen im Frontend}
+ \begin{minipage}{1.7cm}
+ \centering
+ \fontsize{23pt}{0pt}
+ \selectfont
+ \textcolor{kit-blue}
+ \faExclamationCircle
+ \end{minipage}
+ \hspace{-.5cm}
+ \begin{minipage}{.7\textwidth}
+ \begin{itemize}
+ \item Fehlermeldungen sind nun verständlicher
+ \item Erfolgreiche Aktionen werden Nutzer über Meldungen mitgeteilt
+ \end{itemize}
+ \end{minipage}
+\end{blueblock}
+
+\end{frame}
diff --git a/31-qualitaetsheft-kolloquium/slides/classdiagram.tex b/31-qualitaetsheft-kolloquium/slides/classdiagram.tex
new file mode 100644
index 0000000..3186a53
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/slides/classdiagram.tex
@@ -0,0 +1,36 @@
+\begin{frame}[t]{Einführung}
+ \centering
+ \includegraphics[width=\textwidth]{assets/diagrams/classdiagram}
+\end{frame}
+
+% sub
+% episode
+% auth
+% model
+% util
+
+\begin{frame}[t]{Subscriptions-API}
+ \centering
+ \includegraphics[width=\textwidth]{assets/diagrams/classdiagram-subscriptions}
+\end{frame}
+
+\begin{frame}[t]{EpisodeActions-API}
+ \centering
+ \includegraphics[width=\textwidth]{assets/diagrams/classdiagram-episode-actions}
+\end{frame}
+
+\begin{frame}[t]{Authentication-API}
+ \centering
+ \includegraphics[width=.75\textwidth]{assets/diagrams/classdiagram-authentication}
+\end{frame}
+
+\begin{frame}[t]{Model-Paket}
+ \centering
+ \includegraphics[width=\textwidth]{assets/diagrams/classdiagram-model}
+\end{frame}
+
+\begin{frame}[t]{Util-Paket}
+ \centering
+ \includegraphics[width=\textwidth]{assets/diagrams/classdiagram-util}
+\end{frame}
+
diff --git a/31-qualitaetsheft-kolloquium/slides/codestyle.tex b/31-qualitaetsheft-kolloquium/slides/codestyle.tex
new file mode 100644
index 0000000..5c82885
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/slides/codestyle.tex
@@ -0,0 +1,179 @@
+\definecolor{error00}{RGB}{255, 0, 0}
+\definecolor{error01}{RGB}{204, 0, 0}
+\definecolor{error02}{RGB}{153, 0, 0}
+\definecolor{error03}{RGB}{102, 0, 0}
+\definecolor{error04}{RGB}{51, 0, 0}
+\definecolor{error05}{RGB}{25, 0, 0}
+
+\definecolor{warning00}{RGB}{255, 255, 0}
+\definecolor{warning01}{RGB}{255, 215, 0}
+\definecolor{warning02}{RGB}{139, 117, 0}
+\definecolor{warning03}{RGB}{238, 201, 0}
+\definecolor{warning04}{RGB}{255, 215, 0}
+\definecolor{warning05}{RGB}{238, 238, 0}
+\definecolor{warning06}{RGB}{139, 139, 0}
+\definecolor{warning07}{RGB}{255, 255, 0}
+\definecolor{warning08}{RGB}{238, 201, 0}
+\definecolor{warning09}{RGB}{205, 173, 0}
+\definecolor{warning10}{RGB}{205, 205, 0}
+\definecolor{warning11}{RGB}{205, 173, 0}
+\definecolor{warning12}{RGB}{238, 238, 0}
+\definecolor{warning13}{RGB}{139, 117, 0}
+\definecolor{warning14}{RGB}{139, 139, 0}
+
+\begin{frame}{Codestil: Server}
+% Balkendiagram:
+% zwei Balken: vorher, nachher
+% eine Balken besteht aus verschiedenen Ebenen für jeden Linter Fehler
+
+\vspace{-.7cm}
+\begin{multicols}{2}
+\hspace{-0.5cm}
+\begin{tikzpicture}
+\begin{axis}[
+ title={Code-Stil-Anmerkungen durch Checkstyle Sun-Checks},
+ title style={align=left, at={(.45,1)}},
+ ybar stacked, ymin=0,
+ bar width=10mm,
+ symbolic x coords={Vorher,Nachher},
+ xtick=data,
+ xticklabel style={text width=2cm,align=center},
+ nodes near coords={}
+]
+
+\addplot [fill=error02] coordinates { ({Vorher}, 285 ) ({Nachher}, 0)}; % (sizes) LineLength
+\addplot [fill=error00] coordinates { ({Vorher}, 143 ) ({Nachher}, 0)}; % (misc) FinalParameters
+\addplot [fill=error03] coordinates { ({Vorher}, 101 ) ({Nachher}, 0)}; % (javadoc) JavadocVariable
+\addplot [fill=error04] coordinates { ({Vorher}, 83 ) ({Nachher}, 0)}; % (javadoc) JavadocStyle
+\addplot [fill=error02] coordinates { ({Vorher}, 43 ) ({Nachher}, 0)}; % (design) DesignForExtension
+\addplot [fill=error01] coordinates { ({Vorher}, 39 ) ({Nachher}, 0)}; % (javadoc) MissingJavadocMethod
+\addplot [fill=error01] coordinates { ({Vorher}, 26 ) ({Nachher}, 0)}; % (regexp) RegexpSingleline
+\addplot [fill=error02] coordinates { ({Vorher}, 15 ) ({Nachher}, 0)}; % (whitespace) WhitespaceAround
+\addplot [fill=error01] coordinates { ({Vorher}, 13 ) ({Nachher}, 0)}; % (javadoc) JavadocPackage
+\addplot [fill=error03] coordinates { ({Vorher}, 10 ) ({Nachher}, 0)}; % (whitespace) OperatorWrap
+\addplot [fill=error00] coordinates { ({Vorher}, 10 ) ({Nachher}, 0)}; % (javadoc) JavadocType
+\addplot [fill=error05] coordinates { ({Vorher}, 7 ) ({Nachher}, 0)}; % (imports) AvoidStarImport
+\addplot [fill=error05] coordinates { ({Vorher}, 6 ) ({Nachher}, 0)}; % (coding) MagicNumber
+\addplot [fill=error05] coordinates { ({Vorher}, 4 ) ({Nachher}, 0)}; % (javadoc) JavadocMethod
+\addplot [fill=error04] coordinates { ({Vorher}, 3 ) ({Nachher}, 0)}; % (coding) HiddenField
+\addplot [fill=error02] coordinates { ({Vorher}, 2 ) ({Nachher}, 0)}; % (javadoc) InvalidJavadocPosition
+\addplot [fill=error00] coordinates { ({Vorher}, 2 ) ({Nachher}, 0)}; % (blocks) RightCurly
+\addplot [fill=error03] coordinates { ({Vorher}, 1 ) ({Nachher}, 0)}; % (whitespace) WhitespaceAfter
+\addplot [fill=error04] coordinates { ({Vorher}, 1 ) ({Nachher}, 0)}; % (whitespace) FileTabCharacter
+\addplot [fill=error04] coordinates { ({Vorher}, 1 ) ({Nachher}, 0)}; % (misc) NewlineAtEndOfFile
+\addplot [fill=error01] coordinates { ({Vorher}, 1 ) ({Nachher}, 0)}; % (misc) ArrayTypeStyle
+\addplot [fill=error00] coordinates { ({Vorher}, 1 ) ({Nachher}, 0)}; % (imports) UnusedImports
+\addplot [fill=error03, point meta=y,nodes near coords,nodes near coords align={anchor=south}] coordinates { ({Vorher}, 2 ) ({Nachher}, 1)}; % (design) HideUtilityClassConstructor
+
+\end{axis}
+\end{tikzpicture}
+
+\small
+\renewcommand{\arraystretch}{0.8}
+\begin{tabularx}{.5\textwidth}{X | c | c}
+ Regel & Vorher & Nacher \\ \hline
+ sizes: LineLength & 285 & 0 \\
+ misc: FinalParameters & 143 & 0 \\
+ javadoc: JavadocVariable & 101 & 0 \\
+ javadoc: JavadocStyle & 83 & 0 \\
+ design: DesignForExtension & 43 & 0 \\
+ javadoc: MissingJavadocMethod & 39 & 0 \\
+ regexp: RegexpSingleline & 26 & 0 \\
+ whitespace: WhitespaceAround & 15 & 0 \\
+ javadoc: JavadocPackage & 13 & 0 \\
+ whitespace: OperatorWrap & 10 & 0 \\
+ javadoc: JavadocType & 10 & 0 \\
+ imports: AvoidStarImport & 7 & 0 \\
+ coding: MagicNumber & 6 & 0 \\
+ javadoc: JavadocMethod & 4 & 0 \\
+ coding: HiddenField & 3 & 0 \\
+ javadoc: InvalidJavadocPosition & 2 & 0 \\
+ blocks: RightCurly & 2 & 0 \\
+ whitespace: WhitespaceAfter & 1 & 0 \\
+ whitespace: FileTabCharacter & 1 & 0 \\
+ misc: NewlineAtEndOfFile & 1 & 0 \\
+ misc: ArrayTypeStyle & 1 & 0 \\
+ imports: UnusedImports & 1 & 0 \\
+ design: HideUtilityClassConstructor & 2 & 1 \\
+\end{tabularx}
+\end{multicols}
+
+\end{frame}
+
+
+\begin{frame}{Codestil: Dashboard}
+% Balkendiagram:
+% zwei Balken: vorher, nachher
+% eine Balken besteht aus verschiedenen Ebenen für jeden Linter Fehler
+
+\vspace{-.7cm}
+\begin{multicols}{2}
+\hspace{-0.5cm}
+\begin{tikzpicture}
+\begin{axis}[
+ title={Code-Stil-Anmerkungen durch ESLint},
+ title style={align=left, at={(.3,1)}},
+ ybar stacked, ymin=0,
+ bar width=10mm,
+ symbolic x coords={Vorher,Nachher},
+ xtick=data,
+ xticklabel style={text width=2cm,align=center},
+ nodes near coords={},
+ legend style={draw=none}
+]
+
+\addplot [fill=error00] coordinates { ({Vorher}, 26 ) ({Nachher}, 0)}; % error vue/html-indent
+\addplot [fill=error01] coordinates { ({Vorher}, 17 ) ({Nachher}, 0)}; % error vue/script-indent
+\addplot [fill=error02] coordinates { ({Vorher}, 6 ) ({Nachher}, 0)}; % error vue/require-v-for-key
+\addplot [fill=error03] coordinates { ({Vorher}, 5 ) ({Nachher}, 0)}; % error vue/multi-word-component-names
+\addplot [fill=error04] coordinates { ({Vorher}, 1 ) ({Nachher}, 0)}; % error vue/valid-v-for
+\addplot [fill=error05] coordinates { ({Vorher}, 1 ) ({Nachher}, 0)}; % error vue/valid-template-root
+\addplot [fill=warning00] coordinates { ({Vorher}, 125 ) ({Nachher}, 0)}; % warning vue/max-attributes-per-line
+\addplot [fill=warning01] coordinates { ({Vorher}, 34 ) ({Nachher}, 0)}; % warning vue/attributes-order
+\addplot [fill=warning02] coordinates { ({Vorher}, 26 ) ({Nachher}, 0)}; % warning vue/singleline-html-element-content-newline
+\addplot [fill=warning03] coordinates { ({Vorher}, 12 ) ({Nachher}, 0)}; % warning vue/require-default-prop
+\addplot [fill=warning04] coordinates { ({Vorher}, 12 ) ({Nachher}, 0)}; % warning vue/html-self-closing
+\addplot [fill=warning05] coordinates { ({Vorher}, 11 ) ({Nachher}, 0)}; % warning vue/first-attribute-linebreak
+\addplot [fill=warning06] coordinates { ({Vorher}, 10 ) ({Nachher}, 0)}; % warning vue/html-closing-bracket-newline
+\addplot [fill=warning07] coordinates { ({Vorher}, 8 ) ({Nachher}, 0)}; % warning vue/multiline-html-element-content-newline
+\addplot [fill=warning08] coordinates { ({Vorher}, 5 ) ({Nachher}, 0)}; % warning vue/html-closing-bracket-spacing
+\addplot [fill=warning09] coordinates { ({Vorher}, 3 ) ({Nachher}, 0)}; % warning vue/require-prop-types
+\addplot [fill=warning10] coordinates { ({Vorher}, 3 ) ({Nachher}, 0)}; % warning vue/attribute-hyphenation
+\addplot [fill=warning11] coordinates { ({Vorher}, 2 ) ({Nachher}, 0)}; % warning vue/html-self-closing
+\addplot [fill=warning12] coordinates { ({Vorher}, 1 ) ({Nachher}, 0)}; % warning vue/v-on-event-hyphenation
+\addplot [fill=warning13] coordinates { ({Vorher}, 1 ) ({Nachher}, 0)}; % warning vue/no-v-html
+\addplot +[fill=warning14, point meta=y,nodes near coords,nodes near coords align={anchor=south}]coordinates { ({Vorher}, 1 ) ({Nachher}, 1)}; % warning vue/mustache-interpolation-spacing
+
+\end{axis}
+\end{tikzpicture}
+
+\small
+\renewcommand{\arraystretch}{0.8}
+\setlength{\tabcolsep}{1pt}
+\begin{tabularx}{.54\textwidth}{X | c | c}
+ Regel & Vorher & Nachher \\ \hline
+ error: html-indent & 26 & 0 \\
+ error: script-indent & 17 & 0 \\
+ error: require-v-for-key & 6 & 0 \\
+ error: multi-word-component-names & 5 & 0 \\
+ error: valid-v-for & 1 & 0 \\
+ error: valid-template-root & 1 & 0 \\
+ warning: max-attributes-per-line & 125 & 0 \\
+ warning: attributes-order & 34 & 0 \\
+ warning: singleline-html-element-content-newline & 26 & 0 \\
+ warning: require-default-prop & 12 & 0 \\
+ warning: html-self-closing & 12 & 0 \\
+ warning: first-attribute-linebreak & 11 & 0 \\
+ warning: html-closing-bracket-newline & 10 & 0 \\
+ warning: multiline-html-element-content-newline & 8 & 0 \\
+ warning: html-closing-bracket-spacing & 5 & 0 \\
+ warning: require-prop-types & 3 & 0 \\
+ warning: attribute-hyphenation & 3 & 0 \\
+ warning: html-self-closing & 2 & 0 \\
+ warning: v-on-event-hyphenation & 1 & 0 \\
+ warning: mustache-interpolation-spacing & 1 & 0 \\
+ warning: no-v-html & 1 & 1 \\
+\end{tabularx}
+\end{multicols}
+
+\end{frame}
diff --git a/31-qualitaetsheft-kolloquium/slides/components.tex b/31-qualitaetsheft-kolloquium/slides/components.tex
new file mode 100644
index 0000000..5a6afe6
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/slides/components.tex
@@ -0,0 +1,7 @@
+\begin{frame}[t]{Komponenten Backend}
+
+ \begin{figure}[h]
+ \includegraphics[width=0.7\textwidth]{assets/diagrams/backendComponentDiagram}
+ \end{figure}
+
+\end{frame} \ No newline at end of file
diff --git a/31-qualitaetsheft-kolloquium/slides/coverage.tex b/31-qualitaetsheft-kolloquium/slides/coverage.tex
new file mode 100644
index 0000000..51d39ea
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/slides/coverage.tex
@@ -0,0 +1,23 @@
+\begin{frame}{Codeüberdeckung}
+ \vspace{-.4cm}
+ \begin{figure}[t]
+ \centering
+ \includegraphics[width=\textwidth,height=\textheight,keepaspectratio]{assets/coverage/server.png}
+ \end{figure}
+ \begin{redblock}{Lücken}
+ \begin{minipage}{1.7cm}
+ \centering
+ \fontsize{23pt}{0pt}
+ \selectfont
+ \textcolor{kit-red}
+ \faCode
+ \end{minipage}
+ \hspace{-.5cm}
+ \begin{minipage}{.7\textwidth}
+ \begin{itemize}
+ \item Model-Klassen (intern) und Controller (extern) implizit abgedeckt
+ \item Lombok, Spring und JPA Repositories
+ \end{itemize}
+ \end{minipage}
+ \end{redblock}
+\end{frame} \ No newline at end of file
diff --git a/31-qualitaetsheft-kolloquium/slides/difficulties.tex b/31-qualitaetsheft-kolloquium/slides/difficulties.tex
new file mode 100644
index 0000000..d3e64dd
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/slides/difficulties.tex
@@ -0,0 +1,34 @@
+\begin{frame}{Schwierigkeiten}
+
+ \begin{columns}[t]
+
+ \begin{column}{.5\textwidth}
+ \centering{\fontsize{30pt}{36pt}\selectfont\faDesktop}
+ \vspace{.2cm}
+ \begin{blueblock}{Dashboard}
+ \begin{itemize}
+ \item CORS Einschränkung
+ \item Error-Handling
+ \item Kommunikation zwischen Komponenten
+ \end{itemize}
+ \end{blueblock}
+ \end{column}
+
+ \begin{column}{.5\textwidth}
+ \centering{\fontsize{30pt}{36pt}\selectfont\faServer}
+ \vspace{.2cm}
+ \begin{orangeblock}{Server}
+ \begin{itemize}
+ \item Authentifizierung
+ \item API
+ \item EpisodeActionService (AntennaPod)
+ \end{itemize}
+ \end{orangeblock}
+ \end{column}
+
+
+ \end{columns}
+
+
+\end{frame}
+
diff --git a/31-qualitaetsheft-kolloquium/slides/einführung.tex b/31-qualitaetsheft-kolloquium/slides/einführung.tex
new file mode 100644
index 0000000..d818cd3
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/slides/einführung.tex
@@ -0,0 +1,40 @@
+\begin{frame}[t]{Einführung}
+
+
+ \begin{columns}[t]
+ \begin{column}{.3\textwidth}
+ \centering{\fontsize{30pt}{36pt}\selectfont\faPodcast}
+ \vspace{.2cm}
+ \begin{block}{Podcast}
+ \begin{itemize}
+ \item RSS-Feed
+ \item Episoden
+ \item Audio/Video
+ \end{itemize}
+ \end{block}
+ \end{column}
+ \begin{column}{.3\textwidth}
+ \centering{\fontsize{30pt}{36pt}\selectfont\faArrowCircleDown}
+ \vspace{.2cm}
+ \begin{block}{Podcatcher}
+ \begin{itemize}
+ \item lokale Verwaltung von Podcasts
+ \item API Unterstützung
+ \item Abspielen von Episoden
+ \end{itemize}
+ \end{block}
+ \end{column}
+ \begin{column}{.3\textwidth}
+ \centering{\fontsize{30pt}{36pt}\selectfont\faSync}
+ \vspace{.2cm}
+ \begin{block}{Synchronisationsserver}
+ \begin{itemize}
+ \item Hörfortschritte
+ \item Abonnements
+ \item Discovery
+ \end{itemize}
+ \end{block}
+ \end{column}
+ \end{columns}
+
+\end{frame} \ No newline at end of file
diff --git a/31-qualitaetsheft-kolloquium/slides/features.tex b/31-qualitaetsheft-kolloquium/slides/features.tex
new file mode 100644
index 0000000..6ec435b
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/slides/features.tex
@@ -0,0 +1,37 @@
+\begin{frame}{Features}
+\begin{columns}[t]
+\begin{column}{.3\textwidth}
+\centering{\fontsize{30pt}{36pt}\selectfont\faSync}
+\vspace{.2cm}
+\begin{block}{Synchronisation}
+\begin{itemize}
+ \item Abos
+ \item Hörfortschritt
+\end{itemize}
+\end{block}
+\end{column}
+\begin{column}{.3\textwidth}
+\centering{\fontsize{30pt}{36pt}\selectfont\faGlobe}
+\vspace{.2cm}
+\begin{block}{Weboberfläche}
+\begin{itemize}
+ \item Aboliste
+ \item Zuletzt gehört
+\end{itemize}
+\end{block}
+\end{column}
+\begin{column}{.3\textwidth}
+\centering{\fontsize{30pt}{36pt}\selectfont\faUser}
+\vspace{.2cm}
+\begin{block}{Account-Verwaltung}
+\begin{itemize}
+ \item Registrieren und Anmelden
+ \item Passwort ändern und zurücksetzen
+ \item Account löschen
+ \item Daten importieren/exportieren
+\end{itemize}
+\end{block}
+\end{column}
+\end{columns}
+\end{frame}
+
diff --git a/31-qualitaetsheft-kolloquium/slides/gantt.tex b/31-qualitaetsheft-kolloquium/slides/gantt.tex
new file mode 100644
index 0000000..31ed9b9
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/slides/gantt.tex
@@ -0,0 +1,11 @@
+\begin{frame}{Geplanter Zeitplan}
+
+\includegraphics[width=\textwidth]{assets/gantt-plan.eps}
+
+\end{frame}
+\begin{frame}{Tatsächlicher Zeitplan}
+
+\includegraphics[width=\textwidth]{assets/gantt-reality.eps}
+
+\end{frame}
+
diff --git a/31-qualitaetsheft-kolloquium/slides/integrationstrategie.tex b/31-qualitaetsheft-kolloquium/slides/integrationstrategie.tex
new file mode 100644
index 0000000..0564b5f
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/slides/integrationstrategie.tex
@@ -0,0 +1,82 @@
+\begin{frame}{Integrationsstrategie}
+
+\vspace{-.5cm}
+\begin{minipage}[t]{.47\textwidth}
+ \begin{orangeblock}{Top-Down}
+ \begin{minipage}{1.6cm}
+ \centering
+ \vspace{.15cm}
+ \fontsize{30pt}{36pt}
+ \selectfont
+ \faSortAmountDown
+ \vspace{.2cm}
+ \end{minipage}
+ \hspace{-.5cm}
+ \begin{minipage}{\textwidth - 1.4cm}
+ \begin{itemize}
+ \item Schnelle anschauliche Ergebnisse
+ \item Integration von Dashboard aus zum Server
+ \item spätes Zusammenspiel mit Backend
+ \item Aufwendige/Schwere Tests
+ \end{itemize}
+ \end{minipage}
+ \end{orangeblock}
+\end{minipage}
+\hfill
+\begin{minipage}[t]{.47\textwidth}
+ \begin{greenblock}{Bottom-Up}
+ \begin{minipage}{1.6cm}
+ \centering
+ \vspace{.2cm}
+ \fontsize{30pt}{36pt}
+ \selectfont
+ {\faSortAmountUp*}
+ \vspace{.25cm}
+ \end{minipage}
+ \hspace{-.5cm}
+ \begin{minipage}{\textwidth - 1.4cm}
+ \begin{itemize}
+ \item Integration von Datenbank aus zum Dashboard
+ \item viele einfache Tests sind erforderlich
+ \item spätes Zusammenspiel mit Frontend
+ \end{itemize}
+ \end{minipage}
+ \end{greenblock}
+\end{minipage}
+\vspace{.3cm}
+
+\begin{blueblock}{Outside-In}
+ \begin{minipage}{2cm}
+ \centering
+ \vspace{.2cm}
+ \fontsize{30pt}{36pt}
+ \selectfont
+ \faCompressArrows*
+ \vspace{.3cm}
+ \end{minipage}
+ \hspace{-.5cm}
+ \begin{minipage}{\textwidth - 2cm}
+ \begin{itemize}
+ \item Vereinigt Vorteile von Bottom-Up und Top-Down
+ \item Implementierung von Dashboard und Server gleichzeitig
+ \item Schnelle Tests + anschauliche Ergebnisse
+ \item Gut Parallelisierbar auf ganze Team
+ \end{itemize}
+ \end{minipage}
+\end{blueblock}
+
+% \begin{greenblock}{Outside-In Prinzip}
+% \begin{itemize}
+% \item Eine Kombination aus dem Bottom-Up und Top-Down Prinzip
+% \item Beginnt gleichzeitig auf höchster und niedrigster Logischer Ebene
+% \item Schrittweise Integration aus beiden Richtungen
+% \begin{itemize}
+% \item Model und Datenbank
+% \item Controller und Frontend
+% \end{itemize}
+% \item Frühzeitiges testen der Endpunkte und Unit Tests
+% \item Gut Parallelisierbar auf ganze Team
+% \end{itemize}
+% \end{greenblock}
+
+\end{frame}
diff --git a/31-qualitaetsheft-kolloquium/slides/pattern.tex b/31-qualitaetsheft-kolloquium/slides/pattern.tex
new file mode 100644
index 0000000..141954b
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/slides/pattern.tex
@@ -0,0 +1,12 @@
+\begin{frame}{Entwurfsmuster}
+ \begin{columns}
+ \column{.5\textwidth}
+ \begin{greenblock}{Dependency Injection}
+ Standard (\texttt{block})
+ \end{greenblock}
+ \column{.5\textwidth}
+ \begin{blueblock}{Data Access Object (DAO)}
+ = \texttt{exampleblock}
+ \end{blueblock}
+ \end{columns}
+\end{frame} \ No newline at end of file
diff --git a/31-qualitaetsheft-kolloquium/slides/performance.tex b/31-qualitaetsheft-kolloquium/slides/performance.tex
new file mode 100644
index 0000000..dd27226
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/slides/performance.tex
@@ -0,0 +1,56 @@
+\begin{frame}{Lasttests}
+ \begin{columns}[t]
+ \begin{column}{.48\textwidth}
+ \begin{orangeblock}{2 Kerne / 2GB RAM (mind. Anforderung)}
+ \begin{minipage}{.2\textwidth}
+ \centering
+ \vspace{.15cm}
+ \fontsize{30pt}{36pt}
+ \selectfont
+ \vspace{.2cm}
+ \end{minipage}
+ \begin{tabular}{l l}
+ \textbf{Antwortszeit} & 713,25 ms \\
+ \textbf{Durchsatz} & 10,85 Trans./s \\
+ \textbf{Apdex} & 0,563
+ \end{tabular}
+ \end{orangeblock}
+ \end{column}
+
+ \begin{column}{.48\textwidth}
+ \begin{greenblock}{8 Kerne / 32GB RAM}
+ \begin{minipage}{.2\textwidth}
+ \centering
+ \vspace{.2cm}
+ \fontsize{30pt}{36pt}
+ \selectfont
+ \vspace{.25cm}
+ \end{minipage}
+ \begin{tabular}{l l}
+ \textbf{Antwortszeit} & 81,15 ms \\
+ \textbf{Durchsatz} & 88,93 Trans./s \\
+ \textbf{Apdex} & 1,000
+ \end{tabular}
+ \end{greenblock}
+ \end{column}
+ \end{columns}
+ \vspace{.3cm}
+
+ \begin{blueblock}{Schlussfolgerung}
+ \begin{minipage}{1.7cm}
+ \centering
+ \fontsize{23pt}{0pt}
+ \selectfont
+ \textcolor{kit-blue}
+ \faArrowRight
+ \end{minipage}
+ \hspace{-.5cm}
+ \begin{minipage}{.7\textwidth}
+ \begin{itemize}
+ \item Mindestanforderungen bieten unter Last keine optimale Performance
+ \item Mit stärkerer Hardware kann Durchsatz von 50 Trans./s erreicht werden
+ \end{itemize}
+ \end{minipage}
+ \end{blueblock}
+
+\end{frame} \ No newline at end of file
diff --git a/31-qualitaetsheft-kolloquium/slides/problems.tex b/31-qualitaetsheft-kolloquium/slides/problems.tex
new file mode 100644
index 0000000..b3343a6
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/slides/problems.tex
@@ -0,0 +1,59 @@
+\begin{frame}{Herausforderungen}
+
+\vspace{-.4cm}
+
+\begin{orangeblock}{Falsche Zeitangaben}
+ \begin{minipage}{1.7cm}
+ \centering
+ \fontsize{23pt}{0pt}
+ \selectfont
+ \textcolor{orange}
+ \faClockO
+ \end{minipage}
+ \hspace{-.5cm}
+ \begin{minipage}{.7\textwidth}
+ \begin{itemize}
+ \item \textbf{Problem:} Zeit der letzten Podcastinteraktion falsch
+ \item \textbf{Ursache:} Lokale statt universelle Zeit zur Berechnung
+ \item \textbf{Behebung:} Explizite Verwendung von UTC
+ \end{itemize}
+ \end{minipage}
+\end{orangeblock}
+
+\begin{redblock}{AntennaPod Fehlermeldung}
+ \begin{minipage}{1.7cm}
+ \centering
+ \fontsize{23pt}{0pt}
+ \selectfont
+ \textcolor{kit-red}
+ \faWarning
+ \end{minipage}
+ \hspace{-.5cm}
+ \begin{minipage}{.7\textwidth}
+ \begin{itemize}
+ \item \textbf{Problem:} Bei Uploads gibt AntennaPod Fehler aus
+ \item \textbf{Ursache:} Falscher Parametername gesendet
+ \item \textbf{Behebung:} JsonProperty \texttt{updateURLs} zu \texttt{update\textunderscore urls} umbenannt
+ \end{itemize}
+ \end{minipage}
+\end{redblock}
+
+\begin{blueblock}{Doppelte Sicherung von EpisodeActions}
+ \begin{minipage}{1.7cm}
+ \centering
+ \fontsize{23pt}{0pt}
+ \selectfont
+ \textcolor{kit-blue}
+ \faClone
+ \end{minipage}
+ \hspace{-.5cm}
+ \begin{minipage}{.8\textwidth}
+ \begin{itemize}
+ \item \textbf{Problem:} Mehrere EpisodeActions pro Benutzer für eine Episode gespeichert
+ \item \textbf{Ursache:} Aufgrund von Effizienz - Spring ersetzt erst nach Sammeln der Daten
+ \item \textbf{Behebung:} EpisodeActions vor Speichern aussortieren
+ \end{itemize}
+ \end{minipage}
+\end{blueblock}
+
+\end{frame} \ No newline at end of file
diff --git a/31-qualitaetsheft-kolloquium/slides/requirements.tex b/31-qualitaetsheft-kolloquium/slides/requirements.tex
new file mode 100644
index 0000000..e660bb9
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/slides/requirements.tex
@@ -0,0 +1,58 @@
+\begin{frame}{Muss-Kriterien}
+\rowcolors{1}{kit-orange60}{kit-orange30}
+\begin{tabular}{ >{\bfseries}l l l}
+ \rowcolor{kit-orange}
+ Bezeichner & Zusammenfassung & Implementiert\\\hline
+ \textlangle RM1 \textrangle & Registrierung, Bestätigung und Anmeldung eines Accounts über das Frontend & Ja\\
+ \textlangle RM2 \textrangle & Speichern von Abonnements und Episoden auf dem Server & Ja\\
+ \textlangle RM3 \textrangle & Synchronisierung zwischen Podcatchern & Ja\\
+ \textlangle RM4 \textrangle & Eine Weboberfläche & Ja\\
+ \textlangle RM5 \textrangle & Möglichkeit das eigene Passwort zu ändern / zurückzusetzen & Ja\\
+ \textlangle RM6 \textrangle & Abonnementliste in der Weboberfläche & Ja\\
+ \textlangle RM7 \textrangle & 50 Anfragen / Sekunde bearbeiten & Zu testen\\
+ \textlangle RM8 \textrangle & Primäre Auslegung des Webfrontends für Desktop-Nutzer & Ja\\
+ \textlangle RM9 \textrangle & Unterstützung der gpodder.net RESTful-API & Ja\\
+ \textlangle RM10\textrangle & Das Nutzen einer Datenbank zur Speicherung von Daten & Ja\\
+ \textlangle RM11\textrangle & Erweiterte API für Kommunikation zwischen Front- und Backend & Ja
+\end{tabular}
+\end{frame}
+
+\begin{frame}{Soll-Kriterien}
+\rowcolors{1}{kit-green60}{kit-green30}
+\begin{tabular}{ >{\bfseries}l l l}
+ \rowcolor{kit-green}
+ Bezeichner & Zusammenfassung & Implementiert\\\hline
+ \textlangle RS1 \textrangle & Eine Anleitung (Platzhalter) & Ja\\
+ \textlangle RS2 \textrangle & Die Möglichkeit einen Account zu löschen & Ja\\
+ \textlangle RS3 \textrangle & Spring für das Backend und MariaDB als Datenbank & Ja\\
+ \textlangle RS4 \textrangle & Vue.js und Bootstrap für das Frontend & Ja\\
+ \textlangle RS5 \textrangle & npm und vite für das Frontend & Ja\\
+ \textlangle RS6 \textrangle & Eine Single-Page-Application als Frontend mit dynamischer Aktualisierung & Ja\\
+ \textlangle RS7 \textrangle & Ein RSS-Parser um Daten aus einem RSS-Feed zu lesen & Ja\\
+ \textlangle RS8 \textrangle & Mindestanforderungen an ein Passwort & Ja\\
+ \textlangle RS9 \textrangle & Salting und Hashing für Verschlüsselung der Personenbezogenen Daten & Ja\\
+ \textlangle RS10\textrangle & Nutzer bleibt über JWT angemeldet und authentifiziert & Ja
+\end{tabular}
+\end{frame}
+
+\begin{frame}{Kann-Kriterien}
+
+\rowcolors{1}{kit-blue60}{kit-blue30}
+\begin{tabular}{ >{\bfseries}l l l }
+ \rowcolor{kit-blue}
+ Bezeichner & Zusammenfassung & Implementiert\\\hline
+ \textlangle RC1 \textrangle & Abonnierten Podcast in Weboberfläche über Link teilen und hinzufügen & Ja\\
+ \textlangle RC2 \textrangle & Abonnements in Weboberfläche deabonnieren & Nein\\
+ \textlangle RC3 \textrangle & Importieren und Exportieren aller benutzerbezogenen Daten & Ja\\
+ \textlangle RC4 \textrangle & Umsiedeln von anderen Gpodder-Plattformen & Ja\\
+ \textlangle RC5 \textrangle & Kompatible Weboberfläche für beliebige gpodder.net APIs & Entfernt\\
+ \textlangle RC6 \textrangle & Responsive designte Weboberfläche & Ja\\
+ \textlangle RC7 \textrangle & Administratorkonten mit privilegierten Funktionen & Nein\\
+ \textlangle RC8 \textrangle & OAuth 2.0 im Webfrontend & Nein\\
+ \textlangle RC9 \textrangle & Bei Ausfall des Backends im Frontend angemeldet bleiben & Ja\\
+ \textlangle RC10\textrangle & Mehrsprachige Weboberfläche & Ja\\
+ \textlangle RC11\textrangle & Erfüllung der DSGVO & Teils\\
+ \textlangle RC12\textrangle & Docker für einfaches Deployment und Sicherheit & Ja
+\end{tabular}
+\end{frame}
+
diff --git a/31-qualitaetsheft-kolloquium/slides/statistics.tex b/31-qualitaetsheft-kolloquium/slides/statistics.tex
new file mode 100644
index 0000000..ed9b143
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/slides/statistics.tex
@@ -0,0 +1,85 @@
+\begin{frame}{Statistiken}
+
+\begin{columns}[t]
+ \begin{column}{.4\textwidth}
+ \begin{orangeblock}{Dashboard}
+ \centering
+ \begin{minipage}{.2\textwidth}
+ \centering
+ \vspace{.15cm}
+ \fontsize{30pt}{36pt}
+ \selectfont
+ \faDesktop
+ \vspace{.2cm}
+ \end{minipage}
+ \begin{tabular}{l l}
+ \textbf{SLOC} & 2020 Zeilen \\
+ \textbf{Commits} & 191 \\
+ \textbf{Dateien} & 38
+ \end{tabular}
+ \end{orangeblock}
+ \end{column}
+
+ \begin{column}{.4\textwidth}
+ \begin{greenblock}{Server}
+ \centering
+ \begin{minipage}{.2\textwidth}
+ \centering
+ \vspace{.2cm}
+ \fontsize{30pt}{36pt}
+ \selectfont
+ \faServer
+ \vspace{.25cm}
+ \end{minipage}
+ \begin{tabular}{l l}
+ \textbf{SLOC} & 3812 Zeilen \\
+ \textbf{Commits} & 305 \\
+ \textbf{Dateien} & 60
+ \end{tabular}
+ \end{greenblock}
+ \end{column}
+\end{columns}
+\vspace{.3cm}
+
+\centering
+\begin{minipage}{.9\textwidth}
+ \begin{blueblock}{Insgesamt}
+ \centering
+ \begin{minipage}{.5\textwidth}
+ \centering
+ \begin{minipage}{.2\textwidth}
+ \centering
+ \vspace{.2cm}
+ \fontsize{30pt}{36pt}
+ \selectfont
+ \faChartLine
+ \vspace{.3cm}
+ \end{minipage}
+ \begin{tabular}{l l}
+ \textbf{SLOC} & 5832 Zeilen \\
+ \textbf{Commits} & 486 \\
+ \textbf{Dateien} & 98
+ \end{tabular}
+
+ \end{minipage}
+ \end{blueblock}
+ \small SLOC und Anzahl der Dateien würden basierend der Inhalte des
+ Quellordners \texttt{src/} berechnet und beinhalten keine automatisch
+ generierten Dateien.
+\end{minipage}
+\end{frame}
+
+\begin{frame}{Zeitlicher Verlauf der Commits}
+ \textbf{Dashboard}
+ \includegraphics[width=\textwidth]{assets/commits-dashboard.png}
+ \textbf{Server}
+ \includegraphics[width=\textwidth]{assets/commits-server.png}
+\end{frame}
+
+\begin{frame}{Commit-Verteilung Server}
+ \includegraphics[width=\textwidth]{assets/contributors-server.png}
+\end{frame}
+
+\begin{frame}{Commit-Verteilung Dashboard}
+ \includegraphics[width=\textwidth]{assets/contributors-dashboard.png}
+\end{frame}
diff --git a/31-qualitaetsheft-kolloquium/slides/synchronisation.tex b/31-qualitaetsheft-kolloquium/slides/synchronisation.tex
new file mode 100644
index 0000000..0849279
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/slides/synchronisation.tex
@@ -0,0 +1,36 @@
+\begin{frame}{Synchronisation}
+
+ \tikzstyle{line} = [draw, -latex']
+
+ \begin{figure}[H]
+
+ \begin{tikzpicture}
+
+ \tikzset{focus/.style={rectangle, minimum width = 1cm, minimum height = 0.5cm, rounded corners, draw}};
+ \tikzset{hyperfocus/.style={rectangle, minimum width = 1cm, minimum height = 0.5cm, draw}};
+
+ \node[hyperfocus, text width = 2.6cm, fill = green!25](s){Synchronisations-\\\quad \quad Server};
+ \node[focus, left = 3cm of s, text width = 3.1cm, orange](p1){\quad \underline{p1:Podcatcher}
+ \begin{itemize}
+ \vspace{0.2cm}
+ \item Abonnements
+ \item Hörfortschritt
+ \vspace{0.1cm}
+ \end{itemize}};
+ \node[focus, above = 1.8cm of s, orange](p2){p2};
+ \node[focus, right = 2.5cm of s, orange](p3){p3};
+ \node[below = 1.7cm of s](p4){\textbf{...}};
+ \umlactor[left = 2.7cm of p2, blue!60]{Benutzer};
+
+ \draw[] (p1) -- (s);
+ \draw[] (p2) -- (s);
+ \draw[] (s) -- (p3);
+ \draw[] (s) -- (p4);
+ \path [line, thick, blue!60] (Benutzer) -- node [text width=2.5cm, midway, above=0.1cm, align=center] {Podcast abonnieren} (p2);
+ \path [line, thick, blue!60] (Benutzer) -| node [text width=2.5cm, midway, above=0.1cm, align=center] {Episode anhören} (p1);
+
+ \end{tikzpicture}
+
+ \end{figure}
+
+\end{frame} \ No newline at end of file
diff --git a/31-qualitaetsheft-kolloquium/slides/testing.tex b/31-qualitaetsheft-kolloquium/slides/testing.tex
new file mode 100644
index 0000000..0cc862b
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/slides/testing.tex
@@ -0,0 +1,59 @@
+\begin{frame}{Testfälle}
+
+ \begin{orangeblock}{Unit-Tests}
+ \begin{minipage}{1.7cm}
+ \centering
+ \fontsize{23pt}{0pt}
+ \selectfont
+ \textcolor{orange}
+ \faGears
+ \end{minipage}
+ \hspace{-.5cm}
+ \begin{minipage}{.9\textwidth}
+ \begin{itemize}
+ \item Grundlage für alle weiteren Testfälle
+ \item Nur für selbst geschriebene Klassen erstellt
+ \begin{itemize}
+ \item[\textbf{Vorher:}] 38 Testfälle in 610 Codezeilen für 1780 Quellcodezeilen
+ \item[\textbf{Nachher:}] 48 Testfälle in 1035 Codezeilen für 2081 Quellcodezeilen
+ \end{itemize}
+ \end{itemize}
+ \end{minipage}
+ \end{orangeblock}
+
+ \begin{greenblock}{Frontend-Testfälle aus dem Pflichtenheft}
+ \begin{minipage}{1.7cm}
+ \centering
+ \fontsize{23pt}{0pt}
+ \selectfont
+ \textcolor{kit-green}
+ \faDesktop
+ \end{minipage}
+ \hspace{-.5cm}
+ \begin{minipage}{.9\textwidth}
+ \begin{itemize}
+ \item Manuell ausgeführt
+ \item Nicht zu 100\% erfüllt
+ \item Link für das Zurücksetzen des Passworts bleibt nach Benutzung gültig (technisch bedingt)
+ \end{itemize}
+ \end{minipage}
+ \end{greenblock}
+
+ \begin{blueblock}{Synchronisations-Testfälle aus dem Pflichtenheft}
+ \begin{minipage}{1.7cm}
+ \centering
+ \fontsize{23pt}{0pt}
+ \selectfont
+ \textcolor{kit-blue}
+ \faRefresh
+ \end{minipage}
+ \hspace{-.5cm}
+ \begin{minipage}{.7\textwidth}
+ \begin{itemize}
+ \item Manuell (Podcatcher und Frontend) und automatisiert (Unit-Tests)
+ \item Ohne Einschränkungen erfüllt
+ \end{itemize}
+ \end{minipage}
+ \end{blueblock}
+
+\end{frame} \ No newline at end of file
diff --git a/31-qualitaetsheft-kolloquium/slides/zielsetzung.tex b/31-qualitaetsheft-kolloquium/slides/zielsetzung.tex
new file mode 100644
index 0000000..84e1064
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/slides/zielsetzung.tex
@@ -0,0 +1,39 @@
+\begin{frame}{Zielsetzung}
+
+\begin{figure}[H]
+
+\raggedright
+
+\begin{tikzpicture}
+
+\tikzset{focus/.style={rectangle, minimum width=1cm, minimum height=0.5cm, rounded corners=7pt, draw}};
+
+\tikzset{hyperfocus/.style={rectangle, minimum width=1cm, minimum height=0.5cm, draw}};
+
+\node[hyperfocus] (main) {gPodder};
+\node[focus, right = 2cm of main] (sync) {Synchronisation};
+\node[above = of sync] (share) {Inhalt teilen};
+\node[above = 0.5cm of share] (discover) {Podcasts entdecken};
+\node[text width = 3cm, below = of sync] (create) {Listen erstellen und teilen};
+\node[text width = 3cm, below = 0.5cm of create] (popular) {Publisher:\\ Was ist beliebt?};
+
+\node[hyperfocus, right = 3cm of sync, text width = 4cm] (PSE) {\underline{PSE\textsuperscript{2}}\begin{itemize}
+ \item Schlankes Design
+ \item Effizient
+ \item Intuitiv
+\end{itemize}
+};
+
+\draw[] (main) -- (sync);
+\draw[] (main) -- (share);
+\draw[] (main) |- (discover);
+\draw[] (main) -- (create);
+\draw[] (main) |- (popular);
+\draw[stealth-, thick] (sync.east) -- ($(PSE.north west) + (0, -0.3)$);
+
+
+\end{tikzpicture}
+
+\end{figure}
+
+\end{frame} \ No newline at end of file
diff --git a/31-qualitaetsheft-kolloquium/tikz-uml.sty b/31-qualitaetsheft-kolloquium/tikz-uml.sty
new file mode 100644
index 0000000..c6e8e0d
--- /dev/null
+++ b/31-qualitaetsheft-kolloquium/tikz-uml.sty
@@ -0,0 +1,5377 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Start of tikz-uml.sty
+%
+% Some macros for UML Diagrams.
+% Home page of project :
+% Author: Nicolas Kielbasiewicz
+% Style from :
+% Fixed by Nicolas Kielbasiewicz (nicolas.kielbasiewicz@ensta-paristech.fr) in march 2016 to compile with pgf 3.00
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+\NeedsTeXFormat{LaTeX2e}[1995/12/01]%
+\ProvidesPackage{tikz-uml}[2011/01/26]%
+%
+\RequirePackage{etoolbox}%
+\RequirePackage{ifthen}%
+\RequirePackage{tikz}%
+\RequirePackage{xstring}%
+\RequirePackage{calc}%
+\RequirePackage{pgfopts}%
+\usetikzlibrary{backgrounds,arrows,shapes,fit,shadows,decorations.markings}%
+%
+\def\tikzumlPackageLayersNum{3}%
+\pgfkeys{/tikzuml/options/.cd, packageLayers/.initial=3}%
+\pgfkeys{/tikzuml/options/.cd, packageLayers/.store in=\tikzumlPackageLayersNum}%
+\def\tikzumlStateLayersNum{3}%
+\pgfkeys{/tikzuml/options/.cd, stateLayers/.initial=3}%
+\pgfkeys{/tikzuml/options/.cd, stateLayers/.store in=\tikzumlStateLayersNum}%
+\def\tikzumlFragmentLayersNum{3}%
+\pgfkeys{/tikzuml/options/.cd, fragmentLayers/.initial=3}%
+\pgfkeys{/tikzuml/options/.cd, fragmentLayers/.store in=\tikzumlFragmentLayersNum}%
+\def\tikzumlComponentLayersNum{3}%
+\pgfkeys{/tikzuml/options/.cd, componentLayers/.initial=3}%
+\pgfkeys{/tikzuml/options/.cd, componentLayers/.store in=\tikzumlComponentLayersNum}%
+%
+\ProcessPgfOptions{/tikzuml/options}%
+%
+\def\pgfsetlayersArg{background}%
+\pgfdeclarelayer{background}%
+\newcounter{tikzumlPackageLayers}%
+\loop \pgfdeclarelayer{package\thetikzumlPackageLayers}%
+ \xdef\pgfsetlayersArg{\pgfsetlayersArg,package\thetikzumlPackageLayers}%
+ \ifnum\tikzumlPackageLayersNum>\thetikzumlPackageLayers%
+ \stepcounter{tikzumlPackageLayers}%
+\repeat%
+%
+\newcounter{tikzumlFragmentLayers}%
+\loop \pgfdeclarelayer{fragment\thetikzumlFragmentLayers}%
+ \xdef\pgfsetlayersArg{\pgfsetlayersArg,fragment\thetikzumlFragmentLayers}%
+ \ifnum\tikzumlFragmentLayersNum>\thetikzumlFragmentLayers%
+ \stepcounter{tikzumlFragmentLayers}%
+\repeat%
+%
+\newcounter{tikzumlStateLayers}%
+\loop \pgfdeclarelayer{state\thetikzumlStateLayers}%
+ \xdef\pgfsetlayersArg{\pgfsetlayersArg,state\thetikzumlStateLayers}%
+ \ifnum\tikzumlStateLayersNum>\thetikzumlStateLayers%
+ \stepcounter{tikzumlStateLayers}%
+\repeat%
+%
+\newcounter{tikzumlComponentLayers}%
+\loop \pgfdeclarelayer{component\thetikzumlComponentLayers}%
+ \xdef\pgfsetlayersArg{\pgfsetlayersArg,component\thetikzumlComponentLayers}%
+ \ifnum\tikzumlComponentLayersNum>\thetikzumlComponentLayers%
+ \stepcounter{tikzumlComponentLayers}%
+\repeat%
+%
+\pgfdeclarelayer{lifelines}%
+\pgfdeclarelayer{activity}%
+\pgfdeclarelayer{connections}%
+\xdef\pgfsetlayersArg{\pgfsetlayersArg,lifelines,activity,connections,main}%
+\pgfsetlayers{\pgfsetlayersArg}%
+%
+\pgfkeys{/tikzuml/.cd, text/.initial=black, draw/.initial=black, font/.initial=\small,%
+ x/.initial=0, y/.initial=0,%
+ package type/.initial=tikzumlEmpty, fill package/.initial=blue!20,%
+ class width/.initial=10ex, simple interface width/.initial=4ex, class type/.initial=class, fill class/.initial=yellow!20, fill template/.initial=yellow!2,%
+ narynode width/.initial=6ex,%
+ relation geometry/.initial=--, relation angle1/.initial=-30, relation angle2/.initial=30, relation loopsize/.initial=3em, relation weight/.initial=0.5, relation pos1/.initial=0.2, relation pos2/.initial=0.8, relation pos stereo/.initial=0.5,%
+ note width/.initial=3cm, fill note/.initial=green!20,%
+ fill system/.initial=white,%
+ fill usecase/.initial=blue!20,%
+ actor below/.initial=0.5cm,%
+ state join width/.initial=3ex,%
+ state decision width/.initial=3ex,%
+ state initial width/.initial=5ex,%
+ state final width/.initial=5.5ex,%
+ state enter width/.initial=5ex,%
+ state exit width/.initial=5ex,%
+ state end width/.initial=5ex,%
+ state history width/.initial=5ex,%
+ state deep history width/.initial=5ex,%
+ state width/.initial=8ex, fill state/.initial=yellow!20,%
+ object stereo/.initial=object, fill object/.initial=yellow!20,%
+ call dt/.initial=tikzumlEmpty, call padding/.initial=2, call type/.initial=synchron, fill call/.initial=white,%
+ fragment type/.initial=opt, fragment inner xsep/.initial=1, fragment inner ysep/.initial=1, fill fragment/.initial= none,%
+ create call dt/.initial=4,%
+ component width/.initial=8ex, fill component/.initial= yellow!20,%
+ required interface distance/.initial=2.5cm, required interface width/.initial=1em, required interface padding/.initial=1cm,%
+ provided interface distance/.initial=3cm, provided interface width/.initial=1em, provided interface padding/.initial=1cm,%
+ port width/.initial=1ex, fill port/.initial= yellow!20,%
+ fill assembly connector/.initial= white,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \errmessage{TIKZUML ERROR : in tikzuml global, invalid option \keyname}%
+ }%
+}%
+%
+\pgfkeys{/tikzuml/.cd, text/.get=\tikzumlDefaultTextColor, draw/.get=\tikzumlDefaultDrawColor, font/.get=\tikzumlDefaultFont,%
+ x/.get=\tikzumlDefaultX, y/.get=\tikzumlDefaultY,%
+ package type/.get=\tikzumlPackageDefaultType, fill package/.get=\tikzumlPackageDefaultFillColor,%
+ class width/.get=\tikzumlClassDefaultWidth, simple interface width/.get=\tikzumlSimpleInterfaceDefaultWidth, class type/.get=\tikzumlClassDefaultType, fill class/.get=\tikzumlClassDefaultFillColor, fill template/.get=\tikzumlClassTemplateFillColorDefaultFillColor,%
+ narynode width/.get=\tikzumlNaryNodeDefaultWidth,%
+ relation geometry/.get=\tikzumlRelationDefaultGeometry, relation angle1/.get=\tikzumlRelationDefaultAngleO, relation angle2/.get=\tikzumlRelationDefaultAngleT, relation loopsize/.get=\tikzumlRelationDefaultLoopSize, relation weight/.get=\tikzumlRelationDefaultWeight, relation pos1/.get=\tikzumlRelationDefaultPosO, relation pos2/.get=\tikzumlRelationDefaultPosT, relation pos stereo/.get=\tikzumlRelationDefaultPosStereo,%
+ note width/.get=\tikzumlNoteDefaultWidth, fill note/.get=\tikzumlNoteDefaultFillColor,%
+ fill system/.get=\tikzumlSystemDefaultFillColor,%
+ fill usecase/.get=\tikzumlUseCaseDefaultFillColor,%
+ actor below/.get=\tikzumlActorDefaultBelow,%
+ state join width/.get=\tikzumlStateJoinDefaultWidth,%
+ state decision width/.get=\tikzumlStateDecisionDefaultWidth,%
+ state initial width/.get=\tikzumlStateInitialDefaultWidth,%
+ state final width/.get=\tikzumlStateFinalDefaultWidth,%
+ state enter width/.get=\tikzumlStateEnterDefaultWidth,%
+ state exit width/.get=\tikzumlStateExitDefaultWidth,%
+ state end width/.get=\tikzumlStateEndDefaultWidth,%
+ state history width/.get=\tikzumlStateHistoryDefaultWidth,%
+ state deep history width/.get=\tikzumlStateDeepHistoryDefaultWidth,%
+ state width/.get=\tikzumlStateDefaultWidth, fill state/.get=\tikzumlStateDefaultFillColor,%
+ object stereo/.get=\tikzumlObjectDefaultStereo, fill object/.get=\tikzumlObjectDefaultFillColor,%
+ call dt/.get=\tikzumlCallDefaultDT, call padding/.get=\tikzumlCallDefaultPadding, call type/.get=\tikzumlCallDefaultType, fill call/.get=\tikzumlCallDefaultFillColor,%
+ fragment type/.get=\tikzumlFragmentDefaultType, fragment inner xsep/.get=\tikzumlFragmentDefaultXSep, fragment inner ysep/.get=\tikzumlFragmentDefaultYSep, fill fragment/.get=\tikzumlFragmentDefaultFillColor,%
+ create call dt/.get=\tikzumlCreateCallDefaultDT,%
+ component width/.get=\tikzumlComponentDefaultWidth, fill component/.get=\tikzumlComponentDefaultFillColor,%
+ required interface distance/.get=\tikzumlRequiredInterfaceDefaultDistance, required interface width/.get=\tikzumlRequiredInterfaceDefaultWidth, required interface padding/.get=\tikzumlRequiredInterfaceDefaultPadding,%
+ provided interface distance/.get=\tikzumlProvidedInterfaceDefaultDistance, provided interface width/.get=\tikzumlProvidedInterfaceDefaultWidth, provided interface padding/.get=\tikzumlProvidedInterfaceDefaultPadding,%
+ port width/.get=\tikzumlPortDefaultWidth, fill port/.get=\tikzumlPortDefaultFillColor,%
+ fill assembly connector/.get=\tikzumlAssemblyConnectorDefaultFillColor%
+}%
+%
+% utility : change default colors
+\newcommand{\tikzumlset}[1]{%
+ \pgfkeys{/tikzuml/.cd,#1}%
+ \pgfkeys{/tikzuml/.cd, text/.get=\tikzumlDefaultTextColor, draw/.get=\tikzumlDefaultDrawColor, font/.get=\tikzumlDefaultFont,%
+ x/.get=\tikzumlDefaultX, y/.get=\tikzumlDefaultY,%
+ package type/.get=\tikzumlPackageDefaultType, fill package/.get=\tikzumlPackageDefaultFillColor,%
+ class width/.get=\tikzumlClassDefaultWidth, simple interface width/.get=\tikzumlSimpleInterfaceDefaultWidth, class type/.get=\tikzumlClassDefaultType, fill class/.get=\tikzumlClassDefaultFillColor, fill template/.get=\tikzumlClassTemplateFillColorDefaultFillColor,%
+ narynode width/.get=\tikzumlNaryNodeWidth,%
+ relation geometry/.get=\tikzumlRelationDefaultGeometry, relation angle1/.get=\tikzumlRelationDefaultAngleO, relation angle2/.get=\tikzumlRelationDefaultAngleT, relation loopsize/.get=\tikzumlRelationDefaultLoopSize, relation weight/.get=\tikzumlRelationDefaultWeight, relation pos1/.get=\tikzumlRelationDefaultPosO, relation pos2/.get=\tikzumlRelationDefaultPosT, relation pos stereo/.get=\tikzumlRelationDefaultPosStereo,%
+ note width/.get=\tikzumlNoteDefaultWidth, fill note/.get=\tikzumlNoteDefaultFillColor,%
+ fill system/.get=\tikzumlSystemDefaultFillColor,%
+ fill usecase/.get=\tikzumlUseCaseDefaultFillColor,%
+ actor below/.get=\tikzumlActorDefaultBelow,%
+ state join width/.get=\tikzumlStateJoinDefaultWidth,%
+ state decision width/.get=\tikzumlStateDecisionDefaultWidth,%
+ state initial width/.get=\tikzumlStateInitialDefaultWidth,%
+ state final width/.get=\tikzumlStateFinalDefaultWidth,%
+ state enter width/.get=\tikzumlStateEnterDefaultWidth,%
+ state exit width/.get=\tikzumlStateExitDefaultWidth,%
+ state end width/.get=\tikzumlStateEndDefaultWidth,%
+ state history width/.get=\tikzumlStateHistoryDefaultWidth,%
+ state deep history width/.get=\tikzumlStateDeepHistoryDefaultWidth,%
+ state width/.get=\tikzumlStateDefaultWidth, fill state/.get=\tikzumlStateDefaultFillColor,%
+ object stereo/.get=\tikzumlObjectDefaultStereo, fill object/.get=\tikzumlObjectDefaultFillColor,%
+ call dt/.get=\tikzumlCallDefaultDT, call padding/.get=\tikzumlCallDefaultPadding, call type/.get=\tikzumlCallDefaultType, fill call/.get=\tikzumlCallDefaultFillColor,%
+ fragment type/.get=\tikzumlFragmentDefaultType, fragment inner xsep/.get=\tikzumlFragmentDefaultXSep, fragment inner ysep/.get=\tikzumlFragmentDefaultYSep, fill fragment/.get=\tikzumlFragmentDefaultFillColor,%
+ create call dt/.get=\tikzumlCreateCallDT,%
+ component width/.get=\tikzumlComponentDefaultWidth, fill component/.get=\tikzumlComponentDefaultFillColor,%
+ required interface distance/.get=\tikzumlRequiredInterfaceDefaultDistance, required interface width/.get=\tikzumlRequiredInterfaceDefaultWidth, required interface padding/.get=\tikzumlRequiredInterfaceDefaultPadding,%
+ provided interface distance/.get=\tikzumlProvidedInterfaceDefaultDistance, provided interface width/.get=\tikzumlProvidedInterfaceDefaultWidth, provided interface padding/.get=\tikzumlProvidedInterfaceDefaultPadding,%
+ port width/.get=\tikzumlPortDefaultWidth, fill port/.get=\tikzumlPortDefaultFillColor,%
+ fill assembly connector/.get=\tikzumlAssemblyConnectorDefaultFillColor%
+ }%
+}%
+%
+% define a point
+% arg : node/coordinates of the point
+\newcommand{\umlpoint}[1]{%
+ \begin{pgfonlayer}{connections}%
+ \node[tikzuml control nodes style] at (#1) {};%
+ \end{pgfonlayer}%
+}%
+%
+\newcommand{\tikzumlskipescape}[3][_]{%
+\begingroup%
+ \def\_{#1}\edef\x{\endgroup%
+ \def\noexpand\csname #3\endcsname{#2}}\x%
+}%
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% class diagrams %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+\pgfkeys{/tikzuml/relation/.cd, attr1/.style args={#1|#2}{arg1=#1, mult1=#2},%
+ attr2/.style args={#1|#2}{arg2=#1, mult2=#2},%
+ attr/.style args={#1|#2}{arg=#1, mult=#2},%
+ recursive/.style args={#1|#2|#3}{angle1=#1, angle2=#2, loopsize=#3},%
+ anchors/.style args={#1 and #2}{anchor1=#1, anchor2=#2},%
+ recursive direction/.style args={#1 to #2}{recursive direction start=#1, recursive direction end=#2}%
+}%
+%
+\pgfkeys{/tikzuml/note/.cd, anchors/.style args={#1 and #2}{anchor1=#1, anchor2=#2}}%
+%
+\tikzstyle{tikzuml simpleclass style}=[rectangle, minimum height=2em, node distance=2em]%
+\tikzstyle{tikzuml simpleinterface style}=[circle, minimum height=1em, node distance=1em]%
+\tikzstyle{tikzuml class style}=[rectangle split, rectangle split parts=3, rectangle split part align={center, left, left}, minimum height=2em, node distance=2em]%
+\tikzstyle{tikzuml narynode style}=[diamond]%
+\tikzstyle{tikzuml template style}=[dashed, inner ysep=0.5em, inner xsep=1ex]%
+\tikzstyle{tikzuml control nodes style}=[fill=black, inner sep=1.5pt, circle]%
+%
+\tikzstyle{tikzuml association style}=[color=\tikzumlDefaultDrawColor, -]%
+\tikzstyle{tikzuml bidirectional association style}=[color=\tikzumlDefaultDrawColor, angle45-angle45]%
+\tikzstyle{tikzuml unidirectional association style}=[color=\tikzumlDefaultDrawColor, -angle 45]%
+\tikzstyle{tikzuml aggregation style}=[color=\tikzumlDefaultDrawColor, open diamond-]%
+\tikzstyle{tikzuml unidirectional aggregation style}=[color=\tikzumlDefaultDrawColor, open diamond-angle 45]%
+\tikzstyle{tikzuml composition style}=[color=\tikzumlDefaultDrawColor, diamond-]%
+\tikzstyle{tikzuml unidirectional composition style}=[color=\tikzumlDefaultDrawColor, diamond-angle 45]%
+\tikzstyle{tikzuml nesting style}=[color=\tikzumlDefaultDrawColor]%
+\tikzstyle{tikzuml dependency style}=[color=\tikzumlDefaultDrawColor, -angle 45, dashed]%
+\tikzstyle{tikzuml import style}=[color=\tikzumlDefaultDrawColor, -angle 45, dashed]%
+\tikzstyle{tikzuml inherit style}=[color=\tikzumlDefaultDrawColor, -open triangle 45]%
+\tikzstyle{tikzuml implements style}=[color=\tikzumlDefaultDrawColor, -open triangle 45, dashed]%
+%
+\pgfkeys{/tikzuml/assemblyconnectorrelation/.cd, anchors/.style args={#1 and #2}{anchor1=#1, anchor2=#2}}%
+%
+\newcounter{tikzumlPackageClassNum}%
+\newcounter{tikzumlPackageSubPackageNum}%
+\newcounter{tikzumlRelationNum}%
+\setcounter{tikzumlRelationNum}{1}%
+\newcounter{tikzumlNoteNum}%
+\setcounter{tikzumlNoteNum}{1}%
+%
+\newcounter{pos}%
+\newcounter{posT}%
+\newcounter{posStereo}%
+%
+\newcounter{tikzumlPackageLevel}%
+\setcounter{tikzumlPackageLevel}{0}%
+%
+\newif\iftikzumlpackageSimpleStyle%
+\newif\iftikzumlclassSimpleStyle%
+\newif\iftikzumlclassCircleShape%
+\newif\iftikzumlpackageWithoutCoords%
+\newif\iftikzumlclassWithoutCoords%
+\newif\iftikzumlassocclassWithoutCoords%
+\newif\iftikzumlnoteWithoutCoords%
+%
+% define a uml package
+% arg : package name
+% optional : x, y: coordinates of the package
+% type: stereotype of the package
+% name: name of the package node
+% draw, fill, text: colors
+% style: to manage every default TikZ option
+% no coords: to tell that the package position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newenvironment{umlpackage}[2][]{%
+ \pgfkeys{/tikzuml/package/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, style/.style={},%
+ name/.initial=tikzumlEmpty, type/.initial=\tikzumlPackageDefaultType, draw/.initial=\tikzumlDefaultDrawColor,%
+ fill/.initial=\tikzumlPackageDefaultFillColor, text/.initial=\tikzumlDefaultTextColor,%
+ no coords/.is if=tikzumlpackageWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/package/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/package/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/package/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlpackage, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/package/.cd, #1}%
+ \pgfkeys{/tikzuml/package/.cd, x/.get=\tikzumlPackageXShift, y/.get=\tikzumlPackageYShift, name/.get=\tikzumlPackageName, type/.get=\tikzumlPackageTypeTmp,%
+ draw/.get=\tikzumlPackageDrawColor, fill/.get=\tikzumlPackageFillColor,%
+ text/.get=\tikzumlPackageTextColor%
+ }%
+ %
+
+ %
+ \ifthenelse{\equal{\tikzumlPackageTypeTmp}{tikzumlEmpty}}{%
+ \def\tikzumlPackageType{}%
+ }{%
+ \expandafter\def\expandafter\tikzumlPackageType\expandafter{$\ll$\tikzumlPackageTypeTmp$\gg$ \\}%
+ }%
+ %
+ \ifnum\thetikzumlPackageLevel>0%
+ \let\tikzumlPackage@nameold\tikzumlPackage@fitname%
+ \def\tikzumlPackage@name{#2}%
+ \begingroup%
+ \def\_{@}\edef\x{\endgroup%
+ \def\noexpand\tikzumlPackage@fitname{\tikzumlPackage@name}}\x%
+ \let\tikzumlPackage@parentold\tikzumlPackage@parent%
+ \edef\tikzumlPackage@parent{\tikzumlPackage@parentold @@\tikzumlPackage@nameold}%
+ \else%
+ \def\tikzumlPackage@parent{}%
+ \def\tikzumlPackage@name{#2}%
+ \begingroup%
+ \def\_{@}\edef\x{\endgroup%
+ \def\noexpand\tikzumlPackage@fitname{\tikzumlPackage@name}}\x%
+ \fi%
+ %
+ \let\tikzumlPackage@nodeNameold\tikzumlPackage@nodeName%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlPackage@nodeName{\tikzumlPackage@name}}\x%
+ %
+ \ifthenelse{\equal{\tikzumlPackageName}{tikzumlEmpty}}{}{%
+ \def\tikzumlPackage@nodeName{\tikzumlPackageName}%
+ }%
+ %
+ \StrSubstitute{\tikzumlPackage@nodeName}{.}{@POINT@}{\tikzumlPackage@nodeName}%
+ %
+ \expandafter\gdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{}%
+ %
+ \setcounter{tikzumlPackageClassNum}{0}%
+ \setcounter{tikzumlPackageSubPackageNum}{0}%
+ \stepcounter{tikzumlPackageLevel}%
+ %
+ \begin{scope}[xshift=\tikzumlPackageXShift cm, yshift=\tikzumlPackageYShift cm]%
+}{%
+ \addtocounter{tikzumlPackageLevel}{-1}%
+ \begin{pgfonlayer}{package\thetikzumlPackageLevel}%
+ %
+ % if contains no class, and not simple, one define a fictive node to enable the fit option
+ \ifnum\c@tikzumlPackageClassNum=0%
+ \ifnum\c@tikzumlPackageSubPackageNum=0%
+ \iftikzumlpackageWithoutCoords%
+ \node[inner sep=1.5ex, /tikzuml/package/style] (\tikzumlPackage@nodeName-root) {\phantom{\tikzumlPackage@nodeName}};%
+ \else%
+ \node[inner sep=1.5ex, /tikzuml/package/style] (\tikzumlPackage@nodeName-root) at (0,0) {\phantom{\tikzumlPackage@nodeName}};%
+ \fi%
+ \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{(\tikzumlPackage@nodeName-root)}%
+ \fi%
+ \fi%
+ %
+ \ifnum\c@tikzumlPackageLevel>0%
+ \def\tikzumlPackageFitTmp{\csname tikzumlPackageFit\tikzumlPackage@parent\endcsname}%
+ \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent\endcsname{\tikzumlPackageFitTmp (\tikzumlPackage@nodeName) (\tikzumlPackage@nodeName-caption)}%
+ \stepcounter{tikzumlPackageSubPackageNum}%
+ \fi%
+ %
+ \node[draw=\tikzumlPackageDrawColor, fill=\tikzumlPackageFillColor, text=\tikzumlPackageTextColor, font=\tikzumlDefaultFont, inner sep=1.5ex, /tikzuml/package/style, fit = \csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname] (\tikzumlPackage@nodeName) {};%
+ \node[draw=\tikzumlPackageDrawColor, fill=\tikzumlPackageFillColor, text=\tikzumlPackageTextColor, font=\tikzumlDefaultFont, minimum height=1.5em, outer ysep=-0.3, anchor=south west] (\tikzumlPackage@nodeName-caption) at (\tikzumlPackage@nodeName.north west) {\begin{tabular}{c} \tikzumlPackageType \textbf{\tikzumlPackage@name}\end{tabular}};%
+ \end{pgfonlayer}%
+ \end{scope}%
+}%
+%
+% shortcut to define an empty package
+\newcommand{\umlemptypackage}[2][]{\begin{umlpackage}[#1]{#2} \end{umlpackage}}%
+%
+% define a uml class
+% args : name of the class
+% attributes of the class
+% operations of the class
+% optional : x, y: coordinates of the class
+% width: of the class node
+% type: type of class (class, interface, typedef, enum)
+% tags: tagged values of class
+% template: template parameters
+% simple: if used, class is empty and drawn with a rectangle
+% circle: if used with simple, class is empty and drawn with a circle
+% draw, fill, fill template, and text: colors
+% style: to manage every default TikZ option
+% no coords: to tell that the class position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlclass}[4][]{%
+ \pgfkeys{/tikzuml/class/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlClassDefaultWidth, type/.initial=\tikzumlClassDefaultType,%
+ tags/.initial={}, style/.style={},%
+ template/.initial={}, name/.initial=tikzumlEmpty,%
+ draw/.initial=\tikzumlDefaultDrawColor,%
+ fill template/.initial=\tikzumlClassTemplateFillColorDefaultFillColor,%
+ fill/.initial=\tikzumlClassDefaultFillColor,%
+ text/.initial=\tikzumlDefaultTextColor,%
+ simple/.is if=tikzumlclassSimpleStyle, circle/.is if=tikzumlclassCircleShape, no coords/.is if=tikzumlclassWithoutCoords,%
+ simple=false, circle=false, no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/class/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/class/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/class/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlclass, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/class/.cd,#1}%
+ %
+ \iftikzumlclassSimpleStyle%
+ \iftikzumlclassCircleShape%
+ \pgfkeys{/tikzuml/class/.cd, width/.initial=\tikzumlSimpleInterfaceDefaultWidth}%
+ \fi%
+ \fi%
+ %
+ \pgfkeys{/tikzuml/class/.cd, x/.get=\tikzumlClassX, y/.get=\tikzumlClassY, width/.get=\tikzumlClassMinimumWidth,%
+ type/.get=\tikzumlClassTypeTmp, tags/.get=\tikzumlClassTagsTmp, template/.get=\tikzumlClassTemplateFillColorParam,%
+ name/.get=\tikzumlClassName,%
+ draw/.get=\tikzumlClassDrawColor, fill/.get=\tikzumlClassFillColor,%
+ text/.get=\tikzumlClassTextColor, fill template/.get=\tikzumlClassTemplateFillColor%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlClassTypeTmp}{class}\OR\equal{\tikzumlClassTypeTmp}{abstract}}{%
+ \def\tikzumlClassType{}%
+ }{%
+ \expandafter\def\expandafter\tikzumlClassType\expandafter{$\ll$\tikzumlClassTypeTmp$\gg$ \\}%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlClassTagsTmp}{}}{%
+ \def\tikzumlClassTags{}%
+ }{%
+ \def\tikzumlClassTags{\\ \{\tikzumlClassTagsTmp\}}%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlClassTemplateFillColorParam}{}}{%
+ \def\tikzumlClassVPadding{}%
+ \def\tikzumlClassHPadding{}%
+ }{%
+ \def\tikzumlClassVPadding{\vspace{0.1em} \\}%
+ \def\tikzumlClassHPadding{\hspace{0.5ex} $ $}%
+ }%
+ %
+ \def\tikzumlClassName{#2}%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlClassNodeName{\tikzumlClassName}}\x%
+ %
+ \ifthenelse{\equal{\tikzumlClassName}{tikzumlEmpty}}{}{%
+ \def\tikzumlClassNodeName{\tikzumlClassName}%
+ }%
+ %
+ \StrSubstitute{\tikzumlClassNodeName}{:}{@COLON@}[\tikzumlClassNodeName]%
+ \StrSubstitute{\tikzumlClassNodeName}{\_}{@UNDERSCORE@}[\tikzumlClassNodeName]%
+ %
+ \ifthenelse{\equal{\tikzumlClassTypeTmp}{abstract}}{%
+ \let\tikzumlClassNameOld\tikzumlClassName%
+ \def\tikzumlClassName{{\it \tikzumlClassNameOld}}%
+ }{}%
+ %
+ \def\tikzumlClassPos{\tikzumlClassX,\tikzumlClassY}%
+ \def\tikzumlClassAttributes{#3}%
+ \def\tikzumlClassOperations{#4}%
+ %
+ \iftikzumlclassSimpleStyle%
+ \iftikzumlclassWithoutCoords%
+ \iftikzumlclassCircleShape%
+ \node[tikzuml simpleinterface style, draw=\tikzumlClassDrawColor, fill=\tikzumlClassFillColor, text=\tikzumlClassTextColor, font=\tikzumlDefaultFont, minimum width=\tikzumlClassMinimumWidth, /tikzuml/class/style] (\tikzumlClassNodeName) {};%
+ \node[anchor=south] (\tikzumlClassNodeName-label) at (\tikzumlClassNodeName.north) {\begin{tabular}{c}\tikzumlClassVPadding \tikzumlClassType \tikzumlClassHPadding \textbf{\tikzumlClassName} \tikzumlClassHPadding \tikzumlClassTags \end{tabular}%
+ };%
+ \else%
+ \node[tikzuml simpleclass style, draw=\tikzumlClassDrawColor, fill=\tikzumlClassFillColor, text=\tikzumlClassTextColor, font=\tikzumlDefaultFont, minimum width=\tikzumlClassMinimumWidth, /tikzuml/class/style] (\tikzumlClassNodeName) {\begin{tabular}{c}\tikzumlClassVPadding \tikzumlClassType \tikzumlClassHPadding \textbf{\tikzumlClassName} \tikzumlClassHPadding \tikzumlClassTags \end{tabular}%
+ };%
+ \fi%
+ \else%
+ \iftikzumlclassCircleShape%
+ \node[tikzuml simpleinterface style, draw=\tikzumlClassDrawColor, fill=\tikzumlClassFillColor, text=\tikzumlClassTextColor, font=\tikzumlDefaultFont, minimum width=\tikzumlClassMinimumWidth, /tikzuml/class/style] (\tikzumlClassNodeName) at (\tikzumlClassPos) {};
+ \node[anchor=south] (\tikzumlClassNodeName-label) at (\tikzumlClassNodeName.north){\begin{tabular}{c}\tikzumlClassVPadding \tikzumlClassType \tikzumlClassHPadding \textbf{\tikzumlClassName} \tikzumlClassHPadding \tikzumlClassTags \end{tabular}%
+ };%
+ \else%
+ \node[tikzuml simpleclass style, draw=\tikzumlClassDrawColor, fill=\tikzumlClassFillColor, text=\tikzumlClassTextColor, font=\tikzumlDefaultFont, minimum width=\tikzumlClassMinimumWidth, /tikzuml/class/style] (\tikzumlClassNodeName) at (\tikzumlClassPos) {\begin{tabular}{c}\tikzumlClassVPadding \tikzumlClassType \tikzumlClassHPadding \textbf{\tikzumlClassName} \tikzumlClassHPadding \tikzumlClassTags \end{tabular}%
+ };%
+ \fi%
+ \fi%
+ \else%
+ \iftikzumlclassWithoutCoords%
+ \node[tikzuml class style, draw=\tikzumlClassDrawColor, fill=\tikzumlClassFillColor, text=\tikzumlClassTextColor, font=\tikzumlDefaultFont, minimum width=\tikzumlClassMinimumWidth, /tikzuml/class/style] (\tikzumlClassNodeName) {\begin{tabular}{c}\tikzumlClassVPadding \tikzumlClassType \tikzumlClassHPadding \textbf{\tikzumlClassName} \tikzumlClassHPadding \tikzumlClassTags \end{tabular}%
+ \nodepart{second}%
+ \begin{tabular}{l}%
+ \tikzumlClassAttributes%
+ \end{tabular}%
+ \nodepart{third}%
+ \begin{tabular}{l}%
+ \tikzumlClassOperations%
+ \end{tabular}%
+ };%
+ \else%
+ \node[tikzuml class style, draw=\tikzumlClassDrawColor, fill=\tikzumlClassFillColor, text=\tikzumlClassTextColor, font=\tikzumlDefaultFont, minimum width=\tikzumlClassMinimumWidth, /tikzuml/class/style] (\tikzumlClassNodeName) at (\tikzumlClassPos) {\begin{tabular}{c}\tikzumlClassVPadding \tikzumlClassType \tikzumlClassHPadding \textbf{\tikzumlClassName} \tikzumlClassHPadding \tikzumlClassTags \end{tabular}%
+ \nodepart{second}%
+ \begin{tabular}{l}%
+ \tikzumlClassAttributes%
+ \end{tabular}%
+ \nodepart{third}%
+ \begin{tabular}{l}%
+ \tikzumlClassOperations%
+ \end{tabular}%
+ };%
+ \fi%
+ \fi%
+ %
+ \ifthenelse{\equal{\tikzumlClassTemplateFillColorParam}{}}{}{%
+ \draw (\tikzumlClassNodeName.north east) node[tikzuml template style, name=\tikzumlClassNodeName-template, draw=\tikzumlClassDrawColor, fill=\tikzumlClassTemplateFillColor, text=\tikzumlClassTextColor, font=\tikzumlDefaultFont] {\tikzumlClassTemplateFillColorParam};%
+ }%
+ %
+ % add to fit
+ \ifnum\c@tikzumlPackageLevel>0%
+ \edef\tikzumlPackageFitOld{\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname}%
+ \ifthenelse{\equal{\tikzumlClassTemplateFillColorParam}{}}{%
+ \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{\tikzumlPackageFitOld (\tikzumlClassNodeName)}%
+ }{%
+ \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{\tikzumlPackageFitOld (\tikzumlClassNodeName) (\tikzumlClassNodeName-template)}%
+ }%
+ \stepcounter{tikzumlPackageClassNum}%
+ \fi%
+ \ifnum\c@tikzumlComponentLevel>0%
+ \def\tikzumlComponentFitTmp{\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname}%
+ \ifthenelse{\equal{\tikzumlClassTemplateFillColorParam}{}}{%
+ \expandafter\xdef\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname{\tikzumlComponentFitTmp (\tikzumlClassNodeName)}%
+ }{%
+ \expandafter\xdef\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname{\tikzumlComponentFitTmp (\tikzumlClassNodeName) (\tikzumlClassNodeName-template)}%
+ }%
+ \stepcounter{tikzumlComponentSubComponentNum}%
+ \fi%
+}%
+%
+% shortcuts for interface, enum and typedef environments
+\newcommand{\umlabstract}[4][]{%
+ \pgfkeys{/tikzuml/class/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{type}}{%
+ \errmessage{TIKZUML ERROR : in umlabstract, forbidden option type}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/class/.cd, #1}%
+ \umlclass[type=abstract,#1]{#2}{#3}{#4}%
+}%
+\newcommand{\umlinterface}[4][]{%
+ \pgfkeys{/tikzuml/class/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{type}}{%
+ \errmessage{TIKZUML ERROR : in umlinterface, forbidden option type}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/class/.cd, #1}%
+ \umlclass[type=interface,#1]{#2}{#3}{#4}%
+}%
+\newcommand{\umltypedef}[4][]{%
+ \pgfkeys{/tikzuml/class/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{type}}{%
+ \errmessage{TIKZUML ERROR : in umltypedef, forbidden option type}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/class/.cd, #1}%
+ \umlclass[type=typedef,#1]{#2}{#3}{#4}%
+}%
+\newcommand{\umlenum}[4][]{%
+ \pgfkeys{/tikzuml/class/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{type}}{%
+ \errmessage{TIKZUML ERROR : in umlenum, forbidden option type}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/class/.cd, #1}%
+ \umlclass[type=enum,#1]{#2}{#3}{#4}
+}%
+%
+% shortcut to define an empty class
+\newcommand{\umlemptyclass}[2][]{\umlclass[#1]{#2}{}{}}%
+\newcommand{\umlsimpleclass}[2][]{%
+ \pgfkeys{/tikzuml/class/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{simple}}{%
+ \errmessage{TIKZUML ERROR : in umlsimpleclass, forbidden option simple}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/class/.cd, #1}%
+ \umlemptyclass[simple, #1]{#2}%
+}%
+%
+\newcommand{\umlsimpleinterface}[2][]{%
+ \pgfkeys{/tikzuml/class/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{simple}}{%
+ \errmessage{TIKZUML ERROR : in umlsimpleinterface, forbidden option simple}%
+ }{%
+ \ifthenelse{\equal{\keyname}{circle}}{%
+ \errmessage{TIKZUML ERROR : in umlsimpleinterface, forbidden option circle}%
+ }{}%
+ }%
+ }%
+ }%
+ \pgfkeys{/tikzuml/class/.cd, #1}%
+ \umlsimpleclass[circle, #1]{#2}%
+}%
+% underline the text for static arg
+\newcommand{\umlstatic}[1]{\underline{#1}}%
+\newcommand{\umlvirt}[1]{\textit{#1}}%
+%
+% define node for n-ary association
+\newcommand{\umlNarynode}[2][]{%
+ \def\tikzumlNaryNodeAnchor{.north}
+ \def\tikzumlNaryNodeLabelPos{above}
+ \pgfkeys{/tikzuml/narynode/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlNaryNodeDefaultWidth, name/.initial=tikzumlEmpty,%
+ draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlClassDefaultFillColor,%
+ text/.initial=\tikzumlDefaultTextColor, style/.style={},%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}}{%
+ \def\tikzumlNaryNodeAnchor{.north}%
+ \def\tikzumlNaryNodeLabelPos{above}%
+ }{%
+ \ifthenelse{\equal{\keyname}{above left}}{%
+ \def\tikzumlNaryNodeAnchor{.north west}%
+ \def\tikzumlNaryNodeLabelPos{above left}%
+ }{%
+ \ifthenelse{\equal{\keyname}{left}}{%
+ \def\tikzumlNaryNodeAnchor{.west}%
+ \def\tikzumlNaryNodeLabelPos{left}%
+ }{%
+ \ifthenelse{\equal{\keyname}{below left}}{%
+ \def\tikzumlNaryNodeAnchor{.south west}%
+ \def\tikzumlNaryNodeLabelPos{below left}%
+ }{%
+ \ifthenelse{\equal{\keyname}{below}}{%
+ \def\tikzumlNaryNodeAnchor{.south}%
+ \def\tikzumlNaryNodeLabelPos{below}%
+ }{%
+ \ifthenelse{\equal{\keyname}{below right}}{%
+ \def\tikzumlNaryNodeAnchor{.south east}%
+ \def\tikzumlNaryNodeLabelPos{below right}%
+ }{%
+ \ifthenelse{\equal{\keyname}{right}}{%
+ \def\tikzumlNaryNodeAnchor{.east}%
+ \def\tikzumlNaryNodeLabelPos{right}%
+ }{%
+ \ifthenelse{\equal{\keyname}{above right}}{%
+ \def\tikzumlNaryNodeAnchor{.north east}%
+ \def\tikzumlNaryNodeLabelPos{above right}%
+ }{%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/narynode/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/narynode/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlNarynode, invalid option \keyname}%
+ }%
+ }%
+ }%
+ }%
+ }%
+ }%
+ }%
+ }%
+ }%
+ }%
+ \pgfkeys{/tikzuml/narynode/.cd,#1}%
+ \pgfkeys{/tikzuml/narynode/.cd, x/.get=\tikzumlNaryNodeX, y/.get=\tikzumlNaryNodeY, width/.get=\tikzumlNaryNodeMinimumWidth,%
+ name/.get=\tikzumlNaryNodeName,%
+ draw/.get=\tikzumlNaryNodeDrawColor, fill/.get=\tikzumlNaryNodeFillColor,%
+ text/.get=\tikzumlNaryNodeTextColor%
+ }%
+ %
+ \def\tikzumlNaryName{#2}%
+ %
+ \ifthenelse{\equal{\tikzumlNaryNodeName}{tikzumlEmpty}}{%
+ \edef\tikzumlNaryNodeName{\tikzumlNaryName}%
+ }{%
+ \edef\tikzumlNaryNodeName{\tikzumlNaryNodeName}%
+ }%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlNaryNode@nodeName{\tikzumlNaryNodeName}}\x%
+ %
+ \StrSubstitute{\tikzumlNaryNode@nodeName}{:}{@COLON@}[\tikzumlNaryNode@nodeName]%
+ \StrSubstitute{\tikzumlNaryNode@nodeName}{\_}{@UNDERSCORE@}[\tikzumlNaryNode@nodeName]%
+ %
+ \def\tikzumlNarynodePos{\tikzumlNaryNodeX,\tikzumlNaryNodeY}%
+ %
+ \node[tikzuml narynode style, draw=\tikzumlNaryNodeDrawColor, fill=\tikzumlNaryNodeFillColor, text=\tikzumlNaryNodeTextColor, font=\tikzumlDefaultFont, minimum width=\tikzumlNaryNodeMinimumWidth, minimum height=\tikzumlNaryNodeMinimumWidth, /tikzuml/narynode/style] (\tikzumlNaryNode@nodeName) at (\tikzumlNarynodePos) {};%
+ \draw (\tikzumlNaryNode@nodeName\tikzumlNaryNodeAnchor) node[\tikzumlNaryNodeLabelPos] {\tikzumlNaryName};%
+ %
+ % add to fit
+ \ifnum\c@tikzumlPackageLevel>0%
+ \edef\tikzumlPackageFitOld{\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{\tikzumlPackageFitOld (\tikzumlNaryNode@nodeName)}%
+ \stepcounter{tikzumlPackageClassNum}%
+ \fi%
+}%
+%
+\newdimen\tikzumlNestingSymbolSize%
+%
+% main command to define a relation between two classes
+% args : src class
+% dest class
+% optional : geometry: geometry of the line
+% weight: barycentric weight of the middle part when geometry is a 3-line
+% arm1, arm2: lengths of first or last part when geometry id a 3-line
+% arg1, arg2, arg: name of the src/dest/dest side class type attribute defined by the relation
+% mult1, mult2, mult: multiplicity of the src/dest/dest side class type attribute defined by the relation
+% pos1, pos2, pos: position of the src/dest/dest side class type attribute defined by the relation
+% align1, align2, align: text justification of the src/dest/dest side class type attribute defined by the relation
+% anchor1, anchor2: src/dest anchors on linked classes
+% angle1, angle2, loopsize: start angle, end angle and size of the relation (only if recursive)
+% stereo: stereotype of the relation
+% pos stereo: position of the stereotype on the relation
+% style: style of the relation (association, aggregation, composition, inherit, ...)
+% name: rootname used for naming nodes of the relation
+% recursive mode: type of recursive arrow (transition for state diagrams, or default)
+% recursive direction start/end: when transition relation, start/end directions of the relation arrow
+\newcommand{\umlrelation}[3][]{%
+ \pgfkeys{/tikzuml/relation/.cd, geometry/.initial=\tikzumlRelationDefaultGeometry, weight/.initial=\tikzumlRelationDefaultWeight,%
+ arm1/.initial=auto, arm2/.initial=auto,%
+ arg1/.initial={}, arg2/.initial={}, arg/.initial={},%
+ mult1/.initial={}, mult2/.initial={}, mult/.initial={},%
+ pos1/.initial=\tikzumlRelationDefaultPosO, pos2/.initial=\tikzumlRelationDefaultPosT, pos/.initial=tikzumlEmpty,%
+ align1/.initial={}, align2/.initial={}, align/.initial={},%
+ anchor1/.initial=tikzumlEmpty, anchor2/.initial=tikzumlEmpty,%
+ angle1/.initial=\tikzumlRelationDefaultAngleO, angle2/.initial=\tikzumlRelationDefaultAngleT, loopsize/.initial=\tikzumlRelationDefaultLoopSize,%
+ stereo/.initial={}, pos stereo/.initial=\tikzumlRelationDefaultPosStereo,%
+ style/.initial=->, style2/.style={}, name/.initial=relation-\thetikzumlRelationNum,%
+ recursive mode/.initial=default, recursive direction start/.initial=right,%
+ recursive direction end/.initial=bottom,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{with port}%
+ \OR\equal{\keyname}{interface}%
+ \OR\equal{\keyname}{padding}%
+ \OR\equal{\keyname}{width}%
+ \OR\equal{\keyname}{first arm}%
+ \OR\equal{\keyname}{second arm}%
+ \OR\equal{\keyname}{middle arm}%
+ \OR\equal{\keyname}{last arm}%
+ \OR\equal{\keyname}{distance}}{}{%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/relation/.cd, style2/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/relation/.cd, style2/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlrelation, invalid option \keyname}%
+ }%
+ }%
+ }%
+ \pgfkeys{/tikzuml/relation/.cd,#1}%
+ \pgfkeys{/tikzuml/relation/.cd, geometry/.get=\tikzumlRelationGeometry, weight/.get=\tikzumlRelationWeight,%
+ arm1/.get=\tikzumlRelationArmO, arm2/.get=\tikzumlRelationArmT,%
+ arg1/.get=\tikzumlRelationAttrName, arg2/.get=\tikzumlRelationAttrNameTO, arg/.get=\tikzumlRelationAttrNameTT,%
+ mult1/.get=\tikzumlRelationMultiplicity, mult2/.get=\tikzumlRelationMultiplicityTO, mult/.get=\tikzumlRelationMultiplicityTT,%
+ pos1/.get=\tikzumlRelationPosition, pos2/.get=\tikzumlRelationPositionTO, pos/.get=\tikzumlRelationPositionTT,%
+ align1/.get=\tikzumlRelationAlign, align2/.get=\tikzumlRelationAlignTO, align/.get=\tikzumlRelationAlignTT,%
+ anchor1/.get=\tikzumlRelationSrcAnchor, anchor2/.get=\tikzumlRelationDestAnchor,%
+ angle1/.get=\tikzumlRelationStartAngle, angle2/.get=\tikzumlRelationEndAngle, loopsize/.get=\tikzumlRelationLoopSize,%
+ stereo/.get=\tikzumlRelationStereoType, pos stereo/.get=\tikzumlRelationPositionStereotype,%
+ style/.get=\tikzumlRelationStyle, name/.get=\tikzumlRelationName,%
+ recursive mode/.get=\tikzumlRelationRecursiveMode,%
+ recursive direction start/.get=\tikzumlRelationRecursiveDirectionStart,%
+ recursive direction end/.get=\tikzumlRelationRecursiveDirectionEnd%
+ }%
+ %
+ \def\tikzumlSrcClassName{#2}%
+ %
+ % managing \_ in class names for node names
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlSrcClassNodeName{\tikzumlSrcClassName}}\x%
+ %
+ \StrSubstitute{\tikzumlSrcClassNodeName}{:}{@COLON@}[\tikzumlSrcClassNodeName]%
+ \StrSubstitute{\tikzumlSrcClassNodeName}{\_}{@UNDERSCORE@}[\tikzumlSrcClassNodeName]%
+ %
+ \def\tikzumlDestClassName{#3}%
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlDestClassNodeName{\tikzumlDestClassName}}\x%
+ %
+ \StrSubstitute{\tikzumlDestClassNodeName}{:}{@COLON@}[\tikzumlDestClassNodeName]%
+ \StrSubstitute{\tikzumlDestClassNodeName}{\_}{@UNDERSCORE@}[\tikzumlDestClassNodeName]%
+ %
+ % managing alias keys
+ \def\tikzumlRelationAttrNameT{\tikzumlRelationAttrNameTO\tikzumlRelationAttrNameTT}%
+ \def\tikzumlRelationMultiplicityT{\tikzumlRelationMultiplicityTO\tikzumlRelationMultiplicityTT}%
+ \def\tikzumlRelationAlignT{\tikzumlRelationAlignTO\tikzumlRelationAlignTT}%
+ \def\posAttrName{}%
+ \def\posMultiplicity{}%
+ \def\posAttrNameT{}%
+ \def\posMultiplicityT{}%
+ %
+ \ifthenelse{\equal{\tikzumlRelationPositionTT}{tikzumlEmpty}}{%
+ \def\tikzumlRelationPositionT{\tikzumlRelationPositionTO}%
+ }{%
+ \def\tikzumlRelationPositionT{\tikzumlRelationPositionTT}%
+ }%
+ %
+ \def\attrAlign{}%
+ \def\multAlign{}%
+ \def\attrAlignT{}%
+ \def\multAlignT{}%
+ %
+ \ifthenelse{\equal{\tikzumlRelationAlign}{left}}{%
+ \def\attrAlign{above right}%
+ \def\multAlign{below right}%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationAlign}{right}}{%
+ \def\attrAlign{above left}%
+ \def\multAlign{below left}%
+ }{}%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlRelationAlignT}{left}}{%
+ \def\attrAlignT{above right}%
+ \def\multAlignT{below right}%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationAlignT}{right}}{%
+ \def\attrAlignT{above left}%
+ \def\multAlignT{below left}%
+ }{}%
+ }%
+ %
+ % def stereotype
+ \ifthenelse{\equal{\tikzumlRelationStereoType}{}}{%
+ \def\stereotype{}%
+ }{%
+ \def\stereotype{$\ll$\tikzumlRelationStereoType$\gg$}%
+ }%
+
+ % def anchors macros
+ \ifthenelse{\equal{\tikzumlRelationSrcAnchor}{tikzumlEmpty}}{%
+ \def\tikzumlRelationSrcAnchor{}%
+ }{%
+ \let\tikzumlRelationSrcAnchorold\tikzumlRelationSrcAnchor%
+ \def\tikzumlRelationSrcAnchor{.\tikzumlRelationSrcAnchorold}%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlRelationDestAnchor}{tikzumlEmpty}}{%
+ \def\tikzumlRelationDestAnchor{}%
+ }{%
+ \let\tikzumlRelationDestAnchorold\tikzumlRelationDestAnchor%
+ \def\tikzumlRelationDestAnchor{.\tikzumlRelationDestAnchorold}%
+ }%
+ %
+ \setcounter{pos}{100*\real{\tikzumlRelationPosition}}%
+ \setcounter{posT}{100*\real{\tikzumlRelationPositionT}}%
+ \setcounter{posStereo}{100*\real{\tikzumlRelationPositionStereotype}}%
+ %
+ \pgfmathsetmacro{\tikzumlRelationWeightT}{1.0-\tikzumlRelationWeight}%
+ %
+ %\newcounter{tikzumlControlNodesNum}%
+ %\setcounter{tikzumlControlNodesNum}{0}%
+ %
+ \node[inner sep=0] (\tikzumlRelationName-middle) at (barycentric cs:\tikzumlSrcClassNodeName=\tikzumlRelationWeightT,\tikzumlDestClassNodeName=\tikzumlRelationWeight) {};%
+ %
+ % straight line
+ \ifthenelse{\equal{\tikzumlRelationGeometry}{--}}%
+ {%
+ \ifthenelse{\equal{\tikzumlSrcClassNodeName}{\tikzumlDestClassNodeName}}{%
+ \def\arcNum{1}%
+ \def\arcNumT{1}%
+ %
+ \ifthenelse{\equal{\tikzumlRelationRecursiveMode}{default}}{%
+ \xdef\tikzumlLastArc{node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity}%
+ node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT}%
+ node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \xdef\tikzumlPath{(\tikzumlSrcClassNodeName) edge[in=\tikzumlRelationEndAngle, out=\tikzumlRelationStartAngle, distance=\tikzumlRelationLoopSize] \tikzumlLastArc%
+ node[midway, inner sep=0, name=\tikzumlRelationName-1, anchor=center] {} (\tikzumlDestClassNodeName) }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveMode}{transition}}{%
+ \xdef\tikzumlFirstArc{node[midway, inner sep=0, name=\tikzumlRelationName-1, anchor=center] {}}%
+ \xdef\tikzumlMidOneArc{node[midway, inner sep=0, name=\tikzumlRelationName-3, anchor=center] {}}%
+ %
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{\tikzumlRelationRecursiveDirectionEnd}}{%
+ \def\numArcs{3}%
+ \xdef\tikzumlLastArc{node[midway, inner sep=0, name=\tikzumlRelationName-5, anchor=center] {}}%
+ %
+ \begin{pgfonlayer}{connections}%
+ \draw (\tikzumlSrcClassNodeName) edge[in=\tikzumlRelationEndAngle, out=\tikzumlRelationStartAngle, distance=\tikzumlRelationLoopSize, draw=none] %
+ node[midway, inner sep=0, name=\tikzumlRelationName-tmp, anchor=center] {} (\tikzumlDestClassNodeName);%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}\OR\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{%
+ \node[inner sep=0, name=\tikzumlRelationName-2] at (\tikzumlSrcClassNodeName.\tikzumlRelationStartAngle -| \tikzumlRelationName-tmp) {};%
+ \node[inner sep=0, name=\tikzumlRelationName-4] at (\tikzumlDestClassNodeName.\tikzumlRelationEndAngle -| \tikzumlRelationName-tmp) {};%
+ }{%
+ \node[inner sep=0, name=\tikzumlRelationName-2] at (\tikzumlSrcClassNodeName.\tikzumlRelationStartAngle |- \tikzumlRelationName-tmp) {};%
+ \node[inner sep=0, name=\tikzumlRelationName-4] at (\tikzumlDestClassNodeName.\tikzumlRelationEndAngle |- \tikzumlRelationName-tmp) {};%
+ }%
+ \end{pgfonlayer}%
+ }{%
+ \def\numArcs{4}%
+ \xdef\tikzumlMidTwoArc{node[midway, inner sep=0, name=\tikzumlRelationName-5, anchor=center] {}}%
+ \xdef\tikzumlLastArc{node[midway, inner sep=0, name=\tikzumlRelationName-7, anchor=center] {}}%
+ %
+ \begin{pgfonlayer}{connections}%
+ \draw (\tikzumlSrcClassNodeName) edge[in=\tikzumlRelationEndAngle, out=\tikzumlRelationStartAngle, distance=\tikzumlRelationLoopSize, draw=none] %
+ node[midway, name=\tikzumlRelationName-4, anchor=center] {} (\tikzumlDestClassNodeName);%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}\OR\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{%
+ \node[inner sep=0, name=\tikzumlRelationName-2] at (\tikzumlSrcClassNodeName.\tikzumlRelationStartAngle -| \tikzumlRelationName-4) {};%
+ \node[inner sep=0, name=\tikzumlRelationName-6] at (\tikzumlDestClassNodeName.\tikzumlRelationEndAngle |- \tikzumlRelationName-4) {};%
+ }{%
+ \node[inner sep=0, name=\tikzumlRelationName-2] at (\tikzumlSrcClassNodeName.\tikzumlRelationStartAngle |- \tikzumlRelationName-4) {};%
+ \node[inner sep=0, name=\tikzumlRelationName-6] at (\tikzumlDestClassNodeName.\tikzumlRelationEndAngle -| \tikzumlRelationName-4) {};%
+ }%
+ \end{pgfonlayer}%
+ }%
+ %
+ \ifnum\numArcs=4%
+ \ifnum\theposStereo>300%
+ \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-300)/100}%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype}}%
+ \else%
+ \ifnum\theposStereo<100%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype}}%
+ \else%
+ \ifnum\theposStereo>200%
+ \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-200)/100}%
+ \xdef\tikzumlMidTwoArc{\tikzumlMidTwoArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype}}%
+ \else%
+ \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-100)/100}%
+ \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype}}%
+ \fi%
+ \fi%
+ \fi%
+ %
+ \ifthenelse{\thepos=300\OR\thepos=100}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{bottom}}{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{bottom}}{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{top}}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{left}}{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{left}}{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }%
+ }%
+ }%
+ }%
+ }{}%
+ %
+ \ifthenelse{\thepos=200}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{bottom}}{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{bottom}}{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{top}}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{left}}{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{left}}{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }%
+ }%
+ }%
+ }%
+ }{}%
+ %
+ \ifnum\thepos>300%
+ \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-300)/100}%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity}%
+ }%
+ \else%
+ \ifnum\thepos<100%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity}%
+ }%
+ \else%
+ \ifnum\thepos>200%
+ \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-200)/100}%
+ \xdef\tikzumlMidTwoArc{\tikzumlMidTwoArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity}%
+ }%
+ \else%
+ \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-100)/100}%
+ \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity}%
+ }%
+ \fi%
+ \fi%
+ \fi%
+ %
+ \ifthenelse{\theposT=300\OR\theposT=100}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{bottom}}{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{bottom}}{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{top}}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{left}}{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{left}}{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }%
+ }%
+ }%
+ }%
+ }{}%
+ \ifthenelse{\theposT=200}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{bottom}}{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicity{below right}%
+ }{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{bottom}}{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{top}}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{left}}{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{left}}{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }%
+ }%
+ }%
+ }%
+ }{}%
+ %
+ \ifnum\theposT>300%
+ \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-300)/100}%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT}%
+ }%
+ \else%
+ \ifnum\theposT<100%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT}%
+ }%
+ \else%
+ \ifnum\theposT>200%
+ \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-200)/100}%
+ \xdef\tikzumlMidTwoArc{\tikzumlMidTwoArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT}%
+ }%
+ \else%
+ \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-100)/100}%
+ \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT}%
+ }%
+ \fi%
+ \fi%
+ \fi%
+ \else%
+ \ifnum\theposStereo>200%
+ \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-200)/100}%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \else%
+ \ifnum\theposStereo<100%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \else%
+ \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-100)/100}%
+ \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \fi%
+ \fi%
+ %
+ \ifthenelse{\thepos=100}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}}{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{top}}{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }%
+ }{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }%
+ }%
+ }%
+ }%
+ }{}%
+ %
+ \ifthenelse{\thepos=200}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}}{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{top}}{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }%
+ }{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrName{above right}%
+ \def\posMultiplicity{below left}%
+ }{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }%
+ }%
+ }%
+ }%
+ }{}%
+ %
+ \ifnum\thepos>200%
+ \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-200)/100}%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity}%
+ }%
+ \else%
+ \ifnum\thepos<100%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity}%
+ }%
+ \else%
+ \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-100)/100}%
+ \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity}%
+ }%
+ \fi%
+ \fi%
+ %
+ \ifthenelse{\theposT=100}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}}{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{top}}{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }%
+ }{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }%
+ }%
+ }%
+ }%
+ }{}%
+ %
+ \ifthenelse{\theposT=200}{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}}{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{top}}{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }%
+ }{%
+ \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{%
+ \def\posAttrNameT{above right}%
+ \def\posMultiplicityT{below left}%
+ }{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }%
+ }%
+ }%
+ }%
+ }{}%
+ %
+ \ifnum\theposT>200%
+ \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-200)/100}%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT}%
+ }%
+ \else%
+ \ifnum\theposT<100%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT}%
+ }%
+ \else%
+ \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-100)/100}%
+ \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT}%
+ }%
+ \fi%
+ \fi%
+ \fi%
+ %
+ \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{\tikzumlRelationRecursiveDirectionEnd}}{%
+ \xdef\tikzumlPath{(\tikzumlSrcClassNodeName.\tikzumlRelationStartAngle) -- \tikzumlFirstArc (\tikzumlRelationName-2.center) -- \tikzumlMidOneArc (\tikzumlRelationName-4.center) -- \tikzumlLastArc (\tikzumlDestClassNodeName.\tikzumlRelationEndAngle) }%
+ \ifnum\thetikzumlStateLevel>0%
+ \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitTmp (\tikzumlRelationName-1) (\tikzumlRelationName-2) (\tikzumlRelationName-3) (\tikzumlRelationName-4) (\tikzumlRelationName-5)}%
+ \fi%
+ }{%
+ \xdef\tikzumlPath{(\tikzumlSrcClassNodeName.\tikzumlRelationStartAngle) -- \tikzumlFirstArc (\tikzumlRelationName-2.center) -- \tikzumlMidOneArc (\tikzumlRelationName-4.center) -- \tikzumlMidTwoArc (\tikzumlRelationName-6.center) -- \tikzumlLastArc (\tikzumlDestClassNodeName.\tikzumlRelationEndAngle) }%
+ \ifnum\thetikzumlStateLevel>0%
+ \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitTmp (\tikzumlRelationName-1) (\tikzumlRelationName-2) (\tikzumlRelationName-3) (\tikzumlRelationName-4) (\tikzumlRelationName-5) (\tikzumlRelationName-6) (\tikzumlRelationName-7)}%
+ \fi%
+ }%
+ }{}%
+ }%
+ }{%
+ \def\arcNum{1}%
+ \def\arcNumT{1}%
+ %
+ \node[inner sep=0] (\tikzumlRelationName-1) at (\tikzumlRelationName-middle) {};%
+ \xdef\tikzumlLastArc{node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity}%
+ node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT}%
+ node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \xdef\tikzumlPath{(\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor) -- \tikzumlLastArc (\tikzumlDestClassNodeName\tikzumlRelationDestAnchor) }%
+ \ifnum\thetikzumlStateLevel>0%
+ \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitTmp (\tikzumlRelationName-1) }%
+ \fi%
+ }%
+ }{%
+ % first vertical then horizontal line
+ \ifthenelse{\equal{\tikzumlRelationGeometry}{|-}}%
+ {%
+ %\setcounter{tikzumlControlNodesNum}{1}%
+ %
+ \def\tikzumlFirstArc{node[midway, inner sep=0, name=\tikzumlRelationName-1, anchor=center] {} }%
+ \def\tikzumlLastArc{node[midway, inner sep=0, name=\tikzumlRelationName-3, anchor=center]{} }%
+ %
+ \begin{pgfonlayer}{connections}%
+ \node[inner sep=0] (\tikzumlRelationName-2) at (\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor |- \tikzumlDestClassNodeName\tikzumlRelationDestAnchor) {};%
+ \end{pgfonlayer}%
+ %
+ \ifnum\theposStereo>100%
+ \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-100)/100}%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \else%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \fi%
+ %
+ \ifnum\thepos>100%
+ \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-100)/100}%
+ \def\arcNum{2}%
+ \else%
+ \def\arcNum{1}%
+ \ifnum\thepos=100%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ \fi%
+ \fi%
+ %
+ \ifnum\arcNum=1%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }%
+ \fi%
+ \ifnum\arcNum=2%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }%
+ \fi%
+ %
+ \ifnum\theposT>100%
+ \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-100)/100}%
+ \def\arcNumT{2}%
+ \else%
+ \def\arcNumT{1}%
+ \ifnum\theposT=100%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ \fi%
+ \fi%
+ %
+ \ifnum\arcNumT=1%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }%
+ \fi%
+ \ifnum\arcNumT=2%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }%
+ \fi%
+ %
+ \xdef\tikzumlPath{(\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor) -- \tikzumlFirstArc (\tikzumlRelationName-2.base) -- \tikzumlLastArc (\tikzumlDestClassNodeName\tikzumlRelationDestAnchor) }%
+ \ifnum\thetikzumlStateLevel>0%
+ \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitTmp (\tikzumlRelationName-1) (\tikzumlRelationName-2) (\tikzumlRelationName-3) }%
+ \fi%
+ }{%
+ % first horizontal then vertical line
+ \ifthenelse{\equal{\tikzumlRelationGeometry}{-|}}%
+ {%
+ %\setcounter{tikzumlControlNodesNum}{1}%
+ %
+ \def\tikzumlFirstArc{node[midway, inner sep=0, name=\tikzumlRelationName-1, anchor=center]{} }%
+ \def\tikzumlLastArc{node[midway, inner sep=0, name=\tikzumlRelationName-3, anchor=center] {} }%
+ %
+ \begin{pgfonlayer}{connections}%
+ \node[inner sep=0] (\tikzumlRelationName-2) at (\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor -| \tikzumlDestClassNodeName\tikzumlRelationDestAnchor) {};%
+ \end{pgfonlayer}%
+ %
+ \ifnum\theposStereo>100%
+ \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-100)/100}%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \else%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \fi%
+ %
+ \ifnum\thepos>100%
+ \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-100)/100}%
+ \def\arcNum{2}%
+ \else%
+ \def\arcNum{1}%
+ \ifnum\thepos=100%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ \fi%
+ \fi%
+ %
+ \ifnum\arcNum=1%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }%
+ \fi%
+ \ifnum\arcNum=2%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }%
+ \fi%
+ %
+ \ifnum\theposT>100%
+ \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-100)/100}%
+ \def\arcNumT{2}%
+ \else%
+ \def\arcNumT{1}%
+ \ifnum\theposT=100%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ \fi%
+ \fi%
+ %
+ \ifnum\arcNumT=1%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }%
+ \fi%
+ \ifnum\arcNumT=2%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }%
+ \fi%
+ %
+ \xdef\tikzumlPath{(\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor) -- \tikzumlFirstArc (\tikzumlRelationName-2.base) -- \tikzumlLastArc (\tikzumlDestClassNodeName\tikzumlRelationDestAnchor) }%
+ \ifnum\thetikzumlStateLevel>0%
+ \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitTmp (\tikzumlRelationName-1) (\tikzumlRelationName-2) (\tikzumlRelationName-3) }%
+ \fi%
+ }{%
+ % first vertical, then horizontal, finally vertical line
+ \ifthenelse{\equal{\tikzumlRelationGeometry}{|-|}}%
+ {%
+ %\setcounter{tikzumlControlNodesNum}{2}%
+ %
+ \def\tikzumlFirstArc{node[midway, inner sep=0, name=\tikzumlRelationName-1, anchor=center] {} }%
+ \def\tikzumlLastArc{node[midway, inner sep=0, name=\tikzumlRelationName-5, anchor=center] {} }%
+ \def\tikzumlMidOneArc{ }%
+ %
+ \begin{pgfonlayer}{connections}%
+ %
+ \ifthenelse{\equal{\tikzumlRelationArmO}{auto}}{%
+ \ifthenelse{\equal{\tikzumlRelationArmT}{auto}}{%
+ \node[inner sep=0] (\tikzumlRelationName-3) at (\tikzumlRelationName-middle) {};%
+ \node[inner sep=0] (\tikzumlRelationName-2) at (\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor |- \tikzumlRelationName-3) {};%
+ \node[inner sep=0] (\tikzumlRelationName-4) at (\tikzumlRelationName-3 -| \tikzumlDestClassNodeName\tikzumlRelationDestAnchor) {};%
+ }{%
+ \draw (\tikzumlDestClassNodeName\tikzumlRelationDestAnchor)+(0,\tikzumlRelationArmT) node[inner sep=0, name=\tikzumlRelationName-4] {};%
+ \node[inner sep=0] (\tikzumlRelationName-2) at (\tikzumlRelationName-4 -| \tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor) {};%
+ \node[inner sep=0] (\tikzumlRelationName-3) at (barycentric cs:\tikzumlRelationName-2=0.5,\tikzumlRelationName-4=0.5) {};%
+ }%
+ }{%
+ \draw (\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor)+(0,\tikzumlRelationArmO) node[inner sep=0, name=\tikzumlRelationName-2] {};%
+ \node[inner sep=0] (\tikzumlRelationName-4) at (\tikzumlRelationName-2 -| \tikzumlDestClassNodeName\tikzumlRelationDestAnchor) {};%
+ \node[inner sep=0] (\tikzumlRelationName-3) at (barycentric cs:\tikzumlRelationName-2=0.5,\tikzumlRelationName-4=0.5) {};%
+ }%
+ \end{pgfonlayer}%
+ %
+ \ifnum\theposStereo>200%
+ \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-200)/100}%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \else%
+ \ifnum\theposStereo<100%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \else%
+ \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-100)/100}%
+ \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \fi%
+ \fi%
+ %
+ \ifthenelse{\thepos=200\OR\thepos=100}{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }{}%
+ %
+ \ifthenelse{\thepos>200}{%
+ \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-200)/100}%
+ \def\arcNum{3}%
+ }{%
+ \ifthenelse{\thepos<100}{%
+ \def\arcNum{1}%
+ }{%
+ \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-100)/100}%
+ \def\arcNum{2}%
+ }%
+ }%
+ %
+ \ifnum\arcNum=1%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }%
+ \fi%
+ \ifnum\arcNum=2%
+ \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }%
+ \fi%
+ \ifnum\arcNum=3%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }%
+ \fi%
+ %
+ \ifthenelse{\theposT=200\OR\theposT=100}{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }{}%
+ %
+ \ifthenelse{\theposT>200}{%
+ \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-200)/100}%
+ \def\arcNumT{3}%
+ }{%
+ \ifthenelse{\theposT<100}{%
+ \def\arcNumT{1}%
+ }{%
+ \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-100)/100}%
+ \def\arcNumT{2}%
+ }%
+ }%
+ %
+ \ifnum\arcNumT=1%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }%
+ \fi%
+ \ifnum\arcNumT=2%
+ \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }%
+ \fi%
+ \ifnum\arcNumT=3%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }%
+ \fi%
+ %
+ \xdef\tikzumlPath{(\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor) -- \tikzumlFirstArc (\tikzumlRelationName-2.base) -- \tikzumlMidOneArc (\tikzumlRelationName-4.base) -- \tikzumlLastArc (\tikzumlDestClassNodeName\tikzumlRelationDestAnchor) }%
+ \ifnum\thetikzumlStateLevel>0%
+ \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitTmp (\tikzumlRelationName-1) (\tikzumlRelationName-2) (\tikzumlRelationName-3) (\tikzumlRelationName-4) (\tikzumlRelationName-5) }%
+ \fi%
+ }{%
+ % first horizontal, then vertical, finally horizontal line
+ \ifthenelse{\equal{\tikzumlRelationGeometry}{-|-}}%
+ {%
+ %\setcounter{tikzumlControlNodesNum}{2}%
+ %
+ \def\tikzumlFirstArc{node[midway, inner sep=0, name=\tikzumlRelationName-1, anchor=center] {} }%
+ \def\tikzumlLastArc{node[midway, inner sep=0, name=\tikzumlRelationName-5, anchor=center] {} }%
+ \def\tikzumlMidOneArc{}%
+ %
+ \begin{pgfonlayer}{connections}%
+ %
+ \ifthenelse{\equal{\tikzumlRelationArmO}{auto}}{%
+ \ifthenelse{\equal{\tikzumlRelationArmT}{auto}}{%
+ \node[inner sep=0] (\tikzumlRelationName-3) at (\tikzumlRelationName-middle) {};%
+ \node[inner sep=0] (\tikzumlRelationName-2) at (\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor -| \tikzumlRelationName-3) {};%
+ \node[inner sep=0] (\tikzumlRelationName-4) at (\tikzumlRelationName-3 |- \tikzumlDestClassNodeName\tikzumlRelationDestAnchor) {};%
+ }{%
+ \draw (\tikzumlDestClassNodeName\tikzumlRelationDestAnchor)+(\tikzumlRelationArmT,0) node[inner sep=0, name=\tikzumlRelationName-4] {};%
+ \node[inner sep=0] (\tikzumlRelationName-2) at (\tikzumlRelationName-4 |- \tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor) {};%
+ \node[inner sep=0] (\tikzumlRelationName-3) at (barycentric cs:\tikzumlRelationName-2=0.5,\tikzumlRelationName-4=0.5) {};%
+ }%
+ }{%
+ \draw (\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor)+(\tikzumlRelationArmO,0) node[inner sep=0, name=\tikzumlRelationName-2] {};%
+ \node[inner sep=0] (\tikzumlRelationName-4) at (\tikzumlRelationName-2 |- \tikzumlDestClassNodeName\tikzumlRelationDestAnchor) {};%
+ \node[inner sep=0] (\tikzumlRelationName-3) at (barycentric cs:\tikzumlRelationName-2=0.5,\tikzumlRelationName-4=0.5) {};%
+ }%
+ \end{pgfonlayer}%
+ %
+ \ifnum\theposStereo>200%
+ \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-200)/100}%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \else%
+ \ifnum\theposStereo<100%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \else%
+ \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-100)/100}%
+ \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \fi%
+ \fi%
+ %
+ \ifthenelse{\thepos=200\OR\thepos=100}{%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ }{}%
+ %
+ \ifthenelse{\thepos>200}{%
+ \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-200)/100}%
+ \def\arcNum{3}%
+ }{%
+ \ifthenelse{\thepos<100}{%
+ \def\arcNum{1}%
+ }{%
+ \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-100)/100}%
+ \def\arcNum{2}%
+ }%
+ }%
+ %
+ \ifnum\arcNum=1%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }%
+ \fi%
+ \ifnum\arcNum=2%
+ \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }%
+ \fi%
+ \ifnum\arcNum=3%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}%
+ node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }%
+ \fi%
+ %
+ \ifthenelse{\theposT=200\OR\theposT=100}{%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ }{}%
+ %
+ \ifthenelse{\theposT>200}{%
+ \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-200)/100}%
+ \def\arcNumT{3}%
+ }{%
+ \ifthenelse{\theposT<100}{%
+ \def\arcNumT{1}%
+ }{%
+ \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-100)/100}%
+ \def\arcNumT{2}%
+ }%
+ }%
+ %
+ \ifnum\arcNumT=1%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }%
+ \fi%
+ \ifnum\arcNumT=2%
+ \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }%
+ \fi%
+ \ifnum\arcNumT=3%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}%
+ node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }%
+ \fi%
+ %
+ \xdef\tikzumlPath{(\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor) -- \tikzumlFirstArc (\tikzumlRelationName-2.base) -- \tikzumlMidOneArc (\tikzumlRelationName-4.base) -- \tikzumlLastArc (\tikzumlDestClassNodeName\tikzumlRelationDestAnchor) }%
+ \ifnum\thetikzumlStateLevel>0%
+ \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitTmp (\tikzumlRelationName-1) (\tikzumlRelationName-2) (\tikzumlRelationName-3) (\tikzumlRelationName-4) (\tikzumlRelationName-5) }%
+ \fi%
+ }{%
+ \errmessage{TIKZUML ERROR : Unknown geometry value !!! It should be in the following list : --, |-, -|, |-|, -|-}%
+ }%
+ }%
+ }%
+ }%
+ }%
+ %
+ \begin{pgfonlayer}{connections}%
+ \ifthenelse{\equal{\tikzumlRelationStyle}{tikzuml nesting style}}{%
+ \pgfarrowsdeclare{nested}{nested}{...}
+ {
+ \tikzumlNestingSymbolSize=0.2pt%
+ \advance\tikzumlNestingSymbolSize by .5\pgflinewidth%
+ \pgfsetdash{}{0pt} % do not dash
+ \pgfsetroundjoin % fix join
+ \pgfsetroundcap % fix cap
+ \pgfpathmoveto{\pgfpoint{-16*\tikzumlNestingSymbolSize}{0pt}}%
+ \pgfpatharc{180}{90}{8*\tikzumlNestingSymbolSize}%
+ \pgfpatharc{90}{0}{8*\tikzumlNestingSymbolSize}%
+ \pgfpatharc{0}{-90}{8*\tikzumlNestingSymbolSize}%
+ \pgfpatharc{-90}{-180}{8*\tikzumlNestingSymbolSize}%
+ \pgfpathmoveto{\pgfpoint{-8*\tikzumlNestingSymbolSize}{8*\tikzumlNestingSymbolSize}}%
+ \pgfpathlineto{\pgfpoint{-8*\tikzumlNestingSymbolSize}{-8*\tikzumlNestingSymbolSize}}%
+ \pgfusepathqstroke%
+ }%
+ \draw[auto, nested-, font=\tikzumlDefaultFont, \tikzumlRelationStyle, /tikzuml/relation/style2] \tikzumlPath ;%
+ }{
+ \draw[auto, font=\tikzumlDefaultFont, \tikzumlRelationStyle, /tikzuml/relation/style2] \tikzumlPath ;%
+ }
+ \end{pgfonlayer}%
+ %
+ \stepcounter{tikzumlRelationNum}%
+}%
+%
+% shortcuts of \umlrelation
+\newcommand{\umlHVrelation}[3][]{%
+ \pgfkeys{/tikzuml/HVrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlHVrelation, forbidden option geometry}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/HVrelation/.cd, #1}%
+ \umlrelation[geometry=-|, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlVHrelation}[3][]{%
+ \pgfkeys{/tikzuml/VHrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlVHrelation, forbidden option geometry}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/VHrelation/.cd, #1}%
+ \umlrelation[geometry=|-, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlHVHrelation}[3][]{%
+ \pgfkeys{/tikzuml/HVHrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlHVHrelation, forbidden option geometry}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/HVHrelation/.cd, #1}%
+ \umlrelation[geometry=-|-, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlVHVrelation}[3][]{%
+ \pgfkeys{/tikzuml/VHVrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlVHVrelation, forbidden option geometry}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/VHVrelation/.cd, #1}%
+ \umlrelation[geometry=|-|, #1]{#2}{#3}%
+}%
+%
+%
+% shortcuts for relations
+\newcommand{\umlinherit}[3][]{\umlrelation[style={tikzuml inherit style}, #1]{#2}{#3}}%
+\newcommand{\umlimpl}[3][]{\umlrelation[style={tikzuml implements style}, #1]{#2}{#3}}%
+\newcommand{\umlreal}[3][]{\umlrelation[style={tikzuml implements style}, #1]{#2}{#3}}%
+\newcommand{\umlassoc}[3][]{\umlrelation[style={tikzuml association style}, #1]{#2}{#3}}%
+\newcommand{\umlbiassoc}[3][]{\umlrelation[style={tikzuml bidirectional association style}, #1]{#2}{#3}}%
+\newcommand{\umluniassoc}[3][]{\umlrelation[style={tikzuml unidirectional association style}, #1]{#2}{#3}}%
+\newcommand{\umlaggreg}[3][]{\umlrelation[style={tikzuml aggregation style}, #1]{#2}{#3}}%
+\newcommand{\umluniaggreg}[3][]{\umlrelation[style={tikzuml unidirectional aggregation style}, #1]{#2}{#3}}%
+\newcommand{\umlcompo}[3][]{\umlrelation[style={tikzuml composition style}, #1]{#2}{#3}}%
+\newcommand{\umlunicompo}[3][]{\umlrelation[style={tikzuml unidirectional composition style}, #1]{#2}{#3}}%
+\newcommand{\umlimport}[3][]{\umlrelation[style={tikzuml import style}, #1]{#2}{#3}}%
+\newcommand{\umlnest}[3][]{\umlrelation[style={tikzuml nesting style}, #1]{#2}{#3}}%
+\newcommand{\umldep}[3][]{\umlrelation[style={tikzuml dependency style}, #1]{#2}{#3}}%
+\newcommand{\umlfriend}[3][]{%
+ \pgfkeys{/tikzuml/friendrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlfriend, forbidden option stereo}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/friendrelation/.cd, #1}%
+ \umlrelation[stereo=friend, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlHVinherit}[3][]{\umlHVrelation[style={tikzuml inherit style}, #1]{#2}{#3}}%
+\newcommand{\umlHVimpl}[3][]{\umlHVrelation[style={tikzuml implements style}, #1]{#2}{#3}}%
+\newcommand{\umlHVreal}[3][]{\umlHVrelation[style={tikzuml implements style}, #1]{#2}{#3}}%
+\newcommand{\umlHVassoc}[3][]{\umlHVrelation[style={tikzuml association style}, #1]{#2}{#3}}%
+\newcommand{\umlHVuniassoc}[3][]{\umlHVrelation[style={tikzuml unidirectional association style}, #1]{#2}{#3}}%
+\newcommand{\umlHVaggreg}[3][]{\umlHVrelation[style={tikzuml aggregation style}, #1]{#2}{#3}}%
+\newcommand{\umlHVuniaggreg}[3][]{\umlHVrelation[style={tikzuml unidirectional aggregation style}, #1]{#2}{#3}}%
+\newcommand{\umlHVcompo}[3][]{\umlHVrelation[style={tikzuml composition style}, #1]{#2}{#3}}%
+\newcommand{\umlHVunicompo}[3][]{\umlHVrelation[style={tikzuml unidirectional composition style}, #1]{#2}{#3}}%
+\newcommand{\umlHVimport}[3][]{\umlHVrelation[style={tikzuml import style}, #1]{#2}{#3}}%
+\newcommand{\umlHVnest}[3][]{\umlHVrelation[style={tikzuml nesting style}, #1]{#2}{#3}}%
+\newcommand{\umlHVdep}[3][]{\umlHVrelation[style={tikzuml dependency style}, #1]{#2}{#3}}%
+\newcommand{\umlHVfriend}[3][]{%
+ \pgfkeys{/tikzuml/friendrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlHVfriend, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlHVfriend, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/friendrelation/.cd, #1}%
+ \umlrelation[geometry=-|, stereo=friend, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlVHinherit}[3][]{\umlVHrelation[style={tikzuml inherit style}, #1]{#2}{#3}}%
+\newcommand{\umlVHimpl}[3][]{\umlVHrelation[style={tikzuml implements style}, #1]{#2}{#3}}%
+\newcommand{\umlVHreal}[3][]{\umlVHrelation[style={tikzuml implements style}, #1]{#2}{#3}}%
+\newcommand{\umlVHassoc}[3][]{\umlVHrelation[style={tikzuml association style}, #1]{#2}{#3}}%
+\newcommand{\umlVHuniassoc}[3][]{\umlVHrelation[style={tikzuml unidirectional association style}, #1]{#2}{#3}}%
+\newcommand{\umlVHaggreg}[3][]{\umlVHrelation[style={tikzuml aggregation style}, #1]{#2}{#3}}%
+\newcommand{\umlVHuniaggreg}[3][]{\umlVHrelation[style={tikzuml unidirectional aggregation style}, #1]{#2}{#3}}%
+\newcommand{\umlVHcompo}[3][]{\umlVHrelation[style={tikzuml composition style}, #1]{#2}{#3}}%
+\newcommand{\umlVHunicompo}[3][]{\umlVHrelation[style={tikzuml unidirectional composition style}, #1]{#2}{#3}}%
+\newcommand{\umlVHimport}[3][]{\umlVHrelation[style={tikzuml import style}, #1]{#2}{#3}}%
+\newcommand{\umlVHnest}[3][]{\umlVHrelation[style={tikzuml nesting style}, #1]{#2}{#3}}%
+\newcommand{\umlVHdep}[3][]{\umlVHrelation[style={tikzuml dependency style}, #1]{#2}{#3}}%
+\newcommand{\umlVHfriend}[3][]{%
+ \pgfkeys{/tikzuml/friendrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlVHfriend, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlVHfriend, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/friendrelation/.cd, #1}%
+ \umlrelation[geometry=|-, stereo=friend, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlHVHinherit}[3][]{\umlHVHrelation[style={tikzuml inherit style}, #1]{#2}{#3}}%
+\newcommand{\umlHVHimpl}[3][]{\umlHVHrelation[style={tikzuml implements style}, #1]{#2}{#3}}%
+\newcommand{\umlHVHreal}[3][]{\umlHVHrelation[style={tikzuml implements style}, #1]{#2}{#3}}%
+\newcommand{\umlHVHassoc}[3][]{\umlHVHrelation[style={tikzuml association style}, #1]{#2}{#3}}%
+\newcommand{\umlHVHuniassoc}[3][]{\umlHVHrelation[style={tikzuml unidirectional association style}, #1]{#2}{#3}}%
+\newcommand{\umlHVHaggreg}[3][]{\umlHVHrelation[style={tikzuml aggregation style}, #1]{#2}{#3}}%
+\newcommand{\umlHVHuniaggreg}[3][]{\umlHVHrelation[style={tikzuml unidirectional aggregation style}, #1]{#2}{#3}}%
+\newcommand{\umlHVHcompo}[3][]{\umlHVHrelation[style={tikzuml composition style}, #1]{#2}{#3}}%
+\newcommand{\umlHVHunicompo}[3][]{\umlHVHrelation[style={tikzuml unidirectional composition style}, #1]{#2}{#3}}%
+\newcommand{\umlHVHimport}[3][]{\umlHVHrelation[style={tikzuml import style}, #1]{#2}{#3}}%
+\newcommand{\umlHVHnest}[3][]{\umlHVHrelation[style={tikzuml nesting style}, #1]{#2}{#3}}%
+\newcommand{\umlHVHdep}[3][]{\umlHVHrelation[style={tikzuml dependency style}, #1]{#2}{#3}}%
+\newcommand{\umlHVHfriend}[3][]{%
+ \pgfkeys{/tikzuml/friendrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlHVHfriend, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlHVHfriend, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/friendrelation/.cd, #1}%
+ \umlrelation[geometry=-|-, stereo=friend, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlVHVinherit}[3][]{\umlVHVrelation[style={tikzuml inherit style}, #1]{#2}{#3}}%
+\newcommand{\umlVHVimpl}[3][]{\umlVHVrelation[style={tikzuml implements style}, #1]{#2}{#3}}%
+\newcommand{\umlVHVreal}[3][]{\umlVHVrelation[style={tikzuml implements style}, #1]{#2}{#3}}%
+\newcommand{\umlVHVassoc}[3][]{\umlVHVrelation[style={tikzuml association style}, #1]{#2}{#3}}%
+\newcommand{\umlVHVuniassoc}[3][]{\umlVHVrelation[style={tikzuml unidirectional association style}, #1]{#2}{#3}}%
+\newcommand{\umlVHVaggreg}[3][]{\umlVHVrelation[style={tikzuml aggregation style}, #1]{#2}{#3}}%
+\newcommand{\umlVHVuniaggreg}[3][]{\umlVHVrelation[style={tikzuml unidirectional aggregation style}, #1]{#2}{#3}}%
+\newcommand{\umlVHVcompo}[3][]{\umlVHVrelation[style={tikzuml composition style}, #1]{#2}{#3}}%
+\newcommand{\umlVHVunicompo}[3][]{\umlVHVrelation[style={tikzuml unidirectional composition style}, #1]{#2}{#3}}%
+\newcommand{\umlVHVimport}[3][]{\umlVHVrelation[style={tikzuml import style}, #1]{#2}{#3}}%
+\newcommand{\umlVHVnest}[3][]{\umlVHVrelation[style={tikzuml nesting style}, #1]{#2}{#3}}%
+\newcommand{\umlVHVdep}[3][]{\umlVHVrelation[style={tikzuml dependency style}, #1]{#2}{#3}}%
+\newcommand{\umlVHVfriend}[3][]{%
+ \pgfkeys{/tikzuml/friendrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlVHVfriend, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlVHVfriend, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/friendrelation/.cd, #1}%
+ \umlrelation[geometry=|-|, stereo=friend, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+%
+% define a node
+\newcommand{\umlnode}[2]{%
+ \node (#2) at (#1) {};%
+}%
+%
+% main command to define a relation between two classes through a control node
+% args : src class
+% control node
+% dest class
+% optional : arg1, arg2, arg: name of the src/dest/dest side class type attribute defined by the relation
+% mult1, mult2, mult: multiplicity of the src/dest/dest side class type attribute defined by the relation
+% pos1, pos2, pos: position of the src/dest/dest side class type attribute defined by the relation
+% align1, align2, align: text justification of the src/dest/dest side class type attribute defined by the relation
+% anchor1, anchor2: src/dest anchors on linked classes
+% stereo: stereotype of the relation
+% pos stereo: position of the stereotype on the relation
+% style: style of the relation (association, aggregation, composition, inherit, ...)
+% name: rootname used for naming nodes of the relation
+\newcommand{\umlCNrelation}[4][]{%
+ \pgfkeys{/tikzuml/relation/.cd, arg1/.initial={}, arg2/.initial={}, arg/.initial={},%
+ mult1/.initial={}, mult2/.initial={}, mult/.initial={},%
+ pos1/.initial=0.2, pos2/.initial=0.8, pos/.initial=tikzumlEmpty,%
+ align1/.initial={}, align2/.initial={}, align/.initial={},%
+ anchor1/.initial=tikzumlEmpty, anchor2/.initial=tikzumlEmpty,%
+ stereo/.initial={}, pos stereo/.initial=1,%
+ style/.initial=->, name/.initial=relation-\thetikzumlRelationNum,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \errmessage{TIKZUML ERROR : in umlCNrelation, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/relation/.cd,#1}%
+ \pgfkeys{/tikzuml/relation/.cd, arg1/.get=\tikzumlCNRelationAttrName, arg2/.get=\tikzumlCNRelationAttrNameTO, arg/.get=\tikzumlCNRelationAttrNameTT,%
+ mult1/.get=\tikzumlCNRelationMultiplicity, mult2/.get=\tikzumlCNRelationMultiplicityTO, mult/.get=\tikzumlCNRelationMultiplicityTT,%
+ pos1/.get=\tikzumlCNRelationPosition, pos2/.get=\tikzumlCNRelationPositionTO, pos/.get=\tikzumlCNRelationPositionTT,%
+ align1/.get=\tikzumlCNRelationAlign, align2/.get=\tikzumlCNRelationAlignTO, align/.get=\tikzumlCNRelationAlignTT,%
+ anchor1/.get=\tikzumlCNRelationSrcAnchor, anchor2/.get=\tikzumlCNRelationDestAnchor,%
+ stereo/.get=\tikzumlCNRelationStereoType, pos stereo/.get=\tikzumlCNRelationPositionStereotype,%
+ style/.get=\tikzumlCNRelationStyle, name/.get=\tikzumlCNRelationName%
+ }%
+ %
+ % managing \_ in class names for node names
+ \def\tikzumlSrcClassName{#2}%
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlSrcClassNodeName{\tikzumlSrcClassName}}\x%
+ %
+ \StrSubstitute{\tikzumlSrcClassNodeName}{:}{@COLON@}[\tikzumlSrcClassNodeName]%
+ \StrSubstitute{\tikzumlSrcClassNodeName}{\_}{@UNDERSCORE@}[\tikzumlSrcClassNodeName]%
+ %
+ \def\tikzumlDestClassName{#4}%
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlDestClassNodeName{\tikzumlDestClassName}}\x%
+ %
+ \StrSubstitute{\tikzumlDestClassNodeName}{:}{@COLON@}[\tikzumlDestClassNodeName]%
+ \StrSubstitute{\tikzumlDestClassNodeName}{\_}{@UNDERSCORE@}[\tikzumlDestClassNodeName]%
+ %
+ % managing alias keys
+ \def\tikzumlCNRelationAttrNameT{\tikzumlCNRelationAttrNameTO\tikzumlCNRelationAttrNameTT}%
+ \def\tikzumlCNRelationMultiplicityT{\tikzumlCNRelationMultiplicityTO\tikzumlCNRelationMultiplicityTT}%
+ \def\tikzumlCNRelationAlignT{\tikzumlCNRelationAlignTO\tikzumlCNRelationAlignTT}%
+ \def\orientationT{\orientationTO\orientationTT}%
+ %
+ \ifthenelse{\equal{\tikzumlCNRelationPositionTT}{tikzumlEmpty}}{%
+ \def\tikzumlCNRelationPositionT{\tikzumlCNRelationPositionTO}%
+ }{%
+ \def\tikzumlCNRelationPositionT{\tikzumlCNRelationPositionTT}%
+ }%
+ %
+ \def\attrAlign{}%
+ \def\multAlign{}%
+ \def\attrAlignT{}%
+ \def\multAlignT{}%
+ %
+ \ifthenelse{\equal{\tikzumlCNRelationAlign}{left}}{%
+ \def\attrAlign{above right}%
+ \def\multAlign{below right}%
+ }{%
+ \ifthenelse{\equal{\tikzumlCNRelationAlign}{right}}{%
+ \def\attrAlign{above left}%
+ \def\multAlign{below left}%
+ }{}%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlCNRelationAlignT}{left}}{%
+ \def\attrAlignT{above right}%
+ \def\multAlignT{below right}%
+ }{%
+ \ifthenelse{\equal{\tikzumlCNRelationAlignT}{right}}{%
+ \def\attrAlignT{above left}%
+ \def\multAlignT{below left}%
+ }{}%
+ }%
+ %
+ % def stereotype
+ \ifthenelse{\equal{\tikzumlCNRelationStereoType}{}}{%
+ \def\stereotype{}%
+ }{%
+ \def\stereotype{$\ll$\tikzumlCNRelationStereoType$\gg$}%
+ }%
+ %
+ % def anchors macros
+ \ifthenelse{\equal{\tikzumlCNRelationSrcAnchor}{tikzumlEmpty}}{%
+ \def\tikzumlCNRelationSrcAnchor{}%
+ }{%
+ \let\tikzumlCNRelationSrcAnchorold\tikzumlCNRelationSrcAnchor%
+ \def\tikzumlCNRelationSrcAnchor{.\tikzumlCNRelationSrcAnchorold}%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlCNRelationDestAnchor}{tikzumlEmpty}}{%
+ \def\tikzumlCNRelationDestAnchor{}%
+ }{%
+ \let\tikzumlCNRelationDestAnchorold\tikzumlCNRelationDestAnchor%
+ \def\tikzumlCNRelationDestAnchor{.\tikzumlCNRelationDestAnchorold}%
+ }%
+ %
+ \setcounter{pos}{100*\real{\tikzumlCNRelationPosition}}%
+ \setcounter{posT}{100*\real{\tikzumlCNRelationPositionT}}%
+ \setcounter{posStereo}{100*\real{\tikzumlCNRelationPositionStereotype}}%
+ %
+ % straight line
+ %\setcounter{tikzumlControlNodesNum}{1}%
+ %
+ \def\tikzumlFirstArc{node[midway, name=\tikzumlCNRelationName-1, anchor=center] {} }%
+ \def\tikzumlLastArc{node[midway, name=\tikzumlCNRelationName-3, anchor=center]{} }%
+ \def\posAttrName{}%
+ \def\posMultiplicity{}%
+ \def\posAttrNameT{}%
+ \def\posMultiplicityT{}%
+ %
+ \begin{pgfonlayer}{connections}%
+ \node (\tikzumlCNRelationName-2) at (#3) {};%
+ \end{pgfonlayer}%
+ %
+ \ifnum\theposStereo>100%
+ \pgfmathsetmacro{\tikzumlCNRelationPositionStereotype}{(\theposStereo-100)/100}%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlCNRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \else%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlCNRelationPositionStereotype, anchor=center] {\stereotype} }%
+ \fi%
+ %
+ \ifnum\thepos>100%
+ \pgfmathsetmacro{\tikzumlCNRelationPosition}{(\thepos-100)/100}%
+ \def\arcNum{2}%
+ \else%
+ \def\arcNum{1}%
+ \ifnum\thepos=100%
+ \def\posAttrName{above left}%
+ \def\posMultiplicity{below right}%
+ \fi%
+ \fi%
+ %
+ \ifnum\arcNum=1%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlCNRelationPosition, \posAttrName, \attrAlign] {\tikzumlCNRelationAttrName}%
+ node[pos=\tikzumlCNRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlCNRelationMultiplicity} }%
+ \fi%
+ \ifnum\arcNum=2%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlCNRelationPosition, \posAttrName, \attrAlign] {\tikzumlCNRelationAttrName}%
+ node[pos=\tikzumlCNRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlCNRelationMultiplicity} }%
+ \fi%
+ %
+ \ifnum\theposT>100%
+ \pgfmathsetmacro{\tikzumlCNRelationPositionT}{(\theposT-100)/100}%
+ \def\arcNumT{2}%
+ \else%
+ \def\arcNumT{1}%
+ \ifnum\theposT=100%
+ \def\posAttrNameT{above left}%
+ \def\posMultiplicityT{below right}%
+ \fi%
+ \fi%
+ %
+ \ifnum\arcNumT=1%
+ \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlCNRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlCNRelationAttrNameT}%
+ node[pos=\tikzumlCNRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlCNRelationMultiplicityT} }%
+ \fi%
+ \ifnum\arcNumT=2%
+ \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlCNRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlCNRelationAttrNameT}%
+ node[pos=\tikzumlCNRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlCNRelationMultiplicityT} }%
+ \fi%
+ %
+ \xdef\tikzumlPath{(\tikzumlSrcClassNodeName\tikzumlCNRelationSrcAnchor) -- \tikzumlFirstArc (\tikzumlCNRelationName-2.base) -- \tikzumlLastArc (\tikzumlDestClassNodeName\tikzumlCNRelationDestAnchor) }%
+
+ \begin{pgfonlayer}{connections}%
+ \ifthenelse{\equal{\tikzumlCNRelationStyle}{tikzuml nesting style}}{%
+ \pgfarrowsdeclare{nested}{nested}{...}
+ {
+ \tikzumlNestingSymbolSize=0.2pt%
+ \advance\tikzumlNestingSymbolSize by .5\pgflinewidth%
+ \pgfsetdash{}{0pt} % do not dash
+ \pgfsetroundjoin % fix join
+ \pgfsetroundcap % fix cap
+ \pgfpathmoveto{\pgfpoint{-16*\tikzumlNestingSymbolSize}{0pt}}%
+ \pgfpatharc{180}{90}{8*\tikzumlNestingSymbolSize}%
+ \pgfpatharc{90}{0}{8*\tikzumlNestingSymbolSize}%
+ \pgfpatharc{0}{-90}{8*\tikzumlNestingSymbolSize}%
+ \pgfpatharc{-90}{-180}{8*\tikzumlNestingSymbolSize}%
+ \pgfpathmoveto{\pgfpoint{-8*\tikzumlNestingSymbolSize}{8*\tikzumlNestingSymbolSize}}%
+ \pgfpathlineto{\pgfpoint{-8*\tikzumlNestingSymbolSize}{-8*\tikzumlNestingSymbolSize}}%
+ \pgfusepathqstroke%
+ }%
+ \draw[auto, \tikzumlCNRelationStyle, nested-, font=\tikzumlDefaultFont] \tikzumlPath ;%
+ }{
+ \draw[auto, \tikzumlCNRelationStyle, font=\tikzumlDefaultFont] \tikzumlPath ;%
+ }
+ \end{pgfonlayer}%
+ %
+ \stepcounter{tikzumlRelationNum}%
+}%
+%
+% shortcuts for cnrelations
+\newcommand{\umlCNinherit}[4][]{\umlCNrelation[style={tikzuml inherit style}, #1]{#2}{#3}{#4}}%
+\newcommand{\umlCNimpl}[4][]{\umlCNrelation[style={tikzuml implements style}, #1]{#2}{#3}{#4}}%
+\newcommand{\umlCNreal}[4][]{\umlCNrelation[style={tikzuml implements style}, #1]{#2}{#3}{#4}}%
+\newcommand{\umlCNassoc}[4][]{\umlCNrelation[style={tikzuml association style}, #1]{#2}{#3}{#4}}%
+\newcommand{\umlCNuniassoc}[4][]{\umlCNrelation[style={tikzuml unidirectional association style}, #1]{#2}{#3}{#4}}%
+\newcommand{\umlCNaggreg}[4][]{\umlCNrelation[style={tikzuml aggregation style}, #1]{#2}{#3}{#4}}%
+\newcommand{\umlCNuniaggreg}[4][]{\umlCNrelation[style={tikzuml unidirectional aggregation style}, #1]{#2}{#3}{#4}}%
+\newcommand{\umlCNcompo}[4][]{\umlCNrelation[style={tikzuml composition style}, #1]{#2}{#3}{#4}}%
+\newcommand{\umlCNunicompo}[4][]{\umlCNrelation[style={tikzuml unidirectional composition style}, #1]{#2}{#3}{#4}}%
+\newcommand{\umlCNimport}[4][]{\umlCNrelation[style={tikzuml import style}, #1]{#2}{#3}{#4}}%
+\newcommand{\umlCNnest}[4][]{\umlCNrelation[style={tikzuml nesting style}, #1]{#2}{#3}{#4}}%
+\newcommand{\umlCNdep}[4][]{\umlCNrelation[style={tikzuml dependency style}, #1]{#2}{#3}{#4}}%
+\newcommand{\umlCNfriend}[4][]{%
+ \pgfkeys{/tikzuml/friendrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlCNfriend, forbidden option stereo}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/friendrelation/.cd, #1}%
+ \umlCNrelation[stereo=friend, style={tikzuml dependency style}, #1]{#2}{#3}{#4}%
+}%
+%
+% define a note
+% arg : attached class
+% label of the note
+% optional : x,y: coordinates of the note
+% width: width of the note
+% geometry: geometry of the relation between the note and what it is about
+% weight: barycentric weight for a 3-line relation
+% arm: length of the first arm
+% anchor1, anchor2: anchors of the relation
+% draw, fill, text: colors
+% style: to manage every default TikZ option
+% no coords: to tell that the note position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlnote}[3][]{%
+ \pgfkeys{/tikzuml/note/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlNoteDefaultWidth,%
+ geometry/.initial=\tikzumlRelationDefaultGeometry,%
+ weight/.initial=\tikzumlRelationDefaultWeight, arm/.initial=auto, style/.style={},%
+ anchor1/.initial=tikzumlEmpty, anchor2/.initial=tikzumlEmpty,%
+ draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlNoteDefaultFillColor,%
+ text/.initial=\tikzumlDefaultTextColor,%
+ no coords/.is if=tikzumlnoteWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/note/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/note/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/note/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlnote, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/note/.cd, #1}%
+ \pgfkeys{/tikzuml/note/.cd, x/.get=\tikzumlNoteX, y/.get=\tikzumlNoteY, width/.get=\tikzumlNoteTextWidth,%
+ geometry/.get=\tikzumlNoteGeometry,%
+ weight/.get=\tikzumlNoteWeight, arm/.get=\tikzumlNoteArm,%
+ anchor1/.get=\tikzumlNoteSrcAnchor, anchor2/.get=\tikzumlNoteDestAnchor,%
+ draw/.get=\tikzumlNoteDrawColor, fill/.get=\tikzumlNoteFillColor,%
+ text/.get=\tikzumlNoteTextColor%
+ }%
+ %
+ \def\tikzumlClassName{#2}%
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlClassNodeName{\tikzumlClassName}}\x%
+ %
+ % def anchors macros
+ \ifthenelse{\equal{\tikzumlNoteSrcAnchor}{tikzumlEmpty}}{%
+ \def\tikzumlNoteSrcAnchor{}%
+ }{%
+ \let\tikzumlNoteSrcAnchorold\tikzumlNoteSrcAnchor%
+ \def\tikzumlNoteSrcAnchor{.\tikzumlNoteSrcAnchorold}%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlNoteDestAnchor}{tikzumlEmpty}}{%
+ \def\tikzumlNoteDestAnchor{}%
+ }{%
+ \let\tikzumlNoteDestAnchorold\tikzumlNoteDestAnchor%
+ \def\tikzumlNoteDestAnchor{.\tikzumlNoteDestAnchorold}%
+ }%
+ %
+ \iftikzumlnoteWithoutCoords%
+ \node[text=\tikzumlNoteTextColor, text width=\tikzumlNoteTextWidth, font=\tikzumlDefaultFont, outer sep=0, inner xsep=1ex, inner ysep=3ex, /tikzuml/note/style] (note-\thetikzumlNoteNum-coord) {#3};%
+ \else%
+ \node[text=\tikzumlNoteTextColor, text width=\tikzumlNoteTextWidth, font=\tikzumlDefaultFont, outer sep=0, inner xsep=1ex, inner ysep=3ex, /tikzuml/note/style] (note-\thetikzumlNoteNum-coord) at (\tikzumlNoteX, \tikzumlNoteY) {#3};%
+ \fi%
+ \draw (note-\thetikzumlNoteNum-coord.north east) node[name=note-\thetikzumlNoteNum-right-top, below=2ex, coordinate] {};%
+ \draw (note-\thetikzumlNoteNum-coord.north east) node[name=note-\thetikzumlNoteNum-top-right, left=2ex, coordinate] {};%
+ \draw[draw=\tikzumlNoteDrawColor, fill=\tikzumlNoteFillColor] (note-\thetikzumlNoteNum-coord.south west) -- (note-\thetikzumlNoteNum-coord.south east) -- (note-\thetikzumlNoteNum-right-top.base) -- (note-\thetikzumlNoteNum-top-right.base) -- (note-\thetikzumlNoteNum-coord.north west) -- cycle;%
+ \node[text=\tikzumlNoteTextColor, text width=\tikzumlNoteTextWidth, outer sep=0, inner xsep=1ex, inner ysep=3ex, font=\tikzumlDefaultFont] (note-\thetikzumlNoteNum) at (note-\thetikzumlNoteNum-coord) {#3};%
+ \draw[draw=\tikzumlNoteDrawColor] (note-\thetikzumlNoteNum-right-top) -| (note-\thetikzumlNoteNum-top-right);%
+ %
+ \pgfmathsetmacro{\tikzumlNoteWeightT}{1.0-\tikzumlNoteWeight}%
+ \node (note-\thetikzumlNoteNum-middle) at (barycentric cs:note-\thetikzumlNoteNum-coord=\tikzumlNoteWeight,\tikzumlClassNodeName=\tikzumlNoteWeightT) {};%
+ %
+ \ifthenelse{\equal{\tikzumlNoteGeometry}{--}%
+ \OR\equal{\tikzumlNoteGeometry}{-|}%
+ \OR\equal{\tikzumlNoteGeometry}{|-}}{%
+ \edef\tikzumlnotepath{\tikzumlNoteGeometry}
+ }{%
+ \ifthenelse{\equal{\tikzumlNoteGeometry}{-|-}}{%
+ \ifthenelse{\equal{\tikzumlNoteArm}{auto}}{%
+ \edef\tikzumlnotepath{-- (note-\thetikzumlNoteNum-coord\tikzumlNoteSrcAnchor -| note-\thetikzumlNoteNum-middle.center) -- (note-\thetikzumlNoteNum-middle.center) -- (note-\thetikzumlNoteNum-middle.center |- \tikzumlClassNodeName\tikzumlNoteDestAnchor) --}%
+ }{%
+ \draw (note-\thetikzumlNoteNum-coord\tikzumlNoteSrcAnchor)+(\tikzumlNoteArm,0) node[name=note-\thetikzumlNoteNum-tmp] {};
+ \edef\tikzumlnotepath{-- (note-\thetikzumlNoteNum-tmp.center) |-}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlNoteGeometry}{|-|}}{%
+ \ifthenelse{\equal{\tikzumlNoteArm}{auto}}{%
+ \edef\tikzumlnotepath{-- (note-\thetikzumlNoteNum-coord\tikzumlNoteSrcAnchor |- note-\thetikzumlNoteNum-middle.center) -- (note-\thetikzumlNoteNum-middle.center) -- (note-\thetikzumlNoteNum-middle.center -| \tikzumlClassNodeName\tikzumlNoteDestAnchor) --}%
+ }{%
+ \draw (note-\thetikzumlNoteNum-coord\tikzumlNoteSrcAnchor)+(0,\tikzumlNoteArm) node[name=note-\thetikzumlNoteNum-tmp] {};
+ \edef\tikzumlnotepath{-- (note-\thetikzumlNoteNum-tmp.center) -|}%
+ }%
+
+ }{%
+ \errmessage{TIKZUML ERROR : Unknown geometry value !!! It should be in the following list : --, |-, -|, |-|, -|-}%
+ }%
+ }%
+ }%
+ %
+ \begin{pgfonlayer}{connections}%
+ \draw[dashed] (note-\thetikzumlNoteNum-coord\tikzumlNoteSrcAnchor) \tikzumlnotepath (\tikzumlClassNodeName\tikzumlNoteDestAnchor);%
+ \end{pgfonlayer}%
+ %
+ \stepcounter{tikzumlNoteNum}%
+}%
+%
+% shortcuts for note with geometry
+\newcommand{\umlHVnote}[3][]{%
+ \pgfkeys{/tikzuml/note/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlHVnote, forbidden option geometry}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/note/.cd, #1}%
+ \umlnote[geometry=-|, #1]{#2}{#3}%
+}%
+\newcommand{\umlVHnote}[3][]{%
+ \pgfkeys{/tikzuml/note/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlVHnote, forbidden option geometry}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/note/.cd, #1}%
+ \umlnote[geometry=|-, #1]{#2}{#3}%
+}%
+\newcommand{\umlVHVnote}[3][]{%
+ \pgfkeys{/tikzuml/note/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlVHVnote, forbidden option geometry}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/note/.cd, #1}%
+ \umlnote[geometry=|-|, #1]{#2}{#3}%
+}%
+\newcommand{\umlHVHnote}[3][]{%
+ \pgfkeys{/tikzuml/note/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlHVHnote, forbidden option geometry}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/note/.cd, #1}%
+ \umlnote[geometry=-|-, #1]{#2}{#3}%
+}%
+%
+% define a uml association class (command)
+% args : name of the class
+% attributes of the class
+% operations of the class
+% optional : x,y: coordinates of the class
+% width: width of the class node
+% type: type of of class (class, interface, typedef, enum)
+% template: template parameters
+% name: name of the class node
+% geometry: geometry of the line
+% weight: barycentric weight of the middle part when geometry is a 3-line
+% arm: length of first part when geometry id a 3-line
+% anchor1, anchor2: src/dest anchors on linked classes
+% style: style of the association class (association, aggregation, composition, inherit, ...)
+% draw, fill, fill template, text: colors
+% style: to manage every default TikZ option
+% no coords: to tell that the class position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlassocclass}[5][]{%
+ \pgfkeys{/tikzuml/assocclass/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX,
+ width/.initial=\tikzumlClassDefaultWidth, type/.initial=\tikzumlClassDefaultType, style/.style={},%
+ template/.initial={}, name/.initial=tikzumlEmpty, geometry/.initial=\tikzumlRelationDefaultGeometry,%
+ weight/.initial=\tikzumlRelationDefaultWeight, arm/.initial=auto,%
+ anchor1/.initial=tikzumlEmpty, anchor2/.initial=tikzumlEmpty,%
+ draw/.initial=\tikzumlDefaultDrawColor,%
+ fill template/.initial=\tikzumlClassTemplateFillColorDefaultFillColor,%
+ fill/.initial=\tikzumlClassDefaultFillColor,%
+ text/.initial=\tikzumlDefaultTextColor,%
+ no coords/.is if=tikzumlassocclassWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/assocclass/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/assocclass/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/assocclass/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlassocclass, invalid option \keyname}%
+ }%
+ }%
+ %
+ \pgfkeys{/tikzuml/assocclass/.cd,#1}%
+ \pgfkeys{/tikzuml/assocclass/.cd, x/.get=\tikzumlAssocClassX, y/.get=\tikzumlAssocClassY,%
+ width/.get=\tikzumlAssocClassMinimumWidth, type/.get=\tikzumlAssocClassTypeTmp,%
+ template/.get=\tikzumlAssocClassTemplateParam,%
+ name/.get=\tikzumlAssocClassName, geometry/.get=\tikzumlAssocClassGeometry,%
+ weight/.get=\tikzumlAssocClassWeight, arm/.get=\tikzumlAssocClassArm,%
+ anchor1/.get=\tikzumlAssocClassSrcAnchor,%
+ anchor2/.get=\tikzumlAssocClassDestAnchor,%
+ draw/.get=\tikzumlAssocClassDrawColor, fill/.get=\tikzumlAssocClassFillColor,%
+ text/.get=\tikzumlAssocClassTextColor, fill template/.get=\tikzumlAssocClassTemplateFillColor%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlAssocClassTypeTmp}{class}\OR\equal{\tikzumlAssocClassTypeTmp}{abstract}}{%
+ \def\tikzumlAssocClassType{}%
+ }{%
+ \def\tikzumlAssocClassType{$\ll$\tikzumlAssocClassTypeTmp$\gg$ \\}%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlAssocClassTemplateParam}{}}{%
+ \def\tikzumlAssocClassVPadding{}%
+ \def\tikzumlAssocClassHPadding{}%
+ }{%
+ \def\tikzumlAssocClassVPadding{\vspace{0.1em} \\}%
+ \def\tikzumlAssocClassHPadding{\hspace{0.5ex} $ $}%
+ }%
+ %
+ \def\tikzumlAssocClassName{#2}%
+ \def\tikzumlAssocClassRelationName{#3}%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlAssocClassNodeName{\tikzumlAssocClassName}}\x%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlAssocClassRelationNodeName{\tikzumlAssocClassRelationName}}\x%
+ %
+ \ifthenelse{\equal{\tikzumlAssocClassName}{tikzumlEmpty}}{}{%
+ \def\tikzumlAssocClassNodeName{\tikzumlAssocClassName}%
+ }%
+ %
+ \StrSubstitute{\tikzumlAssocClassNodeName}{:}{@COLON@}[\tikzumlAssocClassNodeName]%
+ \StrSubstitute{\tikzumlAssocClassNodeName}{\_}{@UNDERSCORE@}[\tikzumlAssocClassNodeName]%
+ %
+ \ifthenelse{\equal{\tikzumlAssocClassTypeTmp}{abstract}}{%
+ \let\tikzumlAssocClassNameOld\tikzumlAssocClassName%
+ \def\tikzumlAssocClassName{{\it \tikzumlAssocClassNameOld}}%
+ }{}%
+ %
+ \def\tikzumlAssocClassPos{\tikzumlAssocClassX,\tikzumlAssocClassY}%
+ \def\tikzumlAssocClassAttributes{#4}%
+ \def\tikzumlAssocClassOperations{#5}%
+ %
+ % def anchors macros
+ \ifthenelse{\equal{\tikzumlAssocClassSrcAnchor}{tikzumlEmpty}}{%
+ \def\tikzumlAssocClassSrcAnchor{}%
+ }{%
+ \let\tikzumlAssocClassSrcAnchorold\tikzumlAssocClassSrcAnchor%
+ \def\tikzumlAssocClassSrcAnchor{.\tikzumlAssocClassSrcAnchorold}%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlAssocClassDestAnchor}{tikzumlEmpty}}{%
+ \def\tikzumlAssocClassDestAnchor{}%
+ }{%
+ \let\tikzumlAssocClassDestAnchorold\tikzumlAssocClassDestAnchor%
+ \def\tikzumlAssocClassDestAnchor{.\tikzumlAssocClassDestAnchorold}%
+ }%
+ %
+ \iftikzumlassocclassWithoutCoords%
+ \node[tikzuml class style, draw=\tikzumlAssocClassDrawColor, fill=\tikzumlAssocClassFillColor, text=\tikzumlAssocClassTextColor, font=\tikzumlDefaultFont, minimum width=\tikzumlAssocClassMinimumWidth, /tikzuml/assocclass/style] (\tikzumlAssocClassNodeName) {\begin{tabular}{c}\tikzumlAssocClassVPadding \tikzumlAssocClassType \tikzumlAssocClassHPadding \textbf{\tikzumlAssocClassName} \tikzumlAssocClassHPadding \end{tabular}%
+ \nodepart{second}%
+ \begin{tabular}{l}%
+ \tikzumlAssocClassAttributes%
+ \end{tabular}%
+ \nodepart{third}%
+ \begin{tabular}{l}%
+ \tikzumlAssocClassOperations%
+ \end{tabular}%
+ };%
+ \else%
+ \node[tikzuml class style, draw=\tikzumlAssocClassDrawColor, fill=\tikzumlAssocClassFillColor, text=\tikzumlAssocClassTextColor, font=\tikzumlDefaultFont, minimum width=\tikzumlAssocClassMinimumWidth, /tikzuml/assocclass/style] (\tikzumlAssocClassNodeName) at (\tikzumlAssocClassPos) {\begin{tabular}{c}\tikzumlAssocClassVPadding \tikzumlAssocClassType \tikzumlAssocClassHPadding \textbf{\tikzumlAssocClassName} \tikzumlAssocClassHPadding \end{tabular}%
+ \nodepart{second}%
+ \begin{tabular}{l}%
+ \tikzumlAssocClassAttributes%
+ \end{tabular}%
+ \nodepart{third}%
+ \begin{tabular}{l}%
+ \tikzumlAssocClassOperations%
+ \end{tabular}%
+ };%
+ \fi%
+ %
+ \ifthenelse{\equal{\tikzumlAssocClassTemplateParam}{}}{}{%
+ \draw (\tikzumlAssocClassNodeName.north east) node[tikzuml template style, name=\tikzumlAssocClassNodeName-template, draw=\tikzumlAssocClassDrawColor, fill=\tikzumlAssocClassTemplateFillColor, text=\tikzumlAssocClassTextColor, font=\tikzumlDefaultFont] {\tikzumlAssocClassTemplateParam};%
+ }%
+ %
+ \pgfmathsetmacro{\tikzumlAssocClassWeightT}{1.0-\tikzumlAssocClassWeight}
+ \node (\tikzumlAssocClassNodeName-middle) at (barycentric cs:\tikzumlAssocClassNodeName=\tikzumlAssocClassWeight,\tikzumlAssocClassRelationNodeName=\tikzumlAssocClassWeightT) {};%
+ %
+ \ifthenelse{\equal{\tikzumlAssocClassGeometry}{--}\OR\equal{\tikzumlAssocClassGeometry}{-|}\OR\equal{\tikzumlAssocClassGeometry}{|-}}{%
+ \edef\tikzumlassocclasspath{\tikzumlAssocClassGeometry}
+ }{%
+ \ifthenelse{\equal{\tikzumlAssocClassGeometry}{-|-}}{%
+ \ifthenelse{\equal{\tikzumlAssocClassArm}{auto}}{%
+ \edef\tikzumlassocclasspath{-- (\tikzumlAssocClassNodeName\tikzumlAssocClassSrcAnchor -| \tikzumlAssocClassNodeName-middle.center) -- (\tikzumlAssocClassNodeName-middle.center) -- (\tikzumlAssocClassNodeName-middle.center |- \tikzumlAssocClassRelationNodeName\tikzumlAssocClassDestAnchor) --}%
+ }{%
+ \draw (\tikzumlAssocClassNodeName\tikzumlAssocClassSrcAnchor)+(\tikzumlAssocClassArm,0) node[name=\tikzumlAssocClassNodeName-tmp] {};
+ \edef\tikzumlnotepath{-- (\tikzumlAssocClassNodeName-tmp.center) |-}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlAssocClassGeometry}{|-|}}{%
+ \ifthenelse{\equal{\tikzumlAssocClassArm}{auto}}{%
+ \edef\tikzumlassocclasspath{-- (\tikzumlAssocClassNodeName\tikzumlAssocClassSrcAnchor |- \tikzumlAssocClassNodeName-middle.center) -- (\tikzumlAssocClassNodeName-middle.center) -- (\tikzumlAssocClassNodeName-middle.center -| \tikzumlAssocClassRelationNodeName\tikzumlAssocClassDestAnchor) --}%
+ }{%
+ \draw (\tikzumlAssocClassNodeName\tikzumlAssocClassSrcAnchor)+(0,\tikzumlAssocClassArm) node[name=\tikzumlAssocClassNodeName-tmp] {};
+ \edef\tikzumlassocclasspath{-- (\thetikzumlAssocClassNodeName-tmp.center) -|}%
+ }%
+
+ }{%
+ \errmessage{TIKZUML ERROR : Unknown geometry value !!! It should be in the following list : --, |-, -|, |-|, -|-}%
+ }%
+ }%
+ }%
+ %
+ \begin{pgfonlayer}{connections}%
+ \draw[dashed] (\tikzumlAssocClassNodeName\tikzumlAssocClassSrcAnchor) \tikzumlassocclasspath (\tikzumlAssocClassRelationNodeName\tikzumlAssocClassDestAnchor);%
+ \end{pgfonlayer}%
+ %
+ % add to fit
+ \ifnum\c@tikzumlPackageLevel>0%
+ \edef\tikzumlPackageFitOld{\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname}%
+ \ifthenelse{\equal{\tikzumlAssocClassTemplateParam}{}}{%
+ \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{\tikzumlPackageFitOld (\tikzumlAssocClassNodeName)(\tikzumlAssocClassNodeName-middle)}%
+ }{%
+ \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{\tikzumlPackageFitOld (\tikzumlAssocClassNodeName) (\tikzumlAssocClassNodeName-template)(\tikzumlAssocClassNodeName-middle)}%
+ }%
+ \stepcounter{tikzumlPackageClassNum}%
+ \fi%
+}%
+%
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% use case diagrams %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+\tikzstyle{tikzuml usecase style}=[ellipse, text centered]%
+\tikzstyle{tikzuml actor style}=[ellipse, inner sep=0, outer sep=0]%
+%
+\newcounter{tikzumlSystemUseCaseNum}%
+\newcounter{tikzumlSystemLevel}%
+\newcounter{tikzumlUseCaseNum}%
+\newcounter{tikzumlActorNum}%
+%
+\newif\iftikzumlusecaseWithoutCoords%
+\newif\iftikzumlactorWithoutCoords%
+%
+% define a system
+% arg : name
+% optional : x, y: coordinates of the system
+% draw, fill, text: colors
+\newenvironment{umlsystem}[2][]{%
+ \gdef\tikzumlSystemFit{}%
+ \def\tikzumlSystemName{#2}%
+ \setcounter{tikzumlSystemUseCaseNum}{0}%
+ %
+ \pgfkeys{/tikzuml/system/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX,%
+ draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlSystemDefaultFillColor,%
+ text/.initial=\tikzumlDefaultTextColor,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \errmessage{TIKZUML ERROR : in umlsystem, invalid option \keyname}%
+ }%
+ }%
+ %
+ \pgfkeys{/tikzuml/system/.cd, #1}%
+ \pgfkeys{/tikzuml/system/.cd, x/.get=\tikzumlSystemXShift, y/.get=\tikzumlSystemYShift,%
+ draw/.get=\tikzumlSystemDrawColor, fill/.get=\tikzumlSystemFillColor,%
+ text/.get=\tikzumlSystemTextColor}%
+ %
+ \stepcounter{tikzumlSystemLevel}%
+ %
+ \begin{scope}[xshift=\tikzumlSystemXShift cm, yshift=\tikzumlSystemYShift cm]%
+}{%
+ \addtocounter{tikzumlSystemLevel}{-1}%
+ % if contains no usecase, one define a fictive node to enable the fit option
+ \ifnum\c@tikzumlSystemUseCaseNum=0%
+ \node[inner xsep=10ex, inner ysep=1em] (\tikzumlSystemName-root) at (0,0) {};%
+ \xdef\tikzumlSystemFit{(\tikzumlSystemName-root)}%
+ \fi%
+ %
+ \begin{pgfonlayer}{background}%
+ \node[inner ysep=1em, inner xsep=2ex, fit = \tikzumlSystemFit] (\tikzumlSystemName-tmp) {};%
+ \node[text=\tikzumlSystemTextColor, font=\tikzumlDefaultFont] (\tikzumlSystemName-caption-tmp) at (\tikzumlSystemName-tmp.north) {\tikzumlSystemName};%
+ \node[draw=\tikzumlSystemDrawColor, fill=\tikzumlSystemFillColor, text=\tikzumlSystemTextColor, font=\tikzumlDefaultFont, inner ysep=1em, inner xsep=2ex, fit = (\tikzumlSystemName-tmp) (\tikzumlSystemName-caption-tmp)] (\tikzumlSystemName) {};%
+ \node[text=\tikzumlSystemTextColor, font=\tikzumlDefaultFont] (\tikzumlSystemName-caption) at (\tikzumlSystemName-caption-tmp.north) {\tikzumlSystemName};%
+ \end{pgfonlayer}%
+ \end{scope}%
+ %
+}%
+%
+% define a use case
+% arg : label of the use case
+% optional : x, y: coordinates of the use case
+% name: name of the node
+% width: node width
+% draw, fill, text: colors
+% style: to manage every default TikZ option
+% no coords: to tell that the use case position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlusecase}[2][]{%
+ \stepcounter{tikzumlUseCaseNum}%
+ \pgfkeys{/tikzuml/usecase/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=auto,%
+ name/.initial=usecase-\thetikzumlUseCaseNum,%
+ draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlUseCaseDefaultFillColor,%
+ text/.initial=\tikzumlDefaultTextColor, style/.style={},%
+ no coords/.is if=tikzumlusecaseWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/usecase/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/usecase/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/usecase/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlusecase, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/usecase/.cd, #1}%
+ \pgfkeys{/tikzuml/usecase/.cd, x/.get=\tikzumlUseCaseX, y/.get=\tikzumlUseCaseY, width/.get=\tikzumlUseCaseTextWidth,%
+ name/.get=\tikzumlUseCaseName,%
+ draw/.get=\tikzumlUseCaseDrawColor, fill/.get=\tikzumlUseCaseFillColor,%
+ text/.get=\tikzumlUseCaseTextColor%
+ }%
+ %
+ \def\tikzumlUseCaseText{#2}%
+ %
+ \def\tikzumlUseCasePos{\tikzumlUseCaseX,\tikzumlUseCaseY}%
+ %
+ \ifthenelse{\equal{\tikzumlUseCaseTextWidth}{auto}}{%
+ \iftikzumlusecaseWithoutCoords%
+ \node[tikzuml usecase style, draw=\tikzumlUseCaseDrawColor, fill=\tikzumlUseCaseFillColor, text=\tikzumlUseCaseTextColor, font=\tikzumlDefaultFont, /tikzuml/usecase/style] (\tikzumlUseCaseName) {\tikzumlUseCaseText};%
+ \else%
+ \node[tikzuml usecase style, draw=\tikzumlUseCaseDrawColor, fill=\tikzumlUseCaseFillColor, text=\tikzumlUseCaseTextColor, font=\tikzumlDefaultFont, /tikzuml/usecase/style] (\tikzumlUseCaseName) at (\tikzumlUseCasePos) {\tikzumlUseCaseText};%
+ \fi%
+ }{%
+ \iftikzumlusecaseWithoutCoords%
+ \node[tikzuml usecase style, draw=\tikzumlUseCaseDrawColor, fill=\tikzumlUseCaseFillColor, text=\tikzumlUseCaseTextColor, font=\tikzumlDefaultFont, text width=\tikzumlUseCaseTextWidth, /tikzuml/usecase/style] (\tikzumlUseCaseName) {\tikzumlUseCaseText};%
+ \else%
+ \node[tikzuml usecase style, draw=\tikzumlUseCaseDrawColor, fill=\tikzumlUseCaseFillColor, text=\tikzumlUseCaseTextColor, font=\tikzumlDefaultFont, text width=\tikzumlUseCaseTextWidth, /tikzuml/usecase/style] (\tikzumlUseCaseName) at (\tikzumlUseCasePos) {\tikzumlUseCaseText};%
+ \fi%
+ }%
+ %
+ % add to fit
+ \ifnum\c@tikzumlSystemLevel>0%
+ \let\tikzumlSystemFitOld\tikzumlSystemFit%
+ \xdef\tikzumlSystemFit{\tikzumlSystemFitOld (\tikzumlUseCaseName)}%
+ \stepcounter{tikzumlSystemUseCaseNum}%
+ \fi%
+}%
+%
+% define the actor symbol
+% optional : global tikzpicture styles
+\newcommand{\picturedactor}[1]{%
+ \pgfkeys{/tikzuml/picactor/.cd, scale/.initial=1, .unknown/.code={}}%
+ \pgfkeys{/tikzuml/picactor/.cd,#1}%
+ \pgfkeys{/tikzuml/picactor/.cd, scale/.get=\tikzumlPicturedActorScale}%
+ %
+ \begin{tikzpicture}[#1]%
+ \coordinate (head) at (0,4ex);%
+ \coordinate (left-hand) at (-2ex,2ex);%
+ \coordinate (right-hand) at (2ex,2ex);%
+ \coordinate (left-foot) at (-2ex,-2ex);%
+ \coordinate (right-foot) at (2ex,-2ex);%
+ \coordinate (empty) at (0,-3ex);%
+ \draw (empty) (0,0) -- (head);%
+ \draw (left-hand) -- (right-hand);%
+ \draw (0,0) -- (left-foot) (0,0) -- (right-foot);%
+ \node[fill, draw, circle, inner sep=\tikzumlPicturedActorScale*0.3333ex, minimum size=\tikzumlPicturedActorScale*2ex, anchor=base] at (head) {};%
+ \end{tikzpicture}%
+}%
+%
+% define an actor
+% arg : var name
+% optional : x, y: coordinates of the actor
+% scale: scale factor of the actor symbol
+% below: distance between the actor symbol and its name below
+% draw, text: colors
+% style: to manage every default TikZ option
+% no coords: to tell that the actor position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlactor}[2][]{%
+ \stepcounter{tikzumlActorNum}%
+ \pgfkeys{/tikzuml/actor/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, scale/.initial=1, below/.initial=\tikzumlActorDefaultBelow,%
+ draw/.initial=\tikzumlDefaultDrawColor, text/.initial=\tikzumlDefaultTextColor,%
+ style/.style={},%
+ no coords/.is if=tikzumlactorWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/actor/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/actor/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/actor/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlactor, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/actor/.cd, #1}%
+ \pgfkeys{/tikzuml/actor/.cd,%
+ x/.get=\tikzumlActorX, y/.get=\tikzumlActorY, scale/.get=\tikzumlActorScale,%
+ below/.get=\tikzumlActorBelow,%
+ draw/.get=\tikzumlActorDrawColor, text/.get=\tikzumlActorTextColor}%
+ %
+ \def\tikzumlActorName{#2}%
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlActorNodeName{\tikzumlActorName}}\x%
+ %
+ \def\tikzumlActorPos{\tikzumlActorX,\tikzumlActorY}%
+ %
+ \iftikzumlactorWithoutCoords%
+ \node[tikzuml actor style, text=\tikzumlActorTextColor, font=\tikzumlDefaultFont, /tikzuml/actor/style] (\tikzumlActorNodeName) {\picturedactor{scale=\tikzumlActorScale, fill=white, draw=\tikzumlActorDrawColor, thick}};%
+ \else%
+ \node[tikzuml actor style, text=\tikzumlActorTextColor, font=\tikzumlDefaultFont, /tikzuml/actor/style] (\tikzumlActorNodeName) at (\tikzumlActorPos) {\picturedactor{scale=\tikzumlActorScale, fill=white, draw=\tikzumlActorDrawColor, thick}};%
+ \fi%
+ \node[text=\tikzumlActorTextColor, font=\tikzumlDefaultFont, below=\tikzumlActorScale*\tikzumlActorBelow] at (\tikzumlActorNodeName) {\tikzumlActorName};%
+ %
+}%
+
+% shortcuts for include and extend relation
+\newcommand{\umlinclude}[3][]{%
+ \pgfkeys{/tikzuml/includerelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlinclude, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlinclude, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/includerelation/.cd, #1}%
+ \umlrelation[stereo=include, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+\newcommand{\umlextend}[3][]{%
+ \pgfkeys{/tikzuml/extendrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlextend, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlextend, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/extendrelation/.cd, #1}%
+ \umlrelation[stereo=extend, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlHVinclude}[3][]{%
+ \pgfkeys{/tikzuml/includerelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlHVinclude, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlHVinclude, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/includerelation/.cd, #1}%
+ \umlrelation[geometry=-|, stereo=include, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+\newcommand{\umlHVextend}[3][]{%
+ \pgfkeys{/tikzuml/extendrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlHVextend, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlHVextend, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/extendrelation/.cd, #1}%
+ \umlrelation[geometry=-|, stereo=extend, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlVHinclude}[3][]{%
+ \pgfkeys{/tikzuml/includerelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlVHinclude, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlVHinclude, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/includerelation/.cd, #1}%
+ \umlrelation[geometry=|-, stereo=include, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+\newcommand{\umlVHextend}[3][]{%
+ \pgfkeys{/tikzuml/extendrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR :in umlVHextend, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlVHextend, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/extendrelation/.cd, #1}%
+ \umlrelation[geometry=|-, stereo=extend, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlHVHinclude}[3][]{%
+ \pgfkeys{/tikzuml/includerelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlHVHinclude, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlHVHinclude, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/includerelation/.cd, #1}%
+ \umlrelation[geometry=-|-, stereo=include, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+\newcommand{\umlHVHextend}[3][]{%
+ \pgfkeys{/tikzuml/extendrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlHVHextend, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlHVHextend, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/extendrelation/.cd, #1}%
+ \umlrelation[geometry=-|-, stereo=extend, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlVHVinclude}[3][]{%
+ \pgfkeys{/tikzuml/includerelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlVHVinclude, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlVHVinclude, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/includerelation/.cd, #1}%
+ \umlrelation[geometry=|-|, stereo=include, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+\newcommand{\umlVHVextend}[3][]{%
+ \pgfkeys{/tikzuml/extendrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlVHVextend, forbidden option stereo}%
+ }{%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlVHVextend, forbidden option geometry}%
+ }{}%
+ }%
+ }}%
+ \pgfkeys{/tikzuml/extendrelation/.cd, #1}%
+ \umlrelation[geometry=|-|, stereo=extend, style={tikzuml dependency style}, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlCNinclude}[4][]{%
+ \pgfkeys{/tikzuml/includerelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlCNinclude, forbidden option stereo}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/includerelation/.cd, #1}%
+ \umlCNrelation[stereo=include, style={tikzuml dependency style}, #1]{#2}{#3}{#4}%
+}%
+\newcommand{\umlCNextend}[4][]{%
+ \pgfkeys{/tikzuml/extendrelation/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlCNextend, forbidden option stereo}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/extendrelation/.cd, #1}%
+ \umlCNrelation[stereo=extend, style={tikzuml dependency style}, #1]{#2}{#3}{#4}%
+}%
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% state diagrams %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+\tikzstyle{tikzuml state style}=[rectangle split, rectangle split parts=2, rounded corners, inner xsep=1.5ex]%
+\tikzstyle{tikzuml transition style}=[color=\tikzumlDefaultDrawColor, rounded corners, -angle 45]%
+%
+\newcounter{tikzumlStateJoinNum}%
+\newcounter{tikzumlStateDecisionNum}%
+\newcounter{tikzumlStateInitialNum}%
+\newcounter{tikzumlStateFinalNum}%
+\newcounter{tikzumlStateEnterNum}%
+\newcounter{tikzumlStateExitNum}%
+\newcounter{tikzumlStateEndNum}%
+\newcounter{tikzumlStateHistoryNum}%
+\newcounter{tikzumlStateDeepHistoryNum}%
+\newcounter{tikzumlStateLevel}%
+\newcounter{tikzumlStateSubStateNum}%
+\newcounter{tikzumlStateText}%
+%
+\newif\iftikzumlstatejoinWithoutCoords%
+\newif\iftikzumlstatedecisionWithoutCoords%
+\newif\iftikzumlstateinitialWithoutCoords%
+\newif\iftikzumlstatefinalWithoutCoords%
+\newif\iftikzumlstateenterWithoutCoords%
+\newif\iftikzumlstateexitWithoutCoords%
+\newif\iftikzumlstateendWithoutCoords%
+\newif\iftikzumlstatehistoryWithoutCoords%
+\newif\iftikzumlstatedeephistoryWithoutCoords%
+\newif\iftikzumlstateWithoutCoords%
+%
+% define a uml join state
+% args : name of the state
+% optional : x,y: coordinates of the state
+% width: width of the state node
+% name: name of the state node
+% color: color of the join symbol
+% style: to manage every default TikZ option
+% no coords: to tell that the state position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlstatejoin}[1][]{%
+ \pgfkeys{/tikzuml/statejoin/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateJoinDefaultWidth,%
+ name/.initial=statejoin-\thetikzumlStateJoinNum,%
+ color/.initial=\tikzumlDefaultDrawColor, style/.style={},%
+ no coords/.is if=tikzumlstatejoinWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/statejoin/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/statejoin/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/statejoin/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlstatejoin, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/statejoin/.cd, #1}%
+ \pgfkeys{/tikzuml/statejoin/.cd, x/.get=\tikzumlStateJoinX, y/.get=\tikzumlStateJoinY, width/.get=\tikzumlStateJoinMinimumWidth,%
+ name/.get=\tikzumlStateJoinName, color/.get=\tikzumlStateJoinColor%
+ }%
+ %
+ \def\tikzumlStateJoinPos{\tikzumlStateJoinX,\tikzumlStateJoinY}%
+ %
+ \iftikzumlstatejoinWithoutCoords%
+ \node[circle, minimum size=\tikzumlStateJoinMinimumWidth, draw=\tikzumlStateJoinColor, fill=\tikzumlStateJoinColor, /tikzuml/statejoin/style] (\tikzumlStateJoinName) {};%
+ \else%
+ \node[circle, minimum size=\tikzumlStateJoinMinimumWidth, draw=\tikzumlStateJoinColor, fill=\tikzumlStateJoinColor, /tikzuml/statejoin/style] (\tikzumlStateJoinName) at (\tikzumlStateJoinPos) {};%
+ \fi%
+ %
+ % add to fit
+ \ifnum\c@tikzumlStateLevel>0%
+ \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlStateJoinName)}%
+ \stepcounter{tikzumlStateSubStateNum}%
+ \fi%
+ \stepcounter{tikzumlStateJoinNum}%
+}%
+%
+% define a uml decision state
+% args : name of the state
+% optional : x,y: coordinates of the state
+% width: width of the state node
+% name: name of the state node
+% color: color of the join symbol
+% style: to manage every default TikZ option
+% no coords: to tell that the state position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlstatedecision}[1][]{%
+ \pgfkeys{/tikzuml/statedecision/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateDecisionDefaultWidth,%
+ name/.initial=statedecision-\thetikzumlStateDecisionNum,%
+ color/.initial=\tikzumlDefaultDrawColor, style/.style={},%
+ no coords/.is if=tikzumlstatedecisionWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/statedecision/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/statedecision/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/statedecision/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlstatedecision, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/statedecision/.cd, #1}%
+ \pgfkeys{/tikzuml/statedecision/.cd, x/.get=\tikzumlStateDecisionX, y/.get=\tikzumlStateDecisionY, width/.get=\tikzumlStateDecisionMinimumWidth,%
+ name/.get=\tikzumlStateDecisionName, color/.get=\tikzumlStateDecisionColor%
+ }%
+ %
+ \def\tikzumlStateDecisionPos{\tikzumlStateDecisionX,\tikzumlStateDecisionY}%
+ %
+ \iftikzumlstatedecisionWithoutCoords%
+ \node[rectangle, rotate=45, minimum size=\tikzumlStateDecisionMinimumWidth, draw=\tikzumlStateDecisionColor, /tikzuml/statedecision/style] (\tikzumlStateDecisionName) {};%
+ \else%
+ \node[rectangle, rotate=45, minimum size=\tikzumlStateDecisionMinimumWidth, draw=\tikzumlStateDecisionColor, /tikzuml/statedecision/style] (\tikzumlStateDecisionName) at (\tikzumlStateDecisionPos) {};%
+ \fi%
+ %
+ % add to fit
+ \ifnum\c@tikzumlStateLevel>0%
+ \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlStateDecisionName)}%
+ \stepcounter{tikzumlStateSubStateNum}%
+ \fi%
+ \stepcounter{tikzumlStateDecisionNum}%
+}%
+%
+% define a uml initial state
+% args : name of the state
+% optional : x,y: coordinates of the state
+% width: width of the state node
+% name: name of the state node
+% entry, do, exit: entry/do/exit action of the state
+% color: color of the join symbol
+% style: to manage every default TikZ option
+% no coords: to tell that the state position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlstateinitial}[1][]{%
+ \pgfkeys{/tikzuml/stateinitial/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateInitialDefaultWidth,%
+ name/.initial=stateinitial-\thetikzumlStateInitialNum,%
+ color/.initial=\tikzumlDefaultDrawColor, style/.style={},%
+ no coords/.is if=tikzumlstateinitialWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/stateinitial/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/stateinitial/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/stateinitial/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlstateinitial, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/stateinitial/.cd, #1}%
+ \pgfkeys{/tikzuml/stateinitial/.cd, x/.get=\tikzumlStateInitialX, y/.get=\tikzumlStateInitialY, width/.get=\tikzumlStateInitialMinimumWidth,%
+ name/.get=\tikzumlStateInitialName, color/.get=\tikzumlStateInitialColor%
+ }%
+ %
+ \def\tikzumlStateInitialPos{\tikzumlStateInitialX,\tikzumlStateInitialY}%
+ %
+ \iftikzumlstateinitialWithoutCoords%
+ \node[circle, minimum size=\tikzumlStateInitialMinimumWidth, fill=\tikzumlStateInitialColor, /tikzuml/stateinitial/style] (\tikzumlStateInitialName) {};%
+ \else%
+ \node[circle, minimum size=\tikzumlStateInitialMinimumWidth, fill=\tikzumlStateInitialColor, /tikzuml/stateinitial/style] (\tikzumlStateInitialName) at (\tikzumlStateInitialPos) {};%
+ \fi%
+ %
+ % add to fit
+ \ifnum\c@tikzumlStateLevel>0%
+ \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlStateInitialName)}%
+ \stepcounter{tikzumlStateSubStateNum}%
+ \fi%
+ \stepcounter{tikzumlStateInitialNum}%
+}%
+%
+% define a uml final state
+% args : name of the state
+% optional : x,y: coordinates of the state
+% width: width of the state node
+% name: name of the state node
+% color: color of the join symbol
+% style: to manage every default TikZ option
+% no coords: to tell that the state position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlstatefinal}[1][]{%
+ \pgfkeys{/tikzuml/statefinal/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateFinalDefaultWidth,%
+ name/.initial=statefinal-\thetikzumlStateFinalNum,%
+ color/.initial=\tikzumlDefaultDrawColor, style/.style={},%
+ no coords/.is if=tikzumlstatefinalWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/statefinal/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/statefinal/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/statefinal/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlstatefinal, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/statefinal/.cd, #1}%
+ \pgfkeys{/tikzuml/statefinal/.cd, x/.get=\tikzumlStateFinalX, y/.get=\tikzumlStateFinalY, width/.get=\tikzumlStateFinalMinimumWidth,%
+ name/.get=\tikzumlStateFinalName, color/.get=\tikzumlStateFinalColor%
+ }%
+ %
+ \def\tikzumlStateFinalPos{\tikzumlStateFinalX,\tikzumlStateFinalY}%
+ %
+ \iftikzumlstatefinalWithoutCoords%
+ \node[circle, minimum size=\tikzumlStateFinalMinimumWidth, draw=\tikzumlStateFinalColor, fill=\tikzumlStateFinalColor, double, double distance=0.1cm, /tikzuml/statefinal/style] (\tikzumlStateFinalName) {};%
+ \else%
+ \node[circle, minimum size=\tikzumlStateFinalMinimumWidth, draw=\tikzumlStateFinalColor, fill=\tikzumlStateFinalColor, double, double distance=0.1cm, /tikzuml/statefinal/style] (\tikzumlStateFinalName) at (\tikzumlStateFinalPos) {};%
+ \fi%
+ %
+ % add to fit
+ \ifnum\c@tikzumlStateLevel>0%
+ \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlStateFinalName)}%
+ \stepcounter{tikzumlStateSubStateNum}%
+ \fi%
+ \stepcounter{tikzumlStateFinalNum}%
+}%
+%
+% define a uml enter state
+% args : name of the state
+% optional : x,y: coordinates of the state
+% width: width of the state node
+% name: name of the state node
+% color: color of the join symbol
+% style: to manage every default TikZ option
+% no coords: to tell that the state position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlstateenter}[1][]{%
+ \pgfkeys{/tikzuml/stateenter/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateEnterDefaultWidth,%
+ name/.initial=stateenter-\thetikzumlStateEnterNum,%
+ color/.initial=\tikzumlDefaultDrawColor, style/.style={},%
+ no coords/.is if=tikzumlstateenterWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/stateenter/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/stateenter/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/stateenter/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlstateenter, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/stateenter/.cd, #1}%
+ \pgfkeys{/tikzuml/stateenter/.cd, x/.get=\tikzumlStateEnterX, y/.get=\tikzumlStateEnterY, width/.get=\tikzumlStateEnterMinimumWidth,%
+ name/.get=\tikzumlStateEnterName, color/.get=\tikzumlStateEnterColor%
+ }%
+ %
+ \def\tikzumlStateEnterPos{\tikzumlStateEnterX,\tikzumlStateEnterY}%
+ %
+ \iftikzumlstateenterWithoutCoords%
+ \node[circle, minimum size=\tikzumlStateEnterMinimumWidth, draw=\tikzumlStateEnterColor, /tikzuml/stateenter/style] (\tikzumlStateEnterName) {};%
+ \else%
+ \node[circle, minimum size=\tikzumlStateEnterMinimumWidth, draw=\tikzumlStateEnterColor, /tikzuml/stateenter/style] (\tikzumlStateEnterName) at (\tikzumlStateEnterPos) {};%
+ \fi%
+ %
+ % add to fit
+ \ifnum\c@tikzumlStateLevel>0%
+ \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlStateEnterName)}%
+ \stepcounter{tikzumlStateSubStateNum}%
+ \fi%
+ \stepcounter{tikzumlStateEnterNum}%
+}%
+%
+% define a uml exit state
+% args : name of the state
+% optional : x,y: coordinates of the state
+% width: width of the state node
+% name: name of the state node
+% color: color of the join symbol
+% style: to manage every default TikZ option
+% no coords: to tell that the state position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlstateexit}[1][]{%
+ \pgfkeys{/tikzuml/stateexit/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateExitDefaultWidth,%
+ name/.initial=stateexit-\thetikzumlStateExitNum,%
+ color/.initial=\tikzumlDefaultDrawColor, style/.style={},%
+ no coords/.is if=tikzumlstateexitWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/stateexit/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/stateexit/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/stateexit/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlstateexit, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/stateexit/.cd, #1}%
+ \pgfkeys{/tikzuml/stateexit/.cd, x/.get=\tikzumlStateExitX, y/.get=\tikzumlStateExitY, width/.get=\tikzumlStateExitMinimumWidth,%
+ name/.get=\tikzumlStateExitName, color/.get=\tikzumlStateExitColor%
+ }%
+ %
+ \def\tikzumlStateExitPos{\tikzumlStateExitX,\tikzumlStateExitY}%
+ %
+ \iftikzumlstateexitWithoutCoords%
+ \node[circle, minimum size=\tikzumlStateExitMinimumWidth, draw=\tikzumlStateExitColor, /tikzuml/stateexit/style] (\tikzumlStateExitName) {};%
+ \else%
+ \node[circle, minimum size=\tikzumlStateExitMinimumWidth, draw=\tikzumlStateExitColor, /tikzuml/stateexit/style] (\tikzumlStateExitName) at (\tikzumlStateExitPos) {};%
+ \fi%
+ \draw[draw=\tikzumlStateExitColor] (\tikzumlStateExitName.north east) -- (\tikzumlStateExitName.south west) (\tikzumlStateExitName.north west) -- (\tikzumlStateExitName.south east);
+ %
+ % add to fit
+ \ifnum\c@tikzumlStateLevel>0%
+ \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlStateExitName)}%
+ \stepcounter{tikzumlStateSubStateNum}%
+ \fi%
+ \stepcounter{tikzumlStateExitNum}%
+}%
+%
+% define a uml end state
+% args : name of the state
+% optional : x,y: coordinates of the state
+% width: width of the state node
+% name: name of the state node
+% color: color of the join symbol
+% style: to manage every default TikZ option
+% no coords: to tell that the state position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlstateend}[1][]{%
+ \pgfkeys{/tikzuml/stateend/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateEndDefaultWidth,%
+ name/.initial=stateend-\thetikzumlStateEndNum,%
+ color/.initial=\tikzumlDefaultDrawColor, style/.style={},%
+ no coords/.is if=tikzumlstateendWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/stateend/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/stateend/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/stateend/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlstateend, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/stateend/.cd, #1}%
+ \pgfkeys{/tikzuml/stateend/.cd, x/.get=\tikzumlStateEndX, y/.get=\tikzumlStateEndY, width/.get=\tikzumlStateEndMinimumWidth,%
+ name/.get=\tikzumlStateEndName, color/.get=\tikzumlStateEndColor%
+ }%
+ %
+ \def\tikzumlStateEndPos{\tikzumlStateEndX,\tikzumlStateEndY}%
+ %
+ \iftikzumlstateendWithoutCoords%
+ \node[circle, minimum size=\tikzumlStateEndMinimumWidth, /tikzuml/stateend/style] (\tikzumlStateEndName) {};%
+ \else%
+ \node[circle, minimum size=\tikzumlStateEndMinimumWidth, /tikzuml/stateend/style] (\tikzumlStateEndName) at (\tikzumlStateEndPos) {};%
+ \fi%
+ \draw[draw=\tikzumlStateEndColor] (\tikzumlStateEndName.north east) -- (\tikzumlStateEndName.south west) (\tikzumlStateEndName.north west) -- (\tikzumlStateEndName.south east);
+ %
+ % add to fit
+ \ifnum\c@tikzumlStateLevel>0%
+ \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlStateEndName)}%
+ \stepcounter{tikzumlStateSubStateNum}%
+ \fi%
+ \stepcounter{tikzumlStateEndNum}%
+}%
+%
+\newcommand{\picturedhistory}[1]{%
+ \begin{tikzpicture}[#1]%
+ \draw[thick] (-0.1cm,-0.15cm) -- (-0.1cm,0.15cm)
+ (-0.1cm,0) -- (0.1cm,0)
+ (0.1cm,-0.15cm) -- (0.1cm,0.15cm);%
+ \end{tikzpicture}%
+}%
+%
+% define a uml history state
+% args : name of the state
+% optional : x,y: coordinates of the state
+% width: width of the state node
+% name: name of the state node
+% color: color of the join symbol
+% style: to manage every default TikZ option
+% no coords: to tell that the state position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlstatehistory}[1][]{%
+ \pgfkeys{/tikzuml/statehistory/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateHistoryDefaultWidth,%
+ name/.initial=statehistory-\thetikzumlStateHistoryNum,%
+ color/.initial=\tikzumlDefaultDrawColor, style/.style={},%
+ no coords/.is if=tikzumlstatehistoryWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/statehistory/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/statehistory/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/statehistory/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlstatehistory, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/statehistory/.cd, #1}%
+ \pgfkeys{/tikzuml/statehistory/.cd, x/.get=\tikzumlStateHistoryX, y/.get=\tikzumlStateHistoryY, width/.get=\tikzumlStateHistoryMinimumWidth,%
+ name/.get=\tikzumlStateHistoryName, color/.get=\tikzumlStateHistoryColor%
+ }%
+ %
+ \def\tikzumlStateHistoryPos{\tikzumlStateHistoryX,\tikzumlStateHistoryY}%
+ %
+ \iftikzumlstatehistoryWithoutCoords%
+ \node[circle, minimum size=\tikzumlStateHistoryMinimumWidth, draw=\tikzumlStateHistoryColor, /tikzuml/statehistory/style] (\tikzumlStateHistoryName) {\picturedhistory{draw=\tikzumlStateHistoryColor}};%
+ \else%
+ \node[circle, minimum size=\tikzumlStateHistoryMinimumWidth, draw=\tikzumlStateHistoryColor, /tikzuml/statehistory/style] (\tikzumlStateHistoryName) at (\tikzumlStateHistoryPos) {\picturedhistory{draw=\tikzumlStateHistoryColor}};%
+ \fi%
+ %
+ % add to fit
+ \ifnum\c@tikzumlStateLevel>0%
+ \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlStateHistoryName)}%
+ \stepcounter{tikzumlStateSubStateNum}%
+ \fi%
+ \stepcounter{tikzumlStateHistoryNum}%
+}%
+%
+\newcommand{\pictureddeephistory}[1]{%
+ \begin{tikzpicture}[#1]%
+ \draw[thick] (-0.1cm,-0.15cm) -- (-0.1cm,0.15cm)
+ (-0.1cm,0) -- (0.1cm,0)
+ (0.1cm,-0.15cm) -- (0.1cm,0.15cm)
+ (0.23cm,0.19cm) -- (0.23cm,0.11cm)
+ (0.20cm,0.17cm) -- (0.26cm,0.13cm)
+ (0.20cm,0.13cm) -- (0.26cm,0.17cm);%
+ \end{tikzpicture}%
+}%
+%
+% define a uml deep-history state
+% args : name of the state
+% optional : x,y: coordinates of the state
+% width: width of the state node
+% name: name of the state node
+% color: color of the join symbol
+% style: to manage every default TikZ option
+% no coords: to tell that the state position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newcommand{\umlstatedeephistory}[1][]{%
+ \pgfkeys{/tikzuml/statedeephistory/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateDeepHistoryDefaultWidth,%
+ name/.initial=statedeephistory-\thetikzumlStateDeepHistoryNum,%
+ color/.initial=\tikzumlDefaultDrawColor, style/.style={},%
+ no coords/.is if=tikzumlstatedeephistoryWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/statedeephistory/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/statedeephistory/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/statedeephistory/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlstatedeephistory, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/statedeephistory/.cd, #1}%
+ \pgfkeys{/tikzuml/statedeephistory/.cd, x/.get=\tikzumlStateDeepHistoryX, y/.get=\tikzumlStateDeepHistoryY, width/.get=\tikzumlStateDeepHistoryMinimumWidth,%
+ name/.get=\tikzumlStateDeepHistoryName, color/.get=\tikzumlStateDeepHistoryColor%
+ }%
+ %
+ \def\tikzumlStateDeepHistoryPos{\tikzumlStateDeepHistoryX,\tikzumlStateDeepHistoryY}%
+ %
+ \iftikzumlstatedeephistoryWithoutCoords%
+ \node[circle, minimum size=\tikzumlStateDeepHistoryMinimumWidth, draw=\tikzumlStateDeepHistoryColor, /tikzuml/statedeephistory/style] (\tikzumlStateDeepHistoryName) {\pictureddeephistory{draw=\tikzumlStateDeepHistoryColor}};%
+ \else%
+ \node[circle, minimum size=\tikzumlStateDeepHistoryMinimumWidth, draw=\tikzumlStateDeepHistoryColor, /tikzuml/statedeephistory/style] (\tikzumlStateDeepHistoryName) at (\tikzumlStateDeepHistoryPos) {\pictureddeephistory{draw=\tikzumlStateDeepHistoryColor}};%
+ \fi%
+ %
+ % add to fit
+ \ifnum\c@tikzumlStateLevel>0%
+ \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlStateDeepHistoryName)}%
+ \stepcounter{tikzumlStateSubStateNum}%
+ \fi%
+ \stepcounter{tikzumlStateDeepHistoryNum}%
+}%
+%
+% define a uml state
+% args : name of the state
+% content of the state
+% optional : x,y: coordinates of the state
+% width: width of the state node
+% name: name of the state node
+% entry, do, exit: entry/do/exit action of the state
+% draw, fill, text: colors
+% style: to manage every default TikZ option
+% no coords: to tell that the state position is defined relatively
+% to another node (automatically used with TikZ options above, below, left, right, below left, ...)
+\newenvironment{umlstate}[2][]{%
+ \ifnum\thetikzumlStateLevel>0%
+ \let\tikzumlState@nameold\tikzumlState@fitname%
+ \let\tikzumlState@parentold\tikzumlState@parent%
+ \edef\tikzumlState@parent{\tikzumlState@parentold @@\tikzumlState@nameold}%
+ \else%
+ \def\tikzumlState@parent{}%
+ \fi%
+ %
+ \stepcounter{tikzumlStateLevel}%
+ %
+ \pgfkeys{/tikzuml/state/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateDefaultWidth,%
+ name/.initial={},%
+ entry/.initial={}, do/.initial={}, exit/.initial={},%
+ draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlStateDefaultFillColor,%
+ text/.initial=\tikzumlDefaultTextColor, style/.style={},%
+ no coords/.is if=tikzumlstateWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/state/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/state/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/state/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ % \errmessage{TIKZUML ERROR : in umlstate, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/state/.cd, #1}%
+ \pgfkeys{/tikzuml/state/.cd, x/.get=\tikzumlStateXShift, y/.get=\tikzumlStateYShift, width/.get=\tikzumlStateMinimumWidth, name/.get=\tikzumlStateName,%
+ entry/.get=\tikzumlStateEntry, do/.get=\tikzumlStateDo, exit/.get=\tikzumlStateExit,%
+ draw/.get=\tikzumlStateDrawColor, fill/.get=\tikzumlStateFillColor,%
+ text/.get=\tikzumlStateTextColor%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlStateName}{}}{%
+ \edef\tikzumlState@name{#2}%
+ }{%
+ \edef\tikzumlState@name{\tikzumlStateName}%
+ }%
+ %
+ \begingroup%
+ \def\_{@}\edef\x{\endgroup%
+ \def\noexpand\tikzumlState@fitname{\tikzumlState@name}}\x%
+ %
+ \let\tikzumlState@nodeNameold\tikzumlState@nodeName%
+ \def\tikzumlState@caption{#2}%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlState@nodeName{\tikzumlState@name}}\x%
+ %
+ \expandafter\gdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{}%
+ %
+ \setcounter{tikzumlStateSubStateNum}{0}%
+ \setcounter{tikzumlStateText}{0}%
+ %
+ \def\tikzumlStateText{tikzumlEmpty}%
+ \begin{scope}[xshift=\tikzumlStateXShift cm, yshift=\tikzumlStateYShift cm]%
+}{%
+ %
+ \def\tikzumlstaterootlabel{\phantom{\tikzumlState@nodeName}}%
+ %
+ \def\tikzumlstaterootinnerysep{0.5ex}%
+ \def\tikzumlstatebodyinnerysep{2ex}%
+ %
+ \ifthenelse{\equal{\tikzumlStateEntry}{}}{}{%
+ \ifnum\c@tikzumlStateText=0%
+ \def\tikzumlStateText{entry/\tikzumlStateEntry}%
+ \else%
+ \let\tikzumlStateTextOld\tikzumlStateText%
+ \ifthenelse{\equal{\tikzumlStateText}{tikzumlEmpty}}{%
+ \def\tikzumlStateText{entry/\tikzumlStateEntry}%
+ }{%
+ \expandafter\def\expandafter\tikzumlStateText\expandafter{\tikzumlStateTextOld \\ entry/\tikzumlStateEntry}%
+ }%
+ \fi%
+ \setcounter{tikzumlStateText}{1}%
+ \ifnum\c@tikzumlStateSubStateNum=0%
+ \def\tikzumlstatebodyinnerysep{0}%
+ \def\tikzumlstaterootinnerysep{0}%
+ \fi%
+ }%
+ \ifthenelse{\equal{\tikzumlStateDo}{}}{}{%
+ \ifnum\c@tikzumlStateText=0%
+ \def\tikzumlStateText{do/\tikzumlStateDo}%
+ \else%
+ \let\tikzumlStateTextOld\tikzumlStateText%
+ \ifthenelse{\equal{\tikzumlStateText}{tikzumlEmpty}}{%
+ \def\tikzumlStateText{do/\tikzumlStateDo}%
+ }{%
+ \expandafter\def\expandafter\tikzumlStateText\expandafter{\tikzumlStateTextOld \\ do/\tikzumlStateDo}%
+ }%
+ \fi%
+ \setcounter{tikzumlStateText}{1}%
+ \ifnum\c@tikzumlStateSubStateNum=0%
+ \def\tikzumlstatebodyinnerysep{0}%
+ \def\tikzumlstaterootinnerysep{0}%
+ \fi%
+ }%
+ \ifthenelse{\equal{\tikzumlStateExit}{}}{}{%
+ \ifnum\c@tikzumlStateText=0%
+ \def\tikzumlStateText{exit/\tikzumlStateExit}%
+ \else%
+ \let\tikzumlStateTextOld\tikzumlStateText%
+ \ifthenelse{\equal{\tikzumlStateText}{tikzumlEmpty}}{%
+ \def\tikzumlStateText{exit/\tikzumlStateExit}%
+ }{%
+ \expandafter\def\expandafter\tikzumlStateText\expandafter{\tikzumlStateTextOld \\ exit/\tikzumlStateExit}%
+ }%
+ \fi%
+ \setcounter{tikzumlStateText}{1}%
+ \ifnum\c@tikzumlStateSubStateNum=0%
+ \def\tikzumlstatebodyinnerysep{0}%
+ \def\tikzumlstaterootinnerysep{0}%
+ \fi%
+ }%
+ %
+ \addtocounter{tikzumlStateLevel}{-1}%
+ \begin{pgfonlayer}{state\thetikzumlStateLevel}%
+ %
+ % if contains nothing, one define a fictive node to enable the fit option
+ \ifnum\c@tikzumlStateSubStateNum=0%
+ \iftikzumlstateWithoutCoords%
+ \node[inner ysep=\tikzumlstaterootinnerysep, minimum width=\tikzumlStateMinimumWidth, /tikzuml/state/style] (\tikzumlState@nodeName-root) {\tikzumlstaterootlabel};%
+ \else%
+ \node[inner ysep=\tikzumlstaterootinnerysep, minimum width=\tikzumlStateMinimumWidth, /tikzuml/state/style] (\tikzumlState@nodeName-root) at (0,0) {\tikzumlstaterootlabel};%
+ \fi%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{(\tikzumlState@nodeName-root)}%
+ \fi%
+ %
+ \ifnum\c@tikzumlStateLevel>0%
+ \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent\endcsname}%
+ \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent\endcsname{\tikzumlStateFitTmp (\tikzumlState@nodeName-body) (\tikzumlState@nodeName-caption)}%
+ \stepcounter{tikzumlStateSubStateNum}%
+ \fi%
+ %
+ \node[inner xsep=2ex, inner ysep=\tikzumlstatebodyinnerysep, fit = \csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname, /tikzuml/state/style ] (\tikzumlState@nodeName-body) {};%
+ \def\tikzumlState@orig{body}%
+ \ifnum\c@tikzumlStateText=1%
+ \node[above=0] (\tikzumlState@nodeName-texttmp) at (\tikzumlState@nodeName-\tikzumlState@orig.north) {\begin{tabular}{l}\tikzumlStateText \end{tabular}};%
+ \def\tikzumlState@orig{texttmp}%
+ \fi%
+ \node[above] (\tikzumlState@nodeName-captiontmp) at (\tikzumlState@nodeName-\tikzumlState@orig.north) {\tikzumlState@caption};%
+ \ifnum\c@tikzumlStateText=1%
+ \node[rounded corners, draw=\tikzumlStateDrawColor, fill=\tikzumlStateFillColor, name=\tikzumlState@nodeName, fit=(\tikzumlState@nodeName-body) (\tikzumlState@nodeName-texttmp) (\tikzumlState@nodeName-captiontmp)] {};%
+ \else%
+ \node[rounded corners, draw=\tikzumlStateDrawColor, fill=\tikzumlStateFillColor, name=\tikzumlState@nodeName, fit=(\tikzumlState@nodeName-body) (\tikzumlState@nodeName-captiontmp)] {};%
+ \fi%
+ \ifnum\c@tikzumlStateText=1%
+ \node (\tikzumlState@nodeName-text) at (\tikzumlState@nodeName-texttmp) {\begin{tabular}{l}\tikzumlStateText \end{tabular}};%
+ \fi%
+ \node (\tikzumlState@nodeName-caption) at (\tikzumlState@nodeName-captiontmp) {\tikzumlState@caption};%
+ \draw (\tikzumlState@nodeName-caption.south -| \tikzumlState@nodeName.north west) -- (\tikzumlState@nodeName-caption.south -| \tikzumlState@nodeName.north east);%
+ \end{pgfonlayer}%
+ \end{scope}%
+}%
+%
+% shortcut for empty state
+\newcommand{\umlbasicstate}[2][]{\begin{umlstate}[#1]{#2}\end{umlstate}}%
+%
+% command to add text in a state, to be used inside umlstate environment
+\newcommand{\umlstatetext}[1]{%
+ \def\tikzumlStateText{#1}%
+ \setcounter{tikzumlStateText}{1}%
+}%
+%
+% shortcuts for state transitions macros
+\newcommand{\umltrans}[3][]{%
+ \ifthenelse{\equal{#2}{#3}}{%
+ \umlrelation[style={tikzuml transition style}, recursive mode=transition, #1]{#2}{#3}%
+ }{%
+ \umlrelation[style={tikzuml transition style}, #1]{#2}{#3}%
+ }%
+}%
+\newcommand{\umlHVtrans}[3][]{\umlHVrelation[style={tikzuml transition style}, #1]{#2}{#3}}%
+\newcommand{\umlVHtrans}[3][]{\umlVHrelation[style={tikzuml transition style}, #1]{#2}{#3}}%
+\newcommand{\umlVHVtrans}[3][]{\umlVHVrelation[style={tikzuml transition style}, #1]{#2}{#3}}%
+\newcommand{\umlHVHtrans}[3][]{\umlHVHrelation[style={tikzuml transition style}, #1]{#2}{#3}}%
+\newcommand{\umlCNtrans}[4][]{\umlCNrelation[style={tikzuml transition style}, #1]{#2}{#3}{#4}}%
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% sequence diagrams %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+\tikzstyle{tikzuml synchron-msg style}=[color=\tikzumlDefaultDrawColor, -triangle 45]%
+\tikzstyle{tikzuml asynchron-msg style}=[color=\tikzumlDefaultDrawColor, -angle 45]%
+\tikzstyle{tikzuml return-msg style}=[color=\tikzumlDefaultDrawColor, dashed, -angle 45]%
+\tikzstyle{tikzuml call return style}=[color=\tikzumlDefaultDrawColor, dashed, -angle 45]%
+\tikzstyle{tikzuml activity style}=[inner xsep=1ex, inner ysep=1ex]%
+%
+\newcounter{tikzumlObjectNum}%
+\newcounter{tikzumlCallLevel}%
+\newcounter{tikzumlCallNum}%
+\newcounter{tikzumlFragmentLevel}%
+\newcounter{tikzumlFragmentLevelNum}%
+\newcounter{tikzumlFragmentNum}%
+\newcounter{tikzumlFragmentPartNum}%
+\newcounter{tikzumlCallStartFragmentNum}%
+\newcounter{tikzumlCallEndFragmentNum}%
+%
+\newif\iftikzumlobjectNoDDots%
+\newif\iftikzumlcreatecallNoDDots%
+%
+% define a sequence diagram
+%
+\newenvironment{umlseqdiag}{%
+ \gdef\tikzumlInCreateCall{0}%
+ \setcounter{tikzumlObjectNum}{0}%
+ \setcounter{tikzumlCallLevel}{0}%
+ \setcounter{tikzumlCallNum}{0}%
+ \setcounter{tikzumlFragmentLevel}{0}%
+ \setcounter{tikzumlFragmentLevelNum}{0}%
+ \setcounter{tikzumlFragmentNum}{0}%
+ \setcounter{tikzumlFragmentPartNum}{0}%
+ \setcounter{tikzumlCallStartFragmentNum}{0}%
+ \setcounter{tikzumlCallEndFragmentNum}{0}%
+ %
+ \ifx \@umlactor \@empty
+ \newcommand{\umlactor}[2][]{%
+ \pgfkeys{/tikzuml/actorobj/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlactor, forbidden option stereo}%
+ }{}%
+ }%
+ }%
+ %
+ \pgfkeys{/tikzuml/actorobj/.cd, ##1}%
+ \umlobject[stereo=actor, ##1]{##2}%
+ }%
+ \else%
+ \renewcommand{\umlactor}[2][]{%
+ \pgfkeys{/tikzuml/actorobj/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlactor, forbidden option stereo}%
+ }{}%
+ }%
+ }%
+ %
+ \pgfkeys{/tikzuml/actorobj/.cd, ##1}%
+ \umlobject[stereo=actor, ##1]{##2}%
+ }%
+ \fi%
+ \begin{scope}[font=\tikzumlDefaultFont]%
+}{%
+ % draw lifelines of each object
+ \begin{pgfonlayer}{lifelines}%
+ \foreach \id in \tikzumlIdList {%
+ \draw (\csname tikzumlLastChild@\id \endcsname)+(0,-2.5ex) node[inner sep=0, name=end-\id] {};%
+ \draw[dotted] (\id) -- (end-\id);%
+ }%
+ \end{pgfonlayer}%
+ \end{scope}%
+}%
+%
+% define the database symbol
+% optional : global tikzpicture styles
+\newcommand{\pictureddatabase}[1]{%
+ \pgfkeys{/tikzuml/database/.cd, scale/.initial=1, .unknown/.code={}}%
+ \pgfkeys{/tikzuml/database/.cd,#1}%
+ \pgfkeys{/tikzuml/database/.cd, scale/.get=\tikzumlDatabaseScale}%
+ %
+ \begin{tikzpicture}[#1]%
+ \node[fill, draw, ellipse, minimum width=\tikzumlDatabaseScale*4ex, minimum height=\tikzumlDatabaseScale*2ex, inner sep=0] (bottom) at (0,-2ex) {};%
+ \node[fill, draw, ellipse, minimum width=\tikzumlDatabaseScale*4ex, minimum height=\tikzumlDatabaseScale*2ex, inner sep=0] (top) at (0,4ex) {};%
+ \fill (bottom.west) rectangle (top.east);%
+ \begin{scope}%
+ \clip (-3.5ex,-0.5ex) rectangle (3.5ex,2.5ex);%
+ \node[draw, dashed, ellipse, minimum width=\tikzumlDatabaseScale*4ex, minimum height=\tikzumlDatabaseScale*2ex, inner sep=0] (bottom2) at (0,-2ex) {};%
+ \end{scope}%
+ \node[draw, ellipse, minimum width=\tikzumlDatabaseScale*4ex, minimum height=\tikzumlDatabaseScale*2ex, inner sep=0] (top2) at (0,4ex) {};%
+ \draw (bottom.west) -- (top.west) (bottom.east) -- (top.east);%
+ \end{tikzpicture}%
+}%
+%
+% define the entity symbol
+% optional : global tikzpicture styles
+\newcommand{\picturedentity}[1]{%
+ \pgfkeys{/tikzuml/entity/.cd, scale/.initial=1, .unknown/.code={}}%
+ \pgfkeys{/tikzuml/entity/.cd,#1}%
+ \pgfkeys{/tikzuml/entity/.cd, scale/.get=\tikzumlEntityScale}%
+ %
+ \begin{tikzpicture}[#1]%
+ \node[fill, draw, circle, inner sep=0, minimum size=\tikzumlEntityScale*5ex] (center) at (0,0) {};%
+ \draw (center.south) node[coordinate, name=bottom] {};%
+ \draw (bottom)+(-2ex,0) node[coordinate, name=bottom-left] {};%
+ \draw (bottom)+(2ex,0) node[coordinate, name=bottom-right] {};%
+ \draw (center) -- (bottom);%
+ \draw (bottom-left) -- (bottom-right);%
+ \end{tikzpicture}%
+}%
+%
+% define the boundary symbol
+% optional : global tikzpicture styles
+\newcommand{\picturedboundary}[1]{%
+ \pgfkeys{/tikzuml/boundary/.cd, scale/.initial=1, .unknown/.code={}}%
+ \pgfkeys{/tikzuml/boundary/.cd,#1}%
+ \pgfkeys{/tikzuml/boundary/.cd, scale/.get=\tikzumlBoundaryScale}%
+ %
+ \begin{tikzpicture}[#1]
+ \node[fill, draw, circle, inner sep=0, minimum size=\tikzumlBoundaryScale*5ex] (center) at (0,0) {};
+ \draw (center.west)+(-0.8ex,0) node[coordinate, name=left] {};
+ \draw (left)+(0,0.2ex) node[coordinate, name=left-top] {};
+ \draw (left)+(0,-0.2ex) node[coordinate, name=left-bottom] {};
+ \draw (center) -- (left);
+ \draw (left-top) -- (left-bottom);
+ \end{tikzpicture}
+}%
+%
+% define the control symbol
+% optional : global tikzpicture styles
+\newcommand{\picturedcontrol}[1]{%
+ \pgfkeys{/tikzuml/control/.cd, scale/.initial=1, .unknown/.code={}}%
+ \pgfkeys{/tikzuml/control/.cd,#1}%
+ \pgfkeys{/tikzuml/control/.cd, scale/.get=\tikzumlControlScale}%
+ %
+ \begin{tikzpicture}[#1, decoration={markings, mark=at position 0.25 with {\arrow{>}}}]
+ \node[fill, draw, circle, inner sep=0, minimum size=\tikzumlControlScale*5ex, postaction={decorate}] (center) at (0,0) {};
+ \end{tikzpicture}
+}%
+%
+% define a uml object for a sequence diagram
+% args : name of the object
+% optional : x, y: coordinates of the object
+% stereo: stereotype of the object (object, actor, database, boundary, control, entity, multiobject)
+% class: class of the object
+% scale: scale factor of the object symbol
+% draw, fill, text; colors
+% no ddots: when used, disable printing of double dots
+\newcommand{\umlobject}[2][]{
+ \stepcounter{tikzumlObjectNum}%
+ %
+ \edef\tikzumlobject@ddot{:}%
+ \pgfkeys{/tikzuml/obj/.cd, x/.initial=tikzumlEmpty, y/.initial=\tikzumlDefaultX, stereo/.initial=\tikzumlObjectDefaultStereo,%
+ class/.initial={}, scale/.initial=1,%
+ draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlObjectDefaultFillColor,%
+ text/.initial=\tikzumlDefaultTextColor,%
+ no ddots/.is if=tikzumlobjectNoDDots,%
+ no ddots=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \errmessage{TIKZUML ERROR : in umlobject, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/obj/.cd, #1}%
+ \pgfkeys{/tikzuml/obj/.cd, x/.get=\tikzumlObjectX, y/.get=\tikzumlObjectY,%
+ stereo/.get=\tikzumlObjectStereo, class/.get=\tikzumlObjectClass,%
+ scale/.get=\tikzumlObjectScale,%
+ draw/.get=\tikzumlObjectDrawColor, fill/.get=\tikzumlObjectFillColor,%
+ text/.get=\tikzumlObjectTextColor%
+ }%
+ %
+ \iftikzumlobjectNoDDots%
+ \edef\tikzumlobject@ddot{}%
+ \fi%
+ %
+ \ifthenelse{\equal{\tikzumlObjectX}{tikzumlEmpty}}{%
+ \pgfmathsetmacro{\tikzumlObjectX}{4*(\thetikzumlObjectNum-1)}%
+ }{}%
+ %
+ \def\tikzumlObjectName{#2}%
+ \expandafter\xdef\csname tikzumlLastChild@\tikzumlObjectName \endcsname{\tikzumlObjectName}%
+ %
+ \ifnum\thetikzumlObjectNum=1%
+ \xdef\tikzumlIdList{\tikzumlObjectName}%
+ \else%
+ \let\tikzumlIdListOld\tikzumlIdList%
+ \expandafter\xdef\expandafter\tikzumlIdList\expandafter{\tikzumlIdListOld,\tikzumlObjectName}%
+ \fi%
+ %
+ \tikzstyle{tikzuml object box style}=[rectangle, text=\tikzumlObjectTextColor, font=\tikzumlDefaultFont]%
+ %
+ \ifthenelse{\equal{\tikzumlObjectStereo}{object}}{%
+ \tikzstyle{tikzuml object box style}+=[draw=\tikzumlObjectDrawColor, fill=\tikzumlObjectFillColor]%
+ }{%
+ \ifthenelse{\equal{\tikzumlObjectStereo}{multi}}{%
+ \tikzstyle{tikzuml object box style}+=[fill=\tikzumlObjectFillColor]%
+ }{}%
+ }%
+ %
+ \ifnum\tikzumlInCreateCall=1%
+ \draw (\tikzumlCreateCallObjectSrc -| \tikzumlObjectX,0) node[tikzuml object box style] (\tikzumlObjectName) {\tikzumlObjectName\tikzumlobject@ddot\tikzumlObjectClass};%
+ \else%
+ \node[tikzuml object box style] (\tikzumlObjectName) at (\tikzumlObjectX,\tikzumlObjectY) {\tikzumlObjectName\tikzumlobject@ddot\tikzumlObjectClass};%
+ \fi%
+ %
+ \ifthenelse{\equal{\tikzumlObjectStereo}{multi}}{%
+ \draw (\tikzumlObjectName.north east)+(0.4ex,0.4ex) node[name=\tikzumlObjectName-tr, coordinate] {};
+ \draw (\tikzumlObjectName.north west)+(0.4ex,0.4ex) node[name=\tikzumlObjectName-tl, coordinate] {};
+ \draw (\tikzumlObjectName.south east)+(0.4ex,0.4ex) node[name=\tikzumlObjectName-br, coordinate] {};
+ \draw (\tikzumlObjectName-tr)+(0.4ex,0.4ex) node[name=\tikzumlObjectName-ttr, coordinate] {};
+ \draw (\tikzumlObjectName-tl)+(0.4ex,0.4ex) node[name=\tikzumlObjectName-ttl, coordinate] {};
+ \draw (\tikzumlObjectName-br)+(0.4ex,0.4ex) node[name=\tikzumlObjectName-tbr, coordinate] {};
+ \fill[fill=\tikzumlObjectFillColor] (\tikzumlObjectName-ttl |- \tikzumlObjectName.north) -- (\tikzumlObjectName-ttl) -- (\tikzumlObjectName-ttr) -- (\tikzumlObjectName-tbr) -- (\tikzumlObjectName-tbr -| \tikzumlObjectName.east) -- (\tikzumlObjectName.north east) -- (\tikzumlObjectName-ttl |- \tikzumlObjectName.north);
+ \draw[draw=\tikzumlObjectDrawColor] (\tikzumlObjectName-ttl |- \tikzumlObjectName.north) -- (\tikzumlObjectName-ttl) -- (\tikzumlObjectName-ttr) -- (\tikzumlObjectName-tbr) -- (\tikzumlObjectName-tbr -| \tikzumlObjectName.east);
+ \fill[fill=\tikzumlObjectFillColor] (\tikzumlObjectName-tl |- \tikzumlObjectName.north) -- (\tikzumlObjectName-tl) -- (\tikzumlObjectName-tr) -- (\tikzumlObjectName-br) -- (\tikzumlObjectName-br -| \tikzumlObjectName.east) -- (\tikzumlObjectName.north east) -- (\tikzumlObjectName-tl |- \tikzumlObjectName.north);
+ \draw[draw=\tikzumlObjectDrawColor] (\tikzumlObjectName-tl |- \tikzumlObjectName.north) -- (\tikzumlObjectName-tl) -- (\tikzumlObjectName-tr) -- (\tikzumlObjectName-br) -- (\tikzumlObjectName-br -| \tikzumlObjectName.east);
+ \draw[draw=\tikzumlObjectDrawColor] (\tikzumlObjectName.north west) rectangle (\tikzumlObjectName.south east);
+ }{%
+ \ifthenelse{\equal{\tikzumlObjectStereo}{object}}{}{%
+ \node[above=1ex, name=\tikzumlObjectName-picture] at (\tikzumlObjectName) {\csname pictured\tikzumlObjectStereo \endcsname{draw=\tikzumlObjectDrawColor, fill=\tikzumlObjectFillColor, scale=\tikzumlObjectScale}};
+ }%
+ }%
+}%
+%
+% shortcuts for objects
+\newcommand{\umlbasicobject}[2][]{%
+ \pgfkeys{/tikzuml/basicobj/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{no ddots}}{%
+ \errmessage{TIKZUML ERROR : in umlbasicobject, forbidden option no ddots}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/basicobj/.cd, #1}%
+ \umlobject[no ddots, #1]{#2}%
+}%
+%
+\newcommand{\umldatabase}[2][]{%
+ \pgfkeys{/tikzuml/databaseobj/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umldatabase, forbidden option stereo}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/databaseobj/.cd, #1}%
+ \umlobject[stereo=database, #1]{#2}%
+}%
+\newcommand{\umlentity}[2][]{%
+ \pgfkeys{/tikzuml/entityobj/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlentity, forbidden option stereo}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/entityobj/.cd, #1}%
+ \umlobject[stereo=entity, #1]{#2}%
+}%
+\newcommand{\umlcontrol}[2][]{%
+ \pgfkeys{/tikzuml/controlobj/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlcontrol, forbidden option stereo}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/controlobj/.cd, #1}%
+ \umlobject[stereo=control, #1]{#2}%
+}%
+\newcommand{\umlboundary}[2][]{%
+ \pgfkeys{/tikzuml/boundaryobj/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlboundary, forbidden option stereo}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/boundaryobj/.cd, #1}%
+ \umlobject[stereo=boundary, #1]{#2}%
+}%
+\newcommand{\umlmulti}[2][]{%
+ \pgfkeys{/tikzuml/multiobj/.cd, .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlmulti, forbidden option stereo}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/multiobj/.cd, #1}%
+ \umlobject[stereo=multi, #1]{#2}%
+}%
+%
+\newcounter{tikzumlSDNodeNum}%
+%
+% define a hidden node to lengthen lifeline of a object
+% args : object node
+% optional : dt: distance between the sdnode and the last call defined on the lifeline of the object
+% name: name of the sdnode
+\newcommand{\umlsdnode}[2][]{%
+ \pgfkeys{/tikzuml/sdnode/.cd, dt/.initial=0, name/.initial=tikzumlEmpty}%
+ \pgfkeys{/tikzuml/sdnode/.cd, #1}%
+ \pgfkeys{/tikzuml/sdnode/.cd, dt/.get=\tikzumlSDNodeDT, name/.get=\tikzumlSDNodeName}%
+ %
+ \ifthenelse{\equal{\tikzumlSDNodeName}{tikzumlEmpty}}{%
+ \expandafter\def\expandafter\tikzumlSDNode@nodeName{sdnode-\thetikzumlSDNodeNum}%
+ }{%
+ \expandafter\def\expandafter\tikzumlSDNode@nodeName{\tikzumlSDNodeName}%
+ }%
+ %
+ \stepcounter{tikzumlSDNodeNum}%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlSDNode@objnodeName{#2}}\x%
+ %
+ \draw (\expandafter\csname tikzumlLastChild@\tikzumlSDNode@objnodeName \endcsname)+(0,-\tikzumlSDNodeDT ex) node[name=\tikzumlSDNode@nodeName,coordinate] {};%
+ %
+ % update last node drawn on sender lifeline
+ \expandafter\xdef\csname tikzumlLastChild@\tikzumlSDNode@objnodeName \endcsname{\tikzumlSDNode@nodeName}%
+}%
+%
+\newlength{\tikzumlCall@xa}%
+\newlength{\tikzumlCall@xb}%
+%
+% define a uml operation call for sequence diagrams
+% args : call sender
+% call receiver
+% optional : dt: time delay from precedent event end
+% name: name of the call
+% op: operation name and input args
+% return: return value
+% type: type of the call (synchron, asynchron)
+% draw, fill, text: colors
+% padding: time padding from call start and to call end
+\newenvironment{umlcall}[3][]{%
+ \stepcounter{tikzumlCallNum}%
+ \def\tikzumlCallWithReturn{tikzumlFalse}%
+ \edef\tikzumlCall@lastchildNum{\thetikzumlCallNum}% for testing presence of sub-calls
+ \gdef\tikzumlCallBottom{0}%
+ %
+ \pgfkeys{/tikzuml/call/.cd, dt/.initial=\tikzumlCallDefaultDT, name/.initial={call-\thetikzumlCallNum},%
+ op/.initial={}, return/.initial={}, type/.initial=\tikzumlCallDefaultType,%
+ draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlCallDefaultFillColor,%
+ text/.initial=\tikzumlDefaultTextColor,%
+ padding/.initial=\tikzumlCallDefaultPadding,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{with return}}{%
+ \def\tikzumlCallWithReturn{tikzumlTrue}%
+ }{%
+ \errmessage{TIKZUML ERROR : in umlcall, invalid option \keyname}%
+ }%
+ }%
+ }%
+ \pgfkeys{/tikzuml/call/.cd, #1}%
+ \pgfkeys{/tikzuml/call/.cd, dt/.get=\tikzumlCallDT, name/.get=\tikzumlCallName, op/.get=\tikzumlCallOp,%
+ return/.get=\tikzumlCallReturn, type/.get=\tikzumlCallType,%
+ padding/.get=\tikzumlCallPadding,%
+ draw/.get=\tikzumlCallDrawColor, fill/.get=\tikzumlCallFillColor,%
+ text/.get=\tikzumlCallTextColor%
+ }%
+ %
+ \edef\tikzumlfillcall{\tikzumlCallFillColor}%
+ \edef\tikzumldrawcall{\tikzumlCallDrawColor}%
+ \edef\tikzumltextcall{\tikzumlCallTextColor}%
+ \edef\tikzumltypecall{\tikzumlCallType}%
+ %
+ \ifthenelse{\equal{\tikzumlCallDT}{tikzumlEmpty}}{%
+ \ifnum\thetikzumlCallNum=1%
+ \def\tikzumlCallDT{2}%
+ \def\tikzumlcallSrc{2}%
+ \else%
+ \def\tikzumlCallDT{2}%
+ \def\tikzumlcallSrc{1}%
+ \fi%
+ }{%
+ \def\tikzumlcallSrc{0}%
+ }%
+ %
+ \let\tikzumlCallStartNodeNameold\tikzumlCallStartNodeName%
+ \def\tikzumlCallStartNodeName{#2}%
+ \let\tikzumlCallEndNodeNameold\tikzumlCallEndNodeName%
+ \def\tikzumlCallEndNodeName{#3}%
+ \def\tikzumlcallheight{\tikzumlCallPadding}%
+ %
+ % managing time delays from previous/parent fragments
+ \ifnum\thetikzumlCallStartFragmentNum>0%
+ \let\tikzumlCallDTold\tikzumlCallDT%
+ \pgfmathparse{0.5*\tikzumlFragment@paddingy+\tikzumlCallDTold}%
+ \edef\tikzumlCallDT{\pgfmathresult}%
+ \addtocounter{tikzumlCallStartFragmentNum}{-1}
+ \fi%
+ \ifnum\thetikzumlCallEndFragmentNum>0%
+ \let\tikzumlCallDTold\tikzumlCallDT%
+ \pgfmathparse{0.5*\tikzumlFragment@paddingy+\tikzumlCallDTold}%
+ \edef\tikzumlCallDT{\pgfmathresult}%
+ \addtocounter{tikzumlCallEndFragmentNum}{-1}
+ \fi%
+ \ifnum\thetikzumlFragmentPartNum>0%
+ \let\tikzumlCallDTold\tikzumlCallDT%
+ \pgfmathparse{0.5*\tikzumlFragment@paddingy+\tikzumlCallDTold}%
+ \edef\tikzumlCallDT{\pgfmathresult}%
+ \fi%
+ %
+ % managing parent-child structure
+ \ifnum\thetikzumlCallLevel>0%
+ \let\tikzumlCall@nameold\tikzumlCall@name%
+ \edef\tikzumlCall@name{\tikzumlCallName}%
+ \let\tikzumlCall@parentold\tikzumlCall@parent%
+ \edef\tikzumlCall@parent{\tikzumlCall@parentold @@\tikzumlCall@nameold}%
+ \else%
+ \edef\tikzumlCall@parent{}%
+ \edef\tikzumlCall@parentold{}%
+ \edef\tikzumlCall@nameold{}
+ \edef\tikzumlCall@name{\tikzumlCallName}%
+ \fi%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlCall@nodeName{\tikzumlCall@name}}\x%
+ %
+ \let\tikzumlCall@nodeNameold\tikzumlCall@nodeName%
+ %
+ \def\tikzumlcallstyle{tikzuml \tikzumlCallType-msg style}%
+ %
+ % top node of activity period of call sender
+ \begin{pgfonlayer}{connections}%
+ \pgfmathparse{\tikzumlCallDT+\tikzumlcallSrc}%
+ \draw (\csname tikzumlLastChild@\tikzumlCallStartNodeName \endcsname)+(0,-\pgfmathresult ex) node[coordinate, name=tikzumlTmpNode] {};%
+ \node[tikzuml activity style] (st-\tikzumlCall@nodeName) at (\tikzumlCallStartNodeName |- tikzumlTmpNode) {};%
+ %
+ % update last node drawn on sender lifeline
+ \expandafter\xdef\csname tikzumlLastChild@\tikzumlCallStartNodeName \endcsname{st-\tikzumlCall@nodeName}%
+ %
+ % top node of activity period of call receiver
+ \ifstrequal{\tikzumlCallStartNodeName}{\tikzumlCallEndNodeName}{%
+ \draw (st-\tikzumlCall@nodeName)+(0,-0.75*\tikzumlCallPadding ex) node[coordinate, name=tikzumlTmpNode] {};%
+ \node[tikzuml activity style] (et-\tikzumlCall@nodeName) at (\tikzumlCallStartNodeName |- tikzumlTmpNode) {};%
+ }{%
+ \node[tikzuml activity style] (et-\tikzumlCall@nodeName) at (\tikzumlCallEndNodeName |- st-\tikzumlCall@nodeName) {};%
+ }%
+ %
+ % update last node drawn on receiver lifeline
+ \expandafter\xdef\csname tikzumlLastChild@\tikzumlCallEndNodeName \endcsname{et-\tikzumlCall@nodeName}%
+ \xdef\tikzumlCallBottomSrc{et-\tikzumlCall@nodeName}%
+ \end{pgfonlayer}%
+ %
+ \stepcounter{tikzumlCallLevel}%
+}{%
+ \addtocounter{tikzumlCallLevel}{-1}%
+ %
+ % bottom nodes of activity periods of call sender and receiver
+ \begin{pgfonlayer}{connections}%
+ \ifnum\tikzumlCall@lastchildNum=\thetikzumlCallNum%
+ %
+ % this test occurs a bug with latex package preview
+ \ifstrequal{\tikzumlCallStartNodeName}{\tikzumlCallEndNodeName}{%
+ \draw (\tikzumlCallBottomSrc)+(0,-\tikzumlCallPadding ex) node[coordinate, name=tikzumlTmpNode] {};%
+ \node[tikzuml activity style] (eb-\tikzumlCall@nodeName) at (\tikzumlCallEndNodeName |- tikzumlTmpNode) {};%
+ \draw (eb-\tikzumlCall@nodeName)+(0,-0.75*\tikzumlCallPadding ex) node[coordinate, name=tikzumlTmpNode] {};%
+ \node[tikzuml activity style] (sb-\tikzumlCall@nodeName) at (\tikzumlCallStartNodeName |- tikzumlTmpNode) {};%
+ }{%
+ \ifthenelse{\equal{\tikzumlCallReturn}{tikzumlEmpty}}{%
+ \pgfmathsetmacro{\tikzumlCallPaddingd}{0.5*\tikzumlCallPadding}%
+ }{%
+ \pgfmathsetmacro{\tikzumlCallPaddingd}{1.2*\tikzumlCallPadding}%
+ }%
+ \draw (\tikzumlCallBottomSrc)+(0,-\tikzumlCallPaddingd ex) node[coordinate, name=tikzumlTmpNode] {};%
+ \node[tikzuml activity style] (eb-\tikzumlCall@nodeName) at (\tikzumlCallEndNodeName |- tikzumlTmpNode) {};%
+ \node[tikzuml activity style] (sb-\tikzumlCall@nodeName) at (\tikzumlCallStartNodeName |- eb-\tikzumlCall@nodeName) {};%
+ }%
+ \xdef\tikzumlCallBottomSrc{sb-\tikzumlCall@nodeName}%
+ \else%
+ %
+ % managing time delays from previous/parent fragments
+ \ifnum\thetikzumlCallStartFragmentNum>0%
+ \let\tikzumlcallheightold\tikzumlCallPadding%
+ \pgfmathparse{\tikzumlcallheightold+0.5*\tikzumlFragment@paddingy}%
+ \edef\tikzumlcallheight{\pgfmathresult}%
+ \addtocounter{tikzumlCallStartFragmentNum}{-1}%
+ \fi%
+ \ifnum\thetikzumlCallEndFragmentNum>0%
+ \let\tikzumlcallheightold\tikzumlCallPadding%
+ \pgfmathparse{\tikzumlcallheightold+0.5*\tikzumlFragment@paddingy}%
+ \edef\tikzumlcallheight{\pgfmathresult}%
+ \addtocounter{tikzumlCallEndFragmentNum}{-1}%
+ \fi%
+ %
+ \ifstrequal{\tikzumlCallStartNodeName}{\tikzumlCallEndNodeName}{%
+ \draw (\tikzumlCallBottomSrc)+(0,-\tikzumlcallheight ex) node[coordinate, name=tikzumlTmpNode] {};%
+ \node[tikzuml activity style] (eb-\tikzumlCall@nodeName) at (\tikzumlCallEndNodeName |- tikzumlTmpNode) {};%
+ \draw (eb-\tikzumlCall@nodeName)+(0,-0.75*\tikzumlCallPadding ex) node[coordinate, name=tikzumlTmpNode] {};%
+ \node[tikzuml activity style] (sb-\tikzumlCall@nodeName) at (\tikzumlCallStartNodeName |- tikzumlTmpNode) {};%
+ }{%
+ \draw (\tikzumlCallBottomSrc)+(0,-\tikzumlcallheight ex) node[coordinate, name=tikzumlTmpNode] {};%
+ \node[tikzuml activity style] (eb-\tikzumlCall@nodeName) at (\tikzumlCallEndNodeName |- tikzumlTmpNode) {};%
+ \node[tikzuml activity style] (sb-\tikzumlCall@nodeName) at (\tikzumlCallStartNodeName |- eb-\tikzumlCall@nodeName) {};%
+ }%
+ %
+ \xdef\tikzumlCallBottomSrc{sb-\tikzumlCall@nodeName}%
+ \fi%
+ \end{pgfonlayer}%
+ %
+ % draw activity periods
+ \begin{pgfonlayer}{activity}%
+ \ifstrequal{\tikzumlCallStartNodeName}{\tikzumlCallEndNodeName}{%
+ % draw root activity period only
+ \ifnum\thetikzumlCallLevel=0%
+ \draw[draw=\tikzumldrawcall, fill=\tikzumlfillcall] (st-\tikzumlCall@nodeName.north west) rectangle (sb-\tikzumlCall@nodeName.south east);%
+ \else%
+ % draw root activity from inner call
+ \ifthenelse{\equal{\tikzumlCallStartNodeName}{\tikzumlCallEndNodeNameold}}{}{%
+ \draw[draw=\tikzumldrawcall, fill=\tikzumlfillcall] (st-\tikzumlCall@nodeName.north west) rectangle (sb-\tikzumlCall@nodeName.south east);%
+ }%
+ \fi%
+ }{%
+ % draw root activity period
+ \ifnum\thetikzumlCallLevel=0%
+ \draw[draw=\tikzumldrawcall, fill=\tikzumlfillcall] (st-\tikzumlCall@nodeName.north west) rectangle (sb-\tikzumlCall@nodeName.south east);%
+ \else%
+ % draw root activity from inner call
+ \ifthenelse{\equal{\tikzumlCallStartNodeName}{\tikzumlCallEndNodeNameold}}{}{%
+ \draw[draw=\tikzumldrawcall, fill=\tikzumlfillcall] (st-\tikzumlCall@nodeName.north west) rectangle (sb-\tikzumlCall@nodeName.south east);%
+ }%
+ \fi%
+ % draw receiver activity period
+ \draw[draw=\tikzumldrawcall, fill=\tikzumlfillcall] (et-\tikzumlCall@nodeName.north west) rectangle (eb-\tikzumlCall@nodeName.south east);%
+ }%
+ \end{pgfonlayer}%
+ \ifthenelse{\equal{\tikzumlCallDefaultFillColor}{\tikzumlCallFillColor}}{}{%
+ \fill[\tikzumlfillcall] (st-\tikzumlCall@nodeName.north west) rectangle (sb-\tikzumlCall@nodeName.south east);%
+ \draw[\tikzumldrawcall] (st-\tikzumlCall@nodeName.north west) rectangle (sb-\tikzumlCall@nodeName.south west) (st-\tikzumlCall@nodeName.north east) rectangle (sb-\tikzumlCall@nodeName.south east);%
+ }%
+ %
+ % update last nodes drawn on sender and receiver lifelines
+ \expandafter\xdef\csname tikzumlLastChild@\tikzumlCallEndNodeName \endcsname{eb-\tikzumlCall@nodeName}%
+ \expandafter\xdef\csname tikzumlLastChild@\tikzumlCallStartNodeName \endcsname{sb-\tikzumlCall@nodeName}%
+ %
+ % draw call arrows
+ \begin{pgfonlayer}{connections}%
+ \ifstrequal{\tikzumlCallStartNodeName}{\tikzumlCallEndNodeName}{%
+ \draw[\tikzumlcallstyle, \tikzumldrawcall] (st-\tikzumlCall@nodeName.east) -- ++(2.5*\tikzumlCallPadding ex,0) %
+ -- ++(0,-0.75*\tikzumlCallPadding ex) %
+ node[font=\tikzumlDefaultFont, text=\tikzumltextcall, midway, right, name=\tikzumlCall@nodeName-op] {\tikzumlCallOp} %
+ -- (et-\tikzumlCall@nodeName.east);%
+ %
+ % draw return arrow and update fit for parent fragment
+ \ifthenelse{\equal{\tikzumltypecall}{synchron}}{%
+ \ifthenelse{\NOT\equal{\tikzumlCallReturn}{}\OR\equal{\tikzumlCallWithReturn}{tikzumlTrue}}{%
+ \ifnum\c@tikzumlFragmentLevel>0%
+ \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname}%
+ \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{\tikzumlFragmentFitOld (st-\tikzumlCall@nodeName) (et-\tikzumlCall@nodeName) (eb-\tikzumlCall@nodeName) (sb-\tikzumlCall@nodeName) (\tikzumlCall@nodeName-op) (\tikzumlCall@nodeName-return)}%
+ \fi%
+ %
+ \draw[tikzuml call return style, \tikzumldrawcall] (eb-\tikzumlCall@nodeName.east) -- ++(2.5*\tikzumlCallPadding ex,0)
+ -- ++(0,-0.75*\tikzumlCallPadding ex) %
+ node[font=\tikzumlDefaultFont, text=\tikzumltextcall, midway, right, name=\tikzumlCall@nodeName-return] {\tikzumlCallReturn} %
+ -- (sb-\tikzumlCall@nodeName.east);%
+ }{%
+ \ifnum\c@tikzumlFragmentLevel>0%
+ \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname}%
+ \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{\tikzumlFragmentFitOld (st-\tikzumlCall@nodeName) (et-\tikzumlCall@nodeName) (eb-\tikzumlCall@nodeName) (sb-\tikzumlCall@nodeName) (\tikzumlCall@nodeName-op)}%
+ \fi%
+ }%
+ }{%
+ \ifnum\c@tikzumlFragmentLevel>0%
+ \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname}%
+ \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{\tikzumlFragmentFitOld (st-\tikzumlCall@nodeName) (et-\tikzumlCall@nodeName) (eb-\tikzumlCall@nodeName) (sb-\tikzumlCall@nodeName) (\tikzumlCall@nodeName-op)}%
+ \fi%
+ }%
+ }{%
+ % draw call arrows
+ \pgfextractx{\tikzumlCall@xa}{\pgfpointanchor{\tikzumlCallStartNodeName}{center}}%
+ \pgfextractx{\tikzumlCall@xb}{\pgfpointanchor{\tikzumlCallEndNodeName}{center}}%
+ %
+ \ifthenelse{\tikzumlCall@xb>\tikzumlCall@xa}{%
+ \draw[\tikzumlcallstyle, \tikzumldrawcall] (st-\tikzumlCall@nodeName.east) -- (et-\tikzumlCall@nodeName.west) %
+ node[font=\tikzumlDefaultFont, text=\tikzumltextcall, midway, above=-0.4ex, name=\tikzumlCall@nodeName-op] {\tikzumlCallOp};%
+ }{%
+ \draw[\tikzumlcallstyle, \tikzumldrawcall] (st-\tikzumlCall@nodeName.west) -- (et-\tikzumlCall@nodeName.east) %
+ node[font=\tikzumlDefaultFont, text=\tikzumltextcall, midway, above=-0.4ex, name=\tikzumlCall@nodeName-op] {\tikzumlCallOp};%
+ }%
+ %
+ % draw return arrow and update fit for parent fragment
+ \ifthenelse{\equal{\tikzumltypecall}{synchron}}{%
+ \ifthenelse{\NOT\equal{\tikzumlCallReturn}{}\OR\equal{\tikzumlCallWithReturn}{tikzumlTrue}}{%
+ \ifnum\c@tikzumlFragmentLevel>0%
+ \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname}%
+ \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{\tikzumlFragmentFitOld (st-\tikzumlCall@nodeName) (et-\tikzumlCall@nodeName) (eb-\tikzumlCall@nodeName) (sb-\tikzumlCall@nodeName) (\tikzumlCall@nodeName-op) (\tikzumlCall@nodeName-return)}%
+ \fi%
+ %
+ \ifthenelse{\tikzumlCall@xb>\tikzumlCall@xa}{%
+ \draw[tikzuml call return style, \tikzumldrawcall] (eb-\tikzumlCall@nodeName.west) -- (sb-\tikzumlCall@nodeName.east) %
+ node[font=\tikzumlDefaultFont, text=\tikzumltextcall, midway, above=-0.4ex, name=\tikzumlCall@nodeName-return] {\tikzumlCallReturn};%
+ }{%
+ \draw[tikzuml call return style, \tikzumldrawcall] (eb-\tikzumlCall@nodeName.east) -- (sb-\tikzumlCall@nodeName.west) %
+ node[font=\tikzumlDefaultFont, text=\tikzumltextcall, midway, above=-0.4ex, name=\tikzumlCall@nodeName-return] {\tikzumlCallReturn};%
+ }%
+ }{%
+ \ifnum\c@tikzumlFragmentLevel>0%
+ \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname}%
+ \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{\tikzumlFragmentFitOld (st-\tikzumlCall@nodeName) (et-\tikzumlCall@nodeName) (eb-\tikzumlCall@nodeName) (sb-\tikzumlCall@nodeName) (\tikzumlCall@nodeName-op)}%
+ \fi%
+ }%
+ }{%
+ \ifnum\c@tikzumlFragmentLevel>0%
+ \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname}%
+ \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{\tikzumlFragmentFitOld (st-\tikzumlCall@nodeName) (et-\tikzumlCall@nodeName) (eb-\tikzumlCall@nodeName) (sb-\tikzumlCall@nodeName) (\tikzumlCall@nodeName-op)}%
+ \fi%
+ }%
+ }%
+ \end{pgfonlayer}%
+}%
+%
+% alias for function self call
+\newenvironment{umlcallself}[2][]{\begin{umlcall}[#1]{#2}{#2} }{\end{umlcall}}%
+%
+% define a combined fragment
+% optional : name: name of fragment
+% type: type of fragment (opt, alt, break, loop, par, critical, ignore, consider, assert, neg, weak, strict, ref)
+% label: label of fragment (ex : condition for opt, iterator for loop, ...)
+% inner xsep, inner ysep: padding of the fragment box
+% draw, fill, text: colors
+\newenvironment{umlfragment}[1][]{%
+ % define a fragment separator
+ % optional : label of the fragment part (ex : else for alt)
+ \providecommand{\umlfpart}[1][]{%
+ \stepcounter{tikzumlFragmentPartNum}%
+ %
+ \node[outer sep=0, inner xsep=\tikzumlFragmentXSep ex, inner ysep=\tikzumlFragmentYSep ex, fit=\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname, name=\tikzumlFragment@name-Part-tmp] {};%
+ \node[anchor=east, name=\tikzumlFragment@name-PartType-\thetikzumlFragmentPartNum] at (\tikzumlFragment@name-Part-tmp.north west |- \tikzumlCallBottomSrc) {\phantom{\tikzumlFragmentType}};%
+ \draw (\tikzumlFragment@name-PartType-\thetikzumlFragmentPartNum.north west |- \tikzumlCallBottomSrc)+(0,-0.4*\tikzumlFragment@paddingy ex) node[name=\tikzumlFragment@name-PartWest-\thetikzumlFragmentPartNum] {};%
+ \draw (\tikzumlFragment@name-Part-tmp.north east |- \tikzumlCallBottomSrc)+(0,-0.4*\tikzumlFragment@paddingy ex) node[name=\tikzumlFragment@name-PartEast-\thetikzumlFragmentPartNum] {};%
+ \draw[dashed] (\tikzumlFragment@name-PartWest-\thetikzumlFragmentPartNum) -- (\tikzumlFragment@name-PartEast-\thetikzumlFragmentPartNum);
+ \draw (\tikzumlFragment@name-PartType-\thetikzumlFragmentPartNum)+(0,-0.4*\tikzumlFragment@paddingy ex) node[name=tikzumlTmpNode] {\phantom{\tikzumlFragmentType}};%
+ \node[anchor=north west] at (tikzumlTmpNode.south west) {[##1]};%
+ }%
+ %
+ \stepcounter{tikzumlFragmentNum}%
+ %
+ \pgfkeys{/tikzuml/fragment/.cd, name/.initial=fragment@\alph{tikzumlFragmentNum}, type/.initial=\tikzumlFragmentDefaultType,%
+ label/.initial=tikzumlEmpty,%
+ inner xsep/.initial=\tikzumlFragmentDefaultXSep, inner ysep/.initial=\tikzumlFragmentDefaultYSep,%
+ draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlFragmentDefaultFillColor,%
+ text/.initial=\tikzumlDefaultTextColor,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \errmessage{TIKZUML ERROR : in umlfragment, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/fragment/.cd, #1}%
+ \pgfkeys{/tikzuml/fragment/.cd, name/.get=\tikzumlFragmentName, type/.get=\tikzumlFragmentType,%
+ label/.get=\tikzumlFragmentLabel,%
+ inner xsep/.get=\tikzumlFragmentXSep, inner ysep/.get=\tikzumlFragmentYSep,%
+ draw/.get=\tikzumlFragmentDrawColor, fill/.get=\tikzumlFragmentFillColor,%
+ text/.get=\tikzumlFragmentTextColor%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlFragmentLabel}{tikzumlEmpty}}{%
+ \def\tikzumlFragmentLabel{}%
+ }{%
+ \let\tikzumlFragmentLabelold\tikzumlFragmentLabel%
+ \def\tikzumlFragmentLabel{[\tikzumlFragmentLabelold]}%
+ }%
+ %
+ \ifnum\thetikzumlFragmentLevel>0%
+ \let\tikzumlFragment@parentold\tikzumlFragment@parent%
+ \let\tikzumlFragment@nameold\tikzumlFragment@name%
+ \edef\tikzumlFragment@parent{\tikzumlFragment@nameold}%
+ \else%
+ \setcounter{tikzumlFragmentPartNum}{0}%
+ \edef\tikzumlFragment@parent{}%
+ \edef\tikzumlFragment@parentold{}%
+ \edef\tikzumlFragment@nameold{}%
+ \fi%
+ %
+ \edef\tikzumlFragment@name{\tikzumlFragmentName}%
+ \expandafter\gdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{}%
+ %
+ \stepcounter{tikzumlFragmentLevel}%
+ %
+ \ifnum\thetikzumlCallLevel>0%
+ \stepcounter{tikzumlCallStartFragmentNum}%
+ \fi%
+ %
+ \pgfmathparse{6*\tikzumlFragmentYSep}%
+ \xdef\tikzumlFragment@paddingy{\pgfmathresult}%
+ \if\c@tikzumlFragmentLevelNum=0%
+ \setcounter{tikzumlFragmentLevelNum}{\thetikzumlFragmentLevel}%
+ \fi%
+ %
+ % time delay adjustment for two consecutive fragments
+ \ifnum\thetikzumlCallEndFragmentNum>0%
+ \addtocounter{tikzumlCallEndFragmentNum}{-1}
+ \fi%
+}{%
+ %
+ \addtocounter{tikzumlFragmentLevel}{-1}%
+ %
+ \ifnum\thetikzumlFragmentLevel>0%
+ \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@parent \endcsname}%
+ \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@parent \endcsname{\tikzumlFragmentFitOld (\tikzumlFragment@name)}%
+ \fi%
+ %
+ % draw working fragment box
+ \begin{pgfonlayer}{fragment\thetikzumlFragmentLevel}%
+ \node[outer sep=0, inner xsep=\tikzumlFragmentXSep ex, inner ysep=\tikzumlFragmentYSep ex, fit=\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname, name=\tikzumlFragment@name-back] {};%
+ \end{pgfonlayer}%
+ %
+ % draw type and label
+ \node[text=\tikzumlFragmentTextColor, font=\tikzumlDefaultFont, anchor=north east, name=\tikzumlFragment@name-type] %
+ at (\tikzumlFragment@name-back.north west) {\tikzumlFragmentType};%
+ \node[text=\tikzumlFragmentTextColor, font=\tikzumlDefaultFont, anchor=north west, name=\tikzumlFragment@name-label] %
+ at (\tikzumlFragment@name-type.south west) {\tikzumlFragmentLabel};%
+ %
+ % draw final fragment box
+ \begin{pgfonlayer}{fragment\thetikzumlFragmentLevel}%
+ \node[draw=\tikzumlFragmentDrawColor, fill=\tikzumlFragmentFillColor, outer sep=0, inner sep=0, font=\tikzumlDefaultFont, fit=(\tikzumlFragment@name-back) (\tikzumlFragment@name-type) (\tikzumlFragment@name-label), name=\tikzumlFragment@name] {};%
+ \end{pgfonlayer}%
+ %
+ \draw[draw=\tikzumlFragmentDrawColor] (\tikzumlFragment@name.north west) rectangle (\tikzumlFragment@name.south east);%
+ \draw (\tikzumlFragment@name-type.south east)+(0,1ex) node[name=\tikzumlFragment@name-typetop, inner sep=0] {};%
+ \draw (\tikzumlFragment@name-type.south east)+(-1ex,0) node[name=\tikzumlFragment@name-typeleft, inner sep=0] {};%
+ \draw (\tikzumlFragment@name.north west) -| (\tikzumlFragment@name-typetop.center) -- (\tikzumlFragment@name-typeleft.center) -| (\tikzumlFragment@name.north west);%
+ %
+ \ifnum\thetikzumlCallLevel>0%
+ \stepcounter{tikzumlCallEndFragmentNum}%
+ \fi%
+}%
+%
+% define a constructor call
+% arg : call sender
+% name of constructed object
+% optional : x: coordinate of the new object
+% stereo: stereotype of the new object
+% class: class type of the new object
+% dt: time delay from last event
+% name: name of the call
+% draw, fill, text: colors
+% no ddots: when used, disable printing of double dots
+\newcommand{\umlcreatecall}[3][]{%
+ \stepcounter{tikzumlCallNum}%
+ \edef\tikzumlCall@lastchildNum{\thetikzumlCallNum}% for testing presence of sub-calls
+ \gdef\tikzumlInCreateCall{1}%
+ \pgfkeys{/tikzuml/createcall/.cd, x/.initial=tikzumlEmpty, stereo/.initial=\tikzumlObjectDefaultStereo, class/.initial={},%
+ dt/.initial=\tikzumlCreateCallDefaultDT, name/.initial=call-\thetikzumlCallNum,%
+ draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlCallDefaultFillColor,%
+ text/.initial=\tikzumlDefaultTextColor,%
+ draw obj/.initial=\tikzumlDefaultDrawColor, fill obj/.initial=\tikzumlObjectDefaultFillColor,%
+ text obj/.initial=\tikzumlDefaultTextColor,%
+ no ddots/.is if=tikzumlcreatecallNoDDots,%
+ no ddots=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \errmessage{TIKZUML ERROR : in umlcreatecall, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/createcall/.cd, #1}%
+ \pgfkeys{/tikzuml/createcall/.cd, x/.get=\tikzumlCreateCallX, stereo/.get=\tikzumlCreateCallStereo,%
+ class/.get=\tikzumlCreateCallClass,%
+ dt/.get=\tikzumlCreateCallDT, name/.get=\tikzumlCreateCallName,%
+ draw/.get=\tikzumlCreateCallDrawColor, fill/.get=\tikzumlCreateCallFillColor,%
+ text/.get=\tikzumlCreateCallTextColor,%
+ draw obj/.get=\tikzumlCreateCallObjectDrawColor, fill obj/.get=\tikzumlCreateCallObjectFillColor,%
+ text obj/.get=\tikzumlCreateCallObjectTextColor%
+ }%
+ %
+ \def\tikzumlCreateCallSrc@name{#2}%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlCreateCallSrc@nodeName{\tikzumlCreateCallSrc@name}}\x%
+ %
+ % managing time delays from previous/parent fragments
+ \ifnum\thetikzumlCallStartFragmentNum>0%
+ \let\tikzumlCreateCallDTold\tikzumlCreateCallDT%
+ \pgfmathparse{0.5*\tikzumlFragment@paddingy+\tikzumlCreateCallDTold}%
+ \edef\tikzumlCreateCallDT{\pgfmathresult}%
+ \addtocounter{tikzumlCallStartFragmentNum}{-1}
+ \fi%
+ \ifnum\thetikzumlCallEndFragmentNum>0%
+ \let\tikzumlCreateCallDTold\tikzumlCreateCallDT%
+ \pgfmathparse{0.5*\tikzumlFragment@paddingy+\tikzumlCreateCallDTold}%
+ \edef\tikzumlCreateCallDT{\pgfmathresult}%
+ \addtocounter{tikzumlCallEndFragmentNum}{-1}
+ \fi%
+ \ifnum\thetikzumlFragmentPartNum>0%
+ \let\tikzumlCreateCallDTold\tikzumlCreateCallDT%
+ \pgfmathparse{0.5*\tikzumlFragment@paddingy+\tikzumlCreateCallDTold}%
+ \edef\tikzumlCreateCallDT{\pgfmathresult}%
+ \fi%
+ %
+ % managing parent-child structure
+ \ifnum\thetikzumlCallLevel>0%
+ \let\tikzumlCall@nameold\tikzumlCall@name%
+ \def\tikzumlCall@name{\tikzumlCreateCallName}%
+ \let\tikzumlCall@parentold\tikzumlCall@parent%
+ \edef\tikzumlCall@parent{\tikzumlCall@parentold @@\tikzumlCall@nameold}%
+ \else%
+ \edef\tikzumlCall@parent{}%
+ \edef\tikzumlCall@parentold{}%
+ \edef\tikzumlCall@nameold{}
+ \edef\tikzumlCall@name{\tikzumlCreateCallName}%
+ \fi%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlCreateCall@nodeName{\tikzumlCall@name}}\x%
+ %
+ \draw (\csname tikzumlLastChild@\tikzumlCreateCallSrc@nodeName \endcsname)+(0,-\tikzumlCreateCallDT ex) node[name=st-\tikzumlCreateCall@nodeName, tikzuml activity style] {};%
+ %
+ \xdef\tikzumlCreateCallObjectSrc{st-\tikzumlCreateCall@nodeName}%
+ %
+ \iftikzumlcreatecallNoDDots%
+ \umlobject[x=\tikzumlCreateCallX, stereo=\tikzumlCreateCallStereo, class=\tikzumlCreateCallClass, draw=\tikzumlCreateCallObjectDrawColor, fill=\tikzumlCreateCallObjectFillColor, text=\tikzumlCreateCallObjectTextColor, no ddots]{#3}%
+ \else
+ \umlobject[x=\tikzumlCreateCallX, stereo=\tikzumlCreateCallStereo, class=\tikzumlCreateCallClass, draw=\tikzumlCreateCallObjectDrawColor, fill=\tikzumlCreateCallObjectFillColor, text=\tikzumlCreateCallObjectTextColor]{#3}%
+ \fi
+ %
+ \draw (\csname tikzumlLastChild@\tikzumlCreateCallSrc@nodeName \endcsname |- #3)+(0,-0.5*\tikzumlCreateCallDT ex) node[name=sb-\tikzumlCreateCall@nodeName, tikzuml activity style] {};%
+ %
+ \expandafter\xdef\csname tikzumlLastChild@\tikzumlCreateCallSrc@nodeName \endcsname{sb-\tikzumlCreateCall@nodeName}%
+ \xdef\tikzumlCallBottomSrc{sb-\tikzumlCreateCall@nodeName}%
+ %
+ \begin{pgfonlayer}{connections}%
+ \draw[tikzuml synchron-msg style, \tikzumlCreateCallDrawColor] (st-\tikzumlCreateCall@nodeName) -- (#3) node[midway, above, font=\tikzumlDefaultFont, text=\tikzumlCreateCallTextColor, name=\tikzumlCreateCall@nodeName-op] {create};%
+ \end{pgfonlayer}%
+ %
+ \ifnum\thetikzumlCallLevel=0%
+ \begin{pgfonlayer}{activity}%
+ \draw[draw=\tikzumlCreateCallDrawColor, fill=\tikzumlCreateCallFillColor] (st-\tikzumlCreateCall@nodeName.north west) rectangle (sb-\tikzumlCreateCall@nodeName.south east);%
+ \end{pgfonlayer}%
+ \fi%
+ % add to fit fragment
+ \ifnum\c@tikzumlFragmentLevel>0%
+ \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname}%
+ \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{\tikzumlFragmentFitOld (st-\tikzumlCreateCall@nodeName) (sb-\tikzumlCreateCall@nodeName) (\tikzumlCreateCall@nodeName-op) (#3) }%
+ \fi%
+}
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% component diagrams %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+\tikzstyle{tikzuml connector style}=[color=\tikzumlDefaultDrawColor, -]%
+%
+\newcounter{tikzumlComponentLevel}%
+\newcounter{tikzumlComponentSubComponentNum}%
+\newcounter{tikzumlConnectorNum}%
+\setcounter{tikzumlConnectorNum}{1}%
+%
+\newif\iftikzumlcomponentWithoutCoords%
+%
+\newcommand{\picturedcomponent}[1]{%
+ \pgfkeys{/tikzuml/component/picture/.cd, scale/.initial=1, .unknown/.code={}}%
+ \pgfkeys{/tikzuml/component/picture/.cd,#1}%
+ \pgfkeys{/tikzuml/component/picture/.cd, scale/.get=\tikzumlComponentScale}%
+ \begin{tikzpicture}[#1]%
+ \filldraw (0,0) rectangle (1ex,1.5ex);%
+ \filldraw (-0.2ex,0.4ex) rectangle (0.2ex,0.6ex);%
+ \filldraw (-0.2ex,0.9ex) rectangle (0.2ex,1.1ex);%
+ \end{tikzpicture}%
+}%
+%
+% define a uml component
+% args : name of the component
+% content of the component
+% optional args : x,y coordinates of the component
+% width of the component node
+\newenvironment{umlcomponent}[2][]{%
+ \ifnum\thetikzumlComponentLevel>0%
+ \let\tikzumlComponent@nameold\tikzumlComponent@fitname%
+ \let\tikzumlComponent@parentold\tikzumlComponent@parent%
+ \edef\tikzumlComponent@parent{\tikzumlComponent@parentold @@\tikzumlComponent@nameold}%
+ \else%
+ \def\tikzumlComponent@parent{}%
+ \fi%
+ %
+ \stepcounter{tikzumlComponentLevel}%
+ %
+ \pgfkeys{/tikzuml/component/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlComponentDefaultWidth, name/.initial={},%
+ draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlComponentDefaultFillColor,%
+ text/.initial=\tikzumlDefaultTextColor, style/.style={},%
+ no coords/.is if=tikzumlcomponentWithoutCoords,%
+ no coords=false,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{above}\OR%
+ \equal{\keyname}{left}\OR%
+ \equal{\keyname}{below}\OR%
+ \equal{\keyname}{right}\OR%
+ \equal{\keyname}{above left}\OR%
+ \equal{\keyname}{above right}\OR%
+ \equal{\keyname}{below left}\OR%
+ \equal{\keyname}{below right}}{%
+ \IfSubStr{\keyvalue}{ of }{%
+ \pgfkeys{/tikzuml/component/.cd, no coords}%
+ }{}%
+ }{}%
+ \ifx\keyvalue\pgfkeysnovalue%
+ \pgfkeys{/tikzuml/component/.cd, style/.append style/.expand once={\keyname}}%
+ \else%
+ \pgfkeys{/tikzuml/component/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}%
+ \fi%
+ %\errmessage{TIKZUML ERROR : in umlcomponent, invalid option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/component/.cd, #1}%
+ \pgfkeys{/tikzuml/component/.cd, x/.get=\tikzumlComponentXShift, y/.get=\tikzumlComponentYShift,%
+ width/.get=\tikzumlComponentMinimumWidth, name/.get=\tikzumlComponentName,%
+ draw/.get=\tikzumlComponentDrawColor, fill/.get=\tikzumlComponentFillColor,%
+ text/.get=\tikzumlComponentTextColor%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlComponentName}{}}{%
+ \edef\tikzumlComponent@name{#2}%
+ }{%
+ \edef\tikzumlComponent@name{\tikzumlComponentName}%
+ }%
+ %
+ \begingroup%
+ \def\_{@}\edef\x{\endgroup%
+ \def\noexpand\tikzumlComponent@fitname{\tikzumlComponent@name}}\x%
+ %
+ \let\tikzumlComponent@nodeNameold\tikzumlComponent@nodeName%
+ \def\tikzumlComponent@caption{#2}%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlComponent@nodeName{\tikzumlComponent@name}}\x%
+ %
+ \expandafter\gdef\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname{}%
+ %
+ \setcounter{tikzumlComponentSubComponentNum}{0}%
+ %
+ \begin{scope}[xshift=\tikzumlComponentXShift cm, yshift=\tikzumlComponentYShift cm]%
+}{%
+ \addtocounter{tikzumlComponentLevel}{-1}%
+ \begin{pgfonlayer}{component\thetikzumlComponentLevel}%
+ %
+ % if contains nothing, one define a fictive node to enable the fit option
+ \ifnum\c@tikzumlComponentSubComponentNum=0%
+ \iftikzumlcomponentWithoutCoords%
+ \node[inner ysep=0.5ex, minimum width=\tikzumlComponentMinimumWidth, font=\tikzumlDefaultFont, /tikzuml/component/style] (\tikzumlComponent@nodeName-root) {\phantom{\tikzumlComponent@nodeName}};%
+ \else%
+ \node[inner ysep=0.5ex, minimum width=\tikzumlComponentMinimumWidth, font=\tikzumlDefaultFont, /tikzuml/component/style] (\tikzumlComponent@nodeName-root) at (0,0) {\phantom{\tikzumlComponent@nodeName}};%
+ \fi%
+ \expandafter\xdef\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname{(\tikzumlComponent@nodeName-root)}%
+ \fi%
+ %
+ \ifnum\c@tikzumlComponentLevel>0%
+ \def\tikzumlComponentFitTmp{\csname tikzumlComponentFit\tikzumlComponent@parent\endcsname}%
+ \expandafter\xdef\csname tikzumlComponentFit\tikzumlComponent@parent\endcsname{\tikzumlComponentFitTmp (\tikzumlComponent@nodeName-body) (\tikzumlComponent@nodeName-caption)}%
+ \stepcounter{tikzumlComponentSubComponentNum}%
+ \fi%
+ %
+ \node[inner sep=2ex, font=\tikzumlDefaultFont, fit = \csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname] (\tikzumlComponent@nodeName-body) {};%
+ \node[above, font=\tikzumlDefaultFont] (\tikzumlComponent@nodeName-captiontmp) at (\tikzumlComponent@nodeName-body.north) {\tikzumlComponent@caption};%
+ \node (\tikzumlComponent@nodeName-logotmp) at (\tikzumlComponent@nodeName-captiontmp.north -| \tikzumlComponent@nodeName-body.east) {\picturedcomponent{draw=\tikzumlComponentDrawColor, fill=\tikzumlComponentFillColor, font=\tikzumlDefaultFont} };%
+ \node[draw=\tikzumlComponentDrawColor, fill=\tikzumlComponentFillColor, name=\tikzumlComponent@nodeName, /tikzuml/component/style, fit=(\tikzumlComponent@nodeName-body) (\tikzumlComponent@nodeName-captiontmp)] {};%
+ \node[font=\tikzumlDefaultFont] (\tikzumlComponent@nodeName-caption) at (\tikzumlComponent@nodeName-captiontmp) {\tikzumlComponent@caption};%
+ \draw (\tikzumlComponent@nodeName-caption.north -| \tikzumlComponent@nodeName.east) node[font=\tikzumlDefaultFont, xshift=-1ex, below=-1ex, name=\tikzumlComponent@nodeName-logo] {\picturedcomponent{draw=\tikzumlComponentDrawColor, fill=\tikzumlComponentFillColor, font=\tikzumlDefaultFont} };%
+ \draw (\tikzumlComponent@nodeName-caption.south -| \tikzumlComponent@nodeName.north west) -- (\tikzumlComponent@nodeName-caption.south -| \tikzumlComponent@nodeName.north east);%
+ \coordinate (\tikzumlComponent@nodeName-west-port) at (\tikzumlComponent@nodeName.west);
+ \coordinate (\tikzumlComponent@nodeName-east-port) at (\tikzumlComponent@nodeName.east);
+ \coordinate (\tikzumlComponent@nodeName-south-port) at (\tikzumlComponent@nodeName.south);
+ \coordinate (\tikzumlComponent@nodeName-north-port) at (\tikzumlComponent@nodeName.north);
+ \end{pgfonlayer}%
+ \end{scope}%
+ %
+ % add to fit
+ \ifnum\c@tikzumlPackageLevel>0%
+ \edef\tikzumlPackageFitOld{\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{\tikzumlPackageFitOld (\tikzumlComponent@nodeName)}%
+ \stepcounter{tikzumlPackageClassNum}%
+ \fi%
+}%
+%
+% shortcut for empty component
+\newcommand{\umlbasiccomponent}[2][]{\begin{umlcomponent}[#1]{#2} \end{umlcomponent}}%
+%
+\newcommand{\umlrequiredinterface}[2][]{%
+ \def\tikzumlInterfaceWithPort{tikzumlFalse}%
+ \pgfkeys{/tikzuml/requiredinterfacerelation/.cd, interface/.initial={}, distance/.initial=\tikzumlRequiredInterfaceDefaultDistance,%
+ name/.initial=tikzumlEmpty, width/.initial=\tikzumlRequiredInterfaceDefaultWidth,%
+ padding/.initial=\tikzumlRequiredInterfaceDefaultPadding,%
+ draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlComponentDefaultFillColor,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{with port}}{%
+ \def\tikzumlInterfaceWithPort{tikzumlTrue}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/requiredinterfacerelation/.cd, #1}%
+ \pgfkeys{/tikzuml/requiredinterfacerelation/.cd, interface/.get=\tikzumlRequiredInterfaceLabel,%
+ distance/.get=\tikzumlRequiredInterfaceDistance,%
+ name/.get=\tikzumlRequiredInterfaceName,%
+ width/.get=\tikzumlRequiredInterfaceWidth,%
+ padding/.get=\tikzumlRequiredInterfacePadding,%
+ draw/.get=\tikzumlRequiredInterfaceDrawColor,%
+ fill/.get=\tikzumlRequiredInterfaceFillColor%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlRequiredInterfaceName}{tikzumlEmpty}}{%
+ \edef\tikzumlRequiredInterface@interfacename{#2-east-interface}%
+ \edef\tikzumlRequiredInterface@portname{#2-east-port}%
+ \edef\tikzumlRequiredInterface@paddingname{#2-east-padding}%
+ }{%
+ \edef\tikzumlRequiredInterface@interfacename{\tikzumlRequiredInterfaceName}%
+ \edef\tikzumlRequiredInterface@portname{\tikzumlRequiredInterfaceName-port}%
+ \edef\tikzumlRequiredInterface@paddingname{\tikzumlRequiredInterfaceName-padding}%
+ }%
+ %
+ \edef\tikzumlRequiredInterface@name{#2}%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlRequiredInterface@nodeName{\tikzumlRequiredInterface@name}}\x%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlRequiredInterface@interfacenodeName{\tikzumlRequiredInterface@interfacename}}\x%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlRequiredInterface@portnodeName{\tikzumlRequiredInterface@portname}}\x%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlRequiredInterface@paddingnodeName{\tikzumlRequiredInterface@paddingname}}\x%
+ %
+ \ifthenelse{\equal{\tikzumlInterfaceWithPort}{tikzumlTrue}}{%
+ \node[inner sep=0.5*\tikzumlRequiredInterfaceWidth, rectangle, draw=\tikzumlRequiredInterfaceDrawColor, fill=\tikzumlRequiredInterfaceFillColor] (\tikzumlRequiredInterface@portnodeName) at (\tikzumlRequiredInterface@nodeName.east) {};%
+ }{%
+ \node[inner sep=0] (\tikzumlRequiredInterface@nodeName-east-port) at (\tikzumlRequiredInterface@nodeName.east) {};%
+ }%
+ \begin{scope}%
+ \draw (\tikzumlRequiredInterface@nodeName)+(\tikzumlRequiredInterfaceDistance,0) node[inner sep=0, text width=\tikzumlRequiredInterfaceWidth, circle, name=\tikzumlRequiredInterface@interfacenodeName-tmp] {};%
+ \clip (\tikzumlRequiredInterface@interfacenodeName-tmp.north) rectangle (\tikzumlRequiredInterface@interfacenodeName-tmp.south -| \tikzumlRequiredInterface@interfacenodeName-tmp.west);%
+ \node[inner sep=0, text width=\tikzumlRequiredInterfaceWidth, circle, draw=\tikzumlRequiredInterfaceDrawColor] (\tikzumlRequiredInterface@interfacenodeName) at (\tikzumlRequiredInterface@interfacenodeName-tmp) {};%
+ \end{scope}%
+ \node[above] at (\tikzumlRequiredInterface@interfacenodeName.north) {\tikzumlRequiredInterfaceLabel};%
+ %
+ \umlrelation[style={tikzuml connector style}, #1]{\tikzumlRequiredInterface@portnodeName}{\tikzumlRequiredInterface@interfacenodeName}%
+ %
+ \draw (\tikzumlRequiredInterface@interfacenodeName)+(\tikzumlRequiredInterfacePadding,0) node[name=\tikzumlRequiredInterface@paddingnodeName] {};%
+ %
+ % add to fit
+ \ifnum\c@tikzumlComponentLevel>0%
+ \def\tikzumlComponentFitTmp{\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname{\tikzumlComponentFitTmp (\tikzumlRequiredInterface@paddingnodeName) (\tikzumlRequiredInterface@portnodeName) }%
+ \fi%
+}%
+%
+\newcommand{\umlprovidedinterface}[2][]{%
+ \def\tikzumlInterfaceWithPort{tikzumlFalse}%
+ \pgfkeys{/tikzuml/providedinterfacerelation/.cd, interface/.initial={}, distance/.initial=\tikzumlProvidedInterfaceDefaultDistance,%
+ name/.initial=tikzumlEmpty, width/.initial=\tikzumlProvidedInterfaceDefaultWidth,%
+ padding/.initial=\tikzumlProvidedInterfaceDefaultPadding,%
+ draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlComponentDefaultFillColor,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{with port}}{%
+ \def\tikzumlInterfaceWithPort{tikzumlTrue}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/providedinterfacerelation/.cd, #1}%
+ \pgfkeys{/tikzuml/providedinterfacerelation/.cd, interface/.get=\tikzumlProvidedInterfaceLabel,%
+ distance/.get=\tikzumlProvidedInterfaceDistance,%
+ name/.get=\tikzumlProvidedInterfaceName,%
+ width/.get=\tikzumlProvidedInterfaceWidth,%
+ padding/.get=\tikzumlProvidedInterfacePadding,%
+ draw/.get=\tikzumlProvidedInterfaceDrawColor,%
+ fill/.get=\tikzumlProvidedInterfaceFillColor%
+ }%
+ %
+ \ifthenelse{\equal{\tikzumlProvidedInterfaceName}{tikzumlEmpty}}{%
+ \edef\tikzumlProvidedInterface@interfacename{#2-west-interface}%
+ \edef\tikzumlProvidedInterface@portname{#2-west-port}%
+ \edef\tikzumlProvidedInterface@paddingname{#2-west-padding}%
+ }{%
+ \edef\tikzumlProvidedInterface@interfacename{\tikzumlProvidedInterfaceName}%
+ \edef\tikzumlProvidedInterface@portname{\tikzumlProvidedInterfaceName-port}%
+ \edef\tikzumlProvidedInterface@paddingname{\tikzumlProvidedInterfaceName-padding}%
+ }%
+ %
+ \edef\tikzumlProvidedInterface@name{#2}%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlProvidedInterface@nodeName{\tikzumlProvidedInterface@name}}\x%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlProvidedInterface@interfacenodeName{\tikzumlProvidedInterface@interfacename}}\x%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlProvidedInterface@portnodeName{\tikzumlProvidedInterface@portname}}\x%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlProvidedInterface@paddingnodeName{\tikzumlProvidedInterface@paddingname}}\x%
+ %
+ \ifthenelse{\equal{\tikzumlInterfaceWithPort}{tikzumlTrue}}{%
+ \node[inner sep=0.5*\tikzumlProvidedInterfaceWidth, rectangle, draw=\tikzumlProvidedInterfaceDrawColor, fill=\tikzumlProvidedInterfaceFillColor] (\tikzumlProvidedInterface@portnodeName) at (\tikzumlProvidedInterface@nodeName.west) {};%
+ }{%
+ \node[inner sep=0] (\tikzumlProvidedInterface@portnodeName) at (\tikzumlProvidedInterface@nodeName.west) {};%
+ }%
+ \draw (\tikzumlProvidedInterface@nodeName)+(-\tikzumlProvidedInterfaceDistance,0) node[inner sep=0, text width=\tikzumlProvidedInterfaceWidth, circle, draw=\tikzumlProvidedInterfaceDrawColor, fill=\tikzumlProvidedInterfaceFillColor, name=\tikzumlProvidedInterface@interfacenodeName] {};%
+ \node[above] at (\tikzumlProvidedInterface@interfacenodeName.north)
+ {\tikzumlProvidedInterfaceLabel};%
+ %
+ \umlrelation[style={tikzuml connector style}, #1]{\tikzumlProvidedInterface@portnodeName}{\tikzumlProvidedInterface@interfacenodeName}%
+ %
+ \draw (\tikzumlProvidedInterface@interfacenodeName)+(-\tikzumlProvidedInterfacePadding,0) node[name=\tikzumlProvidedInterface@paddingnodeName] {};%
+ %
+ % add to fit
+ \ifnum\thetikzumlComponentLevel>0%
+ \def\tikzumlComponentFitTmp{\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname}%
+ \expandafter\xdef\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname{\tikzumlComponentFitTmp (\tikzumlProvidedInterface@paddingnodeName) (\tikzumlProvidedInterface@portnodeName) }%
+ \fi%
+}%
+%
+\newlength{\tikzuml@AC@xa}%
+\newlength{\tikzuml@AC@ya}%
+\newlength{\tikzuml@AC@xb}%
+\newlength{\tikzuml@AC@yb}%
+\newlength{\tikzuml@AC@xi}%
+\newlength{\tikzuml@AC@yi}%
+\newlength{\tikzuml@AC@xic}%
+\newlength{\tikzuml@AC@yic}%
+\newlength{\tikzuml@AC@xio}%
+\newlength{\tikzuml@AC@yio}%
+\newlength{\tikzuml@AC@AB}%
+\newlength{\tikzuml@AC@lambda}%
+\newlength{\tikzuml@AC@xtrc}%
+\newlength{\tikzuml@AC@ytrc}%
+\newlength{\tikzuml@AC@xtlc}%
+\newlength{\tikzuml@AC@ytlc}%
+\newlength{\tikzuml@AC@xblc}%
+\newlength{\tikzuml@AC@yblc}%
+\newlength{\tikzuml@AC@xbrc}%
+\newlength{\tikzuml@AC@ybrc}%
+\newlength{\tikzuml@AC@middleArm}%
+%
+\newcommand{\umlassemblyconnectorsymbol}[2]{%
+ \ifthenelse{\NOT\equal{\tikzumlAssemblyConnectorLabel}{}}{%
+ \edef\tikzuml@ACStart@name{#1}%
+ \edef\tikzuml@ACEnd@name{#2}%
+ \edef\tikzuml@AC@width{\tikzumlAssemblyConnectorWidth}%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzuml@ACStart@nodeName{\tikzuml@ACStart@name}}\x%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzuml@ACEnd@nodeName{\tikzuml@ACEnd@name}}\x%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzuml@ACInterface@nodeName{\tikzumlAssemblyConnectorSymbolName}}\x%
+ %
+ \pgfextractx{\tikzuml@AC@xa}{\pgfpointanchor{\tikzuml@ACStart@nodeName}{\tikzumlAssemblyConnectorStartAnchor}}%
+ \pgfextracty{\tikzuml@AC@ya}{\pgfpointanchor{\tikzuml@ACStart@nodeName}{\tikzumlAssemblyConnectorStartAnchor}}%
+ \pgfextractx{\tikzuml@AC@xb}{\pgfpointanchor{\tikzuml@ACEnd@nodeName}{\tikzumlAssemblyConnectorEndAnchor}}%
+ \pgfextracty{\tikzuml@AC@yb}{\pgfpointanchor{\tikzuml@ACEnd@nodeName}{\tikzumlAssemblyConnectorEndAnchor}}%
+ \pgfmathsetlength{\tikzuml@AC@xi}{0.5*\tikzuml@AC@xa+0.5*\tikzuml@AC@xb}%
+ \pgfmathsetlength{\tikzuml@AC@yi}{0.5*\tikzuml@AC@ya+0.5*\tikzuml@AC@yb}%
+ \pgfmathsetlength{\tikzuml@AC@AB}{veclen(\tikzuml@AC@xa-\tikzuml@AC@xb,\tikzuml@AC@ya-\tikzuml@AC@yb)}%
+ \pgfmathsetlength{\tikzuml@AC@lambda}{0.25*\tikzuml@AC@width/\tikzuml@AC@AB}%
+ \pgfmathsetlength{\tikzuml@AC@xic}{\tikzuml@AC@xi-\tikzuml@AC@lambda*(\tikzuml@AC@xb-\tikzuml@AC@xa)}%
+ \pgfmathsetlength{\tikzuml@AC@yic}{\tikzuml@AC@yi-\tikzuml@AC@lambda*(\tikzuml@AC@yb-\tikzuml@AC@ya)}%
+ \pgfmathsetlength{\tikzuml@AC@xio}{\tikzuml@AC@xi+\tikzuml@AC@lambda*(\tikzuml@AC@xb-\tikzuml@AC@xa)}%
+ \pgfmathsetlength{\tikzuml@AC@yio}{\tikzuml@AC@yi+\tikzuml@AC@lambda*(\tikzuml@AC@yb-\tikzuml@AC@ya)}%
+ \node[inner sep=0.5*\tikzuml@AC@width] (\tikzuml@ACInterface@nodeName-interface) at (\tikzuml@AC@xi,\tikzuml@AC@yi) {};%
+ \node[inner sep=0, text width=\tikzuml@AC@width, circle, draw=\tikzumlAssemblyConnectorDrawColor, fill=\tikzumlAssemblyConnectorFillColor] (\tikzuml@ACInterface@nodeName-io) at (\tikzuml@AC@xio,\tikzuml@AC@yio) {};%
+ \begin{scope}%
+ \pgfmathsetlength{\tikzuml@AC@xtrc}{\tikzuml@AC@xic-2*\tikzuml@AC@lambda*(\tikzuml@AC@yb-\tikzuml@AC@ya)}%
+ \pgfmathsetlength{\tikzuml@AC@ytrc}{\tikzuml@AC@yic+2*\tikzuml@AC@lambda*(\tikzuml@AC@xb-\tikzuml@AC@xa)}%
+ \pgfmathsetlength{\tikzuml@AC@xbrc}{\tikzuml@AC@xic+2*\tikzuml@AC@lambda*(\tikzuml@AC@yb-\tikzuml@AC@ya)}%
+ \pgfmathsetlength{\tikzuml@AC@ybrc}{\tikzuml@AC@yic-2*\tikzuml@AC@lambda*(\tikzuml@AC@xb-\tikzuml@AC@xa)}%
+ \pgfmathsetlength{\tikzuml@AC@xtlc}{\tikzuml@AC@xic-3*\tikzuml@AC@lambda*(\tikzuml@AC@yb-\tikzuml@AC@ya+\tikzuml@AC@xb-\tikzuml@AC@xa)}%
+ \pgfmathsetlength{\tikzuml@AC@ytlc}{\tikzuml@AC@yic+3*\tikzuml@AC@lambda*(\tikzuml@AC@xb-\tikzuml@AC@xa+\tikzuml@AC@ya-\tikzuml@AC@yb)}%
+ \pgfmathsetlength{\tikzuml@AC@xblc}{\tikzuml@AC@xic+3*\tikzuml@AC@lambda*(\tikzuml@AC@yb-\tikzuml@AC@ya+\tikzuml@AC@xa-\tikzuml@AC@xb)}%
+ \pgfmathsetlength{\tikzuml@AC@yblc}{\tikzuml@AC@yic-3*\tikzuml@AC@lambda*(\tikzuml@AC@xb-\tikzuml@AC@xa+\tikzuml@AC@yb-\tikzuml@AC@ya)}%
+ \coordinate (\tikzuml@ACInterface@nodeName-trc) at (\tikzuml@AC@xtrc,\tikzuml@AC@ytrc);%
+ \coordinate (\tikzuml@ACInterface@nodeName-brc) at (\tikzuml@AC@xbrc,\tikzuml@AC@ybrc);%
+ \coordinate (\tikzuml@ACInterface@nodeName-tlc) at (\tikzuml@AC@xtlc,\tikzuml@AC@ytlc);%
+ \coordinate (\tikzuml@ACInterface@nodeName-blc) at (\tikzuml@AC@xblc,\tikzuml@AC@yblc);%
+ \clip (\tikzuml@ACInterface@nodeName-trc) -- (\tikzuml@ACInterface@nodeName-tlc) -- (\tikzuml@ACInterface@nodeName-blc) -- (\tikzuml@ACInterface@nodeName-brc) -- cycle;%
+ \node[inner sep=0, text width=\tikzuml@AC@width, circle, draw=\tikzumlAssemblyConnectorDrawColor, fill=\tikzumlAssemblyConnectorFillColor] (\tikzuml@ACInterface@nodeName-ic) at (\tikzuml@AC@xic,\tikzuml@AC@yic) {};%
+ \end{scope}%
+ \node[above, font=\tikzumlDefaultFont] at (\tikzuml@ACInterface@nodeName-interface.north)
+ {\tikzumlAssemblyConnectorLabel};%
+ }{}%
+}%
+%
+\newcommand{\umlassemblyconnector}[3][]{%
+ \def\tikzumlAssemblyConnectorWithPort{tikzumlFalse}%
+ \def\tikzumlAssemblyConnectorFirstArm{tikzumlFalse}%
+ \def\tikzumlAssemblyConnectorSecondArm{tikzumlFalse}%
+ \def\tikzumlAssemblyConnectorMiddleArm{tikzumlFalse}%
+ \def\tikzumlAssemblyConnectorLastArm{tikzumlFalse}%
+ \pgfkeys{/tikzuml/assemblyconnectorrelation/.cd, geometry/.initial=--, interface/.initial={},%
+ arm1/.initial={auto}, arm2/.initial={auto},%
+ name/.initial=connector-\thetikzumlConnectorNum, width/.initial=1em,%
+ anchor1/.initial={}, anchor2/.initial={},%
+ draw/.initial=\tikzumlDefaultDrawColor,%
+ fill assembly connector/.initial=\tikzumlAssemblyConnectorDefaultFillColor,%
+ fill port/.initial=\tikzumlPortDefaultFillColor,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{with port}}{%
+ \def\tikzumlAssemblyConnectorWithPort{tikzumlTrue}%
+ }{%
+ \ifthenelse{\equal{\keyname}{first arm}}{%
+ \def\tikzumlAssemblyConnectorFirstArm{tikzumlTrue}%
+ }{%
+ \ifthenelse{\equal{\keyname}{second arm}}{%
+ \def\tikzumlAssemblyConnectorSecondArm{tikzumlTrue}%
+ }{%
+ \ifthenelse{\equal{\keyname}{middle arm}}{%
+ \def\tikzumlAssemblyConnectorMiddleArm{tikzumlTrue}%
+ }{%
+ \ifthenelse{\equal{\keyname}{last arm}}{%
+ \def\tikzumlAssemblyConnectorLastArm{tikzumlTrue}%
+ }{%
+ }%
+ }%
+ }%
+ }%
+ }%
+ }%
+ }%
+ \pgfkeys{/tikzuml/assemblyconnectorrelation/.cd, #1}%
+ \pgfkeys{/tikzuml/assemblyconnectorrelation/.cd, geometry/.get=\tikzumlAssemblyConnectorGeometry,%
+ name/.get=\tikzumlAssemblyConnectorName,%
+ interface/.get=\tikzumlAssemblyConnectorLabel,%
+ width/.get=\tikzumlAssemblyConnectorWidth,%
+ arm1/.get=\tikzumlAssemblyConnectorStartArm,%
+ arm2/.get=\tikzumlAssemblyConnectorEndArm,%
+ anchor1/.get=\tikzumlAssemblyConnectorStartAnchorTmp,%
+ anchor2/.get=\tikzumlAssemblyConnectorEndAnchorTmp,%
+ draw/.get=\tikzumlAssemblyConnectorDrawColor,%
+ fill assembly connector/.get=\tikzumlAssemblyConnectorFillColor,%
+ fill port/.get=\tikzumlAssemblyConnectorPortFillColor%
+ }%
+ %
+ \edef\tikzumlAssemblyConnectorStart@name{#2}%
+ \edef\tikzumlAssemblyConnectorEnd@name{#3}%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlAssemblyConnectorStart@nodeName{\tikzumlAssemblyConnectorStart@name}}\x%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlAssemblyConnectorEnd@nodeName{\tikzumlAssemblyConnectorEnd@name}}\x%
+ %
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlAssemblyConnectorLabel@nodeName{\tikzumlAssemblyConnectorLabel}}\x%
+ %
+ \pgfextractx{\tikzuml@AC@xa}{\pgfpointanchor{\tikzumlAssemblyConnectorStart@nodeName}{center}}%
+ \pgfextracty{\tikzuml@AC@ya}{\pgfpointanchor{\tikzumlAssemblyConnectorStart@nodeName}{center}}%
+ \pgfextractx{\tikzuml@AC@xb}{\pgfpointanchor{\tikzumlAssemblyConnectorEnd@nodeName}{center}}%
+ \pgfextracty{\tikzuml@AC@yb}{\pgfpointanchor{\tikzumlAssemblyConnectorEnd@nodeName}{center}}%
+ %
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{--}}{%
+ \ifthenelse{\tikzuml@AC@xb>\tikzuml@AC@xa}{%
+ \def\tikzumlAssemblyConnectorStartAnchor{east}%
+ \def\tikzumlAssemblyConnectorEndAnchor{west}%
+ }{%
+ \def\tikzumlAssemblyConnectorStartAnchor{west}%
+ \def\tikzumlAssemblyConnectorEndAnchor{east}%
+ }
+ }{}%
+ %
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{-|}}{%
+ \ifthenelse{\tikzuml@AC@xb>\tikzuml@AC@xa}{%
+ \def\tikzumlAssemblyConnectorStartAnchor{east}%
+ }{%
+ \def\tikzumlAssemblyConnectorStartAnchor{west}%
+ }
+ \ifthenelse{\tikzuml@AC@yb>\tikzuml@AC@ya}{%
+ \def\tikzumlAssemblyConnectorEndAnchor{south}%
+ }{%
+ \def\tikzumlAssemblyConnectorEndAnchor{north}%
+ }
+ }{}%
+ %
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{|-}}{%
+ \ifthenelse{\tikzuml@AC@xb>\tikzuml@AC@xa}{%
+ \def\tikzumlAssemblyConnectorEndAnchor{west}%
+ }{%
+ \def\tikzumlAssemblyConnectorEndAnchor{east}%
+ }
+ \ifthenelse{\tikzuml@AC@yb>\tikzuml@AC@ya}{%
+ \def\tikzumlAssemblyConnectorStartAnchor{north}%
+ }{%
+ \def\tikzumlAssemblyConnectorStartAnchor{south}%
+ }
+ }{}%
+ %
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{-|-}}{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorStartArm}{auto}}{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorEndArm}{auto}}{%
+ \pgfmathsetlength{\tikzuml@AC@middleArm}{0.5 * \tikzuml@AC@xa + 0.5 * \tikzuml@AC@xb}%
+ }{%
+ \pgfmathsetlength{\tikzuml@AC@middleArm}{\tikzuml@AC@xb+\tikzumlAssemblyConnectorEndArm}%
+ }%
+ }{%
+ \pgfmathsetlength{\tikzuml@AC@middleArm}{\tikzuml@AC@xa+\tikzumlAssemblyConnectorStartArm}%
+ }%
+ \pgfmathparse{\tikzuml@AC@middleArm>\tikzuml@AC@xa}
+ \pgfmathparse{\tikzuml@AC@middleArm>\tikzuml@AC@xb}
+ \ifthenelse{\lengthtest{\tikzuml@AC@middleArm>\tikzuml@AC@xa}}{%
+ \def\tikzumlAssemblyConnectorStartAnchor{east}%
+ }{%
+ \def\tikzumlAssemblyConnectorStartAnchor{west}%
+ }
+ \ifthenelse{\lengthtest{\tikzuml@AC@middleArm>\tikzuml@AC@xb}}{%
+ \def\tikzumlAssemblyConnectorEndAnchor{east}%
+ }{%
+ \def\tikzumlAssemblyConnectorEndAnchor{west}%
+ }
+ }{}%
+ %
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{|-|}}{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorStartArm}{auto}}{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorEndArm}{auto}}{%
+ \pgfmathsetlength{\tikzuml@AC@middleArm}{0.5 * \tikzuml@AC@ya + 0.5 * \tikzuml@AC@yb}%
+ }{%
+ \pgfmathsetlength{\tikzuml@AC@middleArm}{\tikzuml@AC@yb+\tikzumlAssemblyConnectorEndArm}%
+ }%
+ }{%
+ \pgfmathsetlength{\tikzuml@AC@middleArm}{\tikzuml@AC@ya+\tikzumlAssemblyConnectorStartArm}%
+ }%
+ \ifthenelse{\tikzuml@AC@middleArm>\tikzuml@AC@ya}{%
+ \def\tikzumlAssemblyConnectorStartAnchor{north}%
+ }{%
+ \def\tikzumlAssemblyConnectorStartAnchor{south}%
+ }
+ \ifthenelse{\tikzuml@AC@middleArm>\tikzuml@AC@yb}{%
+ \def\tikzumlAssemblyConnectorEndAnchor{north}%
+ }{%
+ \def\tikzumlAssemblyConnectorEndAnchor{south}%
+ }
+ }{}%
+ %
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorStartAnchorTmp}{}}{%
+ }{%
+ \def\tikzumlAssemblyConnectorStartAnchor{\tikzumlAssemblyConnectorStartAnchorTmp}%
+ }%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorEndAnchorTmp}{}}{%
+ }{%
+ \def\tikzumlAssemblyConnectorEndAnchor{\tikzumlAssemblyConnectorEndAnchorTmp}%
+ }%
+ %
+ \node[inner sep=0] (\tikzumlAssemblyConnectorStart@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port-tmp) at (\tikzumlAssemblyConnectorStart@nodeName.\tikzumlAssemblyConnectorStartAnchor) {};%
+ \node[inner sep=0] (\tikzumlAssemblyConnectorEnd@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port-tmp) at (\tikzumlAssemblyConnectorEnd@nodeName.\tikzumlAssemblyConnectorEndAnchor) {};%
+ %
+ \umlrelation[style={tikzuml connector style}, #1]{\tikzumlAssemblyConnectorStart@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port-tmp}{\tikzumlAssemblyConnectorEnd@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port-tmp}%
+ %
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorWithPort}{tikzumlTrue}}{%
+ \node[inner sep=0.5*\tikzumlAssemblyConnectorWidth, rectangle, draw=\tikzumlAssemblyConnectorDrawColor, fill=\tikzumlAssemblyConnectorPortFillColor] (\tikzumlAssemblyConnectorStart@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port) at (\tikzumlAssemblyConnectorStart@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port-tmp) {};%
+ \node[inner sep=0.5*\tikzumlAssemblyConnectorWidth, rectangle, draw=\tikzumlAssemblyConnectorDrawColor, fill=\tikzumlAssemblyConnectorPortFillColor] (\tikzumlAssemblyConnectorEnd@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port) at (\tikzumlAssemblyConnectorEnd@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port-tmp) {};%
+ }{%
+ \node[inner sep=0] (\tikzumlAssemblyConnectorStart@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port) at (\tikzumlAssemblyConnectorStart@nodeName.\tikzumlAssemblyConnectorStartAnchor) {};%
+ \node[inner sep=0] (\tikzumlAssemblyConnectorEnd@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port) at (\tikzumlAssemblyConnectorEnd@nodeName.\tikzumlAssemblyConnectorEndAnchor) {};%
+ }%
+ %
+ \addtocounter{tikzumlRelationNum}{-1}%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorName}{connector-\thetikzumlConnectorNum}}{%
+ \edef\tikzumlAssemblyConnectorName{relation-\thetikzumlRelationNum}%
+ \edef\tikzumlAssemblyConnectorSymbolName{\tikzumlAssemblyConnectorLabel@nodeName}%
+ }{%
+ \edef\tikzumlAssemblyConnectorSymbolName{\tikzumlAssemblyConnectorName}%
+ }%
+ %
+ \stepcounter{tikzumlRelationNum}%
+ %
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{--}}{%
+ \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorStart@nodeName}{\tikzumlAssemblyConnectorEnd@nodeName}%
+ }{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{-|}}{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorFirstArm}{tikzumlTrue}}{%
+ \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorStart@nodeName}{\tikzumlAssemblyConnectorName-2}%
+ }{%
+ \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorName-2}{\tikzumlAssemblyConnectorEnd@nodeName}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{|-}}{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorFirstArm}{tikzumlTrue}}{%
+ \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorStart@nodeName}{\tikzumlAssemblyConnectorName-2}%
+ }{%
+ \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorName-2}{\tikzumlAssemblyConnectorEnd@nodeName}%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{-|-}}{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorFirstArm}{tikzumlTrue}}{%
+ \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorStart@nodeName}{\tikzumlAssemblyConnectorName-2}%
+ }{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorLastArm}{tikzumlTrue}}{%
+ \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorName-4}{\tikzumlAssemblyConnectorEnd@nodeName}%
+ }{%
+ \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorName-2}{\tikzumlAssemblyConnectorName-4}%
+ }%
+ }%
+ }{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{|-|}}{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorFirstArm}{tikzumlTrue}}{%
+ \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorStart@nodeName}{\tikzumlAssemblyConnectorName-2}%
+ }{%
+ \ifthenelse{\equal{\tikzumlAssemblyConnectorLastArm}{tikzumlTrue}}{%
+ \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorName-4}{\tikzumlAssemblyConnectorEnd@nodeName}%
+ }{%
+ \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorName-2}{\tikzumlAssemblyConnectorName-4}%
+ }%
+ }%
+ }{}%
+ }%
+ }%
+ }%
+ }%
+ \stepcounter{tikzumlConnectorNum}%
+}%
+%
+% shortcuts of \umlassemblyconnector
+\newcommand{\umlHVassemblyconnector}[3][]{%
+ \pgfkeys{/tikzuml/HVassemblyconnector/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlHVassemblyconnector, forbidden option geometry}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/HVassemblyconnector/.cd, #1}%
+ \umlassemblyconnector[geometry=-|, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlVHassemblyconnector}[3][]{%
+ \pgfkeys{/tikzuml/VHassemblyconnector/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlVHassemblyconnector, forbidden option geometry}%
+ }{}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/VHassemblyconnector/.cd, #1}%
+ \umlassemblyconnector[geometry=|-, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlHVHassemblyconnector}[3][]{%
+ \pgfkeys{/tikzuml/HVHassemblyconnector/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlHVHassemblyconnector, forbidden option geometry}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/HVHassemblyconnector/.cd, #1}%
+ \umlassemblyconnector[geometry=-|-, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlVHVassemblyconnector}[3][]{%
+ \pgfkeys{/tikzuml/VHVassemblyconnector/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}}{%
+ \errmessage{TIKZUML ERROR : in umlVHVassemblyconnector, forbidden option geometry}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/VHVassemblyconnector/.cd, #1}%
+ \umlassemblyconnector[geometry=|-|, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlport}[3][]{%
+ \pgfkeys{/tikzuml/port/.cd, draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlPortDefaultFillColor,%
+ width/.initial=\tikzumlPortDefaultWidth,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \errmessage{TIKZUML ERROR : in umlport forbidden option \keyname}%
+ }%
+ }%
+ \pgfkeys{/tikzuml/port/.cd, #1}%
+ \pgfkeys{/tikzuml/port/.cd, width/.get=\tikzumlPortWidth,%
+ draw/.get=\tikzumlPortDrawColor, fill/.get=\tikzumlPortFillColor}%
+ \edef\tikzumlPort@name{#2}%
+ \edef\tikzumlPort@anchor{#3}%
+ \begingroup%
+ \def\_{_}\edef\x{\endgroup%
+ \def\noexpand\tikzumlPort@nodeName{\tikzumlPort@name}}\x%
+ %
+ \node[inner sep=0.5*\tikzumlPortWidth, rectangle, draw=\tikzumlPortDrawColor, fill=\tikzumlPortFillColor] (\tikzumlPort@nodeName-\tikzumlPort@anchor-port) at (\tikzumlPort@nodeName.\tikzumlPort@anchor) {};%
+}%
+%
+\newcommand{\umldelegateconnector}[3][]{%
+ \def\tikzumlDelegateConnectorWithStartPort{tikzumlFalse}%
+ \def\tikzumlDelegateConnectorWithEndPort{tikzumlFalse}%
+ \pgfkeys{/tikzuml/delegateconnector/.cd,
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umldelegateconnector, forbidden option stereo}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/delegateconnector/.cd, #1}%
+ \umlrelation[style={tikzuml connector style}, stereo=delegate, #1]{#2}{#3}%
+}%
+%
+% shortcuts of \umldelegateconnector
+\newcommand{\umlHVdelegateconnector}[3][]{%
+ \pgfkeys{/tikzuml/HVdelegateconnector/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}\OR\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlHVdelegateconnector, forbidden option \keyname}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/HVdelegateconnector/.cd, #1}%
+ \umldelegateconnector[geometry=-|, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlVHdelegateconnector}[3][]{%
+ \pgfkeys{/tikzuml/VHdelegateconnector/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}\OR\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlVHdelegateconnector, forbidden option \keyname}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/VHdelegateconnector/.cd, #1}%
+ \umldelegateconnector[geometry=|-, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlHVHdelegateconnector}[3][]{%
+ \pgfkeys{/tikzuml/HVHdelegateconnector/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}\OR\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlHVHdelegateconnector, forbidden option \keyname}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/HVHdelegateconnector/.cd, #1}%
+ \umldelegateconnector[geometry=-|-, #1]{#2}{#3}%
+}%
+%
+\newcommand{\umlVHVdelegateconnector}[3][]{%
+ \pgfkeys{/tikzuml/VHVdelegateconnector/.cd,%
+ .unknown/.code={%
+ \let\keyname=\pgfkeyscurrentname%
+ \let\keyvalue=\pgfkeyscurrentvalue%
+ \ifthenelse{\equal{\keyname}{geometry}\OR\equal{\keyname}{stereo}}{%
+ \errmessage{TIKZUML ERROR : in umlVHVdelegateconnector, forbidden option \keyname}%
+ }{}%
+ }}%
+ \pgfkeys{/tikzuml/VHVdelegateconnector/.cd, #1}%
+ \umldelegateconnector[geometry=|-|, #1]{#2}{#3}%
+}%
+%%% End of tikz-uml.sty
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \ No newline at end of file
diff --git a/40-abschlusspraesentation/.gitignore b/40-abschlusspraesentation/.gitignore
new file mode 100644
index 0000000..a05e736
--- /dev/null
+++ b/40-abschlusspraesentation/.gitignore
@@ -0,0 +1,26 @@
+public/
+
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+node_modules
+dist
+dist-ssr
+*.local
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+.DS_Store
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
diff --git a/40-abschlusspraesentation/.gitlab-ci.yml b/40-abschlusspraesentation/.gitlab-ci.yml
new file mode 100644
index 0000000..8bc83f2
--- /dev/null
+++ b/40-abschlusspraesentation/.gitlab-ci.yml
@@ -0,0 +1,25 @@
+plantuml:
+ stage: .pre
+ image:
+ name: plantuml/plantuml
+ entrypoint: [""]
+ script:
+ - java -jar plantuml.jar -tsvg assets/diagrams/*.puml
+ artifacts:
+ paths:
+ - assets/diagrams
+
+pages:
+ image:
+ name: webpronl/reveal-md:latest
+ entrypoint: [""]
+ script:
+ - node /app/bin/reveal-md.js presentation.md --static public --static-dirs assets
+ artifacts:
+ paths:
+ - public
+ rules:
+ - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
+ dependencies:
+ - plantuml
+
diff --git a/40-abschlusspraesentation/LICENSE b/40-abschlusspraesentation/LICENSE
new file mode 100644
index 0000000..f288702
--- /dev/null
+++ b/40-abschlusspraesentation/LICENSE
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ <program> Copyright (C) <year> <name of author>
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<https://www.gnu.org/licenses/>.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+<https://www.gnu.org/licenses/why-not-lgpl.html>.
diff --git a/40-abschlusspraesentation/Makefile b/40-abschlusspraesentation/Makefile
new file mode 100644
index 0000000..49433c4
--- /dev/null
+++ b/40-abschlusspraesentation/Makefile
@@ -0,0 +1,10 @@
+all:
+ clean-diagram diagram revealjs
+dev:
+ npm run dev
+revealjs:
+ npm run build
+diagram:
+ java -jar plantuml.jar -tsvg assets/diagrams/*.puml
+clean-diagram:
+ find assets/diagrams -type f -not -name '*.puml' -delete
diff --git a/40-abschlusspraesentation/README.md b/40-abschlusspraesentation/README.md
new file mode 100644
index 0000000..4a13bf6
--- /dev/null
+++ b/40-abschlusspraesentation/README.md
@@ -0,0 +1,26 @@
+# Abschlusspräsentation
+
+## Getting started
+
+Reveal-md installieren
+```sh
+npm install -g reveal-md
+```
+
+Präsentation starten
+```sh
+reveal-md presentation.md -w
+```
+
+## Resourcen
+
+### Reveal.js
+
+- https://github.com/webpro/reveal-md
+- https://revealjs.com/
+
+### Markdown
+
+- https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet
+- https://docs.gitlab.com/ee/user/markdown.html
+
diff --git a/40-abschlusspraesentation/assets/.gitignore b/40-abschlusspraesentation/assets/.gitignore
new file mode 100644
index 0000000..16252a4
--- /dev/null
+++ b/40-abschlusspraesentation/assets/.gitignore
@@ -0,0 +1,3 @@
+diagrams/*
+!diagrams/*.puml
+
diff --git a/40-abschlusspraesentation/assets/LastUpdateComp.png b/40-abschlusspraesentation/assets/LastUpdateComp.png
new file mode 100644
index 0000000..3fae93e
--- /dev/null
+++ b/40-abschlusspraesentation/assets/LastUpdateComp.png
Binary files differ
diff --git a/40-abschlusspraesentation/assets/balken-old.svg b/40-abschlusspraesentation/assets/balken-old.svg
new file mode 100644
index 0000000..0021e88
--- /dev/null
+++ b/40-abschlusspraesentation/assets/balken-old.svg
@@ -0,0 +1,301 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ version="1.0"
+ width="122.881mm"
+ height="76.505615mm"
+ id="svg134"
+ sodipodi:docname="BalkenOld.EMF"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg">
+ <sodipodi:namedview
+ id="namedview136"
+ pagecolor="#ffffff"
+ bordercolor="#000000"
+ borderopacity="0.25"
+ inkscape:showpageshadow="2"
+ inkscape:pageopacity="0.0"
+ inkscape:pagecheckerboard="0"
+ inkscape:deskcolor="#d1d1d1"
+ inkscape:document-units="mm"
+ showgrid="false" />
+ <defs
+ id="defs10" />
+ <path
+ style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none"
+ d="M 1.3125e-5,3.0957031e-6 V 289.15509 H 464.43211 V 3.0957031e-6 Z"
+ id="path14" />
+ <path
+ style="fill:none;stroke:#002060;stroke-width:0.999983px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 44.119263,232.07606 H 449.79236 M 44.119263,205.9965 H 449.79236 M 44.119263,179.91694 H 449.79236 M 44.119263,153.83739 H 449.79236 M 44.119263,127.75783 H 449.79236 M 44.119263,101.67828 H 449.79236 M 44.119263,75.598723 H 449.79236 M 44.119263,49.439163 H 449.79236"
+ id="path16" />
+ <path
+ style="fill:#ffc000;fill-opacity:1;fill-rule:evenodd;stroke:none"
+ d="M 225.75617,80.318643 V 258.23561 h 42.35928 V 80.318643 Z"
+ id="path18" />
+ <path
+ style="fill:#ff0000;fill-opacity:1;fill-rule:evenodd;stroke:none"
+ d="m 360.95387,256.03565 v 2.19996 h 42.39928 v -2.19996 z"
+ id="path20" />
+ <path
+ style="fill:#00b050;fill-opacity:1;fill-rule:evenodd;stroke:none"
+ d="m 90.438483,229.5161 v 28.69951 H 132.83775 V 229.5161 Z"
+ id="path22" />
+ <path
+ style="fill:none;stroke:#d9d9d9;stroke-width:0.999983px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 44.119263,258.23561 H 449.79236"
+ id="path24" />
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;line-height:125%;font-family:Calibri;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
+ x="26.957245"
+ y="261.65784"
+ id="text30"><tspan
+ sodipodi:role="line"
+ x="26.957245"
+ y="261.65784"
+ id="tspan28"><tspan
+ dx="0"
+ dy="0"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;font-family:Calibri;fill:#002060"
+ id="tspan26">0</tspan></tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;line-height:125%;font-family:Calibri;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
+ x="8.7175598"
+ y="235.56168"
+ id="text36"><tspan
+ sodipodi:role="line"
+ x="8.7175598"
+ y="235.56168"
+ id="tspan34"><tspan
+ dx="0"
+ dy="0"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;font-family:Calibri;fill:#002060"
+ id="tspan32">1000</tspan></tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;line-height:125%;font-family:Calibri;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
+ x="8.7175598"
+ y="209.46564"
+ id="text42"><tspan
+ sodipodi:role="line"
+ x="8.7175598"
+ y="209.46564"
+ id="tspan40"><tspan
+ dx="0"
+ dy="0"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;font-family:Calibri;fill:#002060"
+ id="tspan38">2000</tspan></tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;line-height:125%;font-family:Calibri;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
+ x="8.7175598"
+ y="183.36951"
+ id="text48"><tspan
+ sodipodi:role="line"
+ x="8.7175598"
+ y="183.36951"
+ id="tspan46"><tspan
+ dx="0"
+ dy="0"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;font-family:Calibri;fill:#002060"
+ id="tspan44">3000</tspan></tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;line-height:125%;font-family:Calibri;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
+ x="8.7175598"
+ y="157.27347"
+ id="text54"><tspan
+ sodipodi:role="line"
+ x="8.7175598"
+ y="157.27347"
+ id="tspan52"><tspan
+ dx="0"
+ dy="0"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;font-family:Calibri;fill:#002060"
+ id="tspan50">4000</tspan></tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;line-height:125%;font-family:Calibri;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
+ x="8.7175598"
+ y="131.17731"
+ id="text60"><tspan
+ sodipodi:role="line"
+ x="8.7175598"
+ y="131.17731"
+ id="tspan58"><tspan
+ dx="0"
+ dy="0"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;font-family:Calibri;fill:#002060"
+ id="tspan56">5000</tspan></tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;line-height:125%;font-family:Calibri;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
+ x="8.7175598"
+ y="105.08127"
+ id="text66"><tspan
+ sodipodi:role="line"
+ x="8.7175598"
+ y="105.08127"
+ id="tspan64"><tspan
+ dx="0"
+ dy="0"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;font-family:Calibri;fill:#002060"
+ id="tspan62">6000</tspan></tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;line-height:125%;font-family:Calibri;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
+ x="8.7175598"
+ y="78.985138"
+ id="text72"><tspan
+ sodipodi:role="line"
+ x="8.7175598"
+ y="78.985138"
+ id="tspan70"><tspan
+ dx="0"
+ dy="0"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;font-family:Calibri;fill:#002060"
+ id="tspan68">7000</tspan></tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;line-height:125%;font-family:Calibri;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
+ x="8.7175598"
+ y="52.889099"
+ id="text78"><tspan
+ sodipodi:role="line"
+ x="8.7175598"
+ y="52.889099"
+ id="tspan76"><tspan
+ dx="0"
+ dy="0"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;font-family:Calibri;fill:#002060"
+ id="tspan74">8000</tspan></tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;line-height:125%;font-family:Calibri;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
+ x="88.19043"
+ y="277.26016"
+ id="text84"><tspan
+ sodipodi:role="line"
+ x="88.19043"
+ y="277.26016"
+ id="tspan82"><tspan
+ dx="0"
+ dy="0"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;font-family:Calibri;fill:#002060"
+ id="tspan80">&lt;= 500ms</tspan></tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;line-height:125%;font-family:Calibri;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
+ x="187.87622"
+ y="277.26016"
+ id="text90"><tspan
+ sodipodi:role="line"
+ x="187.87622"
+ y="277.26016"
+ id="tspan88"><tspan
+ dx="0"
+ dy="0"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;font-family:Calibri;fill:#002060"
+ id="tspan86">&gt; 500ms and &lt;= 1500ms</tspan></tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;line-height:125%;font-family:Calibri;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
+ x="358.58069"
+ y="277.26016"
+ id="text96"><tspan
+ sodipodi:role="line"
+ x="358.58069"
+ y="277.26016"
+ id="tspan94"><tspan
+ dx="0"
+ dy="0"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;font-family:Calibri;fill:#002060"
+ id="tspan92">&gt; 1500ms</tspan></tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:700;font-size:18.75px;line-height:125%;font-family:Calibri;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
+ x="151.13727"
+ y="27.821213"
+ id="text102"><tspan
+ sodipodi:role="line"
+ x="151.13727"
+ y="27.821213"
+ id="tspan100"><tspan
+ dx="0"
+ dy="0"
+ style="font-style:normal;font-variant:normal;font-weight:700;font-size:18.75px;font-family:Calibri;fill:#002060"
+ id="tspan98">Dual</tspan></tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:700;font-size:18.75px;line-height:125%;font-family:Calibri;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
+ x="186.97668"
+ y="27.821213"
+ id="text108"><tspan
+ sodipodi:role="line"
+ x="186.97668"
+ y="27.821213"
+ id="tspan106"><tspan
+ dx="0"
+ dy="0"
+ style="font-style:normal;font-variant:normal;font-weight:700;font-size:18.75px;font-family:Calibri;fill:#002060"
+ id="tspan104">-</tspan></tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:700;font-size:18.75px;line-height:125%;font-family:Calibri;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
+ x="192.73657"
+ y="27.821213"
+ id="text114"><tspan
+ sodipodi:role="line"
+ x="192.73657"
+ y="27.821213"
+ id="tspan112"><tspan
+ dx="0"
+ dy="0"
+ style="font-style:normal;font-variant:normal;font-weight:700;font-size:18.75px;font-family:Calibri;fill:#002060"
+ id="tspan110">core system old</tspan></tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:700;font-size:12px;line-height:125%;font-family:Calibri;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
+ x="1.6827087"
+ y="276.06406"
+ id="text120"><tspan
+ sodipodi:role="line"
+ x="1.6827087"
+ y="276.06406"
+ id="tspan118"><tspan
+ dx="0"
+ dy="0"
+ style="font-style:normal;font-variant:normal;font-weight:700;font-size:12px;font-family:Calibri;fill:#002060"
+ id="tspan116">Requests</tspan></tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:700;font-size:12px;line-height:125%;font-family:Calibri;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
+ x="50.001892"
+ y="276.06406"
+ id="text126"><tspan
+ sodipodi:role="line"
+ x="50.001892"
+ y="276.06406"
+ id="tspan124"><tspan
+ dx="0"
+ dy="0"
+ style="font-style:normal;font-variant:normal;font-weight:700;font-size:12px;font-family:Calibri;fill:#002060"
+ id="tspan122">with</tspan></tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:700;font-size:12px;line-height:125%;font-family:Calibri;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
+ x="72.40152"
+ y="276.06406"
+ id="text132"><tspan
+ sodipodi:role="line"
+ x="72.40152"
+ y="276.06406"
+ id="tspan130"><tspan
+ dx="0"
+ dy="0"
+ style="font-style:normal;font-variant:normal;font-weight:700;font-size:12px;font-family:Calibri;fill:#002060"
+ id="tspan128">:</tspan></tspan></text>
+</svg>
diff --git a/40-abschlusspraesentation/assets/balken-optimized.svg b/40-abschlusspraesentation/assets/balken-optimized.svg
new file mode 100644
index 0000000..2f0174c
--- /dev/null
+++ b/40-abschlusspraesentation/assets/balken-optimized.svg
@@ -0,0 +1,301 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ version="1.0"
+ width="122.881mm"
+ height="76.82312mm"
+ id="svg618"
+ sodipodi:docname="BalkenOptimized.emf"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg">
+ <sodipodi:namedview
+ id="namedview620"
+ pagecolor="#ffffff"
+ bordercolor="#000000"
+ borderopacity="0.25"
+ inkscape:showpageshadow="2"
+ inkscape:pageopacity="0.0"
+ inkscape:pagecheckerboard="0"
+ inkscape:deskcolor="#d1d1d1"
+ inkscape:document-units="mm"
+ showgrid="false" />
+ <defs
+ id="defs494" />
+ <path
+ style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none"
+ d="M 1.3125e-5,3.9404297e-6 V 290.35507 H 464.43211 V 3.9404297e-6 Z"
+ id="path498" />
+ <path
+ style="fill:none;stroke:#660033;stroke-width:0.999983px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 44.119263,233.15604 H 449.79236 M 44.119263,206.91649 H 449.79236 M 44.119263,180.67693 H 449.79236 M 44.119263,154.43738 H 449.79236 M 44.119263,128.19782 H 449.79236 M 44.119263,101.95827 H 449.79236 M 44.119263,75.718724 H 449.79236 M 44.119263,49.439164 H 449.79236"
+ id="path500" />
+ <path
+ style="fill:#00b050;fill-opacity:1;fill-rule:evenodd;stroke:none"
+ d="M 90.518473,108.47816 V 259.41559 H 132.89775 V 108.47816 Z"
+ id="path502" />
+ <path
+ style="fill:#ffc000;fill-opacity:1;fill-rule:evenodd;stroke:none"
+ d="m 225.75617,214.47636 v 44.95923 h 42.35928 v -44.95923 z"
+ id="path504" />
+ <path
+ style="fill:#ff0000;fill-opacity:1;fill-rule:evenodd;stroke:none"
+ d="m 360.95387,245.39583 v 14.03976 h 42.39928 v -14.03976 z"
+ id="path506" />
+ <path
+ style="fill:none;stroke:#d9d9d9;stroke-width:0.999983px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 44.119263,259.43559 H 449.79236"
+ id="path508" />
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;line-height:125%;font-family:Calibri;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
+ x="26.957245"
+ y="262.85297"
+ id="text514"><tspan
+ sodipodi:role="line"
+ x="26.957245"
+ y="262.85297"
+ id="tspan512"><tspan
+ dx="0"
+ dy="0"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;font-family:Calibri;fill:#800000"
+ id="tspan510">0</tspan></tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;line-height:125%;font-family:Calibri;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
+ x="8.7175598"
+ y="236.60805"
+ id="text520"><tspan
+ sodipodi:role="line"
+ x="8.7175598"
+ y="236.60805"
+ id="tspan518"><tspan
+ dx="0"
+ dy="0"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;font-family:Calibri;fill:#800000"
+ id="tspan516">1000</tspan></tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;line-height:125%;font-family:Calibri;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
+ x="8.7175598"
+ y="210.36327"
+ id="text526"><tspan
+ sodipodi:role="line"
+ x="8.7175598"
+ y="210.36327"
+ id="tspan524"><tspan
+ dx="0"
+ dy="0"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;font-family:Calibri;fill:#800000"
+ id="tspan522">2000</tspan></tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;line-height:125%;font-family:Calibri;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
+ x="8.7175598"
+ y="184.11836"
+ id="text532"><tspan
+ sodipodi:role="line"
+ x="8.7175598"
+ y="184.11836"
+ id="tspan530"><tspan
+ dx="0"
+ dy="0"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;font-family:Calibri;fill:#800000"
+ id="tspan528">3000</tspan></tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;line-height:125%;font-family:Calibri;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
+ x="8.7175598"
+ y="157.87346"
+ id="text538"><tspan
+ sodipodi:role="line"
+ x="8.7175598"
+ y="157.87346"
+ id="tspan536"><tspan
+ dx="0"
+ dy="0"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;font-family:Calibri;fill:#800000"
+ id="tspan534">4000</tspan></tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;line-height:125%;font-family:Calibri;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
+ x="8.7175598"
+ y="131.62865"
+ id="text544"><tspan
+ sodipodi:role="line"
+ x="8.7175598"
+ y="131.62865"
+ id="tspan542"><tspan
+ dx="0"
+ dy="0"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;font-family:Calibri;fill:#800000"
+ id="tspan540">5000</tspan></tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;line-height:125%;font-family:Calibri;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
+ x="8.7175598"
+ y="105.38371"
+ id="text550"><tspan
+ sodipodi:role="line"
+ x="8.7175598"
+ y="105.38371"
+ id="tspan548"><tspan
+ dx="0"
+ dy="0"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;font-family:Calibri;fill:#800000"
+ id="tspan546">6000</tspan></tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;line-height:125%;font-family:Calibri;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
+ x="8.7175598"
+ y="79.138901"
+ id="text556"><tspan
+ sodipodi:role="line"
+ x="8.7175598"
+ y="79.138901"
+ id="tspan554"><tspan
+ dx="0"
+ dy="0"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;font-family:Calibri;fill:#800000"
+ id="tspan552">7000</tspan></tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;line-height:125%;font-family:Calibri;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
+ x="8.7175598"
+ y="52.894028"
+ id="text562"><tspan
+ sodipodi:role="line"
+ x="8.7175598"
+ y="52.894028"
+ id="tspan560"><tspan
+ dx="0"
+ dy="0"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;font-family:Calibri;fill:#800000"
+ id="tspan558">8000</tspan></tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;line-height:125%;font-family:Calibri;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
+ x="88.19043"
+ y="278.45532"
+ id="text568"><tspan
+ sodipodi:role="line"
+ x="88.19043"
+ y="278.45532"
+ id="tspan566"><tspan
+ dx="0"
+ dy="0"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;font-family:Calibri;fill:#800000"
+ id="tspan564">&lt;= 500ms</tspan></tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;line-height:125%;font-family:Calibri;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
+ x="187.87622"
+ y="278.45532"
+ id="text574"><tspan
+ sodipodi:role="line"
+ x="187.87622"
+ y="278.45532"
+ id="tspan572"><tspan
+ dx="0"
+ dy="0"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;font-family:Calibri;fill:#800000"
+ id="tspan570">&gt; 500ms and &lt;= 1500ms</tspan></tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;line-height:125%;font-family:Calibri;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
+ x="358.58069"
+ y="278.45532"
+ id="text580"><tspan
+ sodipodi:role="line"
+ x="358.58069"
+ y="278.45532"
+ id="tspan578"><tspan
+ dx="0"
+ dy="0"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;font-family:Calibri;fill:#800000"
+ id="tspan576">&gt; 1500ms</tspan></tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:700;font-size:18.75px;line-height:125%;font-family:Calibri;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
+ x="124.73773"
+ y="27.826096"
+ id="text586"><tspan
+ sodipodi:role="line"
+ x="124.73773"
+ y="27.826096"
+ id="tspan584"><tspan
+ dx="0"
+ dy="0"
+ style="font-style:normal;font-variant:normal;font-weight:700;font-size:18.75px;font-family:Calibri;fill:#800000"
+ id="tspan582">Dual</tspan></tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:700;font-size:18.75px;line-height:125%;font-family:Calibri;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
+ x="160.57715"
+ y="27.826096"
+ id="text592"><tspan
+ sodipodi:role="line"
+ x="160.57715"
+ y="27.826096"
+ id="tspan590"><tspan
+ dx="0"
+ dy="0"
+ style="font-style:normal;font-variant:normal;font-weight:700;font-size:18.75px;font-family:Calibri;fill:#800000"
+ id="tspan588">-</tspan></tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:700;font-size:18.75px;line-height:125%;font-family:Calibri;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
+ x="166.33704"
+ y="27.826096"
+ id="text598"><tspan
+ sodipodi:role="line"
+ x="166.33704"
+ y="27.826096"
+ id="tspan596"><tspan
+ dx="0"
+ dy="0"
+ style="font-style:normal;font-variant:normal;font-weight:700;font-size:18.75px;font-family:Calibri;fill:#800000"
+ id="tspan594">core system optimized</tspan></tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:700;font-size:12px;line-height:125%;font-family:Calibri;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
+ x="1.651001"
+ y="277.46985"
+ id="text604"><tspan
+ sodipodi:role="line"
+ x="1.651001"
+ y="277.46985"
+ id="tspan602"><tspan
+ dx="0"
+ dy="0"
+ style="font-style:normal;font-variant:normal;font-weight:700;font-size:12px;font-family:Calibri;fill:#800000"
+ id="tspan600">Requests</tspan></tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:700;font-size:12px;line-height:125%;font-family:Calibri;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
+ x="49.970184"
+ y="277.46985"
+ id="text610"><tspan
+ sodipodi:role="line"
+ x="49.970184"
+ y="277.46985"
+ id="tspan608"><tspan
+ dx="0"
+ dy="0"
+ style="font-style:normal;font-variant:normal;font-weight:700;font-size:12px;font-family:Calibri;fill:#800000"
+ id="tspan606">with</tspan></tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:700;font-size:12px;line-height:125%;font-family:Calibri;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
+ x="72.369812"
+ y="277.46985"
+ id="text616"><tspan
+ sodipodi:role="line"
+ x="72.369812"
+ y="277.46985"
+ id="tspan614"><tspan
+ dx="0"
+ dy="0"
+ style="font-style:normal;font-variant:normal;font-weight:700;font-size:12px;font-family:Calibri;fill:#800000"
+ id="tspan612">:</tspan></tspan></text>
+</svg>
diff --git a/40-abschlusspraesentation/assets/bootstrap.svg b/40-abschlusspraesentation/assets/bootstrap.svg
new file mode 100644
index 0000000..8f07cfe
--- /dev/null
+++ b/40-abschlusspraesentation/assets/bootstrap.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="512" height="408"><defs><linearGradient id="bs-logo-a" x1="76.079" x2="523.48" y1="10.798" y2="365.945" gradientUnits="userSpaceOnUse"><stop stop-color="#9013fe"/><stop offset="1" stop-color="#6610f2"/></linearGradient><linearGradient id="bs-logo-b" x1="193.508" x2="293.514" y1="109.74" y2="278.872" gradientUnits="userSpaceOnUse"><stop stop-color="#fff"/><stop offset="1" stop-color="#f1e5fc"/></linearGradient><filter xmlns="http://www.w3.org/2000/svg" id="bs-logo-c" width="197" height="249" x="161.901" y="83.457" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feColorMatrix in="SourceAlpha" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"/><feOffset dy="4"/><feGaussianBlur stdDeviation="8"/><feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.15 0"/><feBlend in2="BackgroundImageFix" result="effect1_dropShadow"/><feBlend in="SourceGraphic" in2="effect1_dropShadow" result="shape"/></filter></defs><path fill="url(#bs-logo-a)" d="M56.481 53.32C55.515 25.58 77.128 0 106.342 0h299.353c29.214 0 50.827 25.58 49.861 53.32-.928 26.647.277 61.165 8.964 89.31 8.715 28.232 23.411 46.077 47.48 48.37v26c-24.069 2.293-38.765 20.138-47.48 48.37-8.687 28.145-9.892 62.663-8.964 89.311.966 27.739-20.647 53.319-49.861 53.319H106.342c-29.214 0-50.827-25.58-49.86-53.319.927-26.648-.278-61.166-8.966-89.311C38.802 237.138 24.07 219.293 0 217v-26c24.069-2.293 38.802-20.138 47.516-48.37 8.688-28.145 9.893-62.663 8.965-89.31z"/><path fill="url(#bs-logo-b)" filter="url(#bs-logo-c)" stroke="#fff" d="M267.103 312.457c47.297 0 75.798-23.158 75.798-61.355 0-28.873-20.336-49.776-50.532-53.085v-1.203c22.185-3.609 39.594-24.211 39.594-47.219 0-32.783-25.882-54.138-65.322-54.138h-88.74v217h89.202zm-54.692-189.48h45.911c24.958 0 39.131 11.128 39.131 31.279 0 21.505-16.484 33.535-46.372 33.535h-38.67v-64.814zm0 161.961v-71.431h45.602c32.661 0 49.608 12.03 49.608 35.49 0 23.459-16.484 35.941-47.605 35.941h-47.605z"/></svg> \ No newline at end of file
diff --git a/40-abschlusspraesentation/assets/checkstyle.png b/40-abschlusspraesentation/assets/checkstyle.png
new file mode 100644
index 0000000..4e2ce0d
--- /dev/null
+++ b/40-abschlusspraesentation/assets/checkstyle.png
Binary files differ
diff --git a/40-abschlusspraesentation/assets/coffee.gif b/40-abschlusspraesentation/assets/coffee.gif
new file mode 100644
index 0000000..b3c5fd9
--- /dev/null
+++ b/40-abschlusspraesentation/assets/coffee.gif
Binary files differ
diff --git a/40-abschlusspraesentation/assets/commits.gnumeric b/40-abschlusspraesentation/assets/commits.gnumeric
new file mode 100644
index 0000000..6a3ee7e
--- /dev/null
+++ b/40-abschlusspraesentation/assets/commits.gnumeric
Binary files differ
diff --git a/40-abschlusspraesentation/assets/commits.svg b/40-abschlusspraesentation/assets/commits.svg
new file mode 100644
index 0000000..1409340
--- /dev/null
+++ b/40-abschlusspraesentation/assets/commits.svg
@@ -0,0 +1,1662 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ width="469.347656"
+ height="247.5"
+ viewBox="0 0 469.347656 247.5"
+ version="1.1"
+ id="svg592"
+ sodipodi:docname="commits.svg"
+ inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg">
+ <sodipodi:namedview
+ id="namedview594"
+ pagecolor="#505050"
+ bordercolor="#eeeeee"
+ borderopacity="1"
+ inkscape:showpageshadow="0"
+ inkscape:pageopacity="0"
+ inkscape:pagecheckerboard="0"
+ inkscape:deskcolor="#505050"
+ showgrid="false"
+ inkscape:zoom="2.8564635"
+ inkscape:cx="230.00469"
+ inkscape:cy="131.80634"
+ inkscape:window-width="1918"
+ inkscape:window-height="1059"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="svg592" />
+ <defs
+ id="defs130">
+ <g
+ id="g92">
+ <g
+ id="glyph-0-0">
+ <path
+ d="M -4.3125 -3.515625 L -2.03125 -7.28125 L 2.6875 -4.453125 L 0.40625 -0.6875 Z M -3.890625 -3.625 L 0.3125 -1.09375 L 2.28125 -4.359375 L -1.921875 -6.890625 Z M -3.890625 -3.625 "
+ id="path2" />
+ </g>
+ <g
+ id="glyph-0-1">
+ <path
+ d="M 0.8125 -4.296875 C 1.238281 -4.035156 1.488281 -3.691406 1.5625 -3.265625 C 1.632812 -2.835938 1.519531 -2.375 1.21875 -1.875 C 0.925781 -1.382812 0.585938 -1.0625 0.203125 -0.90625 C -0.179688 -0.757812 -0.601562 -0.789062 -1.0625 -1 L -0.734375 -1.65625 C -0.117188 -1.382812 0.367188 -1.554688 0.734375 -2.171875 C 0.910156 -2.472656 0.972656 -2.753906 0.921875 -3.015625 C 0.867188 -3.285156 0.695312 -3.507812 0.40625 -3.6875 C 0.144531 -3.84375 -0.113281 -3.863281 -0.375 -3.75 C -0.632812 -3.632812 -0.875 -3.390625 -1.09375 -3.015625 L -1.296875 -2.671875 L -1.828125 -2.984375 L -1.640625 -3.328125 C -1.441406 -3.648438 -1.359375 -3.945312 -1.390625 -4.21875 C -1.421875 -4.488281 -1.566406 -4.703125 -1.828125 -4.859375 C -2.078125 -5.003906 -2.316406 -5.046875 -2.546875 -4.984375 C -2.785156 -4.921875 -2.992188 -4.742188 -3.171875 -4.453125 C -3.328125 -4.191406 -3.382812 -3.9375 -3.34375 -3.6875 C -3.3125 -3.4375 -3.175781 -3.226562 -2.9375 -3.0625 L -3.359375 -2.484375 C -3.710938 -2.765625 -3.914062 -3.101562 -3.96875 -3.5 C -4.03125 -3.90625 -3.925781 -4.328125 -3.65625 -4.765625 C -3.375 -5.234375 -3.039062 -5.535156 -2.65625 -5.671875 C -2.28125 -5.804688 -1.894531 -5.753906 -1.5 -5.515625 C -1.207031 -5.335938 -1.015625 -5.101562 -0.921875 -4.8125 C -0.828125 -4.53125 -0.847656 -4.207031 -0.984375 -3.84375 L -0.96875 -3.84375 C -0.726562 -4.175781 -0.445312 -4.378906 -0.125 -4.453125 C 0.195312 -4.523438 0.507812 -4.472656 0.8125 -4.296875 Z M 0.8125 -4.296875 "
+ id="path5" />
+ </g>
+ <g
+ id="glyph-0-2">
+ <path
+ d="M -0.234375 -4.96875 C 0.554688 -4.488281 1.078125 -3.984375 1.328125 -3.453125 C 1.578125 -2.929688 1.535156 -2.398438 1.203125 -1.859375 C 0.878906 -1.304688 0.429688 -1.019531 -0.140625 -1 C -0.722656 -0.976562 -1.410156 -1.207031 -2.203125 -1.6875 C -3.015625 -2.175781 -3.539062 -2.671875 -3.78125 -3.171875 C -4.03125 -3.679688 -3.984375 -4.222656 -3.640625 -4.796875 C -3.304688 -5.359375 -2.851562 -5.644531 -2.28125 -5.65625 C -1.71875 -5.675781 -1.035156 -5.445312 -0.234375 -4.96875 Z M -0.59375 -4.359375 C -1.28125 -4.765625 -1.820312 -4.976562 -2.21875 -5 C -2.613281 -5.03125 -2.921875 -4.863281 -3.140625 -4.5 C -3.359375 -4.125 -3.367188 -3.769531 -3.171875 -3.4375 C -2.972656 -3.101562 -2.523438 -2.726562 -1.828125 -2.3125 C -1.160156 -1.90625 -0.617188 -1.6875 -0.203125 -1.65625 C 0.203125 -1.625 0.507812 -1.789062 0.71875 -2.15625 C 0.9375 -2.507812 0.9375 -2.863281 0.71875 -3.21875 C 0.5 -3.582031 0.0625 -3.960938 -0.59375 -4.359375 Z M -0.59375 -4.359375 "
+ id="path8" />
+ </g>
+ <g
+ id="glyph-0-3">
+ <path
+ d="M 0.375 -0.625 L -0.359375 -1.0625 L 0.03125 -1.71875 L 0.765625 -1.28125 Z M 0.375 -0.625 "
+ id="path11" />
+ </g>
+ <g
+ id="glyph-0-4">
+ <path
+ d="M 0.3125 -0.515625 L -0.203125 -0.828125 L 0.515625 -2.046875 L -3.109375 -4.21875 L -3 -2.6875 L -3.5625 -3.03125 L -3.65625 -4.609375 L -3.3125 -5.15625 L 0.890625 -2.640625 L 1.578125 -3.796875 L 2.09375 -3.484375 Z M 0.3125 -0.515625 "
+ id="path14" />
+ </g>
+ <g
+ id="glyph-0-5">
+ <path
+ d="M 0.203125 -0.34375 L -0.21875 -0.59375 C -0.40625 -0.863281 -0.550781 -1.140625 -0.65625 -1.421875 C -0.757812 -1.710938 -0.835938 -1.992188 -0.890625 -2.265625 C -0.941406 -2.546875 -0.984375 -2.816406 -1.015625 -3.078125 C -1.046875 -3.347656 -1.085938 -3.59375 -1.140625 -3.8125 C -1.191406 -4.039062 -1.265625 -4.242188 -1.359375 -4.421875 C -1.460938 -4.597656 -1.613281 -4.742188 -1.8125 -4.859375 C -2.070312 -5.015625 -2.316406 -5.054688 -2.546875 -4.984375 C -2.785156 -4.921875 -2.984375 -4.757812 -3.140625 -4.5 C -3.296875 -4.238281 -3.351562 -3.984375 -3.3125 -3.734375 C -3.269531 -3.484375 -3.132812 -3.265625 -2.90625 -3.078125 L -3.328125 -2.5 C -3.679688 -2.78125 -3.882812 -3.125 -3.9375 -3.53125 C -4 -3.9375 -3.898438 -4.359375 -3.640625 -4.796875 C -3.359375 -5.265625 -3.023438 -5.5625 -2.640625 -5.6875 C -2.253906 -5.8125 -1.859375 -5.75 -1.453125 -5.5 C -1.273438 -5.394531 -1.117188 -5.242188 -0.984375 -5.046875 C -0.847656 -4.847656 -0.738281 -4.613281 -0.65625 -4.34375 C -0.582031 -4.070312 -0.492188 -3.585938 -0.390625 -2.890625 C -0.347656 -2.503906 -0.285156 -2.1875 -0.203125 -1.9375 C -0.117188 -1.6875 -0.0195312 -1.476562 0.09375 -1.3125 L 1.5625 -3.78125 L 2.078125 -3.46875 Z M 0.203125 -0.34375 "
+ id="path17" />
+ </g>
+ <g
+ id="glyph-0-6">
+ <path
+ d="M 0.5625 -4.4375 C 1.0625 -4.132812 1.363281 -3.75 1.46875 -3.28125 C 1.582031 -2.820312 1.484375 -2.328125 1.171875 -1.796875 C 0.910156 -1.359375 0.601562 -1.066406 0.25 -0.921875 C -0.101562 -0.773438 -0.484375 -0.773438 -0.890625 -0.921875 L -0.59375 -1.5625 C -0.0507812 -1.40625 0.378906 -1.585938 0.703125 -2.109375 C 0.898438 -2.441406 0.953125 -2.757812 0.859375 -3.0625 C 0.773438 -3.363281 0.5625 -3.617188 0.21875 -3.828125 C -0.0703125 -4.003906 -0.363281 -4.050781 -0.65625 -3.96875 C -0.957031 -3.894531 -1.203125 -3.703125 -1.390625 -3.390625 C -1.484375 -3.234375 -1.546875 -3.066406 -1.578125 -2.890625 C -1.617188 -2.722656 -1.617188 -2.53125 -1.578125 -2.3125 L -1.9375 -1.734375 L -4.375 -3.40625 L -2.765625 -6.078125 L -2.25 -5.78125 L -3.53125 -3.65625 L -2.078125 -2.65625 C -2.128906 -3.039062 -2.039062 -3.429688 -1.8125 -3.828125 C -1.53125 -4.285156 -1.171875 -4.566406 -0.734375 -4.671875 C -0.304688 -4.773438 0.125 -4.695312 0.5625 -4.4375 Z M 0.5625 -4.4375 "
+ id="path20" />
+ </g>
+ <g
+ id="glyph-0-7">
+ <path
+ d="M 0.796875 -4.296875 C 1.222656 -4.046875 1.476562 -3.707031 1.5625 -3.28125 C 1.644531 -2.851562 1.53125 -2.382812 1.21875 -1.875 C 0.90625 -1.363281 0.539062 -1.035156 0.125 -0.890625 C -0.28125 -0.753906 -0.703125 -0.816406 -1.140625 -1.078125 C -1.441406 -1.265625 -1.640625 -1.507812 -1.734375 -1.8125 C -1.835938 -2.113281 -1.832031 -2.421875 -1.71875 -2.734375 L -1.734375 -2.734375 C -1.953125 -2.515625 -2.203125 -2.390625 -2.484375 -2.359375 C -2.773438 -2.335938 -3.054688 -2.410156 -3.328125 -2.578125 C -3.691406 -2.796875 -3.90625 -3.101562 -3.96875 -3.5 C -4.03125 -3.894531 -3.925781 -4.320312 -3.65625 -4.78125 C -3.375 -5.238281 -3.039062 -5.535156 -2.65625 -5.671875 C -2.28125 -5.816406 -1.90625 -5.78125 -1.53125 -5.5625 C -1.257812 -5.394531 -1.070312 -5.175781 -0.96875 -4.90625 C -0.863281 -4.632812 -0.859375 -4.351562 -0.953125 -4.0625 L -0.953125 -4.046875 C -0.703125 -4.316406 -0.425781 -4.472656 -0.125 -4.515625 C 0.175781 -4.554688 0.484375 -4.484375 0.796875 -4.296875 Z M -1.859375 -4.890625 C -2.398438 -5.210938 -2.847656 -5.085938 -3.203125 -4.515625 C -3.367188 -4.222656 -3.425781 -3.960938 -3.375 -3.734375 C -3.332031 -3.503906 -3.175781 -3.3125 -2.90625 -3.15625 C -2.644531 -3 -2.394531 -2.953125 -2.15625 -3.015625 C -1.925781 -3.078125 -1.726562 -3.25 -1.5625 -3.53125 C -1.382812 -3.8125 -1.316406 -4.0625 -1.359375 -4.28125 C -1.410156 -4.507812 -1.578125 -4.710938 -1.859375 -4.890625 Z M 0.359375 -3.71875 C 0.0664062 -3.894531 -0.203125 -3.941406 -0.453125 -3.859375 C -0.710938 -3.773438 -0.9375 -3.578125 -1.125 -3.265625 C -1.3125 -2.953125 -1.375 -2.660156 -1.3125 -2.390625 C -1.25 -2.117188 -1.078125 -1.90625 -0.796875 -1.75 C -0.148438 -1.351562 0.367188 -1.488281 0.765625 -2.15625 C 0.960938 -2.476562 1.03125 -2.765625 0.96875 -3.015625 C 0.90625 -3.273438 0.703125 -3.507812 0.359375 -3.71875 Z M 0.359375 -3.71875 "
+ id="path23" />
+ </g>
+ <g
+ id="glyph-0-8">
+ <path
+ d="M 0.6875 -3.59375 L 1.765625 -2.953125 L 1.4375 -2.390625 L 0.359375 -3.03125 L -0.984375 -0.796875 L -1.453125 -1.078125 L -3.328125 -5.140625 L -2.953125 -5.78125 L 0.21875 -3.875 L 0.625 -4.53125 L 1.09375 -4.25 Z M -2.609375 -4.828125 C -2.597656 -4.804688 -2.554688 -4.734375 -2.484375 -4.609375 C -2.421875 -4.492188 -2.375 -4.40625 -2.34375 -4.34375 L -1.28125 -2.078125 L -1.15625 -1.734375 L -1.125 -1.625 L -0.109375 -3.3125 Z M -2.609375 -4.828125 "
+ id="path26" />
+ </g>
+ <g
+ id="glyph-0-9">
+ <path
+ d="M -2.15625 -6.015625 C -1.695312 -5.085938 -1.316406 -4.398438 -1.015625 -3.953125 C -0.722656 -3.503906 -0.40625 -3.101562 -0.0625 -2.75 C 0.28125 -2.40625 0.671875 -2.101562 1.109375 -1.84375 L 0.734375 -1.21875 C 0.128906 -1.582031 -0.425781 -2.09375 -0.9375 -2.75 C -1.445312 -3.414062 -1.957031 -4.304688 -2.46875 -5.421875 L -4 -2.875 L -4.515625 -3.171875 L -2.640625 -6.296875 Z M -2.15625 -6.015625 "
+ id="path29" />
+ </g>
+ <g
+ id="glyph-0-10">
+ <path
+ d="M 0.5625 -4.4375 C 1.0625 -4.144531 1.375 -3.773438 1.5 -3.328125 C 1.625 -2.878906 1.546875 -2.421875 1.265625 -1.953125 C 0.941406 -1.410156 0.5 -1.117188 -0.0625 -1.078125 C -0.632812 -1.035156 -1.296875 -1.242188 -2.046875 -1.703125 C -2.867188 -2.191406 -3.410156 -2.710938 -3.671875 -3.265625 C -3.929688 -3.828125 -3.898438 -4.375 -3.578125 -4.90625 C -3.148438 -5.625 -2.554688 -5.882812 -1.796875 -5.6875 L -2.03125 -5.046875 C -2.488281 -5.148438 -2.835938 -5.003906 -3.078125 -4.609375 C -3.285156 -4.265625 -3.28125 -3.898438 -3.0625 -3.515625 C -2.851562 -3.140625 -2.445312 -2.769531 -1.84375 -2.40625 C -1.988281 -2.632812 -2.050781 -2.878906 -2.03125 -3.140625 C -2.019531 -3.410156 -1.941406 -3.671875 -1.796875 -3.921875 C -1.523438 -4.359375 -1.175781 -4.625 -0.75 -4.71875 C -0.332031 -4.8125 0.101562 -4.71875 0.5625 -4.4375 Z M 0.234375 -3.8125 C -0.109375 -4.019531 -0.421875 -4.09375 -0.703125 -4.03125 C -0.992188 -3.96875 -1.226562 -3.789062 -1.40625 -3.5 C -1.570312 -3.21875 -1.625 -2.9375 -1.5625 -2.65625 C -1.507812 -2.382812 -1.335938 -2.164062 -1.046875 -2 C -0.679688 -1.78125 -0.332031 -1.691406 0 -1.734375 C 0.34375 -1.773438 0.597656 -1.9375 0.765625 -2.21875 C 0.941406 -2.507812 0.984375 -2.796875 0.890625 -3.078125 C 0.796875 -3.367188 0.578125 -3.613281 0.234375 -3.8125 Z M 0.234375 -3.8125 "
+ id="path32" />
+ </g>
+ <g
+ id="glyph-1-0">
+ <path
+ d="M 0.796875 -5.5 L 5.203125 -5.5 L 5.203125 0 L 0.796875 0 Z M 1.09375 -5.203125 L 1.09375 -0.296875 L 4.90625 -0.296875 L 4.90625 -5.203125 Z M 1.09375 -5.203125 "
+ id="path35" />
+ </g>
+ <g
+ id="glyph-1-1">
+ <path
+ d="M 4.140625 -2.75 C 4.140625 -1.832031 3.976562 -1.128906 3.65625 -0.640625 C 3.332031 -0.160156 2.851562 0.078125 2.21875 0.078125 C 1.582031 0.078125 1.101562 -0.160156 0.78125 -0.640625 C 0.46875 -1.128906 0.3125 -1.832031 0.3125 -2.75 C 0.3125 -3.695312 0.460938 -4.40625 0.765625 -4.875 C 1.078125 -5.351562 1.566406 -5.59375 2.234375 -5.59375 C 2.890625 -5.59375 3.367188 -5.351562 3.671875 -4.875 C 3.984375 -4.394531 4.140625 -3.6875 4.140625 -2.75 Z M 3.421875 -2.75 C 3.421875 -3.550781 3.328125 -4.128906 3.140625 -4.484375 C 2.960938 -4.835938 2.660156 -5.015625 2.234375 -5.015625 C 1.804688 -5.015625 1.5 -4.835938 1.3125 -4.484375 C 1.125 -4.140625 1.03125 -3.5625 1.03125 -2.75 C 1.03125 -1.96875 1.125 -1.394531 1.3125 -1.03125 C 1.5 -0.675781 1.800781 -0.5 2.21875 -0.5 C 2.632812 -0.5 2.9375 -0.679688 3.125 -1.046875 C 3.320312 -1.421875 3.421875 -1.988281 3.421875 -2.75 Z M 3.421875 -2.75 "
+ id="path38" />
+ </g>
+ <g
+ id="glyph-1-2">
+ <path
+ d="M 0.609375 0 L 0.609375 -0.59375 L 2.015625 -0.59375 L 2.015625 -4.828125 L 0.765625 -3.953125 L 0.765625 -4.609375 L 2.078125 -5.5 L 2.71875 -5.5 L 2.71875 -0.59375 L 4.0625 -0.59375 L 4.0625 0 Z M 0.609375 0 "
+ id="path41" />
+ </g>
+ <g
+ id="glyph-1-3">
+ <path
+ d="M 0.40625 0 L 0.40625 -0.5 C 0.539062 -0.800781 0.703125 -1.066406 0.890625 -1.296875 C 1.078125 -1.535156 1.273438 -1.75 1.484375 -1.9375 C 1.703125 -2.125 1.914062 -2.296875 2.125 -2.453125 C 2.332031 -2.617188 2.519531 -2.78125 2.6875 -2.9375 C 2.851562 -3.101562 2.984375 -3.273438 3.078125 -3.453125 C 3.179688 -3.628906 3.234375 -3.832031 3.234375 -4.0625 C 3.234375 -4.363281 3.144531 -4.597656 2.96875 -4.765625 C 2.789062 -4.929688 2.546875 -5.015625 2.234375 -5.015625 C 1.929688 -5.015625 1.679688 -4.929688 1.484375 -4.765625 C 1.296875 -4.597656 1.1875 -4.367188 1.15625 -4.078125 L 0.4375 -4.140625 C 0.488281 -4.585938 0.675781 -4.941406 1 -5.203125 C 1.320312 -5.460938 1.734375 -5.59375 2.234375 -5.59375 C 2.785156 -5.59375 3.210938 -5.457031 3.515625 -5.1875 C 3.816406 -4.925781 3.96875 -4.554688 3.96875 -4.078125 C 3.96875 -3.867188 3.914062 -3.65625 3.8125 -3.4375 C 3.71875 -3.226562 3.570312 -3.019531 3.375 -2.8125 C 3.1875 -2.601562 2.820312 -2.273438 2.28125 -1.828125 C 1.976562 -1.585938 1.738281 -1.367188 1.5625 -1.171875 C 1.382812 -0.972656 1.253906 -0.78125 1.171875 -0.59375 L 4.046875 -0.59375 L 4.046875 0 Z M 0.40625 0 "
+ id="path44" />
+ </g>
+ <g
+ id="glyph-1-4">
+ <path
+ d="M 4.09375 -1.515625 C 4.09375 -1.015625 3.929688 -0.625 3.609375 -0.34375 C 3.285156 -0.0625 2.828125 0.078125 2.234375 0.078125 C 1.671875 0.078125 1.222656 -0.046875 0.890625 -0.296875 C 0.566406 -0.546875 0.375 -0.921875 0.3125 -1.421875 L 1.03125 -1.484375 C 1.125 -0.828125 1.523438 -0.5 2.234375 -0.5 C 2.585938 -0.5 2.863281 -0.585938 3.0625 -0.765625 C 3.269531 -0.941406 3.375 -1.203125 3.375 -1.546875 C 3.375 -1.847656 3.253906 -2.082031 3.015625 -2.25 C 2.785156 -2.414062 2.457031 -2.5 2.03125 -2.5 L 1.625 -2.5 L 1.625 -3.109375 L 2.015625 -3.109375 C 2.398438 -3.109375 2.695312 -3.191406 2.90625 -3.359375 C 3.113281 -3.523438 3.21875 -3.757812 3.21875 -4.0625 C 3.21875 -4.351562 3.128906 -4.582031 2.953125 -4.75 C 2.785156 -4.925781 2.53125 -5.015625 2.1875 -5.015625 C 1.882812 -5.015625 1.632812 -4.929688 1.4375 -4.765625 C 1.25 -4.609375 1.140625 -4.382812 1.109375 -4.09375 L 0.40625 -4.15625 C 0.457031 -4.601562 0.640625 -4.953125 0.953125 -5.203125 C 1.273438 -5.460938 1.691406 -5.59375 2.203125 -5.59375 C 2.753906 -5.59375 3.179688 -5.460938 3.484375 -5.203125 C 3.796875 -4.941406 3.953125 -4.582031 3.953125 -4.125 C 3.953125 -3.78125 3.851562 -3.492188 3.65625 -3.265625 C 3.457031 -3.046875 3.171875 -2.898438 2.796875 -2.828125 L 2.796875 -2.8125 C 3.203125 -2.769531 3.519531 -2.628906 3.75 -2.390625 C 3.976562 -2.160156 4.09375 -1.867188 4.09375 -1.515625 Z M 4.09375 -1.515625 "
+ id="path47" />
+ </g>
+ <g
+ id="glyph-1-5">
+ <path
+ d="M 3.4375 -1.25 L 3.4375 0 L 2.78125 0 L 2.78125 -1.25 L 0.1875 -1.25 L 0.1875 -1.796875 L 2.703125 -5.5 L 3.4375 -5.5 L 3.4375 -1.796875 L 4.21875 -1.796875 L 4.21875 -1.25 Z M 2.78125 -4.71875 C 2.769531 -4.695312 2.726562 -4.625 2.65625 -4.5 C 2.59375 -4.382812 2.546875 -4.300781 2.515625 -4.25 L 1.109375 -2.171875 L 0.890625 -1.875 L 0.828125 -1.796875 L 2.78125 -1.796875 Z M 2.78125 -4.71875 "
+ id="path50" />
+ </g>
+ <g
+ id="glyph-1-6">
+ <path
+ d="M 4.109375 -1.796875 C 4.109375 -1.210938 3.9375 -0.753906 3.59375 -0.421875 C 3.25 -0.0859375 2.769531 0.078125 2.15625 0.078125 C 1.644531 0.078125 1.234375 -0.03125 0.921875 -0.25 C 0.609375 -0.476562 0.410156 -0.804688 0.328125 -1.234375 L 1.03125 -1.3125 C 1.175781 -0.769531 1.554688 -0.5 2.171875 -0.5 C 2.554688 -0.5 2.851562 -0.613281 3.0625 -0.84375 C 3.28125 -1.070312 3.390625 -1.382812 3.390625 -1.78125 C 3.390625 -2.125 3.28125 -2.398438 3.0625 -2.609375 C 2.84375 -2.828125 2.550781 -2.9375 2.1875 -2.9375 C 2 -2.9375 1.820312 -2.90625 1.65625 -2.84375 C 1.5 -2.789062 1.335938 -2.691406 1.171875 -2.546875 L 0.484375 -2.546875 L 0.671875 -5.5 L 3.796875 -5.5 L 3.796875 -4.90625 L 1.3125 -4.90625 L 1.203125 -3.15625 C 1.503906 -3.394531 1.882812 -3.515625 2.34375 -3.515625 C 2.882812 -3.515625 3.3125 -3.351562 3.625 -3.03125 C 3.945312 -2.71875 4.109375 -2.304688 4.109375 -1.796875 Z M 4.109375 -1.796875 "
+ id="path53" />
+ </g>
+ <g
+ id="glyph-1-7">
+ <path
+ d="M 4.09375 -1.796875 C 4.09375 -1.222656 3.9375 -0.765625 3.625 -0.421875 C 3.3125 -0.0859375 2.878906 0.078125 2.328125 0.078125 C 1.703125 0.078125 1.222656 -0.148438 0.890625 -0.609375 C 0.566406 -1.078125 0.40625 -1.75 0.40625 -2.625 C 0.40625 -3.582031 0.578125 -4.316406 0.921875 -4.828125 C 1.265625 -5.335938 1.75 -5.59375 2.375 -5.59375 C 3.207031 -5.59375 3.734375 -5.21875 3.953125 -4.46875 L 3.28125 -4.34375 C 3.132812 -4.789062 2.832031 -5.015625 2.375 -5.015625 C 1.96875 -5.015625 1.65625 -4.828125 1.4375 -4.453125 C 1.21875 -4.078125 1.109375 -3.535156 1.109375 -2.828125 C 1.234375 -3.066406 1.410156 -3.25 1.640625 -3.375 C 1.878906 -3.5 2.144531 -3.5625 2.4375 -3.5625 C 2.945312 -3.5625 3.347656 -3.398438 3.640625 -3.078125 C 3.941406 -2.765625 4.09375 -2.335938 4.09375 -1.796875 Z M 3.390625 -1.765625 C 3.390625 -2.171875 3.289062 -2.476562 3.09375 -2.6875 C 2.894531 -2.90625 2.625 -3.015625 2.28125 -3.015625 C 1.945312 -3.015625 1.675781 -2.914062 1.46875 -2.71875 C 1.269531 -2.53125 1.171875 -2.269531 1.171875 -1.9375 C 1.171875 -1.507812 1.273438 -1.160156 1.484375 -0.890625 C 1.703125 -0.617188 1.972656 -0.484375 2.296875 -0.484375 C 2.640625 -0.484375 2.90625 -0.597656 3.09375 -0.828125 C 3.289062 -1.054688 3.390625 -1.367188 3.390625 -1.765625 Z M 3.390625 -1.765625 "
+ id="path56" />
+ </g>
+ <g
+ id="glyph-1-8">
+ <path
+ d="M 5.390625 -2.8125 C 5.390625 -2.238281 5.28125 -1.738281 5.0625 -1.3125 C 4.84375 -0.894531 4.53125 -0.570312 4.125 -0.34375 C 3.71875 -0.113281 3.25 0 2.71875 0 L 0.65625 0 L 0.65625 -5.5 L 2.484375 -5.5 C 3.410156 -5.5 4.125 -5.265625 4.625 -4.796875 C 5.132812 -4.335938 5.390625 -3.675781 5.390625 -2.8125 Z M 4.640625 -2.8125 C 4.640625 -3.488281 4.453125 -4.003906 4.078125 -4.359375 C 3.710938 -4.722656 3.175781 -4.90625 2.46875 -4.90625 L 1.40625 -4.90625 L 1.40625 -0.59375 L 2.625 -0.59375 C 3.03125 -0.59375 3.382812 -0.679688 3.6875 -0.859375 C 4 -1.035156 4.234375 -1.289062 4.390625 -1.625 C 4.554688 -1.957031 4.640625 -2.351562 4.640625 -2.8125 Z M 4.640625 -2.8125 "
+ id="path59" />
+ </g>
+ <g
+ id="glyph-1-9">
+ <path
+ d="M 5.84375 -2.78125 C 5.84375 -2.207031 5.734375 -1.703125 5.515625 -1.265625 C 5.296875 -0.835938 4.976562 -0.503906 4.5625 -0.265625 C 4.15625 -0.0351562 3.671875 0.078125 3.109375 0.078125 C 2.546875 0.078125 2.054688 -0.0351562 1.640625 -0.265625 C 1.234375 -0.492188 0.921875 -0.820312 0.703125 -1.25 C 0.484375 -1.6875 0.375 -2.195312 0.375 -2.78125 C 0.375 -3.65625 0.613281 -4.34375 1.09375 -4.84375 C 1.582031 -5.34375 2.253906 -5.59375 3.109375 -5.59375 C 3.671875 -5.59375 4.15625 -5.476562 4.5625 -5.25 C 4.976562 -5.03125 5.296875 -4.707031 5.515625 -4.28125 C 5.734375 -3.851562 5.84375 -3.351562 5.84375 -2.78125 Z M 5.078125 -2.78125 C 5.078125 -3.46875 4.90625 -4.003906 4.5625 -4.390625 C 4.21875 -4.785156 3.734375 -4.984375 3.109375 -4.984375 C 2.484375 -4.984375 2 -4.789062 1.65625 -4.40625 C 1.3125 -4.019531 1.140625 -3.476562 1.140625 -2.78125 C 1.140625 -2.09375 1.3125 -1.546875 1.65625 -1.140625 C 2.007812 -0.734375 2.492188 -0.53125 3.109375 -0.53125 C 3.742188 -0.53125 4.226562 -0.722656 4.5625 -1.109375 C 4.90625 -1.503906 5.078125 -2.0625 5.078125 -2.78125 Z M 5.078125 -2.78125 "
+ id="path62" />
+ </g>
+ <g
+ id="glyph-1-10">
+ <path
+ d="M 3.09375 -4.984375 C 2.488281 -4.984375 2.015625 -4.785156 1.671875 -4.390625 C 1.335938 -3.992188 1.171875 -3.457031 1.171875 -2.78125 C 1.171875 -2.101562 1.34375 -1.554688 1.6875 -1.140625 C 2.039062 -0.734375 2.519531 -0.53125 3.125 -0.53125 C 3.894531 -0.53125 4.472656 -0.914062 4.859375 -1.6875 L 5.46875 -1.375 C 5.25 -0.90625 4.929688 -0.546875 4.515625 -0.296875 C 4.109375 -0.046875 3.632812 0.078125 3.09375 0.078125 C 2.539062 0.078125 2.0625 -0.0351562 1.65625 -0.265625 C 1.25 -0.492188 0.9375 -0.820312 0.71875 -1.25 C 0.507812 -1.6875 0.40625 -2.195312 0.40625 -2.78125 C 0.40625 -3.65625 0.640625 -4.34375 1.109375 -4.84375 C 1.585938 -5.34375 2.25 -5.59375 3.09375 -5.59375 C 3.675781 -5.59375 4.160156 -5.476562 4.546875 -5.25 C 4.941406 -5.019531 5.234375 -4.675781 5.421875 -4.21875 L 4.71875 -3.984375 C 4.59375 -4.304688 4.382812 -4.550781 4.09375 -4.71875 C 3.8125 -4.894531 3.476562 -4.984375 3.09375 -4.984375 Z M 3.09375 -4.984375 "
+ id="path65" />
+ </g>
+ <g
+ id="glyph-1-11">
+ <path
+ d="M 4.328125 0 L 2.125 -2.65625 L 1.40625 -2.109375 L 1.40625 0 L 0.65625 0 L 0.65625 -5.5 L 1.40625 -5.5 L 1.40625 -2.75 L 4.0625 -5.5 L 4.9375 -5.5 L 2.59375 -3.109375 L 5.25 0 Z M 4.328125 0 "
+ id="path68" />
+ </g>
+ <g
+ id="glyph-1-12">
+ <path
+ d="M 0.65625 0 L 0.65625 -5.5 L 4.828125 -5.5 L 4.828125 -4.890625 L 1.40625 -4.890625 L 1.40625 -3.125 L 4.59375 -3.125 L 4.59375 -2.53125 L 1.40625 -2.53125 L 1.40625 -0.609375 L 5 -0.609375 L 5 0 Z M 0.65625 0 "
+ id="path71" />
+ </g>
+ <g
+ id="glyph-1-13">
+ <path
+ d="M 4.546875 0 L 3.125 -2.28125 L 1.40625 -2.28125 L 1.40625 0 L 0.65625 0 L 0.65625 -5.5 L 3.25 -5.5 C 3.863281 -5.5 4.335938 -5.359375 4.671875 -5.078125 C 5.015625 -4.804688 5.1875 -4.425781 5.1875 -3.9375 C 5.1875 -3.519531 5.066406 -3.171875 4.828125 -2.890625 C 4.585938 -2.617188 4.257812 -2.445312 3.84375 -2.375 L 5.40625 0 Z M 4.4375 -3.921875 C 4.4375 -4.242188 4.328125 -4.488281 4.109375 -4.65625 C 3.890625 -4.820312 3.578125 -4.90625 3.171875 -4.90625 L 1.40625 -4.90625 L 1.40625 -2.875 L 3.203125 -2.875 C 3.597656 -2.875 3.898438 -2.960938 4.109375 -3.140625 C 4.328125 -3.328125 4.4375 -3.585938 4.4375 -3.921875 Z M 4.4375 -3.921875 "
+ id="path74" />
+ </g>
+ <g
+ id="glyph-1-14">
+ <path
+ d="M 4.5625 0 L 3.9375 -1.609375 L 1.421875 -1.609375 L 0.796875 0 L 0.015625 0 L 2.265625 -5.5 L 3.109375 -5.5 L 5.328125 0 Z M 2.671875 -4.9375 L 2.640625 -4.828125 C 2.578125 -4.617188 2.484375 -4.34375 2.359375 -4 L 1.65625 -2.1875 L 3.703125 -2.1875 L 3 -4.015625 C 2.925781 -4.191406 2.851562 -4.394531 2.78125 -4.625 Z M 2.671875 -4.9375 "
+ id="path77" />
+ </g>
+ <g
+ id="glyph-1-15">
+ <path
+ d="M 4.96875 -1.515625 C 4.96875 -1.015625 4.769531 -0.625 4.375 -0.34375 C 3.976562 -0.0625 3.421875 0.078125 2.703125 0.078125 C 1.359375 0.078125 0.578125 -0.390625 0.359375 -1.328125 L 1.09375 -1.46875 C 1.175781 -1.132812 1.351562 -0.890625 1.625 -0.734375 C 1.894531 -0.578125 2.257812 -0.5 2.71875 -0.5 C 3.207031 -0.5 3.582031 -0.582031 3.84375 -0.75 C 4.101562 -0.914062 4.234375 -1.160156 4.234375 -1.484375 C 4.234375 -1.660156 4.191406 -1.804688 4.109375 -1.921875 C 4.023438 -2.035156 3.910156 -2.128906 3.765625 -2.203125 C 3.617188 -2.273438 3.441406 -2.332031 3.234375 -2.375 C 3.023438 -2.425781 2.796875 -2.484375 2.546875 -2.546875 C 2.109375 -2.640625 1.773438 -2.734375 1.546875 -2.828125 C 1.328125 -2.921875 1.148438 -3.023438 1.015625 -3.140625 C 0.890625 -3.265625 0.789062 -3.40625 0.71875 -3.5625 C 0.65625 -3.726562 0.625 -3.910156 0.625 -4.109375 C 0.625 -4.585938 0.800781 -4.953125 1.15625 -5.203125 C 1.519531 -5.460938 2.039062 -5.59375 2.71875 -5.59375 C 3.34375 -5.59375 3.816406 -5.492188 4.140625 -5.296875 C 4.472656 -5.109375 4.707031 -4.785156 4.84375 -4.328125 L 4.109375 -4.1875 C 4.023438 -4.476562 3.867188 -4.691406 3.640625 -4.828125 C 3.421875 -4.960938 3.109375 -5.03125 2.703125 -5.03125 C 2.265625 -5.03125 1.925781 -4.957031 1.6875 -4.8125 C 1.457031 -4.664062 1.34375 -4.445312 1.34375 -4.15625 C 1.34375 -3.988281 1.390625 -3.847656 1.484375 -3.734375 C 1.578125 -3.617188 1.707031 -3.523438 1.875 -3.453125 C 2.039062 -3.378906 2.378906 -3.285156 2.890625 -3.171875 C 3.054688 -3.128906 3.222656 -3.085938 3.390625 -3.046875 C 3.554688 -3.003906 3.71875 -2.957031 3.875 -2.90625 C 4.03125 -2.851562 4.171875 -2.785156 4.296875 -2.703125 C 4.429688 -2.628906 4.546875 -2.535156 4.640625 -2.421875 C 4.742188 -2.316406 4.820312 -2.191406 4.875 -2.046875 C 4.9375 -1.898438 4.96875 -1.722656 4.96875 -1.515625 Z M 4.96875 -1.515625 "
+ id="path80" />
+ </g>
+ <g
+ id="glyph-1-16">
+ <path
+ d="M 4.375 0 L 4.375 -2.546875 L 1.40625 -2.546875 L 1.40625 0 L 0.65625 0 L 0.65625 -5.5 L 1.40625 -5.5 L 1.40625 -3.171875 L 4.375 -3.171875 L 4.375 -5.5 L 5.125 -5.5 L 5.125 0 Z M 4.375 0 "
+ id="path83" />
+ </g>
+ <g
+ id="glyph-1-17">
+ <path
+ d="M 4.921875 -1.546875 C 4.921875 -1.054688 4.738281 -0.675781 4.375 -0.40625 C 4.019531 -0.132812 3.523438 0 2.890625 0 L 0.65625 0 L 0.65625 -5.5 L 2.65625 -5.5 C 3.945312 -5.5 4.59375 -5.054688 4.59375 -4.171875 C 4.59375 -3.847656 4.5 -3.570312 4.3125 -3.34375 C 4.132812 -3.125 3.878906 -2.976562 3.546875 -2.90625 C 3.984375 -2.851562 4.320312 -2.707031 4.5625 -2.46875 C 4.800781 -2.226562 4.921875 -1.921875 4.921875 -1.546875 Z M 3.84375 -4.078125 C 3.84375 -4.378906 3.738281 -4.59375 3.53125 -4.71875 C 3.332031 -4.84375 3.039062 -4.90625 2.65625 -4.90625 L 1.40625 -4.90625 L 1.40625 -3.171875 L 2.65625 -3.171875 C 3.050781 -3.171875 3.347656 -3.242188 3.546875 -3.390625 C 3.742188 -3.535156 3.84375 -3.765625 3.84375 -4.078125 Z M 4.15625 -1.609375 C 4.15625 -2.253906 3.703125 -2.578125 2.796875 -2.578125 L 1.40625 -2.578125 L 1.40625 -0.59375 L 2.859375 -0.59375 C 3.304688 -0.59375 3.632812 -0.675781 3.84375 -0.84375 C 4.050781 -1.019531 4.15625 -1.273438 4.15625 -1.609375 Z M 4.15625 -1.609375 "
+ id="path86" />
+ </g>
+ <g
+ id="glyph-1-18">
+ <path
+ d="M 3.0625 0 L 2.28125 0 L 0.03125 -5.5 L 0.828125 -5.5 L 2.34375 -1.625 L 2.671875 -0.65625 L 3 -1.625 L 4.515625 -5.5 L 5.296875 -5.5 Z M 3.0625 0 "
+ id="path89" />
+ </g>
+ </g>
+ <clipPath
+ id="clip-0">
+ <path
+ clip-rule="nonzero"
+ d="M 17.957031 89 L 378 89 L 378 201.894531 L 17.957031 201.894531 Z M 17.957031 89 "
+ id="path94" />
+ </clipPath>
+ <clipPath
+ id="clip-1">
+ <path
+ clip-rule="nonzero"
+ d="M 17.957031 201 L 378 201 L 378 201.894531 L 17.957031 201.894531 Z M 17.957031 201 "
+ id="path97" />
+ </clipPath>
+ <clipPath
+ id="clip-2">
+ <path
+ clip-rule="nonzero"
+ d="M 17.957031 88 L 378 88 L 378 201.894531 L 17.957031 201.894531 Z M 17.957031 88 "
+ id="path100" />
+ </clipPath>
+ <clipPath
+ id="clip-3">
+ <path
+ clip-rule="nonzero"
+ d="M 17.957031 28 L 378 28 L 378 201.894531 L 17.957031 201.894531 Z M 17.957031 28 "
+ id="path103" />
+ </clipPath>
+ <clipPath
+ id="clip-4">
+ <path
+ clip-rule="nonzero"
+ d="M 17.957031 88 L 378 88 L 378 201.894531 L 17.957031 201.894531 Z M 17.957031 88 "
+ id="path106" />
+ </clipPath>
+ <clipPath
+ id="clip-5">
+ <path
+ clip-rule="nonzero"
+ d="M 17.957031 27 L 378 27 L 378 199 L 17.957031 199 Z M 17.957031 27 "
+ id="path109" />
+ </clipPath>
+ <clipPath
+ id="clip-6">
+ <path
+ clip-rule="nonzero"
+ d="M 17.957031 11 L 386.671875 11 L 386.671875 201.894531 L 17.957031 201.894531 Z M 17.957031 11 "
+ id="path112" />
+ </clipPath>
+ <clipPath
+ id="clip-7">
+ <path
+ clip-rule="nonzero"
+ d="M 17.957031 27 L 386.671875 27 L 386.671875 201.894531 L 17.957031 201.894531 Z M 17.957031 27 "
+ id="path115" />
+ </clipPath>
+ <clipPath
+ id="clip-8">
+ <path
+ clip-rule="nonzero"
+ d="M 17.957031 11 L 386.671875 11 L 386.671875 199 L 17.957031 199 Z M 17.957031 11 "
+ id="path118" />
+ </clipPath>
+ <clipPath
+ id="clip-9">
+ <path
+ clip-rule="nonzero"
+ d="M 398.761719 110 L 407 110 L 407 119 L 398.761719 119 Z M 398.761719 110 "
+ id="path121" />
+ </clipPath>
+ <clipPath
+ id="clip-10">
+ <path
+ clip-rule="nonzero"
+ d="M 398.761719 119 L 407 119 L 407 128 L 398.761719 128 Z M 398.761719 119 "
+ id="path124" />
+ </clipPath>
+ <clipPath
+ id="clip-11">
+ <path
+ clip-rule="nonzero"
+ d="M 398.761719 129 L 407 129 L 407 138 L 398.761719 138 Z M 398.761719 129 "
+ id="path127" />
+ </clipPath>
+ </defs>
+ <path
+ fill="none"
+ stroke-width="0.5"
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ stroke="rgb(0%, 0%, 0%)"
+ stroke-opacity="1"
+ stroke-miterlimit="10"
+ d="M 0.25 0.25 L 469.097656 0.25 L 469.097656 247.25 L 0.25 247.25 Z M 0.25 0.25 "
+ id="path132" />
+ <path
+ fill="none"
+ stroke-width="1"
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ stroke="rgb(51.764706%, 50.980392%, 51.764706%)"
+ stroke-opacity="1"
+ stroke-miterlimit="10"
+ d="M 17.957031 8.761719 L 386.671875 8.761719 L 386.671875 201.894531 L 17.957031 201.894531 Z M 17.957031 8.761719 "
+ id="path134" />
+ <path
+ fill="none"
+ stroke-width="0.5"
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ stroke="#000000"
+ stroke-opacity="1"
+ stroke-miterlimit="10"
+ d="M 17.957031,201.89453 H 386.67187 m -350.726558,4.25 v -4.25 m 26.980469,4.25 v -4.25 m 26.976563,4.25 v -4.25 m 26.980466,4.25 v -4.25 m 26.97656,4.25 v -4.25 m 26.98047,4.25 v -4.25 m 26.98047,4.25 v -4.25 m 26.97656,4.25 v -4.25 m 26.98047,4.25 v -4.25 m 26.98047,4.25 v -4.25 m 26.97656,4.25 v -4.25 m 26.98047,4.25 v -4.25 m 26.98047,4.25 v -4.25 m 26.97656,4.25 v -4.25 m -116.88082,4.50404 v -4.25"
+ id="path136"
+ sodipodi:nodetypes="cccccccccccccccccccccccccccccccc" />
+ <g
+ fill="rgb(0%, 0%, 0%)"
+ fill-opacity="1"
+ id="g158">
+ <use
+ xlink:href="#glyph-0-1"
+ x="19.309329"
+ y="242.577659"
+ id="use138" />
+ <use
+ xlink:href="#glyph-0-2"
+ x="21.369481"
+ y="239.148989"
+ id="use140" />
+ <use
+ xlink:href="#glyph-0-3"
+ x="23.429633"
+ y="235.72032"
+ id="use142" />
+ <use
+ xlink:href="#glyph-0-2"
+ x="24.45971"
+ y="234.005986"
+ id="use144" />
+ <use
+ xlink:href="#glyph-0-4"
+ x="26.519862"
+ y="230.577316"
+ id="use146" />
+ <use
+ xlink:href="#glyph-0-3"
+ x="28.580014"
+ y="227.148647"
+ id="use148" />
+ <use
+ xlink:href="#glyph-0-5"
+ x="29.61009"
+ y="225.434313"
+ id="use150" />
+ <use
+ xlink:href="#glyph-0-2"
+ x="31.670243"
+ y="222.005643"
+ id="use152" />
+ <use
+ xlink:href="#glyph-0-5"
+ x="33.730395"
+ y="218.576974"
+ id="use154" />
+ <use
+ xlink:href="#glyph-0-1"
+ x="35.790547"
+ y="215.148305"
+ id="use156" />
+ </g>
+ <g
+ fill="rgb(0%, 0%, 0%)"
+ fill-opacity="1"
+ id="g180">
+ <use
+ xlink:href="#glyph-0-2"
+ x="46.289798"
+ y="242.577659"
+ id="use160" />
+ <use
+ xlink:href="#glyph-0-5"
+ x="48.34995"
+ y="239.148989"
+ id="use162" />
+ <use
+ xlink:href="#glyph-0-3"
+ x="50.410102"
+ y="235.72032"
+ id="use164" />
+ <use
+ xlink:href="#glyph-0-2"
+ x="51.440178"
+ y="234.005986"
+ id="use166" />
+ <use
+ xlink:href="#glyph-0-5"
+ x="53.500331"
+ y="230.577316"
+ id="use168" />
+ <use
+ xlink:href="#glyph-0-3"
+ x="55.560483"
+ y="227.148647"
+ id="use170" />
+ <use
+ xlink:href="#glyph-0-5"
+ x="56.590559"
+ y="225.434313"
+ id="use172" />
+ <use
+ xlink:href="#glyph-0-2"
+ x="58.650711"
+ y="222.005643"
+ id="use174" />
+ <use
+ xlink:href="#glyph-0-5"
+ x="60.710864"
+ y="218.576974"
+ id="use176" />
+ <use
+ xlink:href="#glyph-0-1"
+ x="62.771016"
+ y="215.148305"
+ id="use178" />
+ </g>
+ <g
+ fill="rgb(0%, 0%, 0%)"
+ fill-opacity="1"
+ id="g202">
+ <use
+ xlink:href="#glyph-0-2"
+ x="73.26636"
+ y="242.577659"
+ id="use182" />
+ <use
+ xlink:href="#glyph-0-6"
+ x="75.326512"
+ y="239.148989"
+ id="use184" />
+ <use
+ xlink:href="#glyph-0-3"
+ x="77.386665"
+ y="235.72032"
+ id="use186" />
+ <use
+ xlink:href="#glyph-0-2"
+ x="78.416741"
+ y="234.005986"
+ id="use188" />
+ <use
+ xlink:href="#glyph-0-5"
+ x="80.476893"
+ y="230.577316"
+ id="use190" />
+ <use
+ xlink:href="#glyph-0-3"
+ x="82.537045"
+ y="227.148647"
+ id="use192" />
+ <use
+ xlink:href="#glyph-0-5"
+ x="83.567122"
+ y="225.434313"
+ id="use194" />
+ <use
+ xlink:href="#glyph-0-2"
+ x="85.627274"
+ y="222.005643"
+ id="use196" />
+ <use
+ xlink:href="#glyph-0-5"
+ x="87.687426"
+ y="218.576974"
+ id="use198" />
+ <use
+ xlink:href="#glyph-0-1"
+ x="89.747578"
+ y="215.148305"
+ id="use200" />
+ </g>
+ <g
+ fill="rgb(0%, 0%, 0%)"
+ fill-opacity="1"
+ id="g224">
+ <use
+ xlink:href="#glyph-0-2"
+ x="100.246829"
+ y="242.577659"
+ id="use204" />
+ <use
+ xlink:href="#glyph-0-7"
+ x="102.306981"
+ y="239.148989"
+ id="use206" />
+ <use
+ xlink:href="#glyph-0-3"
+ x="104.367133"
+ y="235.72032"
+ id="use208" />
+ <use
+ xlink:href="#glyph-0-2"
+ x="105.39721"
+ y="234.005986"
+ id="use210" />
+ <use
+ xlink:href="#glyph-0-5"
+ x="107.457362"
+ y="230.577316"
+ id="use212" />
+ <use
+ xlink:href="#glyph-0-3"
+ x="109.517514"
+ y="227.148647"
+ id="use214" />
+ <use
+ xlink:href="#glyph-0-5"
+ x="110.54759"
+ y="225.434313"
+ id="use216" />
+ <use
+ xlink:href="#glyph-0-2"
+ x="112.607743"
+ y="222.005643"
+ id="use218" />
+ <use
+ xlink:href="#glyph-0-5"
+ x="114.667895"
+ y="218.576974"
+ id="use220" />
+ <use
+ xlink:href="#glyph-0-1"
+ x="116.728047"
+ y="215.148305"
+ id="use222" />
+ </g>
+ <g
+ fill="rgb(0%, 0%, 0%)"
+ fill-opacity="1"
+ id="g246">
+ <use
+ xlink:href="#glyph-0-4"
+ x="127.227298"
+ y="242.577659"
+ id="use226" />
+ <use
+ xlink:href="#glyph-0-4"
+ x="129.28745"
+ y="239.148989"
+ id="use228" />
+ <use
+ xlink:href="#glyph-0-3"
+ x="131.347602"
+ y="235.72032"
+ id="use230" />
+ <use
+ xlink:href="#glyph-0-2"
+ x="132.377678"
+ y="234.005986"
+ id="use232" />
+ <use
+ xlink:href="#glyph-0-5"
+ x="134.437831"
+ y="230.577316"
+ id="use234" />
+ <use
+ xlink:href="#glyph-0-3"
+ x="136.497983"
+ y="227.148647"
+ id="use236" />
+ <use
+ xlink:href="#glyph-0-5"
+ x="137.528059"
+ y="225.434313"
+ id="use238" />
+ <use
+ xlink:href="#glyph-0-2"
+ x="139.588211"
+ y="222.005643"
+ id="use240" />
+ <use
+ xlink:href="#glyph-0-5"
+ x="141.648364"
+ y="218.576974"
+ id="use242" />
+ <use
+ xlink:href="#glyph-0-1"
+ x="143.708516"
+ y="215.148305"
+ id="use244" />
+ </g>
+ <g
+ fill="rgb(0%, 0%, 0%)"
+ fill-opacity="1"
+ id="g268">
+ <use
+ xlink:href="#glyph-0-4"
+ x="154.20386"
+ y="242.577659"
+ id="use248" />
+ <use
+ xlink:href="#glyph-0-8"
+ x="156.264012"
+ y="239.148989"
+ id="use250" />
+ <use
+ xlink:href="#glyph-0-3"
+ x="158.324165"
+ y="235.72032"
+ id="use252" />
+ <use
+ xlink:href="#glyph-0-2"
+ x="159.354241"
+ y="234.005986"
+ id="use254" />
+ <use
+ xlink:href="#glyph-0-5"
+ x="161.414393"
+ y="230.577316"
+ id="use256" />
+ <use
+ xlink:href="#glyph-0-3"
+ x="163.474545"
+ y="227.148647"
+ id="use258" />
+ <use
+ xlink:href="#glyph-0-5"
+ x="164.504622"
+ y="225.434313"
+ id="use260" />
+ <use
+ xlink:href="#glyph-0-2"
+ x="166.564774"
+ y="222.005643"
+ id="use262" />
+ <use
+ xlink:href="#glyph-0-5"
+ x="168.624926"
+ y="218.576974"
+ id="use264" />
+ <use
+ xlink:href="#glyph-0-1"
+ x="170.685078"
+ y="215.148305"
+ id="use266" />
+ </g>
+ <g
+ fill="rgb(0%, 0%, 0%)"
+ fill-opacity="1"
+ id="g290">
+ <use
+ xlink:href="#glyph-0-4"
+ x="181.184329"
+ y="242.577659"
+ id="use270" />
+ <use
+ xlink:href="#glyph-0-9"
+ x="183.244481"
+ y="239.148989"
+ id="use272" />
+ <use
+ xlink:href="#glyph-0-3"
+ x="185.304633"
+ y="235.72032"
+ id="use274" />
+ <use
+ xlink:href="#glyph-0-2"
+ x="186.33471"
+ y="234.005986"
+ id="use276" />
+ <use
+ xlink:href="#glyph-0-5"
+ x="188.394862"
+ y="230.577316"
+ id="use278" />
+ <use
+ xlink:href="#glyph-0-3"
+ x="190.455014"
+ y="227.148647"
+ id="use280" />
+ <use
+ xlink:href="#glyph-0-5"
+ x="191.48509"
+ y="225.434313"
+ id="use282" />
+ <use
+ xlink:href="#glyph-0-2"
+ x="193.545243"
+ y="222.005643"
+ id="use284" />
+ <use
+ xlink:href="#glyph-0-5"
+ x="195.605395"
+ y="218.576974"
+ id="use286" />
+ <use
+ xlink:href="#glyph-0-1"
+ x="197.665547"
+ y="215.148305"
+ id="use288" />
+ </g>
+ <g
+ fill="rgb(0%, 0%, 0%)"
+ fill-opacity="1"
+ id="g312">
+ <use
+ xlink:href="#glyph-0-5"
+ x="208.160891"
+ y="242.577659"
+ id="use292" />
+ <use
+ xlink:href="#glyph-0-2"
+ x="210.221044"
+ y="239.148989"
+ id="use294" />
+ <use
+ xlink:href="#glyph-0-3"
+ x="212.281196"
+ y="235.72032"
+ id="use296" />
+ <use
+ xlink:href="#glyph-0-2"
+ x="213.311272"
+ y="234.005986"
+ id="use298" />
+ <use
+ xlink:href="#glyph-0-5"
+ x="215.371424"
+ y="230.577316"
+ id="use300" />
+ <use
+ xlink:href="#glyph-0-3"
+ x="217.431577"
+ y="227.148647"
+ id="use302" />
+ <use
+ xlink:href="#glyph-0-5"
+ x="218.461653"
+ y="225.434313"
+ id="use304" />
+ <use
+ xlink:href="#glyph-0-2"
+ x="220.521805"
+ y="222.005643"
+ id="use306" />
+ <use
+ xlink:href="#glyph-0-5"
+ x="222.581957"
+ y="218.576974"
+ id="use308" />
+ <use
+ xlink:href="#glyph-0-1"
+ x="224.64211"
+ y="215.148305"
+ id="use310" />
+ </g>
+ <g
+ fill="rgb(0%, 0%, 0%)"
+ fill-opacity="1"
+ id="g334">
+ <use
+ xlink:href="#glyph-0-5"
+ x="235.14136"
+ y="242.577659"
+ id="use314" />
+ <use
+ xlink:href="#glyph-0-1"
+ x="237.201512"
+ y="239.148989"
+ id="use316" />
+ <use
+ xlink:href="#glyph-0-3"
+ x="239.261665"
+ y="235.72032"
+ id="use318" />
+ <use
+ xlink:href="#glyph-0-2"
+ x="240.291741"
+ y="234.005986"
+ id="use320" />
+ <use
+ xlink:href="#glyph-0-5"
+ x="242.351893"
+ y="230.577316"
+ id="use322" />
+ <use
+ xlink:href="#glyph-0-3"
+ x="244.412045"
+ y="227.148647"
+ id="use324" />
+ <use
+ xlink:href="#glyph-0-5"
+ x="245.442122"
+ y="225.434313"
+ id="use326" />
+ <use
+ xlink:href="#glyph-0-2"
+ x="247.502274"
+ y="222.005643"
+ id="use328" />
+ <use
+ xlink:href="#glyph-0-5"
+ x="249.562426"
+ y="218.576974"
+ id="use330" />
+ <use
+ xlink:href="#glyph-0-1"
+ x="251.622578"
+ y="215.148305"
+ id="use332" />
+ </g>
+ <g
+ fill="rgb(0%, 0%, 0%)"
+ fill-opacity="1"
+ id="g356">
+ <use
+ xlink:href="#glyph-0-5"
+ x="262.121829"
+ y="242.577659"
+ id="use336" />
+ <use
+ xlink:href="#glyph-0-10"
+ x="264.181981"
+ y="239.148989"
+ id="use338" />
+ <use
+ xlink:href="#glyph-0-3"
+ x="266.242133"
+ y="235.72032"
+ id="use340" />
+ <use
+ xlink:href="#glyph-0-2"
+ x="267.27221"
+ y="234.005986"
+ id="use342" />
+ <use
+ xlink:href="#glyph-0-5"
+ x="269.332362"
+ y="230.577316"
+ id="use344" />
+ <use
+ xlink:href="#glyph-0-3"
+ x="271.392514"
+ y="227.148647"
+ id="use346" />
+ <use
+ xlink:href="#glyph-0-5"
+ x="272.42259"
+ y="225.434313"
+ id="use348" />
+ <use
+ xlink:href="#glyph-0-2"
+ x="274.482743"
+ y="222.005643"
+ id="use350" />
+ <use
+ xlink:href="#glyph-0-5"
+ x="276.542895"
+ y="218.576974"
+ id="use352" />
+ <use
+ xlink:href="#glyph-0-1"
+ x="278.603047"
+ y="215.148305"
+ id="use354" />
+ </g>
+ <g
+ fill="#000000"
+ fill-opacity="1"
+ id="g356-7"
+ transform="translate(-9.161394,-0.7157038)"
+ style="fill:#ff0000">
+ <use
+ xlink:href="#glyph-0-5"
+ x="262.12183"
+ y="242.57765"
+ id="use336-5"
+ style="fill:#ff0000" />
+ <use
+ xlink:href="#glyph-0-3"
+ x="266.24213"
+ y="235.72032"
+ id="use340-5"
+ style="fill:#ff0000" />
+ <use
+ xlink:href="#glyph-0-2"
+ x="267.27222"
+ y="234.00598"
+ id="use342-6"
+ style="fill:#ff0000" />
+ <use
+ xlink:href="#glyph-0-5"
+ x="269.33237"
+ y="230.57732"
+ id="use344-2"
+ style="fill:#ff0000" />
+ <use
+ xlink:href="#glyph-0-3"
+ x="271.39252"
+ y="227.14865"
+ id="use346-9"
+ style="fill:#ff0000" />
+ <use
+ xlink:href="#glyph-0-5"
+ x="272.42258"
+ y="225.43431"
+ id="use348-1"
+ style="fill:#ff0000" />
+ <use
+ xlink:href="#glyph-0-2"
+ x="274.48276"
+ y="222.00565"
+ id="use350-2"
+ style="fill:#ff0000" />
+ <use
+ xlink:href="#glyph-0-5"
+ x="276.54291"
+ y="218.57698"
+ id="use352-7"
+ style="fill:#ff0000" />
+ <use
+ xlink:href="#glyph-0-1"
+ x="278.60306"
+ y="215.1483"
+ id="use354-0"
+ style="fill:#ff0000" />
+ </g>
+ <g
+ fill="rgb(0%, 0%, 0%)"
+ fill-opacity="1"
+ id="g378">
+ <use
+ xlink:href="#glyph-0-4"
+ x="289.098391"
+ y="242.577659"
+ id="use358" />
+ <use
+ xlink:href="#glyph-0-6"
+ x="291.158544"
+ y="239.148989"
+ id="use360" />
+ <use
+ xlink:href="#glyph-0-6"
+ x="291.15854"
+ y="239.14899"
+ id="use360-9"
+ transform="translate(-35.9813,-0.91435203)"
+ style="fill:#ff0000" />
+ <use
+ xlink:href="#glyph-0-3"
+ x="293.218696"
+ y="235.72032"
+ id="use362" />
+ <use
+ xlink:href="#glyph-0-2"
+ x="294.248772"
+ y="234.005986"
+ id="use364" />
+ <use
+ xlink:href="#glyph-0-1"
+ x="296.308924"
+ y="230.577316"
+ id="use366" />
+ <use
+ xlink:href="#glyph-0-3"
+ x="298.369077"
+ y="227.148647"
+ id="use368" />
+ <use
+ xlink:href="#glyph-0-5"
+ x="299.399153"
+ y="225.434313"
+ id="use370" />
+ <use
+ xlink:href="#glyph-0-2"
+ x="301.459305"
+ y="222.005643"
+ id="use372" />
+ <use
+ xlink:href="#glyph-0-5"
+ x="303.519457"
+ y="218.576974"
+ id="use374" />
+ <use
+ xlink:href="#glyph-0-1"
+ x="305.57961"
+ y="215.148305"
+ id="use376" />
+ </g>
+ <g
+ fill="rgb(0%, 0%, 0%)"
+ fill-opacity="1"
+ id="g400"
+ style="stroke:none;fill:#ff0000">
+ <use
+ xlink:href="#glyph-0-4"
+ x="316.07886"
+ y="242.577659"
+ id="use380"
+ style="stroke:none;fill:#ff0000" />
+ <use
+ xlink:href="#glyph-0-7"
+ x="318.139012"
+ y="239.148989"
+ id="use382"
+ style="stroke:none;fill:#ff0000" />
+ <use
+ xlink:href="#glyph-0-3"
+ x="320.199165"
+ y="235.72032"
+ id="use384"
+ style="stroke:none;fill:#ff0000" />
+ <use
+ xlink:href="#glyph-0-2"
+ x="321.229241"
+ y="234.005986"
+ id="use386"
+ style="stroke:none;fill:#ff0000" />
+ <use
+ xlink:href="#glyph-0-1"
+ x="323.289393"
+ y="230.577316"
+ id="use388"
+ style="stroke:none;fill:#ff0000" />
+ <use
+ xlink:href="#glyph-0-3"
+ x="325.349545"
+ y="227.148647"
+ id="use390"
+ style="stroke:none;fill:#ff0000" />
+ <use
+ xlink:href="#glyph-0-5"
+ x="326.379622"
+ y="225.434313"
+ id="use392"
+ style="stroke:none;fill:#ff0000" />
+ <use
+ xlink:href="#glyph-0-2"
+ x="328.439774"
+ y="222.005643"
+ id="use394"
+ style="stroke:none;fill:#ff0000" />
+ <use
+ xlink:href="#glyph-0-5"
+ x="330.499926"
+ y="218.576974"
+ id="use396"
+ style="stroke:none;fill:#ff0000" />
+ <use
+ xlink:href="#glyph-0-1"
+ x="332.560078"
+ y="215.148305"
+ id="use398"
+ style="stroke:none;fill:#ff0000" />
+ </g>
+ <g
+ fill="rgb(0%, 0%, 0%)"
+ fill-opacity="1"
+ id="g422">
+ <use
+ xlink:href="#glyph-0-5"
+ x="343.059329"
+ y="242.577659"
+ id="use402" />
+ <use
+ xlink:href="#glyph-0-8"
+ x="345.119481"
+ y="239.148989"
+ id="use404" />
+ <use
+ xlink:href="#glyph-0-3"
+ x="347.179633"
+ y="235.72032"
+ id="use406" />
+ <use
+ xlink:href="#glyph-0-2"
+ x="348.20971"
+ y="234.005986"
+ id="use408" />
+ <use
+ xlink:href="#glyph-0-1"
+ x="350.269862"
+ y="230.577316"
+ id="use410" />
+ <use
+ xlink:href="#glyph-0-3"
+ x="352.330014"
+ y="227.148647"
+ id="use412" />
+ <use
+ xlink:href="#glyph-0-5"
+ x="353.36009"
+ y="225.434313"
+ id="use414" />
+ <use
+ xlink:href="#glyph-0-2"
+ x="355.420243"
+ y="222.005643"
+ id="use416" />
+ <use
+ xlink:href="#glyph-0-5"
+ x="357.480395"
+ y="218.576974"
+ id="use418" />
+ <use
+ xlink:href="#glyph-0-1"
+ x="359.540547"
+ y="215.148305"
+ id="use420" />
+ </g>
+ <g
+ fill="rgb(0%, 0%, 0%)"
+ fill-opacity="1"
+ id="g444"
+ style="fill:#ff0000">
+ <use
+ xlink:href="#glyph-0-1"
+ x="370.035891"
+ y="242.577659"
+ id="use424"
+ style="fill:#ff0000" />
+ <use
+ xlink:href="#glyph-0-2"
+ x="372.096044"
+ y="239.148989"
+ id="use426"
+ style="fill:#ff0000" />
+ <use
+ xlink:href="#glyph-0-3"
+ x="374.156196"
+ y="235.72032"
+ id="use428"
+ style="fill:#ff0000" />
+ <use
+ xlink:href="#glyph-0-2"
+ x="375.186272"
+ y="234.005986"
+ id="use430"
+ style="fill:#ff0000" />
+ <use
+ xlink:href="#glyph-0-1"
+ x="377.246424"
+ y="230.577316"
+ id="use432"
+ style="fill:#ff0000" />
+ <use
+ xlink:href="#glyph-0-3"
+ x="379.306577"
+ y="227.148647"
+ id="use434"
+ style="fill:#ff0000" />
+ <use
+ xlink:href="#glyph-0-5"
+ x="380.336653"
+ y="225.434313"
+ id="use436"
+ style="fill:#ff0000" />
+ <use
+ xlink:href="#glyph-0-2"
+ x="382.396805"
+ y="222.005643"
+ id="use438"
+ style="fill:#ff0000" />
+ <use
+ xlink:href="#glyph-0-5"
+ x="384.456957"
+ y="218.576974"
+ id="use440"
+ style="fill:#ff0000" />
+ <use
+ xlink:href="#glyph-0-1"
+ x="386.51711"
+ y="215.148305"
+ id="use442"
+ style="fill:#ff0000" />
+ </g>
+ <path
+ fill="none"
+ stroke-width="0.5"
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ stroke="rgb(0%, 0%, 0%)"
+ stroke-opacity="1"
+ stroke-miterlimit="10"
+ d="M 17.957031 201.894531 L 17.957031 8.761719 M 13.707031 201.894531 L 17.957031 201.894531 M 13.707031 169.707031 L 17.957031 169.707031 M 13.707031 137.515625 L 17.957031 137.515625 M 13.707031 105.328125 L 17.957031 105.328125 M 13.707031 73.140625 L 17.957031 73.140625 M 13.707031 40.949219 L 17.957031 40.949219 M 13.707031 8.761719 L 17.957031 8.761719 "
+ id="path446" />
+ <g
+ fill="rgb(0%, 0%, 0%)"
+ fill-opacity="1"
+ id="g450">
+ <use
+ xlink:href="#glyph-1-1"
+ x="7.792969"
+ y="204.417969"
+ id="use448" />
+ </g>
+ <g
+ fill="rgb(0%, 0%, 0%)"
+ fill-opacity="1"
+ id="g456">
+ <use
+ xlink:href="#glyph-1-2"
+ x="3.792969"
+ y="172.230469"
+ id="use452" />
+ <use
+ xlink:href="#glyph-1-1"
+ x="7.792969"
+ y="172.230469"
+ id="use454" />
+ </g>
+ <g
+ fill="rgb(0%, 0%, 0%)"
+ fill-opacity="1"
+ id="g462">
+ <use
+ xlink:href="#glyph-1-3"
+ x="3.792969"
+ y="140.039062"
+ id="use458" />
+ <use
+ xlink:href="#glyph-1-1"
+ x="7.792969"
+ y="140.039062"
+ id="use460" />
+ </g>
+ <g
+ fill="rgb(0%, 0%, 0%)"
+ fill-opacity="1"
+ id="g468">
+ <use
+ xlink:href="#glyph-1-4"
+ x="3.792969"
+ y="107.851562"
+ id="use464" />
+ <use
+ xlink:href="#glyph-1-1"
+ x="7.792969"
+ y="107.851562"
+ id="use466" />
+ </g>
+ <g
+ fill="rgb(0%, 0%, 0%)"
+ fill-opacity="1"
+ id="g474">
+ <use
+ xlink:href="#glyph-1-5"
+ x="3.792969"
+ y="75.664062"
+ id="use470" />
+ <use
+ xlink:href="#glyph-1-1"
+ x="7.792969"
+ y="75.664062"
+ id="use472" />
+ </g>
+ <g
+ fill="rgb(0%, 0%, 0%)"
+ fill-opacity="1"
+ id="g480">
+ <use
+ xlink:href="#glyph-1-6"
+ x="3.792969"
+ y="43.472656"
+ id="use476" />
+ <use
+ xlink:href="#glyph-1-1"
+ x="7.792969"
+ y="43.472656"
+ id="use478" />
+ </g>
+ <g
+ fill="rgb(0%, 0%, 0%)"
+ fill-opacity="1"
+ id="g486">
+ <use
+ xlink:href="#glyph-1-7"
+ x="3.792969"
+ y="11.285156"
+ id="use482" />
+ <use
+ xlink:href="#glyph-1-1"
+ x="7.792969"
+ y="11.285156"
+ id="use484" />
+ </g>
+ <g
+ clip-path="url(#clip-0)"
+ id="g490">
+ <path
+ fill-rule="nonzero"
+ fill="rgb(2.352941%, 60.392157%, 18.039216%)"
+ fill-opacity="1"
+ d="M 17.957031 195.457031 L 26.953125 201.894531 L 35.945312 195.457031 L 44.9375 185.800781 L 53.929688 198.675781 L 62.925781 185.800781 L 71.917969 201.894531 L 80.910156 198.675781 L 89.902344 201.894531 L 98.894531 198.675781 L 107.890625 147.171875 L 116.882812 169.707031 L 125.875 163.265625 L 134.867188 195.457031 L 143.859375 185.800781 L 152.855469 185.800781 L 161.847656 111.765625 L 170.839844 131.078125 L 179.832031 169.707031 L 188.828125 189.019531 L 197.820312 166.484375 L 206.8125 201.894531 L 215.804688 124.640625 L 224.796875 150.390625 L 233.792969 156.828125 L 242.785156 150.390625 L 251.777344 111.765625 L 260.769531 108.546875 L 269.761719 89.234375 L 278.757812 201.894531 L 287.75 201.894531 L 296.742188 198.675781 L 305.734375 156.828125 L 314.730469 124.640625 L 323.722656 105.328125 L 332.714844 127.859375 L 341.707031 176.144531 L 350.699219 160.046875 L 359.695312 166.484375 L 368.6875 195.457031 L 377.679688 189.019531 L 377.679688 201.894531 L 17.957031 201.894531 Z M 17.957031 195.457031 "
+ id="path488" />
+ </g>
+ <g
+ clip-path="url(#clip-1)"
+ id="g494">
+ <path
+ fill="none"
+ stroke-width="0.5"
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ stroke="rgb(0%, 0%, 0%)"
+ stroke-opacity="1"
+ stroke-miterlimit="10"
+ d="M 17.957031 201.894531 L 377.679688 201.894531 "
+ id="path492" />
+ </g>
+ <g
+ clip-path="url(#clip-2)"
+ id="g498">
+ <path
+ fill="none"
+ stroke-width="0.5"
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ stroke="rgb(0%, 0%, 0%)"
+ stroke-opacity="1"
+ stroke-miterlimit="10"
+ d="M 17.957031 195.457031 L 26.953125 201.894531 L 35.945312 195.457031 L 44.9375 185.800781 L 53.929688 198.675781 L 62.925781 185.800781 L 71.917969 201.894531 L 80.910156 198.675781 L 89.902344 201.894531 L 98.894531 198.675781 L 107.890625 147.171875 L 116.882812 169.707031 L 125.875 163.265625 L 134.867188 195.457031 L 143.859375 185.800781 L 152.855469 185.800781 L 161.847656 111.765625 L 170.839844 131.078125 L 179.832031 169.707031 L 188.828125 189.019531 L 197.820312 166.484375 L 206.8125 201.894531 L 215.804688 124.640625 L 224.796875 150.390625 L 233.792969 156.828125 L 242.785156 150.390625 L 251.777344 111.765625 L 260.769531 108.546875 L 269.761719 89.234375 L 278.757812 201.894531 L 287.75 201.894531 L 296.742188 198.675781 L 305.734375 156.828125 L 314.730469 124.640625 L 323.722656 105.328125 L 332.714844 127.859375 L 341.707031 176.144531 L 350.699219 160.046875 L 359.695312 166.484375 L 368.6875 195.457031 L 377.679688 189.019531 "
+ id="path496" />
+ </g>
+ <g
+ clip-path="url(#clip-3)"
+ id="g502">
+ <path
+ fill-rule="nonzero"
+ fill="rgb(100%, 50.196078%, 0%)"
+ fill-opacity="1"
+ d="M 17.957031 189.019531 L 26.953125 150.390625 L 35.945312 124.640625 L 44.9375 172.925781 L 53.929688 189.019531 L 62.925781 176.144531 L 71.917969 195.457031 L 80.910156 182.582031 L 89.902344 163.265625 L 98.894531 179.363281 L 107.890625 137.515625 L 116.882812 124.640625 L 125.875 134.296875 L 134.867188 189.019531 L 143.859375 185.800781 L 152.855469 176.144531 L 161.847656 105.328125 L 170.839844 127.859375 L 179.832031 156.828125 L 188.828125 189.019531 L 197.820312 160.046875 L 206.8125 176.144531 L 215.804688 108.546875 L 224.796875 108.546875 L 233.792969 143.953125 L 242.785156 121.421875 L 251.777344 76.359375 L 260.769531 86.015625 L 269.761719 28.074219 L 278.757812 198.675781 L 296.742188 198.675781 L 305.734375 131.078125 L 314.730469 114.984375 L 323.722656 69.921875 L 332.714844 63.484375 L 341.707031 176.144531 L 350.699219 153.609375 L 359.695312 147.171875 L 368.6875 192.238281 L 377.679688 179.363281 L 377.679688 189.019531 L 368.6875 195.457031 L 359.695312 166.484375 L 350.699219 160.046875 L 341.707031 176.144531 L 332.714844 127.859375 L 323.722656 105.328125 L 314.730469 124.640625 L 305.734375 156.828125 L 296.742188 198.675781 L 287.75 201.894531 L 278.757812 201.894531 L 269.761719 89.234375 L 260.769531 108.546875 L 251.777344 111.765625 L 242.785156 150.390625 L 233.792969 156.828125 L 224.796875 150.390625 L 215.804688 124.640625 L 206.8125 201.894531 L 197.820312 166.484375 L 188.828125 189.019531 L 179.832031 169.707031 L 170.839844 131.078125 L 161.847656 111.765625 L 152.855469 185.800781 L 143.859375 185.800781 L 134.867188 195.457031 L 125.875 163.265625 L 116.882812 169.707031 L 107.890625 147.171875 L 98.894531 198.675781 L 89.902344 201.894531 L 80.910156 198.675781 L 71.917969 201.894531 L 62.925781 185.800781 L 53.929688 198.675781 L 44.9375 185.800781 L 35.945312 195.457031 L 26.953125 201.894531 L 17.957031 195.457031 Z M 17.957031 189.019531 "
+ id="path500" />
+ </g>
+ <g
+ clip-path="url(#clip-4)"
+ id="g506">
+ <path
+ fill="none"
+ stroke-width="0.5"
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ stroke="rgb(0%, 0%, 0%)"
+ stroke-opacity="1"
+ stroke-miterlimit="10"
+ d="M 17.957031 195.457031 L 26.953125 201.894531 L 35.945312 195.457031 L 44.9375 185.800781 L 53.929688 198.675781 L 62.925781 185.800781 L 71.917969 201.894531 L 80.910156 198.675781 L 89.902344 201.894531 L 98.894531 198.675781 L 107.890625 147.171875 L 116.882812 169.707031 L 125.875 163.265625 L 134.867188 195.457031 L 143.859375 185.800781 L 152.855469 185.800781 L 161.847656 111.765625 L 170.839844 131.078125 L 179.832031 169.707031 L 188.828125 189.019531 L 197.820312 166.484375 L 206.8125 201.894531 L 215.804688 124.640625 L 224.796875 150.390625 L 233.792969 156.828125 L 242.785156 150.390625 L 251.777344 111.765625 L 260.769531 108.546875 L 269.761719 89.234375 L 278.757812 201.894531 L 287.75 201.894531 L 296.742188 198.675781 L 305.734375 156.828125 L 314.730469 124.640625 L 323.722656 105.328125 L 332.714844 127.859375 L 341.707031 176.144531 L 350.699219 160.046875 L 359.695312 166.484375 L 368.6875 195.457031 L 377.679688 189.019531 "
+ id="path504" />
+ </g>
+ <g
+ clip-path="url(#clip-5)"
+ id="g510">
+ <path
+ fill="none"
+ stroke-width="0.5"
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ stroke="rgb(0%, 0%, 0%)"
+ stroke-opacity="1"
+ stroke-miterlimit="10"
+ d="M 17.957031 189.019531 L 26.953125 150.390625 L 35.945312 124.640625 L 44.9375 172.925781 L 53.929688 189.019531 L 62.925781 176.144531 L 71.917969 195.457031 L 80.910156 182.582031 L 89.902344 163.265625 L 98.894531 179.363281 L 107.890625 137.515625 L 116.882812 124.640625 L 125.875 134.296875 L 134.867188 189.019531 L 143.859375 185.800781 L 152.855469 176.144531 L 161.847656 105.328125 L 170.839844 127.859375 L 179.832031 156.828125 L 188.828125 189.019531 L 197.820312 160.046875 L 206.8125 176.144531 L 215.804688 108.546875 L 224.796875 108.546875 L 233.792969 143.953125 L 242.785156 121.421875 L 251.777344 76.359375 L 260.769531 86.015625 L 269.761719 28.074219 L 278.757812 198.675781 L 296.742188 198.675781 L 305.734375 131.078125 L 314.730469 114.984375 L 323.722656 69.921875 L 332.714844 63.484375 L 341.707031 176.144531 L 350.699219 153.609375 L 359.695312 147.171875 L 368.6875 192.238281 L 377.679688 179.363281 "
+ id="path508" />
+ </g>
+ <g
+ clip-path="url(#clip-6)"
+ id="g514">
+ <path
+ fill-rule="nonzero"
+ fill="rgb(0%, 51.764706%, 81.960784%)"
+ fill-opacity="1"
+ d="M 17.957031 189.019531 L 26.953125 150.390625 L 35.945312 124.640625 L 44.9375 172.925781 L 53.929688 189.019531 L 62.925781 176.144531 L 71.917969 195.457031 L 80.910156 182.582031 L 89.902344 163.265625 L 98.894531 179.363281 L 107.890625 137.515625 L 116.882812 124.640625 L 125.875 134.296875 L 134.867188 189.019531 L 143.859375 185.800781 L 152.855469 176.144531 L 161.847656 105.328125 L 170.839844 127.859375 L 179.832031 156.828125 L 188.828125 189.019531 L 197.820312 160.046875 L 206.8125 176.144531 L 215.804688 108.546875 L 224.796875 108.546875 L 233.792969 143.953125 L 242.785156 121.421875 L 251.777344 60.265625 L 260.769531 37.730469 L 269.761719 11.980469 L 278.757812 198.675781 L 296.742188 198.675781 L 305.734375 131.078125 L 314.730469 114.984375 L 323.722656 69.921875 L 332.714844 63.484375 L 341.707031 176.144531 L 350.699219 140.734375 L 359.695312 137.515625 L 368.6875 172.925781 L 377.679688 179.363281 L 386.671875 169.707031 L 386.671875 201.894531 L 377.679688 201.894531 L 377.679688 179.363281 L 368.6875 192.238281 L 359.695312 147.171875 L 350.699219 153.609375 L 341.707031 176.144531 L 332.714844 63.484375 L 323.722656 69.921875 L 314.730469 114.984375 L 305.734375 131.078125 L 296.742188 198.675781 L 278.757812 198.675781 L 269.761719 28.074219 L 260.769531 86.015625 L 251.777344 76.359375 L 242.785156 121.421875 L 233.792969 143.953125 L 224.796875 108.546875 L 215.804688 108.546875 L 206.8125 176.144531 L 197.820312 160.046875 L 188.828125 189.019531 L 179.832031 156.828125 L 170.839844 127.859375 L 161.847656 105.328125 L 152.855469 176.144531 L 143.859375 185.800781 L 134.867188 189.019531 L 125.875 134.296875 L 116.882812 124.640625 L 107.890625 137.515625 L 98.894531 179.363281 L 89.902344 163.265625 L 80.910156 182.582031 L 71.917969 195.457031 L 62.925781 176.144531 L 53.929688 189.019531 L 44.9375 172.925781 L 35.945312 124.640625 L 26.953125 150.390625 Z M 17.957031 189.019531 "
+ id="path512" />
+ </g>
+ <g
+ clip-path="url(#clip-7)"
+ id="g518">
+ <path
+ fill="none"
+ stroke-width="0.5"
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ stroke="rgb(0%, 0%, 0%)"
+ stroke-opacity="1"
+ stroke-miterlimit="10"
+ d="M 17.957031 189.019531 L 26.953125 150.390625 L 35.945312 124.640625 L 44.9375 172.925781 L 53.929688 189.019531 L 62.925781 176.144531 L 71.917969 195.457031 L 80.910156 182.582031 L 89.902344 163.265625 L 98.894531 179.363281 L 107.890625 137.515625 L 116.882812 124.640625 L 125.875 134.296875 L 134.867188 189.019531 L 143.859375 185.800781 L 152.855469 176.144531 L 161.847656 105.328125 L 170.839844 127.859375 L 179.832031 156.828125 L 188.828125 189.019531 L 197.820312 160.046875 L 206.8125 176.144531 L 215.804688 108.546875 L 224.796875 108.546875 L 233.792969 143.953125 L 242.785156 121.421875 L 251.777344 76.359375 L 260.769531 86.015625 L 269.761719 28.074219 L 278.757812 198.675781 L 296.742188 198.675781 L 305.734375 131.078125 L 314.730469 114.984375 L 323.722656 69.921875 L 332.714844 63.484375 L 341.707031 176.144531 L 350.699219 153.609375 L 359.695312 147.171875 L 368.6875 192.238281 L 377.679688 179.363281 M 377.679688 201.894531 L 386.671875 201.894531 "
+ id="path516" />
+ </g>
+ <g
+ clip-path="url(#clip-8)"
+ id="g522">
+ <path
+ fill="none"
+ stroke-width="0.5"
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ stroke="rgb(0%, 0%, 0%)"
+ stroke-opacity="1"
+ stroke-miterlimit="10"
+ d="M 17.957031 189.019531 L 26.953125 150.390625 L 35.945312 124.640625 L 44.9375 172.925781 L 53.929688 189.019531 L 62.925781 176.144531 L 71.917969 195.457031 L 80.910156 182.582031 L 89.902344 163.265625 L 98.894531 179.363281 L 107.890625 137.515625 L 116.882812 124.640625 L 125.875 134.296875 L 134.867188 189.019531 L 143.859375 185.800781 L 152.855469 176.144531 L 161.847656 105.328125 L 170.839844 127.859375 L 179.832031 156.828125 L 188.828125 189.019531 L 197.820312 160.046875 L 206.8125 176.144531 L 215.804688 108.546875 L 224.796875 108.546875 L 233.792969 143.953125 L 242.785156 121.421875 L 251.777344 60.265625 L 260.769531 37.730469 L 269.761719 11.980469 L 278.757812 198.675781 L 296.742188 198.675781 L 305.734375 131.078125 L 314.730469 114.984375 L 323.722656 69.921875 L 332.714844 63.484375 L 341.707031 176.144531 L 350.699219 140.734375 L 359.695312 137.515625 L 368.6875 172.925781 L 377.679688 179.363281 L 386.671875 169.707031 "
+ id="path520" />
+ </g>
+ <path
+ fill-rule="nonzero"
+ fill="rgb(100%, 100%, 100%)"
+ fill-opacity="1"
+ stroke-width="0.5"
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ stroke="rgb(0%, 0%, 0%)"
+ stroke-opacity="1"
+ stroke-miterlimit="10"
+ d="M 394.96875 105.558594 L 465.054688 105.558594 L 465.054688 141.941406 L 394.96875 141.941406 Z M 394.96875 105.558594 "
+ id="path524" />
+ <path
+ fill-rule="nonzero"
+ fill="rgb(0%, 51.764706%, 81.960784%)"
+ fill-opacity="1"
+ d="M 399.011719 110.398438 L 406.511719 110.398438 L 406.511719 117.898438 L 399.011719 117.898438 Z M 399.011719 110.398438 "
+ id="path526" />
+ <g
+ clip-path="url(#clip-9)"
+ id="g530">
+ <path
+ fill="none"
+ stroke-width="0.5"
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ stroke="rgb(0%, 0%, 0%)"
+ stroke-opacity="1"
+ stroke-miterlimit="10"
+ d="M 399.011719 110.398438 L 406.511719 110.398438 L 406.511719 117.898438 L 399.011719 117.898438 Z M 399.011719 110.398438 "
+ id="path528" />
+ </g>
+ <g
+ fill="rgb(0%, 0%, 0%)"
+ fill-opacity="1"
+ id="g544">
+ <use
+ xlink:href="#glyph-1-8"
+ x="410.761719"
+ y="116.671875"
+ id="use532" />
+ <use
+ xlink:href="#glyph-1-9"
+ x="416.761719"
+ y="116.671875"
+ id="use534" />
+ <use
+ xlink:href="#glyph-1-10"
+ x="422.761719"
+ y="116.671875"
+ id="use536" />
+ <use
+ xlink:href="#glyph-1-11"
+ x="428.761719"
+ y="116.671875"
+ id="use538" />
+ <use
+ xlink:href="#glyph-1-12"
+ x="433.761719"
+ y="116.671875"
+ id="use540" />
+ <use
+ xlink:href="#glyph-1-13"
+ x="438.761719"
+ y="116.671875"
+ id="use542" />
+ </g>
+ <path
+ fill-rule="nonzero"
+ fill="rgb(100%, 50.196078%, 0%)"
+ fill-opacity="1"
+ d="M 399.011719 120 L 406.511719 120 L 406.511719 127.5 L 399.011719 127.5 Z M 399.011719 120 "
+ id="path546" />
+ <g
+ clip-path="url(#clip-10)"
+ id="g550">
+ <path
+ fill="none"
+ stroke-width="0.5"
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ stroke="rgb(0%, 0%, 0%)"
+ stroke-opacity="1"
+ stroke-miterlimit="10"
+ d="M 399.011719 120 L 406.511719 120 L 406.511719 127.5 L 399.011719 127.5 Z M 399.011719 120 "
+ id="path548" />
+ </g>
+ <g
+ fill="rgb(0%, 0%, 0%)"
+ fill-opacity="1"
+ id="g570">
+ <use
+ xlink:href="#glyph-1-8"
+ x="410.761719"
+ y="126.273438"
+ id="use552" />
+ <use
+ xlink:href="#glyph-1-14"
+ x="416.761719"
+ y="126.273438"
+ id="use554" />
+ <use
+ xlink:href="#glyph-1-15"
+ x="421.761719"
+ y="126.273438"
+ id="use556" />
+ <use
+ xlink:href="#glyph-1-16"
+ x="426.761719"
+ y="126.273438"
+ id="use558" />
+ <use
+ xlink:href="#glyph-1-17"
+ x="432.761719"
+ y="126.273438"
+ id="use560" />
+ <use
+ xlink:href="#glyph-1-9"
+ x="437.761719"
+ y="126.273438"
+ id="use562" />
+ <use
+ xlink:href="#glyph-1-14"
+ x="443.761719"
+ y="126.273438"
+ id="use564" />
+ <use
+ xlink:href="#glyph-1-13"
+ x="448.761719"
+ y="126.273438"
+ id="use566" />
+ <use
+ xlink:href="#glyph-1-8"
+ x="454.761719"
+ y="126.273438"
+ id="use568" />
+ </g>
+ <path
+ fill-rule="nonzero"
+ fill="rgb(2.352941%, 60.392157%, 18.039216%)"
+ fill-opacity="1"
+ d="M 399.011719 129.601562 L 406.511719 129.601562 L 406.511719 137.101562 L 399.011719 137.101562 Z M 399.011719 129.601562 "
+ id="path572" />
+ <g
+ clip-path="url(#clip-11)"
+ id="g576">
+ <path
+ fill="none"
+ stroke-width="0.5"
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ stroke="rgb(0%, 0%, 0%)"
+ stroke-opacity="1"
+ stroke-miterlimit="10"
+ d="M 399.011719 129.601562 L 406.511719 129.601562 L 406.511719 137.101562 L 399.011719 137.101562 Z M 399.011719 129.601562 "
+ id="path574" />
+ </g>
+ <g
+ fill="rgb(0%, 0%, 0%)"
+ fill-opacity="1"
+ id="g590">
+ <use
+ xlink:href="#glyph-1-15"
+ x="410.761719"
+ y="135.875"
+ id="use578" />
+ <use
+ xlink:href="#glyph-1-12"
+ x="415.761719"
+ y="135.875"
+ id="use580" />
+ <use
+ xlink:href="#glyph-1-13"
+ x="420.761719"
+ y="135.875"
+ id="use582" />
+ <use
+ xlink:href="#glyph-1-18"
+ x="426.761719"
+ y="135.875"
+ id="use584" />
+ <use
+ xlink:href="#glyph-1-12"
+ x="431.761719"
+ y="135.875"
+ id="use586" />
+ <use
+ xlink:href="#glyph-1-13"
+ x="436.761719"
+ y="135.875"
+ id="use588" />
+ </g>
+ <path
+ style="fill:#000000;stroke:#000000;stroke-width:1.6;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ d="m 269.76172,8.761719 0,193.132811"
+ id="path1081"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:#c83737;stroke:#000000;stroke-width:1.6;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ d="M 332.71484,8.761723 V 201.89453"
+ id="path1081-3"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:#c83737;stroke:#000000;stroke-width:1.6;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ d="M 386.92187,8.814386 V 201.94719"
+ id="path1081-3-6"
+ sodipodi:nodetypes="cc" />
+ <text
+ xml:space="preserve"
+ style="font-size:8px;line-height:0.85;font-family:sans-serif;fill:#000000"
+ x="-198.40245"
+ y="266.31934"
+ id="text12489"
+ transform="rotate(-90)"><tspan
+ sodipodi:role="line"
+ id="tspan12487"
+ x="-198.40245"
+ y="266.31934"
+ style="font-size:8px;fill:#000000">Implementierungsphase</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:8px;line-height:0.85;font-family:sans-serif;fill:#000000"
+ x="-199.17578"
+ y="328.75073"
+ id="text12489-3"
+ transform="rotate(-90)"><tspan
+ sodipodi:role="line"
+ id="tspan12487-6"
+ x="-199.17578"
+ y="328.75073"
+ style="font-size:8px;fill:#000000">Qualitätssicherung</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:8px;line-height:0.85;font-family:sans-serif;fill:#000000"
+ x="-198.50244"
+ y="384.32617"
+ id="text12489-3-0"
+ transform="rotate(-90)"><tspan
+ sodipodi:role="line"
+ x="-198.50244"
+ y="384.32617"
+ style="font-size:8px;fill:#000000"
+ id="tspan12595">Abnahme</tspan></text>
+</svg>
diff --git a/40-abschlusspraesentation/assets/component6.drawio b/40-abschlusspraesentation/assets/component6.drawio
new file mode 100644
index 0000000..a4de93a
--- /dev/null
+++ b/40-abschlusspraesentation/assets/component6.drawio
@@ -0,0 +1,114 @@
+<mxfile host="app.diagrams.net" modified="2023-03-30T22:57:44.487Z" agent="Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/111.0" etag="H3OuyL8X3I4HUZeSuPEp" version="21.1.2" type="device">
+ <diagram name="Seite-1" id="XfYHgy5avJqr8EgWlpBP">
+ <mxGraphModel dx="260" dy="334" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
+ <root>
+ <mxCell id="0" />
+ <mxCell id="1" parent="0" />
+ <mxCell id="xGkIlv-mTJFvFgtXs7Zm-36" value="" style="shape=module;align=left;spacingLeft=20;align=center;verticalAlign=top;whiteSpace=wrap;html=1;fillColor=#f5f5f5;fontColor=#333333;strokeColor=#666666;" parent="1" vertex="1">
+ <mxGeometry x="600" y="258" width="110" height="62" as="geometry" />
+ </mxCell>
+ <mxCell id="xGkIlv-mTJFvFgtXs7Zm-35" value="Podcatcher" style="shape=module;align=left;spacingLeft=20;align=center;verticalAlign=top;whiteSpace=wrap;html=1;fillColor=#f5f5f5;fontColor=#333333;strokeColor=#666666;" parent="1" vertex="1">
+ <mxGeometry x="605" y="370" width="100" height="59" as="geometry" />
+ </mxCell>
+ <mxCell id="xGkIlv-mTJFvFgtXs7Zm-34" value="" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
+ <mxGeometry x="440" y="230" width="140" height="200" as="geometry" />
+ </mxCell>
+ <mxCell id="xGkIlv-mTJFvFgtXs7Zm-5" value="" style="rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=none;endFill=0;sketch=0;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;exitX=0.442;exitY=1.006;exitDx=0;exitDy=0;exitPerimeter=0;" parent="1" source="xGkIlv-mTJFvFgtXs7Zm-36" target="xGkIlv-mTJFvFgtXs7Zm-7" edge="1">
+ <mxGeometry relative="1" as="geometry">
+ <mxPoint x="643" y="312" as="sourcePoint" />
+ <mxPoint x="643.6398566881776" y="322.04111066662256" as="targetPoint" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="xGkIlv-mTJFvFgtXs7Zm-6" value="" style="rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=halfCircle;endFill=0;entryX=0.5;entryY=0.5;endSize=6;strokeWidth=1;sketch=0;fillColor=#f0a30a;strokeColor=#BD7000;exitX=0.105;exitY=0.848;exitDx=0;exitDy=0;exitPerimeter=0;" parent="1" source="xGkIlv-mTJFvFgtXs7Zm-9" target="xGkIlv-mTJFvFgtXs7Zm-7" edge="1">
+ <mxGeometry relative="1" as="geometry">
+ <mxPoint x="380" y="361" as="sourcePoint" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="xGkIlv-mTJFvFgtXs7Zm-7" value="" style="ellipse;whiteSpace=wrap;html=1;align=center;aspect=fixed;resizable=0;points=[];outlineConnect=0;sketch=0;" parent="1" vertex="1">
+ <mxGeometry x="643.75" y="330" width="10" height="10" as="geometry" />
+ </mxCell>
+ <mxCell id="xGkIlv-mTJFvFgtXs7Zm-8" value="Podcast-Server" style="shape=module;align=left;spacingLeft=20;align=center;verticalAlign=top;whiteSpace=wrap;html=1;fillColor=#f5f5f5;fontColor=#333333;strokeColor=#666666;" parent="1" vertex="1">
+ <mxGeometry x="589" y="248" width="111" height="62" as="geometry" />
+ </mxCell>
+ <mxCell id="xGkIlv-mTJFvFgtXs7Zm-9" value="&lt;div align=&quot;left&quot;&gt;Sync-Server&lt;br&gt;&lt;/div&gt;" style="shape=module;align=left;spacingLeft=20;align=center;verticalAlign=top;whiteSpace=wrap;html=1;fillColor=#ffcc99;strokeColor=#36393d;" parent="1" vertex="1">
+ <mxGeometry x="470.91999999999996" y="258.5" width="90" height="61" as="geometry" />
+ </mxCell>
+ <mxCell id="xGkIlv-mTJFvFgtXs7Zm-10" value="Web-Dashboard" style="shape=module;align=left;spacingLeft=20;align=center;verticalAlign=top;whiteSpace=wrap;html=1;fillColor=#cdeb8b;strokeColor=#36393d;" parent="1" vertex="1">
+ <mxGeometry x="459" y="360.67" width="110" height="59" as="geometry" />
+ </mxCell>
+ <mxCell id="xGkIlv-mTJFvFgtXs7Zm-11" value="Podcatcher" style="shape=module;align=left;spacingLeft=20;align=center;verticalAlign=top;whiteSpace=wrap;html=1;fillColor=#f5f5f5;fontColor=#333333;strokeColor=#666666;" parent="1" vertex="1">
+ <mxGeometry x="595" y="360" width="100" height="59" as="geometry" />
+ </mxCell>
+ <mxCell id="xGkIlv-mTJFvFgtXs7Zm-13" value="&lt;div&gt;RSS-Feed&lt;/div&gt;" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
+ <mxGeometry x="655" y="318.5" width="60" height="30" as="geometry" />
+ </mxCell>
+ <mxCell id="xGkIlv-mTJFvFgtXs7Zm-16" value="" style="ellipse;whiteSpace=wrap;html=1;align=center;aspect=fixed;resizable=0;points=[];outlineConnect=0;sketch=0;fillColor=#ffe6cc;strokeColor=#d79b00;" parent="1" vertex="1">
+ <mxGeometry x="515.23" y="330" width="10" height="10" as="geometry" />
+ </mxCell>
+ <mxCell id="xGkIlv-mTJFvFgtXs7Zm-19" value="" style="rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=halfCircle;endFill=0;endSize=6;strokeWidth=1;sketch=0;fillColor=#d5e8d4;strokeColor=#82b366;exitX=0.554;exitY=-0.006;exitDx=0;exitDy=0;exitPerimeter=0;" parent="1" source="xGkIlv-mTJFvFgtXs7Zm-10" target="xGkIlv-mTJFvFgtXs7Zm-16" edge="1">
+ <mxGeometry relative="1" as="geometry">
+ <mxPoint x="520" y="360" as="sourcePoint" />
+ <mxPoint x="442.57375746718986" y="349.9982618621103" as="targetPoint" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="xGkIlv-mTJFvFgtXs7Zm-17" value="" style="rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=halfCircle;endFill=0;endSize=6;strokeWidth=1;sketch=0;exitX=0.25;exitY=0;exitDx=0;exitDy=0;" parent="1" source="xGkIlv-mTJFvFgtXs7Zm-11" target="xGkIlv-mTJFvFgtXs7Zm-16" edge="1">
+ <mxGeometry relative="1" as="geometry">
+ <mxPoint x="281.17" y="709.5" as="sourcePoint" />
+ <mxPoint x="455.9957655924505" y="516.7807582209869" as="targetPoint" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="xGkIlv-mTJFvFgtXs7Zm-20" value="GPodder-API" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
+ <mxGeometry x="435.23" y="320" width="84" height="30" as="geometry" />
+ </mxCell>
+ <mxCell id="xGkIlv-mTJFvFgtXs7Zm-21" value="" style="shape=image;verticalLabelPosition=bottom;labelBackgroundColor=default;verticalAlign=top;aspect=fixed;imageAspect=0;image=data:image/svg+xml,PHN2ZyB2aWV3Qm94PSIwIDAgNDQ4IDUxMiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMzE5LjQgMzcyYzQ4LjUtMzEuMyA4MC42LTg1LjkgODAuNi0xNDhjMC05Ny4yLTc4LjgtMTc2LTE3Ni0xNzZTNDggMTI2LjggNDggMjI0YzAgNjIuMSAzMi4xIDExNi42IDgwLjYgMTQ4YzEuMiAxNy4zIDQgMzggNy4yIDU3LjFsLjIgMUM1NiAzOTUuOCAwIDMxNi41IDAgMjI0QzAgMTAwLjMgMTAwLjMgMCAyMjQgMFM0NDggMTAwLjMgNDQ4IDIyNGMwIDkyLjUtNTYgMTcxLjktMTM2IDIwNi4xbC4yLTEuMWMzLjEtMTkuMiA2LTM5LjggNy4yLTU3em0tMi4zLTM4LjFjLTEuNi01LjctMy45LTExLjEtNy0xNi4yYy01LjgtOS43LTEzLjUtMTctMjEuOS0yMi40YzE5LjUtMTcuNiAzMS44LTQzIDMxLjgtNzEuM2MwLTUzLTQzLTk2LTk2LTk2cy05NiA0My05NiA5NmMwIDI4LjMgMTIuMyA1My44IDMxLjggNzEuM2MtOC40IDUuNC0xNi4xIDEyLjctMjEuOSAyMi40Yy0zLjEgNS4xLTUuNCAxMC41LTcgMTYuMkM5OS44IDMwNy41IDgwIDI2OCA4MCAyMjRjMC03OS41IDY0LjUtMTQ0IDE0NC0xNDRzMTQ0IDY0LjUgMTQ0IDE0NGMwIDQ0LTE5LjggODMuNS01MC45IDEwOS45ek0yMjQgMzEyYzMyLjkgMCA2NCA4LjYgNjQgNDMuOGMwIDMzLTEyLjkgMTA0LjEtMjAuNiAxMzIuOWMtNS4xIDE5LTI0LjUgMjMuNC00My40IDIzLjRzLTM4LjItNC40LTQzLjQtMjMuNGMtNy44LTI4LjUtMjAuNi05OS43LTIwLjYtMTMyLjhjMC0zNS4xIDMxLjEtNDMuOCA2NC00My44em0wLTE0NGE1NiA1NiAwIDEgMSAwIDExMiA1NiA1NiAwIDEgMSAwLTExMnoiLz48L3N2Zz4=;opacity=50;" parent="1" vertex="1">
+ <mxGeometry x="632" y="269" width="35" height="40" as="geometry" />
+ </mxCell>
+ <mxCell id="xGkIlv-mTJFvFgtXs7Zm-22" value="" style="shape=image;verticalLabelPosition=bottom;labelBackgroundColor=default;verticalAlign=top;aspect=fixed;imageAspect=0;image=data:image/svg+xml,PHN2ZyB2aWV3Qm94PSIwIDAgNTEyIDUxMiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMTQyLjkgMTQyLjljNjIuMi02Mi4yIDE2Mi43LTYyLjUgMjI1LjMtMUwzMjcgMTgzYy02LjkgNi45LTguOSAxNy4yLTUuMiAyNi4yczEyLjUgMTQuOCAyMi4yIDE0LjhINDYzLjVjMCAwIDAgMCAwIDBINDcyYzEzLjMgMCAyNC0xMC43IDI0LTI0VjcyYzAtOS43LTUuOC0xOC41LTE0LjgtMjIuMnMtMTkuMy0xLjctMjYuMiA1LjJMNDEzLjQgOTYuNmMtODcuNi04Ni41LTIyOC43LTg2LjItMzE1LjggMUM3My4yIDEyMiA1NS42IDE1MC43IDQ0LjggMTgxLjRjLTUuOSAxNi43IDIuOSAzNC45IDE5LjUgNDAuOHMzNC45LTIuOSA0MC44LTE5LjVjNy43LTIxLjggMjAuMi00Mi4zIDM3LjgtNTkuOHpNMTYgMzEydjcuNiAuN1Y0NDBjMCA5LjcgNS44IDE4LjUgMTQuOCAyMi4yczE5LjMgMS43IDI2LjItNS4ybDQxLjYtNDEuNmM4Ny42IDg2LjUgMjI4LjcgODYuMiAzMTUuOC0xYzI0LjQtMjQuNCA0Mi4xLTUzLjEgNTIuOS04My43YzUuOS0xNi43LTIuOS0zNC45LTE5LjUtNDAuOHMtMzQuOSAyLjktNDAuOCAxOS41Yy03LjcgMjEuOC0yMC4yIDQyLjMtMzcuOCA1OS44Yy02Mi4yIDYyLjItMTYyLjcgNjIuNS0yMjUuMyAxTDE4NSAzMjljNi45LTYuOSA4LjktMTcuMiA1LjItMjYuMnMtMTIuNS0xNC44LTIyLjItMTQuOEg0OC40aC0uN0g0MGMtMTMuMyAwLTI0IDEwLjctMjQgMjR6Ii8+PC9zdmc+;imageBackground=none;" parent="1" vertex="1">
+ <mxGeometry x="500.23" y="278.5" width="40" height="40" as="geometry" />
+ </mxCell>
+ <mxCell id="xGkIlv-mTJFvFgtXs7Zm-23" value="" style="shape=image;verticalLabelPosition=bottom;labelBackgroundColor=default;verticalAlign=top;aspect=fixed;imageAspect=0;image=data:image/svg+xml,PHN2ZyB2aWV3Qm94PSIwIDAgNTc2IDUxMiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNNjQgMEMyOC43IDAgMCAyOC43IDAgNjRWMzUyYzAgMzUuMyAyOC43IDY0IDY0IDY0SDI0MGwtMTAuNyAzMkgxNjBjLTE3LjcgMC0zMiAxNC4zLTMyIDMyczE0LjMgMzIgMzIgMzJINDE2YzE3LjcgMCAzMi0xNC4zIDMyLTMycy0xNC4zLTMyLTMyLTMySDM0Ni43TDMzNiA0MTZINTEyYzM1LjMgMCA2NC0yOC43IDY0LTY0VjY0YzAtMzUuMy0yOC43LTY0LTY0LTY0SDY0ek01MTIgNjRWMjg4SDY0VjY0SDUxMnoiLz48L3N2Zz4=;" parent="1" vertex="1">
+ <mxGeometry x="503.03999999999996" y="384.16999999999996" width="33.77" height="30" as="geometry" />
+ </mxCell>
+ <mxCell id="xGkIlv-mTJFvFgtXs7Zm-25" value="" style="rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=none;endFill=0;sketch=0;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;fillColor=#ffe6cc;strokeColor=#d79b00;" parent="1" edge="1">
+ <mxGeometry relative="1" as="geometry">
+ <mxPoint x="520" y="320" as="sourcePoint" />
+ <mxPoint x="520" y="330" as="targetPoint" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="xGkIlv-mTJFvFgtXs7Zm-26" value="" style="shape=image;verticalLabelPosition=bottom;labelBackgroundColor=default;verticalAlign=top;aspect=fixed;imageAspect=0;image=data:image/svg+xml,PHN2ZyB2aWV3Qm94PSIwIDAgNTEyIDUxMiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMjU2IDgwQzE0MS4xIDgwIDQ4IDE3My4xIDQ4IDI4OFYzOTJjMCAxMy4zLTEwLjcgMjQtMjQgMjRzLTI0LTEwLjctMjQtMjRWMjg4QzAgMTQ2LjYgMTE0LjYgMzIgMjU2IDMyczI1NiAxMTQuNiAyNTYgMjU2VjM5MmMwIDEzLjMtMTAuNyAyNC0yNCAyNHMtMjQtMTAuNy0yNC0yNFYyODhjMC0xMTQuOS05My4xLTIwOC0yMDgtMjA4ek04MCAzNTJjMC0zNS4zIDI4LjctNjQgNjQtNjRoMTZjMTcuNyAwIDMyIDE0LjMgMzIgMzJWNDQ4YzAgMTcuNy0xNC4zIDMyLTMyIDMySDE0NGMtMzUuMyAwLTY0LTI4LjctNjQtNjRWMzUyem0yODgtNjRjMzUuMyAwIDY0IDI4LjcgNjQgNjR2NjRjMCAzNS4zLTI4LjcgNjQtNjQgNjRIMzUyYy0xNy43IDAtMzItMTQuMy0zMi0zMlYzMjBjMC0xNy43IDE0LjMtMzIgMzItMzJoMTZ6Ii8+PC9zdmc+;opacity=50;" parent="1" vertex="1">
+ <mxGeometry x="638" y="378.5" width="33.5" height="33.5" as="geometry" />
+ </mxCell>
+ <mxCell id="xGkIlv-mTJFvFgtXs7Zm-30" value="" style="rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=halfCircle;endFill=0;endSize=6;strokeWidth=1;sketch=0;exitX=0.536;exitY=0.003;exitDx=0;exitDy=0;exitPerimeter=0;" parent="1" source="xGkIlv-mTJFvFgtXs7Zm-11" edge="1" target="xGkIlv-mTJFvFgtXs7Zm-7">
+ <mxGeometry relative="1" as="geometry">
+ <mxPoint x="746" y="334.8670000000001" as="sourcePoint" />
+ <mxPoint x="643" y="335" as="targetPoint" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="xGkIlv-mTJFvFgtXs7Zm-32" value="PSE²" style="shape=umlFrame;whiteSpace=wrap;html=1;pointerEvents=0;width=60;height=15;fillColor=#66B2FF;strokeColor=#36393d;fillStyle=auto;" parent="1" vertex="1">
+ <mxGeometry x="440" y="230" width="140" height="200" as="geometry" />
+ </mxCell>
+ <mxCell id="l2kD7ozNFPAWC7if-8YD-1" value="" style="rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=halfCircle;endFill=0;endSize=6;strokeWidth=1;sketch=0;exitX=0.5;exitY=0;exitDx=0;exitDy=0;fillColor=#ffe6cc;strokeColor=#d79b00;" parent="1" edge="1">
+ <mxGeometry relative="1" as="geometry">
+ <mxPoint x="520" y="258" as="sourcePoint" />
+ <mxPoint x="520" y="237" as="targetPoint" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="l2kD7ozNFPAWC7if-8YD-2" value="&lt;div&gt;&lt;font&gt;E-Mail&lt;/font&gt;&lt;/div&gt;" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontFamily=Helvetica;" parent="1" vertex="1">
+ <mxGeometry x="525.23" y="225" width="50.77" height="30" as="geometry" />
+ </mxCell>
+ <mxCell id="l2kD7ozNFPAWC7if-8YD-5" value="" style="shape=image;verticalLabelPosition=bottom;labelBackgroundColor=default;verticalAlign=top;aspect=fixed;imageAspect=0;image=data:image/svg+xml,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNjEuNzYgMjI2LjY5IiB2ZXJzaW9uPSIxLjEiPjxnIHRyYW5zZm9ybT0ibWF0cml4KDEuMzMzMyAwIDAgLTEuMzMzMyAtNzYuMzExIDMxMy4zNCkiPjxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKDE3OC4wNiAyMzUuMDEpIj48cGF0aCBmaWxsPSIjNDFiODgzIiBkPSJtMCAwLTIyLjY2OS0zOS4yNjQtMjIuNjY5IDM5LjI2NGgtNzUuNDkxbDk4LjE2LTE3MC4wMiA5OC4xNiAxNzAuMDJ6Ii8+PC9nPjxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKDE3OC4wNiAyMzUuMDEpIj48cGF0aCBmaWxsPSIjMzQ0OTVlIiBkPSJtMCAwLTIyLjY2OS0zOS4yNjQtMjIuNjY5IDM5LjI2NGgtMzYuMjI3bDU4Ljg5Ni0xMDIuMDEgNTguODk2IDEwMi4wMXoiLz48L2c+PC9nPjwvc3ZnPg==;" parent="1" vertex="1">
+ <mxGeometry x="555.9200000000001" y="388.17" width="20" height="17.32" as="geometry" />
+ </mxCell>
+ <mxCell id="l2kD7ozNFPAWC7if-8YD-7" value="" style="shape=image;verticalLabelPosition=bottom;labelBackgroundColor=default;verticalAlign=top;aspect=fixed;imageAspect=0;image=data:image/svg+xml,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZlcnNpb249IjEuMSIgaGVpZ2h0PSIyNTAwIiB3aWR0aD0iMjQ5OSIgdmlld0JveD0iMCAwIDc2Ny44IDc2OCIgaWQ9IkxheWVyXzEiPiYjeGE7ICA8ZGVmcyBpZD0iZGVmczkiLz4mI3hhOyAgJiN4YTsgIDxzdHlsZSBpZD0ic3R5bGUyIj4uc3Qwe2ZpbGw6Izc3YmMxZn08L3N0eWxlPiYjeGE7ICA8cGF0aCBpZD0icGF0aDQiIGQ9Ik02OTguMyA0MGMtMTAuOCAyNS44LTI0LjUgNTAuMy00MSA3Mi44QzU4NS4xIDQwLjYgNDg3LjEgMCAzODUgMCAxNzMuOCAwIDAgMTc0IDAgMzg1LjUgMCA0OTEgNDMuMiA1OTIgMTE5LjYgNjY0LjhsMTQuMiAxMi42YzY5LjQgNTguNSAxNTcuMyA5MC43IDI0OCA5MC43IDIwMC44IDAgMzY5LjYtMTU3LjQgMzgzLjktMzU4IDEwLjUtOTguMi0xOC4zLTIyMi40LTY3LjQtMzcwLjF6bS01MjQgNjI3Yy02LjIgNy43LTE1LjcgMTIuMi0yNS42IDEyLjItMTguMSAwLTMyLjktMTQuOS0zMi45LTMzczE0LjktMzMgMzIuOS0zM2M3LjUgMCAxNC45IDIuNiAyMC43IDcuNCAxNC4xIDExLjQgMTYuMyAzMi4zIDQuOSA0Ni40em01MjIuNC0xMTUuNGMtOTUgMTI2LjctMjk3LjkgODQtNDI4IDkwLjEgMCAwLTIzLjEgMS40LTQ2LjMgNS4yIDAgMCA4LjctMy43IDIwLTggOTEuMy0zMS44IDEzNC41LTM4IDE5MC02Ni41IDEwNC41LTUzLjIgMjA3LjgtMTY5LjYgMjI5LjMtMjkwLjdDNjIxLjkgMzk4LjIgNTAxLjMgNDk4LjMgMzkxLjQgNTM5Yy03NS4zIDI3LjgtMjExLjMgNTQuOC0yMTEuMyA1NC44bC01LjUtMi45QzgyIDU0NS44IDc5LjIgMzQ1LjEgMjQ3LjUgMjgwLjNjNzMuNy0yOC40IDE0NC4yLTEyLjggMjIzLjgtMzEuOCA4NS0yMC4yIDE4My4zLTg0IDIyMy4zLTE2Ny4yIDQ0LjggMTMzLjEgOTguNyAzNDEuNSAyLjEgNDcwLjN6IiBjbGFzcz0ic3QwIi8+JiN4YTsgIDxwYXRoIHRyYW5zZm9ybT0ibWF0cml4KDAuMzA3MjQyOSwwLDAsMC4zMDcyNDI5LDAsLTAuMDUzNjIxNDUpIiBpZD0icGF0aDM3NiIgZD0ibSA3NzMuMTIxMzksMjA4OC4wMDI0IGMgMzguMzM3NjQsLTE1LjE5MjQgMTQ4LjU1NjkzLC01MS4yNDE3IDI4NS40MDQ2MSwtOTMuMzQ3MSAyMDAuNTU5LC02MS43MDc5IDI2My4wNjc5LC04NS4yODAzIDM1OS40NjUzLC0xMzUuNTU1OSAyOTAuNjIzNSwtMTUxLjU3MzIgNTUzLjMzMjQsLTQzNS42NzQ5IDY3My43NDU0LC03MjguNjA5NSAyMi41MzM3LC01NC44MTg3IDQxLjY0NzgsLTExMy42NDE1IDUyLjczMjQsLTE2Mi4yODE4MSAxMi43MjMyLC01NS44MzA4NSAxMC42OTIzLC01Ny41MjI4MyAtOS4zNjA0LC03Ljc5ODAxIC0xMDIuOTE3NywyNTUuMjA1NzIgLTMyNy45MzA0LDUwMC43NTc3MiAtNjE3Ljc2NzcsNjc0LjE1NzkyIC0xNTYuMTEyMSw5My4zOTY3IC0yOTkuNzg3OSwxNDYuODQ2MyAtNTg3LjA2NjQzLDIxOC4zOTc3IC0xMjkuOTU3MDEsMzIuMzY3OSAtMzI1LjI1NDUyLDc2LjIyNTEgLTMzOS40MzI4LDc2LjIyNTEgLTMuMjAyMDIsMCAtMTQuMzAyODUsLTQuMjU4NiAtMjQuNjY4NTIsLTkuNDYzNSAtNzkuMjIxNTksLTM5Ljc3OTUgLTE0Mi44MTI1NSwtMTIwLjI0MTIgLTE3NS4yNTUwOCwtMjIxLjc1MDQgLTE2LjE2NTY1LC01MC41ODA2IC0yMi43MjIwOCwtODkuNDU4NyAtMjQuOTk1NTksLTE0OC4yMTc5IC0zLjEwNTU4LC04MC4yNjQgNi4wNjg1NiwtMTQ0LjMwMTMgMzEuNzYwOTUsLTIyMS42OTc3IDYyLjU4MjUxLC0xODguNTI1MSAyMDUuODk5MDIsLTMzNC4zNTEzMyA0MDQuOTMyNjIsLTQxMi4wMjM2MiAxMDYuNTk0NDQsLTQxLjU5ODE5IDE5Ni45MTc2NywtNTYuMTQ3MDcgNDI3LjUxMzk1LC02OC44NjIyMSAyNDguNTk5NCwtMTMuNzA3OCAzNzAuMjg2NywtNDEuMTY2MjkgNTM0LjY4MiwtMTIwLjY0OTkzIDIxMC4yMTA1LC0xMDEuNjM0ODcgMzgyLjE3NDksLTI1My41NjkyIDQ3Ni4xMzk2LC00MjAuNjc5OTUgbCAxOS45OTI5LC0zNS41NTYxNCAxNi4yNjM0LDUwLjAwNzAxIGMgMTg0LjQ2OTYsNTY3LjIxMTA5IDIxMi43NzMsOTkxLjEyMjE0IDg2Ljc5NzgsMTMwMC4wMDcwNCAtNDIuNjgxLDEwNC42NTE4IC0xMTEuOTQ0MiwyMDQuNzAzNyAtMTg2LjQ3NzMsMjY5LjM2OTggLTgzLjQ3MDksNzIuNDIwNiAtMTkwLjc3MSwxMjYuMjg1IC0zMTYuNjk3MiwxNTguOTgxMiAtMTYyLjYzOTMsNDIuMjI4NSAtMzM2LjQ1NjQsNTEuNzE1MSAtNzI4LjI0NDYsMzkuNzQ2IC0xNjUuNjgzNjMsLTUuMDYxNyAtMjQ5LjQ1ODQxLC0zLjc0NDcgLTMyOC43NTcyMiw1LjE2ODMgLTYxLjg2MTcxLDYuOTUzIC02Mi4xNjI3NSw2Ljg5ODQgLTMwLjcwODA5LC01LjU2NjQgeiIgc3R5bGU9ImZpbGw6I2ZmZmZmZjtmaWxsLXJ1bGU6ZXZlbm9kZDtzdHJva2Utd2lkdGg6NjguMjcxOCIvPiYjeGE7ICA8cGF0aCB0cmFuc2Zvcm09Im1hdHJpeCgwLjMwNzI0MjksMCwwLDAuMzA3MjQyOSwwLC0wLjA1MzYyMTQ1KSIgaWQ9InBhdGgzNzgiIGQ9Im0gNDQ5LjMyMSwyMjAzLjE2OTIgYyAtMzUuNzc2OTYsLTEyLjA4NDYgLTY1LjkwNTM3LC01MS44NjIzIC02OS4wNjE0LC05MS4xNzk4IC0yLjcxNjk0LC0zMy44NDc0IDUuOTc2MiwtNTYuNjEyMSAzMS4yNjU0MSwtODEuODc0NiAzMC45MDU1NywtMzAuODczIDYzLjA4NTMyLC0zOS4wMDM4IDEwNS4wNDc5NiwtMjYuNTQyMiAyNi41NTE4MSw3Ljg4NSA1Ny42MzcwNCwzOC42ODM4IDY2Ljc1NzE3LDY2LjE0MTkgMTYuMTY1MzUsNDguNjY5MyAtNi4xMzg4OCwxMDQuMTEzMiAtNTEuMDIyNzcsMTI2LjgzMjQgLTE5LjY4MjExLDkuOTYyNiAtNjIuODg5NDMsMTMuNDEwNSAtODIuOTg2MzcsNi42MjIzIHoiIHN0eWxlPSJmaWxsOiNmZmZmZmY7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlLXdpZHRoOjY4LjI3MTgiLz4mI3hhOzwvc3ZnPg==;" parent="1" vertex="1">
+ <mxGeometry x="546.92" y="278.5" width="21" height="21" as="geometry" />
+ </mxCell>
+ <mxCell id="xR_aQyUa65SQuSEJo7b6-1" value="" style="shape=image;verticalLabelPosition=bottom;labelBackgroundColor=default;verticalAlign=top;aspect=fixed;imageAspect=0;image=data:image/svg+xml,PHN2ZyB2aWV3Qm94PSIwIDAgMzA5Ljg4IDI1Mi43MiIgZGF0YS1uYW1lPSJMYXllciAxIiBpZD0iTGF5ZXJfMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4mI3hhOyAgPGRlZnM+JiN4YTsgICAgPHN0eWxlPi5jbHMtMXtmaWxsOiMwMDM1NDU7fTwvc3R5bGU+JiN4YTsgIDwvZGVmcz4mI3hhOyAgPHRpdGxlPk1EQi1WTG9nb19SR0I8L3RpdGxlPiYjeGE7ICA8cGF0aCB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtNS41OCAtNi40KSIgZD0iTTYxLjc0LDIxNC45MSw3MywyNTguNDZoLTguNUw1NywyMjcuMDksNDIuODYsMjU4LjQ2SDM1LjY4TDIxLjYyLDIyNy4yNywxMy45LDI1OC40Nkg1LjU4bDExLjE2LTQzLjU1SDI0LjFsMTUuMiwzMy43MiwxNS4xNC0zMy43MloiIGNsYXNzPSJjbHMtMSIvPiYjeGE7ICA8cGF0aCB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtNS41OCAtNi40KSIgZD0iTTEwNS4xMSwyMzEuNzR2LTUuMDdoOC4yMXYzMS43OWgtOC4yMXYtNS4xMmMtMi4xNywzLjY4LTYuNjMsNS43OS0xMi4wNiw1Ljc5LTExLjM1LDAtMTcuNjgtOC0xNy42OC0xNy4yLDAtOC44Nyw2LTE2LDE2LjQ3LTE2Qzk3LjgxLDIyNiwxMDIuNzYsMjI4LDEwNS4xMSwyMzEuNzRabS0yMSwxMC42MmMwLDUuODUsMy42OCwxMC44NiwxMC44LDEwLjg2LDYuODcsMCwxMC42MS00Ljg5LDEwLjYxLTEwLjY4cy0zLjg2LTEwLjc0LTExLTEwLjc0Qzg3LjY4LDIzMS44LDg0LjEyLDIzNi43NCw4NC4xMiwyNDIuMzZaIiBjbGFzcz0iY2xzLTEiLz4mI3hhOyAgPHBhdGggdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTUuNTggLTYuNCkiIGQ9Ik0xMzEuODMsMjU4LjQ2aC04LjJWMjI2LjY3aDguMnY3LjEyQTEyLjU4LDEyLjU4LDAsMCwxLDE0My4yOSwyMjZhMTQuODQsMTQuODQsMCwwLDEsNS4xMy44NGwtMS43NSw2YTE4LDE4LDAsMCwwLTQuMzQtLjZjLTUuOTIsMC0xMC41LDQuNDYtMTAuNSwxMVoiIGNsYXNzPSJjbHMtMSIvPiYjeGE7ICA8cGF0aCB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtNS41OCAtNi40KSIgZD0iTTE1Mi41MiwyMTguMjhhNC4xNyw0LjE3LDAsMCwxLDQuNC00LjI4LDQuMzMsNC4zMywwLDAsMSw0LjQ3LDQuNDEsNC4xNSw0LjE1LDAsMCwxLTQuNDcsNC4yMkE0LjIyLDQuMjIsMCwwLDEsMTUyLjUyLDIxOC4yOFptLjM2LDguMzloOC4yMVYyNDkuOWMwLDEuNDQuMywyLjQ3LDEuNSwyLjQ3YTguODUsOC44NSwwLDAsMCwxLjU3LS4xOGwxLjI3LDZhMTQuMzYsMTQuMzYsMCwwLDEtNS40MywxYy0zLjQ0LDAtNy4xMi0xLTcuMTItOC44MVoiIGNsYXNzPSJjbHMtMSIvPiYjeGE7ICA8cGF0aCB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtNS41OCAtNi40KSIgZD0iTTE5Ny43NiwyMzEuNzR2LTUuMDdIMjA2djMxLjc5aC04LjIxdi01LjEyYy0yLjE3LDMuNjgtNi42Myw1Ljc5LTEyLjA2LDUuNzktMTEuMzQsMC0xNy42OC04LTE3LjY4LTE3LjIsMC04Ljg3LDYtMTYsMTYuNDctMTZDMTkwLjQ2LDIyNiwxOTUuNDEsMjI4LDE5Ny43NiwyMzEuNzRabS0yMSwxMC42MmMwLDUuODUsMy42OCwxMC44NiwxMC44LDEwLjg2LDYuODgsMCwxMC42Mi00Ljg5LDEwLjYyLTEwLjY4cy0zLjg3LTEwLjc0LTExLTEwLjc0QzE4MC4zMywyMzEuOCwxNzYuNzcsMjM2Ljc0LDE3Ni43NywyNDIuMzZaIiBjbGFzcz0iY2xzLTEiLz4mI3hhOyAgPHBhdGggdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTUuNTggLTYuNCkiIGQ9Ik0yMTguNTcsMjE0LjkxaDE5LjY3YzE2LjUzLDAsMjQuNzksOS4xMSwyNC42NywyMS43Ny4xMiwxMy4xNi05LDIxLjc4LTIzLjIyLDIxLjc4SDIxOC41N1ptNS40MywzLjg2djM1Ljg5aDE1YzEzLjE1LDAsMTguMTYtOC44NywxOC4xNi0xOC4xLDAtMTAuNDMtNi4yNy0xNy43OS0xOC4xNi0xNy43OVoiIGNsYXNzPSJjbHMtMSIvPiYjeGE7ICA8cGF0aCB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtNS41OCAtNi40KSIgZD0iTTI5Ni40NSwyNTguNDZoLTI1VjIxNC45MUgyOTRjOC42MiwwLDE2LjgzLDEuNjIsMTYuNzEsMTEuMjgsMCw2LjgxLTQuMjMsOC42OS04LjY5LDkuNDEsNi4zMy41NCwxMC4xNCw0LjU4LDEwLjE0LDExLjFDMzEyLjIsMjU2LjQ3LDMwMy42MywyNTguNDYsMjk2LjQ1LDI1OC40NlptLTEuODctMjQuNTVjOC42MywwLDEwLjU2LTMuMzIsMTAuNTYtNy41NCwwLTYuMzQtMy44Ni03Ljc4LTEwLjU2LTcuNzhIMjc2LjY2djE1LjMyWm0uMjQsMy42OEgyNzYuNjZ2MTcuMTlIMjk1LjZjNS4zMSwwLDEwLjkyLTEuNzUsMTAuOTItOC40NEMzMDYuNTIsMjM4LjYyLDMwMC4wNywyMzcuNTksMjk0LjgyLDIzNy41OVoiIGNsYXNzPSJjbHMtMSIvPiYjeGE7ICA8cGF0aCB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtNS41OCAtNi40KSIgZD0iTTMxNC4wOCw3LjM1YTQuMTgsNC4xOCwwLDAsMC0yLjg0LS45NWMtMi44MywwLTYuNDksMS45Mi04LjQ2LDIuOTVsLS43OC40YTI2Ljg2LDI2Ljg2LDAsMCwxLTEwLjU3LDIuNjZjLTMuNzYuMTItNywuMzQtMTEuMjIuNzgtMjUsMi41Ny0zNi4xNSwyMS43My00Ni44OSw0MC4yNkMyMjcuNDcsNjMuNTMsMjIxLjQzLDc0LDIxMy4xNSw4MmE1NC40LDU0LjQsMCwwLDEtNS40NSw0LjYzQzE5OS4xMyw5MywxODguMzcsOTcuNTUsMTgwLDEwMC43N2MtOC4wNiwzLjA4LTE2Ljg2LDUuODUtMjUuMzYsOC41My03Ljc5LDIuNDUtMTUuMTQsNC43Ny0yMS45LDcuMjgtMy4wNSwxLjEzLTUuNjQsMi03LjkzLDIuNzYtNi4xNiwyLTEwLjYsMy41My0xNy4wOSw4LTIuNTMsMS43My01LjA3LDMuNi02Ljc5LDVhNzEuNjIsNzEuNjIsMCwwLDAtMTMuNTUsMTQuMjdBODQuMjUsODQuMjUsMCwwLDEsNzYsMTYwLjI3Yy0xLjM3LDEuMzQtMy44LDItNy40NCwyLTQuMjYsMC05LjQzLS44OC0xNC45LTEuODEtNS42NC0xLTExLjQ3LTEuOTUtMTYuNDctMS45NS00LjA2LDAtNy4xNy42Ni05LjQ5LDIsMCwwLTMuOTEsMi4yOC01LjU2LDUuMjNsMS42Mi43M2EzMy4yMSwzMy4yMSwwLDAsMSw2LjkyLDUsMzQuNzIsMzQuNzIsMCwwLDAsNy4yLDUuMTJBNi4xOCw2LjE4LDAsMCwxLDQwLjEsMTc4Yy0uNjgsMS0xLjY4LDIuMjktMi43MywzLjY3LTUuNzcsNy41NS05LjE0LDEyLjMyLTcuMjEsMTQuOTJhNi4wNyw2LjA3LDAsMCwwLDMsLjY4YzEyLjU4LDAsMTkuMzQtMy4yNywyNy44OS03LjQxLDIuNDgtMS4yLDUtMi40Myw4LTMuNyw1LTIuMTcsMTAuMzgtNS42MywxNi4wOS05LjI5QzkyLjYxLDE3MiwxMDAuNDIsMTY3LDEwOCwxNjQuNTlhNjIuMyw2Mi4zLDAsMCwxLDE5LjIzLTIuN2M4LDAsMTYuNDIsMS4wNywyNC41NCwyLjExLDYuMDUuNzgsMTIuMzIsMS41OCwxOC40NywxLjk1LDIuMzkuMTQsNC42LjIxLDYuNzUuMjFhNzguMjEsNzguMjEsMCwwLDAsOC42MS0uNDVsLjY5LS4yNGM0LjMxLTIuNjUsNi4zMy04LjM0LDguMjktMTMuODQsMS4yNi0zLjU0LDIuMzItNi43Miw0LTguNzRhMi41NSwyLjU1LDAsMCwxLC4zMi0uMjcuNC40LDAsMCwxLC40OS4wOHMwLC4wNSwwLC4xNmMtMSwyMS41MS05LjY2LDM1LjE3LTE4LjQyLDQ3LjMxbC01Ljg1LDYuMjdzOC4xOSwwLDEyLjg1LTEuOGMxNy01LjA4LDI5LjgzLTE2LjI4LDM5LjE3LTM0LjE0YTE0NS43LDE0NS43LDAsMCwwLDYuMTctMTQuMDljLjE2LS40LDEuNjMtMS4xNCwxLjQ5LjkzLS4wNS42MS0uMDksMS4yOS0uMTQsMmgwYzAsLjQyLDAsLjg1LS4wOCwxLjI4LS4yNCwzLS45NSw5LjM0LS45NSw5LjM0bDUuMjUtMi44MWMxMi42Ni04LDIyLjQyLTI0LjE0LDI5LjgyLTQ5LjI1LDMuMDgtMTAuNDYsNS4zNC0yMC44NSw3LjMzLTMwLDIuMzgtMTEsNC40My0yMC40Myw2Ljc4LTI0LjA5LDMuNjktNS43NCw5LjMyLTkuNjIsMTQuNzctMTMuMzkuNzQtLjUxLDEuNDktMSwyLjIyLTEuNTQsNi44NS00LjgxLDEzLjY2LTEwLjM2LDE1LjE2LTIwLjcxbDAtLjIzQzMxNi4wNSwxMC4yMiwzMTUuMTMsOC4yNSwzMTQuMDgsNy4zNVoiIGNsYXNzPSJjbHMtMSIvPiYjeGE7PC9zdmc+;" parent="1" vertex="1">
+ <mxGeometry x="544.41" y="298" width="24.51" height="20" as="geometry" />
+ </mxCell>
+ <mxCell id="l2kD7ozNFPAWC7if-8YD-3" value="" style="shape=image;verticalLabelPosition=bottom;labelBackgroundColor=default;verticalAlign=top;aspect=fixed;imageAspect=0;image=data:image/svg+xml,PHN2ZyBoZWlnaHQ9IjQwOCIgd2lkdGg9IjUxMiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgNTEyIDQwOCI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiB5Mj0iMzY1Ljk0NSIgeTE9IjEwLjc5OCIgeDI9IjUyMy40OCIgeDE9Ijc2LjA3OSIgaWQ9ImJzLWxvZ28tYSI+PHN0b3Agc3RvcC1jb2xvcj0iIzkwMTNmZSIvPjxzdG9wIHN0b3AtY29sb3I9IiM2NjEwZjIiIG9mZnNldD0iMSIvPjwvbGluZWFyR3JhZGllbnQ+PGxpbmVhckdyYWRpZW50IGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiB5Mj0iMjc4Ljg3MiIgeTE9IjEwOS43NCIgeDI9IjI5My41MTQiIHgxPSIxOTMuNTA4IiBpZD0iYnMtbG9nby1iIj48c3RvcCBzdG9wLWNvbG9yPSIjZmZmIi8+PHN0b3Agc3RvcC1jb2xvcj0iI2YxZTVmYyIgb2Zmc2V0PSIxIi8+PC9saW5lYXJHcmFkaWVudD48ZmlsdGVyIGZpbHRlclVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgY29sb3ItaW50ZXJwb2xhdGlvbi1maWx0ZXJzPSJzUkdCIiB5PSI4My40NTciIHg9IjE2MS45MDEiIGhlaWdodD0iMjQ5IiB3aWR0aD0iMTk3IiBpZD0iYnMtbG9nby1jIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxmZUZsb29kIHJlc3VsdD0iQmFja2dyb3VuZEltYWdlRml4IiBmbG9vZC1vcGFjaXR5PSIwIi8+PGZlQ29sb3JNYXRyaXggdmFsdWVzPSIwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAxMjcgMCIgaW49IlNvdXJjZUFscGhhIi8+PGZlT2Zmc2V0IGR5PSI0Ii8+PGZlR2F1c3NpYW5CbHVyIHN0ZERldmlhdGlvbj0iOCIvPjxmZUNvbG9yTWF0cml4IHZhbHVlcz0iMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMC4xNSAwIi8+PGZlQmxlbmQgcmVzdWx0PSJlZmZlY3QxX2Ryb3BTaGFkb3ciIGluMj0iQmFja2dyb3VuZEltYWdlRml4Ii8+PGZlQmxlbmQgcmVzdWx0PSJzaGFwZSIgaW4yPSJlZmZlY3QxX2Ryb3BTaGFkb3ciIGluPSJTb3VyY2VHcmFwaGljIi8+PC9maWx0ZXI+PC9kZWZzPjxwYXRoIGQ9Ik01Ni40ODEgNTMuMzJDNTUuNTE1IDI1LjU4IDc3LjEyOCAwIDEwNi4zNDIgMGgyOTkuMzUzYzI5LjIxNCAwIDUwLjgyNyAyNS41OCA0OS44NjEgNTMuMzItLjkyOCAyNi42NDcuMjc3IDYxLjE2NSA4Ljk2NCA4OS4zMSA4LjcxNSAyOC4yMzIgMjMuNDExIDQ2LjA3NyA0Ny40OCA0OC4zN3YyNmMtMjQuMDY5IDIuMjkzLTM4Ljc2NSAyMC4xMzgtNDcuNDggNDguMzctOC42ODcgMjguMTQ1LTkuODkyIDYyLjY2My04Ljk2NCA4OS4zMTEuOTY2IDI3LjczOS0yMC42NDcgNTMuMzE5LTQ5Ljg2MSA1My4zMTlIMTA2LjM0MmMtMjkuMjE0IDAtNTAuODI3LTI1LjU4LTQ5Ljg2LTUzLjMxOS45MjctMjYuNjQ4LS4yNzgtNjEuMTY2LTguOTY2LTg5LjMxMUMzOC44MDIgMjM3LjEzOCAyNC4wNyAyMTkuMjkzIDAgMjE3di0yNmMyNC4wNjktMi4yOTMgMzguODAyLTIwLjEzOCA0Ny41MTYtNDguMzcgOC42ODgtMjguMTQ1IDkuODkzLTYyLjY2MyA4Ljk2NS04OS4zMXoiIGZpbGw9InVybCgjYnMtbG9nby1hKSIvPjxwYXRoIGQ9Ik0yNjcuMTAzIDMxMi40NTdjNDcuMjk3IDAgNzUuNzk4LTIzLjE1OCA3NS43OTgtNjEuMzU1IDAtMjguODczLTIwLjMzNi00OS43NzYtNTAuNTMyLTUzLjA4NXYtMS4yMDNjMjIuMTg1LTMuNjA5IDM5LjU5NC0yNC4yMTEgMzkuNTk0LTQ3LjIxOSAwLTMyLjc4My0yNS44ODItNTQuMTM4LTY1LjMyMi01NC4xMzhoLTg4Ljc0djIxN2g4OS4yMDJ6bS01NC42OTItMTg5LjQ4aDQ1LjkxMWMyNC45NTggMCAzOS4xMzEgMTEuMTI4IDM5LjEzMSAzMS4yNzkgMCAyMS41MDUtMTYuNDg0IDMzLjUzNS00Ni4zNzIgMzMuNTM1aC0zOC42N3YtNjQuODE0em0wIDE2MS45NjF2LTcxLjQzMWg0NS42MDJjMzIuNjYxIDAgNDkuNjA4IDEyLjAzIDQ5LjYwOCAzNS40OSAwIDIzLjQ1OS0xNi40ODQgMzUuOTQxLTQ3LjYwNSAzNS45NDFoLTQ3LjYwNXoiIHN0cm9rZT0iI2ZmZiIgZmlsdGVyPSJ1cmwoI2JzLWxvZ28tYykiIGZpbGw9InVybCgjYnMtbG9nby1iKSIvPjwvc3ZnPg==;" parent="1" vertex="1">
+ <mxGeometry x="555.47" y="407.5" width="19.45" height="15.5" as="geometry" />
+ </mxCell>
+ </root>
+ </mxGraphModel>
+ </diagram>
+</mxfile>
diff --git a/40-abschlusspraesentation/assets/component6.svg b/40-abschlusspraesentation/assets/component6.svg
new file mode 100644
index 0000000..3c2b08d
--- /dev/null
+++ b/40-abschlusspraesentation/assets/component6.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Do not edit this file with editors other than diagrams.net -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="281px" height="206px" viewBox="-0.5 -0.5 281 206" content="&lt;mxfile host=&quot;app.diagrams.net&quot; modified=&quot;2023-03-30T22:57:23.251Z&quot; agent=&quot;Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/111.0&quot; etag=&quot;cDrBtGvJZcLJR91ZSGJK&quot; version=&quot;21.1.2&quot; type=&quot;device&quot;&gt;&lt;diagram name=&quot;Seite-1&quot; id=&quot;XfYHgy5avJqr8EgWlpBP&quot;&gt;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&lt;/diagram&gt;&lt;/mxfile&gt;"><defs/><g><path d="M 175 33 L 275 33 L 275 95 L 175 95 L 175 73 L 165 73 L 165 63 L 175 63 L 175 53 L 165 53 L 165 43 L 175 43 Z" fill="#f5f5f5" stroke="#666666" stroke-miterlimit="10" pointer-events="all"/><path d="M 175 43 L 185 43 L 185 53 L 175 53 M 175 63 L 185 63 L 185 73 L 175 73" fill="none" stroke="#666666" stroke-miterlimit="10" pointer-events="all"/><path d="M 180 145 L 270 145 L 270 204 L 180 204 L 180 185 L 170 185 L 170 175 L 180 175 L 180 165 L 170 165 L 170 155 L 180 155 Z" fill="#f5f5f5" stroke="#666666" stroke-miterlimit="10" pointer-events="all"/><path d="M 180 155 L 190 155 L 190 165 L 180 165 M 180 175 L 190 175 L 190 185 L 180 185" fill="none" stroke="#666666" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 152px; margin-left: 191px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: #333333; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Podcatcher</div></div></div></foreignObject><text x="230" y="164" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">Podcatcher</text></switch></g><rect x="5" y="5" width="140" height="200" fill="#dae8fc" stroke="#6c8ebf" pointer-events="all"/><path d="M 213.62 95.37 L 213.75 105" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 45.37 85.23 L 205.84 108.84" fill="none" stroke="#bd7000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 212.59 117.91 Q 204.67 116.75 205.84 108.84 Q 207 100.92 214.91 102.09" fill="none" stroke="#bd7000" stroke-miterlimit="10" pointer-events="all"/><ellipse cx="213.75" cy="110" rx="5" ry="5" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><path d="M 164 23 L 265 23 L 265 85 L 164 85 L 164 63 L 154 63 L 154 53 L 164 53 L 164 43 L 154 43 L 154 33 L 164 33 Z" fill="#f5f5f5" stroke="#666666" stroke-miterlimit="10" pointer-events="all"/><path d="M 164 33 L 174 33 L 174 43 L 164 43 M 164 53 L 174 53 L 174 63 L 164 63" fill="none" stroke="#666666" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 89px; height: 1px; padding-top: 30px; margin-left: 175px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: #333333; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Podcast-Server</div></div></div></foreignObject><text x="220" y="42" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">Podcast-Server</text></switch></g><path d="M 45.92 33.5 L 125.92 33.5 L 125.92 94.5 L 45.92 94.5 L 45.92 73.5 L 35.92 73.5 L 35.92 63.5 L 45.92 63.5 L 45.92 53.5 L 35.92 53.5 L 35.92 43.5 L 45.92 43.5 Z" fill="#ffcc99" stroke="#36393d" stroke-miterlimit="10" pointer-events="all"/><path d="M 45.92 43.5 L 55.92 43.5 L 55.92 53.5 L 45.92 53.5 M 45.92 63.5 L 55.92 63.5 L 55.92 73.5 L 45.92 73.5" fill="none" stroke="#36393d" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 68px; height: 1px; padding-top: 41px; margin-left: 57px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><div align="left">Sync-Server<br /></div></div></div></div></foreignObject><text x="91" y="53" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Sync-Server&#xa;</text></switch></g><path d="M 34 135.67 L 134 135.67 L 134 194.67 L 34 194.67 L 34 175.67 L 24 175.67 L 24 165.67 L 34 165.67 L 34 155.67 L 24 155.67 L 24 145.67 L 34 145.67 Z" fill="#cdeb8b" stroke="#36393d" stroke-miterlimit="10" pointer-events="all"/><path d="M 34 145.67 L 44 145.67 L 44 155.67 L 34 155.67 M 34 165.67 L 44 165.67 L 44 175.67 L 34 175.67" fill="none" stroke="#36393d" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 88px; height: 1px; padding-top: 143px; margin-left: 45px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Web-Dashboard</div></div></div></foreignObject><text x="89" y="155" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Web-Dashboard</text></switch></g><path d="M 170 135 L 260 135 L 260 194 L 170 194 L 170 175 L 160 175 L 160 165 L 170 165 L 170 155 L 160 155 L 160 145 L 170 145 Z" fill="#f5f5f5" stroke="#666666" stroke-miterlimit="10" pointer-events="all"/><path d="M 170 145 L 180 145 L 180 155 L 170 155 M 170 165 L 180 165 L 180 175 L 170 175" fill="none" stroke="#666666" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 142px; margin-left: 181px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: #333333; "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Podcatcher</div></div></div></foreignObject><text x="220" y="154" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle">Podcatcher</text></switch></g><rect x="220" y="93.5" width="60" height="30" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 58px; height: 1px; padding-top: 109px; margin-left: 221px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><div>RSS-Feed</div></div></div></div></foreignObject><text x="250" y="112" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">RSS-Feed</text></switch></g><ellipse cx="85.23" cy="110" rx="5" ry="5" fill="#ffe6cc" stroke="#d79b00" pointer-events="all"/><path d="M 84.94 135.32 L 85.12 123" fill="none" stroke="#82b366" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 93.23 115.11 Q 93.12 123.11 85.12 123 Q 77.12 122.89 77.23 114.89" fill="none" stroke="#82b366" stroke-miterlimit="10" pointer-events="all"/><path d="M 185 135 L 97.84 113.15" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 92.03 103.44 Q 99.79 105.39 97.84 113.15 Q 95.9 120.91 88.14 118.96" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><rect x="0.23" y="95" width="84" height="30" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 82px; height: 1px; padding-top: 110px; margin-left: 1px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">GPodder-API</div></div></div></foreignObject><text x="42" y="114" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">GPodder-API</text></switch></g><image x="196.5" y="43.5" width="35" height="40" xlink:href="data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgNDQ4IDUxMiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMzE5LjQgMzcyYzQ4LjUtMzEuMyA4MC42LTg1LjkgODAuNi0xNDhjMC05Ny4yLTc4LjgtMTc2LTE3Ni0xNzZTNDggMTI2LjggNDggMjI0YzAgNjIuMSAzMi4xIDExNi42IDgwLjYgMTQ4YzEuMiAxNy4zIDQgMzggNy4yIDU3LjFsLjIgMUM1NiAzOTUuOCAwIDMxNi41IDAgMjI0QzAgMTAwLjMgMTAwLjMgMCAyMjQgMFM0NDggMTAwLjMgNDQ4IDIyNGMwIDkyLjUtNTYgMTcxLjktMTM2IDIwNi4xbC4yLTEuMWMzLjEtMTkuMiA2LTM5LjggNy4yLTU3em0tMi4zLTM4LjFjLTEuNi01LjctMy45LTExLjEtNy0xNi4yYy01LjgtOS43LTEzLjUtMTctMjEuOS0yMi40YzE5LjUtMTcuNiAzMS44LTQzIDMxLjgtNzEuM2MwLTUzLTQzLTk2LTk2LTk2cy05NiA0My05NiA5NmMwIDI4LjMgMTIuMyA1My44IDMxLjggNzEuM2MtOC40IDUuNC0xNi4xIDEyLjctMjEuOSAyMi40Yy0zLjEgNS4xLTUuNCAxMC41LTcgMTYuMkM5OS44IDMwNy41IDgwIDI2OCA4MCAyMjRjMC03OS41IDY0LjUtMTQ0IDE0NC0xNDRzMTQ0IDY0LjUgMTQ0IDE0NGMwIDQ0LTE5LjggODMuNS01MC45IDEwOS45ek0yMjQgMzEyYzMyLjkgMCA2NCA4LjYgNjQgNDMuOGMwIDMzLTEyLjkgMTA0LjEtMjAuNiAxMzIuOWMtNS4xIDE5LTI0LjUgMjMuNC00My40IDIzLjRzLTM4LjItNC40LTQzLjQtMjMuNGMtNy44LTI4LjUtMjAuNi05OS43LTIwLjYtMTMyLjhjMC0zNS4xIDMxLjEtNDMuOCA2NC00My44em0wLTE0NGE1NiA1NiAwIDEgMSAwIDExMiA1NiA1NiAwIDEgMSAwLTExMnoiLz48L3N2Zz4=" preserveAspectRatio="none" opacity="0.5"/><image x="64.73" y="53" width="40" height="40" xlink:href="data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgNTEyIDUxMiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMTQyLjkgMTQyLjljNjIuMi02Mi4yIDE2Mi43LTYyLjUgMjI1LjMtMUwzMjcgMTgzYy02LjkgNi45LTguOSAxNy4yLTUuMiAyNi4yczEyLjUgMTQuOCAyMi4yIDE0LjhINDYzLjVjMCAwIDAgMCAwIDBINDcyYzEzLjMgMCAyNC0xMC43IDI0LTI0VjcyYzAtOS43LTUuOC0xOC41LTE0LjgtMjIuMnMtMTkuMy0xLjctMjYuMiA1LjJMNDEzLjQgOTYuNmMtODcuNi04Ni41LTIyOC43LTg2LjItMzE1LjggMUM3My4yIDEyMiA1NS42IDE1MC43IDQ0LjggMTgxLjRjLTUuOSAxNi43IDIuOSAzNC45IDE5LjUgNDAuOHMzNC45LTIuOSA0MC44LTE5LjVjNy43LTIxLjggMjAuMi00Mi4zIDM3LjgtNTkuOHpNMTYgMzEydjcuNiAuN1Y0NDBjMCA5LjcgNS44IDE4LjUgMTQuOCAyMi4yczE5LjMgMS43IDI2LjItNS4ybDQxLjYtNDEuNmM4Ny42IDg2LjUgMjI4LjcgODYuMiAzMTUuOC0xYzI0LjQtMjQuNCA0Mi4xLTUzLjEgNTIuOS04My43YzUuOS0xNi43LTIuOS0zNC45LTE5LjUtNDAuOHMtMzQuOSAyLjktNDAuOCAxOS41Yy03LjcgMjEuOC0yMC4yIDQyLjMtMzcuOCA1OS44Yy02Mi4yIDYyLjItMTYyLjcgNjIuNS0yMjUuMyAxTDE4NSAzMjljNi45LTYuOSA4LjktMTcuMiA1LjItMjYuMnMtMTIuNS0xNC44LTIyLjItMTQuOEg0OC40aC0uN0g0MGMtMTMuMyAwLTI0IDEwLjctMjQgMjR6Ii8+PC9zdmc+" preserveAspectRatio="none"/><image x="67.54" y="158.67" width="33.77" height="30" xlink:href="data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgNTc2IDUxMiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNNjQgMEMyOC43IDAgMCAyOC43IDAgNjRWMzUyYzAgMzUuMyAyOC43IDY0IDY0IDY0SDI0MGwtMTAuNyAzMkgxNjBjLTE3LjcgMC0zMiAxNC4zLTMyIDMyczE0LjMgMzIgMzIgMzJINDE2YzE3LjcgMCAzMi0xNC4zIDMyLTMycy0xNC4zLTMyLTMyLTMySDM0Ni43TDMzNiA0MTZINTEyYzM1LjMgMCA2NC0yOC43IDY0LTY0VjY0YzAtMzUuMy0yOC43LTY0LTY0LTY0SDY0ek01MTIgNjRWMjg4SDY0VjY0SDUxMnoiLz48L3N2Zz4=" preserveAspectRatio="none"/><path d="M 85 95 L 85 105" fill="none" stroke="#d79b00" stroke-miterlimit="10" pointer-events="stroke"/><image x="202.5" y="153" width="33.5" height="33.5" xlink:href="data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgNTEyIDUxMiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMjU2IDgwQzE0MS4xIDgwIDQ4IDE3My4xIDQ4IDI4OFYzOTJjMCAxMy4zLTEwLjcgMjQtMjQgMjRzLTI0LTEwLjctMjQtMjRWMjg4QzAgMTQ2LjYgMTE0LjYgMzIgMjU2IDMyczI1NiAxMTQuNiAyNTYgMjU2VjM5MmMwIDEzLjMtMTAuNyAyNC0yNCAyNHMtMjQtMTAuNy0yNC0yNFYyODhjMC0xMTQuOS05My4xLTIwOC0yMDgtMjA4ek04MCAzNTJjMC0zNS4zIDI4LjctNjQgNjQtNjRoMTZjMTcuNyAwIDMyIDE0LjMgMzIgMzJWNDQ4YzAgMTcuNy0xNC4zIDMyLTMyIDMySDE0NGMtMzUuMyAwLTY0LTI4LjctNjQtNjRWMzUyem0yODgtNjRjMzUuMyAwIDY0IDI4LjcgNjQgNjR2NjRjMCAzNS4zLTI4LjcgNjQtNjQgNjRIMzUyYy0xNy43IDAtMzItMTQuMy0zMi0zMlYzMjBjMC0xNy43IDE0LjMtMzIgMzItMzJoMTZ6Ii8+PC9zdmc+" preserveAspectRatio="none" opacity="0.5"/><path d="M 213.6 135.18 L 213.69 123" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 221.75 115.06 Q 221.69 123.06 213.69 123 Q 205.69 122.94 205.75 114.94" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 5 5 L 65 5 L 65 5 L 55 20 L 5 20 Z" fill="#66b2ff" stroke="#36393d" stroke-miterlimit="10" pointer-events="all"/><path d="M 65 5 L 145 5 L 145 205 L 5 205 L 5 20" fill="none" stroke="#36393d" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 58px; height: 1px; padding-top: 12px; margin-left: 6px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">PSE²</div></div></div></foreignObject><text x="35" y="16" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">PSE²</text></switch></g><path d="M 85 33 L 85 20" fill="none" stroke="#d79b00" stroke-miterlimit="10" pointer-events="none"/><path d="M 93 12 Q 93 20 85 20 Q 77 20 77 12" fill="none" stroke="#d79b00" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 49px; height: 1px; padding-top: 15px; margin-left: 91px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;"><div><font>E-Mail</font></div></div></div></div></foreignObject><text x="116" y="19" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">E-Mail</text></switch></g><image x="120.42" y="162.67" width="20" height="17.32" xlink:href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNjEuNzYgMjI2LjY5IiB2ZXJzaW9uPSIxLjEiPjxnIHRyYW5zZm9ybT0ibWF0cml4KDEuMzMzMyAwIDAgLTEuMzMzMyAtNzYuMzExIDMxMy4zNCkiPjxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKDE3OC4wNiAyMzUuMDEpIj48cGF0aCBmaWxsPSIjNDFiODgzIiBkPSJtMCAwLTIyLjY2OS0zOS4yNjQtMjIuNjY5IDM5LjI2NGgtNzUuNDkxbDk4LjE2LTE3MC4wMiA5OC4xNiAxNzAuMDJ6Ii8+PC9nPjxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKDE3OC4wNiAyMzUuMDEpIj48cGF0aCBmaWxsPSIjMzQ0OTVlIiBkPSJtMCAwLTIyLjY2OS0zOS4yNjQtMjIuNjY5IDM5LjI2NGgtMzYuMjI3bDU4Ljg5Ni0xMDIuMDEgNTguODk2IDEwMi4wMXoiLz48L2c+PC9nPjwvc3ZnPg==" preserveAspectRatio="none" pointer-events="none"/><image x="111.42" y="53" width="21" height="21" xlink:href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZlcnNpb249IjEuMSIgaGVpZ2h0PSIyNTAwIiB3aWR0aD0iMjQ5OSIgdmlld0JveD0iMCAwIDc2Ny44IDc2OCIgaWQ9IkxheWVyXzEiPiYjeGE7ICA8ZGVmcyBpZD0iZGVmczkiLz4mI3hhOyAgJiN4YTsgIDxzdHlsZSBpZD0ic3R5bGUyIj4uc3Qwe2ZpbGw6Izc3YmMxZn08L3N0eWxlPiYjeGE7ICA8cGF0aCBpZD0icGF0aDQiIGQ9Ik02OTguMyA0MGMtMTAuOCAyNS44LTI0LjUgNTAuMy00MSA3Mi44QzU4NS4xIDQwLjYgNDg3LjEgMCAzODUgMCAxNzMuOCAwIDAgMTc0IDAgMzg1LjUgMCA0OTEgNDMuMiA1OTIgMTE5LjYgNjY0LjhsMTQuMiAxMi42YzY5LjQgNTguNSAxNTcuMyA5MC43IDI0OCA5MC43IDIwMC44IDAgMzY5LjYtMTU3LjQgMzgzLjktMzU4IDEwLjUtOTguMi0xOC4zLTIyMi40LTY3LjQtMzcwLjF6bS01MjQgNjI3Yy02LjIgNy43LTE1LjcgMTIuMi0yNS42IDEyLjItMTguMSAwLTMyLjktMTQuOS0zMi45LTMzczE0LjktMzMgMzIuOS0zM2M3LjUgMCAxNC45IDIuNiAyMC43IDcuNCAxNC4xIDExLjQgMTYuMyAzMi4zIDQuOSA0Ni40em01MjIuNC0xMTUuNGMtOTUgMTI2LjctMjk3LjkgODQtNDI4IDkwLjEgMCAwLTIzLjEgMS40LTQ2LjMgNS4yIDAgMCA4LjctMy43IDIwLTggOTEuMy0zMS44IDEzNC41LTM4IDE5MC02Ni41IDEwNC41LTUzLjIgMjA3LjgtMTY5LjYgMjI5LjMtMjkwLjdDNjIxLjkgMzk4LjIgNTAxLjMgNDk4LjMgMzkxLjQgNTM5Yy03NS4zIDI3LjgtMjExLjMgNTQuOC0yMTEuMyA1NC44bC01LjUtMi45QzgyIDU0NS44IDc5LjIgMzQ1LjEgMjQ3LjUgMjgwLjNjNzMuNy0yOC40IDE0NC4yLTEyLjggMjIzLjgtMzEuOCA4NS0yMC4yIDE4My4zLTg0IDIyMy4zLTE2Ny4yIDQ0LjggMTMzLjEgOTguNyAzNDEuNSAyLjEgNDcwLjN6IiBjbGFzcz0ic3QwIi8+JiN4YTsgIDxwYXRoIHRyYW5zZm9ybT0ibWF0cml4KDAuMzA3MjQyOSwwLDAsMC4zMDcyNDI5LDAsLTAuMDUzNjIxNDUpIiBpZD0icGF0aDM3NiIgZD0ibSA3NzMuMTIxMzksMjA4OC4wMDI0IGMgMzguMzM3NjQsLTE1LjE5MjQgMTQ4LjU1NjkzLC01MS4yNDE3IDI4NS40MDQ2MSwtOTMuMzQ3MSAyMDAuNTU5LC02MS43MDc5IDI2My4wNjc5LC04NS4yODAzIDM1OS40NjUzLC0xMzUuNTU1OSAyOTAuNjIzNSwtMTUxLjU3MzIgNTUzLjMzMjQsLTQzNS42NzQ5IDY3My43NDU0LC03MjguNjA5NSAyMi41MzM3LC01NC44MTg3IDQxLjY0NzgsLTExMy42NDE1IDUyLjczMjQsLTE2Mi4yODE4MSAxMi43MjMyLC01NS44MzA4NSAxMC42OTIzLC01Ny41MjI4MyAtOS4zNjA0LC03Ljc5ODAxIC0xMDIuOTE3NywyNTUuMjA1NzIgLTMyNy45MzA0LDUwMC43NTc3MiAtNjE3Ljc2NzcsNjc0LjE1NzkyIC0xNTYuMTEyMSw5My4zOTY3IC0yOTkuNzg3OSwxNDYuODQ2MyAtNTg3LjA2NjQzLDIxOC4zOTc3IC0xMjkuOTU3MDEsMzIuMzY3OSAtMzI1LjI1NDUyLDc2LjIyNTEgLTMzOS40MzI4LDc2LjIyNTEgLTMuMjAyMDIsMCAtMTQuMzAyODUsLTQuMjU4NiAtMjQuNjY4NTIsLTkuNDYzNSAtNzkuMjIxNTksLTM5Ljc3OTUgLTE0Mi44MTI1NSwtMTIwLjI0MTIgLTE3NS4yNTUwOCwtMjIxLjc1MDQgLTE2LjE2NTY1LC01MC41ODA2IC0yMi43MjIwOCwtODkuNDU4NyAtMjQuOTk1NTksLTE0OC4yMTc5IC0zLjEwNTU4LC04MC4yNjQgNi4wNjg1NiwtMTQ0LjMwMTMgMzEuNzYwOTUsLTIyMS42OTc3IDYyLjU4MjUxLC0xODguNTI1MSAyMDUuODk5MDIsLTMzNC4zNTEzMyA0MDQuOTMyNjIsLTQxMi4wMjM2MiAxMDYuNTk0NDQsLTQxLjU5ODE5IDE5Ni45MTc2NywtNTYuMTQ3MDcgNDI3LjUxMzk1LC02OC44NjIyMSAyNDguNTk5NCwtMTMuNzA3OCAzNzAuMjg2NywtNDEuMTY2MjkgNTM0LjY4MiwtMTIwLjY0OTkzIDIxMC4yMTA1LC0xMDEuNjM0ODcgMzgyLjE3NDksLTI1My41NjkyIDQ3Ni4xMzk2LC00MjAuNjc5OTUgbCAxOS45OTI5LC0zNS41NTYxNCAxNi4yNjM0LDUwLjAwNzAxIGMgMTg0LjQ2OTYsNTY3LjIxMTA5IDIxMi43NzMsOTkxLjEyMjE0IDg2Ljc5NzgsMTMwMC4wMDcwNCAtNDIuNjgxLDEwNC42NTE4IC0xMTEuOTQ0MiwyMDQuNzAzNyAtMTg2LjQ3NzMsMjY5LjM2OTggLTgzLjQ3MDksNzIuNDIwNiAtMTkwLjc3MSwxMjYuMjg1IC0zMTYuNjk3MiwxNTguOTgxMiAtMTYyLjYzOTMsNDIuMjI4NSAtMzM2LjQ1NjQsNTEuNzE1MSAtNzI4LjI0NDYsMzkuNzQ2IC0xNjUuNjgzNjMsLTUuMDYxNyAtMjQ5LjQ1ODQxLC0zLjc0NDcgLTMyOC43NTcyMiw1LjE2ODMgLTYxLjg2MTcxLDYuOTUzIC02Mi4xNjI3NSw2Ljg5ODQgLTMwLjcwODA5LC01LjU2NjQgeiIgc3R5bGU9ImZpbGw6I2ZmZmZmZjtmaWxsLXJ1bGU6ZXZlbm9kZDtzdHJva2Utd2lkdGg6NjguMjcxOCIvPiYjeGE7ICA8cGF0aCB0cmFuc2Zvcm09Im1hdHJpeCgwLjMwNzI0MjksMCwwLDAuMzA3MjQyOSwwLC0wLjA1MzYyMTQ1KSIgaWQ9InBhdGgzNzgiIGQ9Im0gNDQ5LjMyMSwyMjAzLjE2OTIgYyAtMzUuNzc2OTYsLTEyLjA4NDYgLTY1LjkwNTM3LC01MS44NjIzIC02OS4wNjE0LC05MS4xNzk4IC0yLjcxNjk0LC0zMy44NDc0IDUuOTc2MiwtNTYuNjEyMSAzMS4yNjU0MSwtODEuODc0NiAzMC45MDU1NywtMzAuODczIDYzLjA4NTMyLC0zOS4wMDM4IDEwNS4wNDc5NiwtMjYuNTQyMiAyNi41NTE4MSw3Ljg4NSA1Ny42MzcwNCwzOC42ODM4IDY2Ljc1NzE3LDY2LjE0MTkgMTYuMTY1MzUsNDguNjY5MyAtNi4xMzg4OCwxMDQuMTEzMiAtNTEuMDIyNzcsMTI2LjgzMjQgLTE5LjY4MjExLDkuOTYyNiAtNjIuODg5NDMsMTMuNDEwNSAtODIuOTg2MzcsNi42MjIzIHoiIHN0eWxlPSJmaWxsOiNmZmZmZmY7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlLXdpZHRoOjY4LjI3MTgiLz4mI3hhOzwvc3ZnPg==" preserveAspectRatio="none" pointer-events="none"/><image x="108.91" y="72.5" width="24.51" height="20" xlink:href="data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMzA5Ljg4IDI1Mi43MiIgZGF0YS1uYW1lPSJMYXllciAxIiBpZD0iTGF5ZXJfMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4mI3hhOyAgPGRlZnM+JiN4YTsgICAgPHN0eWxlPi5jbHMtMXtmaWxsOiMwMDM1NDU7fTwvc3R5bGU+JiN4YTsgIDwvZGVmcz4mI3hhOyAgPHRpdGxlPk1EQi1WTG9nb19SR0I8L3RpdGxlPiYjeGE7ICA8cGF0aCB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtNS41OCAtNi40KSIgZD0iTTYxLjc0LDIxNC45MSw3MywyNTguNDZoLTguNUw1NywyMjcuMDksNDIuODYsMjU4LjQ2SDM1LjY4TDIxLjYyLDIyNy4yNywxMy45LDI1OC40Nkg1LjU4bDExLjE2LTQzLjU1SDI0LjFsMTUuMiwzMy43MiwxNS4xNC0zMy43MloiIGNsYXNzPSJjbHMtMSIvPiYjeGE7ICA8cGF0aCB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtNS41OCAtNi40KSIgZD0iTTEwNS4xMSwyMzEuNzR2LTUuMDdoOC4yMXYzMS43OWgtOC4yMXYtNS4xMmMtMi4xNywzLjY4LTYuNjMsNS43OS0xMi4wNiw1Ljc5LTExLjM1LDAtMTcuNjgtOC0xNy42OC0xNy4yLDAtOC44Nyw2LTE2LDE2LjQ3LTE2Qzk3LjgxLDIyNiwxMDIuNzYsMjI4LDEwNS4xMSwyMzEuNzRabS0yMSwxMC42MmMwLDUuODUsMy42OCwxMC44NiwxMC44LDEwLjg2LDYuODcsMCwxMC42MS00Ljg5LDEwLjYxLTEwLjY4cy0zLjg2LTEwLjc0LTExLTEwLjc0Qzg3LjY4LDIzMS44LDg0LjEyLDIzNi43NCw4NC4xMiwyNDIuMzZaIiBjbGFzcz0iY2xzLTEiLz4mI3hhOyAgPHBhdGggdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTUuNTggLTYuNCkiIGQ9Ik0xMzEuODMsMjU4LjQ2aC04LjJWMjI2LjY3aDguMnY3LjEyQTEyLjU4LDEyLjU4LDAsMCwxLDE0My4yOSwyMjZhMTQuODQsMTQuODQsMCwwLDEsNS4xMy44NGwtMS43NSw2YTE4LDE4LDAsMCwwLTQuMzQtLjZjLTUuOTIsMC0xMC41LDQuNDYtMTAuNSwxMVoiIGNsYXNzPSJjbHMtMSIvPiYjeGE7ICA8cGF0aCB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtNS41OCAtNi40KSIgZD0iTTE1Mi41MiwyMTguMjhhNC4xNyw0LjE3LDAsMCwxLDQuNC00LjI4LDQuMzMsNC4zMywwLDAsMSw0LjQ3LDQuNDEsNC4xNSw0LjE1LDAsMCwxLTQuNDcsNC4yMkE0LjIyLDQuMjIsMCwwLDEsMTUyLjUyLDIxOC4yOFptLjM2LDguMzloOC4yMVYyNDkuOWMwLDEuNDQuMywyLjQ3LDEuNSwyLjQ3YTguODUsOC44NSwwLDAsMCwxLjU3LS4xOGwxLjI3LDZhMTQuMzYsMTQuMzYsMCwwLDEtNS40MywxYy0zLjQ0LDAtNy4xMi0xLTcuMTItOC44MVoiIGNsYXNzPSJjbHMtMSIvPiYjeGE7ICA8cGF0aCB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtNS41OCAtNi40KSIgZD0iTTE5Ny43NiwyMzEuNzR2LTUuMDdIMjA2djMxLjc5aC04LjIxdi01LjEyYy0yLjE3LDMuNjgtNi42Myw1Ljc5LTEyLjA2LDUuNzktMTEuMzQsMC0xNy42OC04LTE3LjY4LTE3LjIsMC04Ljg3LDYtMTYsMTYuNDctMTZDMTkwLjQ2LDIyNiwxOTUuNDEsMjI4LDE5Ny43NiwyMzEuNzRabS0yMSwxMC42MmMwLDUuODUsMy42OCwxMC44NiwxMC44LDEwLjg2LDYuODgsMCwxMC42Mi00Ljg5LDEwLjYyLTEwLjY4cy0zLjg3LTEwLjc0LTExLTEwLjc0QzE4MC4zMywyMzEuOCwxNzYuNzcsMjM2Ljc0LDE3Ni43NywyNDIuMzZaIiBjbGFzcz0iY2xzLTEiLz4mI3hhOyAgPHBhdGggdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTUuNTggLTYuNCkiIGQ9Ik0yMTguNTcsMjE0LjkxaDE5LjY3YzE2LjUzLDAsMjQuNzksOS4xMSwyNC42NywyMS43Ny4xMiwxMy4xNi05LDIxLjc4LTIzLjIyLDIxLjc4SDIxOC41N1ptNS40MywzLjg2djM1Ljg5aDE1YzEzLjE1LDAsMTguMTYtOC44NywxOC4xNi0xOC4xLDAtMTAuNDMtNi4yNy0xNy43OS0xOC4xNi0xNy43OVoiIGNsYXNzPSJjbHMtMSIvPiYjeGE7ICA8cGF0aCB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtNS41OCAtNi40KSIgZD0iTTI5Ni40NSwyNTguNDZoLTI1VjIxNC45MUgyOTRjOC42MiwwLDE2LjgzLDEuNjIsMTYuNzEsMTEuMjgsMCw2LjgxLTQuMjMsOC42OS04LjY5LDkuNDEsNi4zMy41NCwxMC4xNCw0LjU4LDEwLjE0LDExLjFDMzEyLjIsMjU2LjQ3LDMwMy42MywyNTguNDYsMjk2LjQ1LDI1OC40NlptLTEuODctMjQuNTVjOC42MywwLDEwLjU2LTMuMzIsMTAuNTYtNy41NCwwLTYuMzQtMy44Ni03Ljc4LTEwLjU2LTcuNzhIMjc2LjY2djE1LjMyWm0uMjQsMy42OEgyNzYuNjZ2MTcuMTlIMjk1LjZjNS4zMSwwLDEwLjkyLTEuNzUsMTAuOTItOC40NEMzMDYuNTIsMjM4LjYyLDMwMC4wNywyMzcuNTksMjk0LjgyLDIzNy41OVoiIGNsYXNzPSJjbHMtMSIvPiYjeGE7ICA8cGF0aCB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtNS41OCAtNi40KSIgZD0iTTMxNC4wOCw3LjM1YTQuMTgsNC4xOCwwLDAsMC0yLjg0LS45NWMtMi44MywwLTYuNDksMS45Mi04LjQ2LDIuOTVsLS43OC40YTI2Ljg2LDI2Ljg2LDAsMCwxLTEwLjU3LDIuNjZjLTMuNzYuMTItNywuMzQtMTEuMjIuNzgtMjUsMi41Ny0zNi4xNSwyMS43My00Ni44OSw0MC4yNkMyMjcuNDcsNjMuNTMsMjIxLjQzLDc0LDIxMy4xNSw4MmE1NC40LDU0LjQsMCwwLDEtNS40NSw0LjYzQzE5OS4xMyw5MywxODguMzcsOTcuNTUsMTgwLDEwMC43N2MtOC4wNiwzLjA4LTE2Ljg2LDUuODUtMjUuMzYsOC41My03Ljc5LDIuNDUtMTUuMTQsNC43Ny0yMS45LDcuMjgtMy4wNSwxLjEzLTUuNjQsMi03LjkzLDIuNzYtNi4xNiwyLTEwLjYsMy41My0xNy4wOSw4LTIuNTMsMS43My01LjA3LDMuNi02Ljc5LDVhNzEuNjIsNzEuNjIsMCwwLDAtMTMuNTUsMTQuMjdBODQuMjUsODQuMjUsMCwwLDEsNzYsMTYwLjI3Yy0xLjM3LDEuMzQtMy44LDItNy40NCwyLTQuMjYsMC05LjQzLS44OC0xNC45LTEuODEtNS42NC0xLTExLjQ3LTEuOTUtMTYuNDctMS45NS00LjA2LDAtNy4xNy42Ni05LjQ5LDIsMCwwLTMuOTEsMi4yOC01LjU2LDUuMjNsMS42Mi43M2EzMy4yMSwzMy4yMSwwLDAsMSw2LjkyLDUsMzQuNzIsMzQuNzIsMCwwLDAsNy4yLDUuMTJBNi4xOCw2LjE4LDAsMCwxLDQwLjEsMTc4Yy0uNjgsMS0xLjY4LDIuMjktMi43MywzLjY3LTUuNzcsNy41NS05LjE0LDEyLjMyLTcuMjEsMTQuOTJhNi4wNyw2LjA3LDAsMCwwLDMsLjY4YzEyLjU4LDAsMTkuMzQtMy4yNywyNy44OS03LjQxLDIuNDgtMS4yLDUtMi40Myw4LTMuNyw1LTIuMTcsMTAuMzgtNS42MywxNi4wOS05LjI5QzkyLjYxLDE3MiwxMDAuNDIsMTY3LDEwOCwxNjQuNTlhNjIuMyw2Mi4zLDAsMCwxLDE5LjIzLTIuN2M4LDAsMTYuNDIsMS4wNywyNC41NCwyLjExLDYuMDUuNzgsMTIuMzIsMS41OCwxOC40NywxLjk1LDIuMzkuMTQsNC42LjIxLDYuNzUuMjFhNzguMjEsNzguMjEsMCwwLDAsOC42MS0uNDVsLjY5LS4yNGM0LjMxLTIuNjUsNi4zMy04LjM0LDguMjktMTMuODQsMS4yNi0zLjU0LDIuMzItNi43Miw0LTguNzRhMi41NSwyLjU1LDAsMCwxLC4zMi0uMjcuNC40LDAsMCwxLC40OS4wOHMwLC4wNSwwLC4xNmMtMSwyMS41MS05LjY2LDM1LjE3LTE4LjQyLDQ3LjMxbC01Ljg1LDYuMjdzOC4xOSwwLDEyLjg1LTEuOGMxNy01LjA4LDI5LjgzLTE2LjI4LDM5LjE3LTM0LjE0YTE0NS43LDE0NS43LDAsMCwwLDYuMTctMTQuMDljLjE2LS40LDEuNjMtMS4xNCwxLjQ5LjkzLS4wNS42MS0uMDksMS4yOS0uMTQsMmgwYzAsLjQyLDAsLjg1LS4wOCwxLjI4LS4yNCwzLS45NSw5LjM0LS45NSw5LjM0bDUuMjUtMi44MWMxMi42Ni04LDIyLjQyLTI0LjE0LDI5LjgyLTQ5LjI1LDMuMDgtMTAuNDYsNS4zNC0yMC44NSw3LjMzLTMwLDIuMzgtMTEsNC40My0yMC40Myw2Ljc4LTI0LjA5LDMuNjktNS43NCw5LjMyLTkuNjIsMTQuNzctMTMuMzkuNzQtLjUxLDEuNDktMSwyLjIyLTEuNTQsNi44NS00LjgxLDEzLjY2LTEwLjM2LDE1LjE2LTIwLjcxbDAtLjIzQzMxNi4wNSwxMC4yMiwzMTUuMTMsOC4yNSwzMTQuMDgsNy4zNVoiIGNsYXNzPSJjbHMtMSIvPiYjeGE7PC9zdmc+" preserveAspectRatio="none" pointer-events="none"/><image x="119.97" y="182" width="19.45" height="15.5" xlink:href="data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9IjQwOCIgd2lkdGg9IjUxMiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgNTEyIDQwOCI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiB5Mj0iMzY1Ljk0NSIgeTE9IjEwLjc5OCIgeDI9IjUyMy40OCIgeDE9Ijc2LjA3OSIgaWQ9ImJzLWxvZ28tYSI+PHN0b3Agc3RvcC1jb2xvcj0iIzkwMTNmZSIvPjxzdG9wIHN0b3AtY29sb3I9IiM2NjEwZjIiIG9mZnNldD0iMSIvPjwvbGluZWFyR3JhZGllbnQ+PGxpbmVhckdyYWRpZW50IGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiB5Mj0iMjc4Ljg3MiIgeTE9IjEwOS43NCIgeDI9IjI5My41MTQiIHgxPSIxOTMuNTA4IiBpZD0iYnMtbG9nby1iIj48c3RvcCBzdG9wLWNvbG9yPSIjZmZmIi8+PHN0b3Agc3RvcC1jb2xvcj0iI2YxZTVmYyIgb2Zmc2V0PSIxIi8+PC9saW5lYXJHcmFkaWVudD48ZmlsdGVyIGZpbHRlclVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgY29sb3ItaW50ZXJwb2xhdGlvbi1maWx0ZXJzPSJzUkdCIiB5PSI4My40NTciIHg9IjE2MS45MDEiIGhlaWdodD0iMjQ5IiB3aWR0aD0iMTk3IiBpZD0iYnMtbG9nby1jIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxmZUZsb29kIHJlc3VsdD0iQmFja2dyb3VuZEltYWdlRml4IiBmbG9vZC1vcGFjaXR5PSIwIi8+PGZlQ29sb3JNYXRyaXggdmFsdWVzPSIwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAxMjcgMCIgaW49IlNvdXJjZUFscGhhIi8+PGZlT2Zmc2V0IGR5PSI0Ii8+PGZlR2F1c3NpYW5CbHVyIHN0ZERldmlhdGlvbj0iOCIvPjxmZUNvbG9yTWF0cml4IHZhbHVlcz0iMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMC4xNSAwIi8+PGZlQmxlbmQgcmVzdWx0PSJlZmZlY3QxX2Ryb3BTaGFkb3ciIGluMj0iQmFja2dyb3VuZEltYWdlRml4Ii8+PGZlQmxlbmQgcmVzdWx0PSJzaGFwZSIgaW4yPSJlZmZlY3QxX2Ryb3BTaGFkb3ciIGluPSJTb3VyY2VHcmFwaGljIi8+PC9maWx0ZXI+PC9kZWZzPjxwYXRoIGQ9Ik01Ni40ODEgNTMuMzJDNTUuNTE1IDI1LjU4IDc3LjEyOCAwIDEwNi4zNDIgMGgyOTkuMzUzYzI5LjIxNCAwIDUwLjgyNyAyNS41OCA0OS44NjEgNTMuMzItLjkyOCAyNi42NDcuMjc3IDYxLjE2NSA4Ljk2NCA4OS4zMSA4LjcxNSAyOC4yMzIgMjMuNDExIDQ2LjA3NyA0Ny40OCA0OC4zN3YyNmMtMjQuMDY5IDIuMjkzLTM4Ljc2NSAyMC4xMzgtNDcuNDggNDguMzctOC42ODcgMjguMTQ1LTkuODkyIDYyLjY2My04Ljk2NCA4OS4zMTEuOTY2IDI3LjczOS0yMC42NDcgNTMuMzE5LTQ5Ljg2MSA1My4zMTlIMTA2LjM0MmMtMjkuMjE0IDAtNTAuODI3LTI1LjU4LTQ5Ljg2LTUzLjMxOS45MjctMjYuNjQ4LS4yNzgtNjEuMTY2LTguOTY2LTg5LjMxMUMzOC44MDIgMjM3LjEzOCAyNC4wNyAyMTkuMjkzIDAgMjE3di0yNmMyNC4wNjktMi4yOTMgMzguODAyLTIwLjEzOCA0Ny41MTYtNDguMzcgOC42ODgtMjguMTQ1IDkuODkzLTYyLjY2MyA4Ljk2NS04OS4zMXoiIGZpbGw9InVybCgjYnMtbG9nby1hKSIvPjxwYXRoIGQ9Ik0yNjcuMTAzIDMxMi40NTdjNDcuMjk3IDAgNzUuNzk4LTIzLjE1OCA3NS43OTgtNjEuMzU1IDAtMjguODczLTIwLjMzNi00OS43NzYtNTAuNTMyLTUzLjA4NXYtMS4yMDNjMjIuMTg1LTMuNjA5IDM5LjU5NC0yNC4yMTEgMzkuNTk0LTQ3LjIxOSAwLTMyLjc4My0yNS44ODItNTQuMTM4LTY1LjMyMi01NC4xMzhoLTg4Ljc0djIxN2g4OS4yMDJ6bS01NC42OTItMTg5LjQ4aDQ1LjkxMWMyNC45NTggMCAzOS4xMzEgMTEuMTI4IDM5LjEzMSAzMS4yNzkgMCAyMS41MDUtMTYuNDg0IDMzLjUzNS00Ni4zNzIgMzMuNTM1aC0zOC42N3YtNjQuODE0em0wIDE2MS45NjF2LTcxLjQzMWg0NS42MDJjMzIuNjYxIDAgNDkuNjA4IDEyLjAzIDQ5LjYwOCAzNS40OSAwIDIzLjQ1OS0xNi40ODQgMzUuOTQxLTQ3LjYwNSAzNS45NDFoLTQ3LjYwNXoiIHN0cm9rZT0iI2ZmZiIgZmlsdGVyPSJ1cmwoI2JzLWxvZ28tYykiIGZpbGw9InVybCgjYnMtbG9nby1iKSIvPjwvc3ZnPg==" preserveAspectRatio="none" pointer-events="none"/></g><switch><g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/><a transform="translate(0,-5)" xlink:href="https://www.diagrams.net/doc/faq/svg-export-text-problems" target="_blank"><text text-anchor="middle" font-size="10px" x="50%" y="100%">Text is not SVG - cannot display</text></a></switch></svg> \ No newline at end of file
diff --git a/40-abschlusspraesentation/assets/diagrams/componentdiagram.puml b/40-abschlusspraesentation/assets/diagrams/componentdiagram.puml
new file mode 100644
index 0000000..7e23754
--- /dev/null
+++ b/40-abschlusspraesentation/assets/diagrams/componentdiagram.puml
@@ -0,0 +1,79 @@
+@startuml
+
+[App] as app
+[VueRouter] as router
+
+[EpisodesViewComponent] as episodes_view
+[ForgotPasswordViewComponent] as forgot_password_view
+[LoginViewComponent] as login_view
+[RegistrationViewComponent] as registration_view
+[ResetPasswordViewComponent] as reset_password_view
+[settingsViewComponent] as settings_view
+[SubscriptionsViewComponent] as subscriptions_view
+
+[DashboardLayoutComponent] as dashboard_layout
+[EpisodeComponent] as episode
+[ErrorLogComponent] as error_log
+[FloatingLabelInputComponent] as floating_label_input
+[FormLayoutComponent] as form_layout
+[HelpComponent] as help
+[LastUpdateComponent] as last_update
+[LoadingComponent] as loading
+[NavbarComponent] as navbar
+[PasswordInputComponent] as password_input
+[PasswordValidatorComponent] as password_validator
+[ProgressTimeComponent] as progress_time
+[SubscriptionComponent] as subscription
+
+app --> router
+app --> navbar
+app --> help
+app --> error_log
+
+password_validator --> password_input
+password_input --> floating_label_input
+
+router --> registration_view
+router --> login_view
+router --> reset_password_view
+router --> forgot_password_view
+router --> episodes_view
+router --> subscriptions_view
+router --> settings_view
+
+
+login_view --> form_layout
+login_view --> floating_label_input
+login_view --> password_input
+
+forgot_password_view --> form_layout
+forgot_password_view --> floating_label_input
+
+registration_view --> form_layout
+registration_view --> password_validator
+registration_view --> floating_label_input
+
+reset_password_view --> form_layout
+reset_password_view --> password_validator
+
+settings_view --> dashboard_layout
+settings_view --> floating_label_input
+settings_view --> password_input
+settings_view --> password_validator
+
+episodes_view --> dashboard_layout
+episodes_view --> episode
+episodes_view --> loading
+
+episode --> last_update
+episode --> progress_time
+
+subscriptions_view --> dashboard_layout
+subscriptions_view --> floating_label_input
+subscriptions_view --> loading
+subscriptions_view --> subscription
+
+subscription --> last_update
+subscription --> progress_time
+
+@enduml
diff --git a/40-abschlusspraesentation/assets/diagrams/packageDiagram1.puml b/40-abschlusspraesentation/assets/diagrams/packageDiagram1.puml
new file mode 100644
index 0000000..e4e5bc7
--- /dev/null
+++ b/40-abschlusspraesentation/assets/diagrams/packageDiagram1.puml
@@ -0,0 +1,67 @@
+@startuml
+allowmixing
+skinparam PackageStyle Frame
+
+package EpisodeActionApi {
+ package EpisodeActionController {}
+ package EpisodeActionService {}
+ package EpisodeActionDAO {}
+}
+
+package SubscriptionsApi {
+ package SubscriptionController {}
+ package SubscriptionService {}
+ package SubscriptionDAO {}
+}
+
+package AuthenticationApi {
+ package AuthenticationController {}
+ package AuthenticationService {}
+ package AuthenticationDAO {}
+}
+
+package Model {}
+
+database Database
+
+class PSEApplication
+
+() HTTPS
+
+HTTPS -down- PSEApplication
+
+Model .o Database: ORM
+
+PSEApplication --> EpisodeActionController
+PSEApplication --> SubscriptionController
+PSEApplication --> AuthenticationController
+
+AuthenticationController --> AuthenticationService
+AuthenticationService --> AuthenticationDAO
+AuthenticationDAO --> Database
+
+SubscriptionController --> SubscriptionService
+SubscriptionService --> SubscriptionDAO
+SubscriptionDAO --> Database
+
+EpisodeActionController --> EpisodeActionService
+EpisodeActionService --> EpisodeActionDAO
+EpisodeActionDAO --> Database
+
+hide AuthenticationController
+hide AuthenticationService
+hide AuthenticationDAO
+
+hide SubscriptionController
+hide SubscriptionService
+hide SubscriptionDAO
+
+hide EpisodeActionController
+hide EpisodeActionService
+hide EpisodeActionDAO
+
+hide Model
+
+hide Util
+
+@enduml \ No newline at end of file
diff --git a/40-abschlusspraesentation/assets/diagrams/packageDiagram2.puml b/40-abschlusspraesentation/assets/diagrams/packageDiagram2.puml
new file mode 100644
index 0000000..13335fb
--- /dev/null
+++ b/40-abschlusspraesentation/assets/diagrams/packageDiagram2.puml
@@ -0,0 +1,59 @@
+@startuml
+allowmixing
+skinparam PackageStyle Frame
+
+package EpisodeActionApi {
+ package EpisodeActionController {}
+ package EpisodeActionService {}
+ package EpisodeActionDAO {}
+}
+
+package SubscriptionsApi {
+ package SubscriptionController {}
+ package SubscriptionService {}
+ package SubscriptionDAO {}
+}
+
+package AuthenticationApi {
+ package AuthenticationController {}
+ package AuthenticationService {}
+ package AuthenticationDAO {}
+}
+
+package Model {}
+
+database Database
+
+class PSEApplication
+
+() HTTPS
+
+HTTPS -down- PSEApplication
+
+Model .o Database: ORM
+
+PSEApplication --> EpisodeActionController
+PSEApplication --> SubscriptionController
+PSEApplication --> AuthenticationController
+
+AuthenticationController --> AuthenticationService
+AuthenticationService --> AuthenticationDAO
+AuthenticationDAO --> Database
+
+SubscriptionController --> SubscriptionService
+SubscriptionService --> SubscriptionDAO
+SubscriptionDAO --> Database
+
+EpisodeActionController --> EpisodeActionService
+EpisodeActionService --> EpisodeActionDAO
+EpisodeActionDAO --> Database
+
+hide AuthenticationController
+hide AuthenticationService
+hide AuthenticationDAO
+
+hide EpisodeActionController
+hide EpisodeActionService
+hide EpisodeActionDAO
+
+@enduml \ No newline at end of file
diff --git a/40-abschlusspraesentation/assets/diagrams/packageDiagram3.puml b/40-abschlusspraesentation/assets/diagrams/packageDiagram3.puml
new file mode 100644
index 0000000..4a5a304
--- /dev/null
+++ b/40-abschlusspraesentation/assets/diagrams/packageDiagram3.puml
@@ -0,0 +1,51 @@
+@startuml
+allowmixing
+skinparam PackageStyle Frame
+
+package EpisodeActionApi {
+ package EpisodeActionController {}
+ package EpisodeActionService {}
+ package EpisodeActionDAO {}
+}
+
+package SubscriptionsApi {
+ package SubscriptionController {}
+ package SubscriptionService {}
+ package SubscriptionDAO {}
+}
+
+package AuthenticationApi {
+ package AuthenticationController {}
+ package AuthenticationService {}
+ package AuthenticationDAO {}
+}
+
+package Model {}
+
+database Database
+
+class PSEApplication
+
+() HTTPS
+
+HTTPS -down- PSEApplication
+
+Model .o Database: ORM
+
+PSEApplication --> EpisodeActionController
+PSEApplication --> SubscriptionController
+PSEApplication --> AuthenticationController
+
+AuthenticationController --> AuthenticationService
+AuthenticationService --> AuthenticationDAO
+AuthenticationDAO --> Database
+
+SubscriptionController --> SubscriptionService
+SubscriptionService --> SubscriptionDAO
+SubscriptionDAO --> Database
+
+EpisodeActionController --> EpisodeActionService
+EpisodeActionService --> EpisodeActionDAO
+EpisodeActionDAO --> Database
+
+@enduml \ No newline at end of file
diff --git a/40-abschlusspraesentation/assets/diagrams/packageDiagram4.puml b/40-abschlusspraesentation/assets/diagrams/packageDiagram4.puml
new file mode 100644
index 0000000..c88e9ae
--- /dev/null
+++ b/40-abschlusspraesentation/assets/diagrams/packageDiagram4.puml
@@ -0,0 +1,59 @@
+@startuml
+allowmixing
+skinparam PackageStyle Frame
+
+package Util {}
+
+package EpisodeActionApi {
+ package EpisodeActionController {}
+ package EpisodeActionService {}
+ package EpisodeActionDAO {}
+}
+
+package SubscriptionsApi {
+ package SubscriptionController {}
+ package SubscriptionService {}
+ package SubscriptionDAO {}
+}
+
+package AuthenticationApi {
+ package AuthenticationController {}
+ package AuthenticationService {}
+ package AuthenticationDAO {}
+}
+
+package Model {}
+
+database Database
+
+class PSEApplication
+
+() HTTPS
+
+HTTPS -down- PSEApplication
+
+Model .o Database: ORM
+
+PSEApplication --> EpisodeActionController
+PSEApplication --> SubscriptionController
+PSEApplication --> AuthenticationController
+
+AuthenticationController --> AuthenticationService
+AuthenticationService --> AuthenticationDAO
+AuthenticationDAO --> Database
+
+SubscriptionController --> SubscriptionService
+SubscriptionService --> SubscriptionDAO
+SubscriptionDAO --> Database
+
+EpisodeActionController --> EpisodeActionService
+EpisodeActionService --> EpisodeActionDAO
+EpisodeActionDAO --> Database
+
+EpisodeActionService .left.> Util: Async
+SubscriptionService .right.> Util: Async
+
+Util .left.> EpisodeActionDAO
+Util ..> SubscriptionDAO
+
+@enduml \ No newline at end of file
diff --git a/40-abschlusspraesentation/assets/docker.webp b/40-abschlusspraesentation/assets/docker.webp
new file mode 100644
index 0000000..36faa2e
--- /dev/null
+++ b/40-abschlusspraesentation/assets/docker.webp
Binary files differ
diff --git a/40-abschlusspraesentation/assets/fontawesome/LICENSE.txt b/40-abschlusspraesentation/assets/fontawesome/LICENSE.txt
new file mode 100644
index 0000000..39e18e3
--- /dev/null
+++ b/40-abschlusspraesentation/assets/fontawesome/LICENSE.txt
@@ -0,0 +1,165 @@
+Fonticons, Inc. (https://fontawesome.com)
+
+--------------------------------------------------------------------------------
+
+Font Awesome Free License
+
+Font Awesome Free is free, open source, and GPL friendly. You can use it for
+commercial projects, open source projects, or really almost whatever you want.
+Full Font Awesome Free license: https://fontawesome.com/license/free.
+
+--------------------------------------------------------------------------------
+
+# Icons: CC BY 4.0 License (https://creativecommons.org/licenses/by/4.0/)
+
+The Font Awesome Free download is licensed under a Creative Commons
+Attribution 4.0 International License and applies to all icons packaged
+as SVG and JS file types.
+
+--------------------------------------------------------------------------------
+
+# Fonts: SIL OFL 1.1 License
+
+In the Font Awesome Free download, the SIL OFL license applies to all icons
+packaged as web and desktop font files.
+
+Copyright (c) 2023 Fonticons, Inc. (https://fontawesome.com)
+with Reserved Font Name: "Font Awesome".
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1.
+This license is copied below, and is also available with a FAQ at:
+http://scripts.sil.org/OFL
+
+SIL OPEN FONT LICENSE
+Version 1.1 - 26 February 2007
+
+PREAMBLE
+The goals of the Open Font License (OFL) are to stimulate worldwide
+development of collaborative font projects, to support the font creation
+efforts of academic and linguistic communities, and to provide a free and
+open framework in which fonts may be shared and improved in partnership
+with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and
+redistributed freely as long as they are not sold by themselves. The
+fonts, including any derivative works, can be bundled, embedded,
+redistributed and/or sold with any software provided that any reserved
+names are not used by derivative works. The fonts and derivatives,
+however, cannot be released under any other type of license. The
+requirement for fonts to remain under this license does not apply
+to any document created using the fonts or their derivatives.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright
+Holder(s) under this license and clearly marked as such. This may
+include source files, build scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the
+copyright statement(s).
+
+"Original Version" refers to the collection of Font Software components as
+distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to, deleting,
+or substituting — in part or in whole — any of the components of the
+Original Version, by changing formats or by porting the Font Software to a
+new environment.
+
+"Author" refers to any designer, engineer, programmer, technical
+writer or other person who contributed to the Font Software.
+
+PERMISSION & CONDITIONS
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Font Software, to use, study, copy, merge, embed, modify,
+redistribute, and sell modified and unmodified copies of the Font
+Software, subject to the following conditions:
+
+1) Neither the Font Software nor any of its individual components,
+in Original or Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled,
+redistributed and/or sold with any software, provided that each copy
+contains the above copyright notice and this license. These can be
+included either as stand-alone text files, human-readable headers or
+in the appropriate machine-readable metadata fields within text or
+binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font
+Name(s) unless explicit written permission is granted by the corresponding
+Copyright Holder. This restriction only applies to the primary font name as
+presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
+Software shall not be used to promote, endorse or advertise any
+Modified Version, except to acknowledge the contribution(s) of the
+Copyright Holder(s) and the Author(s) or with their explicit written
+permission.
+
+5) The Font Software, modified or unmodified, in part or in whole,
+must be distributed entirely under this license, and must not be
+distributed under any other license. The requirement for fonts to
+remain under this license does not apply to any document created
+using the Font Software.
+
+TERMINATION
+This license becomes null and void if any of the above conditions are
+not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.
+
+--------------------------------------------------------------------------------
+
+# Code: MIT License (https://opensource.org/licenses/MIT)
+
+In the Font Awesome Free download, the MIT license applies to all non-font and
+non-icon files.
+
+Copyright 2023 Fonticons, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in the
+Software without restriction, including without limitation the rights to use, copy,
+modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+and to permit persons to whom the Software is furnished to do so, subject to the
+following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+--------------------------------------------------------------------------------
+
+# Attribution
+
+Attribution is required by MIT, SIL OFL, and CC BY licenses. Downloaded Font
+Awesome Free files already contain embedded comments with sufficient
+attribution, so you shouldn't need to do anything additional when using these
+files normally.
+
+We've kept attribution comments terse, so we ask that you do not actively work
+to remove them from files, especially code. They're a great way for folks to
+learn about Font Awesome.
+
+--------------------------------------------------------------------------------
+
+# Brand Icons
+
+All brand icons are trademarks of their respective owners. The use of these
+trademarks does not indicate endorsement of the trademark holder by Font
+Awesome, nor vice versa. **Please do not use brand logos for any purpose except
+to represent the company, product, or service to which they refer.**
diff --git a/40-abschlusspraesentation/assets/fontawesome/css/all.css b/40-abschlusspraesentation/assets/fontawesome/css/all.css
new file mode 100644
index 0000000..2fa60b1
--- /dev/null
+++ b/40-abschlusspraesentation/assets/fontawesome/css/all.css
@@ -0,0 +1,7955 @@
+/*!
+ * Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com
+ * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
+ * Copyright 2023 Fonticons, Inc.
+ */
+.fa {
+ font-family: var(--fa-style-family, "Font Awesome 6 Free");
+ font-weight: var(--fa-style, 900); }
+
+.fa,
+.fa-classic,
+.fa-sharp,
+.fas,
+.fa-solid,
+.far,
+.fa-regular,
+.fab,
+.fa-brands {
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+ display: var(--fa-display, inline-block);
+ font-style: normal;
+ font-variant: normal;
+ line-height: 1;
+ text-rendering: auto; }
+
+.fas,
+.fa-classic,
+.fa-solid,
+.far,
+.fa-regular {
+ font-family: 'Font Awesome 6 Free'; }
+
+.fab,
+.fa-brands {
+ font-family: 'Font Awesome 6 Brands'; }
+
+.fa-1x {
+ font-size: 1em; }
+
+.fa-2x {
+ font-size: 2em; }
+
+.fa-3x {
+ font-size: 3em; }
+
+.fa-4x {
+ font-size: 4em; }
+
+.fa-5x {
+ font-size: 5em; }
+
+.fa-6x {
+ font-size: 6em; }
+
+.fa-7x {
+ font-size: 7em; }
+
+.fa-8x {
+ font-size: 8em; }
+
+.fa-9x {
+ font-size: 9em; }
+
+.fa-10x {
+ font-size: 10em; }
+
+.fa-2xs {
+ font-size: 0.625em;
+ line-height: 0.1em;
+ vertical-align: 0.225em; }
+
+.fa-xs {
+ font-size: 0.75em;
+ line-height: 0.08333em;
+ vertical-align: 0.125em; }
+
+.fa-sm {
+ font-size: 0.875em;
+ line-height: 0.07143em;
+ vertical-align: 0.05357em; }
+
+.fa-lg {
+ font-size: 1.25em;
+ line-height: 0.05em;
+ vertical-align: -0.075em; }
+
+.fa-xl {
+ font-size: 1.5em;
+ line-height: 0.04167em;
+ vertical-align: -0.125em; }
+
+.fa-2xl {
+ font-size: 2em;
+ line-height: 0.03125em;
+ vertical-align: -0.1875em; }
+
+.fa-fw {
+ text-align: center;
+ width: 1.25em; }
+
+.fa-ul {
+ list-style-type: none;
+ margin-left: var(--fa-li-margin, 2.5em);
+ padding-left: 0; }
+ .fa-ul > li {
+ position: relative; }
+
+.fa-li {
+ left: calc(var(--fa-li-width, 2em) * -1);
+ position: absolute;
+ text-align: center;
+ width: var(--fa-li-width, 2em);
+ line-height: inherit; }
+
+.fa-border {
+ border-color: var(--fa-border-color, #eee);
+ border-radius: var(--fa-border-radius, 0.1em);
+ border-style: var(--fa-border-style, solid);
+ border-width: var(--fa-border-width, 0.08em);
+ padding: var(--fa-border-padding, 0.2em 0.25em 0.15em); }
+
+.fa-pull-left {
+ float: left;
+ margin-right: var(--fa-pull-margin, 0.3em); }
+
+.fa-pull-right {
+ float: right;
+ margin-left: var(--fa-pull-margin, 0.3em); }
+
+.fa-beat {
+ -webkit-animation-name: fa-beat;
+ animation-name: fa-beat;
+ -webkit-animation-delay: var(--fa-animation-delay, 0s);
+ animation-delay: var(--fa-animation-delay, 0s);
+ -webkit-animation-direction: var(--fa-animation-direction, normal);
+ animation-direction: var(--fa-animation-direction, normal);
+ -webkit-animation-duration: var(--fa-animation-duration, 1s);
+ animation-duration: var(--fa-animation-duration, 1s);
+ -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);
+ animation-iteration-count: var(--fa-animation-iteration-count, infinite);
+ -webkit-animation-timing-function: var(--fa-animation-timing, ease-in-out);
+ animation-timing-function: var(--fa-animation-timing, ease-in-out); }
+
+.fa-bounce {
+ -webkit-animation-name: fa-bounce;
+ animation-name: fa-bounce;
+ -webkit-animation-delay: var(--fa-animation-delay, 0s);
+ animation-delay: var(--fa-animation-delay, 0s);
+ -webkit-animation-direction: var(--fa-animation-direction, normal);
+ animation-direction: var(--fa-animation-direction, normal);
+ -webkit-animation-duration: var(--fa-animation-duration, 1s);
+ animation-duration: var(--fa-animation-duration, 1s);
+ -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);
+ animation-iteration-count: var(--fa-animation-iteration-count, infinite);
+ -webkit-animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.28, 0.84, 0.42, 1));
+ animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.28, 0.84, 0.42, 1)); }
+
+.fa-fade {
+ -webkit-animation-name: fa-fade;
+ animation-name: fa-fade;
+ -webkit-animation-delay: var(--fa-animation-delay, 0s);
+ animation-delay: var(--fa-animation-delay, 0s);
+ -webkit-animation-direction: var(--fa-animation-direction, normal);
+ animation-direction: var(--fa-animation-direction, normal);
+ -webkit-animation-duration: var(--fa-animation-duration, 1s);
+ animation-duration: var(--fa-animation-duration, 1s);
+ -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);
+ animation-iteration-count: var(--fa-animation-iteration-count, infinite);
+ -webkit-animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1));
+ animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1)); }
+
+.fa-beat-fade {
+ -webkit-animation-name: fa-beat-fade;
+ animation-name: fa-beat-fade;
+ -webkit-animation-delay: var(--fa-animation-delay, 0s);
+ animation-delay: var(--fa-animation-delay, 0s);
+ -webkit-animation-direction: var(--fa-animation-direction, normal);
+ animation-direction: var(--fa-animation-direction, normal);
+ -webkit-animation-duration: var(--fa-animation-duration, 1s);
+ animation-duration: var(--fa-animation-duration, 1s);
+ -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);
+ animation-iteration-count: var(--fa-animation-iteration-count, infinite);
+ -webkit-animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1));
+ animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1)); }
+
+.fa-flip {
+ -webkit-animation-name: fa-flip;
+ animation-name: fa-flip;
+ -webkit-animation-delay: var(--fa-animation-delay, 0s);
+ animation-delay: var(--fa-animation-delay, 0s);
+ -webkit-animation-direction: var(--fa-animation-direction, normal);
+ animation-direction: var(--fa-animation-direction, normal);
+ -webkit-animation-duration: var(--fa-animation-duration, 1s);
+ animation-duration: var(--fa-animation-duration, 1s);
+ -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);
+ animation-iteration-count: var(--fa-animation-iteration-count, infinite);
+ -webkit-animation-timing-function: var(--fa-animation-timing, ease-in-out);
+ animation-timing-function: var(--fa-animation-timing, ease-in-out); }
+
+.fa-shake {
+ -webkit-animation-name: fa-shake;
+ animation-name: fa-shake;
+ -webkit-animation-delay: var(--fa-animation-delay, 0s);
+ animation-delay: var(--fa-animation-delay, 0s);
+ -webkit-animation-direction: var(--fa-animation-direction, normal);
+ animation-direction: var(--fa-animation-direction, normal);
+ -webkit-animation-duration: var(--fa-animation-duration, 1s);
+ animation-duration: var(--fa-animation-duration, 1s);
+ -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);
+ animation-iteration-count: var(--fa-animation-iteration-count, infinite);
+ -webkit-animation-timing-function: var(--fa-animation-timing, linear);
+ animation-timing-function: var(--fa-animation-timing, linear); }
+
+.fa-spin {
+ -webkit-animation-name: fa-spin;
+ animation-name: fa-spin;
+ -webkit-animation-delay: var(--fa-animation-delay, 0s);
+ animation-delay: var(--fa-animation-delay, 0s);
+ -webkit-animation-direction: var(--fa-animation-direction, normal);
+ animation-direction: var(--fa-animation-direction, normal);
+ -webkit-animation-duration: var(--fa-animation-duration, 2s);
+ animation-duration: var(--fa-animation-duration, 2s);
+ -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);
+ animation-iteration-count: var(--fa-animation-iteration-count, infinite);
+ -webkit-animation-timing-function: var(--fa-animation-timing, linear);
+ animation-timing-function: var(--fa-animation-timing, linear); }
+
+.fa-spin-reverse {
+ --fa-animation-direction: reverse; }
+
+.fa-pulse,
+.fa-spin-pulse {
+ -webkit-animation-name: fa-spin;
+ animation-name: fa-spin;
+ -webkit-animation-direction: var(--fa-animation-direction, normal);
+ animation-direction: var(--fa-animation-direction, normal);
+ -webkit-animation-duration: var(--fa-animation-duration, 1s);
+ animation-duration: var(--fa-animation-duration, 1s);
+ -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);
+ animation-iteration-count: var(--fa-animation-iteration-count, infinite);
+ -webkit-animation-timing-function: var(--fa-animation-timing, steps(8));
+ animation-timing-function: var(--fa-animation-timing, steps(8)); }
+
+@media (prefers-reduced-motion: reduce) {
+ .fa-beat,
+ .fa-bounce,
+ .fa-fade,
+ .fa-beat-fade,
+ .fa-flip,
+ .fa-pulse,
+ .fa-shake,
+ .fa-spin,
+ .fa-spin-pulse {
+ -webkit-animation-delay: -1ms;
+ animation-delay: -1ms;
+ -webkit-animation-duration: 1ms;
+ animation-duration: 1ms;
+ -webkit-animation-iteration-count: 1;
+ animation-iteration-count: 1;
+ -webkit-transition-delay: 0s;
+ transition-delay: 0s;
+ -webkit-transition-duration: 0s;
+ transition-duration: 0s; } }
+
+@-webkit-keyframes fa-beat {
+ 0%, 90% {
+ -webkit-transform: scale(1);
+ transform: scale(1); }
+ 45% {
+ -webkit-transform: scale(var(--fa-beat-scale, 1.25));
+ transform: scale(var(--fa-beat-scale, 1.25)); } }
+
+@keyframes fa-beat {
+ 0%, 90% {
+ -webkit-transform: scale(1);
+ transform: scale(1); }
+ 45% {
+ -webkit-transform: scale(var(--fa-beat-scale, 1.25));
+ transform: scale(var(--fa-beat-scale, 1.25)); } }
+
+@-webkit-keyframes fa-bounce {
+ 0% {
+ -webkit-transform: scale(1, 1) translateY(0);
+ transform: scale(1, 1) translateY(0); }
+ 10% {
+ -webkit-transform: scale(var(--fa-bounce-start-scale-x, 1.1), var(--fa-bounce-start-scale-y, 0.9)) translateY(0);
+ transform: scale(var(--fa-bounce-start-scale-x, 1.1), var(--fa-bounce-start-scale-y, 0.9)) translateY(0); }
+ 30% {
+ -webkit-transform: scale(var(--fa-bounce-jump-scale-x, 0.9), var(--fa-bounce-jump-scale-y, 1.1)) translateY(var(--fa-bounce-height, -0.5em));
+ transform: scale(var(--fa-bounce-jump-scale-x, 0.9), var(--fa-bounce-jump-scale-y, 1.1)) translateY(var(--fa-bounce-height, -0.5em)); }
+ 50% {
+ -webkit-transform: scale(var(--fa-bounce-land-scale-x, 1.05), var(--fa-bounce-land-scale-y, 0.95)) translateY(0);
+ transform: scale(var(--fa-bounce-land-scale-x, 1.05), var(--fa-bounce-land-scale-y, 0.95)) translateY(0); }
+ 57% {
+ -webkit-transform: scale(1, 1) translateY(var(--fa-bounce-rebound, -0.125em));
+ transform: scale(1, 1) translateY(var(--fa-bounce-rebound, -0.125em)); }
+ 64% {
+ -webkit-transform: scale(1, 1) translateY(0);
+ transform: scale(1, 1) translateY(0); }
+ 100% {
+ -webkit-transform: scale(1, 1) translateY(0);
+ transform: scale(1, 1) translateY(0); } }
+
+@keyframes fa-bounce {
+ 0% {
+ -webkit-transform: scale(1, 1) translateY(0);
+ transform: scale(1, 1) translateY(0); }
+ 10% {
+ -webkit-transform: scale(var(--fa-bounce-start-scale-x, 1.1), var(--fa-bounce-start-scale-y, 0.9)) translateY(0);
+ transform: scale(var(--fa-bounce-start-scale-x, 1.1), var(--fa-bounce-start-scale-y, 0.9)) translateY(0); }
+ 30% {
+ -webkit-transform: scale(var(--fa-bounce-jump-scale-x, 0.9), var(--fa-bounce-jump-scale-y, 1.1)) translateY(var(--fa-bounce-height, -0.5em));
+ transform: scale(var(--fa-bounce-jump-scale-x, 0.9), var(--fa-bounce-jump-scale-y, 1.1)) translateY(var(--fa-bounce-height, -0.5em)); }
+ 50% {
+ -webkit-transform: scale(var(--fa-bounce-land-scale-x, 1.05), var(--fa-bounce-land-scale-y, 0.95)) translateY(0);
+ transform: scale(var(--fa-bounce-land-scale-x, 1.05), var(--fa-bounce-land-scale-y, 0.95)) translateY(0); }
+ 57% {
+ -webkit-transform: scale(1, 1) translateY(var(--fa-bounce-rebound, -0.125em));
+ transform: scale(1, 1) translateY(var(--fa-bounce-rebound, -0.125em)); }
+ 64% {
+ -webkit-transform: scale(1, 1) translateY(0);
+ transform: scale(1, 1) translateY(0); }
+ 100% {
+ -webkit-transform: scale(1, 1) translateY(0);
+ transform: scale(1, 1) translateY(0); } }
+
+@-webkit-keyframes fa-fade {
+ 50% {
+ opacity: var(--fa-fade-opacity, 0.4); } }
+
+@keyframes fa-fade {
+ 50% {
+ opacity: var(--fa-fade-opacity, 0.4); } }
+
+@-webkit-keyframes fa-beat-fade {
+ 0%, 100% {
+ opacity: var(--fa-beat-fade-opacity, 0.4);
+ -webkit-transform: scale(1);
+ transform: scale(1); }
+ 50% {
+ opacity: 1;
+ -webkit-transform: scale(var(--fa-beat-fade-scale, 1.125));
+ transform: scale(var(--fa-beat-fade-scale, 1.125)); } }
+
+@keyframes fa-beat-fade {
+ 0%, 100% {
+ opacity: var(--fa-beat-fade-opacity, 0.4);
+ -webkit-transform: scale(1);
+ transform: scale(1); }
+ 50% {
+ opacity: 1;
+ -webkit-transform: scale(var(--fa-beat-fade-scale, 1.125));
+ transform: scale(var(--fa-beat-fade-scale, 1.125)); } }
+
+@-webkit-keyframes fa-flip {
+ 50% {
+ -webkit-transform: rotate3d(var(--fa-flip-x, 0), var(--fa-flip-y, 1), var(--fa-flip-z, 0), var(--fa-flip-angle, -180deg));
+ transform: rotate3d(var(--fa-flip-x, 0), var(--fa-flip-y, 1), var(--fa-flip-z, 0), var(--fa-flip-angle, -180deg)); } }
+
+@keyframes fa-flip {
+ 50% {
+ -webkit-transform: rotate3d(var(--fa-flip-x, 0), var(--fa-flip-y, 1), var(--fa-flip-z, 0), var(--fa-flip-angle, -180deg));
+ transform: rotate3d(var(--fa-flip-x, 0), var(--fa-flip-y, 1), var(--fa-flip-z, 0), var(--fa-flip-angle, -180deg)); } }
+
+@-webkit-keyframes fa-shake {
+ 0% {
+ -webkit-transform: rotate(-15deg);
+ transform: rotate(-15deg); }
+ 4% {
+ -webkit-transform: rotate(15deg);
+ transform: rotate(15deg); }
+ 8%, 24% {
+ -webkit-transform: rotate(-18deg);
+ transform: rotate(-18deg); }
+ 12%, 28% {
+ -webkit-transform: rotate(18deg);
+ transform: rotate(18deg); }
+ 16% {
+ -webkit-transform: rotate(-22deg);
+ transform: rotate(-22deg); }
+ 20% {
+ -webkit-transform: rotate(22deg);
+ transform: rotate(22deg); }
+ 32% {
+ -webkit-transform: rotate(-12deg);
+ transform: rotate(-12deg); }
+ 36% {
+ -webkit-transform: rotate(12deg);
+ transform: rotate(12deg); }
+ 40%, 100% {
+ -webkit-transform: rotate(0deg);
+ transform: rotate(0deg); } }
+
+@keyframes fa-shake {
+ 0% {
+ -webkit-transform: rotate(-15deg);
+ transform: rotate(-15deg); }
+ 4% {
+ -webkit-transform: rotate(15deg);
+ transform: rotate(15deg); }
+ 8%, 24% {
+ -webkit-transform: rotate(-18deg);
+ transform: rotate(-18deg); }
+ 12%, 28% {
+ -webkit-transform: rotate(18deg);
+ transform: rotate(18deg); }
+ 16% {
+ -webkit-transform: rotate(-22deg);
+ transform: rotate(-22deg); }
+ 20% {
+ -webkit-transform: rotate(22deg);
+ transform: rotate(22deg); }
+ 32% {
+ -webkit-transform: rotate(-12deg);
+ transform: rotate(-12deg); }
+ 36% {
+ -webkit-transform: rotate(12deg);
+ transform: rotate(12deg); }
+ 40%, 100% {
+ -webkit-transform: rotate(0deg);
+ transform: rotate(0deg); } }
+
+@-webkit-keyframes fa-spin {
+ 0% {
+ -webkit-transform: rotate(0deg);
+ transform: rotate(0deg); }
+ 100% {
+ -webkit-transform: rotate(360deg);
+ transform: rotate(360deg); } }
+
+@keyframes fa-spin {
+ 0% {
+ -webkit-transform: rotate(0deg);
+ transform: rotate(0deg); }
+ 100% {
+ -webkit-transform: rotate(360deg);
+ transform: rotate(360deg); } }
+
+.fa-rotate-90 {
+ -webkit-transform: rotate(90deg);
+ transform: rotate(90deg); }
+
+.fa-rotate-180 {
+ -webkit-transform: rotate(180deg);
+ transform: rotate(180deg); }
+
+.fa-rotate-270 {
+ -webkit-transform: rotate(270deg);
+ transform: rotate(270deg); }
+
+.fa-flip-horizontal {
+ -webkit-transform: scale(-1, 1);
+ transform: scale(-1, 1); }
+
+.fa-flip-vertical {
+ -webkit-transform: scale(1, -1);
+ transform: scale(1, -1); }
+
+.fa-flip-both,
+.fa-flip-horizontal.fa-flip-vertical {
+ -webkit-transform: scale(-1, -1);
+ transform: scale(-1, -1); }
+
+.fa-rotate-by {
+ -webkit-transform: rotate(var(--fa-rotate-angle, none));
+ transform: rotate(var(--fa-rotate-angle, none)); }
+
+.fa-stack {
+ display: inline-block;
+ height: 2em;
+ line-height: 2em;
+ position: relative;
+ vertical-align: middle;
+ width: 2.5em; }
+
+.fa-stack-1x,
+.fa-stack-2x {
+ left: 0;
+ position: absolute;
+ text-align: center;
+ width: 100%;
+ z-index: var(--fa-stack-z-index, auto); }
+
+.fa-stack-1x {
+ line-height: inherit; }
+
+.fa-stack-2x {
+ font-size: 2em; }
+
+.fa-inverse {
+ color: var(--fa-inverse, #fff); }
+
+/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen
+readers do not read off random characters that represent icons */
+
+.fa-0::before {
+ content: "\30"; }
+
+.fa-1::before {
+ content: "\31"; }
+
+.fa-2::before {
+ content: "\32"; }
+
+.fa-3::before {
+ content: "\33"; }
+
+.fa-4::before {
+ content: "\34"; }
+
+.fa-5::before {
+ content: "\35"; }
+
+.fa-6::before {
+ content: "\36"; }
+
+.fa-7::before {
+ content: "\37"; }
+
+.fa-8::before {
+ content: "\38"; }
+
+.fa-9::before {
+ content: "\39"; }
+
+.fa-fill-drip::before {
+ content: "\f576"; }
+
+.fa-arrows-to-circle::before {
+ content: "\e4bd"; }
+
+.fa-circle-chevron-right::before {
+ content: "\f138"; }
+
+.fa-chevron-circle-right::before {
+ content: "\f138"; }
+
+.fa-at::before {
+ content: "\40"; }
+
+.fa-trash-can::before {
+ content: "\f2ed"; }
+
+.fa-trash-alt::before {
+ content: "\f2ed"; }
+
+.fa-text-height::before {
+ content: "\f034"; }
+
+.fa-user-xmark::before {
+ content: "\f235"; }
+
+.fa-user-times::before {
+ content: "\f235"; }
+
+.fa-stethoscope::before {
+ content: "\f0f1"; }
+
+.fa-message::before {
+ content: "\f27a"; }
+
+.fa-comment-alt::before {
+ content: "\f27a"; }
+
+.fa-info::before {
+ content: "\f129"; }
+
+.fa-down-left-and-up-right-to-center::before {
+ content: "\f422"; }
+
+.fa-compress-alt::before {
+ content: "\f422"; }
+
+.fa-explosion::before {
+ content: "\e4e9"; }
+
+.fa-file-lines::before {
+ content: "\f15c"; }
+
+.fa-file-alt::before {
+ content: "\f15c"; }
+
+.fa-file-text::before {
+ content: "\f15c"; }
+
+.fa-wave-square::before {
+ content: "\f83e"; }
+
+.fa-ring::before {
+ content: "\f70b"; }
+
+.fa-building-un::before {
+ content: "\e4d9"; }
+
+.fa-dice-three::before {
+ content: "\f527"; }
+
+.fa-calendar-days::before {
+ content: "\f073"; }
+
+.fa-calendar-alt::before {
+ content: "\f073"; }
+
+.fa-anchor-circle-check::before {
+ content: "\e4aa"; }
+
+.fa-building-circle-arrow-right::before {
+ content: "\e4d1"; }
+
+.fa-volleyball::before {
+ content: "\f45f"; }
+
+.fa-volleyball-ball::before {
+ content: "\f45f"; }
+
+.fa-arrows-up-to-line::before {
+ content: "\e4c2"; }
+
+.fa-sort-down::before {
+ content: "\f0dd"; }
+
+.fa-sort-desc::before {
+ content: "\f0dd"; }
+
+.fa-circle-minus::before {
+ content: "\f056"; }
+
+.fa-minus-circle::before {
+ content: "\f056"; }
+
+.fa-door-open::before {
+ content: "\f52b"; }
+
+.fa-right-from-bracket::before {
+ content: "\f2f5"; }
+
+.fa-sign-out-alt::before {
+ content: "\f2f5"; }
+
+.fa-atom::before {
+ content: "\f5d2"; }
+
+.fa-soap::before {
+ content: "\e06e"; }
+
+.fa-icons::before {
+ content: "\f86d"; }
+
+.fa-heart-music-camera-bolt::before {
+ content: "\f86d"; }
+
+.fa-microphone-lines-slash::before {
+ content: "\f539"; }
+
+.fa-microphone-alt-slash::before {
+ content: "\f539"; }
+
+.fa-bridge-circle-check::before {
+ content: "\e4c9"; }
+
+.fa-pump-medical::before {
+ content: "\e06a"; }
+
+.fa-fingerprint::before {
+ content: "\f577"; }
+
+.fa-hand-point-right::before {
+ content: "\f0a4"; }
+
+.fa-magnifying-glass-location::before {
+ content: "\f689"; }
+
+.fa-search-location::before {
+ content: "\f689"; }
+
+.fa-forward-step::before {
+ content: "\f051"; }
+
+.fa-step-forward::before {
+ content: "\f051"; }
+
+.fa-face-smile-beam::before {
+ content: "\f5b8"; }
+
+.fa-smile-beam::before {
+ content: "\f5b8"; }
+
+.fa-flag-checkered::before {
+ content: "\f11e"; }
+
+.fa-football::before {
+ content: "\f44e"; }
+
+.fa-football-ball::before {
+ content: "\f44e"; }
+
+.fa-school-circle-exclamation::before {
+ content: "\e56c"; }
+
+.fa-crop::before {
+ content: "\f125"; }
+
+.fa-angles-down::before {
+ content: "\f103"; }
+
+.fa-angle-double-down::before {
+ content: "\f103"; }
+
+.fa-users-rectangle::before {
+ content: "\e594"; }
+
+.fa-people-roof::before {
+ content: "\e537"; }
+
+.fa-people-line::before {
+ content: "\e534"; }
+
+.fa-beer-mug-empty::before {
+ content: "\f0fc"; }
+
+.fa-beer::before {
+ content: "\f0fc"; }
+
+.fa-diagram-predecessor::before {
+ content: "\e477"; }
+
+.fa-arrow-up-long::before {
+ content: "\f176"; }
+
+.fa-long-arrow-up::before {
+ content: "\f176"; }
+
+.fa-fire-flame-simple::before {
+ content: "\f46a"; }
+
+.fa-burn::before {
+ content: "\f46a"; }
+
+.fa-person::before {
+ content: "\f183"; }
+
+.fa-male::before {
+ content: "\f183"; }
+
+.fa-laptop::before {
+ content: "\f109"; }
+
+.fa-file-csv::before {
+ content: "\f6dd"; }
+
+.fa-menorah::before {
+ content: "\f676"; }
+
+.fa-truck-plane::before {
+ content: "\e58f"; }
+
+.fa-record-vinyl::before {
+ content: "\f8d9"; }
+
+.fa-face-grin-stars::before {
+ content: "\f587"; }
+
+.fa-grin-stars::before {
+ content: "\f587"; }
+
+.fa-bong::before {
+ content: "\f55c"; }
+
+.fa-spaghetti-monster-flying::before {
+ content: "\f67b"; }
+
+.fa-pastafarianism::before {
+ content: "\f67b"; }
+
+.fa-arrow-down-up-across-line::before {
+ content: "\e4af"; }
+
+.fa-spoon::before {
+ content: "\f2e5"; }
+
+.fa-utensil-spoon::before {
+ content: "\f2e5"; }
+
+.fa-jar-wheat::before {
+ content: "\e517"; }
+
+.fa-envelopes-bulk::before {
+ content: "\f674"; }
+
+.fa-mail-bulk::before {
+ content: "\f674"; }
+
+.fa-file-circle-exclamation::before {
+ content: "\e4eb"; }
+
+.fa-circle-h::before {
+ content: "\f47e"; }
+
+.fa-hospital-symbol::before {
+ content: "\f47e"; }
+
+.fa-pager::before {
+ content: "\f815"; }
+
+.fa-address-book::before {
+ content: "\f2b9"; }
+
+.fa-contact-book::before {
+ content: "\f2b9"; }
+
+.fa-strikethrough::before {
+ content: "\f0cc"; }
+
+.fa-k::before {
+ content: "\4b"; }
+
+.fa-landmark-flag::before {
+ content: "\e51c"; }
+
+.fa-pencil::before {
+ content: "\f303"; }
+
+.fa-pencil-alt::before {
+ content: "\f303"; }
+
+.fa-backward::before {
+ content: "\f04a"; }
+
+.fa-caret-right::before {
+ content: "\f0da"; }
+
+.fa-comments::before {
+ content: "\f086"; }
+
+.fa-paste::before {
+ content: "\f0ea"; }
+
+.fa-file-clipboard::before {
+ content: "\f0ea"; }
+
+.fa-code-pull-request::before {
+ content: "\e13c"; }
+
+.fa-clipboard-list::before {
+ content: "\f46d"; }
+
+.fa-truck-ramp-box::before {
+ content: "\f4de"; }
+
+.fa-truck-loading::before {
+ content: "\f4de"; }
+
+.fa-user-check::before {
+ content: "\f4fc"; }
+
+.fa-vial-virus::before {
+ content: "\e597"; }
+
+.fa-sheet-plastic::before {
+ content: "\e571"; }
+
+.fa-blog::before {
+ content: "\f781"; }
+
+.fa-user-ninja::before {
+ content: "\f504"; }
+
+.fa-person-arrow-up-from-line::before {
+ content: "\e539"; }
+
+.fa-scroll-torah::before {
+ content: "\f6a0"; }
+
+.fa-torah::before {
+ content: "\f6a0"; }
+
+.fa-broom-ball::before {
+ content: "\f458"; }
+
+.fa-quidditch::before {
+ content: "\f458"; }
+
+.fa-quidditch-broom-ball::before {
+ content: "\f458"; }
+
+.fa-toggle-off::before {
+ content: "\f204"; }
+
+.fa-box-archive::before {
+ content: "\f187"; }
+
+.fa-archive::before {
+ content: "\f187"; }
+
+.fa-person-drowning::before {
+ content: "\e545"; }
+
+.fa-arrow-down-9-1::before {
+ content: "\f886"; }
+
+.fa-sort-numeric-desc::before {
+ content: "\f886"; }
+
+.fa-sort-numeric-down-alt::before {
+ content: "\f886"; }
+
+.fa-face-grin-tongue-squint::before {
+ content: "\f58a"; }
+
+.fa-grin-tongue-squint::before {
+ content: "\f58a"; }
+
+.fa-spray-can::before {
+ content: "\f5bd"; }
+
+.fa-truck-monster::before {
+ content: "\f63b"; }
+
+.fa-w::before {
+ content: "\57"; }
+
+.fa-earth-africa::before {
+ content: "\f57c"; }
+
+.fa-globe-africa::before {
+ content: "\f57c"; }
+
+.fa-rainbow::before {
+ content: "\f75b"; }
+
+.fa-circle-notch::before {
+ content: "\f1ce"; }
+
+.fa-tablet-screen-button::before {
+ content: "\f3fa"; }
+
+.fa-tablet-alt::before {
+ content: "\f3fa"; }
+
+.fa-paw::before {
+ content: "\f1b0"; }
+
+.fa-cloud::before {
+ content: "\f0c2"; }
+
+.fa-trowel-bricks::before {
+ content: "\e58a"; }
+
+.fa-face-flushed::before {
+ content: "\f579"; }
+
+.fa-flushed::before {
+ content: "\f579"; }
+
+.fa-hospital-user::before {
+ content: "\f80d"; }
+
+.fa-tent-arrow-left-right::before {
+ content: "\e57f"; }
+
+.fa-gavel::before {
+ content: "\f0e3"; }
+
+.fa-legal::before {
+ content: "\f0e3"; }
+
+.fa-binoculars::before {
+ content: "\f1e5"; }
+
+.fa-microphone-slash::before {
+ content: "\f131"; }
+
+.fa-box-tissue::before {
+ content: "\e05b"; }
+
+.fa-motorcycle::before {
+ content: "\f21c"; }
+
+.fa-bell-concierge::before {
+ content: "\f562"; }
+
+.fa-concierge-bell::before {
+ content: "\f562"; }
+
+.fa-pen-ruler::before {
+ content: "\f5ae"; }
+
+.fa-pencil-ruler::before {
+ content: "\f5ae"; }
+
+.fa-people-arrows::before {
+ content: "\e068"; }
+
+.fa-people-arrows-left-right::before {
+ content: "\e068"; }
+
+.fa-mars-and-venus-burst::before {
+ content: "\e523"; }
+
+.fa-square-caret-right::before {
+ content: "\f152"; }
+
+.fa-caret-square-right::before {
+ content: "\f152"; }
+
+.fa-scissors::before {
+ content: "\f0c4"; }
+
+.fa-cut::before {
+ content: "\f0c4"; }
+
+.fa-sun-plant-wilt::before {
+ content: "\e57a"; }
+
+.fa-toilets-portable::before {
+ content: "\e584"; }
+
+.fa-hockey-puck::before {
+ content: "\f453"; }
+
+.fa-table::before {
+ content: "\f0ce"; }
+
+.fa-magnifying-glass-arrow-right::before {
+ content: "\e521"; }
+
+.fa-tachograph-digital::before {
+ content: "\f566"; }
+
+.fa-digital-tachograph::before {
+ content: "\f566"; }
+
+.fa-users-slash::before {
+ content: "\e073"; }
+
+.fa-clover::before {
+ content: "\e139"; }
+
+.fa-reply::before {
+ content: "\f3e5"; }
+
+.fa-mail-reply::before {
+ content: "\f3e5"; }
+
+.fa-star-and-crescent::before {
+ content: "\f699"; }
+
+.fa-house-fire::before {
+ content: "\e50c"; }
+
+.fa-square-minus::before {
+ content: "\f146"; }
+
+.fa-minus-square::before {
+ content: "\f146"; }
+
+.fa-helicopter::before {
+ content: "\f533"; }
+
+.fa-compass::before {
+ content: "\f14e"; }
+
+.fa-square-caret-down::before {
+ content: "\f150"; }
+
+.fa-caret-square-down::before {
+ content: "\f150"; }
+
+.fa-file-circle-question::before {
+ content: "\e4ef"; }
+
+.fa-laptop-code::before {
+ content: "\f5fc"; }
+
+.fa-swatchbook::before {
+ content: "\f5c3"; }
+
+.fa-prescription-bottle::before {
+ content: "\f485"; }
+
+.fa-bars::before {
+ content: "\f0c9"; }
+
+.fa-navicon::before {
+ content: "\f0c9"; }
+
+.fa-people-group::before {
+ content: "\e533"; }
+
+.fa-hourglass-end::before {
+ content: "\f253"; }
+
+.fa-hourglass-3::before {
+ content: "\f253"; }
+
+.fa-heart-crack::before {
+ content: "\f7a9"; }
+
+.fa-heart-broken::before {
+ content: "\f7a9"; }
+
+.fa-square-up-right::before {
+ content: "\f360"; }
+
+.fa-external-link-square-alt::before {
+ content: "\f360"; }
+
+.fa-face-kiss-beam::before {
+ content: "\f597"; }
+
+.fa-kiss-beam::before {
+ content: "\f597"; }
+
+.fa-film::before {
+ content: "\f008"; }
+
+.fa-ruler-horizontal::before {
+ content: "\f547"; }
+
+.fa-people-robbery::before {
+ content: "\e536"; }
+
+.fa-lightbulb::before {
+ content: "\f0eb"; }
+
+.fa-caret-left::before {
+ content: "\f0d9"; }
+
+.fa-circle-exclamation::before {
+ content: "\f06a"; }
+
+.fa-exclamation-circle::before {
+ content: "\f06a"; }
+
+.fa-school-circle-xmark::before {
+ content: "\e56d"; }
+
+.fa-arrow-right-from-bracket::before {
+ content: "\f08b"; }
+
+.fa-sign-out::before {
+ content: "\f08b"; }
+
+.fa-circle-chevron-down::before {
+ content: "\f13a"; }
+
+.fa-chevron-circle-down::before {
+ content: "\f13a"; }
+
+.fa-unlock-keyhole::before {
+ content: "\f13e"; }
+
+.fa-unlock-alt::before {
+ content: "\f13e"; }
+
+.fa-cloud-showers-heavy::before {
+ content: "\f740"; }
+
+.fa-headphones-simple::before {
+ content: "\f58f"; }
+
+.fa-headphones-alt::before {
+ content: "\f58f"; }
+
+.fa-sitemap::before {
+ content: "\f0e8"; }
+
+.fa-circle-dollar-to-slot::before {
+ content: "\f4b9"; }
+
+.fa-donate::before {
+ content: "\f4b9"; }
+
+.fa-memory::before {
+ content: "\f538"; }
+
+.fa-road-spikes::before {
+ content: "\e568"; }
+
+.fa-fire-burner::before {
+ content: "\e4f1"; }
+
+.fa-flag::before {
+ content: "\f024"; }
+
+.fa-hanukiah::before {
+ content: "\f6e6"; }
+
+.fa-feather::before {
+ content: "\f52d"; }
+
+.fa-volume-low::before {
+ content: "\f027"; }
+
+.fa-volume-down::before {
+ content: "\f027"; }
+
+.fa-comment-slash::before {
+ content: "\f4b3"; }
+
+.fa-cloud-sun-rain::before {
+ content: "\f743"; }
+
+.fa-compress::before {
+ content: "\f066"; }
+
+.fa-wheat-awn::before {
+ content: "\e2cd"; }
+
+.fa-wheat-alt::before {
+ content: "\e2cd"; }
+
+.fa-ankh::before {
+ content: "\f644"; }
+
+.fa-hands-holding-child::before {
+ content: "\e4fa"; }
+
+.fa-asterisk::before {
+ content: "\2a"; }
+
+.fa-square-check::before {
+ content: "\f14a"; }
+
+.fa-check-square::before {
+ content: "\f14a"; }
+
+.fa-peseta-sign::before {
+ content: "\e221"; }
+
+.fa-heading::before {
+ content: "\f1dc"; }
+
+.fa-header::before {
+ content: "\f1dc"; }
+
+.fa-ghost::before {
+ content: "\f6e2"; }
+
+.fa-list::before {
+ content: "\f03a"; }
+
+.fa-list-squares::before {
+ content: "\f03a"; }
+
+.fa-square-phone-flip::before {
+ content: "\f87b"; }
+
+.fa-phone-square-alt::before {
+ content: "\f87b"; }
+
+.fa-cart-plus::before {
+ content: "\f217"; }
+
+.fa-gamepad::before {
+ content: "\f11b"; }
+
+.fa-circle-dot::before {
+ content: "\f192"; }
+
+.fa-dot-circle::before {
+ content: "\f192"; }
+
+.fa-face-dizzy::before {
+ content: "\f567"; }
+
+.fa-dizzy::before {
+ content: "\f567"; }
+
+.fa-egg::before {
+ content: "\f7fb"; }
+
+.fa-house-medical-circle-xmark::before {
+ content: "\e513"; }
+
+.fa-campground::before {
+ content: "\f6bb"; }
+
+.fa-folder-plus::before {
+ content: "\f65e"; }
+
+.fa-futbol::before {
+ content: "\f1e3"; }
+
+.fa-futbol-ball::before {
+ content: "\f1e3"; }
+
+.fa-soccer-ball::before {
+ content: "\f1e3"; }
+
+.fa-paintbrush::before {
+ content: "\f1fc"; }
+
+.fa-paint-brush::before {
+ content: "\f1fc"; }
+
+.fa-lock::before {
+ content: "\f023"; }
+
+.fa-gas-pump::before {
+ content: "\f52f"; }
+
+.fa-hot-tub-person::before {
+ content: "\f593"; }
+
+.fa-hot-tub::before {
+ content: "\f593"; }
+
+.fa-map-location::before {
+ content: "\f59f"; }
+
+.fa-map-marked::before {
+ content: "\f59f"; }
+
+.fa-house-flood-water::before {
+ content: "\e50e"; }
+
+.fa-tree::before {
+ content: "\f1bb"; }
+
+.fa-bridge-lock::before {
+ content: "\e4cc"; }
+
+.fa-sack-dollar::before {
+ content: "\f81d"; }
+
+.fa-pen-to-square::before {
+ content: "\f044"; }
+
+.fa-edit::before {
+ content: "\f044"; }
+
+.fa-car-side::before {
+ content: "\f5e4"; }
+
+.fa-share-nodes::before {
+ content: "\f1e0"; }
+
+.fa-share-alt::before {
+ content: "\f1e0"; }
+
+.fa-heart-circle-minus::before {
+ content: "\e4ff"; }
+
+.fa-hourglass-half::before {
+ content: "\f252"; }
+
+.fa-hourglass-2::before {
+ content: "\f252"; }
+
+.fa-microscope::before {
+ content: "\f610"; }
+
+.fa-sink::before {
+ content: "\e06d"; }
+
+.fa-bag-shopping::before {
+ content: "\f290"; }
+
+.fa-shopping-bag::before {
+ content: "\f290"; }
+
+.fa-arrow-down-z-a::before {
+ content: "\f881"; }
+
+.fa-sort-alpha-desc::before {
+ content: "\f881"; }
+
+.fa-sort-alpha-down-alt::before {
+ content: "\f881"; }
+
+.fa-mitten::before {
+ content: "\f7b5"; }
+
+.fa-person-rays::before {
+ content: "\e54d"; }
+
+.fa-users::before {
+ content: "\f0c0"; }
+
+.fa-eye-slash::before {
+ content: "\f070"; }
+
+.fa-flask-vial::before {
+ content: "\e4f3"; }
+
+.fa-hand::before {
+ content: "\f256"; }
+
+.fa-hand-paper::before {
+ content: "\f256"; }
+
+.fa-om::before {
+ content: "\f679"; }
+
+.fa-worm::before {
+ content: "\e599"; }
+
+.fa-house-circle-xmark::before {
+ content: "\e50b"; }
+
+.fa-plug::before {
+ content: "\f1e6"; }
+
+.fa-chevron-up::before {
+ content: "\f077"; }
+
+.fa-hand-spock::before {
+ content: "\f259"; }
+
+.fa-stopwatch::before {
+ content: "\f2f2"; }
+
+.fa-face-kiss::before {
+ content: "\f596"; }
+
+.fa-kiss::before {
+ content: "\f596"; }
+
+.fa-bridge-circle-xmark::before {
+ content: "\e4cb"; }
+
+.fa-face-grin-tongue::before {
+ content: "\f589"; }
+
+.fa-grin-tongue::before {
+ content: "\f589"; }
+
+.fa-chess-bishop::before {
+ content: "\f43a"; }
+
+.fa-face-grin-wink::before {
+ content: "\f58c"; }
+
+.fa-grin-wink::before {
+ content: "\f58c"; }
+
+.fa-ear-deaf::before {
+ content: "\f2a4"; }
+
+.fa-deaf::before {
+ content: "\f2a4"; }
+
+.fa-deafness::before {
+ content: "\f2a4"; }
+
+.fa-hard-of-hearing::before {
+ content: "\f2a4"; }
+
+.fa-road-circle-check::before {
+ content: "\e564"; }
+
+.fa-dice-five::before {
+ content: "\f523"; }
+
+.fa-square-rss::before {
+ content: "\f143"; }
+
+.fa-rss-square::before {
+ content: "\f143"; }
+
+.fa-land-mine-on::before {
+ content: "\e51b"; }
+
+.fa-i-cursor::before {
+ content: "\f246"; }
+
+.fa-stamp::before {
+ content: "\f5bf"; }
+
+.fa-stairs::before {
+ content: "\e289"; }
+
+.fa-i::before {
+ content: "\49"; }
+
+.fa-hryvnia-sign::before {
+ content: "\f6f2"; }
+
+.fa-hryvnia::before {
+ content: "\f6f2"; }
+
+.fa-pills::before {
+ content: "\f484"; }
+
+.fa-face-grin-wide::before {
+ content: "\f581"; }
+
+.fa-grin-alt::before {
+ content: "\f581"; }
+
+.fa-tooth::before {
+ content: "\f5c9"; }
+
+.fa-v::before {
+ content: "\56"; }
+
+.fa-bangladeshi-taka-sign::before {
+ content: "\e2e6"; }
+
+.fa-bicycle::before {
+ content: "\f206"; }
+
+.fa-staff-snake::before {
+ content: "\e579"; }
+
+.fa-rod-asclepius::before {
+ content: "\e579"; }
+
+.fa-rod-snake::before {
+ content: "\e579"; }
+
+.fa-staff-aesculapius::before {
+ content: "\e579"; }
+
+.fa-head-side-cough-slash::before {
+ content: "\e062"; }
+
+.fa-truck-medical::before {
+ content: "\f0f9"; }
+
+.fa-ambulance::before {
+ content: "\f0f9"; }
+
+.fa-wheat-awn-circle-exclamation::before {
+ content: "\e598"; }
+
+.fa-snowman::before {
+ content: "\f7d0"; }
+
+.fa-mortar-pestle::before {
+ content: "\f5a7"; }
+
+.fa-road-barrier::before {
+ content: "\e562"; }
+
+.fa-school::before {
+ content: "\f549"; }
+
+.fa-igloo::before {
+ content: "\f7ae"; }
+
+.fa-joint::before {
+ content: "\f595"; }
+
+.fa-angle-right::before {
+ content: "\f105"; }
+
+.fa-horse::before {
+ content: "\f6f0"; }
+
+.fa-q::before {
+ content: "\51"; }
+
+.fa-g::before {
+ content: "\47"; }
+
+.fa-notes-medical::before {
+ content: "\f481"; }
+
+.fa-temperature-half::before {
+ content: "\f2c9"; }
+
+.fa-temperature-2::before {
+ content: "\f2c9"; }
+
+.fa-thermometer-2::before {
+ content: "\f2c9"; }
+
+.fa-thermometer-half::before {
+ content: "\f2c9"; }
+
+.fa-dong-sign::before {
+ content: "\e169"; }
+
+.fa-capsules::before {
+ content: "\f46b"; }
+
+.fa-poo-storm::before {
+ content: "\f75a"; }
+
+.fa-poo-bolt::before {
+ content: "\f75a"; }
+
+.fa-face-frown-open::before {
+ content: "\f57a"; }
+
+.fa-frown-open::before {
+ content: "\f57a"; }
+
+.fa-hand-point-up::before {
+ content: "\f0a6"; }
+
+.fa-money-bill::before {
+ content: "\f0d6"; }
+
+.fa-bookmark::before {
+ content: "\f02e"; }
+
+.fa-align-justify::before {
+ content: "\f039"; }
+
+.fa-umbrella-beach::before {
+ content: "\f5ca"; }
+
+.fa-helmet-un::before {
+ content: "\e503"; }
+
+.fa-bullseye::before {
+ content: "\f140"; }
+
+.fa-bacon::before {
+ content: "\f7e5"; }
+
+.fa-hand-point-down::before {
+ content: "\f0a7"; }
+
+.fa-arrow-up-from-bracket::before {
+ content: "\e09a"; }
+
+.fa-folder::before {
+ content: "\f07b"; }
+
+.fa-folder-blank::before {
+ content: "\f07b"; }
+
+.fa-file-waveform::before {
+ content: "\f478"; }
+
+.fa-file-medical-alt::before {
+ content: "\f478"; }
+
+.fa-radiation::before {
+ content: "\f7b9"; }
+
+.fa-chart-simple::before {
+ content: "\e473"; }
+
+.fa-mars-stroke::before {
+ content: "\f229"; }
+
+.fa-vial::before {
+ content: "\f492"; }
+
+.fa-gauge::before {
+ content: "\f624"; }
+
+.fa-dashboard::before {
+ content: "\f624"; }
+
+.fa-gauge-med::before {
+ content: "\f624"; }
+
+.fa-tachometer-alt-average::before {
+ content: "\f624"; }
+
+.fa-wand-magic-sparkles::before {
+ content: "\e2ca"; }
+
+.fa-magic-wand-sparkles::before {
+ content: "\e2ca"; }
+
+.fa-e::before {
+ content: "\45"; }
+
+.fa-pen-clip::before {
+ content: "\f305"; }
+
+.fa-pen-alt::before {
+ content: "\f305"; }
+
+.fa-bridge-circle-exclamation::before {
+ content: "\e4ca"; }
+
+.fa-user::before {
+ content: "\f007"; }
+
+.fa-school-circle-check::before {
+ content: "\e56b"; }
+
+.fa-dumpster::before {
+ content: "\f793"; }
+
+.fa-van-shuttle::before {
+ content: "\f5b6"; }
+
+.fa-shuttle-van::before {
+ content: "\f5b6"; }
+
+.fa-building-user::before {
+ content: "\e4da"; }
+
+.fa-square-caret-left::before {
+ content: "\f191"; }
+
+.fa-caret-square-left::before {
+ content: "\f191"; }
+
+.fa-highlighter::before {
+ content: "\f591"; }
+
+.fa-key::before {
+ content: "\f084"; }
+
+.fa-bullhorn::before {
+ content: "\f0a1"; }
+
+.fa-globe::before {
+ content: "\f0ac"; }
+
+.fa-synagogue::before {
+ content: "\f69b"; }
+
+.fa-person-half-dress::before {
+ content: "\e548"; }
+
+.fa-road-bridge::before {
+ content: "\e563"; }
+
+.fa-location-arrow::before {
+ content: "\f124"; }
+
+.fa-c::before {
+ content: "\43"; }
+
+.fa-tablet-button::before {
+ content: "\f10a"; }
+
+.fa-building-lock::before {
+ content: "\e4d6"; }
+
+.fa-pizza-slice::before {
+ content: "\f818"; }
+
+.fa-money-bill-wave::before {
+ content: "\f53a"; }
+
+.fa-chart-area::before {
+ content: "\f1fe"; }
+
+.fa-area-chart::before {
+ content: "\f1fe"; }
+
+.fa-house-flag::before {
+ content: "\e50d"; }
+
+.fa-person-circle-minus::before {
+ content: "\e540"; }
+
+.fa-ban::before {
+ content: "\f05e"; }
+
+.fa-cancel::before {
+ content: "\f05e"; }
+
+.fa-camera-rotate::before {
+ content: "\e0d8"; }
+
+.fa-spray-can-sparkles::before {
+ content: "\f5d0"; }
+
+.fa-air-freshener::before {
+ content: "\f5d0"; }
+
+.fa-star::before {
+ content: "\f005"; }
+
+.fa-repeat::before {
+ content: "\f363"; }
+
+.fa-cross::before {
+ content: "\f654"; }
+
+.fa-box::before {
+ content: "\f466"; }
+
+.fa-venus-mars::before {
+ content: "\f228"; }
+
+.fa-arrow-pointer::before {
+ content: "\f245"; }
+
+.fa-mouse-pointer::before {
+ content: "\f245"; }
+
+.fa-maximize::before {
+ content: "\f31e"; }
+
+.fa-expand-arrows-alt::before {
+ content: "\f31e"; }
+
+.fa-charging-station::before {
+ content: "\f5e7"; }
+
+.fa-shapes::before {
+ content: "\f61f"; }
+
+.fa-triangle-circle-square::before {
+ content: "\f61f"; }
+
+.fa-shuffle::before {
+ content: "\f074"; }
+
+.fa-random::before {
+ content: "\f074"; }
+
+.fa-person-running::before {
+ content: "\f70c"; }
+
+.fa-running::before {
+ content: "\f70c"; }
+
+.fa-mobile-retro::before {
+ content: "\e527"; }
+
+.fa-grip-lines-vertical::before {
+ content: "\f7a5"; }
+
+.fa-spider::before {
+ content: "\f717"; }
+
+.fa-hands-bound::before {
+ content: "\e4f9"; }
+
+.fa-file-invoice-dollar::before {
+ content: "\f571"; }
+
+.fa-plane-circle-exclamation::before {
+ content: "\e556"; }
+
+.fa-x-ray::before {
+ content: "\f497"; }
+
+.fa-spell-check::before {
+ content: "\f891"; }
+
+.fa-slash::before {
+ content: "\f715"; }
+
+.fa-computer-mouse::before {
+ content: "\f8cc"; }
+
+.fa-mouse::before {
+ content: "\f8cc"; }
+
+.fa-arrow-right-to-bracket::before {
+ content: "\f090"; }
+
+.fa-sign-in::before {
+ content: "\f090"; }
+
+.fa-shop-slash::before {
+ content: "\e070"; }
+
+.fa-store-alt-slash::before {
+ content: "\e070"; }
+
+.fa-server::before {
+ content: "\f233"; }
+
+.fa-virus-covid-slash::before {
+ content: "\e4a9"; }
+
+.fa-shop-lock::before {
+ content: "\e4a5"; }
+
+.fa-hourglass-start::before {
+ content: "\f251"; }
+
+.fa-hourglass-1::before {
+ content: "\f251"; }
+
+.fa-blender-phone::before {
+ content: "\f6b6"; }
+
+.fa-building-wheat::before {
+ content: "\e4db"; }
+
+.fa-person-breastfeeding::before {
+ content: "\e53a"; }
+
+.fa-right-to-bracket::before {
+ content: "\f2f6"; }
+
+.fa-sign-in-alt::before {
+ content: "\f2f6"; }
+
+.fa-venus::before {
+ content: "\f221"; }
+
+.fa-passport::before {
+ content: "\f5ab"; }
+
+.fa-heart-pulse::before {
+ content: "\f21e"; }
+
+.fa-heartbeat::before {
+ content: "\f21e"; }
+
+.fa-people-carry-box::before {
+ content: "\f4ce"; }
+
+.fa-people-carry::before {
+ content: "\f4ce"; }
+
+.fa-temperature-high::before {
+ content: "\f769"; }
+
+.fa-microchip::before {
+ content: "\f2db"; }
+
+.fa-crown::before {
+ content: "\f521"; }
+
+.fa-weight-hanging::before {
+ content: "\f5cd"; }
+
+.fa-xmarks-lines::before {
+ content: "\e59a"; }
+
+.fa-file-prescription::before {
+ content: "\f572"; }
+
+.fa-weight-scale::before {
+ content: "\f496"; }
+
+.fa-weight::before {
+ content: "\f496"; }
+
+.fa-user-group::before {
+ content: "\f500"; }
+
+.fa-user-friends::before {
+ content: "\f500"; }
+
+.fa-arrow-up-a-z::before {
+ content: "\f15e"; }
+
+.fa-sort-alpha-up::before {
+ content: "\f15e"; }
+
+.fa-chess-knight::before {
+ content: "\f441"; }
+
+.fa-face-laugh-squint::before {
+ content: "\f59b"; }
+
+.fa-laugh-squint::before {
+ content: "\f59b"; }
+
+.fa-wheelchair::before {
+ content: "\f193"; }
+
+.fa-circle-arrow-up::before {
+ content: "\f0aa"; }
+
+.fa-arrow-circle-up::before {
+ content: "\f0aa"; }
+
+.fa-toggle-on::before {
+ content: "\f205"; }
+
+.fa-person-walking::before {
+ content: "\f554"; }
+
+.fa-walking::before {
+ content: "\f554"; }
+
+.fa-l::before {
+ content: "\4c"; }
+
+.fa-fire::before {
+ content: "\f06d"; }
+
+.fa-bed-pulse::before {
+ content: "\f487"; }
+
+.fa-procedures::before {
+ content: "\f487"; }
+
+.fa-shuttle-space::before {
+ content: "\f197"; }
+
+.fa-space-shuttle::before {
+ content: "\f197"; }
+
+.fa-face-laugh::before {
+ content: "\f599"; }
+
+.fa-laugh::before {
+ content: "\f599"; }
+
+.fa-folder-open::before {
+ content: "\f07c"; }
+
+.fa-heart-circle-plus::before {
+ content: "\e500"; }
+
+.fa-code-fork::before {
+ content: "\e13b"; }
+
+.fa-city::before {
+ content: "\f64f"; }
+
+.fa-microphone-lines::before {
+ content: "\f3c9"; }
+
+.fa-microphone-alt::before {
+ content: "\f3c9"; }
+
+.fa-pepper-hot::before {
+ content: "\f816"; }
+
+.fa-unlock::before {
+ content: "\f09c"; }
+
+.fa-colon-sign::before {
+ content: "\e140"; }
+
+.fa-headset::before {
+ content: "\f590"; }
+
+.fa-store-slash::before {
+ content: "\e071"; }
+
+.fa-road-circle-xmark::before {
+ content: "\e566"; }
+
+.fa-user-minus::before {
+ content: "\f503"; }
+
+.fa-mars-stroke-up::before {
+ content: "\f22a"; }
+
+.fa-mars-stroke-v::before {
+ content: "\f22a"; }
+
+.fa-champagne-glasses::before {
+ content: "\f79f"; }
+
+.fa-glass-cheers::before {
+ content: "\f79f"; }
+
+.fa-clipboard::before {
+ content: "\f328"; }
+
+.fa-house-circle-exclamation::before {
+ content: "\e50a"; }
+
+.fa-file-arrow-up::before {
+ content: "\f574"; }
+
+.fa-file-upload::before {
+ content: "\f574"; }
+
+.fa-wifi::before {
+ content: "\f1eb"; }
+
+.fa-wifi-3::before {
+ content: "\f1eb"; }
+
+.fa-wifi-strong::before {
+ content: "\f1eb"; }
+
+.fa-bath::before {
+ content: "\f2cd"; }
+
+.fa-bathtub::before {
+ content: "\f2cd"; }
+
+.fa-underline::before {
+ content: "\f0cd"; }
+
+.fa-user-pen::before {
+ content: "\f4ff"; }
+
+.fa-user-edit::before {
+ content: "\f4ff"; }
+
+.fa-signature::before {
+ content: "\f5b7"; }
+
+.fa-stroopwafel::before {
+ content: "\f551"; }
+
+.fa-bold::before {
+ content: "\f032"; }
+
+.fa-anchor-lock::before {
+ content: "\e4ad"; }
+
+.fa-building-ngo::before {
+ content: "\e4d7"; }
+
+.fa-manat-sign::before {
+ content: "\e1d5"; }
+
+.fa-not-equal::before {
+ content: "\f53e"; }
+
+.fa-border-top-left::before {
+ content: "\f853"; }
+
+.fa-border-style::before {
+ content: "\f853"; }
+
+.fa-map-location-dot::before {
+ content: "\f5a0"; }
+
+.fa-map-marked-alt::before {
+ content: "\f5a0"; }
+
+.fa-jedi::before {
+ content: "\f669"; }
+
+.fa-square-poll-vertical::before {
+ content: "\f681"; }
+
+.fa-poll::before {
+ content: "\f681"; }
+
+.fa-mug-hot::before {
+ content: "\f7b6"; }
+
+.fa-car-battery::before {
+ content: "\f5df"; }
+
+.fa-battery-car::before {
+ content: "\f5df"; }
+
+.fa-gift::before {
+ content: "\f06b"; }
+
+.fa-dice-two::before {
+ content: "\f528"; }
+
+.fa-chess-queen::before {
+ content: "\f445"; }
+
+.fa-glasses::before {
+ content: "\f530"; }
+
+.fa-chess-board::before {
+ content: "\f43c"; }
+
+.fa-building-circle-check::before {
+ content: "\e4d2"; }
+
+.fa-person-chalkboard::before {
+ content: "\e53d"; }
+
+.fa-mars-stroke-right::before {
+ content: "\f22b"; }
+
+.fa-mars-stroke-h::before {
+ content: "\f22b"; }
+
+.fa-hand-back-fist::before {
+ content: "\f255"; }
+
+.fa-hand-rock::before {
+ content: "\f255"; }
+
+.fa-square-caret-up::before {
+ content: "\f151"; }
+
+.fa-caret-square-up::before {
+ content: "\f151"; }
+
+.fa-cloud-showers-water::before {
+ content: "\e4e4"; }
+
+.fa-chart-bar::before {
+ content: "\f080"; }
+
+.fa-bar-chart::before {
+ content: "\f080"; }
+
+.fa-hands-bubbles::before {
+ content: "\e05e"; }
+
+.fa-hands-wash::before {
+ content: "\e05e"; }
+
+.fa-less-than-equal::before {
+ content: "\f537"; }
+
+.fa-train::before {
+ content: "\f238"; }
+
+.fa-eye-low-vision::before {
+ content: "\f2a8"; }
+
+.fa-low-vision::before {
+ content: "\f2a8"; }
+
+.fa-crow::before {
+ content: "\f520"; }
+
+.fa-sailboat::before {
+ content: "\e445"; }
+
+.fa-window-restore::before {
+ content: "\f2d2"; }
+
+.fa-square-plus::before {
+ content: "\f0fe"; }
+
+.fa-plus-square::before {
+ content: "\f0fe"; }
+
+.fa-torii-gate::before {
+ content: "\f6a1"; }
+
+.fa-frog::before {
+ content: "\f52e"; }
+
+.fa-bucket::before {
+ content: "\e4cf"; }
+
+.fa-image::before {
+ content: "\f03e"; }
+
+.fa-microphone::before {
+ content: "\f130"; }
+
+.fa-cow::before {
+ content: "\f6c8"; }
+
+.fa-caret-up::before {
+ content: "\f0d8"; }
+
+.fa-screwdriver::before {
+ content: "\f54a"; }
+
+.fa-folder-closed::before {
+ content: "\e185"; }
+
+.fa-house-tsunami::before {
+ content: "\e515"; }
+
+.fa-square-nfi::before {
+ content: "\e576"; }
+
+.fa-arrow-up-from-ground-water::before {
+ content: "\e4b5"; }
+
+.fa-martini-glass::before {
+ content: "\f57b"; }
+
+.fa-glass-martini-alt::before {
+ content: "\f57b"; }
+
+.fa-rotate-left::before {
+ content: "\f2ea"; }
+
+.fa-rotate-back::before {
+ content: "\f2ea"; }
+
+.fa-rotate-backward::before {
+ content: "\f2ea"; }
+
+.fa-undo-alt::before {
+ content: "\f2ea"; }
+
+.fa-table-columns::before {
+ content: "\f0db"; }
+
+.fa-columns::before {
+ content: "\f0db"; }
+
+.fa-lemon::before {
+ content: "\f094"; }
+
+.fa-head-side-mask::before {
+ content: "\e063"; }
+
+.fa-handshake::before {
+ content: "\f2b5"; }
+
+.fa-gem::before {
+ content: "\f3a5"; }
+
+.fa-dolly::before {
+ content: "\f472"; }
+
+.fa-dolly-box::before {
+ content: "\f472"; }
+
+.fa-smoking::before {
+ content: "\f48d"; }
+
+.fa-minimize::before {
+ content: "\f78c"; }
+
+.fa-compress-arrows-alt::before {
+ content: "\f78c"; }
+
+.fa-monument::before {
+ content: "\f5a6"; }
+
+.fa-snowplow::before {
+ content: "\f7d2"; }
+
+.fa-angles-right::before {
+ content: "\f101"; }
+
+.fa-angle-double-right::before {
+ content: "\f101"; }
+
+.fa-cannabis::before {
+ content: "\f55f"; }
+
+.fa-circle-play::before {
+ content: "\f144"; }
+
+.fa-play-circle::before {
+ content: "\f144"; }
+
+.fa-tablets::before {
+ content: "\f490"; }
+
+.fa-ethernet::before {
+ content: "\f796"; }
+
+.fa-euro-sign::before {
+ content: "\f153"; }
+
+.fa-eur::before {
+ content: "\f153"; }
+
+.fa-euro::before {
+ content: "\f153"; }
+
+.fa-chair::before {
+ content: "\f6c0"; }
+
+.fa-circle-check::before {
+ content: "\f058"; }
+
+.fa-check-circle::before {
+ content: "\f058"; }
+
+.fa-circle-stop::before {
+ content: "\f28d"; }
+
+.fa-stop-circle::before {
+ content: "\f28d"; }
+
+.fa-compass-drafting::before {
+ content: "\f568"; }
+
+.fa-drafting-compass::before {
+ content: "\f568"; }
+
+.fa-plate-wheat::before {
+ content: "\e55a"; }
+
+.fa-icicles::before {
+ content: "\f7ad"; }
+
+.fa-person-shelter::before {
+ content: "\e54f"; }
+
+.fa-neuter::before {
+ content: "\f22c"; }
+
+.fa-id-badge::before {
+ content: "\f2c1"; }
+
+.fa-marker::before {
+ content: "\f5a1"; }
+
+.fa-face-laugh-beam::before {
+ content: "\f59a"; }
+
+.fa-laugh-beam::before {
+ content: "\f59a"; }
+
+.fa-helicopter-symbol::before {
+ content: "\e502"; }
+
+.fa-universal-access::before {
+ content: "\f29a"; }
+
+.fa-circle-chevron-up::before {
+ content: "\f139"; }
+
+.fa-chevron-circle-up::before {
+ content: "\f139"; }
+
+.fa-lari-sign::before {
+ content: "\e1c8"; }
+
+.fa-volcano::before {
+ content: "\f770"; }
+
+.fa-person-walking-dashed-line-arrow-right::before {
+ content: "\e553"; }
+
+.fa-sterling-sign::before {
+ content: "\f154"; }
+
+.fa-gbp::before {
+ content: "\f154"; }
+
+.fa-pound-sign::before {
+ content: "\f154"; }
+
+.fa-viruses::before {
+ content: "\e076"; }
+
+.fa-square-person-confined::before {
+ content: "\e577"; }
+
+.fa-user-tie::before {
+ content: "\f508"; }
+
+.fa-arrow-down-long::before {
+ content: "\f175"; }
+
+.fa-long-arrow-down::before {
+ content: "\f175"; }
+
+.fa-tent-arrow-down-to-line::before {
+ content: "\e57e"; }
+
+.fa-certificate::before {
+ content: "\f0a3"; }
+
+.fa-reply-all::before {
+ content: "\f122"; }
+
+.fa-mail-reply-all::before {
+ content: "\f122"; }
+
+.fa-suitcase::before {
+ content: "\f0f2"; }
+
+.fa-person-skating::before {
+ content: "\f7c5"; }
+
+.fa-skating::before {
+ content: "\f7c5"; }
+
+.fa-filter-circle-dollar::before {
+ content: "\f662"; }
+
+.fa-funnel-dollar::before {
+ content: "\f662"; }
+
+.fa-camera-retro::before {
+ content: "\f083"; }
+
+.fa-circle-arrow-down::before {
+ content: "\f0ab"; }
+
+.fa-arrow-circle-down::before {
+ content: "\f0ab"; }
+
+.fa-file-import::before {
+ content: "\f56f"; }
+
+.fa-arrow-right-to-file::before {
+ content: "\f56f"; }
+
+.fa-square-arrow-up-right::before {
+ content: "\f14c"; }
+
+.fa-external-link-square::before {
+ content: "\f14c"; }
+
+.fa-box-open::before {
+ content: "\f49e"; }
+
+.fa-scroll::before {
+ content: "\f70e"; }
+
+.fa-spa::before {
+ content: "\f5bb"; }
+
+.fa-location-pin-lock::before {
+ content: "\e51f"; }
+
+.fa-pause::before {
+ content: "\f04c"; }
+
+.fa-hill-avalanche::before {
+ content: "\e507"; }
+
+.fa-temperature-empty::before {
+ content: "\f2cb"; }
+
+.fa-temperature-0::before {
+ content: "\f2cb"; }
+
+.fa-thermometer-0::before {
+ content: "\f2cb"; }
+
+.fa-thermometer-empty::before {
+ content: "\f2cb"; }
+
+.fa-bomb::before {
+ content: "\f1e2"; }
+
+.fa-registered::before {
+ content: "\f25d"; }
+
+.fa-address-card::before {
+ content: "\f2bb"; }
+
+.fa-contact-card::before {
+ content: "\f2bb"; }
+
+.fa-vcard::before {
+ content: "\f2bb"; }
+
+.fa-scale-unbalanced-flip::before {
+ content: "\f516"; }
+
+.fa-balance-scale-right::before {
+ content: "\f516"; }
+
+.fa-subscript::before {
+ content: "\f12c"; }
+
+.fa-diamond-turn-right::before {
+ content: "\f5eb"; }
+
+.fa-directions::before {
+ content: "\f5eb"; }
+
+.fa-burst::before {
+ content: "\e4dc"; }
+
+.fa-house-laptop::before {
+ content: "\e066"; }
+
+.fa-laptop-house::before {
+ content: "\e066"; }
+
+.fa-face-tired::before {
+ content: "\f5c8"; }
+
+.fa-tired::before {
+ content: "\f5c8"; }
+
+.fa-money-bills::before {
+ content: "\e1f3"; }
+
+.fa-smog::before {
+ content: "\f75f"; }
+
+.fa-crutch::before {
+ content: "\f7f7"; }
+
+.fa-cloud-arrow-up::before {
+ content: "\f0ee"; }
+
+.fa-cloud-upload::before {
+ content: "\f0ee"; }
+
+.fa-cloud-upload-alt::before {
+ content: "\f0ee"; }
+
+.fa-palette::before {
+ content: "\f53f"; }
+
+.fa-arrows-turn-right::before {
+ content: "\e4c0"; }
+
+.fa-vest::before {
+ content: "\e085"; }
+
+.fa-ferry::before {
+ content: "\e4ea"; }
+
+.fa-arrows-down-to-people::before {
+ content: "\e4b9"; }
+
+.fa-seedling::before {
+ content: "\f4d8"; }
+
+.fa-sprout::before {
+ content: "\f4d8"; }
+
+.fa-left-right::before {
+ content: "\f337"; }
+
+.fa-arrows-alt-h::before {
+ content: "\f337"; }
+
+.fa-boxes-packing::before {
+ content: "\e4c7"; }
+
+.fa-circle-arrow-left::before {
+ content: "\f0a8"; }
+
+.fa-arrow-circle-left::before {
+ content: "\f0a8"; }
+
+.fa-group-arrows-rotate::before {
+ content: "\e4f6"; }
+
+.fa-bowl-food::before {
+ content: "\e4c6"; }
+
+.fa-candy-cane::before {
+ content: "\f786"; }
+
+.fa-arrow-down-wide-short::before {
+ content: "\f160"; }
+
+.fa-sort-amount-asc::before {
+ content: "\f160"; }
+
+.fa-sort-amount-down::before {
+ content: "\f160"; }
+
+.fa-cloud-bolt::before {
+ content: "\f76c"; }
+
+.fa-thunderstorm::before {
+ content: "\f76c"; }
+
+.fa-text-slash::before {
+ content: "\f87d"; }
+
+.fa-remove-format::before {
+ content: "\f87d"; }
+
+.fa-face-smile-wink::before {
+ content: "\f4da"; }
+
+.fa-smile-wink::before {
+ content: "\f4da"; }
+
+.fa-file-word::before {
+ content: "\f1c2"; }
+
+.fa-file-powerpoint::before {
+ content: "\f1c4"; }
+
+.fa-arrows-left-right::before {
+ content: "\f07e"; }
+
+.fa-arrows-h::before {
+ content: "\f07e"; }
+
+.fa-house-lock::before {
+ content: "\e510"; }
+
+.fa-cloud-arrow-down::before {
+ content: "\f0ed"; }
+
+.fa-cloud-download::before {
+ content: "\f0ed"; }
+
+.fa-cloud-download-alt::before {
+ content: "\f0ed"; }
+
+.fa-children::before {
+ content: "\e4e1"; }
+
+.fa-chalkboard::before {
+ content: "\f51b"; }
+
+.fa-blackboard::before {
+ content: "\f51b"; }
+
+.fa-user-large-slash::before {
+ content: "\f4fa"; }
+
+.fa-user-alt-slash::before {
+ content: "\f4fa"; }
+
+.fa-envelope-open::before {
+ content: "\f2b6"; }
+
+.fa-handshake-simple-slash::before {
+ content: "\e05f"; }
+
+.fa-handshake-alt-slash::before {
+ content: "\e05f"; }
+
+.fa-mattress-pillow::before {
+ content: "\e525"; }
+
+.fa-guarani-sign::before {
+ content: "\e19a"; }
+
+.fa-arrows-rotate::before {
+ content: "\f021"; }
+
+.fa-refresh::before {
+ content: "\f021"; }
+
+.fa-sync::before {
+ content: "\f021"; }
+
+.fa-fire-extinguisher::before {
+ content: "\f134"; }
+
+.fa-cruzeiro-sign::before {
+ content: "\e152"; }
+
+.fa-greater-than-equal::before {
+ content: "\f532"; }
+
+.fa-shield-halved::before {
+ content: "\f3ed"; }
+
+.fa-shield-alt::before {
+ content: "\f3ed"; }
+
+.fa-book-atlas::before {
+ content: "\f558"; }
+
+.fa-atlas::before {
+ content: "\f558"; }
+
+.fa-virus::before {
+ content: "\e074"; }
+
+.fa-envelope-circle-check::before {
+ content: "\e4e8"; }
+
+.fa-layer-group::before {
+ content: "\f5fd"; }
+
+.fa-arrows-to-dot::before {
+ content: "\e4be"; }
+
+.fa-archway::before {
+ content: "\f557"; }
+
+.fa-heart-circle-check::before {
+ content: "\e4fd"; }
+
+.fa-house-chimney-crack::before {
+ content: "\f6f1"; }
+
+.fa-house-damage::before {
+ content: "\f6f1"; }
+
+.fa-file-zipper::before {
+ content: "\f1c6"; }
+
+.fa-file-archive::before {
+ content: "\f1c6"; }
+
+.fa-square::before {
+ content: "\f0c8"; }
+
+.fa-martini-glass-empty::before {
+ content: "\f000"; }
+
+.fa-glass-martini::before {
+ content: "\f000"; }
+
+.fa-couch::before {
+ content: "\f4b8"; }
+
+.fa-cedi-sign::before {
+ content: "\e0df"; }
+
+.fa-italic::before {
+ content: "\f033"; }
+
+.fa-church::before {
+ content: "\f51d"; }
+
+.fa-comments-dollar::before {
+ content: "\f653"; }
+
+.fa-democrat::before {
+ content: "\f747"; }
+
+.fa-z::before {
+ content: "\5a"; }
+
+.fa-person-skiing::before {
+ content: "\f7c9"; }
+
+.fa-skiing::before {
+ content: "\f7c9"; }
+
+.fa-road-lock::before {
+ content: "\e567"; }
+
+.fa-a::before {
+ content: "\41"; }
+
+.fa-temperature-arrow-down::before {
+ content: "\e03f"; }
+
+.fa-temperature-down::before {
+ content: "\e03f"; }
+
+.fa-feather-pointed::before {
+ content: "\f56b"; }
+
+.fa-feather-alt::before {
+ content: "\f56b"; }
+
+.fa-p::before {
+ content: "\50"; }
+
+.fa-snowflake::before {
+ content: "\f2dc"; }
+
+.fa-newspaper::before {
+ content: "\f1ea"; }
+
+.fa-rectangle-ad::before {
+ content: "\f641"; }
+
+.fa-ad::before {
+ content: "\f641"; }
+
+.fa-circle-arrow-right::before {
+ content: "\f0a9"; }
+
+.fa-arrow-circle-right::before {
+ content: "\f0a9"; }
+
+.fa-filter-circle-xmark::before {
+ content: "\e17b"; }
+
+.fa-locust::before {
+ content: "\e520"; }
+
+.fa-sort::before {
+ content: "\f0dc"; }
+
+.fa-unsorted::before {
+ content: "\f0dc"; }
+
+.fa-list-ol::before {
+ content: "\f0cb"; }
+
+.fa-list-1-2::before {
+ content: "\f0cb"; }
+
+.fa-list-numeric::before {
+ content: "\f0cb"; }
+
+.fa-person-dress-burst::before {
+ content: "\e544"; }
+
+.fa-money-check-dollar::before {
+ content: "\f53d"; }
+
+.fa-money-check-alt::before {
+ content: "\f53d"; }
+
+.fa-vector-square::before {
+ content: "\f5cb"; }
+
+.fa-bread-slice::before {
+ content: "\f7ec"; }
+
+.fa-language::before {
+ content: "\f1ab"; }
+
+.fa-face-kiss-wink-heart::before {
+ content: "\f598"; }
+
+.fa-kiss-wink-heart::before {
+ content: "\f598"; }
+
+.fa-filter::before {
+ content: "\f0b0"; }
+
+.fa-question::before {
+ content: "\3f"; }
+
+.fa-file-signature::before {
+ content: "\f573"; }
+
+.fa-up-down-left-right::before {
+ content: "\f0b2"; }
+
+.fa-arrows-alt::before {
+ content: "\f0b2"; }
+
+.fa-house-chimney-user::before {
+ content: "\e065"; }
+
+.fa-hand-holding-heart::before {
+ content: "\f4be"; }
+
+.fa-puzzle-piece::before {
+ content: "\f12e"; }
+
+.fa-money-check::before {
+ content: "\f53c"; }
+
+.fa-star-half-stroke::before {
+ content: "\f5c0"; }
+
+.fa-star-half-alt::before {
+ content: "\f5c0"; }
+
+.fa-code::before {
+ content: "\f121"; }
+
+.fa-whiskey-glass::before {
+ content: "\f7a0"; }
+
+.fa-glass-whiskey::before {
+ content: "\f7a0"; }
+
+.fa-building-circle-exclamation::before {
+ content: "\e4d3"; }
+
+.fa-magnifying-glass-chart::before {
+ content: "\e522"; }
+
+.fa-arrow-up-right-from-square::before {
+ content: "\f08e"; }
+
+.fa-external-link::before {
+ content: "\f08e"; }
+
+.fa-cubes-stacked::before {
+ content: "\e4e6"; }
+
+.fa-won-sign::before {
+ content: "\f159"; }
+
+.fa-krw::before {
+ content: "\f159"; }
+
+.fa-won::before {
+ content: "\f159"; }
+
+.fa-virus-covid::before {
+ content: "\e4a8"; }
+
+.fa-austral-sign::before {
+ content: "\e0a9"; }
+
+.fa-f::before {
+ content: "\46"; }
+
+.fa-leaf::before {
+ content: "\f06c"; }
+
+.fa-road::before {
+ content: "\f018"; }
+
+.fa-taxi::before {
+ content: "\f1ba"; }
+
+.fa-cab::before {
+ content: "\f1ba"; }
+
+.fa-person-circle-plus::before {
+ content: "\e541"; }
+
+.fa-chart-pie::before {
+ content: "\f200"; }
+
+.fa-pie-chart::before {
+ content: "\f200"; }
+
+.fa-bolt-lightning::before {
+ content: "\e0b7"; }
+
+.fa-sack-xmark::before {
+ content: "\e56a"; }
+
+.fa-file-excel::before {
+ content: "\f1c3"; }
+
+.fa-file-contract::before {
+ content: "\f56c"; }
+
+.fa-fish-fins::before {
+ content: "\e4f2"; }
+
+.fa-building-flag::before {
+ content: "\e4d5"; }
+
+.fa-face-grin-beam::before {
+ content: "\f582"; }
+
+.fa-grin-beam::before {
+ content: "\f582"; }
+
+.fa-object-ungroup::before {
+ content: "\f248"; }
+
+.fa-poop::before {
+ content: "\f619"; }
+
+.fa-location-pin::before {
+ content: "\f041"; }
+
+.fa-map-marker::before {
+ content: "\f041"; }
+
+.fa-kaaba::before {
+ content: "\f66b"; }
+
+.fa-toilet-paper::before {
+ content: "\f71e"; }
+
+.fa-helmet-safety::before {
+ content: "\f807"; }
+
+.fa-hard-hat::before {
+ content: "\f807"; }
+
+.fa-hat-hard::before {
+ content: "\f807"; }
+
+.fa-eject::before {
+ content: "\f052"; }
+
+.fa-circle-right::before {
+ content: "\f35a"; }
+
+.fa-arrow-alt-circle-right::before {
+ content: "\f35a"; }
+
+.fa-plane-circle-check::before {
+ content: "\e555"; }
+
+.fa-face-rolling-eyes::before {
+ content: "\f5a5"; }
+
+.fa-meh-rolling-eyes::before {
+ content: "\f5a5"; }
+
+.fa-object-group::before {
+ content: "\f247"; }
+
+.fa-chart-line::before {
+ content: "\f201"; }
+
+.fa-line-chart::before {
+ content: "\f201"; }
+
+.fa-mask-ventilator::before {
+ content: "\e524"; }
+
+.fa-arrow-right::before {
+ content: "\f061"; }
+
+.fa-signs-post::before {
+ content: "\f277"; }
+
+.fa-map-signs::before {
+ content: "\f277"; }
+
+.fa-cash-register::before {
+ content: "\f788"; }
+
+.fa-person-circle-question::before {
+ content: "\e542"; }
+
+.fa-h::before {
+ content: "\48"; }
+
+.fa-tarp::before {
+ content: "\e57b"; }
+
+.fa-screwdriver-wrench::before {
+ content: "\f7d9"; }
+
+.fa-tools::before {
+ content: "\f7d9"; }
+
+.fa-arrows-to-eye::before {
+ content: "\e4bf"; }
+
+.fa-plug-circle-bolt::before {
+ content: "\e55b"; }
+
+.fa-heart::before {
+ content: "\f004"; }
+
+.fa-mars-and-venus::before {
+ content: "\f224"; }
+
+.fa-house-user::before {
+ content: "\e1b0"; }
+
+.fa-home-user::before {
+ content: "\e1b0"; }
+
+.fa-dumpster-fire::before {
+ content: "\f794"; }
+
+.fa-house-crack::before {
+ content: "\e3b1"; }
+
+.fa-martini-glass-citrus::before {
+ content: "\f561"; }
+
+.fa-cocktail::before {
+ content: "\f561"; }
+
+.fa-face-surprise::before {
+ content: "\f5c2"; }
+
+.fa-surprise::before {
+ content: "\f5c2"; }
+
+.fa-bottle-water::before {
+ content: "\e4c5"; }
+
+.fa-circle-pause::before {
+ content: "\f28b"; }
+
+.fa-pause-circle::before {
+ content: "\f28b"; }
+
+.fa-toilet-paper-slash::before {
+ content: "\e072"; }
+
+.fa-apple-whole::before {
+ content: "\f5d1"; }
+
+.fa-apple-alt::before {
+ content: "\f5d1"; }
+
+.fa-kitchen-set::before {
+ content: "\e51a"; }
+
+.fa-r::before {
+ content: "\52"; }
+
+.fa-temperature-quarter::before {
+ content: "\f2ca"; }
+
+.fa-temperature-1::before {
+ content: "\f2ca"; }
+
+.fa-thermometer-1::before {
+ content: "\f2ca"; }
+
+.fa-thermometer-quarter::before {
+ content: "\f2ca"; }
+
+.fa-cube::before {
+ content: "\f1b2"; }
+
+.fa-bitcoin-sign::before {
+ content: "\e0b4"; }
+
+.fa-shield-dog::before {
+ content: "\e573"; }
+
+.fa-solar-panel::before {
+ content: "\f5ba"; }
+
+.fa-lock-open::before {
+ content: "\f3c1"; }
+
+.fa-elevator::before {
+ content: "\e16d"; }
+
+.fa-money-bill-transfer::before {
+ content: "\e528"; }
+
+.fa-money-bill-trend-up::before {
+ content: "\e529"; }
+
+.fa-house-flood-water-circle-arrow-right::before {
+ content: "\e50f"; }
+
+.fa-square-poll-horizontal::before {
+ content: "\f682"; }
+
+.fa-poll-h::before {
+ content: "\f682"; }
+
+.fa-circle::before {
+ content: "\f111"; }
+
+.fa-backward-fast::before {
+ content: "\f049"; }
+
+.fa-fast-backward::before {
+ content: "\f049"; }
+
+.fa-recycle::before {
+ content: "\f1b8"; }
+
+.fa-user-astronaut::before {
+ content: "\f4fb"; }
+
+.fa-plane-slash::before {
+ content: "\e069"; }
+
+.fa-trademark::before {
+ content: "\f25c"; }
+
+.fa-basketball::before {
+ content: "\f434"; }
+
+.fa-basketball-ball::before {
+ content: "\f434"; }
+
+.fa-satellite-dish::before {
+ content: "\f7c0"; }
+
+.fa-circle-up::before {
+ content: "\f35b"; }
+
+.fa-arrow-alt-circle-up::before {
+ content: "\f35b"; }
+
+.fa-mobile-screen-button::before {
+ content: "\f3cd"; }
+
+.fa-mobile-alt::before {
+ content: "\f3cd"; }
+
+.fa-volume-high::before {
+ content: "\f028"; }
+
+.fa-volume-up::before {
+ content: "\f028"; }
+
+.fa-users-rays::before {
+ content: "\e593"; }
+
+.fa-wallet::before {
+ content: "\f555"; }
+
+.fa-clipboard-check::before {
+ content: "\f46c"; }
+
+.fa-file-audio::before {
+ content: "\f1c7"; }
+
+.fa-burger::before {
+ content: "\f805"; }
+
+.fa-hamburger::before {
+ content: "\f805"; }
+
+.fa-wrench::before {
+ content: "\f0ad"; }
+
+.fa-bugs::before {
+ content: "\e4d0"; }
+
+.fa-rupee-sign::before {
+ content: "\f156"; }
+
+.fa-rupee::before {
+ content: "\f156"; }
+
+.fa-file-image::before {
+ content: "\f1c5"; }
+
+.fa-circle-question::before {
+ content: "\f059"; }
+
+.fa-question-circle::before {
+ content: "\f059"; }
+
+.fa-plane-departure::before {
+ content: "\f5b0"; }
+
+.fa-handshake-slash::before {
+ content: "\e060"; }
+
+.fa-book-bookmark::before {
+ content: "\e0bb"; }
+
+.fa-code-branch::before {
+ content: "\f126"; }
+
+.fa-hat-cowboy::before {
+ content: "\f8c0"; }
+
+.fa-bridge::before {
+ content: "\e4c8"; }
+
+.fa-phone-flip::before {
+ content: "\f879"; }
+
+.fa-phone-alt::before {
+ content: "\f879"; }
+
+.fa-truck-front::before {
+ content: "\e2b7"; }
+
+.fa-cat::before {
+ content: "\f6be"; }
+
+.fa-anchor-circle-exclamation::before {
+ content: "\e4ab"; }
+
+.fa-truck-field::before {
+ content: "\e58d"; }
+
+.fa-route::before {
+ content: "\f4d7"; }
+
+.fa-clipboard-question::before {
+ content: "\e4e3"; }
+
+.fa-panorama::before {
+ content: "\e209"; }
+
+.fa-comment-medical::before {
+ content: "\f7f5"; }
+
+.fa-teeth-open::before {
+ content: "\f62f"; }
+
+.fa-file-circle-minus::before {
+ content: "\e4ed"; }
+
+.fa-tags::before {
+ content: "\f02c"; }
+
+.fa-wine-glass::before {
+ content: "\f4e3"; }
+
+.fa-forward-fast::before {
+ content: "\f050"; }
+
+.fa-fast-forward::before {
+ content: "\f050"; }
+
+.fa-face-meh-blank::before {
+ content: "\f5a4"; }
+
+.fa-meh-blank::before {
+ content: "\f5a4"; }
+
+.fa-square-parking::before {
+ content: "\f540"; }
+
+.fa-parking::before {
+ content: "\f540"; }
+
+.fa-house-signal::before {
+ content: "\e012"; }
+
+.fa-bars-progress::before {
+ content: "\f828"; }
+
+.fa-tasks-alt::before {
+ content: "\f828"; }
+
+.fa-faucet-drip::before {
+ content: "\e006"; }
+
+.fa-cart-flatbed::before {
+ content: "\f474"; }
+
+.fa-dolly-flatbed::before {
+ content: "\f474"; }
+
+.fa-ban-smoking::before {
+ content: "\f54d"; }
+
+.fa-smoking-ban::before {
+ content: "\f54d"; }
+
+.fa-terminal::before {
+ content: "\f120"; }
+
+.fa-mobile-button::before {
+ content: "\f10b"; }
+
+.fa-house-medical-flag::before {
+ content: "\e514"; }
+
+.fa-basket-shopping::before {
+ content: "\f291"; }
+
+.fa-shopping-basket::before {
+ content: "\f291"; }
+
+.fa-tape::before {
+ content: "\f4db"; }
+
+.fa-bus-simple::before {
+ content: "\f55e"; }
+
+.fa-bus-alt::before {
+ content: "\f55e"; }
+
+.fa-eye::before {
+ content: "\f06e"; }
+
+.fa-face-sad-cry::before {
+ content: "\f5b3"; }
+
+.fa-sad-cry::before {
+ content: "\f5b3"; }
+
+.fa-audio-description::before {
+ content: "\f29e"; }
+
+.fa-person-military-to-person::before {
+ content: "\e54c"; }
+
+.fa-file-shield::before {
+ content: "\e4f0"; }
+
+.fa-user-slash::before {
+ content: "\f506"; }
+
+.fa-pen::before {
+ content: "\f304"; }
+
+.fa-tower-observation::before {
+ content: "\e586"; }
+
+.fa-file-code::before {
+ content: "\f1c9"; }
+
+.fa-signal::before {
+ content: "\f012"; }
+
+.fa-signal-5::before {
+ content: "\f012"; }
+
+.fa-signal-perfect::before {
+ content: "\f012"; }
+
+.fa-bus::before {
+ content: "\f207"; }
+
+.fa-heart-circle-xmark::before {
+ content: "\e501"; }
+
+.fa-house-chimney::before {
+ content: "\e3af"; }
+
+.fa-home-lg::before {
+ content: "\e3af"; }
+
+.fa-window-maximize::before {
+ content: "\f2d0"; }
+
+.fa-face-frown::before {
+ content: "\f119"; }
+
+.fa-frown::before {
+ content: "\f119"; }
+
+.fa-prescription::before {
+ content: "\f5b1"; }
+
+.fa-shop::before {
+ content: "\f54f"; }
+
+.fa-store-alt::before {
+ content: "\f54f"; }
+
+.fa-floppy-disk::before {
+ content: "\f0c7"; }
+
+.fa-save::before {
+ content: "\f0c7"; }
+
+.fa-vihara::before {
+ content: "\f6a7"; }
+
+.fa-scale-unbalanced::before {
+ content: "\f515"; }
+
+.fa-balance-scale-left::before {
+ content: "\f515"; }
+
+.fa-sort-up::before {
+ content: "\f0de"; }
+
+.fa-sort-asc::before {
+ content: "\f0de"; }
+
+.fa-comment-dots::before {
+ content: "\f4ad"; }
+
+.fa-commenting::before {
+ content: "\f4ad"; }
+
+.fa-plant-wilt::before {
+ content: "\e5aa"; }
+
+.fa-diamond::before {
+ content: "\f219"; }
+
+.fa-face-grin-squint::before {
+ content: "\f585"; }
+
+.fa-grin-squint::before {
+ content: "\f585"; }
+
+.fa-hand-holding-dollar::before {
+ content: "\f4c0"; }
+
+.fa-hand-holding-usd::before {
+ content: "\f4c0"; }
+
+.fa-bacterium::before {
+ content: "\e05a"; }
+
+.fa-hand-pointer::before {
+ content: "\f25a"; }
+
+.fa-drum-steelpan::before {
+ content: "\f56a"; }
+
+.fa-hand-scissors::before {
+ content: "\f257"; }
+
+.fa-hands-praying::before {
+ content: "\f684"; }
+
+.fa-praying-hands::before {
+ content: "\f684"; }
+
+.fa-arrow-rotate-right::before {
+ content: "\f01e"; }
+
+.fa-arrow-right-rotate::before {
+ content: "\f01e"; }
+
+.fa-arrow-rotate-forward::before {
+ content: "\f01e"; }
+
+.fa-redo::before {
+ content: "\f01e"; }
+
+.fa-biohazard::before {
+ content: "\f780"; }
+
+.fa-location-crosshairs::before {
+ content: "\f601"; }
+
+.fa-location::before {
+ content: "\f601"; }
+
+.fa-mars-double::before {
+ content: "\f227"; }
+
+.fa-child-dress::before {
+ content: "\e59c"; }
+
+.fa-users-between-lines::before {
+ content: "\e591"; }
+
+.fa-lungs-virus::before {
+ content: "\e067"; }
+
+.fa-face-grin-tears::before {
+ content: "\f588"; }
+
+.fa-grin-tears::before {
+ content: "\f588"; }
+
+.fa-phone::before {
+ content: "\f095"; }
+
+.fa-calendar-xmark::before {
+ content: "\f273"; }
+
+.fa-calendar-times::before {
+ content: "\f273"; }
+
+.fa-child-reaching::before {
+ content: "\e59d"; }
+
+.fa-head-side-virus::before {
+ content: "\e064"; }
+
+.fa-user-gear::before {
+ content: "\f4fe"; }
+
+.fa-user-cog::before {
+ content: "\f4fe"; }
+
+.fa-arrow-up-1-9::before {
+ content: "\f163"; }
+
+.fa-sort-numeric-up::before {
+ content: "\f163"; }
+
+.fa-door-closed::before {
+ content: "\f52a"; }
+
+.fa-shield-virus::before {
+ content: "\e06c"; }
+
+.fa-dice-six::before {
+ content: "\f526"; }
+
+.fa-mosquito-net::before {
+ content: "\e52c"; }
+
+.fa-bridge-water::before {
+ content: "\e4ce"; }
+
+.fa-person-booth::before {
+ content: "\f756"; }
+
+.fa-text-width::before {
+ content: "\f035"; }
+
+.fa-hat-wizard::before {
+ content: "\f6e8"; }
+
+.fa-pen-fancy::before {
+ content: "\f5ac"; }
+
+.fa-person-digging::before {
+ content: "\f85e"; }
+
+.fa-digging::before {
+ content: "\f85e"; }
+
+.fa-trash::before {
+ content: "\f1f8"; }
+
+.fa-gauge-simple::before {
+ content: "\f629"; }
+
+.fa-gauge-simple-med::before {
+ content: "\f629"; }
+
+.fa-tachometer-average::before {
+ content: "\f629"; }
+
+.fa-book-medical::before {
+ content: "\f7e6"; }
+
+.fa-poo::before {
+ content: "\f2fe"; }
+
+.fa-quote-right::before {
+ content: "\f10e"; }
+
+.fa-quote-right-alt::before {
+ content: "\f10e"; }
+
+.fa-shirt::before {
+ content: "\f553"; }
+
+.fa-t-shirt::before {
+ content: "\f553"; }
+
+.fa-tshirt::before {
+ content: "\f553"; }
+
+.fa-cubes::before {
+ content: "\f1b3"; }
+
+.fa-divide::before {
+ content: "\f529"; }
+
+.fa-tenge-sign::before {
+ content: "\f7d7"; }
+
+.fa-tenge::before {
+ content: "\f7d7"; }
+
+.fa-headphones::before {
+ content: "\f025"; }
+
+.fa-hands-holding::before {
+ content: "\f4c2"; }
+
+.fa-hands-clapping::before {
+ content: "\e1a8"; }
+
+.fa-republican::before {
+ content: "\f75e"; }
+
+.fa-arrow-left::before {
+ content: "\f060"; }
+
+.fa-person-circle-xmark::before {
+ content: "\e543"; }
+
+.fa-ruler::before {
+ content: "\f545"; }
+
+.fa-align-left::before {
+ content: "\f036"; }
+
+.fa-dice-d6::before {
+ content: "\f6d1"; }
+
+.fa-restroom::before {
+ content: "\f7bd"; }
+
+.fa-j::before {
+ content: "\4a"; }
+
+.fa-users-viewfinder::before {
+ content: "\e595"; }
+
+.fa-file-video::before {
+ content: "\f1c8"; }
+
+.fa-up-right-from-square::before {
+ content: "\f35d"; }
+
+.fa-external-link-alt::before {
+ content: "\f35d"; }
+
+.fa-table-cells::before {
+ content: "\f00a"; }
+
+.fa-th::before {
+ content: "\f00a"; }
+
+.fa-file-pdf::before {
+ content: "\f1c1"; }
+
+.fa-book-bible::before {
+ content: "\f647"; }
+
+.fa-bible::before {
+ content: "\f647"; }
+
+.fa-o::before {
+ content: "\4f"; }
+
+.fa-suitcase-medical::before {
+ content: "\f0fa"; }
+
+.fa-medkit::before {
+ content: "\f0fa"; }
+
+.fa-user-secret::before {
+ content: "\f21b"; }
+
+.fa-otter::before {
+ content: "\f700"; }
+
+.fa-person-dress::before {
+ content: "\f182"; }
+
+.fa-female::before {
+ content: "\f182"; }
+
+.fa-comment-dollar::before {
+ content: "\f651"; }
+
+.fa-business-time::before {
+ content: "\f64a"; }
+
+.fa-briefcase-clock::before {
+ content: "\f64a"; }
+
+.fa-table-cells-large::before {
+ content: "\f009"; }
+
+.fa-th-large::before {
+ content: "\f009"; }
+
+.fa-book-tanakh::before {
+ content: "\f827"; }
+
+.fa-tanakh::before {
+ content: "\f827"; }
+
+.fa-phone-volume::before {
+ content: "\f2a0"; }
+
+.fa-volume-control-phone::before {
+ content: "\f2a0"; }
+
+.fa-hat-cowboy-side::before {
+ content: "\f8c1"; }
+
+.fa-clipboard-user::before {
+ content: "\f7f3"; }
+
+.fa-child::before {
+ content: "\f1ae"; }
+
+.fa-lira-sign::before {
+ content: "\f195"; }
+
+.fa-satellite::before {
+ content: "\f7bf"; }
+
+.fa-plane-lock::before {
+ content: "\e558"; }
+
+.fa-tag::before {
+ content: "\f02b"; }
+
+.fa-comment::before {
+ content: "\f075"; }
+
+.fa-cake-candles::before {
+ content: "\f1fd"; }
+
+.fa-birthday-cake::before {
+ content: "\f1fd"; }
+
+.fa-cake::before {
+ content: "\f1fd"; }
+
+.fa-envelope::before {
+ content: "\f0e0"; }
+
+.fa-angles-up::before {
+ content: "\f102"; }
+
+.fa-angle-double-up::before {
+ content: "\f102"; }
+
+.fa-paperclip::before {
+ content: "\f0c6"; }
+
+.fa-arrow-right-to-city::before {
+ content: "\e4b3"; }
+
+.fa-ribbon::before {
+ content: "\f4d6"; }
+
+.fa-lungs::before {
+ content: "\f604"; }
+
+.fa-arrow-up-9-1::before {
+ content: "\f887"; }
+
+.fa-sort-numeric-up-alt::before {
+ content: "\f887"; }
+
+.fa-litecoin-sign::before {
+ content: "\e1d3"; }
+
+.fa-border-none::before {
+ content: "\f850"; }
+
+.fa-circle-nodes::before {
+ content: "\e4e2"; }
+
+.fa-parachute-box::before {
+ content: "\f4cd"; }
+
+.fa-indent::before {
+ content: "\f03c"; }
+
+.fa-truck-field-un::before {
+ content: "\e58e"; }
+
+.fa-hourglass::before {
+ content: "\f254"; }
+
+.fa-hourglass-empty::before {
+ content: "\f254"; }
+
+.fa-mountain::before {
+ content: "\f6fc"; }
+
+.fa-user-doctor::before {
+ content: "\f0f0"; }
+
+.fa-user-md::before {
+ content: "\f0f0"; }
+
+.fa-circle-info::before {
+ content: "\f05a"; }
+
+.fa-info-circle::before {
+ content: "\f05a"; }
+
+.fa-cloud-meatball::before {
+ content: "\f73b"; }
+
+.fa-camera::before {
+ content: "\f030"; }
+
+.fa-camera-alt::before {
+ content: "\f030"; }
+
+.fa-square-virus::before {
+ content: "\e578"; }
+
+.fa-meteor::before {
+ content: "\f753"; }
+
+.fa-car-on::before {
+ content: "\e4dd"; }
+
+.fa-sleigh::before {
+ content: "\f7cc"; }
+
+.fa-arrow-down-1-9::before {
+ content: "\f162"; }
+
+.fa-sort-numeric-asc::before {
+ content: "\f162"; }
+
+.fa-sort-numeric-down::before {
+ content: "\f162"; }
+
+.fa-hand-holding-droplet::before {
+ content: "\f4c1"; }
+
+.fa-hand-holding-water::before {
+ content: "\f4c1"; }
+
+.fa-water::before {
+ content: "\f773"; }
+
+.fa-calendar-check::before {
+ content: "\f274"; }
+
+.fa-braille::before {
+ content: "\f2a1"; }
+
+.fa-prescription-bottle-medical::before {
+ content: "\f486"; }
+
+.fa-prescription-bottle-alt::before {
+ content: "\f486"; }
+
+.fa-landmark::before {
+ content: "\f66f"; }
+
+.fa-truck::before {
+ content: "\f0d1"; }
+
+.fa-crosshairs::before {
+ content: "\f05b"; }
+
+.fa-person-cane::before {
+ content: "\e53c"; }
+
+.fa-tent::before {
+ content: "\e57d"; }
+
+.fa-vest-patches::before {
+ content: "\e086"; }
+
+.fa-check-double::before {
+ content: "\f560"; }
+
+.fa-arrow-down-a-z::before {
+ content: "\f15d"; }
+
+.fa-sort-alpha-asc::before {
+ content: "\f15d"; }
+
+.fa-sort-alpha-down::before {
+ content: "\f15d"; }
+
+.fa-money-bill-wheat::before {
+ content: "\e52a"; }
+
+.fa-cookie::before {
+ content: "\f563"; }
+
+.fa-arrow-rotate-left::before {
+ content: "\f0e2"; }
+
+.fa-arrow-left-rotate::before {
+ content: "\f0e2"; }
+
+.fa-arrow-rotate-back::before {
+ content: "\f0e2"; }
+
+.fa-arrow-rotate-backward::before {
+ content: "\f0e2"; }
+
+.fa-undo::before {
+ content: "\f0e2"; }
+
+.fa-hard-drive::before {
+ content: "\f0a0"; }
+
+.fa-hdd::before {
+ content: "\f0a0"; }
+
+.fa-face-grin-squint-tears::before {
+ content: "\f586"; }
+
+.fa-grin-squint-tears::before {
+ content: "\f586"; }
+
+.fa-dumbbell::before {
+ content: "\f44b"; }
+
+.fa-rectangle-list::before {
+ content: "\f022"; }
+
+.fa-list-alt::before {
+ content: "\f022"; }
+
+.fa-tarp-droplet::before {
+ content: "\e57c"; }
+
+.fa-house-medical-circle-check::before {
+ content: "\e511"; }
+
+.fa-person-skiing-nordic::before {
+ content: "\f7ca"; }
+
+.fa-skiing-nordic::before {
+ content: "\f7ca"; }
+
+.fa-calendar-plus::before {
+ content: "\f271"; }
+
+.fa-plane-arrival::before {
+ content: "\f5af"; }
+
+.fa-circle-left::before {
+ content: "\f359"; }
+
+.fa-arrow-alt-circle-left::before {
+ content: "\f359"; }
+
+.fa-train-subway::before {
+ content: "\f239"; }
+
+.fa-subway::before {
+ content: "\f239"; }
+
+.fa-chart-gantt::before {
+ content: "\e0e4"; }
+
+.fa-indian-rupee-sign::before {
+ content: "\e1bc"; }
+
+.fa-indian-rupee::before {
+ content: "\e1bc"; }
+
+.fa-inr::before {
+ content: "\e1bc"; }
+
+.fa-crop-simple::before {
+ content: "\f565"; }
+
+.fa-crop-alt::before {
+ content: "\f565"; }
+
+.fa-money-bill-1::before {
+ content: "\f3d1"; }
+
+.fa-money-bill-alt::before {
+ content: "\f3d1"; }
+
+.fa-left-long::before {
+ content: "\f30a"; }
+
+.fa-long-arrow-alt-left::before {
+ content: "\f30a"; }
+
+.fa-dna::before {
+ content: "\f471"; }
+
+.fa-virus-slash::before {
+ content: "\e075"; }
+
+.fa-minus::before {
+ content: "\f068"; }
+
+.fa-subtract::before {
+ content: "\f068"; }
+
+.fa-chess::before {
+ content: "\f439"; }
+
+.fa-arrow-left-long::before {
+ content: "\f177"; }
+
+.fa-long-arrow-left::before {
+ content: "\f177"; }
+
+.fa-plug-circle-check::before {
+ content: "\e55c"; }
+
+.fa-street-view::before {
+ content: "\f21d"; }
+
+.fa-franc-sign::before {
+ content: "\e18f"; }
+
+.fa-volume-off::before {
+ content: "\f026"; }
+
+.fa-hands-asl-interpreting::before {
+ content: "\f2a3"; }
+
+.fa-american-sign-language-interpreting::before {
+ content: "\f2a3"; }
+
+.fa-asl-interpreting::before {
+ content: "\f2a3"; }
+
+.fa-hands-american-sign-language-interpreting::before {
+ content: "\f2a3"; }
+
+.fa-gear::before {
+ content: "\f013"; }
+
+.fa-cog::before {
+ content: "\f013"; }
+
+.fa-droplet-slash::before {
+ content: "\f5c7"; }
+
+.fa-tint-slash::before {
+ content: "\f5c7"; }
+
+.fa-mosque::before {
+ content: "\f678"; }
+
+.fa-mosquito::before {
+ content: "\e52b"; }
+
+.fa-star-of-david::before {
+ content: "\f69a"; }
+
+.fa-person-military-rifle::before {
+ content: "\e54b"; }
+
+.fa-cart-shopping::before {
+ content: "\f07a"; }
+
+.fa-shopping-cart::before {
+ content: "\f07a"; }
+
+.fa-vials::before {
+ content: "\f493"; }
+
+.fa-plug-circle-plus::before {
+ content: "\e55f"; }
+
+.fa-place-of-worship::before {
+ content: "\f67f"; }
+
+.fa-grip-vertical::before {
+ content: "\f58e"; }
+
+.fa-arrow-turn-up::before {
+ content: "\f148"; }
+
+.fa-level-up::before {
+ content: "\f148"; }
+
+.fa-u::before {
+ content: "\55"; }
+
+.fa-square-root-variable::before {
+ content: "\f698"; }
+
+.fa-square-root-alt::before {
+ content: "\f698"; }
+
+.fa-clock::before {
+ content: "\f017"; }
+
+.fa-clock-four::before {
+ content: "\f017"; }
+
+.fa-backward-step::before {
+ content: "\f048"; }
+
+.fa-step-backward::before {
+ content: "\f048"; }
+
+.fa-pallet::before {
+ content: "\f482"; }
+
+.fa-faucet::before {
+ content: "\e005"; }
+
+.fa-baseball-bat-ball::before {
+ content: "\f432"; }
+
+.fa-s::before {
+ content: "\53"; }
+
+.fa-timeline::before {
+ content: "\e29c"; }
+
+.fa-keyboard::before {
+ content: "\f11c"; }
+
+.fa-caret-down::before {
+ content: "\f0d7"; }
+
+.fa-house-chimney-medical::before {
+ content: "\f7f2"; }
+
+.fa-clinic-medical::before {
+ content: "\f7f2"; }
+
+.fa-temperature-three-quarters::before {
+ content: "\f2c8"; }
+
+.fa-temperature-3::before {
+ content: "\f2c8"; }
+
+.fa-thermometer-3::before {
+ content: "\f2c8"; }
+
+.fa-thermometer-three-quarters::before {
+ content: "\f2c8"; }
+
+.fa-mobile-screen::before {
+ content: "\f3cf"; }
+
+.fa-mobile-android-alt::before {
+ content: "\f3cf"; }
+
+.fa-plane-up::before {
+ content: "\e22d"; }
+
+.fa-piggy-bank::before {
+ content: "\f4d3"; }
+
+.fa-battery-half::before {
+ content: "\f242"; }
+
+.fa-battery-3::before {
+ content: "\f242"; }
+
+.fa-mountain-city::before {
+ content: "\e52e"; }
+
+.fa-coins::before {
+ content: "\f51e"; }
+
+.fa-khanda::before {
+ content: "\f66d"; }
+
+.fa-sliders::before {
+ content: "\f1de"; }
+
+.fa-sliders-h::before {
+ content: "\f1de"; }
+
+.fa-folder-tree::before {
+ content: "\f802"; }
+
+.fa-network-wired::before {
+ content: "\f6ff"; }
+
+.fa-map-pin::before {
+ content: "\f276"; }
+
+.fa-hamsa::before {
+ content: "\f665"; }
+
+.fa-cent-sign::before {
+ content: "\e3f5"; }
+
+.fa-flask::before {
+ content: "\f0c3"; }
+
+.fa-person-pregnant::before {
+ content: "\e31e"; }
+
+.fa-wand-sparkles::before {
+ content: "\f72b"; }
+
+.fa-ellipsis-vertical::before {
+ content: "\f142"; }
+
+.fa-ellipsis-v::before {
+ content: "\f142"; }
+
+.fa-ticket::before {
+ content: "\f145"; }
+
+.fa-power-off::before {
+ content: "\f011"; }
+
+.fa-right-long::before {
+ content: "\f30b"; }
+
+.fa-long-arrow-alt-right::before {
+ content: "\f30b"; }
+
+.fa-flag-usa::before {
+ content: "\f74d"; }
+
+.fa-laptop-file::before {
+ content: "\e51d"; }
+
+.fa-tty::before {
+ content: "\f1e4"; }
+
+.fa-teletype::before {
+ content: "\f1e4"; }
+
+.fa-diagram-next::before {
+ content: "\e476"; }
+
+.fa-person-rifle::before {
+ content: "\e54e"; }
+
+.fa-house-medical-circle-exclamation::before {
+ content: "\e512"; }
+
+.fa-closed-captioning::before {
+ content: "\f20a"; }
+
+.fa-person-hiking::before {
+ content: "\f6ec"; }
+
+.fa-hiking::before {
+ content: "\f6ec"; }
+
+.fa-venus-double::before {
+ content: "\f226"; }
+
+.fa-images::before {
+ content: "\f302"; }
+
+.fa-calculator::before {
+ content: "\f1ec"; }
+
+.fa-people-pulling::before {
+ content: "\e535"; }
+
+.fa-n::before {
+ content: "\4e"; }
+
+.fa-cable-car::before {
+ content: "\f7da"; }
+
+.fa-tram::before {
+ content: "\f7da"; }
+
+.fa-cloud-rain::before {
+ content: "\f73d"; }
+
+.fa-building-circle-xmark::before {
+ content: "\e4d4"; }
+
+.fa-ship::before {
+ content: "\f21a"; }
+
+.fa-arrows-down-to-line::before {
+ content: "\e4b8"; }
+
+.fa-download::before {
+ content: "\f019"; }
+
+.fa-face-grin::before {
+ content: "\f580"; }
+
+.fa-grin::before {
+ content: "\f580"; }
+
+.fa-delete-left::before {
+ content: "\f55a"; }
+
+.fa-backspace::before {
+ content: "\f55a"; }
+
+.fa-eye-dropper::before {
+ content: "\f1fb"; }
+
+.fa-eye-dropper-empty::before {
+ content: "\f1fb"; }
+
+.fa-eyedropper::before {
+ content: "\f1fb"; }
+
+.fa-file-circle-check::before {
+ content: "\e5a0"; }
+
+.fa-forward::before {
+ content: "\f04e"; }
+
+.fa-mobile::before {
+ content: "\f3ce"; }
+
+.fa-mobile-android::before {
+ content: "\f3ce"; }
+
+.fa-mobile-phone::before {
+ content: "\f3ce"; }
+
+.fa-face-meh::before {
+ content: "\f11a"; }
+
+.fa-meh::before {
+ content: "\f11a"; }
+
+.fa-align-center::before {
+ content: "\f037"; }
+
+.fa-book-skull::before {
+ content: "\f6b7"; }
+
+.fa-book-dead::before {
+ content: "\f6b7"; }
+
+.fa-id-card::before {
+ content: "\f2c2"; }
+
+.fa-drivers-license::before {
+ content: "\f2c2"; }
+
+.fa-outdent::before {
+ content: "\f03b"; }
+
+.fa-dedent::before {
+ content: "\f03b"; }
+
+.fa-heart-circle-exclamation::before {
+ content: "\e4fe"; }
+
+.fa-house::before {
+ content: "\f015"; }
+
+.fa-home::before {
+ content: "\f015"; }
+
+.fa-home-alt::before {
+ content: "\f015"; }
+
+.fa-home-lg-alt::before {
+ content: "\f015"; }
+
+.fa-calendar-week::before {
+ content: "\f784"; }
+
+.fa-laptop-medical::before {
+ content: "\f812"; }
+
+.fa-b::before {
+ content: "\42"; }
+
+.fa-file-medical::before {
+ content: "\f477"; }
+
+.fa-dice-one::before {
+ content: "\f525"; }
+
+.fa-kiwi-bird::before {
+ content: "\f535"; }
+
+.fa-arrow-right-arrow-left::before {
+ content: "\f0ec"; }
+
+.fa-exchange::before {
+ content: "\f0ec"; }
+
+.fa-rotate-right::before {
+ content: "\f2f9"; }
+
+.fa-redo-alt::before {
+ content: "\f2f9"; }
+
+.fa-rotate-forward::before {
+ content: "\f2f9"; }
+
+.fa-utensils::before {
+ content: "\f2e7"; }
+
+.fa-cutlery::before {
+ content: "\f2e7"; }
+
+.fa-arrow-up-wide-short::before {
+ content: "\f161"; }
+
+.fa-sort-amount-up::before {
+ content: "\f161"; }
+
+.fa-mill-sign::before {
+ content: "\e1ed"; }
+
+.fa-bowl-rice::before {
+ content: "\e2eb"; }
+
+.fa-skull::before {
+ content: "\f54c"; }
+
+.fa-tower-broadcast::before {
+ content: "\f519"; }
+
+.fa-broadcast-tower::before {
+ content: "\f519"; }
+
+.fa-truck-pickup::before {
+ content: "\f63c"; }
+
+.fa-up-long::before {
+ content: "\f30c"; }
+
+.fa-long-arrow-alt-up::before {
+ content: "\f30c"; }
+
+.fa-stop::before {
+ content: "\f04d"; }
+
+.fa-code-merge::before {
+ content: "\f387"; }
+
+.fa-upload::before {
+ content: "\f093"; }
+
+.fa-hurricane::before {
+ content: "\f751"; }
+
+.fa-mound::before {
+ content: "\e52d"; }
+
+.fa-toilet-portable::before {
+ content: "\e583"; }
+
+.fa-compact-disc::before {
+ content: "\f51f"; }
+
+.fa-file-arrow-down::before {
+ content: "\f56d"; }
+
+.fa-file-download::before {
+ content: "\f56d"; }
+
+.fa-caravan::before {
+ content: "\f8ff"; }
+
+.fa-shield-cat::before {
+ content: "\e572"; }
+
+.fa-bolt::before {
+ content: "\f0e7"; }
+
+.fa-zap::before {
+ content: "\f0e7"; }
+
+.fa-glass-water::before {
+ content: "\e4f4"; }
+
+.fa-oil-well::before {
+ content: "\e532"; }
+
+.fa-vault::before {
+ content: "\e2c5"; }
+
+.fa-mars::before {
+ content: "\f222"; }
+
+.fa-toilet::before {
+ content: "\f7d8"; }
+
+.fa-plane-circle-xmark::before {
+ content: "\e557"; }
+
+.fa-yen-sign::before {
+ content: "\f157"; }
+
+.fa-cny::before {
+ content: "\f157"; }
+
+.fa-jpy::before {
+ content: "\f157"; }
+
+.fa-rmb::before {
+ content: "\f157"; }
+
+.fa-yen::before {
+ content: "\f157"; }
+
+.fa-ruble-sign::before {
+ content: "\f158"; }
+
+.fa-rouble::before {
+ content: "\f158"; }
+
+.fa-rub::before {
+ content: "\f158"; }
+
+.fa-ruble::before {
+ content: "\f158"; }
+
+.fa-sun::before {
+ content: "\f185"; }
+
+.fa-guitar::before {
+ content: "\f7a6"; }
+
+.fa-face-laugh-wink::before {
+ content: "\f59c"; }
+
+.fa-laugh-wink::before {
+ content: "\f59c"; }
+
+.fa-horse-head::before {
+ content: "\f7ab"; }
+
+.fa-bore-hole::before {
+ content: "\e4c3"; }
+
+.fa-industry::before {
+ content: "\f275"; }
+
+.fa-circle-down::before {
+ content: "\f358"; }
+
+.fa-arrow-alt-circle-down::before {
+ content: "\f358"; }
+
+.fa-arrows-turn-to-dots::before {
+ content: "\e4c1"; }
+
+.fa-florin-sign::before {
+ content: "\e184"; }
+
+.fa-arrow-down-short-wide::before {
+ content: "\f884"; }
+
+.fa-sort-amount-desc::before {
+ content: "\f884"; }
+
+.fa-sort-amount-down-alt::before {
+ content: "\f884"; }
+
+.fa-less-than::before {
+ content: "\3c"; }
+
+.fa-angle-down::before {
+ content: "\f107"; }
+
+.fa-car-tunnel::before {
+ content: "\e4de"; }
+
+.fa-head-side-cough::before {
+ content: "\e061"; }
+
+.fa-grip-lines::before {
+ content: "\f7a4"; }
+
+.fa-thumbs-down::before {
+ content: "\f165"; }
+
+.fa-user-lock::before {
+ content: "\f502"; }
+
+.fa-arrow-right-long::before {
+ content: "\f178"; }
+
+.fa-long-arrow-right::before {
+ content: "\f178"; }
+
+.fa-anchor-circle-xmark::before {
+ content: "\e4ac"; }
+
+.fa-ellipsis::before {
+ content: "\f141"; }
+
+.fa-ellipsis-h::before {
+ content: "\f141"; }
+
+.fa-chess-pawn::before {
+ content: "\f443"; }
+
+.fa-kit-medical::before {
+ content: "\f479"; }
+
+.fa-first-aid::before {
+ content: "\f479"; }
+
+.fa-person-through-window::before {
+ content: "\e5a9"; }
+
+.fa-toolbox::before {
+ content: "\f552"; }
+
+.fa-hands-holding-circle::before {
+ content: "\e4fb"; }
+
+.fa-bug::before {
+ content: "\f188"; }
+
+.fa-credit-card::before {
+ content: "\f09d"; }
+
+.fa-credit-card-alt::before {
+ content: "\f09d"; }
+
+.fa-car::before {
+ content: "\f1b9"; }
+
+.fa-automobile::before {
+ content: "\f1b9"; }
+
+.fa-hand-holding-hand::before {
+ content: "\e4f7"; }
+
+.fa-book-open-reader::before {
+ content: "\f5da"; }
+
+.fa-book-reader::before {
+ content: "\f5da"; }
+
+.fa-mountain-sun::before {
+ content: "\e52f"; }
+
+.fa-arrows-left-right-to-line::before {
+ content: "\e4ba"; }
+
+.fa-dice-d20::before {
+ content: "\f6cf"; }
+
+.fa-truck-droplet::before {
+ content: "\e58c"; }
+
+.fa-file-circle-xmark::before {
+ content: "\e5a1"; }
+
+.fa-temperature-arrow-up::before {
+ content: "\e040"; }
+
+.fa-temperature-up::before {
+ content: "\e040"; }
+
+.fa-medal::before {
+ content: "\f5a2"; }
+
+.fa-bed::before {
+ content: "\f236"; }
+
+.fa-square-h::before {
+ content: "\f0fd"; }
+
+.fa-h-square::before {
+ content: "\f0fd"; }
+
+.fa-podcast::before {
+ content: "\f2ce"; }
+
+.fa-temperature-full::before {
+ content: "\f2c7"; }
+
+.fa-temperature-4::before {
+ content: "\f2c7"; }
+
+.fa-thermometer-4::before {
+ content: "\f2c7"; }
+
+.fa-thermometer-full::before {
+ content: "\f2c7"; }
+
+.fa-bell::before {
+ content: "\f0f3"; }
+
+.fa-superscript::before {
+ content: "\f12b"; }
+
+.fa-plug-circle-xmark::before {
+ content: "\e560"; }
+
+.fa-star-of-life::before {
+ content: "\f621"; }
+
+.fa-phone-slash::before {
+ content: "\f3dd"; }
+
+.fa-paint-roller::before {
+ content: "\f5aa"; }
+
+.fa-handshake-angle::before {
+ content: "\f4c4"; }
+
+.fa-hands-helping::before {
+ content: "\f4c4"; }
+
+.fa-location-dot::before {
+ content: "\f3c5"; }
+
+.fa-map-marker-alt::before {
+ content: "\f3c5"; }
+
+.fa-file::before {
+ content: "\f15b"; }
+
+.fa-greater-than::before {
+ content: "\3e"; }
+
+.fa-person-swimming::before {
+ content: "\f5c4"; }
+
+.fa-swimmer::before {
+ content: "\f5c4"; }
+
+.fa-arrow-down::before {
+ content: "\f063"; }
+
+.fa-droplet::before {
+ content: "\f043"; }
+
+.fa-tint::before {
+ content: "\f043"; }
+
+.fa-eraser::before {
+ content: "\f12d"; }
+
+.fa-earth-americas::before {
+ content: "\f57d"; }
+
+.fa-earth::before {
+ content: "\f57d"; }
+
+.fa-earth-america::before {
+ content: "\f57d"; }
+
+.fa-globe-americas::before {
+ content: "\f57d"; }
+
+.fa-person-burst::before {
+ content: "\e53b"; }
+
+.fa-dove::before {
+ content: "\f4ba"; }
+
+.fa-battery-empty::before {
+ content: "\f244"; }
+
+.fa-battery-0::before {
+ content: "\f244"; }
+
+.fa-socks::before {
+ content: "\f696"; }
+
+.fa-inbox::before {
+ content: "\f01c"; }
+
+.fa-section::before {
+ content: "\e447"; }
+
+.fa-gauge-high::before {
+ content: "\f625"; }
+
+.fa-tachometer-alt::before {
+ content: "\f625"; }
+
+.fa-tachometer-alt-fast::before {
+ content: "\f625"; }
+
+.fa-envelope-open-text::before {
+ content: "\f658"; }
+
+.fa-hospital::before {
+ content: "\f0f8"; }
+
+.fa-hospital-alt::before {
+ content: "\f0f8"; }
+
+.fa-hospital-wide::before {
+ content: "\f0f8"; }
+
+.fa-wine-bottle::before {
+ content: "\f72f"; }
+
+.fa-chess-rook::before {
+ content: "\f447"; }
+
+.fa-bars-staggered::before {
+ content: "\f550"; }
+
+.fa-reorder::before {
+ content: "\f550"; }
+
+.fa-stream::before {
+ content: "\f550"; }
+
+.fa-dharmachakra::before {
+ content: "\f655"; }
+
+.fa-hotdog::before {
+ content: "\f80f"; }
+
+.fa-person-walking-with-cane::before {
+ content: "\f29d"; }
+
+.fa-blind::before {
+ content: "\f29d"; }
+
+.fa-drum::before {
+ content: "\f569"; }
+
+.fa-ice-cream::before {
+ content: "\f810"; }
+
+.fa-heart-circle-bolt::before {
+ content: "\e4fc"; }
+
+.fa-fax::before {
+ content: "\f1ac"; }
+
+.fa-paragraph::before {
+ content: "\f1dd"; }
+
+.fa-check-to-slot::before {
+ content: "\f772"; }
+
+.fa-vote-yea::before {
+ content: "\f772"; }
+
+.fa-star-half::before {
+ content: "\f089"; }
+
+.fa-boxes-stacked::before {
+ content: "\f468"; }
+
+.fa-boxes::before {
+ content: "\f468"; }
+
+.fa-boxes-alt::before {
+ content: "\f468"; }
+
+.fa-link::before {
+ content: "\f0c1"; }
+
+.fa-chain::before {
+ content: "\f0c1"; }
+
+.fa-ear-listen::before {
+ content: "\f2a2"; }
+
+.fa-assistive-listening-systems::before {
+ content: "\f2a2"; }
+
+.fa-tree-city::before {
+ content: "\e587"; }
+
+.fa-play::before {
+ content: "\f04b"; }
+
+.fa-font::before {
+ content: "\f031"; }
+
+.fa-rupiah-sign::before {
+ content: "\e23d"; }
+
+.fa-magnifying-glass::before {
+ content: "\f002"; }
+
+.fa-search::before {
+ content: "\f002"; }
+
+.fa-table-tennis-paddle-ball::before {
+ content: "\f45d"; }
+
+.fa-ping-pong-paddle-ball::before {
+ content: "\f45d"; }
+
+.fa-table-tennis::before {
+ content: "\f45d"; }
+
+.fa-person-dots-from-line::before {
+ content: "\f470"; }
+
+.fa-diagnoses::before {
+ content: "\f470"; }
+
+.fa-trash-can-arrow-up::before {
+ content: "\f82a"; }
+
+.fa-trash-restore-alt::before {
+ content: "\f82a"; }
+
+.fa-naira-sign::before {
+ content: "\e1f6"; }
+
+.fa-cart-arrow-down::before {
+ content: "\f218"; }
+
+.fa-walkie-talkie::before {
+ content: "\f8ef"; }
+
+.fa-file-pen::before {
+ content: "\f31c"; }
+
+.fa-file-edit::before {
+ content: "\f31c"; }
+
+.fa-receipt::before {
+ content: "\f543"; }
+
+.fa-square-pen::before {
+ content: "\f14b"; }
+
+.fa-pen-square::before {
+ content: "\f14b"; }
+
+.fa-pencil-square::before {
+ content: "\f14b"; }
+
+.fa-suitcase-rolling::before {
+ content: "\f5c1"; }
+
+.fa-person-circle-exclamation::before {
+ content: "\e53f"; }
+
+.fa-chevron-down::before {
+ content: "\f078"; }
+
+.fa-battery-full::before {
+ content: "\f240"; }
+
+.fa-battery::before {
+ content: "\f240"; }
+
+.fa-battery-5::before {
+ content: "\f240"; }
+
+.fa-skull-crossbones::before {
+ content: "\f714"; }
+
+.fa-code-compare::before {
+ content: "\e13a"; }
+
+.fa-list-ul::before {
+ content: "\f0ca"; }
+
+.fa-list-dots::before {
+ content: "\f0ca"; }
+
+.fa-school-lock::before {
+ content: "\e56f"; }
+
+.fa-tower-cell::before {
+ content: "\e585"; }
+
+.fa-down-long::before {
+ content: "\f309"; }
+
+.fa-long-arrow-alt-down::before {
+ content: "\f309"; }
+
+.fa-ranking-star::before {
+ content: "\e561"; }
+
+.fa-chess-king::before {
+ content: "\f43f"; }
+
+.fa-person-harassing::before {
+ content: "\e549"; }
+
+.fa-brazilian-real-sign::before {
+ content: "\e46c"; }
+
+.fa-landmark-dome::before {
+ content: "\f752"; }
+
+.fa-landmark-alt::before {
+ content: "\f752"; }
+
+.fa-arrow-up::before {
+ content: "\f062"; }
+
+.fa-tv::before {
+ content: "\f26c"; }
+
+.fa-television::before {
+ content: "\f26c"; }
+
+.fa-tv-alt::before {
+ content: "\f26c"; }
+
+.fa-shrimp::before {
+ content: "\e448"; }
+
+.fa-list-check::before {
+ content: "\f0ae"; }
+
+.fa-tasks::before {
+ content: "\f0ae"; }
+
+.fa-jug-detergent::before {
+ content: "\e519"; }
+
+.fa-circle-user::before {
+ content: "\f2bd"; }
+
+.fa-user-circle::before {
+ content: "\f2bd"; }
+
+.fa-user-shield::before {
+ content: "\f505"; }
+
+.fa-wind::before {
+ content: "\f72e"; }
+
+.fa-car-burst::before {
+ content: "\f5e1"; }
+
+.fa-car-crash::before {
+ content: "\f5e1"; }
+
+.fa-y::before {
+ content: "\59"; }
+
+.fa-person-snowboarding::before {
+ content: "\f7ce"; }
+
+.fa-snowboarding::before {
+ content: "\f7ce"; }
+
+.fa-truck-fast::before {
+ content: "\f48b"; }
+
+.fa-shipping-fast::before {
+ content: "\f48b"; }
+
+.fa-fish::before {
+ content: "\f578"; }
+
+.fa-user-graduate::before {
+ content: "\f501"; }
+
+.fa-circle-half-stroke::before {
+ content: "\f042"; }
+
+.fa-adjust::before {
+ content: "\f042"; }
+
+.fa-clapperboard::before {
+ content: "\e131"; }
+
+.fa-circle-radiation::before {
+ content: "\f7ba"; }
+
+.fa-radiation-alt::before {
+ content: "\f7ba"; }
+
+.fa-baseball::before {
+ content: "\f433"; }
+
+.fa-baseball-ball::before {
+ content: "\f433"; }
+
+.fa-jet-fighter-up::before {
+ content: "\e518"; }
+
+.fa-diagram-project::before {
+ content: "\f542"; }
+
+.fa-project-diagram::before {
+ content: "\f542"; }
+
+.fa-copy::before {
+ content: "\f0c5"; }
+
+.fa-volume-xmark::before {
+ content: "\f6a9"; }
+
+.fa-volume-mute::before {
+ content: "\f6a9"; }
+
+.fa-volume-times::before {
+ content: "\f6a9"; }
+
+.fa-hand-sparkles::before {
+ content: "\e05d"; }
+
+.fa-grip::before {
+ content: "\f58d"; }
+
+.fa-grip-horizontal::before {
+ content: "\f58d"; }
+
+.fa-share-from-square::before {
+ content: "\f14d"; }
+
+.fa-share-square::before {
+ content: "\f14d"; }
+
+.fa-child-combatant::before {
+ content: "\e4e0"; }
+
+.fa-child-rifle::before {
+ content: "\e4e0"; }
+
+.fa-gun::before {
+ content: "\e19b"; }
+
+.fa-square-phone::before {
+ content: "\f098"; }
+
+.fa-phone-square::before {
+ content: "\f098"; }
+
+.fa-plus::before {
+ content: "\2b"; }
+
+.fa-add::before {
+ content: "\2b"; }
+
+.fa-expand::before {
+ content: "\f065"; }
+
+.fa-computer::before {
+ content: "\e4e5"; }
+
+.fa-xmark::before {
+ content: "\f00d"; }
+
+.fa-close::before {
+ content: "\f00d"; }
+
+.fa-multiply::before {
+ content: "\f00d"; }
+
+.fa-remove::before {
+ content: "\f00d"; }
+
+.fa-times::before {
+ content: "\f00d"; }
+
+.fa-arrows-up-down-left-right::before {
+ content: "\f047"; }
+
+.fa-arrows::before {
+ content: "\f047"; }
+
+.fa-chalkboard-user::before {
+ content: "\f51c"; }
+
+.fa-chalkboard-teacher::before {
+ content: "\f51c"; }
+
+.fa-peso-sign::before {
+ content: "\e222"; }
+
+.fa-building-shield::before {
+ content: "\e4d8"; }
+
+.fa-baby::before {
+ content: "\f77c"; }
+
+.fa-users-line::before {
+ content: "\e592"; }
+
+.fa-quote-left::before {
+ content: "\f10d"; }
+
+.fa-quote-left-alt::before {
+ content: "\f10d"; }
+
+.fa-tractor::before {
+ content: "\f722"; }
+
+.fa-trash-arrow-up::before {
+ content: "\f829"; }
+
+.fa-trash-restore::before {
+ content: "\f829"; }
+
+.fa-arrow-down-up-lock::before {
+ content: "\e4b0"; }
+
+.fa-lines-leaning::before {
+ content: "\e51e"; }
+
+.fa-ruler-combined::before {
+ content: "\f546"; }
+
+.fa-copyright::before {
+ content: "\f1f9"; }
+
+.fa-equals::before {
+ content: "\3d"; }
+
+.fa-blender::before {
+ content: "\f517"; }
+
+.fa-teeth::before {
+ content: "\f62e"; }
+
+.fa-shekel-sign::before {
+ content: "\f20b"; }
+
+.fa-ils::before {
+ content: "\f20b"; }
+
+.fa-shekel::before {
+ content: "\f20b"; }
+
+.fa-sheqel::before {
+ content: "\f20b"; }
+
+.fa-sheqel-sign::before {
+ content: "\f20b"; }
+
+.fa-map::before {
+ content: "\f279"; }
+
+.fa-rocket::before {
+ content: "\f135"; }
+
+.fa-photo-film::before {
+ content: "\f87c"; }
+
+.fa-photo-video::before {
+ content: "\f87c"; }
+
+.fa-folder-minus::before {
+ content: "\f65d"; }
+
+.fa-store::before {
+ content: "\f54e"; }
+
+.fa-arrow-trend-up::before {
+ content: "\e098"; }
+
+.fa-plug-circle-minus::before {
+ content: "\e55e"; }
+
+.fa-sign-hanging::before {
+ content: "\f4d9"; }
+
+.fa-sign::before {
+ content: "\f4d9"; }
+
+.fa-bezier-curve::before {
+ content: "\f55b"; }
+
+.fa-bell-slash::before {
+ content: "\f1f6"; }
+
+.fa-tablet::before {
+ content: "\f3fb"; }
+
+.fa-tablet-android::before {
+ content: "\f3fb"; }
+
+.fa-school-flag::before {
+ content: "\e56e"; }
+
+.fa-fill::before {
+ content: "\f575"; }
+
+.fa-angle-up::before {
+ content: "\f106"; }
+
+.fa-drumstick-bite::before {
+ content: "\f6d7"; }
+
+.fa-holly-berry::before {
+ content: "\f7aa"; }
+
+.fa-chevron-left::before {
+ content: "\f053"; }
+
+.fa-bacteria::before {
+ content: "\e059"; }
+
+.fa-hand-lizard::before {
+ content: "\f258"; }
+
+.fa-notdef::before {
+ content: "\e1fe"; }
+
+.fa-disease::before {
+ content: "\f7fa"; }
+
+.fa-briefcase-medical::before {
+ content: "\f469"; }
+
+.fa-genderless::before {
+ content: "\f22d"; }
+
+.fa-chevron-right::before {
+ content: "\f054"; }
+
+.fa-retweet::before {
+ content: "\f079"; }
+
+.fa-car-rear::before {
+ content: "\f5de"; }
+
+.fa-car-alt::before {
+ content: "\f5de"; }
+
+.fa-pump-soap::before {
+ content: "\e06b"; }
+
+.fa-video-slash::before {
+ content: "\f4e2"; }
+
+.fa-battery-quarter::before {
+ content: "\f243"; }
+
+.fa-battery-2::before {
+ content: "\f243"; }
+
+.fa-radio::before {
+ content: "\f8d7"; }
+
+.fa-baby-carriage::before {
+ content: "\f77d"; }
+
+.fa-carriage-baby::before {
+ content: "\f77d"; }
+
+.fa-traffic-light::before {
+ content: "\f637"; }
+
+.fa-thermometer::before {
+ content: "\f491"; }
+
+.fa-vr-cardboard::before {
+ content: "\f729"; }
+
+.fa-hand-middle-finger::before {
+ content: "\f806"; }
+
+.fa-percent::before {
+ content: "\25"; }
+
+.fa-percentage::before {
+ content: "\25"; }
+
+.fa-truck-moving::before {
+ content: "\f4df"; }
+
+.fa-glass-water-droplet::before {
+ content: "\e4f5"; }
+
+.fa-display::before {
+ content: "\e163"; }
+
+.fa-face-smile::before {
+ content: "\f118"; }
+
+.fa-smile::before {
+ content: "\f118"; }
+
+.fa-thumbtack::before {
+ content: "\f08d"; }
+
+.fa-thumb-tack::before {
+ content: "\f08d"; }
+
+.fa-trophy::before {
+ content: "\f091"; }
+
+.fa-person-praying::before {
+ content: "\f683"; }
+
+.fa-pray::before {
+ content: "\f683"; }
+
+.fa-hammer::before {
+ content: "\f6e3"; }
+
+.fa-hand-peace::before {
+ content: "\f25b"; }
+
+.fa-rotate::before {
+ content: "\f2f1"; }
+
+.fa-sync-alt::before {
+ content: "\f2f1"; }
+
+.fa-spinner::before {
+ content: "\f110"; }
+
+.fa-robot::before {
+ content: "\f544"; }
+
+.fa-peace::before {
+ content: "\f67c"; }
+
+.fa-gears::before {
+ content: "\f085"; }
+
+.fa-cogs::before {
+ content: "\f085"; }
+
+.fa-warehouse::before {
+ content: "\f494"; }
+
+.fa-arrow-up-right-dots::before {
+ content: "\e4b7"; }
+
+.fa-splotch::before {
+ content: "\f5bc"; }
+
+.fa-face-grin-hearts::before {
+ content: "\f584"; }
+
+.fa-grin-hearts::before {
+ content: "\f584"; }
+
+.fa-dice-four::before {
+ content: "\f524"; }
+
+.fa-sim-card::before {
+ content: "\f7c4"; }
+
+.fa-transgender::before {
+ content: "\f225"; }
+
+.fa-transgender-alt::before {
+ content: "\f225"; }
+
+.fa-mercury::before {
+ content: "\f223"; }
+
+.fa-arrow-turn-down::before {
+ content: "\f149"; }
+
+.fa-level-down::before {
+ content: "\f149"; }
+
+.fa-person-falling-burst::before {
+ content: "\e547"; }
+
+.fa-award::before {
+ content: "\f559"; }
+
+.fa-ticket-simple::before {
+ content: "\f3ff"; }
+
+.fa-ticket-alt::before {
+ content: "\f3ff"; }
+
+.fa-building::before {
+ content: "\f1ad"; }
+
+.fa-angles-left::before {
+ content: "\f100"; }
+
+.fa-angle-double-left::before {
+ content: "\f100"; }
+
+.fa-qrcode::before {
+ content: "\f029"; }
+
+.fa-clock-rotate-left::before {
+ content: "\f1da"; }
+
+.fa-history::before {
+ content: "\f1da"; }
+
+.fa-face-grin-beam-sweat::before {
+ content: "\f583"; }
+
+.fa-grin-beam-sweat::before {
+ content: "\f583"; }
+
+.fa-file-export::before {
+ content: "\f56e"; }
+
+.fa-arrow-right-from-file::before {
+ content: "\f56e"; }
+
+.fa-shield::before {
+ content: "\f132"; }
+
+.fa-shield-blank::before {
+ content: "\f132"; }
+
+.fa-arrow-up-short-wide::before {
+ content: "\f885"; }
+
+.fa-sort-amount-up-alt::before {
+ content: "\f885"; }
+
+.fa-house-medical::before {
+ content: "\e3b2"; }
+
+.fa-golf-ball-tee::before {
+ content: "\f450"; }
+
+.fa-golf-ball::before {
+ content: "\f450"; }
+
+.fa-circle-chevron-left::before {
+ content: "\f137"; }
+
+.fa-chevron-circle-left::before {
+ content: "\f137"; }
+
+.fa-house-chimney-window::before {
+ content: "\e00d"; }
+
+.fa-pen-nib::before {
+ content: "\f5ad"; }
+
+.fa-tent-arrow-turn-left::before {
+ content: "\e580"; }
+
+.fa-tents::before {
+ content: "\e582"; }
+
+.fa-wand-magic::before {
+ content: "\f0d0"; }
+
+.fa-magic::before {
+ content: "\f0d0"; }
+
+.fa-dog::before {
+ content: "\f6d3"; }
+
+.fa-carrot::before {
+ content: "\f787"; }
+
+.fa-moon::before {
+ content: "\f186"; }
+
+.fa-wine-glass-empty::before {
+ content: "\f5ce"; }
+
+.fa-wine-glass-alt::before {
+ content: "\f5ce"; }
+
+.fa-cheese::before {
+ content: "\f7ef"; }
+
+.fa-yin-yang::before {
+ content: "\f6ad"; }
+
+.fa-music::before {
+ content: "\f001"; }
+
+.fa-code-commit::before {
+ content: "\f386"; }
+
+.fa-temperature-low::before {
+ content: "\f76b"; }
+
+.fa-person-biking::before {
+ content: "\f84a"; }
+
+.fa-biking::before {
+ content: "\f84a"; }
+
+.fa-broom::before {
+ content: "\f51a"; }
+
+.fa-shield-heart::before {
+ content: "\e574"; }
+
+.fa-gopuram::before {
+ content: "\f664"; }
+
+.fa-earth-oceania::before {
+ content: "\e47b"; }
+
+.fa-globe-oceania::before {
+ content: "\e47b"; }
+
+.fa-square-xmark::before {
+ content: "\f2d3"; }
+
+.fa-times-square::before {
+ content: "\f2d3"; }
+
+.fa-xmark-square::before {
+ content: "\f2d3"; }
+
+.fa-hashtag::before {
+ content: "\23"; }
+
+.fa-up-right-and-down-left-from-center::before {
+ content: "\f424"; }
+
+.fa-expand-alt::before {
+ content: "\f424"; }
+
+.fa-oil-can::before {
+ content: "\f613"; }
+
+.fa-t::before {
+ content: "\54"; }
+
+.fa-hippo::before {
+ content: "\f6ed"; }
+
+.fa-chart-column::before {
+ content: "\e0e3"; }
+
+.fa-infinity::before {
+ content: "\f534"; }
+
+.fa-vial-circle-check::before {
+ content: "\e596"; }
+
+.fa-person-arrow-down-to-line::before {
+ content: "\e538"; }
+
+.fa-voicemail::before {
+ content: "\f897"; }
+
+.fa-fan::before {
+ content: "\f863"; }
+
+.fa-person-walking-luggage::before {
+ content: "\e554"; }
+
+.fa-up-down::before {
+ content: "\f338"; }
+
+.fa-arrows-alt-v::before {
+ content: "\f338"; }
+
+.fa-cloud-moon-rain::before {
+ content: "\f73c"; }
+
+.fa-calendar::before {
+ content: "\f133"; }
+
+.fa-trailer::before {
+ content: "\e041"; }
+
+.fa-bahai::before {
+ content: "\f666"; }
+
+.fa-haykal::before {
+ content: "\f666"; }
+
+.fa-sd-card::before {
+ content: "\f7c2"; }
+
+.fa-dragon::before {
+ content: "\f6d5"; }
+
+.fa-shoe-prints::before {
+ content: "\f54b"; }
+
+.fa-circle-plus::before {
+ content: "\f055"; }
+
+.fa-plus-circle::before {
+ content: "\f055"; }
+
+.fa-face-grin-tongue-wink::before {
+ content: "\f58b"; }
+
+.fa-grin-tongue-wink::before {
+ content: "\f58b"; }
+
+.fa-hand-holding::before {
+ content: "\f4bd"; }
+
+.fa-plug-circle-exclamation::before {
+ content: "\e55d"; }
+
+.fa-link-slash::before {
+ content: "\f127"; }
+
+.fa-chain-broken::before {
+ content: "\f127"; }
+
+.fa-chain-slash::before {
+ content: "\f127"; }
+
+.fa-unlink::before {
+ content: "\f127"; }
+
+.fa-clone::before {
+ content: "\f24d"; }
+
+.fa-person-walking-arrow-loop-left::before {
+ content: "\e551"; }
+
+.fa-arrow-up-z-a::before {
+ content: "\f882"; }
+
+.fa-sort-alpha-up-alt::before {
+ content: "\f882"; }
+
+.fa-fire-flame-curved::before {
+ content: "\f7e4"; }
+
+.fa-fire-alt::before {
+ content: "\f7e4"; }
+
+.fa-tornado::before {
+ content: "\f76f"; }
+
+.fa-file-circle-plus::before {
+ content: "\e494"; }
+
+.fa-book-quran::before {
+ content: "\f687"; }
+
+.fa-quran::before {
+ content: "\f687"; }
+
+.fa-anchor::before {
+ content: "\f13d"; }
+
+.fa-border-all::before {
+ content: "\f84c"; }
+
+.fa-face-angry::before {
+ content: "\f556"; }
+
+.fa-angry::before {
+ content: "\f556"; }
+
+.fa-cookie-bite::before {
+ content: "\f564"; }
+
+.fa-arrow-trend-down::before {
+ content: "\e097"; }
+
+.fa-rss::before {
+ content: "\f09e"; }
+
+.fa-feed::before {
+ content: "\f09e"; }
+
+.fa-draw-polygon::before {
+ content: "\f5ee"; }
+
+.fa-scale-balanced::before {
+ content: "\f24e"; }
+
+.fa-balance-scale::before {
+ content: "\f24e"; }
+
+.fa-gauge-simple-high::before {
+ content: "\f62a"; }
+
+.fa-tachometer::before {
+ content: "\f62a"; }
+
+.fa-tachometer-fast::before {
+ content: "\f62a"; }
+
+.fa-shower::before {
+ content: "\f2cc"; }
+
+.fa-desktop::before {
+ content: "\f390"; }
+
+.fa-desktop-alt::before {
+ content: "\f390"; }
+
+.fa-m::before {
+ content: "\4d"; }
+
+.fa-table-list::before {
+ content: "\f00b"; }
+
+.fa-th-list::before {
+ content: "\f00b"; }
+
+.fa-comment-sms::before {
+ content: "\f7cd"; }
+
+.fa-sms::before {
+ content: "\f7cd"; }
+
+.fa-book::before {
+ content: "\f02d"; }
+
+.fa-user-plus::before {
+ content: "\f234"; }
+
+.fa-check::before {
+ content: "\f00c"; }
+
+.fa-battery-three-quarters::before {
+ content: "\f241"; }
+
+.fa-battery-4::before {
+ content: "\f241"; }
+
+.fa-house-circle-check::before {
+ content: "\e509"; }
+
+.fa-angle-left::before {
+ content: "\f104"; }
+
+.fa-diagram-successor::before {
+ content: "\e47a"; }
+
+.fa-truck-arrow-right::before {
+ content: "\e58b"; }
+
+.fa-arrows-split-up-and-left::before {
+ content: "\e4bc"; }
+
+.fa-hand-fist::before {
+ content: "\f6de"; }
+
+.fa-fist-raised::before {
+ content: "\f6de"; }
+
+.fa-cloud-moon::before {
+ content: "\f6c3"; }
+
+.fa-briefcase::before {
+ content: "\f0b1"; }
+
+.fa-person-falling::before {
+ content: "\e546"; }
+
+.fa-image-portrait::before {
+ content: "\f3e0"; }
+
+.fa-portrait::before {
+ content: "\f3e0"; }
+
+.fa-user-tag::before {
+ content: "\f507"; }
+
+.fa-rug::before {
+ content: "\e569"; }
+
+.fa-earth-europe::before {
+ content: "\f7a2"; }
+
+.fa-globe-europe::before {
+ content: "\f7a2"; }
+
+.fa-cart-flatbed-suitcase::before {
+ content: "\f59d"; }
+
+.fa-luggage-cart::before {
+ content: "\f59d"; }
+
+.fa-rectangle-xmark::before {
+ content: "\f410"; }
+
+.fa-rectangle-times::before {
+ content: "\f410"; }
+
+.fa-times-rectangle::before {
+ content: "\f410"; }
+
+.fa-window-close::before {
+ content: "\f410"; }
+
+.fa-baht-sign::before {
+ content: "\e0ac"; }
+
+.fa-book-open::before {
+ content: "\f518"; }
+
+.fa-book-journal-whills::before {
+ content: "\f66a"; }
+
+.fa-journal-whills::before {
+ content: "\f66a"; }
+
+.fa-handcuffs::before {
+ content: "\e4f8"; }
+
+.fa-triangle-exclamation::before {
+ content: "\f071"; }
+
+.fa-exclamation-triangle::before {
+ content: "\f071"; }
+
+.fa-warning::before {
+ content: "\f071"; }
+
+.fa-database::before {
+ content: "\f1c0"; }
+
+.fa-share::before {
+ content: "\f064"; }
+
+.fa-arrow-turn-right::before {
+ content: "\f064"; }
+
+.fa-mail-forward::before {
+ content: "\f064"; }
+
+.fa-bottle-droplet::before {
+ content: "\e4c4"; }
+
+.fa-mask-face::before {
+ content: "\e1d7"; }
+
+.fa-hill-rockslide::before {
+ content: "\e508"; }
+
+.fa-right-left::before {
+ content: "\f362"; }
+
+.fa-exchange-alt::before {
+ content: "\f362"; }
+
+.fa-paper-plane::before {
+ content: "\f1d8"; }
+
+.fa-road-circle-exclamation::before {
+ content: "\e565"; }
+
+.fa-dungeon::before {
+ content: "\f6d9"; }
+
+.fa-align-right::before {
+ content: "\f038"; }
+
+.fa-money-bill-1-wave::before {
+ content: "\f53b"; }
+
+.fa-money-bill-wave-alt::before {
+ content: "\f53b"; }
+
+.fa-life-ring::before {
+ content: "\f1cd"; }
+
+.fa-hands::before {
+ content: "\f2a7"; }
+
+.fa-sign-language::before {
+ content: "\f2a7"; }
+
+.fa-signing::before {
+ content: "\f2a7"; }
+
+.fa-calendar-day::before {
+ content: "\f783"; }
+
+.fa-water-ladder::before {
+ content: "\f5c5"; }
+
+.fa-ladder-water::before {
+ content: "\f5c5"; }
+
+.fa-swimming-pool::before {
+ content: "\f5c5"; }
+
+.fa-arrows-up-down::before {
+ content: "\f07d"; }
+
+.fa-arrows-v::before {
+ content: "\f07d"; }
+
+.fa-face-grimace::before {
+ content: "\f57f"; }
+
+.fa-grimace::before {
+ content: "\f57f"; }
+
+.fa-wheelchair-move::before {
+ content: "\e2ce"; }
+
+.fa-wheelchair-alt::before {
+ content: "\e2ce"; }
+
+.fa-turn-down::before {
+ content: "\f3be"; }
+
+.fa-level-down-alt::before {
+ content: "\f3be"; }
+
+.fa-person-walking-arrow-right::before {
+ content: "\e552"; }
+
+.fa-square-envelope::before {
+ content: "\f199"; }
+
+.fa-envelope-square::before {
+ content: "\f199"; }
+
+.fa-dice::before {
+ content: "\f522"; }
+
+.fa-bowling-ball::before {
+ content: "\f436"; }
+
+.fa-brain::before {
+ content: "\f5dc"; }
+
+.fa-bandage::before {
+ content: "\f462"; }
+
+.fa-band-aid::before {
+ content: "\f462"; }
+
+.fa-calendar-minus::before {
+ content: "\f272"; }
+
+.fa-circle-xmark::before {
+ content: "\f057"; }
+
+.fa-times-circle::before {
+ content: "\f057"; }
+
+.fa-xmark-circle::before {
+ content: "\f057"; }
+
+.fa-gifts::before {
+ content: "\f79c"; }
+
+.fa-hotel::before {
+ content: "\f594"; }
+
+.fa-earth-asia::before {
+ content: "\f57e"; }
+
+.fa-globe-asia::before {
+ content: "\f57e"; }
+
+.fa-id-card-clip::before {
+ content: "\f47f"; }
+
+.fa-id-card-alt::before {
+ content: "\f47f"; }
+
+.fa-magnifying-glass-plus::before {
+ content: "\f00e"; }
+
+.fa-search-plus::before {
+ content: "\f00e"; }
+
+.fa-thumbs-up::before {
+ content: "\f164"; }
+
+.fa-user-clock::before {
+ content: "\f4fd"; }
+
+.fa-hand-dots::before {
+ content: "\f461"; }
+
+.fa-allergies::before {
+ content: "\f461"; }
+
+.fa-file-invoice::before {
+ content: "\f570"; }
+
+.fa-window-minimize::before {
+ content: "\f2d1"; }
+
+.fa-mug-saucer::before {
+ content: "\f0f4"; }
+
+.fa-coffee::before {
+ content: "\f0f4"; }
+
+.fa-brush::before {
+ content: "\f55d"; }
+
+.fa-mask::before {
+ content: "\f6fa"; }
+
+.fa-magnifying-glass-minus::before {
+ content: "\f010"; }
+
+.fa-search-minus::before {
+ content: "\f010"; }
+
+.fa-ruler-vertical::before {
+ content: "\f548"; }
+
+.fa-user-large::before {
+ content: "\f406"; }
+
+.fa-user-alt::before {
+ content: "\f406"; }
+
+.fa-train-tram::before {
+ content: "\e5b4"; }
+
+.fa-user-nurse::before {
+ content: "\f82f"; }
+
+.fa-syringe::before {
+ content: "\f48e"; }
+
+.fa-cloud-sun::before {
+ content: "\f6c4"; }
+
+.fa-stopwatch-20::before {
+ content: "\e06f"; }
+
+.fa-square-full::before {
+ content: "\f45c"; }
+
+.fa-magnet::before {
+ content: "\f076"; }
+
+.fa-jar::before {
+ content: "\e516"; }
+
+.fa-note-sticky::before {
+ content: "\f249"; }
+
+.fa-sticky-note::before {
+ content: "\f249"; }
+
+.fa-bug-slash::before {
+ content: "\e490"; }
+
+.fa-arrow-up-from-water-pump::before {
+ content: "\e4b6"; }
+
+.fa-bone::before {
+ content: "\f5d7"; }
+
+.fa-user-injured::before {
+ content: "\f728"; }
+
+.fa-face-sad-tear::before {
+ content: "\f5b4"; }
+
+.fa-sad-tear::before {
+ content: "\f5b4"; }
+
+.fa-plane::before {
+ content: "\f072"; }
+
+.fa-tent-arrows-down::before {
+ content: "\e581"; }
+
+.fa-exclamation::before {
+ content: "\21"; }
+
+.fa-arrows-spin::before {
+ content: "\e4bb"; }
+
+.fa-print::before {
+ content: "\f02f"; }
+
+.fa-turkish-lira-sign::before {
+ content: "\e2bb"; }
+
+.fa-try::before {
+ content: "\e2bb"; }
+
+.fa-turkish-lira::before {
+ content: "\e2bb"; }
+
+.fa-dollar-sign::before {
+ content: "\24"; }
+
+.fa-dollar::before {
+ content: "\24"; }
+
+.fa-usd::before {
+ content: "\24"; }
+
+.fa-x::before {
+ content: "\58"; }
+
+.fa-magnifying-glass-dollar::before {
+ content: "\f688"; }
+
+.fa-search-dollar::before {
+ content: "\f688"; }
+
+.fa-users-gear::before {
+ content: "\f509"; }
+
+.fa-users-cog::before {
+ content: "\f509"; }
+
+.fa-person-military-pointing::before {
+ content: "\e54a"; }
+
+.fa-building-columns::before {
+ content: "\f19c"; }
+
+.fa-bank::before {
+ content: "\f19c"; }
+
+.fa-institution::before {
+ content: "\f19c"; }
+
+.fa-museum::before {
+ content: "\f19c"; }
+
+.fa-university::before {
+ content: "\f19c"; }
+
+.fa-umbrella::before {
+ content: "\f0e9"; }
+
+.fa-trowel::before {
+ content: "\e589"; }
+
+.fa-d::before {
+ content: "\44"; }
+
+.fa-stapler::before {
+ content: "\e5af"; }
+
+.fa-masks-theater::before {
+ content: "\f630"; }
+
+.fa-theater-masks::before {
+ content: "\f630"; }
+
+.fa-kip-sign::before {
+ content: "\e1c4"; }
+
+.fa-hand-point-left::before {
+ content: "\f0a5"; }
+
+.fa-handshake-simple::before {
+ content: "\f4c6"; }
+
+.fa-handshake-alt::before {
+ content: "\f4c6"; }
+
+.fa-jet-fighter::before {
+ content: "\f0fb"; }
+
+.fa-fighter-jet::before {
+ content: "\f0fb"; }
+
+.fa-square-share-nodes::before {
+ content: "\f1e1"; }
+
+.fa-share-alt-square::before {
+ content: "\f1e1"; }
+
+.fa-barcode::before {
+ content: "\f02a"; }
+
+.fa-plus-minus::before {
+ content: "\e43c"; }
+
+.fa-video::before {
+ content: "\f03d"; }
+
+.fa-video-camera::before {
+ content: "\f03d"; }
+
+.fa-graduation-cap::before {
+ content: "\f19d"; }
+
+.fa-mortar-board::before {
+ content: "\f19d"; }
+
+.fa-hand-holding-medical::before {
+ content: "\e05c"; }
+
+.fa-person-circle-check::before {
+ content: "\e53e"; }
+
+.fa-turn-up::before {
+ content: "\f3bf"; }
+
+.fa-level-up-alt::before {
+ content: "\f3bf"; }
+
+.sr-only,
+.fa-sr-only {
+ position: absolute;
+ width: 1px;
+ height: 1px;
+ padding: 0;
+ margin: -1px;
+ overflow: hidden;
+ clip: rect(0, 0, 0, 0);
+ white-space: nowrap;
+ border-width: 0; }
+
+.sr-only-focusable:not(:focus),
+.fa-sr-only-focusable:not(:focus) {
+ position: absolute;
+ width: 1px;
+ height: 1px;
+ padding: 0;
+ margin: -1px;
+ overflow: hidden;
+ clip: rect(0, 0, 0, 0);
+ white-space: nowrap;
+ border-width: 0; }
+:root, :host {
+ --fa-style-family-brands: 'Font Awesome 6 Brands';
+ --fa-font-brands: normal 400 1em/1 'Font Awesome 6 Brands'; }
+
+@font-face {
+ font-family: 'Font Awesome 6 Brands';
+ font-style: normal;
+ font-weight: 400;
+ font-display: block;
+ src: url("../webfonts/fa-brands-400.woff2") format("woff2"), url("../webfonts/fa-brands-400.ttf") format("truetype"); }
+
+.fab,
+.fa-brands {
+ font-weight: 400; }
+
+.fa-monero:before {
+ content: "\f3d0"; }
+
+.fa-hooli:before {
+ content: "\f427"; }
+
+.fa-yelp:before {
+ content: "\f1e9"; }
+
+.fa-cc-visa:before {
+ content: "\f1f0"; }
+
+.fa-lastfm:before {
+ content: "\f202"; }
+
+.fa-shopware:before {
+ content: "\f5b5"; }
+
+.fa-creative-commons-nc:before {
+ content: "\f4e8"; }
+
+.fa-aws:before {
+ content: "\f375"; }
+
+.fa-redhat:before {
+ content: "\f7bc"; }
+
+.fa-yoast:before {
+ content: "\f2b1"; }
+
+.fa-cloudflare:before {
+ content: "\e07d"; }
+
+.fa-ups:before {
+ content: "\f7e0"; }
+
+.fa-wpexplorer:before {
+ content: "\f2de"; }
+
+.fa-dyalog:before {
+ content: "\f399"; }
+
+.fa-bity:before {
+ content: "\f37a"; }
+
+.fa-stackpath:before {
+ content: "\f842"; }
+
+.fa-buysellads:before {
+ content: "\f20d"; }
+
+.fa-first-order:before {
+ content: "\f2b0"; }
+
+.fa-modx:before {
+ content: "\f285"; }
+
+.fa-guilded:before {
+ content: "\e07e"; }
+
+.fa-vnv:before {
+ content: "\f40b"; }
+
+.fa-square-js:before {
+ content: "\f3b9"; }
+
+.fa-js-square:before {
+ content: "\f3b9"; }
+
+.fa-microsoft:before {
+ content: "\f3ca"; }
+
+.fa-qq:before {
+ content: "\f1d6"; }
+
+.fa-orcid:before {
+ content: "\f8d2"; }
+
+.fa-java:before {
+ content: "\f4e4"; }
+
+.fa-invision:before {
+ content: "\f7b0"; }
+
+.fa-creative-commons-pd-alt:before {
+ content: "\f4ed"; }
+
+.fa-centercode:before {
+ content: "\f380"; }
+
+.fa-glide-g:before {
+ content: "\f2a6"; }
+
+.fa-drupal:before {
+ content: "\f1a9"; }
+
+.fa-hire-a-helper:before {
+ content: "\f3b0"; }
+
+.fa-creative-commons-by:before {
+ content: "\f4e7"; }
+
+.fa-unity:before {
+ content: "\e049"; }
+
+.fa-whmcs:before {
+ content: "\f40d"; }
+
+.fa-rocketchat:before {
+ content: "\f3e8"; }
+
+.fa-vk:before {
+ content: "\f189"; }
+
+.fa-untappd:before {
+ content: "\f405"; }
+
+.fa-mailchimp:before {
+ content: "\f59e"; }
+
+.fa-css3-alt:before {
+ content: "\f38b"; }
+
+.fa-square-reddit:before {
+ content: "\f1a2"; }
+
+.fa-reddit-square:before {
+ content: "\f1a2"; }
+
+.fa-vimeo-v:before {
+ content: "\f27d"; }
+
+.fa-contao:before {
+ content: "\f26d"; }
+
+.fa-square-font-awesome:before {
+ content: "\e5ad"; }
+
+.fa-deskpro:before {
+ content: "\f38f"; }
+
+.fa-sistrix:before {
+ content: "\f3ee"; }
+
+.fa-square-instagram:before {
+ content: "\e055"; }
+
+.fa-instagram-square:before {
+ content: "\e055"; }
+
+.fa-battle-net:before {
+ content: "\f835"; }
+
+.fa-the-red-yeti:before {
+ content: "\f69d"; }
+
+.fa-square-hacker-news:before {
+ content: "\f3af"; }
+
+.fa-hacker-news-square:before {
+ content: "\f3af"; }
+
+.fa-edge:before {
+ content: "\f282"; }
+
+.fa-napster:before {
+ content: "\f3d2"; }
+
+.fa-square-snapchat:before {
+ content: "\f2ad"; }
+
+.fa-snapchat-square:before {
+ content: "\f2ad"; }
+
+.fa-google-plus-g:before {
+ content: "\f0d5"; }
+
+.fa-artstation:before {
+ content: "\f77a"; }
+
+.fa-markdown:before {
+ content: "\f60f"; }
+
+.fa-sourcetree:before {
+ content: "\f7d3"; }
+
+.fa-google-plus:before {
+ content: "\f2b3"; }
+
+.fa-diaspora:before {
+ content: "\f791"; }
+
+.fa-foursquare:before {
+ content: "\f180"; }
+
+.fa-stack-overflow:before {
+ content: "\f16c"; }
+
+.fa-github-alt:before {
+ content: "\f113"; }
+
+.fa-phoenix-squadron:before {
+ content: "\f511"; }
+
+.fa-pagelines:before {
+ content: "\f18c"; }
+
+.fa-algolia:before {
+ content: "\f36c"; }
+
+.fa-red-river:before {
+ content: "\f3e3"; }
+
+.fa-creative-commons-sa:before {
+ content: "\f4ef"; }
+
+.fa-safari:before {
+ content: "\f267"; }
+
+.fa-google:before {
+ content: "\f1a0"; }
+
+.fa-square-font-awesome-stroke:before {
+ content: "\f35c"; }
+
+.fa-font-awesome-alt:before {
+ content: "\f35c"; }
+
+.fa-atlassian:before {
+ content: "\f77b"; }
+
+.fa-linkedin-in:before {
+ content: "\f0e1"; }
+
+.fa-digital-ocean:before {
+ content: "\f391"; }
+
+.fa-nimblr:before {
+ content: "\f5a8"; }
+
+.fa-chromecast:before {
+ content: "\f838"; }
+
+.fa-evernote:before {
+ content: "\f839"; }
+
+.fa-hacker-news:before {
+ content: "\f1d4"; }
+
+.fa-creative-commons-sampling:before {
+ content: "\f4f0"; }
+
+.fa-adversal:before {
+ content: "\f36a"; }
+
+.fa-creative-commons:before {
+ content: "\f25e"; }
+
+.fa-watchman-monitoring:before {
+ content: "\e087"; }
+
+.fa-fonticons:before {
+ content: "\f280"; }
+
+.fa-weixin:before {
+ content: "\f1d7"; }
+
+.fa-shirtsinbulk:before {
+ content: "\f214"; }
+
+.fa-codepen:before {
+ content: "\f1cb"; }
+
+.fa-git-alt:before {
+ content: "\f841"; }
+
+.fa-lyft:before {
+ content: "\f3c3"; }
+
+.fa-rev:before {
+ content: "\f5b2"; }
+
+.fa-windows:before {
+ content: "\f17a"; }
+
+.fa-wizards-of-the-coast:before {
+ content: "\f730"; }
+
+.fa-square-viadeo:before {
+ content: "\f2aa"; }
+
+.fa-viadeo-square:before {
+ content: "\f2aa"; }
+
+.fa-meetup:before {
+ content: "\f2e0"; }
+
+.fa-centos:before {
+ content: "\f789"; }
+
+.fa-adn:before {
+ content: "\f170"; }
+
+.fa-cloudsmith:before {
+ content: "\f384"; }
+
+.fa-pied-piper-alt:before {
+ content: "\f1a8"; }
+
+.fa-square-dribbble:before {
+ content: "\f397"; }
+
+.fa-dribbble-square:before {
+ content: "\f397"; }
+
+.fa-codiepie:before {
+ content: "\f284"; }
+
+.fa-node:before {
+ content: "\f419"; }
+
+.fa-mix:before {
+ content: "\f3cb"; }
+
+.fa-steam:before {
+ content: "\f1b6"; }
+
+.fa-cc-apple-pay:before {
+ content: "\f416"; }
+
+.fa-scribd:before {
+ content: "\f28a"; }
+
+.fa-openid:before {
+ content: "\f19b"; }
+
+.fa-instalod:before {
+ content: "\e081"; }
+
+.fa-expeditedssl:before {
+ content: "\f23e"; }
+
+.fa-sellcast:before {
+ content: "\f2da"; }
+
+.fa-square-twitter:before {
+ content: "\f081"; }
+
+.fa-twitter-square:before {
+ content: "\f081"; }
+
+.fa-r-project:before {
+ content: "\f4f7"; }
+
+.fa-delicious:before {
+ content: "\f1a5"; }
+
+.fa-freebsd:before {
+ content: "\f3a4"; }
+
+.fa-vuejs:before {
+ content: "\f41f"; }
+
+.fa-accusoft:before {
+ content: "\f369"; }
+
+.fa-ioxhost:before {
+ content: "\f208"; }
+
+.fa-fonticons-fi:before {
+ content: "\f3a2"; }
+
+.fa-app-store:before {
+ content: "\f36f"; }
+
+.fa-cc-mastercard:before {
+ content: "\f1f1"; }
+
+.fa-itunes-note:before {
+ content: "\f3b5"; }
+
+.fa-golang:before {
+ content: "\e40f"; }
+
+.fa-kickstarter:before {
+ content: "\f3bb"; }
+
+.fa-grav:before {
+ content: "\f2d6"; }
+
+.fa-weibo:before {
+ content: "\f18a"; }
+
+.fa-uncharted:before {
+ content: "\e084"; }
+
+.fa-firstdraft:before {
+ content: "\f3a1"; }
+
+.fa-square-youtube:before {
+ content: "\f431"; }
+
+.fa-youtube-square:before {
+ content: "\f431"; }
+
+.fa-wikipedia-w:before {
+ content: "\f266"; }
+
+.fa-wpressr:before {
+ content: "\f3e4"; }
+
+.fa-rendact:before {
+ content: "\f3e4"; }
+
+.fa-angellist:before {
+ content: "\f209"; }
+
+.fa-galactic-republic:before {
+ content: "\f50c"; }
+
+.fa-nfc-directional:before {
+ content: "\e530"; }
+
+.fa-skype:before {
+ content: "\f17e"; }
+
+.fa-joget:before {
+ content: "\f3b7"; }
+
+.fa-fedora:before {
+ content: "\f798"; }
+
+.fa-stripe-s:before {
+ content: "\f42a"; }
+
+.fa-meta:before {
+ content: "\e49b"; }
+
+.fa-laravel:before {
+ content: "\f3bd"; }
+
+.fa-hotjar:before {
+ content: "\f3b1"; }
+
+.fa-bluetooth-b:before {
+ content: "\f294"; }
+
+.fa-sticker-mule:before {
+ content: "\f3f7"; }
+
+.fa-creative-commons-zero:before {
+ content: "\f4f3"; }
+
+.fa-hips:before {
+ content: "\f452"; }
+
+.fa-behance:before {
+ content: "\f1b4"; }
+
+.fa-reddit:before {
+ content: "\f1a1"; }
+
+.fa-discord:before {
+ content: "\f392"; }
+
+.fa-chrome:before {
+ content: "\f268"; }
+
+.fa-app-store-ios:before {
+ content: "\f370"; }
+
+.fa-cc-discover:before {
+ content: "\f1f2"; }
+
+.fa-wpbeginner:before {
+ content: "\f297"; }
+
+.fa-confluence:before {
+ content: "\f78d"; }
+
+.fa-mdb:before {
+ content: "\f8ca"; }
+
+.fa-dochub:before {
+ content: "\f394"; }
+
+.fa-accessible-icon:before {
+ content: "\f368"; }
+
+.fa-ebay:before {
+ content: "\f4f4"; }
+
+.fa-amazon:before {
+ content: "\f270"; }
+
+.fa-unsplash:before {
+ content: "\e07c"; }
+
+.fa-yarn:before {
+ content: "\f7e3"; }
+
+.fa-square-steam:before {
+ content: "\f1b7"; }
+
+.fa-steam-square:before {
+ content: "\f1b7"; }
+
+.fa-500px:before {
+ content: "\f26e"; }
+
+.fa-square-vimeo:before {
+ content: "\f194"; }
+
+.fa-vimeo-square:before {
+ content: "\f194"; }
+
+.fa-asymmetrik:before {
+ content: "\f372"; }
+
+.fa-font-awesome:before {
+ content: "\f2b4"; }
+
+.fa-font-awesome-flag:before {
+ content: "\f2b4"; }
+
+.fa-font-awesome-logo-full:before {
+ content: "\f2b4"; }
+
+.fa-gratipay:before {
+ content: "\f184"; }
+
+.fa-apple:before {
+ content: "\f179"; }
+
+.fa-hive:before {
+ content: "\e07f"; }
+
+.fa-gitkraken:before {
+ content: "\f3a6"; }
+
+.fa-keybase:before {
+ content: "\f4f5"; }
+
+.fa-apple-pay:before {
+ content: "\f415"; }
+
+.fa-padlet:before {
+ content: "\e4a0"; }
+
+.fa-amazon-pay:before {
+ content: "\f42c"; }
+
+.fa-square-github:before {
+ content: "\f092"; }
+
+.fa-github-square:before {
+ content: "\f092"; }
+
+.fa-stumbleupon:before {
+ content: "\f1a4"; }
+
+.fa-fedex:before {
+ content: "\f797"; }
+
+.fa-phoenix-framework:before {
+ content: "\f3dc"; }
+
+.fa-shopify:before {
+ content: "\e057"; }
+
+.fa-neos:before {
+ content: "\f612"; }
+
+.fa-hackerrank:before {
+ content: "\f5f7"; }
+
+.fa-researchgate:before {
+ content: "\f4f8"; }
+
+.fa-swift:before {
+ content: "\f8e1"; }
+
+.fa-angular:before {
+ content: "\f420"; }
+
+.fa-speakap:before {
+ content: "\f3f3"; }
+
+.fa-angrycreative:before {
+ content: "\f36e"; }
+
+.fa-y-combinator:before {
+ content: "\f23b"; }
+
+.fa-empire:before {
+ content: "\f1d1"; }
+
+.fa-envira:before {
+ content: "\f299"; }
+
+.fa-square-gitlab:before {
+ content: "\e5ae"; }
+
+.fa-gitlab-square:before {
+ content: "\e5ae"; }
+
+.fa-studiovinari:before {
+ content: "\f3f8"; }
+
+.fa-pied-piper:before {
+ content: "\f2ae"; }
+
+.fa-wordpress:before {
+ content: "\f19a"; }
+
+.fa-product-hunt:before {
+ content: "\f288"; }
+
+.fa-firefox:before {
+ content: "\f269"; }
+
+.fa-linode:before {
+ content: "\f2b8"; }
+
+.fa-goodreads:before {
+ content: "\f3a8"; }
+
+.fa-square-odnoklassniki:before {
+ content: "\f264"; }
+
+.fa-odnoklassniki-square:before {
+ content: "\f264"; }
+
+.fa-jsfiddle:before {
+ content: "\f1cc"; }
+
+.fa-sith:before {
+ content: "\f512"; }
+
+.fa-themeisle:before {
+ content: "\f2b2"; }
+
+.fa-page4:before {
+ content: "\f3d7"; }
+
+.fa-hashnode:before {
+ content: "\e499"; }
+
+.fa-react:before {
+ content: "\f41b"; }
+
+.fa-cc-paypal:before {
+ content: "\f1f4"; }
+
+.fa-squarespace:before {
+ content: "\f5be"; }
+
+.fa-cc-stripe:before {
+ content: "\f1f5"; }
+
+.fa-creative-commons-share:before {
+ content: "\f4f2"; }
+
+.fa-bitcoin:before {
+ content: "\f379"; }
+
+.fa-keycdn:before {
+ content: "\f3ba"; }
+
+.fa-opera:before {
+ content: "\f26a"; }
+
+.fa-itch-io:before {
+ content: "\f83a"; }
+
+.fa-umbraco:before {
+ content: "\f8e8"; }
+
+.fa-galactic-senate:before {
+ content: "\f50d"; }
+
+.fa-ubuntu:before {
+ content: "\f7df"; }
+
+.fa-draft2digital:before {
+ content: "\f396"; }
+
+.fa-stripe:before {
+ content: "\f429"; }
+
+.fa-houzz:before {
+ content: "\f27c"; }
+
+.fa-gg:before {
+ content: "\f260"; }
+
+.fa-dhl:before {
+ content: "\f790"; }
+
+.fa-square-pinterest:before {
+ content: "\f0d3"; }
+
+.fa-pinterest-square:before {
+ content: "\f0d3"; }
+
+.fa-xing:before {
+ content: "\f168"; }
+
+.fa-blackberry:before {
+ content: "\f37b"; }
+
+.fa-creative-commons-pd:before {
+ content: "\f4ec"; }
+
+.fa-playstation:before {
+ content: "\f3df"; }
+
+.fa-quinscape:before {
+ content: "\f459"; }
+
+.fa-less:before {
+ content: "\f41d"; }
+
+.fa-blogger-b:before {
+ content: "\f37d"; }
+
+.fa-opencart:before {
+ content: "\f23d"; }
+
+.fa-vine:before {
+ content: "\f1ca"; }
+
+.fa-paypal:before {
+ content: "\f1ed"; }
+
+.fa-gitlab:before {
+ content: "\f296"; }
+
+.fa-typo3:before {
+ content: "\f42b"; }
+
+.fa-reddit-alien:before {
+ content: "\f281"; }
+
+.fa-yahoo:before {
+ content: "\f19e"; }
+
+.fa-dailymotion:before {
+ content: "\e052"; }
+
+.fa-affiliatetheme:before {
+ content: "\f36b"; }
+
+.fa-pied-piper-pp:before {
+ content: "\f1a7"; }
+
+.fa-bootstrap:before {
+ content: "\f836"; }
+
+.fa-odnoklassniki:before {
+ content: "\f263"; }
+
+.fa-nfc-symbol:before {
+ content: "\e531"; }
+
+.fa-ethereum:before {
+ content: "\f42e"; }
+
+.fa-speaker-deck:before {
+ content: "\f83c"; }
+
+.fa-creative-commons-nc-eu:before {
+ content: "\f4e9"; }
+
+.fa-patreon:before {
+ content: "\f3d9"; }
+
+.fa-avianex:before {
+ content: "\f374"; }
+
+.fa-ello:before {
+ content: "\f5f1"; }
+
+.fa-gofore:before {
+ content: "\f3a7"; }
+
+.fa-bimobject:before {
+ content: "\f378"; }
+
+.fa-facebook-f:before {
+ content: "\f39e"; }
+
+.fa-square-google-plus:before {
+ content: "\f0d4"; }
+
+.fa-google-plus-square:before {
+ content: "\f0d4"; }
+
+.fa-mandalorian:before {
+ content: "\f50f"; }
+
+.fa-first-order-alt:before {
+ content: "\f50a"; }
+
+.fa-osi:before {
+ content: "\f41a"; }
+
+.fa-google-wallet:before {
+ content: "\f1ee"; }
+
+.fa-d-and-d-beyond:before {
+ content: "\f6ca"; }
+
+.fa-periscope:before {
+ content: "\f3da"; }
+
+.fa-fulcrum:before {
+ content: "\f50b"; }
+
+.fa-cloudscale:before {
+ content: "\f383"; }
+
+.fa-forumbee:before {
+ content: "\f211"; }
+
+.fa-mizuni:before {
+ content: "\f3cc"; }
+
+.fa-schlix:before {
+ content: "\f3ea"; }
+
+.fa-square-xing:before {
+ content: "\f169"; }
+
+.fa-xing-square:before {
+ content: "\f169"; }
+
+.fa-bandcamp:before {
+ content: "\f2d5"; }
+
+.fa-wpforms:before {
+ content: "\f298"; }
+
+.fa-cloudversify:before {
+ content: "\f385"; }
+
+.fa-usps:before {
+ content: "\f7e1"; }
+
+.fa-megaport:before {
+ content: "\f5a3"; }
+
+.fa-magento:before {
+ content: "\f3c4"; }
+
+.fa-spotify:before {
+ content: "\f1bc"; }
+
+.fa-optin-monster:before {
+ content: "\f23c"; }
+
+.fa-fly:before {
+ content: "\f417"; }
+
+.fa-aviato:before {
+ content: "\f421"; }
+
+.fa-itunes:before {
+ content: "\f3b4"; }
+
+.fa-cuttlefish:before {
+ content: "\f38c"; }
+
+.fa-blogger:before {
+ content: "\f37c"; }
+
+.fa-flickr:before {
+ content: "\f16e"; }
+
+.fa-viber:before {
+ content: "\f409"; }
+
+.fa-soundcloud:before {
+ content: "\f1be"; }
+
+.fa-digg:before {
+ content: "\f1a6"; }
+
+.fa-tencent-weibo:before {
+ content: "\f1d5"; }
+
+.fa-symfony:before {
+ content: "\f83d"; }
+
+.fa-maxcdn:before {
+ content: "\f136"; }
+
+.fa-etsy:before {
+ content: "\f2d7"; }
+
+.fa-facebook-messenger:before {
+ content: "\f39f"; }
+
+.fa-audible:before {
+ content: "\f373"; }
+
+.fa-think-peaks:before {
+ content: "\f731"; }
+
+.fa-bilibili:before {
+ content: "\e3d9"; }
+
+.fa-erlang:before {
+ content: "\f39d"; }
+
+.fa-cotton-bureau:before {
+ content: "\f89e"; }
+
+.fa-dashcube:before {
+ content: "\f210"; }
+
+.fa-42-group:before {
+ content: "\e080"; }
+
+.fa-innosoft:before {
+ content: "\e080"; }
+
+.fa-stack-exchange:before {
+ content: "\f18d"; }
+
+.fa-elementor:before {
+ content: "\f430"; }
+
+.fa-square-pied-piper:before {
+ content: "\e01e"; }
+
+.fa-pied-piper-square:before {
+ content: "\e01e"; }
+
+.fa-creative-commons-nd:before {
+ content: "\f4eb"; }
+
+.fa-palfed:before {
+ content: "\f3d8"; }
+
+.fa-superpowers:before {
+ content: "\f2dd"; }
+
+.fa-resolving:before {
+ content: "\f3e7"; }
+
+.fa-xbox:before {
+ content: "\f412"; }
+
+.fa-searchengin:before {
+ content: "\f3eb"; }
+
+.fa-tiktok:before {
+ content: "\e07b"; }
+
+.fa-square-facebook:before {
+ content: "\f082"; }
+
+.fa-facebook-square:before {
+ content: "\f082"; }
+
+.fa-renren:before {
+ content: "\f18b"; }
+
+.fa-linux:before {
+ content: "\f17c"; }
+
+.fa-glide:before {
+ content: "\f2a5"; }
+
+.fa-linkedin:before {
+ content: "\f08c"; }
+
+.fa-hubspot:before {
+ content: "\f3b2"; }
+
+.fa-deploydog:before {
+ content: "\f38e"; }
+
+.fa-twitch:before {
+ content: "\f1e8"; }
+
+.fa-ravelry:before {
+ content: "\f2d9"; }
+
+.fa-mixer:before {
+ content: "\e056"; }
+
+.fa-square-lastfm:before {
+ content: "\f203"; }
+
+.fa-lastfm-square:before {
+ content: "\f203"; }
+
+.fa-vimeo:before {
+ content: "\f40a"; }
+
+.fa-mendeley:before {
+ content: "\f7b3"; }
+
+.fa-uniregistry:before {
+ content: "\f404"; }
+
+.fa-figma:before {
+ content: "\f799"; }
+
+.fa-creative-commons-remix:before {
+ content: "\f4ee"; }
+
+.fa-cc-amazon-pay:before {
+ content: "\f42d"; }
+
+.fa-dropbox:before {
+ content: "\f16b"; }
+
+.fa-instagram:before {
+ content: "\f16d"; }
+
+.fa-cmplid:before {
+ content: "\e360"; }
+
+.fa-facebook:before {
+ content: "\f09a"; }
+
+.fa-gripfire:before {
+ content: "\f3ac"; }
+
+.fa-jedi-order:before {
+ content: "\f50e"; }
+
+.fa-uikit:before {
+ content: "\f403"; }
+
+.fa-fort-awesome-alt:before {
+ content: "\f3a3"; }
+
+.fa-phabricator:before {
+ content: "\f3db"; }
+
+.fa-ussunnah:before {
+ content: "\f407"; }
+
+.fa-earlybirds:before {
+ content: "\f39a"; }
+
+.fa-trade-federation:before {
+ content: "\f513"; }
+
+.fa-autoprefixer:before {
+ content: "\f41c"; }
+
+.fa-whatsapp:before {
+ content: "\f232"; }
+
+.fa-slideshare:before {
+ content: "\f1e7"; }
+
+.fa-google-play:before {
+ content: "\f3ab"; }
+
+.fa-viadeo:before {
+ content: "\f2a9"; }
+
+.fa-line:before {
+ content: "\f3c0"; }
+
+.fa-google-drive:before {
+ content: "\f3aa"; }
+
+.fa-servicestack:before {
+ content: "\f3ec"; }
+
+.fa-simplybuilt:before {
+ content: "\f215"; }
+
+.fa-bitbucket:before {
+ content: "\f171"; }
+
+.fa-imdb:before {
+ content: "\f2d8"; }
+
+.fa-deezer:before {
+ content: "\e077"; }
+
+.fa-raspberry-pi:before {
+ content: "\f7bb"; }
+
+.fa-jira:before {
+ content: "\f7b1"; }
+
+.fa-docker:before {
+ content: "\f395"; }
+
+.fa-screenpal:before {
+ content: "\e570"; }
+
+.fa-bluetooth:before {
+ content: "\f293"; }
+
+.fa-gitter:before {
+ content: "\f426"; }
+
+.fa-d-and-d:before {
+ content: "\f38d"; }
+
+.fa-microblog:before {
+ content: "\e01a"; }
+
+.fa-cc-diners-club:before {
+ content: "\f24c"; }
+
+.fa-gg-circle:before {
+ content: "\f261"; }
+
+.fa-pied-piper-hat:before {
+ content: "\f4e5"; }
+
+.fa-kickstarter-k:before {
+ content: "\f3bc"; }
+
+.fa-yandex:before {
+ content: "\f413"; }
+
+.fa-readme:before {
+ content: "\f4d5"; }
+
+.fa-html5:before {
+ content: "\f13b"; }
+
+.fa-sellsy:before {
+ content: "\f213"; }
+
+.fa-sass:before {
+ content: "\f41e"; }
+
+.fa-wirsindhandwerk:before {
+ content: "\e2d0"; }
+
+.fa-wsh:before {
+ content: "\e2d0"; }
+
+.fa-buromobelexperte:before {
+ content: "\f37f"; }
+
+.fa-salesforce:before {
+ content: "\f83b"; }
+
+.fa-octopus-deploy:before {
+ content: "\e082"; }
+
+.fa-medapps:before {
+ content: "\f3c6"; }
+
+.fa-ns8:before {
+ content: "\f3d5"; }
+
+.fa-pinterest-p:before {
+ content: "\f231"; }
+
+.fa-apper:before {
+ content: "\f371"; }
+
+.fa-fort-awesome:before {
+ content: "\f286"; }
+
+.fa-waze:before {
+ content: "\f83f"; }
+
+.fa-cc-jcb:before {
+ content: "\f24b"; }
+
+.fa-snapchat:before {
+ content: "\f2ab"; }
+
+.fa-snapchat-ghost:before {
+ content: "\f2ab"; }
+
+.fa-fantasy-flight-games:before {
+ content: "\f6dc"; }
+
+.fa-rust:before {
+ content: "\e07a"; }
+
+.fa-wix:before {
+ content: "\f5cf"; }
+
+.fa-square-behance:before {
+ content: "\f1b5"; }
+
+.fa-behance-square:before {
+ content: "\f1b5"; }
+
+.fa-supple:before {
+ content: "\f3f9"; }
+
+.fa-rebel:before {
+ content: "\f1d0"; }
+
+.fa-css3:before {
+ content: "\f13c"; }
+
+.fa-staylinked:before {
+ content: "\f3f5"; }
+
+.fa-kaggle:before {
+ content: "\f5fa"; }
+
+.fa-space-awesome:before {
+ content: "\e5ac"; }
+
+.fa-deviantart:before {
+ content: "\f1bd"; }
+
+.fa-cpanel:before {
+ content: "\f388"; }
+
+.fa-goodreads-g:before {
+ content: "\f3a9"; }
+
+.fa-square-git:before {
+ content: "\f1d2"; }
+
+.fa-git-square:before {
+ content: "\f1d2"; }
+
+.fa-square-tumblr:before {
+ content: "\f174"; }
+
+.fa-tumblr-square:before {
+ content: "\f174"; }
+
+.fa-trello:before {
+ content: "\f181"; }
+
+.fa-creative-commons-nc-jp:before {
+ content: "\f4ea"; }
+
+.fa-get-pocket:before {
+ content: "\f265"; }
+
+.fa-perbyte:before {
+ content: "\e083"; }
+
+.fa-grunt:before {
+ content: "\f3ad"; }
+
+.fa-weebly:before {
+ content: "\f5cc"; }
+
+.fa-connectdevelop:before {
+ content: "\f20e"; }
+
+.fa-leanpub:before {
+ content: "\f212"; }
+
+.fa-black-tie:before {
+ content: "\f27e"; }
+
+.fa-themeco:before {
+ content: "\f5c6"; }
+
+.fa-python:before {
+ content: "\f3e2"; }
+
+.fa-android:before {
+ content: "\f17b"; }
+
+.fa-bots:before {
+ content: "\e340"; }
+
+.fa-free-code-camp:before {
+ content: "\f2c5"; }
+
+.fa-hornbill:before {
+ content: "\f592"; }
+
+.fa-js:before {
+ content: "\f3b8"; }
+
+.fa-ideal:before {
+ content: "\e013"; }
+
+.fa-git:before {
+ content: "\f1d3"; }
+
+.fa-dev:before {
+ content: "\f6cc"; }
+
+.fa-sketch:before {
+ content: "\f7c6"; }
+
+.fa-yandex-international:before {
+ content: "\f414"; }
+
+.fa-cc-amex:before {
+ content: "\f1f3"; }
+
+.fa-uber:before {
+ content: "\f402"; }
+
+.fa-github:before {
+ content: "\f09b"; }
+
+.fa-php:before {
+ content: "\f457"; }
+
+.fa-alipay:before {
+ content: "\f642"; }
+
+.fa-youtube:before {
+ content: "\f167"; }
+
+.fa-skyatlas:before {
+ content: "\f216"; }
+
+.fa-firefox-browser:before {
+ content: "\e007"; }
+
+.fa-replyd:before {
+ content: "\f3e6"; }
+
+.fa-suse:before {
+ content: "\f7d6"; }
+
+.fa-jenkins:before {
+ content: "\f3b6"; }
+
+.fa-twitter:before {
+ content: "\f099"; }
+
+.fa-rockrms:before {
+ content: "\f3e9"; }
+
+.fa-pinterest:before {
+ content: "\f0d2"; }
+
+.fa-buffer:before {
+ content: "\f837"; }
+
+.fa-npm:before {
+ content: "\f3d4"; }
+
+.fa-yammer:before {
+ content: "\f840"; }
+
+.fa-btc:before {
+ content: "\f15a"; }
+
+.fa-dribbble:before {
+ content: "\f17d"; }
+
+.fa-stumbleupon-circle:before {
+ content: "\f1a3"; }
+
+.fa-internet-explorer:before {
+ content: "\f26b"; }
+
+.fa-stubber:before {
+ content: "\e5c7"; }
+
+.fa-telegram:before {
+ content: "\f2c6"; }
+
+.fa-telegram-plane:before {
+ content: "\f2c6"; }
+
+.fa-old-republic:before {
+ content: "\f510"; }
+
+.fa-odysee:before {
+ content: "\e5c6"; }
+
+.fa-square-whatsapp:before {
+ content: "\f40c"; }
+
+.fa-whatsapp-square:before {
+ content: "\f40c"; }
+
+.fa-node-js:before {
+ content: "\f3d3"; }
+
+.fa-edge-legacy:before {
+ content: "\e078"; }
+
+.fa-slack:before {
+ content: "\f198"; }
+
+.fa-slack-hash:before {
+ content: "\f198"; }
+
+.fa-medrt:before {
+ content: "\f3c8"; }
+
+.fa-usb:before {
+ content: "\f287"; }
+
+.fa-tumblr:before {
+ content: "\f173"; }
+
+.fa-vaadin:before {
+ content: "\f408"; }
+
+.fa-quora:before {
+ content: "\f2c4"; }
+
+.fa-reacteurope:before {
+ content: "\f75d"; }
+
+.fa-medium:before {
+ content: "\f23a"; }
+
+.fa-medium-m:before {
+ content: "\f23a"; }
+
+.fa-amilia:before {
+ content: "\f36d"; }
+
+.fa-mixcloud:before {
+ content: "\f289"; }
+
+.fa-flipboard:before {
+ content: "\f44d"; }
+
+.fa-viacoin:before {
+ content: "\f237"; }
+
+.fa-critical-role:before {
+ content: "\f6c9"; }
+
+.fa-sitrox:before {
+ content: "\e44a"; }
+
+.fa-discourse:before {
+ content: "\f393"; }
+
+.fa-joomla:before {
+ content: "\f1aa"; }
+
+.fa-mastodon:before {
+ content: "\f4f6"; }
+
+.fa-airbnb:before {
+ content: "\f834"; }
+
+.fa-wolf-pack-battalion:before {
+ content: "\f514"; }
+
+.fa-buy-n-large:before {
+ content: "\f8a6"; }
+
+.fa-gulp:before {
+ content: "\f3ae"; }
+
+.fa-creative-commons-sampling-plus:before {
+ content: "\f4f1"; }
+
+.fa-strava:before {
+ content: "\f428"; }
+
+.fa-ember:before {
+ content: "\f423"; }
+
+.fa-canadian-maple-leaf:before {
+ content: "\f785"; }
+
+.fa-teamspeak:before {
+ content: "\f4f9"; }
+
+.fa-pushed:before {
+ content: "\f3e1"; }
+
+.fa-wordpress-simple:before {
+ content: "\f411"; }
+
+.fa-nutritionix:before {
+ content: "\f3d6"; }
+
+.fa-wodu:before {
+ content: "\e088"; }
+
+.fa-google-pay:before {
+ content: "\e079"; }
+
+.fa-intercom:before {
+ content: "\f7af"; }
+
+.fa-zhihu:before {
+ content: "\f63f"; }
+
+.fa-korvue:before {
+ content: "\f42f"; }
+
+.fa-pix:before {
+ content: "\e43a"; }
+
+.fa-steam-symbol:before {
+ content: "\f3f6"; }
+:root, :host {
+ --fa-style-family-classic: 'Font Awesome 6 Free';
+ --fa-font-regular: normal 400 1em/1 'Font Awesome 6 Free'; }
+
+@font-face {
+ font-family: 'Font Awesome 6 Free';
+ font-style: normal;
+ font-weight: 400;
+ font-display: block;
+ src: url("../webfonts/fa-regular-400.woff2") format("woff2"), url("../webfonts/fa-regular-400.ttf") format("truetype"); }
+
+.far,
+.fa-regular {
+ font-weight: 400; }
+:root, :host {
+ --fa-style-family-classic: 'Font Awesome 6 Free';
+ --fa-font-solid: normal 900 1em/1 'Font Awesome 6 Free'; }
+
+@font-face {
+ font-family: 'Font Awesome 6 Free';
+ font-style: normal;
+ font-weight: 900;
+ font-display: block;
+ src: url("../webfonts/fa-solid-900.woff2") format("woff2"), url("../webfonts/fa-solid-900.ttf") format("truetype"); }
+
+.fas,
+.fa-solid {
+ font-weight: 900; }
+@font-face {
+ font-family: 'Font Awesome 5 Brands';
+ font-display: block;
+ font-weight: 400;
+ src: url("../webfonts/fa-brands-400.woff2") format("woff2"), url("../webfonts/fa-brands-400.ttf") format("truetype"); }
+
+@font-face {
+ font-family: 'Font Awesome 5 Free';
+ font-display: block;
+ font-weight: 900;
+ src: url("../webfonts/fa-solid-900.woff2") format("woff2"), url("../webfonts/fa-solid-900.ttf") format("truetype"); }
+
+@font-face {
+ font-family: 'Font Awesome 5 Free';
+ font-display: block;
+ font-weight: 400;
+ src: url("../webfonts/fa-regular-400.woff2") format("woff2"), url("../webfonts/fa-regular-400.ttf") format("truetype"); }
+@font-face {
+ font-family: 'FontAwesome';
+ font-display: block;
+ src: url("../webfonts/fa-solid-900.woff2") format("woff2"), url("../webfonts/fa-solid-900.ttf") format("truetype"); }
+
+@font-face {
+ font-family: 'FontAwesome';
+ font-display: block;
+ src: url("../webfonts/fa-brands-400.woff2") format("woff2"), url("../webfonts/fa-brands-400.ttf") format("truetype"); }
+
+@font-face {
+ font-family: 'FontAwesome';
+ font-display: block;
+ src: url("../webfonts/fa-regular-400.woff2") format("woff2"), url("../webfonts/fa-regular-400.ttf") format("truetype");
+ unicode-range: U+F003,U+F006,U+F014,U+F016-F017,U+F01A-F01B,U+F01D,U+F022,U+F03E,U+F044,U+F046,U+F05C-F05D,U+F06E,U+F070,U+F087-F088,U+F08A,U+F094,U+F096-F097,U+F09D,U+F0A0,U+F0A2,U+F0A4-F0A7,U+F0C5,U+F0C7,U+F0E5-F0E6,U+F0EB,U+F0F6-F0F8,U+F10C,U+F114-F115,U+F118-F11A,U+F11C-F11D,U+F133,U+F147,U+F14E,U+F150-F152,U+F185-F186,U+F18E,U+F190-F192,U+F196,U+F1C1-F1C9,U+F1D9,U+F1DB,U+F1E3,U+F1EA,U+F1F7,U+F1F9,U+F20A,U+F247-F248,U+F24A,U+F24D,U+F255-F25B,U+F25D,U+F271-F274,U+F278,U+F27B,U+F28C,U+F28E,U+F29C,U+F2B5,U+F2B7,U+F2BA,U+F2BC,U+F2BE,U+F2C0-F2C1,U+F2C3,U+F2D0,U+F2D2,U+F2D4,U+F2DC; }
+
+@font-face {
+ font-family: 'FontAwesome';
+ font-display: block;
+ src: url("../webfonts/fa-v4compatibility.woff2") format("woff2"), url("../webfonts/fa-v4compatibility.ttf") format("truetype");
+ unicode-range: U+F041,U+F047,U+F065-F066,U+F07D-F07E,U+F080,U+F08B,U+F08E,U+F090,U+F09A,U+F0AC,U+F0AE,U+F0B2,U+F0D0,U+F0D6,U+F0E4,U+F0EC,U+F10A-F10B,U+F123,U+F13E,U+F148-F149,U+F14C,U+F156,U+F15E,U+F160-F161,U+F163,U+F175-F178,U+F195,U+F1F8,U+F219,U+F27A; }
diff --git a/40-abschlusspraesentation/assets/fontawesome/css/all.min.css b/40-abschlusspraesentation/assets/fontawesome/css/all.min.css
new file mode 100644
index 0000000..1f367c1
--- /dev/null
+++ b/40-abschlusspraesentation/assets/fontawesome/css/all.min.css
@@ -0,0 +1,9 @@
+/*!
+ * Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com
+ * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
+ * Copyright 2023 Fonticons, Inc.
+ */
+.fa{font-family:var(--fa-style-family,"Font Awesome 6 Free");font-weight:var(--fa-style,900)}.fa,.fa-brands,.fa-classic,.fa-regular,.fa-sharp,.fa-solid,.fab,.far,.fas{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;display:var(--fa-display,inline-block);font-style:normal;font-variant:normal;line-height:1;text-rendering:auto}.fa-classic,.fa-regular,.fa-solid,.far,.fas{font-family:"Font Awesome 6 Free"}.fa-brands,.fab{font-family:"Font Awesome 6 Brands"}.fa-1x{font-size:1em}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-6x{font-size:6em}.fa-7x{font-size:7em}.fa-8x{font-size:8em}.fa-9x{font-size:9em}.fa-10x{font-size:10em}.fa-2xs{font-size:.625em;line-height:.1em;vertical-align:.225em}.fa-xs{font-size:.75em;line-height:.08333em;vertical-align:.125em}.fa-sm{font-size:.875em;line-height:.07143em;vertical-align:.05357em}.fa-lg{font-size:1.25em;line-height:.05em;vertical-align:-.075em}.fa-xl{font-size:1.5em;line-height:.04167em;vertical-align:-.125em}.fa-2xl{font-size:2em;line-height:.03125em;vertical-align:-.1875em}.fa-fw{text-align:center;width:1.25em}.fa-ul{list-style-type:none;margin-left:var(--fa-li-margin,2.5em);padding-left:0}.fa-ul>li{position:relative}.fa-li{left:calc(var(--fa-li-width, 2em)*-1);position:absolute;text-align:center;width:var(--fa-li-width,2em);line-height:inherit}.fa-border{border-radius:var(--fa-border-radius,.1em);border:var(--fa-border-width,.08em) var(--fa-border-style,solid) var(--fa-border-color,#eee);padding:var(--fa-border-padding,.2em .25em .15em)}.fa-pull-left{float:left;margin-right:var(--fa-pull-margin,.3em)}.fa-pull-right{float:right;margin-left:var(--fa-pull-margin,.3em)}.fa-beat{-webkit-animation-name:fa-beat;animation-name:fa-beat;-webkit-animation-delay:var(--fa-animation-delay,0s);animation-delay:var(--fa-animation-delay,0s);-webkit-animation-direction:var(--fa-animation-direction,normal);animation-direction:var(--fa-animation-direction,normal);-webkit-animation-duration:var(--fa-animation-duration,1s);animation-duration:var(--fa-animation-duration,1s);-webkit-animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-iteration-count:var(--fa-animation-iteration-count,infinite);-webkit-animation-timing-function:var(--fa-animation-timing,ease-in-out);animation-timing-function:var(--fa-animation-timing,ease-in-out)}.fa-bounce{-webkit-animation-name:fa-bounce;animation-name:fa-bounce;-webkit-animation-delay:var(--fa-animation-delay,0s);animation-delay:var(--fa-animation-delay,0s);-webkit-animation-direction:var(--fa-animation-direction,normal);animation-direction:var(--fa-animation-direction,normal);-webkit-animation-duration:var(--fa-animation-duration,1s);animation-duration:var(--fa-animation-duration,1s);-webkit-animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-iteration-count:var(--fa-animation-iteration-count,infinite);-webkit-animation-timing-function:var(--fa-animation-timing,cubic-bezier(.28,.84,.42,1));animation-timing-function:var(--fa-animation-timing,cubic-bezier(.28,.84,.42,1))}.fa-fade{-webkit-animation-name:fa-fade;animation-name:fa-fade;-webkit-animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-iteration-count:var(--fa-animation-iteration-count,infinite);-webkit-animation-timing-function:var(--fa-animation-timing,cubic-bezier(.4,0,.6,1));animation-timing-function:var(--fa-animation-timing,cubic-bezier(.4,0,.6,1))}.fa-beat-fade,.fa-fade{-webkit-animation-delay:var(--fa-animation-delay,0s);animation-delay:var(--fa-animation-delay,0s);-webkit-animation-direction:var(--fa-animation-direction,normal);animation-direction:var(--fa-animation-direction,normal);-webkit-animation-duration:var(--fa-animation-duration,1s);animation-duration:var(--fa-animation-duration,1s)}.fa-beat-fade{-webkit-animation-name:fa-beat-fade;animation-name:fa-beat-fade;-webkit-animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-iteration-count:var(--fa-animation-iteration-count,infinite);-webkit-animation-timing-function:var(--fa-animation-timing,cubic-bezier(.4,0,.6,1));animation-timing-function:var(--fa-animation-timing,cubic-bezier(.4,0,.6,1))}.fa-flip{-webkit-animation-name:fa-flip;animation-name:fa-flip;-webkit-animation-delay:var(--fa-animation-delay,0s);animation-delay:var(--fa-animation-delay,0s);-webkit-animation-direction:var(--fa-animation-direction,normal);animation-direction:var(--fa-animation-direction,normal);-webkit-animation-duration:var(--fa-animation-duration,1s);animation-duration:var(--fa-animation-duration,1s);-webkit-animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-iteration-count:var(--fa-animation-iteration-count,infinite);-webkit-animation-timing-function:var(--fa-animation-timing,ease-in-out);animation-timing-function:var(--fa-animation-timing,ease-in-out)}.fa-shake{-webkit-animation-name:fa-shake;animation-name:fa-shake;-webkit-animation-duration:var(--fa-animation-duration,1s);animation-duration:var(--fa-animation-duration,1s);-webkit-animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-iteration-count:var(--fa-animation-iteration-count,infinite);-webkit-animation-timing-function:var(--fa-animation-timing,linear);animation-timing-function:var(--fa-animation-timing,linear)}.fa-shake,.fa-spin{-webkit-animation-delay:var(--fa-animation-delay,0s);animation-delay:var(--fa-animation-delay,0s);-webkit-animation-direction:var(--fa-animation-direction,normal);animation-direction:var(--fa-animation-direction,normal)}.fa-spin{-webkit-animation-name:fa-spin;animation-name:fa-spin;-webkit-animation-duration:var(--fa-animation-duration,2s);animation-duration:var(--fa-animation-duration,2s);-webkit-animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-iteration-count:var(--fa-animation-iteration-count,infinite);-webkit-animation-timing-function:var(--fa-animation-timing,linear);animation-timing-function:var(--fa-animation-timing,linear)}.fa-spin-reverse{--fa-animation-direction:reverse}.fa-pulse,.fa-spin-pulse{-webkit-animation-name:fa-spin;animation-name:fa-spin;-webkit-animation-direction:var(--fa-animation-direction,normal);animation-direction:var(--fa-animation-direction,normal);-webkit-animation-duration:var(--fa-animation-duration,1s);animation-duration:var(--fa-animation-duration,1s);-webkit-animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-iteration-count:var(--fa-animation-iteration-count,infinite);-webkit-animation-timing-function:var(--fa-animation-timing,steps(8));animation-timing-function:var(--fa-animation-timing,steps(8))}@media (prefers-reduced-motion:reduce){.fa-beat,.fa-beat-fade,.fa-bounce,.fa-fade,.fa-flip,.fa-pulse,.fa-shake,.fa-spin,.fa-spin-pulse{-webkit-animation-delay:-1ms;animation-delay:-1ms;-webkit-animation-duration:1ms;animation-duration:1ms;-webkit-animation-iteration-count:1;animation-iteration-count:1;-webkit-transition-delay:0s;transition-delay:0s;-webkit-transition-duration:0s;transition-duration:0s}}@-webkit-keyframes fa-beat{0%,90%{-webkit-transform:scale(1);transform:scale(1)}45%{-webkit-transform:scale(var(--fa-beat-scale,1.25));transform:scale(var(--fa-beat-scale,1.25))}}@keyframes fa-beat{0%,90%{-webkit-transform:scale(1);transform:scale(1)}45%{-webkit-transform:scale(var(--fa-beat-scale,1.25));transform:scale(var(--fa-beat-scale,1.25))}}@-webkit-keyframes fa-bounce{0%{-webkit-transform:scale(1) translateY(0);transform:scale(1) translateY(0)}10%{-webkit-transform:scale(var(--fa-bounce-start-scale-x,1.1),var(--fa-bounce-start-scale-y,.9)) translateY(0);transform:scale(var(--fa-bounce-start-scale-x,1.1),var(--fa-bounce-start-scale-y,.9)) translateY(0)}30%{-webkit-transform:scale(var(--fa-bounce-jump-scale-x,.9),var(--fa-bounce-jump-scale-y,1.1)) translateY(var(--fa-bounce-height,-.5em));transform:scale(var(--fa-bounce-jump-scale-x,.9),var(--fa-bounce-jump-scale-y,1.1)) translateY(var(--fa-bounce-height,-.5em))}50%{-webkit-transform:scale(var(--fa-bounce-land-scale-x,1.05),var(--fa-bounce-land-scale-y,.95)) translateY(0);transform:scale(var(--fa-bounce-land-scale-x,1.05),var(--fa-bounce-land-scale-y,.95)) translateY(0)}57%{-webkit-transform:scale(1) translateY(var(--fa-bounce-rebound,-.125em));transform:scale(1) translateY(var(--fa-bounce-rebound,-.125em))}64%{-webkit-transform:scale(1) translateY(0);transform:scale(1) translateY(0)}to{-webkit-transform:scale(1) translateY(0);transform:scale(1) translateY(0)}}@keyframes fa-bounce{0%{-webkit-transform:scale(1) translateY(0);transform:scale(1) translateY(0)}10%{-webkit-transform:scale(var(--fa-bounce-start-scale-x,1.1),var(--fa-bounce-start-scale-y,.9)) translateY(0);transform:scale(var(--fa-bounce-start-scale-x,1.1),var(--fa-bounce-start-scale-y,.9)) translateY(0)}30%{-webkit-transform:scale(var(--fa-bounce-jump-scale-x,.9),var(--fa-bounce-jump-scale-y,1.1)) translateY(var(--fa-bounce-height,-.5em));transform:scale(var(--fa-bounce-jump-scale-x,.9),var(--fa-bounce-jump-scale-y,1.1)) translateY(var(--fa-bounce-height,-.5em))}50%{-webkit-transform:scale(var(--fa-bounce-land-scale-x,1.05),var(--fa-bounce-land-scale-y,.95)) translateY(0);transform:scale(var(--fa-bounce-land-scale-x,1.05),var(--fa-bounce-land-scale-y,.95)) translateY(0)}57%{-webkit-transform:scale(1) translateY(var(--fa-bounce-rebound,-.125em));transform:scale(1) translateY(var(--fa-bounce-rebound,-.125em))}64%{-webkit-transform:scale(1) translateY(0);transform:scale(1) translateY(0)}to{-webkit-transform:scale(1) translateY(0);transform:scale(1) translateY(0)}}@-webkit-keyframes fa-fade{50%{opacity:var(--fa-fade-opacity,.4)}}@keyframes fa-fade{50%{opacity:var(--fa-fade-opacity,.4)}}@-webkit-keyframes fa-beat-fade{0%,to{opacity:var(--fa-beat-fade-opacity,.4);-webkit-transform:scale(1);transform:scale(1)}50%{opacity:1;-webkit-transform:scale(var(--fa-beat-fade-scale,1.125));transform:scale(var(--fa-beat-fade-scale,1.125))}}@keyframes fa-beat-fade{0%,to{opacity:var(--fa-beat-fade-opacity,.4);-webkit-transform:scale(1);transform:scale(1)}50%{opacity:1;-webkit-transform:scale(var(--fa-beat-fade-scale,1.125));transform:scale(var(--fa-beat-fade-scale,1.125))}}@-webkit-keyframes fa-flip{50%{-webkit-transform:rotate3d(var(--fa-flip-x,0),var(--fa-flip-y,1),var(--fa-flip-z,0),var(--fa-flip-angle,-180deg));transform:rotate3d(var(--fa-flip-x,0),var(--fa-flip-y,1),var(--fa-flip-z,0),var(--fa-flip-angle,-180deg))}}@keyframes fa-flip{50%{-webkit-transform:rotate3d(var(--fa-flip-x,0),var(--fa-flip-y,1),var(--fa-flip-z,0),var(--fa-flip-angle,-180deg));transform:rotate3d(var(--fa-flip-x,0),var(--fa-flip-y,1),var(--fa-flip-z,0),var(--fa-flip-angle,-180deg))}}@-webkit-keyframes fa-shake{0%{-webkit-transform:rotate(-15deg);transform:rotate(-15deg)}4%{-webkit-transform:rotate(15deg);transform:rotate(15deg)}8%,24%{-webkit-transform:rotate(-18deg);transform:rotate(-18deg)}12%,28%{-webkit-transform:rotate(18deg);transform:rotate(18deg)}16%{-webkit-transform:rotate(-22deg);transform:rotate(-22deg)}20%{-webkit-transform:rotate(22deg);transform:rotate(22deg)}32%{-webkit-transform:rotate(-12deg);transform:rotate(-12deg)}36%{-webkit-transform:rotate(12deg);transform:rotate(12deg)}40%,to{-webkit-transform:rotate(0deg);transform:rotate(0deg)}}@keyframes fa-shake{0%{-webkit-transform:rotate(-15deg);transform:rotate(-15deg)}4%{-webkit-transform:rotate(15deg);transform:rotate(15deg)}8%,24%{-webkit-transform:rotate(-18deg);transform:rotate(-18deg)}12%,28%{-webkit-transform:rotate(18deg);transform:rotate(18deg)}16%{-webkit-transform:rotate(-22deg);transform:rotate(-22deg)}20%{-webkit-transform:rotate(22deg);transform:rotate(22deg)}32%{-webkit-transform:rotate(-12deg);transform:rotate(-12deg)}36%{-webkit-transform:rotate(12deg);transform:rotate(12deg)}40%,to{-webkit-transform:rotate(0deg);transform:rotate(0deg)}}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}.fa-rotate-90{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-webkit-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-webkit-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-webkit-transform:scaleX(-1);transform:scaleX(-1)}.fa-flip-vertical{-webkit-transform:scaleY(-1);transform:scaleY(-1)}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical{-webkit-transform:scale(-1);transform:scale(-1)}.fa-rotate-by{-webkit-transform:rotate(var(--fa-rotate-angle,none));transform:rotate(var(--fa-rotate-angle,none))}.fa-stack{display:inline-block;height:2em;line-height:2em;position:relative;vertical-align:middle;width:2.5em}.fa-stack-1x,.fa-stack-2x{left:0;position:absolute;text-align:center;width:100%;z-index:var(--fa-stack-z-index,auto)}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:var(--fa-inverse,#fff)}
+
+.fa-0:before{content:"\30"}.fa-1:before{content:"\31"}.fa-2:before{content:"\32"}.fa-3:before{content:"\33"}.fa-4:before{content:"\34"}.fa-5:before{content:"\35"}.fa-6:before{content:"\36"}.fa-7:before{content:"\37"}.fa-8:before{content:"\38"}.fa-9:before{content:"\39"}.fa-fill-drip:before{content:"\f576"}.fa-arrows-to-circle:before{content:"\e4bd"}.fa-chevron-circle-right:before,.fa-circle-chevron-right:before{content:"\f138"}.fa-at:before{content:"\40"}.fa-trash-alt:before,.fa-trash-can:before{content:"\f2ed"}.fa-text-height:before{content:"\f034"}.fa-user-times:before,.fa-user-xmark:before{content:"\f235"}.fa-stethoscope:before{content:"\f0f1"}.fa-comment-alt:before,.fa-message:before{content:"\f27a"}.fa-info:before{content:"\f129"}.fa-compress-alt:before,.fa-down-left-and-up-right-to-center:before{content:"\f422"}.fa-explosion:before{content:"\e4e9"}.fa-file-alt:before,.fa-file-lines:before,.fa-file-text:before{content:"\f15c"}.fa-wave-square:before{content:"\f83e"}.fa-ring:before{content:"\f70b"}.fa-building-un:before{content:"\e4d9"}.fa-dice-three:before{content:"\f527"}.fa-calendar-alt:before,.fa-calendar-days:before{content:"\f073"}.fa-anchor-circle-check:before{content:"\e4aa"}.fa-building-circle-arrow-right:before{content:"\e4d1"}.fa-volleyball-ball:before,.fa-volleyball:before{content:"\f45f"}.fa-arrows-up-to-line:before{content:"\e4c2"}.fa-sort-desc:before,.fa-sort-down:before{content:"\f0dd"}.fa-circle-minus:before,.fa-minus-circle:before{content:"\f056"}.fa-door-open:before{content:"\f52b"}.fa-right-from-bracket:before,.fa-sign-out-alt:before{content:"\f2f5"}.fa-atom:before{content:"\f5d2"}.fa-soap:before{content:"\e06e"}.fa-heart-music-camera-bolt:before,.fa-icons:before{content:"\f86d"}.fa-microphone-alt-slash:before,.fa-microphone-lines-slash:before{content:"\f539"}.fa-bridge-circle-check:before{content:"\e4c9"}.fa-pump-medical:before{content:"\e06a"}.fa-fingerprint:before{content:"\f577"}.fa-hand-point-right:before{content:"\f0a4"}.fa-magnifying-glass-location:before,.fa-search-location:before{content:"\f689"}.fa-forward-step:before,.fa-step-forward:before{content:"\f051"}.fa-face-smile-beam:before,.fa-smile-beam:before{content:"\f5b8"}.fa-flag-checkered:before{content:"\f11e"}.fa-football-ball:before,.fa-football:before{content:"\f44e"}.fa-school-circle-exclamation:before{content:"\e56c"}.fa-crop:before{content:"\f125"}.fa-angle-double-down:before,.fa-angles-down:before{content:"\f103"}.fa-users-rectangle:before{content:"\e594"}.fa-people-roof:before{content:"\e537"}.fa-people-line:before{content:"\e534"}.fa-beer-mug-empty:before,.fa-beer:before{content:"\f0fc"}.fa-diagram-predecessor:before{content:"\e477"}.fa-arrow-up-long:before,.fa-long-arrow-up:before{content:"\f176"}.fa-burn:before,.fa-fire-flame-simple:before{content:"\f46a"}.fa-male:before,.fa-person:before{content:"\f183"}.fa-laptop:before{content:"\f109"}.fa-file-csv:before{content:"\f6dd"}.fa-menorah:before{content:"\f676"}.fa-truck-plane:before{content:"\e58f"}.fa-record-vinyl:before{content:"\f8d9"}.fa-face-grin-stars:before,.fa-grin-stars:before{content:"\f587"}.fa-bong:before{content:"\f55c"}.fa-pastafarianism:before,.fa-spaghetti-monster-flying:before{content:"\f67b"}.fa-arrow-down-up-across-line:before{content:"\e4af"}.fa-spoon:before,.fa-utensil-spoon:before{content:"\f2e5"}.fa-jar-wheat:before{content:"\e517"}.fa-envelopes-bulk:before,.fa-mail-bulk:before{content:"\f674"}.fa-file-circle-exclamation:before{content:"\e4eb"}.fa-circle-h:before,.fa-hospital-symbol:before{content:"\f47e"}.fa-pager:before{content:"\f815"}.fa-address-book:before,.fa-contact-book:before{content:"\f2b9"}.fa-strikethrough:before{content:"\f0cc"}.fa-k:before{content:"\4b"}.fa-landmark-flag:before{content:"\e51c"}.fa-pencil-alt:before,.fa-pencil:before{content:"\f303"}.fa-backward:before{content:"\f04a"}.fa-caret-right:before{content:"\f0da"}.fa-comments:before{content:"\f086"}.fa-file-clipboard:before,.fa-paste:before{content:"\f0ea"}.fa-code-pull-request:before{content:"\e13c"}.fa-clipboard-list:before{content:"\f46d"}.fa-truck-loading:before,.fa-truck-ramp-box:before{content:"\f4de"}.fa-user-check:before{content:"\f4fc"}.fa-vial-virus:before{content:"\e597"}.fa-sheet-plastic:before{content:"\e571"}.fa-blog:before{content:"\f781"}.fa-user-ninja:before{content:"\f504"}.fa-person-arrow-up-from-line:before{content:"\e539"}.fa-scroll-torah:before,.fa-torah:before{content:"\f6a0"}.fa-broom-ball:before,.fa-quidditch-broom-ball:before,.fa-quidditch:before{content:"\f458"}.fa-toggle-off:before{content:"\f204"}.fa-archive:before,.fa-box-archive:before{content:"\f187"}.fa-person-drowning:before{content:"\e545"}.fa-arrow-down-9-1:before,.fa-sort-numeric-desc:before,.fa-sort-numeric-down-alt:before{content:"\f886"}.fa-face-grin-tongue-squint:before,.fa-grin-tongue-squint:before{content:"\f58a"}.fa-spray-can:before{content:"\f5bd"}.fa-truck-monster:before{content:"\f63b"}.fa-w:before{content:"\57"}.fa-earth-africa:before,.fa-globe-africa:before{content:"\f57c"}.fa-rainbow:before{content:"\f75b"}.fa-circle-notch:before{content:"\f1ce"}.fa-tablet-alt:before,.fa-tablet-screen-button:before{content:"\f3fa"}.fa-paw:before{content:"\f1b0"}.fa-cloud:before{content:"\f0c2"}.fa-trowel-bricks:before{content:"\e58a"}.fa-face-flushed:before,.fa-flushed:before{content:"\f579"}.fa-hospital-user:before{content:"\f80d"}.fa-tent-arrow-left-right:before{content:"\e57f"}.fa-gavel:before,.fa-legal:before{content:"\f0e3"}.fa-binoculars:before{content:"\f1e5"}.fa-microphone-slash:before{content:"\f131"}.fa-box-tissue:before{content:"\e05b"}.fa-motorcycle:before{content:"\f21c"}.fa-bell-concierge:before,.fa-concierge-bell:before{content:"\f562"}.fa-pen-ruler:before,.fa-pencil-ruler:before{content:"\f5ae"}.fa-people-arrows-left-right:before,.fa-people-arrows:before{content:"\e068"}.fa-mars-and-venus-burst:before{content:"\e523"}.fa-caret-square-right:before,.fa-square-caret-right:before{content:"\f152"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-sun-plant-wilt:before{content:"\e57a"}.fa-toilets-portable:before{content:"\e584"}.fa-hockey-puck:before{content:"\f453"}.fa-table:before{content:"\f0ce"}.fa-magnifying-glass-arrow-right:before{content:"\e521"}.fa-digital-tachograph:before,.fa-tachograph-digital:before{content:"\f566"}.fa-users-slash:before{content:"\e073"}.fa-clover:before{content:"\e139"}.fa-mail-reply:before,.fa-reply:before{content:"\f3e5"}.fa-star-and-crescent:before{content:"\f699"}.fa-house-fire:before{content:"\e50c"}.fa-minus-square:before,.fa-square-minus:before{content:"\f146"}.fa-helicopter:before{content:"\f533"}.fa-compass:before{content:"\f14e"}.fa-caret-square-down:before,.fa-square-caret-down:before{content:"\f150"}.fa-file-circle-question:before{content:"\e4ef"}.fa-laptop-code:before{content:"\f5fc"}.fa-swatchbook:before{content:"\f5c3"}.fa-prescription-bottle:before{content:"\f485"}.fa-bars:before,.fa-navicon:before{content:"\f0c9"}.fa-people-group:before{content:"\e533"}.fa-hourglass-3:before,.fa-hourglass-end:before{content:"\f253"}.fa-heart-broken:before,.fa-heart-crack:before{content:"\f7a9"}.fa-external-link-square-alt:before,.fa-square-up-right:before{content:"\f360"}.fa-face-kiss-beam:before,.fa-kiss-beam:before{content:"\f597"}.fa-film:before{content:"\f008"}.fa-ruler-horizontal:before{content:"\f547"}.fa-people-robbery:before{content:"\e536"}.fa-lightbulb:before{content:"\f0eb"}.fa-caret-left:before{content:"\f0d9"}.fa-circle-exclamation:before,.fa-exclamation-circle:before{content:"\f06a"}.fa-school-circle-xmark:before{content:"\e56d"}.fa-arrow-right-from-bracket:before,.fa-sign-out:before{content:"\f08b"}.fa-chevron-circle-down:before,.fa-circle-chevron-down:before{content:"\f13a"}.fa-unlock-alt:before,.fa-unlock-keyhole:before{content:"\f13e"}.fa-cloud-showers-heavy:before{content:"\f740"}.fa-headphones-alt:before,.fa-headphones-simple:before{content:"\f58f"}.fa-sitemap:before{content:"\f0e8"}.fa-circle-dollar-to-slot:before,.fa-donate:before{content:"\f4b9"}.fa-memory:before{content:"\f538"}.fa-road-spikes:before{content:"\e568"}.fa-fire-burner:before{content:"\e4f1"}.fa-flag:before{content:"\f024"}.fa-hanukiah:before{content:"\f6e6"}.fa-feather:before{content:"\f52d"}.fa-volume-down:before,.fa-volume-low:before{content:"\f027"}.fa-comment-slash:before{content:"\f4b3"}.fa-cloud-sun-rain:before{content:"\f743"}.fa-compress:before{content:"\f066"}.fa-wheat-alt:before,.fa-wheat-awn:before{content:"\e2cd"}.fa-ankh:before{content:"\f644"}.fa-hands-holding-child:before{content:"\e4fa"}.fa-asterisk:before{content:"\2a"}.fa-check-square:before,.fa-square-check:before{content:"\f14a"}.fa-peseta-sign:before{content:"\e221"}.fa-header:before,.fa-heading:before{content:"\f1dc"}.fa-ghost:before{content:"\f6e2"}.fa-list-squares:before,.fa-list:before{content:"\f03a"}.fa-phone-square-alt:before,.fa-square-phone-flip:before{content:"\f87b"}.fa-cart-plus:before{content:"\f217"}.fa-gamepad:before{content:"\f11b"}.fa-circle-dot:before,.fa-dot-circle:before{content:"\f192"}.fa-dizzy:before,.fa-face-dizzy:before{content:"\f567"}.fa-egg:before{content:"\f7fb"}.fa-house-medical-circle-xmark:before{content:"\e513"}.fa-campground:before{content:"\f6bb"}.fa-folder-plus:before{content:"\f65e"}.fa-futbol-ball:before,.fa-futbol:before,.fa-soccer-ball:before{content:"\f1e3"}.fa-paint-brush:before,.fa-paintbrush:before{content:"\f1fc"}.fa-lock:before{content:"\f023"}.fa-gas-pump:before{content:"\f52f"}.fa-hot-tub-person:before,.fa-hot-tub:before{content:"\f593"}.fa-map-location:before,.fa-map-marked:before{content:"\f59f"}.fa-house-flood-water:before{content:"\e50e"}.fa-tree:before{content:"\f1bb"}.fa-bridge-lock:before{content:"\e4cc"}.fa-sack-dollar:before{content:"\f81d"}.fa-edit:before,.fa-pen-to-square:before{content:"\f044"}.fa-car-side:before{content:"\f5e4"}.fa-share-alt:before,.fa-share-nodes:before{content:"\f1e0"}.fa-heart-circle-minus:before{content:"\e4ff"}.fa-hourglass-2:before,.fa-hourglass-half:before{content:"\f252"}.fa-microscope:before{content:"\f610"}.fa-sink:before{content:"\e06d"}.fa-bag-shopping:before,.fa-shopping-bag:before{content:"\f290"}.fa-arrow-down-z-a:before,.fa-sort-alpha-desc:before,.fa-sort-alpha-down-alt:before{content:"\f881"}.fa-mitten:before{content:"\f7b5"}.fa-person-rays:before{content:"\e54d"}.fa-users:before{content:"\f0c0"}.fa-eye-slash:before{content:"\f070"}.fa-flask-vial:before{content:"\e4f3"}.fa-hand-paper:before,.fa-hand:before{content:"\f256"}.fa-om:before{content:"\f679"}.fa-worm:before{content:"\e599"}.fa-house-circle-xmark:before{content:"\e50b"}.fa-plug:before{content:"\f1e6"}.fa-chevron-up:before{content:"\f077"}.fa-hand-spock:before{content:"\f259"}.fa-stopwatch:before{content:"\f2f2"}.fa-face-kiss:before,.fa-kiss:before{content:"\f596"}.fa-bridge-circle-xmark:before{content:"\e4cb"}.fa-face-grin-tongue:before,.fa-grin-tongue:before{content:"\f589"}.fa-chess-bishop:before{content:"\f43a"}.fa-face-grin-wink:before,.fa-grin-wink:before{content:"\f58c"}.fa-deaf:before,.fa-deafness:before,.fa-ear-deaf:before,.fa-hard-of-hearing:before{content:"\f2a4"}.fa-road-circle-check:before{content:"\e564"}.fa-dice-five:before{content:"\f523"}.fa-rss-square:before,.fa-square-rss:before{content:"\f143"}.fa-land-mine-on:before{content:"\e51b"}.fa-i-cursor:before{content:"\f246"}.fa-stamp:before{content:"\f5bf"}.fa-stairs:before{content:"\e289"}.fa-i:before{content:"\49"}.fa-hryvnia-sign:before,.fa-hryvnia:before{content:"\f6f2"}.fa-pills:before{content:"\f484"}.fa-face-grin-wide:before,.fa-grin-alt:before{content:"\f581"}.fa-tooth:before{content:"\f5c9"}.fa-v:before{content:"\56"}.fa-bangladeshi-taka-sign:before{content:"\e2e6"}.fa-bicycle:before{content:"\f206"}.fa-rod-asclepius:before,.fa-rod-snake:before,.fa-staff-aesculapius:before,.fa-staff-snake:before{content:"\e579"}.fa-head-side-cough-slash:before{content:"\e062"}.fa-ambulance:before,.fa-truck-medical:before{content:"\f0f9"}.fa-wheat-awn-circle-exclamation:before{content:"\e598"}.fa-snowman:before{content:"\f7d0"}.fa-mortar-pestle:before{content:"\f5a7"}.fa-road-barrier:before{content:"\e562"}.fa-school:before{content:"\f549"}.fa-igloo:before{content:"\f7ae"}.fa-joint:before{content:"\f595"}.fa-angle-right:before{content:"\f105"}.fa-horse:before{content:"\f6f0"}.fa-q:before{content:"\51"}.fa-g:before{content:"\47"}.fa-notes-medical:before{content:"\f481"}.fa-temperature-2:before,.fa-temperature-half:before,.fa-thermometer-2:before,.fa-thermometer-half:before{content:"\f2c9"}.fa-dong-sign:before{content:"\e169"}.fa-capsules:before{content:"\f46b"}.fa-poo-bolt:before,.fa-poo-storm:before{content:"\f75a"}.fa-face-frown-open:before,.fa-frown-open:before{content:"\f57a"}.fa-hand-point-up:before{content:"\f0a6"}.fa-money-bill:before{content:"\f0d6"}.fa-bookmark:before{content:"\f02e"}.fa-align-justify:before{content:"\f039"}.fa-umbrella-beach:before{content:"\f5ca"}.fa-helmet-un:before{content:"\e503"}.fa-bullseye:before{content:"\f140"}.fa-bacon:before{content:"\f7e5"}.fa-hand-point-down:before{content:"\f0a7"}.fa-arrow-up-from-bracket:before{content:"\e09a"}.fa-folder-blank:before,.fa-folder:before{content:"\f07b"}.fa-file-medical-alt:before,.fa-file-waveform:before{content:"\f478"}.fa-radiation:before{content:"\f7b9"}.fa-chart-simple:before{content:"\e473"}.fa-mars-stroke:before{content:"\f229"}.fa-vial:before{content:"\f492"}.fa-dashboard:before,.fa-gauge-med:before,.fa-gauge:before,.fa-tachometer-alt-average:before{content:"\f624"}.fa-magic-wand-sparkles:before,.fa-wand-magic-sparkles:before{content:"\e2ca"}.fa-e:before{content:"\45"}.fa-pen-alt:before,.fa-pen-clip:before{content:"\f305"}.fa-bridge-circle-exclamation:before{content:"\e4ca"}.fa-user:before{content:"\f007"}.fa-school-circle-check:before{content:"\e56b"}.fa-dumpster:before{content:"\f793"}.fa-shuttle-van:before,.fa-van-shuttle:before{content:"\f5b6"}.fa-building-user:before{content:"\e4da"}.fa-caret-square-left:before,.fa-square-caret-left:before{content:"\f191"}.fa-highlighter:before{content:"\f591"}.fa-key:before{content:"\f084"}.fa-bullhorn:before{content:"\f0a1"}.fa-globe:before{content:"\f0ac"}.fa-synagogue:before{content:"\f69b"}.fa-person-half-dress:before{content:"\e548"}.fa-road-bridge:before{content:"\e563"}.fa-location-arrow:before{content:"\f124"}.fa-c:before{content:"\43"}.fa-tablet-button:before{content:"\f10a"}.fa-building-lock:before{content:"\e4d6"}.fa-pizza-slice:before{content:"\f818"}.fa-money-bill-wave:before{content:"\f53a"}.fa-area-chart:before,.fa-chart-area:before{content:"\f1fe"}.fa-house-flag:before{content:"\e50d"}.fa-person-circle-minus:before{content:"\e540"}.fa-ban:before,.fa-cancel:before{content:"\f05e"}.fa-camera-rotate:before{content:"\e0d8"}.fa-air-freshener:before,.fa-spray-can-sparkles:before{content:"\f5d0"}.fa-star:before{content:"\f005"}.fa-repeat:before{content:"\f363"}.fa-cross:before{content:"\f654"}.fa-box:before{content:"\f466"}.fa-venus-mars:before{content:"\f228"}.fa-arrow-pointer:before,.fa-mouse-pointer:before{content:"\f245"}.fa-expand-arrows-alt:before,.fa-maximize:before{content:"\f31e"}.fa-charging-station:before{content:"\f5e7"}.fa-shapes:before,.fa-triangle-circle-square:before{content:"\f61f"}.fa-random:before,.fa-shuffle:before{content:"\f074"}.fa-person-running:before,.fa-running:before{content:"\f70c"}.fa-mobile-retro:before{content:"\e527"}.fa-grip-lines-vertical:before{content:"\f7a5"}.fa-spider:before{content:"\f717"}.fa-hands-bound:before{content:"\e4f9"}.fa-file-invoice-dollar:before{content:"\f571"}.fa-plane-circle-exclamation:before{content:"\e556"}.fa-x-ray:before{content:"\f497"}.fa-spell-check:before{content:"\f891"}.fa-slash:before{content:"\f715"}.fa-computer-mouse:before,.fa-mouse:before{content:"\f8cc"}.fa-arrow-right-to-bracket:before,.fa-sign-in:before{content:"\f090"}.fa-shop-slash:before,.fa-store-alt-slash:before{content:"\e070"}.fa-server:before{content:"\f233"}.fa-virus-covid-slash:before{content:"\e4a9"}.fa-shop-lock:before{content:"\e4a5"}.fa-hourglass-1:before,.fa-hourglass-start:before{content:"\f251"}.fa-blender-phone:before{content:"\f6b6"}.fa-building-wheat:before{content:"\e4db"}.fa-person-breastfeeding:before{content:"\e53a"}.fa-right-to-bracket:before,.fa-sign-in-alt:before{content:"\f2f6"}.fa-venus:before{content:"\f221"}.fa-passport:before{content:"\f5ab"}.fa-heart-pulse:before,.fa-heartbeat:before{content:"\f21e"}.fa-people-carry-box:before,.fa-people-carry:before{content:"\f4ce"}.fa-temperature-high:before{content:"\f769"}.fa-microchip:before{content:"\f2db"}.fa-crown:before{content:"\f521"}.fa-weight-hanging:before{content:"\f5cd"}.fa-xmarks-lines:before{content:"\e59a"}.fa-file-prescription:before{content:"\f572"}.fa-weight-scale:before,.fa-weight:before{content:"\f496"}.fa-user-friends:before,.fa-user-group:before{content:"\f500"}.fa-arrow-up-a-z:before,.fa-sort-alpha-up:before{content:"\f15e"}.fa-chess-knight:before{content:"\f441"}.fa-face-laugh-squint:before,.fa-laugh-squint:before{content:"\f59b"}.fa-wheelchair:before{content:"\f193"}.fa-arrow-circle-up:before,.fa-circle-arrow-up:before{content:"\f0aa"}.fa-toggle-on:before{content:"\f205"}.fa-person-walking:before,.fa-walking:before{content:"\f554"}.fa-l:before{content:"\4c"}.fa-fire:before{content:"\f06d"}.fa-bed-pulse:before,.fa-procedures:before{content:"\f487"}.fa-shuttle-space:before,.fa-space-shuttle:before{content:"\f197"}.fa-face-laugh:before,.fa-laugh:before{content:"\f599"}.fa-folder-open:before{content:"\f07c"}.fa-heart-circle-plus:before{content:"\e500"}.fa-code-fork:before{content:"\e13b"}.fa-city:before{content:"\f64f"}.fa-microphone-alt:before,.fa-microphone-lines:before{content:"\f3c9"}.fa-pepper-hot:before{content:"\f816"}.fa-unlock:before{content:"\f09c"}.fa-colon-sign:before{content:"\e140"}.fa-headset:before{content:"\f590"}.fa-store-slash:before{content:"\e071"}.fa-road-circle-xmark:before{content:"\e566"}.fa-user-minus:before{content:"\f503"}.fa-mars-stroke-up:before,.fa-mars-stroke-v:before{content:"\f22a"}.fa-champagne-glasses:before,.fa-glass-cheers:before{content:"\f79f"}.fa-clipboard:before{content:"\f328"}.fa-house-circle-exclamation:before{content:"\e50a"}.fa-file-arrow-up:before,.fa-file-upload:before{content:"\f574"}.fa-wifi-3:before,.fa-wifi-strong:before,.fa-wifi:before{content:"\f1eb"}.fa-bath:before,.fa-bathtub:before{content:"\f2cd"}.fa-underline:before{content:"\f0cd"}.fa-user-edit:before,.fa-user-pen:before{content:"\f4ff"}.fa-signature:before{content:"\f5b7"}.fa-stroopwafel:before{content:"\f551"}.fa-bold:before{content:"\f032"}.fa-anchor-lock:before{content:"\e4ad"}.fa-building-ngo:before{content:"\e4d7"}.fa-manat-sign:before{content:"\e1d5"}.fa-not-equal:before{content:"\f53e"}.fa-border-style:before,.fa-border-top-left:before{content:"\f853"}.fa-map-location-dot:before,.fa-map-marked-alt:before{content:"\f5a0"}.fa-jedi:before{content:"\f669"}.fa-poll:before,.fa-square-poll-vertical:before{content:"\f681"}.fa-mug-hot:before{content:"\f7b6"}.fa-battery-car:before,.fa-car-battery:before{content:"\f5df"}.fa-gift:before{content:"\f06b"}.fa-dice-two:before{content:"\f528"}.fa-chess-queen:before{content:"\f445"}.fa-glasses:before{content:"\f530"}.fa-chess-board:before{content:"\f43c"}.fa-building-circle-check:before{content:"\e4d2"}.fa-person-chalkboard:before{content:"\e53d"}.fa-mars-stroke-h:before,.fa-mars-stroke-right:before{content:"\f22b"}.fa-hand-back-fist:before,.fa-hand-rock:before{content:"\f255"}.fa-caret-square-up:before,.fa-square-caret-up:before{content:"\f151"}.fa-cloud-showers-water:before{content:"\e4e4"}.fa-bar-chart:before,.fa-chart-bar:before{content:"\f080"}.fa-hands-bubbles:before,.fa-hands-wash:before{content:"\e05e"}.fa-less-than-equal:before{content:"\f537"}.fa-train:before{content:"\f238"}.fa-eye-low-vision:before,.fa-low-vision:before{content:"\f2a8"}.fa-crow:before{content:"\f520"}.fa-sailboat:before{content:"\e445"}.fa-window-restore:before{content:"\f2d2"}.fa-plus-square:before,.fa-square-plus:before{content:"\f0fe"}.fa-torii-gate:before{content:"\f6a1"}.fa-frog:before{content:"\f52e"}.fa-bucket:before{content:"\e4cf"}.fa-image:before{content:"\f03e"}.fa-microphone:before{content:"\f130"}.fa-cow:before{content:"\f6c8"}.fa-caret-up:before{content:"\f0d8"}.fa-screwdriver:before{content:"\f54a"}.fa-folder-closed:before{content:"\e185"}.fa-house-tsunami:before{content:"\e515"}.fa-square-nfi:before{content:"\e576"}.fa-arrow-up-from-ground-water:before{content:"\e4b5"}.fa-glass-martini-alt:before,.fa-martini-glass:before{content:"\f57b"}.fa-rotate-back:before,.fa-rotate-backward:before,.fa-rotate-left:before,.fa-undo-alt:before{content:"\f2ea"}.fa-columns:before,.fa-table-columns:before{content:"\f0db"}.fa-lemon:before{content:"\f094"}.fa-head-side-mask:before{content:"\e063"}.fa-handshake:before{content:"\f2b5"}.fa-gem:before{content:"\f3a5"}.fa-dolly-box:before,.fa-dolly:before{content:"\f472"}.fa-smoking:before{content:"\f48d"}.fa-compress-arrows-alt:before,.fa-minimize:before{content:"\f78c"}.fa-monument:before{content:"\f5a6"}.fa-snowplow:before{content:"\f7d2"}.fa-angle-double-right:before,.fa-angles-right:before{content:"\f101"}.fa-cannabis:before{content:"\f55f"}.fa-circle-play:before,.fa-play-circle:before{content:"\f144"}.fa-tablets:before{content:"\f490"}.fa-ethernet:before{content:"\f796"}.fa-eur:before,.fa-euro-sign:before,.fa-euro:before{content:"\f153"}.fa-chair:before{content:"\f6c0"}.fa-check-circle:before,.fa-circle-check:before{content:"\f058"}.fa-circle-stop:before,.fa-stop-circle:before{content:"\f28d"}.fa-compass-drafting:before,.fa-drafting-compass:before{content:"\f568"}.fa-plate-wheat:before{content:"\e55a"}.fa-icicles:before{content:"\f7ad"}.fa-person-shelter:before{content:"\e54f"}.fa-neuter:before{content:"\f22c"}.fa-id-badge:before{content:"\f2c1"}.fa-marker:before{content:"\f5a1"}.fa-face-laugh-beam:before,.fa-laugh-beam:before{content:"\f59a"}.fa-helicopter-symbol:before{content:"\e502"}.fa-universal-access:before{content:"\f29a"}.fa-chevron-circle-up:before,.fa-circle-chevron-up:before{content:"\f139"}.fa-lari-sign:before{content:"\e1c8"}.fa-volcano:before{content:"\f770"}.fa-person-walking-dashed-line-arrow-right:before{content:"\e553"}.fa-gbp:before,.fa-pound-sign:before,.fa-sterling-sign:before{content:"\f154"}.fa-viruses:before{content:"\e076"}.fa-square-person-confined:before{content:"\e577"}.fa-user-tie:before{content:"\f508"}.fa-arrow-down-long:before,.fa-long-arrow-down:before{content:"\f175"}.fa-tent-arrow-down-to-line:before{content:"\e57e"}.fa-certificate:before{content:"\f0a3"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-suitcase:before{content:"\f0f2"}.fa-person-skating:before,.fa-skating:before{content:"\f7c5"}.fa-filter-circle-dollar:before,.fa-funnel-dollar:before{content:"\f662"}.fa-camera-retro:before{content:"\f083"}.fa-arrow-circle-down:before,.fa-circle-arrow-down:before{content:"\f0ab"}.fa-arrow-right-to-file:before,.fa-file-import:before{content:"\f56f"}.fa-external-link-square:before,.fa-square-arrow-up-right:before{content:"\f14c"}.fa-box-open:before{content:"\f49e"}.fa-scroll:before{content:"\f70e"}.fa-spa:before{content:"\f5bb"}.fa-location-pin-lock:before{content:"\e51f"}.fa-pause:before{content:"\f04c"}.fa-hill-avalanche:before{content:"\e507"}.fa-temperature-0:before,.fa-temperature-empty:before,.fa-thermometer-0:before,.fa-thermometer-empty:before{content:"\f2cb"}.fa-bomb:before{content:"\f1e2"}.fa-registered:before{content:"\f25d"}.fa-address-card:before,.fa-contact-card:before,.fa-vcard:before{content:"\f2bb"}.fa-balance-scale-right:before,.fa-scale-unbalanced-flip:before{content:"\f516"}.fa-subscript:before{content:"\f12c"}.fa-diamond-turn-right:before,.fa-directions:before{content:"\f5eb"}.fa-burst:before{content:"\e4dc"}.fa-house-laptop:before,.fa-laptop-house:before{content:"\e066"}.fa-face-tired:before,.fa-tired:before{content:"\f5c8"}.fa-money-bills:before{content:"\e1f3"}.fa-smog:before{content:"\f75f"}.fa-crutch:before{content:"\f7f7"}.fa-cloud-arrow-up:before,.fa-cloud-upload-alt:before,.fa-cloud-upload:before{content:"\f0ee"}.fa-palette:before{content:"\f53f"}.fa-arrows-turn-right:before{content:"\e4c0"}.fa-vest:before{content:"\e085"}.fa-ferry:before{content:"\e4ea"}.fa-arrows-down-to-people:before{content:"\e4b9"}.fa-seedling:before,.fa-sprout:before{content:"\f4d8"}.fa-arrows-alt-h:before,.fa-left-right:before{content:"\f337"}.fa-boxes-packing:before{content:"\e4c7"}.fa-arrow-circle-left:before,.fa-circle-arrow-left:before{content:"\f0a8"}.fa-group-arrows-rotate:before{content:"\e4f6"}.fa-bowl-food:before{content:"\e4c6"}.fa-candy-cane:before{content:"\f786"}.fa-arrow-down-wide-short:before,.fa-sort-amount-asc:before,.fa-sort-amount-down:before{content:"\f160"}.fa-cloud-bolt:before,.fa-thunderstorm:before{content:"\f76c"}.fa-remove-format:before,.fa-text-slash:before{content:"\f87d"}.fa-face-smile-wink:before,.fa-smile-wink:before{content:"\f4da"}.fa-file-word:before{content:"\f1c2"}.fa-file-powerpoint:before{content:"\f1c4"}.fa-arrows-h:before,.fa-arrows-left-right:before{content:"\f07e"}.fa-house-lock:before{content:"\e510"}.fa-cloud-arrow-down:before,.fa-cloud-download-alt:before,.fa-cloud-download:before{content:"\f0ed"}.fa-children:before{content:"\e4e1"}.fa-blackboard:before,.fa-chalkboard:before{content:"\f51b"}.fa-user-alt-slash:before,.fa-user-large-slash:before{content:"\f4fa"}.fa-envelope-open:before{content:"\f2b6"}.fa-handshake-alt-slash:before,.fa-handshake-simple-slash:before{content:"\e05f"}.fa-mattress-pillow:before{content:"\e525"}.fa-guarani-sign:before{content:"\e19a"}.fa-arrows-rotate:before,.fa-refresh:before,.fa-sync:before{content:"\f021"}.fa-fire-extinguisher:before{content:"\f134"}.fa-cruzeiro-sign:before{content:"\e152"}.fa-greater-than-equal:before{content:"\f532"}.fa-shield-alt:before,.fa-shield-halved:before{content:"\f3ed"}.fa-atlas:before,.fa-book-atlas:before{content:"\f558"}.fa-virus:before{content:"\e074"}.fa-envelope-circle-check:before{content:"\e4e8"}.fa-layer-group:before{content:"\f5fd"}.fa-arrows-to-dot:before{content:"\e4be"}.fa-archway:before{content:"\f557"}.fa-heart-circle-check:before{content:"\e4fd"}.fa-house-chimney-crack:before,.fa-house-damage:before{content:"\f6f1"}.fa-file-archive:before,.fa-file-zipper:before{content:"\f1c6"}.fa-square:before{content:"\f0c8"}.fa-glass-martini:before,.fa-martini-glass-empty:before{content:"\f000"}.fa-couch:before{content:"\f4b8"}.fa-cedi-sign:before{content:"\e0df"}.fa-italic:before{content:"\f033"}.fa-church:before{content:"\f51d"}.fa-comments-dollar:before{content:"\f653"}.fa-democrat:before{content:"\f747"}.fa-z:before{content:"\5a"}.fa-person-skiing:before,.fa-skiing:before{content:"\f7c9"}.fa-road-lock:before{content:"\e567"}.fa-a:before{content:"\41"}.fa-temperature-arrow-down:before,.fa-temperature-down:before{content:"\e03f"}.fa-feather-alt:before,.fa-feather-pointed:before{content:"\f56b"}.fa-p:before{content:"\50"}.fa-snowflake:before{content:"\f2dc"}.fa-newspaper:before{content:"\f1ea"}.fa-ad:before,.fa-rectangle-ad:before{content:"\f641"}.fa-arrow-circle-right:before,.fa-circle-arrow-right:before{content:"\f0a9"}.fa-filter-circle-xmark:before{content:"\e17b"}.fa-locust:before{content:"\e520"}.fa-sort:before,.fa-unsorted:before{content:"\f0dc"}.fa-list-1-2:before,.fa-list-numeric:before,.fa-list-ol:before{content:"\f0cb"}.fa-person-dress-burst:before{content:"\e544"}.fa-money-check-alt:before,.fa-money-check-dollar:before{content:"\f53d"}.fa-vector-square:before{content:"\f5cb"}.fa-bread-slice:before{content:"\f7ec"}.fa-language:before{content:"\f1ab"}.fa-face-kiss-wink-heart:before,.fa-kiss-wink-heart:before{content:"\f598"}.fa-filter:before{content:"\f0b0"}.fa-question:before{content:"\3f"}.fa-file-signature:before{content:"\f573"}.fa-arrows-alt:before,.fa-up-down-left-right:before{content:"\f0b2"}.fa-house-chimney-user:before{content:"\e065"}.fa-hand-holding-heart:before{content:"\f4be"}.fa-puzzle-piece:before{content:"\f12e"}.fa-money-check:before{content:"\f53c"}.fa-star-half-alt:before,.fa-star-half-stroke:before{content:"\f5c0"}.fa-code:before{content:"\f121"}.fa-glass-whiskey:before,.fa-whiskey-glass:before{content:"\f7a0"}.fa-building-circle-exclamation:before{content:"\e4d3"}.fa-magnifying-glass-chart:before{content:"\e522"}.fa-arrow-up-right-from-square:before,.fa-external-link:before{content:"\f08e"}.fa-cubes-stacked:before{content:"\e4e6"}.fa-krw:before,.fa-won-sign:before,.fa-won:before{content:"\f159"}.fa-virus-covid:before{content:"\e4a8"}.fa-austral-sign:before{content:"\e0a9"}.fa-f:before{content:"\46"}.fa-leaf:before{content:"\f06c"}.fa-road:before{content:"\f018"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-person-circle-plus:before{content:"\e541"}.fa-chart-pie:before,.fa-pie-chart:before{content:"\f200"}.fa-bolt-lightning:before{content:"\e0b7"}.fa-sack-xmark:before{content:"\e56a"}.fa-file-excel:before{content:"\f1c3"}.fa-file-contract:before{content:"\f56c"}.fa-fish-fins:before{content:"\e4f2"}.fa-building-flag:before{content:"\e4d5"}.fa-face-grin-beam:before,.fa-grin-beam:before{content:"\f582"}.fa-object-ungroup:before{content:"\f248"}.fa-poop:before{content:"\f619"}.fa-location-pin:before,.fa-map-marker:before{content:"\f041"}.fa-kaaba:before{content:"\f66b"}.fa-toilet-paper:before{content:"\f71e"}.fa-hard-hat:before,.fa-hat-hard:before,.fa-helmet-safety:before{content:"\f807"}.fa-eject:before{content:"\f052"}.fa-arrow-alt-circle-right:before,.fa-circle-right:before{content:"\f35a"}.fa-plane-circle-check:before{content:"\e555"}.fa-face-rolling-eyes:before,.fa-meh-rolling-eyes:before{content:"\f5a5"}.fa-object-group:before{content:"\f247"}.fa-chart-line:before,.fa-line-chart:before{content:"\f201"}.fa-mask-ventilator:before{content:"\e524"}.fa-arrow-right:before{content:"\f061"}.fa-map-signs:before,.fa-signs-post:before{content:"\f277"}.fa-cash-register:before{content:"\f788"}.fa-person-circle-question:before{content:"\e542"}.fa-h:before{content:"\48"}.fa-tarp:before{content:"\e57b"}.fa-screwdriver-wrench:before,.fa-tools:before{content:"\f7d9"}.fa-arrows-to-eye:before{content:"\e4bf"}.fa-plug-circle-bolt:before{content:"\e55b"}.fa-heart:before{content:"\f004"}.fa-mars-and-venus:before{content:"\f224"}.fa-home-user:before,.fa-house-user:before{content:"\e1b0"}.fa-dumpster-fire:before{content:"\f794"}.fa-house-crack:before{content:"\e3b1"}.fa-cocktail:before,.fa-martini-glass-citrus:before{content:"\f561"}.fa-face-surprise:before,.fa-surprise:before{content:"\f5c2"}.fa-bottle-water:before{content:"\e4c5"}.fa-circle-pause:before,.fa-pause-circle:before{content:"\f28b"}.fa-toilet-paper-slash:before{content:"\e072"}.fa-apple-alt:before,.fa-apple-whole:before{content:"\f5d1"}.fa-kitchen-set:before{content:"\e51a"}.fa-r:before{content:"\52"}.fa-temperature-1:before,.fa-temperature-quarter:before,.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:"\f2ca"}.fa-cube:before{content:"\f1b2"}.fa-bitcoin-sign:before{content:"\e0b4"}.fa-shield-dog:before{content:"\e573"}.fa-solar-panel:before{content:"\f5ba"}.fa-lock-open:before{content:"\f3c1"}.fa-elevator:before{content:"\e16d"}.fa-money-bill-transfer:before{content:"\e528"}.fa-money-bill-trend-up:before{content:"\e529"}.fa-house-flood-water-circle-arrow-right:before{content:"\e50f"}.fa-poll-h:before,.fa-square-poll-horizontal:before{content:"\f682"}.fa-circle:before{content:"\f111"}.fa-backward-fast:before,.fa-fast-backward:before{content:"\f049"}.fa-recycle:before{content:"\f1b8"}.fa-user-astronaut:before{content:"\f4fb"}.fa-plane-slash:before{content:"\e069"}.fa-trademark:before{content:"\f25c"}.fa-basketball-ball:before,.fa-basketball:before{content:"\f434"}.fa-satellite-dish:before{content:"\f7c0"}.fa-arrow-alt-circle-up:before,.fa-circle-up:before{content:"\f35b"}.fa-mobile-alt:before,.fa-mobile-screen-button:before{content:"\f3cd"}.fa-volume-high:before,.fa-volume-up:before{content:"\f028"}.fa-users-rays:before{content:"\e593"}.fa-wallet:before{content:"\f555"}.fa-clipboard-check:before{content:"\f46c"}.fa-file-audio:before{content:"\f1c7"}.fa-burger:before,.fa-hamburger:before{content:"\f805"}.fa-wrench:before{content:"\f0ad"}.fa-bugs:before{content:"\e4d0"}.fa-rupee-sign:before,.fa-rupee:before{content:"\f156"}.fa-file-image:before{content:"\f1c5"}.fa-circle-question:before,.fa-question-circle:before{content:"\f059"}.fa-plane-departure:before{content:"\f5b0"}.fa-handshake-slash:before{content:"\e060"}.fa-book-bookmark:before{content:"\e0bb"}.fa-code-branch:before{content:"\f126"}.fa-hat-cowboy:before{content:"\f8c0"}.fa-bridge:before{content:"\e4c8"}.fa-phone-alt:before,.fa-phone-flip:before{content:"\f879"}.fa-truck-front:before{content:"\e2b7"}.fa-cat:before{content:"\f6be"}.fa-anchor-circle-exclamation:before{content:"\e4ab"}.fa-truck-field:before{content:"\e58d"}.fa-route:before{content:"\f4d7"}.fa-clipboard-question:before{content:"\e4e3"}.fa-panorama:before{content:"\e209"}.fa-comment-medical:before{content:"\f7f5"}.fa-teeth-open:before{content:"\f62f"}.fa-file-circle-minus:before{content:"\e4ed"}.fa-tags:before{content:"\f02c"}.fa-wine-glass:before{content:"\f4e3"}.fa-fast-forward:before,.fa-forward-fast:before{content:"\f050"}.fa-face-meh-blank:before,.fa-meh-blank:before{content:"\f5a4"}.fa-parking:before,.fa-square-parking:before{content:"\f540"}.fa-house-signal:before{content:"\e012"}.fa-bars-progress:before,.fa-tasks-alt:before{content:"\f828"}.fa-faucet-drip:before{content:"\e006"}.fa-cart-flatbed:before,.fa-dolly-flatbed:before{content:"\f474"}.fa-ban-smoking:before,.fa-smoking-ban:before{content:"\f54d"}.fa-terminal:before{content:"\f120"}.fa-mobile-button:before{content:"\f10b"}.fa-house-medical-flag:before{content:"\e514"}.fa-basket-shopping:before,.fa-shopping-basket:before{content:"\f291"}.fa-tape:before{content:"\f4db"}.fa-bus-alt:before,.fa-bus-simple:before{content:"\f55e"}.fa-eye:before{content:"\f06e"}.fa-face-sad-cry:before,.fa-sad-cry:before{content:"\f5b3"}.fa-audio-description:before{content:"\f29e"}.fa-person-military-to-person:before{content:"\e54c"}.fa-file-shield:before{content:"\e4f0"}.fa-user-slash:before{content:"\f506"}.fa-pen:before{content:"\f304"}.fa-tower-observation:before{content:"\e586"}.fa-file-code:before{content:"\f1c9"}.fa-signal-5:before,.fa-signal-perfect:before,.fa-signal:before{content:"\f012"}.fa-bus:before{content:"\f207"}.fa-heart-circle-xmark:before{content:"\e501"}.fa-home-lg:before,.fa-house-chimney:before{content:"\e3af"}.fa-window-maximize:before{content:"\f2d0"}.fa-face-frown:before,.fa-frown:before{content:"\f119"}.fa-prescription:before{content:"\f5b1"}.fa-shop:before,.fa-store-alt:before{content:"\f54f"}.fa-floppy-disk:before,.fa-save:before{content:"\f0c7"}.fa-vihara:before{content:"\f6a7"}.fa-balance-scale-left:before,.fa-scale-unbalanced:before{content:"\f515"}.fa-sort-asc:before,.fa-sort-up:before{content:"\f0de"}.fa-comment-dots:before,.fa-commenting:before{content:"\f4ad"}.fa-plant-wilt:before{content:"\e5aa"}.fa-diamond:before{content:"\f219"}.fa-face-grin-squint:before,.fa-grin-squint:before{content:"\f585"}.fa-hand-holding-dollar:before,.fa-hand-holding-usd:before{content:"\f4c0"}.fa-bacterium:before{content:"\e05a"}.fa-hand-pointer:before{content:"\f25a"}.fa-drum-steelpan:before{content:"\f56a"}.fa-hand-scissors:before{content:"\f257"}.fa-hands-praying:before,.fa-praying-hands:before{content:"\f684"}.fa-arrow-right-rotate:before,.fa-arrow-rotate-forward:before,.fa-arrow-rotate-right:before,.fa-redo:before{content:"\f01e"}.fa-biohazard:before{content:"\f780"}.fa-location-crosshairs:before,.fa-location:before{content:"\f601"}.fa-mars-double:before{content:"\f227"}.fa-child-dress:before{content:"\e59c"}.fa-users-between-lines:before{content:"\e591"}.fa-lungs-virus:before{content:"\e067"}.fa-face-grin-tears:before,.fa-grin-tears:before{content:"\f588"}.fa-phone:before{content:"\f095"}.fa-calendar-times:before,.fa-calendar-xmark:before{content:"\f273"}.fa-child-reaching:before{content:"\e59d"}.fa-head-side-virus:before{content:"\e064"}.fa-user-cog:before,.fa-user-gear:before{content:"\f4fe"}.fa-arrow-up-1-9:before,.fa-sort-numeric-up:before{content:"\f163"}.fa-door-closed:before{content:"\f52a"}.fa-shield-virus:before{content:"\e06c"}.fa-dice-six:before{content:"\f526"}.fa-mosquito-net:before{content:"\e52c"}.fa-bridge-water:before{content:"\e4ce"}.fa-person-booth:before{content:"\f756"}.fa-text-width:before{content:"\f035"}.fa-hat-wizard:before{content:"\f6e8"}.fa-pen-fancy:before{content:"\f5ac"}.fa-digging:before,.fa-person-digging:before{content:"\f85e"}.fa-trash:before{content:"\f1f8"}.fa-gauge-simple-med:before,.fa-gauge-simple:before,.fa-tachometer-average:before{content:"\f629"}.fa-book-medical:before{content:"\f7e6"}.fa-poo:before{content:"\f2fe"}.fa-quote-right-alt:before,.fa-quote-right:before{content:"\f10e"}.fa-shirt:before,.fa-t-shirt:before,.fa-tshirt:before{content:"\f553"}.fa-cubes:before{content:"\f1b3"}.fa-divide:before{content:"\f529"}.fa-tenge-sign:before,.fa-tenge:before{content:"\f7d7"}.fa-headphones:before{content:"\f025"}.fa-hands-holding:before{content:"\f4c2"}.fa-hands-clapping:before{content:"\e1a8"}.fa-republican:before{content:"\f75e"}.fa-arrow-left:before{content:"\f060"}.fa-person-circle-xmark:before{content:"\e543"}.fa-ruler:before{content:"\f545"}.fa-align-left:before{content:"\f036"}.fa-dice-d6:before{content:"\f6d1"}.fa-restroom:before{content:"\f7bd"}.fa-j:before{content:"\4a"}.fa-users-viewfinder:before{content:"\e595"}.fa-file-video:before{content:"\f1c8"}.fa-external-link-alt:before,.fa-up-right-from-square:before{content:"\f35d"}.fa-table-cells:before,.fa-th:before{content:"\f00a"}.fa-file-pdf:before{content:"\f1c1"}.fa-bible:before,.fa-book-bible:before{content:"\f647"}.fa-o:before{content:"\4f"}.fa-medkit:before,.fa-suitcase-medical:before{content:"\f0fa"}.fa-user-secret:before{content:"\f21b"}.fa-otter:before{content:"\f700"}.fa-female:before,.fa-person-dress:before{content:"\f182"}.fa-comment-dollar:before{content:"\f651"}.fa-briefcase-clock:before,.fa-business-time:before{content:"\f64a"}.fa-table-cells-large:before,.fa-th-large:before{content:"\f009"}.fa-book-tanakh:before,.fa-tanakh:before{content:"\f827"}.fa-phone-volume:before,.fa-volume-control-phone:before{content:"\f2a0"}.fa-hat-cowboy-side:before{content:"\f8c1"}.fa-clipboard-user:before{content:"\f7f3"}.fa-child:before{content:"\f1ae"}.fa-lira-sign:before{content:"\f195"}.fa-satellite:before{content:"\f7bf"}.fa-plane-lock:before{content:"\e558"}.fa-tag:before{content:"\f02b"}.fa-comment:before{content:"\f075"}.fa-birthday-cake:before,.fa-cake-candles:before,.fa-cake:before{content:"\f1fd"}.fa-envelope:before{content:"\f0e0"}.fa-angle-double-up:before,.fa-angles-up:before{content:"\f102"}.fa-paperclip:before{content:"\f0c6"}.fa-arrow-right-to-city:before{content:"\e4b3"}.fa-ribbon:before{content:"\f4d6"}.fa-lungs:before{content:"\f604"}.fa-arrow-up-9-1:before,.fa-sort-numeric-up-alt:before{content:"\f887"}.fa-litecoin-sign:before{content:"\e1d3"}.fa-border-none:before{content:"\f850"}.fa-circle-nodes:before{content:"\e4e2"}.fa-parachute-box:before{content:"\f4cd"}.fa-indent:before{content:"\f03c"}.fa-truck-field-un:before{content:"\e58e"}.fa-hourglass-empty:before,.fa-hourglass:before{content:"\f254"}.fa-mountain:before{content:"\f6fc"}.fa-user-doctor:before,.fa-user-md:before{content:"\f0f0"}.fa-circle-info:before,.fa-info-circle:before{content:"\f05a"}.fa-cloud-meatball:before{content:"\f73b"}.fa-camera-alt:before,.fa-camera:before{content:"\f030"}.fa-square-virus:before{content:"\e578"}.fa-meteor:before{content:"\f753"}.fa-car-on:before{content:"\e4dd"}.fa-sleigh:before{content:"\f7cc"}.fa-arrow-down-1-9:before,.fa-sort-numeric-asc:before,.fa-sort-numeric-down:before{content:"\f162"}.fa-hand-holding-droplet:before,.fa-hand-holding-water:before{content:"\f4c1"}.fa-water:before{content:"\f773"}.fa-calendar-check:before{content:"\f274"}.fa-braille:before{content:"\f2a1"}.fa-prescription-bottle-alt:before,.fa-prescription-bottle-medical:before{content:"\f486"}.fa-landmark:before{content:"\f66f"}.fa-truck:before{content:"\f0d1"}.fa-crosshairs:before{content:"\f05b"}.fa-person-cane:before{content:"\e53c"}.fa-tent:before{content:"\e57d"}.fa-vest-patches:before{content:"\e086"}.fa-check-double:before{content:"\f560"}.fa-arrow-down-a-z:before,.fa-sort-alpha-asc:before,.fa-sort-alpha-down:before{content:"\f15d"}.fa-money-bill-wheat:before{content:"\e52a"}.fa-cookie:before{content:"\f563"}.fa-arrow-left-rotate:before,.fa-arrow-rotate-back:before,.fa-arrow-rotate-backward:before,.fa-arrow-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-hard-drive:before,.fa-hdd:before{content:"\f0a0"}.fa-face-grin-squint-tears:before,.fa-grin-squint-tears:before{content:"\f586"}.fa-dumbbell:before{content:"\f44b"}.fa-list-alt:before,.fa-rectangle-list:before{content:"\f022"}.fa-tarp-droplet:before{content:"\e57c"}.fa-house-medical-circle-check:before{content:"\e511"}.fa-person-skiing-nordic:before,.fa-skiing-nordic:before{content:"\f7ca"}.fa-calendar-plus:before{content:"\f271"}.fa-plane-arrival:before{content:"\f5af"}.fa-arrow-alt-circle-left:before,.fa-circle-left:before{content:"\f359"}.fa-subway:before,.fa-train-subway:before{content:"\f239"}.fa-chart-gantt:before{content:"\e0e4"}.fa-indian-rupee-sign:before,.fa-indian-rupee:before,.fa-inr:before{content:"\e1bc"}.fa-crop-alt:before,.fa-crop-simple:before{content:"\f565"}.fa-money-bill-1:before,.fa-money-bill-alt:before{content:"\f3d1"}.fa-left-long:before,.fa-long-arrow-alt-left:before{content:"\f30a"}.fa-dna:before{content:"\f471"}.fa-virus-slash:before{content:"\e075"}.fa-minus:before,.fa-subtract:before{content:"\f068"}.fa-chess:before{content:"\f439"}.fa-arrow-left-long:before,.fa-long-arrow-left:before{content:"\f177"}.fa-plug-circle-check:before{content:"\e55c"}.fa-street-view:before{content:"\f21d"}.fa-franc-sign:before{content:"\e18f"}.fa-volume-off:before{content:"\f026"}.fa-american-sign-language-interpreting:before,.fa-asl-interpreting:before,.fa-hands-american-sign-language-interpreting:before,.fa-hands-asl-interpreting:before{content:"\f2a3"}.fa-cog:before,.fa-gear:before{content:"\f013"}.fa-droplet-slash:before,.fa-tint-slash:before{content:"\f5c7"}.fa-mosque:before{content:"\f678"}.fa-mosquito:before{content:"\e52b"}.fa-star-of-david:before{content:"\f69a"}.fa-person-military-rifle:before{content:"\e54b"}.fa-cart-shopping:before,.fa-shopping-cart:before{content:"\f07a"}.fa-vials:before{content:"\f493"}.fa-plug-circle-plus:before{content:"\e55f"}.fa-place-of-worship:before{content:"\f67f"}.fa-grip-vertical:before{content:"\f58e"}.fa-arrow-turn-up:before,.fa-level-up:before{content:"\f148"}.fa-u:before{content:"\55"}.fa-square-root-alt:before,.fa-square-root-variable:before{content:"\f698"}.fa-clock-four:before,.fa-clock:before{content:"\f017"}.fa-backward-step:before,.fa-step-backward:before{content:"\f048"}.fa-pallet:before{content:"\f482"}.fa-faucet:before{content:"\e005"}.fa-baseball-bat-ball:before{content:"\f432"}.fa-s:before{content:"\53"}.fa-timeline:before{content:"\e29c"}.fa-keyboard:before{content:"\f11c"}.fa-caret-down:before{content:"\f0d7"}.fa-clinic-medical:before,.fa-house-chimney-medical:before{content:"\f7f2"}.fa-temperature-3:before,.fa-temperature-three-quarters:before,.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:"\f2c8"}.fa-mobile-android-alt:before,.fa-mobile-screen:before{content:"\f3cf"}.fa-plane-up:before{content:"\e22d"}.fa-piggy-bank:before{content:"\f4d3"}.fa-battery-3:before,.fa-battery-half:before{content:"\f242"}.fa-mountain-city:before{content:"\e52e"}.fa-coins:before{content:"\f51e"}.fa-khanda:before{content:"\f66d"}.fa-sliders-h:before,.fa-sliders:before{content:"\f1de"}.fa-folder-tree:before{content:"\f802"}.fa-network-wired:before{content:"\f6ff"}.fa-map-pin:before{content:"\f276"}.fa-hamsa:before{content:"\f665"}.fa-cent-sign:before{content:"\e3f5"}.fa-flask:before{content:"\f0c3"}.fa-person-pregnant:before{content:"\e31e"}.fa-wand-sparkles:before{content:"\f72b"}.fa-ellipsis-v:before,.fa-ellipsis-vertical:before{content:"\f142"}.fa-ticket:before{content:"\f145"}.fa-power-off:before{content:"\f011"}.fa-long-arrow-alt-right:before,.fa-right-long:before{content:"\f30b"}.fa-flag-usa:before{content:"\f74d"}.fa-laptop-file:before{content:"\e51d"}.fa-teletype:before,.fa-tty:before{content:"\f1e4"}.fa-diagram-next:before{content:"\e476"}.fa-person-rifle:before{content:"\e54e"}.fa-house-medical-circle-exclamation:before{content:"\e512"}.fa-closed-captioning:before{content:"\f20a"}.fa-hiking:before,.fa-person-hiking:before{content:"\f6ec"}.fa-venus-double:before{content:"\f226"}.fa-images:before{content:"\f302"}.fa-calculator:before{content:"\f1ec"}.fa-people-pulling:before{content:"\e535"}.fa-n:before{content:"\4e"}.fa-cable-car:before,.fa-tram:before{content:"\f7da"}.fa-cloud-rain:before{content:"\f73d"}.fa-building-circle-xmark:before{content:"\e4d4"}.fa-ship:before{content:"\f21a"}.fa-arrows-down-to-line:before{content:"\e4b8"}.fa-download:before{content:"\f019"}.fa-face-grin:before,.fa-grin:before{content:"\f580"}.fa-backspace:before,.fa-delete-left:before{content:"\f55a"}.fa-eye-dropper-empty:before,.fa-eye-dropper:before,.fa-eyedropper:before{content:"\f1fb"}.fa-file-circle-check:before{content:"\e5a0"}.fa-forward:before{content:"\f04e"}.fa-mobile-android:before,.fa-mobile-phone:before,.fa-mobile:before{content:"\f3ce"}.fa-face-meh:before,.fa-meh:before{content:"\f11a"}.fa-align-center:before{content:"\f037"}.fa-book-dead:before,.fa-book-skull:before{content:"\f6b7"}.fa-drivers-license:before,.fa-id-card:before{content:"\f2c2"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-heart-circle-exclamation:before{content:"\e4fe"}.fa-home-alt:before,.fa-home-lg-alt:before,.fa-home:before,.fa-house:before{content:"\f015"}.fa-calendar-week:before{content:"\f784"}.fa-laptop-medical:before{content:"\f812"}.fa-b:before{content:"\42"}.fa-file-medical:before{content:"\f477"}.fa-dice-one:before{content:"\f525"}.fa-kiwi-bird:before{content:"\f535"}.fa-arrow-right-arrow-left:before,.fa-exchange:before{content:"\f0ec"}.fa-redo-alt:before,.fa-rotate-forward:before,.fa-rotate-right:before{content:"\f2f9"}.fa-cutlery:before,.fa-utensils:before{content:"\f2e7"}.fa-arrow-up-wide-short:before,.fa-sort-amount-up:before{content:"\f161"}.fa-mill-sign:before{content:"\e1ed"}.fa-bowl-rice:before{content:"\e2eb"}.fa-skull:before{content:"\f54c"}.fa-broadcast-tower:before,.fa-tower-broadcast:before{content:"\f519"}.fa-truck-pickup:before{content:"\f63c"}.fa-long-arrow-alt-up:before,.fa-up-long:before{content:"\f30c"}.fa-stop:before{content:"\f04d"}.fa-code-merge:before{content:"\f387"}.fa-upload:before{content:"\f093"}.fa-hurricane:before{content:"\f751"}.fa-mound:before{content:"\e52d"}.fa-toilet-portable:before{content:"\e583"}.fa-compact-disc:before{content:"\f51f"}.fa-file-arrow-down:before,.fa-file-download:before{content:"\f56d"}.fa-caravan:before{content:"\f8ff"}.fa-shield-cat:before{content:"\e572"}.fa-bolt:before,.fa-zap:before{content:"\f0e7"}.fa-glass-water:before{content:"\e4f4"}.fa-oil-well:before{content:"\e532"}.fa-vault:before{content:"\e2c5"}.fa-mars:before{content:"\f222"}.fa-toilet:before{content:"\f7d8"}.fa-plane-circle-xmark:before{content:"\e557"}.fa-cny:before,.fa-jpy:before,.fa-rmb:before,.fa-yen-sign:before,.fa-yen:before{content:"\f157"}.fa-rouble:before,.fa-rub:before,.fa-ruble-sign:before,.fa-ruble:before{content:"\f158"}.fa-sun:before{content:"\f185"}.fa-guitar:before{content:"\f7a6"}.fa-face-laugh-wink:before,.fa-laugh-wink:before{content:"\f59c"}.fa-horse-head:before{content:"\f7ab"}.fa-bore-hole:before{content:"\e4c3"}.fa-industry:before{content:"\f275"}.fa-arrow-alt-circle-down:before,.fa-circle-down:before{content:"\f358"}.fa-arrows-turn-to-dots:before{content:"\e4c1"}.fa-florin-sign:before{content:"\e184"}.fa-arrow-down-short-wide:before,.fa-sort-amount-desc:before,.fa-sort-amount-down-alt:before{content:"\f884"}.fa-less-than:before{content:"\3c"}.fa-angle-down:before{content:"\f107"}.fa-car-tunnel:before{content:"\e4de"}.fa-head-side-cough:before{content:"\e061"}.fa-grip-lines:before{content:"\f7a4"}.fa-thumbs-down:before{content:"\f165"}.fa-user-lock:before{content:"\f502"}.fa-arrow-right-long:before,.fa-long-arrow-right:before{content:"\f178"}.fa-anchor-circle-xmark:before{content:"\e4ac"}.fa-ellipsis-h:before,.fa-ellipsis:before{content:"\f141"}.fa-chess-pawn:before{content:"\f443"}.fa-first-aid:before,.fa-kit-medical:before{content:"\f479"}.fa-person-through-window:before{content:"\e5a9"}.fa-toolbox:before{content:"\f552"}.fa-hands-holding-circle:before{content:"\e4fb"}.fa-bug:before{content:"\f188"}.fa-credit-card-alt:before,.fa-credit-card:before{content:"\f09d"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-hand-holding-hand:before{content:"\e4f7"}.fa-book-open-reader:before,.fa-book-reader:before{content:"\f5da"}.fa-mountain-sun:before{content:"\e52f"}.fa-arrows-left-right-to-line:before{content:"\e4ba"}.fa-dice-d20:before{content:"\f6cf"}.fa-truck-droplet:before{content:"\e58c"}.fa-file-circle-xmark:before{content:"\e5a1"}.fa-temperature-arrow-up:before,.fa-temperature-up:before{content:"\e040"}.fa-medal:before{content:"\f5a2"}.fa-bed:before{content:"\f236"}.fa-h-square:before,.fa-square-h:before{content:"\f0fd"}.fa-podcast:before{content:"\f2ce"}.fa-temperature-4:before,.fa-temperature-full:before,.fa-thermometer-4:before,.fa-thermometer-full:before{content:"\f2c7"}.fa-bell:before{content:"\f0f3"}.fa-superscript:before{content:"\f12b"}.fa-plug-circle-xmark:before{content:"\e560"}.fa-star-of-life:before{content:"\f621"}.fa-phone-slash:before{content:"\f3dd"}.fa-paint-roller:before{content:"\f5aa"}.fa-hands-helping:before,.fa-handshake-angle:before{content:"\f4c4"}.fa-location-dot:before,.fa-map-marker-alt:before{content:"\f3c5"}.fa-file:before{content:"\f15b"}.fa-greater-than:before{content:"\3e"}.fa-person-swimming:before,.fa-swimmer:before{content:"\f5c4"}.fa-arrow-down:before{content:"\f063"}.fa-droplet:before,.fa-tint:before{content:"\f043"}.fa-eraser:before{content:"\f12d"}.fa-earth-america:before,.fa-earth-americas:before,.fa-earth:before,.fa-globe-americas:before{content:"\f57d"}.fa-person-burst:before{content:"\e53b"}.fa-dove:before{content:"\f4ba"}.fa-battery-0:before,.fa-battery-empty:before{content:"\f244"}.fa-socks:before{content:"\f696"}.fa-inbox:before{content:"\f01c"}.fa-section:before{content:"\e447"}.fa-gauge-high:before,.fa-tachometer-alt-fast:before,.fa-tachometer-alt:before{content:"\f625"}.fa-envelope-open-text:before{content:"\f658"}.fa-hospital-alt:before,.fa-hospital-wide:before,.fa-hospital:before{content:"\f0f8"}.fa-wine-bottle:before{content:"\f72f"}.fa-chess-rook:before{content:"\f447"}.fa-bars-staggered:before,.fa-reorder:before,.fa-stream:before{content:"\f550"}.fa-dharmachakra:before{content:"\f655"}.fa-hotdog:before{content:"\f80f"}.fa-blind:before,.fa-person-walking-with-cane:before{content:"\f29d"}.fa-drum:before{content:"\f569"}.fa-ice-cream:before{content:"\f810"}.fa-heart-circle-bolt:before{content:"\e4fc"}.fa-fax:before{content:"\f1ac"}.fa-paragraph:before{content:"\f1dd"}.fa-check-to-slot:before,.fa-vote-yea:before{content:"\f772"}.fa-star-half:before{content:"\f089"}.fa-boxes-alt:before,.fa-boxes-stacked:before,.fa-boxes:before{content:"\f468"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-assistive-listening-systems:before,.fa-ear-listen:before{content:"\f2a2"}.fa-tree-city:before{content:"\e587"}.fa-play:before{content:"\f04b"}.fa-font:before{content:"\f031"}.fa-rupiah-sign:before{content:"\e23d"}.fa-magnifying-glass:before,.fa-search:before{content:"\f002"}.fa-ping-pong-paddle-ball:before,.fa-table-tennis-paddle-ball:before,.fa-table-tennis:before{content:"\f45d"}.fa-diagnoses:before,.fa-person-dots-from-line:before{content:"\f470"}.fa-trash-can-arrow-up:before,.fa-trash-restore-alt:before{content:"\f82a"}.fa-naira-sign:before{content:"\e1f6"}.fa-cart-arrow-down:before{content:"\f218"}.fa-walkie-talkie:before{content:"\f8ef"}.fa-file-edit:before,.fa-file-pen:before{content:"\f31c"}.fa-receipt:before{content:"\f543"}.fa-pen-square:before,.fa-pencil-square:before,.fa-square-pen:before{content:"\f14b"}.fa-suitcase-rolling:before{content:"\f5c1"}.fa-person-circle-exclamation:before{content:"\e53f"}.fa-chevron-down:before{content:"\f078"}.fa-battery-5:before,.fa-battery-full:before,.fa-battery:before{content:"\f240"}.fa-skull-crossbones:before{content:"\f714"}.fa-code-compare:before{content:"\e13a"}.fa-list-dots:before,.fa-list-ul:before{content:"\f0ca"}.fa-school-lock:before{content:"\e56f"}.fa-tower-cell:before{content:"\e585"}.fa-down-long:before,.fa-long-arrow-alt-down:before{content:"\f309"}.fa-ranking-star:before{content:"\e561"}.fa-chess-king:before{content:"\f43f"}.fa-person-harassing:before{content:"\e549"}.fa-brazilian-real-sign:before{content:"\e46c"}.fa-landmark-alt:before,.fa-landmark-dome:before{content:"\f752"}.fa-arrow-up:before{content:"\f062"}.fa-television:before,.fa-tv-alt:before,.fa-tv:before{content:"\f26c"}.fa-shrimp:before{content:"\e448"}.fa-list-check:before,.fa-tasks:before{content:"\f0ae"}.fa-jug-detergent:before{content:"\e519"}.fa-circle-user:before,.fa-user-circle:before{content:"\f2bd"}.fa-user-shield:before{content:"\f505"}.fa-wind:before{content:"\f72e"}.fa-car-burst:before,.fa-car-crash:before{content:"\f5e1"}.fa-y:before{content:"\59"}.fa-person-snowboarding:before,.fa-snowboarding:before{content:"\f7ce"}.fa-shipping-fast:before,.fa-truck-fast:before{content:"\f48b"}.fa-fish:before{content:"\f578"}.fa-user-graduate:before{content:"\f501"}.fa-adjust:before,.fa-circle-half-stroke:before{content:"\f042"}.fa-clapperboard:before{content:"\e131"}.fa-circle-radiation:before,.fa-radiation-alt:before{content:"\f7ba"}.fa-baseball-ball:before,.fa-baseball:before{content:"\f433"}.fa-jet-fighter-up:before{content:"\e518"}.fa-diagram-project:before,.fa-project-diagram:before{content:"\f542"}.fa-copy:before{content:"\f0c5"}.fa-volume-mute:before,.fa-volume-times:before,.fa-volume-xmark:before{content:"\f6a9"}.fa-hand-sparkles:before{content:"\e05d"}.fa-grip-horizontal:before,.fa-grip:before{content:"\f58d"}.fa-share-from-square:before,.fa-share-square:before{content:"\f14d"}.fa-child-combatant:before,.fa-child-rifle:before{content:"\e4e0"}.fa-gun:before{content:"\e19b"}.fa-phone-square:before,.fa-square-phone:before{content:"\f098"}.fa-add:before,.fa-plus:before{content:"\2b"}.fa-expand:before{content:"\f065"}.fa-computer:before{content:"\e4e5"}.fa-close:before,.fa-multiply:before,.fa-remove:before,.fa-times:before,.fa-xmark:before{content:"\f00d"}.fa-arrows-up-down-left-right:before,.fa-arrows:before{content:"\f047"}.fa-chalkboard-teacher:before,.fa-chalkboard-user:before{content:"\f51c"}.fa-peso-sign:before{content:"\e222"}.fa-building-shield:before{content:"\e4d8"}.fa-baby:before{content:"\f77c"}.fa-users-line:before{content:"\e592"}.fa-quote-left-alt:before,.fa-quote-left:before{content:"\f10d"}.fa-tractor:before{content:"\f722"}.fa-trash-arrow-up:before,.fa-trash-restore:before{content:"\f829"}.fa-arrow-down-up-lock:before{content:"\e4b0"}.fa-lines-leaning:before{content:"\e51e"}.fa-ruler-combined:before{content:"\f546"}.fa-copyright:before{content:"\f1f9"}.fa-equals:before{content:"\3d"}.fa-blender:before{content:"\f517"}.fa-teeth:before{content:"\f62e"}.fa-ils:before,.fa-shekel-sign:before,.fa-shekel:before,.fa-sheqel-sign:before,.fa-sheqel:before{content:"\f20b"}.fa-map:before{content:"\f279"}.fa-rocket:before{content:"\f135"}.fa-photo-film:before,.fa-photo-video:before{content:"\f87c"}.fa-folder-minus:before{content:"\f65d"}.fa-store:before{content:"\f54e"}.fa-arrow-trend-up:before{content:"\e098"}.fa-plug-circle-minus:before{content:"\e55e"}.fa-sign-hanging:before,.fa-sign:before{content:"\f4d9"}.fa-bezier-curve:before{content:"\f55b"}.fa-bell-slash:before{content:"\f1f6"}.fa-tablet-android:before,.fa-tablet:before{content:"\f3fb"}.fa-school-flag:before{content:"\e56e"}.fa-fill:before{content:"\f575"}.fa-angle-up:before{content:"\f106"}.fa-drumstick-bite:before{content:"\f6d7"}.fa-holly-berry:before{content:"\f7aa"}.fa-chevron-left:before{content:"\f053"}.fa-bacteria:before{content:"\e059"}.fa-hand-lizard:before{content:"\f258"}.fa-notdef:before{content:"\e1fe"}.fa-disease:before{content:"\f7fa"}.fa-briefcase-medical:before{content:"\f469"}.fa-genderless:before{content:"\f22d"}.fa-chevron-right:before{content:"\f054"}.fa-retweet:before{content:"\f079"}.fa-car-alt:before,.fa-car-rear:before{content:"\f5de"}.fa-pump-soap:before{content:"\e06b"}.fa-video-slash:before{content:"\f4e2"}.fa-battery-2:before,.fa-battery-quarter:before{content:"\f243"}.fa-radio:before{content:"\f8d7"}.fa-baby-carriage:before,.fa-carriage-baby:before{content:"\f77d"}.fa-traffic-light:before{content:"\f637"}.fa-thermometer:before{content:"\f491"}.fa-vr-cardboard:before{content:"\f729"}.fa-hand-middle-finger:before{content:"\f806"}.fa-percent:before,.fa-percentage:before{content:"\25"}.fa-truck-moving:before{content:"\f4df"}.fa-glass-water-droplet:before{content:"\e4f5"}.fa-display:before{content:"\e163"}.fa-face-smile:before,.fa-smile:before{content:"\f118"}.fa-thumb-tack:before,.fa-thumbtack:before{content:"\f08d"}.fa-trophy:before{content:"\f091"}.fa-person-praying:before,.fa-pray:before{content:"\f683"}.fa-hammer:before{content:"\f6e3"}.fa-hand-peace:before{content:"\f25b"}.fa-rotate:before,.fa-sync-alt:before{content:"\f2f1"}.fa-spinner:before{content:"\f110"}.fa-robot:before{content:"\f544"}.fa-peace:before{content:"\f67c"}.fa-cogs:before,.fa-gears:before{content:"\f085"}.fa-warehouse:before{content:"\f494"}.fa-arrow-up-right-dots:before{content:"\e4b7"}.fa-splotch:before{content:"\f5bc"}.fa-face-grin-hearts:before,.fa-grin-hearts:before{content:"\f584"}.fa-dice-four:before{content:"\f524"}.fa-sim-card:before{content:"\f7c4"}.fa-transgender-alt:before,.fa-transgender:before{content:"\f225"}.fa-mercury:before{content:"\f223"}.fa-arrow-turn-down:before,.fa-level-down:before{content:"\f149"}.fa-person-falling-burst:before{content:"\e547"}.fa-award:before{content:"\f559"}.fa-ticket-alt:before,.fa-ticket-simple:before{content:"\f3ff"}.fa-building:before{content:"\f1ad"}.fa-angle-double-left:before,.fa-angles-left:before{content:"\f100"}.fa-qrcode:before{content:"\f029"}.fa-clock-rotate-left:before,.fa-history:before{content:"\f1da"}.fa-face-grin-beam-sweat:before,.fa-grin-beam-sweat:before{content:"\f583"}.fa-arrow-right-from-file:before,.fa-file-export:before{content:"\f56e"}.fa-shield-blank:before,.fa-shield:before{content:"\f132"}.fa-arrow-up-short-wide:before,.fa-sort-amount-up-alt:before{content:"\f885"}.fa-house-medical:before{content:"\e3b2"}.fa-golf-ball-tee:before,.fa-golf-ball:before{content:"\f450"}.fa-chevron-circle-left:before,.fa-circle-chevron-left:before{content:"\f137"}.fa-house-chimney-window:before{content:"\e00d"}.fa-pen-nib:before{content:"\f5ad"}.fa-tent-arrow-turn-left:before{content:"\e580"}.fa-tents:before{content:"\e582"}.fa-magic:before,.fa-wand-magic:before{content:"\f0d0"}.fa-dog:before{content:"\f6d3"}.fa-carrot:before{content:"\f787"}.fa-moon:before{content:"\f186"}.fa-wine-glass-alt:before,.fa-wine-glass-empty:before{content:"\f5ce"}.fa-cheese:before{content:"\f7ef"}.fa-yin-yang:before{content:"\f6ad"}.fa-music:before{content:"\f001"}.fa-code-commit:before{content:"\f386"}.fa-temperature-low:before{content:"\f76b"}.fa-biking:before,.fa-person-biking:before{content:"\f84a"}.fa-broom:before{content:"\f51a"}.fa-shield-heart:before{content:"\e574"}.fa-gopuram:before{content:"\f664"}.fa-earth-oceania:before,.fa-globe-oceania:before{content:"\e47b"}.fa-square-xmark:before,.fa-times-square:before,.fa-xmark-square:before{content:"\f2d3"}.fa-hashtag:before{content:"\23"}.fa-expand-alt:before,.fa-up-right-and-down-left-from-center:before{content:"\f424"}.fa-oil-can:before{content:"\f613"}.fa-t:before{content:"\54"}.fa-hippo:before{content:"\f6ed"}.fa-chart-column:before{content:"\e0e3"}.fa-infinity:before{content:"\f534"}.fa-vial-circle-check:before{content:"\e596"}.fa-person-arrow-down-to-line:before{content:"\e538"}.fa-voicemail:before{content:"\f897"}.fa-fan:before{content:"\f863"}.fa-person-walking-luggage:before{content:"\e554"}.fa-arrows-alt-v:before,.fa-up-down:before{content:"\f338"}.fa-cloud-moon-rain:before{content:"\f73c"}.fa-calendar:before{content:"\f133"}.fa-trailer:before{content:"\e041"}.fa-bahai:before,.fa-haykal:before{content:"\f666"}.fa-sd-card:before{content:"\f7c2"}.fa-dragon:before{content:"\f6d5"}.fa-shoe-prints:before{content:"\f54b"}.fa-circle-plus:before,.fa-plus-circle:before{content:"\f055"}.fa-face-grin-tongue-wink:before,.fa-grin-tongue-wink:before{content:"\f58b"}.fa-hand-holding:before{content:"\f4bd"}.fa-plug-circle-exclamation:before{content:"\e55d"}.fa-chain-broken:before,.fa-chain-slash:before,.fa-link-slash:before,.fa-unlink:before{content:"\f127"}.fa-clone:before{content:"\f24d"}.fa-person-walking-arrow-loop-left:before{content:"\e551"}.fa-arrow-up-z-a:before,.fa-sort-alpha-up-alt:before{content:"\f882"}.fa-fire-alt:before,.fa-fire-flame-curved:before{content:"\f7e4"}.fa-tornado:before{content:"\f76f"}.fa-file-circle-plus:before{content:"\e494"}.fa-book-quran:before,.fa-quran:before{content:"\f687"}.fa-anchor:before{content:"\f13d"}.fa-border-all:before{content:"\f84c"}.fa-angry:before,.fa-face-angry:before{content:"\f556"}.fa-cookie-bite:before{content:"\f564"}.fa-arrow-trend-down:before{content:"\e097"}.fa-feed:before,.fa-rss:before{content:"\f09e"}.fa-draw-polygon:before{content:"\f5ee"}.fa-balance-scale:before,.fa-scale-balanced:before{content:"\f24e"}.fa-gauge-simple-high:before,.fa-tachometer-fast:before,.fa-tachometer:before{content:"\f62a"}.fa-shower:before{content:"\f2cc"}.fa-desktop-alt:before,.fa-desktop:before{content:"\f390"}.fa-m:before{content:"\4d"}.fa-table-list:before,.fa-th-list:before{content:"\f00b"}.fa-comment-sms:before,.fa-sms:before{content:"\f7cd"}.fa-book:before{content:"\f02d"}.fa-user-plus:before{content:"\f234"}.fa-check:before{content:"\f00c"}.fa-battery-4:before,.fa-battery-three-quarters:before{content:"\f241"}.fa-house-circle-check:before{content:"\e509"}.fa-angle-left:before{content:"\f104"}.fa-diagram-successor:before{content:"\e47a"}.fa-truck-arrow-right:before{content:"\e58b"}.fa-arrows-split-up-and-left:before{content:"\e4bc"}.fa-fist-raised:before,.fa-hand-fist:before{content:"\f6de"}.fa-cloud-moon:before{content:"\f6c3"}.fa-briefcase:before{content:"\f0b1"}.fa-person-falling:before{content:"\e546"}.fa-image-portrait:before,.fa-portrait:before{content:"\f3e0"}.fa-user-tag:before{content:"\f507"}.fa-rug:before{content:"\e569"}.fa-earth-europe:before,.fa-globe-europe:before{content:"\f7a2"}.fa-cart-flatbed-suitcase:before,.fa-luggage-cart:before{content:"\f59d"}.fa-rectangle-times:before,.fa-rectangle-xmark:before,.fa-times-rectangle:before,.fa-window-close:before{content:"\f410"}.fa-baht-sign:before{content:"\e0ac"}.fa-book-open:before{content:"\f518"}.fa-book-journal-whills:before,.fa-journal-whills:before{content:"\f66a"}.fa-handcuffs:before{content:"\e4f8"}.fa-exclamation-triangle:before,.fa-triangle-exclamation:before,.fa-warning:before{content:"\f071"}.fa-database:before{content:"\f1c0"}.fa-arrow-turn-right:before,.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-bottle-droplet:before{content:"\e4c4"}.fa-mask-face:before{content:"\e1d7"}.fa-hill-rockslide:before{content:"\e508"}.fa-exchange-alt:before,.fa-right-left:before{content:"\f362"}.fa-paper-plane:before{content:"\f1d8"}.fa-road-circle-exclamation:before{content:"\e565"}.fa-dungeon:before{content:"\f6d9"}.fa-align-right:before{content:"\f038"}.fa-money-bill-1-wave:before,.fa-money-bill-wave-alt:before{content:"\f53b"}.fa-life-ring:before{content:"\f1cd"}.fa-hands:before,.fa-sign-language:before,.fa-signing:before{content:"\f2a7"}.fa-calendar-day:before{content:"\f783"}.fa-ladder-water:before,.fa-swimming-pool:before,.fa-water-ladder:before{content:"\f5c5"}.fa-arrows-up-down:before,.fa-arrows-v:before{content:"\f07d"}.fa-face-grimace:before,.fa-grimace:before{content:"\f57f"}.fa-wheelchair-alt:before,.fa-wheelchair-move:before{content:"\e2ce"}.fa-level-down-alt:before,.fa-turn-down:before{content:"\f3be"}.fa-person-walking-arrow-right:before{content:"\e552"}.fa-envelope-square:before,.fa-square-envelope:before{content:"\f199"}.fa-dice:before{content:"\f522"}.fa-bowling-ball:before{content:"\f436"}.fa-brain:before{content:"\f5dc"}.fa-band-aid:before,.fa-bandage:before{content:"\f462"}.fa-calendar-minus:before{content:"\f272"}.fa-circle-xmark:before,.fa-times-circle:before,.fa-xmark-circle:before{content:"\f057"}.fa-gifts:before{content:"\f79c"}.fa-hotel:before{content:"\f594"}.fa-earth-asia:before,.fa-globe-asia:before{content:"\f57e"}.fa-id-card-alt:before,.fa-id-card-clip:before{content:"\f47f"}.fa-magnifying-glass-plus:before,.fa-search-plus:before{content:"\f00e"}.fa-thumbs-up:before{content:"\f164"}.fa-user-clock:before{content:"\f4fd"}.fa-allergies:before,.fa-hand-dots:before{content:"\f461"}.fa-file-invoice:before{content:"\f570"}.fa-window-minimize:before{content:"\f2d1"}.fa-coffee:before,.fa-mug-saucer:before{content:"\f0f4"}.fa-brush:before{content:"\f55d"}.fa-mask:before{content:"\f6fa"}.fa-magnifying-glass-minus:before,.fa-search-minus:before{content:"\f010"}.fa-ruler-vertical:before{content:"\f548"}.fa-user-alt:before,.fa-user-large:before{content:"\f406"}.fa-train-tram:before{content:"\e5b4"}.fa-user-nurse:before{content:"\f82f"}.fa-syringe:before{content:"\f48e"}.fa-cloud-sun:before{content:"\f6c4"}.fa-stopwatch-20:before{content:"\e06f"}.fa-square-full:before{content:"\f45c"}.fa-magnet:before{content:"\f076"}.fa-jar:before{content:"\e516"}.fa-note-sticky:before,.fa-sticky-note:before{content:"\f249"}.fa-bug-slash:before{content:"\e490"}.fa-arrow-up-from-water-pump:before{content:"\e4b6"}.fa-bone:before{content:"\f5d7"}.fa-user-injured:before{content:"\f728"}.fa-face-sad-tear:before,.fa-sad-tear:before{content:"\f5b4"}.fa-plane:before{content:"\f072"}.fa-tent-arrows-down:before{content:"\e581"}.fa-exclamation:before{content:"\21"}.fa-arrows-spin:before{content:"\e4bb"}.fa-print:before{content:"\f02f"}.fa-try:before,.fa-turkish-lira-sign:before,.fa-turkish-lira:before{content:"\e2bb"}.fa-dollar-sign:before,.fa-dollar:before,.fa-usd:before{content:"\24"}.fa-x:before{content:"\58"}.fa-magnifying-glass-dollar:before,.fa-search-dollar:before{content:"\f688"}.fa-users-cog:before,.fa-users-gear:before{content:"\f509"}.fa-person-military-pointing:before{content:"\e54a"}.fa-bank:before,.fa-building-columns:before,.fa-institution:before,.fa-museum:before,.fa-university:before{content:"\f19c"}.fa-umbrella:before{content:"\f0e9"}.fa-trowel:before{content:"\e589"}.fa-d:before{content:"\44"}.fa-stapler:before{content:"\e5af"}.fa-masks-theater:before,.fa-theater-masks:before{content:"\f630"}.fa-kip-sign:before{content:"\e1c4"}.fa-hand-point-left:before{content:"\f0a5"}.fa-handshake-alt:before,.fa-handshake-simple:before{content:"\f4c6"}.fa-fighter-jet:before,.fa-jet-fighter:before{content:"\f0fb"}.fa-share-alt-square:before,.fa-square-share-nodes:before{content:"\f1e1"}.fa-barcode:before{content:"\f02a"}.fa-plus-minus:before{content:"\e43c"}.fa-video-camera:before,.fa-video:before{content:"\f03d"}.fa-graduation-cap:before,.fa-mortar-board:before{content:"\f19d"}.fa-hand-holding-medical:before{content:"\e05c"}.fa-person-circle-check:before{content:"\e53e"}.fa-level-up-alt:before,.fa-turn-up:before{content:"\f3bf"}
+.fa-sr-only,.fa-sr-only-focusable:not(:focus),.sr-only,.sr-only-focusable:not(:focus){position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}:host,:root{--fa-style-family-brands:"Font Awesome 6 Brands";--fa-font-brands:normal 400 1em/1 "Font Awesome 6 Brands"}@font-face{font-family:"Font Awesome 6 Brands";font-style:normal;font-weight:400;font-display:block;src:url(../webfonts/fa-brands-400.woff2) format("woff2"),url(../webfonts/fa-brands-400.ttf) format("truetype")}.fa-brands,.fab{font-weight:400}.fa-monero:before{content:"\f3d0"}.fa-hooli:before{content:"\f427"}.fa-yelp:before{content:"\f1e9"}.fa-cc-visa:before{content:"\f1f0"}.fa-lastfm:before{content:"\f202"}.fa-shopware:before{content:"\f5b5"}.fa-creative-commons-nc:before{content:"\f4e8"}.fa-aws:before{content:"\f375"}.fa-redhat:before{content:"\f7bc"}.fa-yoast:before{content:"\f2b1"}.fa-cloudflare:before{content:"\e07d"}.fa-ups:before{content:"\f7e0"}.fa-wpexplorer:before{content:"\f2de"}.fa-dyalog:before{content:"\f399"}.fa-bity:before{content:"\f37a"}.fa-stackpath:before{content:"\f842"}.fa-buysellads:before{content:"\f20d"}.fa-first-order:before{content:"\f2b0"}.fa-modx:before{content:"\f285"}.fa-guilded:before{content:"\e07e"}.fa-vnv:before{content:"\f40b"}.fa-js-square:before,.fa-square-js:before{content:"\f3b9"}.fa-microsoft:before{content:"\f3ca"}.fa-qq:before{content:"\f1d6"}.fa-orcid:before{content:"\f8d2"}.fa-java:before{content:"\f4e4"}.fa-invision:before{content:"\f7b0"}.fa-creative-commons-pd-alt:before{content:"\f4ed"}.fa-centercode:before{content:"\f380"}.fa-glide-g:before{content:"\f2a6"}.fa-drupal:before{content:"\f1a9"}.fa-hire-a-helper:before{content:"\f3b0"}.fa-creative-commons-by:before{content:"\f4e7"}.fa-unity:before{content:"\e049"}.fa-whmcs:before{content:"\f40d"}.fa-rocketchat:before{content:"\f3e8"}.fa-vk:before{content:"\f189"}.fa-untappd:before{content:"\f405"}.fa-mailchimp:before{content:"\f59e"}.fa-css3-alt:before{content:"\f38b"}.fa-reddit-square:before,.fa-square-reddit:before{content:"\f1a2"}.fa-vimeo-v:before{content:"\f27d"}.fa-contao:before{content:"\f26d"}.fa-square-font-awesome:before{content:"\e5ad"}.fa-deskpro:before{content:"\f38f"}.fa-sistrix:before{content:"\f3ee"}.fa-instagram-square:before,.fa-square-instagram:before{content:"\e055"}.fa-battle-net:before{content:"\f835"}.fa-the-red-yeti:before{content:"\f69d"}.fa-hacker-news-square:before,.fa-square-hacker-news:before{content:"\f3af"}.fa-edge:before{content:"\f282"}.fa-napster:before{content:"\f3d2"}.fa-snapchat-square:before,.fa-square-snapchat:before{content:"\f2ad"}.fa-google-plus-g:before{content:"\f0d5"}.fa-artstation:before{content:"\f77a"}.fa-markdown:before{content:"\f60f"}.fa-sourcetree:before{content:"\f7d3"}.fa-google-plus:before{content:"\f2b3"}.fa-diaspora:before{content:"\f791"}.fa-foursquare:before{content:"\f180"}.fa-stack-overflow:before{content:"\f16c"}.fa-github-alt:before{content:"\f113"}.fa-phoenix-squadron:before{content:"\f511"}.fa-pagelines:before{content:"\f18c"}.fa-algolia:before{content:"\f36c"}.fa-red-river:before{content:"\f3e3"}.fa-creative-commons-sa:before{content:"\f4ef"}.fa-safari:before{content:"\f267"}.fa-google:before{content:"\f1a0"}.fa-font-awesome-alt:before,.fa-square-font-awesome-stroke:before{content:"\f35c"}.fa-atlassian:before{content:"\f77b"}.fa-linkedin-in:before{content:"\f0e1"}.fa-digital-ocean:before{content:"\f391"}.fa-nimblr:before{content:"\f5a8"}.fa-chromecast:before{content:"\f838"}.fa-evernote:before{content:"\f839"}.fa-hacker-news:before{content:"\f1d4"}.fa-creative-commons-sampling:before{content:"\f4f0"}.fa-adversal:before{content:"\f36a"}.fa-creative-commons:before{content:"\f25e"}.fa-watchman-monitoring:before{content:"\e087"}.fa-fonticons:before{content:"\f280"}.fa-weixin:before{content:"\f1d7"}.fa-shirtsinbulk:before{content:"\f214"}.fa-codepen:before{content:"\f1cb"}.fa-git-alt:before{content:"\f841"}.fa-lyft:before{content:"\f3c3"}.fa-rev:before{content:"\f5b2"}.fa-windows:before{content:"\f17a"}.fa-wizards-of-the-coast:before{content:"\f730"}.fa-square-viadeo:before,.fa-viadeo-square:before{content:"\f2aa"}.fa-meetup:before{content:"\f2e0"}.fa-centos:before{content:"\f789"}.fa-adn:before{content:"\f170"}.fa-cloudsmith:before{content:"\f384"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-dribbble-square:before,.fa-square-dribbble:before{content:"\f397"}.fa-codiepie:before{content:"\f284"}.fa-node:before{content:"\f419"}.fa-mix:before{content:"\f3cb"}.fa-steam:before{content:"\f1b6"}.fa-cc-apple-pay:before{content:"\f416"}.fa-scribd:before{content:"\f28a"}.fa-openid:before{content:"\f19b"}.fa-instalod:before{content:"\e081"}.fa-expeditedssl:before{content:"\f23e"}.fa-sellcast:before{content:"\f2da"}.fa-square-twitter:before,.fa-twitter-square:before{content:"\f081"}.fa-r-project:before{content:"\f4f7"}.fa-delicious:before{content:"\f1a5"}.fa-freebsd:before{content:"\f3a4"}.fa-vuejs:before{content:"\f41f"}.fa-accusoft:before{content:"\f369"}.fa-ioxhost:before{content:"\f208"}.fa-fonticons-fi:before{content:"\f3a2"}.fa-app-store:before{content:"\f36f"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-itunes-note:before{content:"\f3b5"}.fa-golang:before{content:"\e40f"}.fa-kickstarter:before{content:"\f3bb"}.fa-grav:before{content:"\f2d6"}.fa-weibo:before{content:"\f18a"}.fa-uncharted:before{content:"\e084"}.fa-firstdraft:before{content:"\f3a1"}.fa-square-youtube:before,.fa-youtube-square:before{content:"\f431"}.fa-wikipedia-w:before{content:"\f266"}.fa-rendact:before,.fa-wpressr:before{content:"\f3e4"}.fa-angellist:before{content:"\f209"}.fa-galactic-republic:before{content:"\f50c"}.fa-nfc-directional:before{content:"\e530"}.fa-skype:before{content:"\f17e"}.fa-joget:before{content:"\f3b7"}.fa-fedora:before{content:"\f798"}.fa-stripe-s:before{content:"\f42a"}.fa-meta:before{content:"\e49b"}.fa-laravel:before{content:"\f3bd"}.fa-hotjar:before{content:"\f3b1"}.fa-bluetooth-b:before{content:"\f294"}.fa-sticker-mule:before{content:"\f3f7"}.fa-creative-commons-zero:before{content:"\f4f3"}.fa-hips:before{content:"\f452"}.fa-behance:before{content:"\f1b4"}.fa-reddit:before{content:"\f1a1"}.fa-discord:before{content:"\f392"}.fa-chrome:before{content:"\f268"}.fa-app-store-ios:before{content:"\f370"}.fa-cc-discover:before{content:"\f1f2"}.fa-wpbeginner:before{content:"\f297"}.fa-confluence:before{content:"\f78d"}.fa-mdb:before{content:"\f8ca"}.fa-dochub:before{content:"\f394"}.fa-accessible-icon:before{content:"\f368"}.fa-ebay:before{content:"\f4f4"}.fa-amazon:before{content:"\f270"}.fa-unsplash:before{content:"\e07c"}.fa-yarn:before{content:"\f7e3"}.fa-square-steam:before,.fa-steam-square:before{content:"\f1b7"}.fa-500px:before{content:"\f26e"}.fa-square-vimeo:before,.fa-vimeo-square:before{content:"\f194"}.fa-asymmetrik:before{content:"\f372"}.fa-font-awesome-flag:before,.fa-font-awesome-logo-full:before,.fa-font-awesome:before{content:"\f2b4"}.fa-gratipay:before{content:"\f184"}.fa-apple:before{content:"\f179"}.fa-hive:before{content:"\e07f"}.fa-gitkraken:before{content:"\f3a6"}.fa-keybase:before{content:"\f4f5"}.fa-apple-pay:before{content:"\f415"}.fa-padlet:before{content:"\e4a0"}.fa-amazon-pay:before{content:"\f42c"}.fa-github-square:before,.fa-square-github:before{content:"\f092"}.fa-stumbleupon:before{content:"\f1a4"}.fa-fedex:before{content:"\f797"}.fa-phoenix-framework:before{content:"\f3dc"}.fa-shopify:before{content:"\e057"}.fa-neos:before{content:"\f612"}.fa-hackerrank:before{content:"\f5f7"}.fa-researchgate:before{content:"\f4f8"}.fa-swift:before{content:"\f8e1"}.fa-angular:before{content:"\f420"}.fa-speakap:before{content:"\f3f3"}.fa-angrycreative:before{content:"\f36e"}.fa-y-combinator:before{content:"\f23b"}.fa-empire:before{content:"\f1d1"}.fa-envira:before{content:"\f299"}.fa-gitlab-square:before,.fa-square-gitlab:before{content:"\e5ae"}.fa-studiovinari:before{content:"\f3f8"}.fa-pied-piper:before{content:"\f2ae"}.fa-wordpress:before{content:"\f19a"}.fa-product-hunt:before{content:"\f288"}.fa-firefox:before{content:"\f269"}.fa-linode:before{content:"\f2b8"}.fa-goodreads:before{content:"\f3a8"}.fa-odnoklassniki-square:before,.fa-square-odnoklassniki:before{content:"\f264"}.fa-jsfiddle:before{content:"\f1cc"}.fa-sith:before{content:"\f512"}.fa-themeisle:before{content:"\f2b2"}.fa-page4:before{content:"\f3d7"}.fa-hashnode:before{content:"\e499"}.fa-react:before{content:"\f41b"}.fa-cc-paypal:before{content:"\f1f4"}.fa-squarespace:before{content:"\f5be"}.fa-cc-stripe:before{content:"\f1f5"}.fa-creative-commons-share:before{content:"\f4f2"}.fa-bitcoin:before{content:"\f379"}.fa-keycdn:before{content:"\f3ba"}.fa-opera:before{content:"\f26a"}.fa-itch-io:before{content:"\f83a"}.fa-umbraco:before{content:"\f8e8"}.fa-galactic-senate:before{content:"\f50d"}.fa-ubuntu:before{content:"\f7df"}.fa-draft2digital:before{content:"\f396"}.fa-stripe:before{content:"\f429"}.fa-houzz:before{content:"\f27c"}.fa-gg:before{content:"\f260"}.fa-dhl:before{content:"\f790"}.fa-pinterest-square:before,.fa-square-pinterest:before{content:"\f0d3"}.fa-xing:before{content:"\f168"}.fa-blackberry:before{content:"\f37b"}.fa-creative-commons-pd:before{content:"\f4ec"}.fa-playstation:before{content:"\f3df"}.fa-quinscape:before{content:"\f459"}.fa-less:before{content:"\f41d"}.fa-blogger-b:before{content:"\f37d"}.fa-opencart:before{content:"\f23d"}.fa-vine:before{content:"\f1ca"}.fa-paypal:before{content:"\f1ed"}.fa-gitlab:before{content:"\f296"}.fa-typo3:before{content:"\f42b"}.fa-reddit-alien:before{content:"\f281"}.fa-yahoo:before{content:"\f19e"}.fa-dailymotion:before{content:"\e052"}.fa-affiliatetheme:before{content:"\f36b"}.fa-pied-piper-pp:before{content:"\f1a7"}.fa-bootstrap:before{content:"\f836"}.fa-odnoklassniki:before{content:"\f263"}.fa-nfc-symbol:before{content:"\e531"}.fa-ethereum:before{content:"\f42e"}.fa-speaker-deck:before{content:"\f83c"}.fa-creative-commons-nc-eu:before{content:"\f4e9"}.fa-patreon:before{content:"\f3d9"}.fa-avianex:before{content:"\f374"}.fa-ello:before{content:"\f5f1"}.fa-gofore:before{content:"\f3a7"}.fa-bimobject:before{content:"\f378"}.fa-facebook-f:before{content:"\f39e"}.fa-google-plus-square:before,.fa-square-google-plus:before{content:"\f0d4"}.fa-mandalorian:before{content:"\f50f"}.fa-first-order-alt:before{content:"\f50a"}.fa-osi:before{content:"\f41a"}.fa-google-wallet:before{content:"\f1ee"}.fa-d-and-d-beyond:before{content:"\f6ca"}.fa-periscope:before{content:"\f3da"}.fa-fulcrum:before{content:"\f50b"}.fa-cloudscale:before{content:"\f383"}.fa-forumbee:before{content:"\f211"}.fa-mizuni:before{content:"\f3cc"}.fa-schlix:before{content:"\f3ea"}.fa-square-xing:before,.fa-xing-square:before{content:"\f169"}.fa-bandcamp:before{content:"\f2d5"}.fa-wpforms:before{content:"\f298"}.fa-cloudversify:before{content:"\f385"}.fa-usps:before{content:"\f7e1"}.fa-megaport:before{content:"\f5a3"}.fa-magento:before{content:"\f3c4"}.fa-spotify:before{content:"\f1bc"}.fa-optin-monster:before{content:"\f23c"}.fa-fly:before{content:"\f417"}.fa-aviato:before{content:"\f421"}.fa-itunes:before{content:"\f3b4"}.fa-cuttlefish:before{content:"\f38c"}.fa-blogger:before{content:"\f37c"}.fa-flickr:before{content:"\f16e"}.fa-viber:before{content:"\f409"}.fa-soundcloud:before{content:"\f1be"}.fa-digg:before{content:"\f1a6"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-symfony:before{content:"\f83d"}.fa-maxcdn:before{content:"\f136"}.fa-etsy:before{content:"\f2d7"}.fa-facebook-messenger:before{content:"\f39f"}.fa-audible:before{content:"\f373"}.fa-think-peaks:before{content:"\f731"}.fa-bilibili:before{content:"\e3d9"}.fa-erlang:before{content:"\f39d"}.fa-cotton-bureau:before{content:"\f89e"}.fa-dashcube:before{content:"\f210"}.fa-42-group:before,.fa-innosoft:before{content:"\e080"}.fa-stack-exchange:before{content:"\f18d"}.fa-elementor:before{content:"\f430"}.fa-pied-piper-square:before,.fa-square-pied-piper:before{content:"\e01e"}.fa-creative-commons-nd:before{content:"\f4eb"}.fa-palfed:before{content:"\f3d8"}.fa-superpowers:before{content:"\f2dd"}.fa-resolving:before{content:"\f3e7"}.fa-xbox:before{content:"\f412"}.fa-searchengin:before{content:"\f3eb"}.fa-tiktok:before{content:"\e07b"}.fa-facebook-square:before,.fa-square-facebook:before{content:"\f082"}.fa-renren:before{content:"\f18b"}.fa-linux:before{content:"\f17c"}.fa-glide:before{content:"\f2a5"}.fa-linkedin:before{content:"\f08c"}.fa-hubspot:before{content:"\f3b2"}.fa-deploydog:before{content:"\f38e"}.fa-twitch:before{content:"\f1e8"}.fa-ravelry:before{content:"\f2d9"}.fa-mixer:before{content:"\e056"}.fa-lastfm-square:before,.fa-square-lastfm:before{content:"\f203"}.fa-vimeo:before{content:"\f40a"}.fa-mendeley:before{content:"\f7b3"}.fa-uniregistry:before{content:"\f404"}.fa-figma:before{content:"\f799"}.fa-creative-commons-remix:before{content:"\f4ee"}.fa-cc-amazon-pay:before{content:"\f42d"}.fa-dropbox:before{content:"\f16b"}.fa-instagram:before{content:"\f16d"}.fa-cmplid:before{content:"\e360"}.fa-facebook:before{content:"\f09a"}.fa-gripfire:before{content:"\f3ac"}.fa-jedi-order:before{content:"\f50e"}.fa-uikit:before{content:"\f403"}.fa-fort-awesome-alt:before{content:"\f3a3"}.fa-phabricator:before{content:"\f3db"}.fa-ussunnah:before{content:"\f407"}.fa-earlybirds:before{content:"\f39a"}.fa-trade-federation:before{content:"\f513"}.fa-autoprefixer:before{content:"\f41c"}.fa-whatsapp:before{content:"\f232"}.fa-slideshare:before{content:"\f1e7"}.fa-google-play:before{content:"\f3ab"}.fa-viadeo:before{content:"\f2a9"}.fa-line:before{content:"\f3c0"}.fa-google-drive:before{content:"\f3aa"}.fa-servicestack:before{content:"\f3ec"}.fa-simplybuilt:before{content:"\f215"}.fa-bitbucket:before{content:"\f171"}.fa-imdb:before{content:"\f2d8"}.fa-deezer:before{content:"\e077"}.fa-raspberry-pi:before{content:"\f7bb"}.fa-jira:before{content:"\f7b1"}.fa-docker:before{content:"\f395"}.fa-screenpal:before{content:"\e570"}.fa-bluetooth:before{content:"\f293"}.fa-gitter:before{content:"\f426"}.fa-d-and-d:before{content:"\f38d"}.fa-microblog:before{content:"\e01a"}.fa-cc-diners-club:before{content:"\f24c"}.fa-gg-circle:before{content:"\f261"}.fa-pied-piper-hat:before{content:"\f4e5"}.fa-kickstarter-k:before{content:"\f3bc"}.fa-yandex:before{content:"\f413"}.fa-readme:before{content:"\f4d5"}.fa-html5:before{content:"\f13b"}.fa-sellsy:before{content:"\f213"}.fa-sass:before{content:"\f41e"}.fa-wirsindhandwerk:before,.fa-wsh:before{content:"\e2d0"}.fa-buromobelexperte:before{content:"\f37f"}.fa-salesforce:before{content:"\f83b"}.fa-octopus-deploy:before{content:"\e082"}.fa-medapps:before{content:"\f3c6"}.fa-ns8:before{content:"\f3d5"}.fa-pinterest-p:before{content:"\f231"}.fa-apper:before{content:"\f371"}.fa-fort-awesome:before{content:"\f286"}.fa-waze:before{content:"\f83f"}.fa-cc-jcb:before{content:"\f24b"}.fa-snapchat-ghost:before,.fa-snapchat:before{content:"\f2ab"}.fa-fantasy-flight-games:before{content:"\f6dc"}.fa-rust:before{content:"\e07a"}.fa-wix:before{content:"\f5cf"}.fa-behance-square:before,.fa-square-behance:before{content:"\f1b5"}.fa-supple:before{content:"\f3f9"}.fa-rebel:before{content:"\f1d0"}.fa-css3:before{content:"\f13c"}.fa-staylinked:before{content:"\f3f5"}.fa-kaggle:before{content:"\f5fa"}.fa-space-awesome:before{content:"\e5ac"}.fa-deviantart:before{content:"\f1bd"}.fa-cpanel:before{content:"\f388"}.fa-goodreads-g:before{content:"\f3a9"}.fa-git-square:before,.fa-square-git:before{content:"\f1d2"}.fa-square-tumblr:before,.fa-tumblr-square:before{content:"\f174"}.fa-trello:before{content:"\f181"}.fa-creative-commons-nc-jp:before{content:"\f4ea"}.fa-get-pocket:before{content:"\f265"}.fa-perbyte:before{content:"\e083"}.fa-grunt:before{content:"\f3ad"}.fa-weebly:before{content:"\f5cc"}.fa-connectdevelop:before{content:"\f20e"}.fa-leanpub:before{content:"\f212"}.fa-black-tie:before{content:"\f27e"}.fa-themeco:before{content:"\f5c6"}.fa-python:before{content:"\f3e2"}.fa-android:before{content:"\f17b"}.fa-bots:before{content:"\e340"}.fa-free-code-camp:before{content:"\f2c5"}.fa-hornbill:before{content:"\f592"}.fa-js:before{content:"\f3b8"}.fa-ideal:before{content:"\e013"}.fa-git:before{content:"\f1d3"}.fa-dev:before{content:"\f6cc"}.fa-sketch:before{content:"\f7c6"}.fa-yandex-international:before{content:"\f414"}.fa-cc-amex:before{content:"\f1f3"}.fa-uber:before{content:"\f402"}.fa-github:before{content:"\f09b"}.fa-php:before{content:"\f457"}.fa-alipay:before{content:"\f642"}.fa-youtube:before{content:"\f167"}.fa-skyatlas:before{content:"\f216"}.fa-firefox-browser:before{content:"\e007"}.fa-replyd:before{content:"\f3e6"}.fa-suse:before{content:"\f7d6"}.fa-jenkins:before{content:"\f3b6"}.fa-twitter:before{content:"\f099"}.fa-rockrms:before{content:"\f3e9"}.fa-pinterest:before{content:"\f0d2"}.fa-buffer:before{content:"\f837"}.fa-npm:before{content:"\f3d4"}.fa-yammer:before{content:"\f840"}.fa-btc:before{content:"\f15a"}.fa-dribbble:before{content:"\f17d"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-internet-explorer:before{content:"\f26b"}.fa-stubber:before{content:"\e5c7"}.fa-telegram-plane:before,.fa-telegram:before{content:"\f2c6"}.fa-old-republic:before{content:"\f510"}.fa-odysee:before{content:"\e5c6"}.fa-square-whatsapp:before,.fa-whatsapp-square:before{content:"\f40c"}.fa-node-js:before{content:"\f3d3"}.fa-edge-legacy:before{content:"\e078"}.fa-slack-hash:before,.fa-slack:before{content:"\f198"}.fa-medrt:before{content:"\f3c8"}.fa-usb:before{content:"\f287"}.fa-tumblr:before{content:"\f173"}.fa-vaadin:before{content:"\f408"}.fa-quora:before{content:"\f2c4"}.fa-reacteurope:before{content:"\f75d"}.fa-medium-m:before,.fa-medium:before{content:"\f23a"}.fa-amilia:before{content:"\f36d"}.fa-mixcloud:before{content:"\f289"}.fa-flipboard:before{content:"\f44d"}.fa-viacoin:before{content:"\f237"}.fa-critical-role:before{content:"\f6c9"}.fa-sitrox:before{content:"\e44a"}.fa-discourse:before{content:"\f393"}.fa-joomla:before{content:"\f1aa"}.fa-mastodon:before{content:"\f4f6"}.fa-airbnb:before{content:"\f834"}.fa-wolf-pack-battalion:before{content:"\f514"}.fa-buy-n-large:before{content:"\f8a6"}.fa-gulp:before{content:"\f3ae"}.fa-creative-commons-sampling-plus:before{content:"\f4f1"}.fa-strava:before{content:"\f428"}.fa-ember:before{content:"\f423"}.fa-canadian-maple-leaf:before{content:"\f785"}.fa-teamspeak:before{content:"\f4f9"}.fa-pushed:before{content:"\f3e1"}.fa-wordpress-simple:before{content:"\f411"}.fa-nutritionix:before{content:"\f3d6"}.fa-wodu:before{content:"\e088"}.fa-google-pay:before{content:"\e079"}.fa-intercom:before{content:"\f7af"}.fa-zhihu:before{content:"\f63f"}.fa-korvue:before{content:"\f42f"}.fa-pix:before{content:"\e43a"}.fa-steam-symbol:before{content:"\f3f6"}:host,:root{--fa-font-regular:normal 400 1em/1 "Font Awesome 6 Free"}@font-face{font-family:"Font Awesome 6 Free";font-style:normal;font-weight:400;font-display:block;src:url(../webfonts/fa-regular-400.woff2) format("woff2"),url(../webfonts/fa-regular-400.ttf) format("truetype")}.fa-regular,.far{font-weight:400}:host,:root{--fa-style-family-classic:"Font Awesome 6 Free";--fa-font-solid:normal 900 1em/1 "Font Awesome 6 Free"}@font-face{font-family:"Font Awesome 6 Free";font-style:normal;font-weight:900;font-display:block;src:url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.ttf) format("truetype")}.fa-solid,.fas{font-weight:900}@font-face{font-family:"Font Awesome 5 Brands";font-display:block;font-weight:400;src:url(../webfonts/fa-brands-400.woff2) format("woff2"),url(../webfonts/fa-brands-400.ttf) format("truetype")}@font-face{font-family:"Font Awesome 5 Free";font-display:block;font-weight:900;src:url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.ttf) format("truetype")}@font-face{font-family:"Font Awesome 5 Free";font-display:block;font-weight:400;src:url(../webfonts/fa-regular-400.woff2) format("woff2"),url(../webfonts/fa-regular-400.ttf) format("truetype")}@font-face{font-family:"FontAwesome";font-display:block;src:url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.ttf) format("truetype")}@font-face{font-family:"FontAwesome";font-display:block;src:url(../webfonts/fa-brands-400.woff2) format("woff2"),url(../webfonts/fa-brands-400.ttf) format("truetype")}@font-face{font-family:"FontAwesome";font-display:block;src:url(../webfonts/fa-regular-400.woff2) format("woff2"),url(../webfonts/fa-regular-400.ttf) format("truetype");unicode-range:u+f003,u+f006,u+f014,u+f016-f017,u+f01a-f01b,u+f01d,u+f022,u+f03e,u+f044,u+f046,u+f05c-f05d,u+f06e,u+f070,u+f087-f088,u+f08a,u+f094,u+f096-f097,u+f09d,u+f0a0,u+f0a2,u+f0a4-f0a7,u+f0c5,u+f0c7,u+f0e5-f0e6,u+f0eb,u+f0f6-f0f8,u+f10c,u+f114-f115,u+f118-f11a,u+f11c-f11d,u+f133,u+f147,u+f14e,u+f150-f152,u+f185-f186,u+f18e,u+f190-f192,u+f196,u+f1c1-f1c9,u+f1d9,u+f1db,u+f1e3,u+f1ea,u+f1f7,u+f1f9,u+f20a,u+f247-f248,u+f24a,u+f24d,u+f255-f25b,u+f25d,u+f271-f274,u+f278,u+f27b,u+f28c,u+f28e,u+f29c,u+f2b5,u+f2b7,u+f2ba,u+f2bc,u+f2be,u+f2c0-f2c1,u+f2c3,u+f2d0,u+f2d2,u+f2d4,u+f2dc}@font-face{font-family:"FontAwesome";font-display:block;src:url(../webfonts/fa-v4compatibility.woff2) format("woff2"),url(../webfonts/fa-v4compatibility.ttf) format("truetype");unicode-range:u+f041,u+f047,u+f065-f066,u+f07d-f07e,u+f080,u+f08b,u+f08e,u+f090,u+f09a,u+f0ac,u+f0ae,u+f0b2,u+f0d0,u+f0d6,u+f0e4,u+f0ec,u+f10a-f10b,u+f123,u+f13e,u+f148-f149,u+f14c,u+f156,u+f15e,u+f160-f161,u+f163,u+f175-f178,u+f195,u+f1f8,u+f219,u+f27a} \ No newline at end of file
diff --git a/40-abschlusspraesentation/assets/fontawesome/css/brands.css b/40-abschlusspraesentation/assets/fontawesome/css/brands.css
new file mode 100644
index 0000000..362acab
--- /dev/null
+++ b/40-abschlusspraesentation/assets/fontawesome/css/brands.css
@@ -0,0 +1,1522 @@
+/*!
+ * Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com
+ * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
+ * Copyright 2023 Fonticons, Inc.
+ */
+:root, :host {
+ --fa-style-family-brands: 'Font Awesome 6 Brands';
+ --fa-font-brands: normal 400 1em/1 'Font Awesome 6 Brands'; }
+
+@font-face {
+ font-family: 'Font Awesome 6 Brands';
+ font-style: normal;
+ font-weight: 400;
+ font-display: block;
+ src: url("../webfonts/fa-brands-400.woff2") format("woff2"), url("../webfonts/fa-brands-400.ttf") format("truetype"); }
+
+.fab,
+.fa-brands {
+ font-weight: 400; }
+
+.fa-monero:before {
+ content: "\f3d0"; }
+
+.fa-hooli:before {
+ content: "\f427"; }
+
+.fa-yelp:before {
+ content: "\f1e9"; }
+
+.fa-cc-visa:before {
+ content: "\f1f0"; }
+
+.fa-lastfm:before {
+ content: "\f202"; }
+
+.fa-shopware:before {
+ content: "\f5b5"; }
+
+.fa-creative-commons-nc:before {
+ content: "\f4e8"; }
+
+.fa-aws:before {
+ content: "\f375"; }
+
+.fa-redhat:before {
+ content: "\f7bc"; }
+
+.fa-yoast:before {
+ content: "\f2b1"; }
+
+.fa-cloudflare:before {
+ content: "\e07d"; }
+
+.fa-ups:before {
+ content: "\f7e0"; }
+
+.fa-wpexplorer:before {
+ content: "\f2de"; }
+
+.fa-dyalog:before {
+ content: "\f399"; }
+
+.fa-bity:before {
+ content: "\f37a"; }
+
+.fa-stackpath:before {
+ content: "\f842"; }
+
+.fa-buysellads:before {
+ content: "\f20d"; }
+
+.fa-first-order:before {
+ content: "\f2b0"; }
+
+.fa-modx:before {
+ content: "\f285"; }
+
+.fa-guilded:before {
+ content: "\e07e"; }
+
+.fa-vnv:before {
+ content: "\f40b"; }
+
+.fa-square-js:before {
+ content: "\f3b9"; }
+
+.fa-js-square:before {
+ content: "\f3b9"; }
+
+.fa-microsoft:before {
+ content: "\f3ca"; }
+
+.fa-qq:before {
+ content: "\f1d6"; }
+
+.fa-orcid:before {
+ content: "\f8d2"; }
+
+.fa-java:before {
+ content: "\f4e4"; }
+
+.fa-invision:before {
+ content: "\f7b0"; }
+
+.fa-creative-commons-pd-alt:before {
+ content: "\f4ed"; }
+
+.fa-centercode:before {
+ content: "\f380"; }
+
+.fa-glide-g:before {
+ content: "\f2a6"; }
+
+.fa-drupal:before {
+ content: "\f1a9"; }
+
+.fa-hire-a-helper:before {
+ content: "\f3b0"; }
+
+.fa-creative-commons-by:before {
+ content: "\f4e7"; }
+
+.fa-unity:before {
+ content: "\e049"; }
+
+.fa-whmcs:before {
+ content: "\f40d"; }
+
+.fa-rocketchat:before {
+ content: "\f3e8"; }
+
+.fa-vk:before {
+ content: "\f189"; }
+
+.fa-untappd:before {
+ content: "\f405"; }
+
+.fa-mailchimp:before {
+ content: "\f59e"; }
+
+.fa-css3-alt:before {
+ content: "\f38b"; }
+
+.fa-square-reddit:before {
+ content: "\f1a2"; }
+
+.fa-reddit-square:before {
+ content: "\f1a2"; }
+
+.fa-vimeo-v:before {
+ content: "\f27d"; }
+
+.fa-contao:before {
+ content: "\f26d"; }
+
+.fa-square-font-awesome:before {
+ content: "\e5ad"; }
+
+.fa-deskpro:before {
+ content: "\f38f"; }
+
+.fa-sistrix:before {
+ content: "\f3ee"; }
+
+.fa-square-instagram:before {
+ content: "\e055"; }
+
+.fa-instagram-square:before {
+ content: "\e055"; }
+
+.fa-battle-net:before {
+ content: "\f835"; }
+
+.fa-the-red-yeti:before {
+ content: "\f69d"; }
+
+.fa-square-hacker-news:before {
+ content: "\f3af"; }
+
+.fa-hacker-news-square:before {
+ content: "\f3af"; }
+
+.fa-edge:before {
+ content: "\f282"; }
+
+.fa-napster:before {
+ content: "\f3d2"; }
+
+.fa-square-snapchat:before {
+ content: "\f2ad"; }
+
+.fa-snapchat-square:before {
+ content: "\f2ad"; }
+
+.fa-google-plus-g:before {
+ content: "\f0d5"; }
+
+.fa-artstation:before {
+ content: "\f77a"; }
+
+.fa-markdown:before {
+ content: "\f60f"; }
+
+.fa-sourcetree:before {
+ content: "\f7d3"; }
+
+.fa-google-plus:before {
+ content: "\f2b3"; }
+
+.fa-diaspora:before {
+ content: "\f791"; }
+
+.fa-foursquare:before {
+ content: "\f180"; }
+
+.fa-stack-overflow:before {
+ content: "\f16c"; }
+
+.fa-github-alt:before {
+ content: "\f113"; }
+
+.fa-phoenix-squadron:before {
+ content: "\f511"; }
+
+.fa-pagelines:before {
+ content: "\f18c"; }
+
+.fa-algolia:before {
+ content: "\f36c"; }
+
+.fa-red-river:before {
+ content: "\f3e3"; }
+
+.fa-creative-commons-sa:before {
+ content: "\f4ef"; }
+
+.fa-safari:before {
+ content: "\f267"; }
+
+.fa-google:before {
+ content: "\f1a0"; }
+
+.fa-square-font-awesome-stroke:before {
+ content: "\f35c"; }
+
+.fa-font-awesome-alt:before {
+ content: "\f35c"; }
+
+.fa-atlassian:before {
+ content: "\f77b"; }
+
+.fa-linkedin-in:before {
+ content: "\f0e1"; }
+
+.fa-digital-ocean:before {
+ content: "\f391"; }
+
+.fa-nimblr:before {
+ content: "\f5a8"; }
+
+.fa-chromecast:before {
+ content: "\f838"; }
+
+.fa-evernote:before {
+ content: "\f839"; }
+
+.fa-hacker-news:before {
+ content: "\f1d4"; }
+
+.fa-creative-commons-sampling:before {
+ content: "\f4f0"; }
+
+.fa-adversal:before {
+ content: "\f36a"; }
+
+.fa-creative-commons:before {
+ content: "\f25e"; }
+
+.fa-watchman-monitoring:before {
+ content: "\e087"; }
+
+.fa-fonticons:before {
+ content: "\f280"; }
+
+.fa-weixin:before {
+ content: "\f1d7"; }
+
+.fa-shirtsinbulk:before {
+ content: "\f214"; }
+
+.fa-codepen:before {
+ content: "\f1cb"; }
+
+.fa-git-alt:before {
+ content: "\f841"; }
+
+.fa-lyft:before {
+ content: "\f3c3"; }
+
+.fa-rev:before {
+ content: "\f5b2"; }
+
+.fa-windows:before {
+ content: "\f17a"; }
+
+.fa-wizards-of-the-coast:before {
+ content: "\f730"; }
+
+.fa-square-viadeo:before {
+ content: "\f2aa"; }
+
+.fa-viadeo-square:before {
+ content: "\f2aa"; }
+
+.fa-meetup:before {
+ content: "\f2e0"; }
+
+.fa-centos:before {
+ content: "\f789"; }
+
+.fa-adn:before {
+ content: "\f170"; }
+
+.fa-cloudsmith:before {
+ content: "\f384"; }
+
+.fa-pied-piper-alt:before {
+ content: "\f1a8"; }
+
+.fa-square-dribbble:before {
+ content: "\f397"; }
+
+.fa-dribbble-square:before {
+ content: "\f397"; }
+
+.fa-codiepie:before {
+ content: "\f284"; }
+
+.fa-node:before {
+ content: "\f419"; }
+
+.fa-mix:before {
+ content: "\f3cb"; }
+
+.fa-steam:before {
+ content: "\f1b6"; }
+
+.fa-cc-apple-pay:before {
+ content: "\f416"; }
+
+.fa-scribd:before {
+ content: "\f28a"; }
+
+.fa-openid:before {
+ content: "\f19b"; }
+
+.fa-instalod:before {
+ content: "\e081"; }
+
+.fa-expeditedssl:before {
+ content: "\f23e"; }
+
+.fa-sellcast:before {
+ content: "\f2da"; }
+
+.fa-square-twitter:before {
+ content: "\f081"; }
+
+.fa-twitter-square:before {
+ content: "\f081"; }
+
+.fa-r-project:before {
+ content: "\f4f7"; }
+
+.fa-delicious:before {
+ content: "\f1a5"; }
+
+.fa-freebsd:before {
+ content: "\f3a4"; }
+
+.fa-vuejs:before {
+ content: "\f41f"; }
+
+.fa-accusoft:before {
+ content: "\f369"; }
+
+.fa-ioxhost:before {
+ content: "\f208"; }
+
+.fa-fonticons-fi:before {
+ content: "\f3a2"; }
+
+.fa-app-store:before {
+ content: "\f36f"; }
+
+.fa-cc-mastercard:before {
+ content: "\f1f1"; }
+
+.fa-itunes-note:before {
+ content: "\f3b5"; }
+
+.fa-golang:before {
+ content: "\e40f"; }
+
+.fa-kickstarter:before {
+ content: "\f3bb"; }
+
+.fa-grav:before {
+ content: "\f2d6"; }
+
+.fa-weibo:before {
+ content: "\f18a"; }
+
+.fa-uncharted:before {
+ content: "\e084"; }
+
+.fa-firstdraft:before {
+ content: "\f3a1"; }
+
+.fa-square-youtube:before {
+ content: "\f431"; }
+
+.fa-youtube-square:before {
+ content: "\f431"; }
+
+.fa-wikipedia-w:before {
+ content: "\f266"; }
+
+.fa-wpressr:before {
+ content: "\f3e4"; }
+
+.fa-rendact:before {
+ content: "\f3e4"; }
+
+.fa-angellist:before {
+ content: "\f209"; }
+
+.fa-galactic-republic:before {
+ content: "\f50c"; }
+
+.fa-nfc-directional:before {
+ content: "\e530"; }
+
+.fa-skype:before {
+ content: "\f17e"; }
+
+.fa-joget:before {
+ content: "\f3b7"; }
+
+.fa-fedora:before {
+ content: "\f798"; }
+
+.fa-stripe-s:before {
+ content: "\f42a"; }
+
+.fa-meta:before {
+ content: "\e49b"; }
+
+.fa-laravel:before {
+ content: "\f3bd"; }
+
+.fa-hotjar:before {
+ content: "\f3b1"; }
+
+.fa-bluetooth-b:before {
+ content: "\f294"; }
+
+.fa-sticker-mule:before {
+ content: "\f3f7"; }
+
+.fa-creative-commons-zero:before {
+ content: "\f4f3"; }
+
+.fa-hips:before {
+ content: "\f452"; }
+
+.fa-behance:before {
+ content: "\f1b4"; }
+
+.fa-reddit:before {
+ content: "\f1a1"; }
+
+.fa-discord:before {
+ content: "\f392"; }
+
+.fa-chrome:before {
+ content: "\f268"; }
+
+.fa-app-store-ios:before {
+ content: "\f370"; }
+
+.fa-cc-discover:before {
+ content: "\f1f2"; }
+
+.fa-wpbeginner:before {
+ content: "\f297"; }
+
+.fa-confluence:before {
+ content: "\f78d"; }
+
+.fa-mdb:before {
+ content: "\f8ca"; }
+
+.fa-dochub:before {
+ content: "\f394"; }
+
+.fa-accessible-icon:before {
+ content: "\f368"; }
+
+.fa-ebay:before {
+ content: "\f4f4"; }
+
+.fa-amazon:before {
+ content: "\f270"; }
+
+.fa-unsplash:before {
+ content: "\e07c"; }
+
+.fa-yarn:before {
+ content: "\f7e3"; }
+
+.fa-square-steam:before {
+ content: "\f1b7"; }
+
+.fa-steam-square:before {
+ content: "\f1b7"; }
+
+.fa-500px:before {
+ content: "\f26e"; }
+
+.fa-square-vimeo:before {
+ content: "\f194"; }
+
+.fa-vimeo-square:before {
+ content: "\f194"; }
+
+.fa-asymmetrik:before {
+ content: "\f372"; }
+
+.fa-font-awesome:before {
+ content: "\f2b4"; }
+
+.fa-font-awesome-flag:before {
+ content: "\f2b4"; }
+
+.fa-font-awesome-logo-full:before {
+ content: "\f2b4"; }
+
+.fa-gratipay:before {
+ content: "\f184"; }
+
+.fa-apple:before {
+ content: "\f179"; }
+
+.fa-hive:before {
+ content: "\e07f"; }
+
+.fa-gitkraken:before {
+ content: "\f3a6"; }
+
+.fa-keybase:before {
+ content: "\f4f5"; }
+
+.fa-apple-pay:before {
+ content: "\f415"; }
+
+.fa-padlet:before {
+ content: "\e4a0"; }
+
+.fa-amazon-pay:before {
+ content: "\f42c"; }
+
+.fa-square-github:before {
+ content: "\f092"; }
+
+.fa-github-square:before {
+ content: "\f092"; }
+
+.fa-stumbleupon:before {
+ content: "\f1a4"; }
+
+.fa-fedex:before {
+ content: "\f797"; }
+
+.fa-phoenix-framework:before {
+ content: "\f3dc"; }
+
+.fa-shopify:before {
+ content: "\e057"; }
+
+.fa-neos:before {
+ content: "\f612"; }
+
+.fa-hackerrank:before {
+ content: "\f5f7"; }
+
+.fa-researchgate:before {
+ content: "\f4f8"; }
+
+.fa-swift:before {
+ content: "\f8e1"; }
+
+.fa-angular:before {
+ content: "\f420"; }
+
+.fa-speakap:before {
+ content: "\f3f3"; }
+
+.fa-angrycreative:before {
+ content: "\f36e"; }
+
+.fa-y-combinator:before {
+ content: "\f23b"; }
+
+.fa-empire:before {
+ content: "\f1d1"; }
+
+.fa-envira:before {
+ content: "\f299"; }
+
+.fa-square-gitlab:before {
+ content: "\e5ae"; }
+
+.fa-gitlab-square:before {
+ content: "\e5ae"; }
+
+.fa-studiovinari:before {
+ content: "\f3f8"; }
+
+.fa-pied-piper:before {
+ content: "\f2ae"; }
+
+.fa-wordpress:before {
+ content: "\f19a"; }
+
+.fa-product-hunt:before {
+ content: "\f288"; }
+
+.fa-firefox:before {
+ content: "\f269"; }
+
+.fa-linode:before {
+ content: "\f2b8"; }
+
+.fa-goodreads:before {
+ content: "\f3a8"; }
+
+.fa-square-odnoklassniki:before {
+ content: "\f264"; }
+
+.fa-odnoklassniki-square:before {
+ content: "\f264"; }
+
+.fa-jsfiddle:before {
+ content: "\f1cc"; }
+
+.fa-sith:before {
+ content: "\f512"; }
+
+.fa-themeisle:before {
+ content: "\f2b2"; }
+
+.fa-page4:before {
+ content: "\f3d7"; }
+
+.fa-hashnode:before {
+ content: "\e499"; }
+
+.fa-react:before {
+ content: "\f41b"; }
+
+.fa-cc-paypal:before {
+ content: "\f1f4"; }
+
+.fa-squarespace:before {
+ content: "\f5be"; }
+
+.fa-cc-stripe:before {
+ content: "\f1f5"; }
+
+.fa-creative-commons-share:before {
+ content: "\f4f2"; }
+
+.fa-bitcoin:before {
+ content: "\f379"; }
+
+.fa-keycdn:before {
+ content: "\f3ba"; }
+
+.fa-opera:before {
+ content: "\f26a"; }
+
+.fa-itch-io:before {
+ content: "\f83a"; }
+
+.fa-umbraco:before {
+ content: "\f8e8"; }
+
+.fa-galactic-senate:before {
+ content: "\f50d"; }
+
+.fa-ubuntu:before {
+ content: "\f7df"; }
+
+.fa-draft2digital:before {
+ content: "\f396"; }
+
+.fa-stripe:before {
+ content: "\f429"; }
+
+.fa-houzz:before {
+ content: "\f27c"; }
+
+.fa-gg:before {
+ content: "\f260"; }
+
+.fa-dhl:before {
+ content: "\f790"; }
+
+.fa-square-pinterest:before {
+ content: "\f0d3"; }
+
+.fa-pinterest-square:before {
+ content: "\f0d3"; }
+
+.fa-xing:before {
+ content: "\f168"; }
+
+.fa-blackberry:before {
+ content: "\f37b"; }
+
+.fa-creative-commons-pd:before {
+ content: "\f4ec"; }
+
+.fa-playstation:before {
+ content: "\f3df"; }
+
+.fa-quinscape:before {
+ content: "\f459"; }
+
+.fa-less:before {
+ content: "\f41d"; }
+
+.fa-blogger-b:before {
+ content: "\f37d"; }
+
+.fa-opencart:before {
+ content: "\f23d"; }
+
+.fa-vine:before {
+ content: "\f1ca"; }
+
+.fa-paypal:before {
+ content: "\f1ed"; }
+
+.fa-gitlab:before {
+ content: "\f296"; }
+
+.fa-typo3:before {
+ content: "\f42b"; }
+
+.fa-reddit-alien:before {
+ content: "\f281"; }
+
+.fa-yahoo:before {
+ content: "\f19e"; }
+
+.fa-dailymotion:before {
+ content: "\e052"; }
+
+.fa-affiliatetheme:before {
+ content: "\f36b"; }
+
+.fa-pied-piper-pp:before {
+ content: "\f1a7"; }
+
+.fa-bootstrap:before {
+ content: "\f836"; }
+
+.fa-odnoklassniki:before {
+ content: "\f263"; }
+
+.fa-nfc-symbol:before {
+ content: "\e531"; }
+
+.fa-ethereum:before {
+ content: "\f42e"; }
+
+.fa-speaker-deck:before {
+ content: "\f83c"; }
+
+.fa-creative-commons-nc-eu:before {
+ content: "\f4e9"; }
+
+.fa-patreon:before {
+ content: "\f3d9"; }
+
+.fa-avianex:before {
+ content: "\f374"; }
+
+.fa-ello:before {
+ content: "\f5f1"; }
+
+.fa-gofore:before {
+ content: "\f3a7"; }
+
+.fa-bimobject:before {
+ content: "\f378"; }
+
+.fa-facebook-f:before {
+ content: "\f39e"; }
+
+.fa-square-google-plus:before {
+ content: "\f0d4"; }
+
+.fa-google-plus-square:before {
+ content: "\f0d4"; }
+
+.fa-mandalorian:before {
+ content: "\f50f"; }
+
+.fa-first-order-alt:before {
+ content: "\f50a"; }
+
+.fa-osi:before {
+ content: "\f41a"; }
+
+.fa-google-wallet:before {
+ content: "\f1ee"; }
+
+.fa-d-and-d-beyond:before {
+ content: "\f6ca"; }
+
+.fa-periscope:before {
+ content: "\f3da"; }
+
+.fa-fulcrum:before {
+ content: "\f50b"; }
+
+.fa-cloudscale:before {
+ content: "\f383"; }
+
+.fa-forumbee:before {
+ content: "\f211"; }
+
+.fa-mizuni:before {
+ content: "\f3cc"; }
+
+.fa-schlix:before {
+ content: "\f3ea"; }
+
+.fa-square-xing:before {
+ content: "\f169"; }
+
+.fa-xing-square:before {
+ content: "\f169"; }
+
+.fa-bandcamp:before {
+ content: "\f2d5"; }
+
+.fa-wpforms:before {
+ content: "\f298"; }
+
+.fa-cloudversify:before {
+ content: "\f385"; }
+
+.fa-usps:before {
+ content: "\f7e1"; }
+
+.fa-megaport:before {
+ content: "\f5a3"; }
+
+.fa-magento:before {
+ content: "\f3c4"; }
+
+.fa-spotify:before {
+ content: "\f1bc"; }
+
+.fa-optin-monster:before {
+ content: "\f23c"; }
+
+.fa-fly:before {
+ content: "\f417"; }
+
+.fa-aviato:before {
+ content: "\f421"; }
+
+.fa-itunes:before {
+ content: "\f3b4"; }
+
+.fa-cuttlefish:before {
+ content: "\f38c"; }
+
+.fa-blogger:before {
+ content: "\f37c"; }
+
+.fa-flickr:before {
+ content: "\f16e"; }
+
+.fa-viber:before {
+ content: "\f409"; }
+
+.fa-soundcloud:before {
+ content: "\f1be"; }
+
+.fa-digg:before {
+ content: "\f1a6"; }
+
+.fa-tencent-weibo:before {
+ content: "\f1d5"; }
+
+.fa-symfony:before {
+ content: "\f83d"; }
+
+.fa-maxcdn:before {
+ content: "\f136"; }
+
+.fa-etsy:before {
+ content: "\f2d7"; }
+
+.fa-facebook-messenger:before {
+ content: "\f39f"; }
+
+.fa-audible:before {
+ content: "\f373"; }
+
+.fa-think-peaks:before {
+ content: "\f731"; }
+
+.fa-bilibili:before {
+ content: "\e3d9"; }
+
+.fa-erlang:before {
+ content: "\f39d"; }
+
+.fa-cotton-bureau:before {
+ content: "\f89e"; }
+
+.fa-dashcube:before {
+ content: "\f210"; }
+
+.fa-42-group:before {
+ content: "\e080"; }
+
+.fa-innosoft:before {
+ content: "\e080"; }
+
+.fa-stack-exchange:before {
+ content: "\f18d"; }
+
+.fa-elementor:before {
+ content: "\f430"; }
+
+.fa-square-pied-piper:before {
+ content: "\e01e"; }
+
+.fa-pied-piper-square:before {
+ content: "\e01e"; }
+
+.fa-creative-commons-nd:before {
+ content: "\f4eb"; }
+
+.fa-palfed:before {
+ content: "\f3d8"; }
+
+.fa-superpowers:before {
+ content: "\f2dd"; }
+
+.fa-resolving:before {
+ content: "\f3e7"; }
+
+.fa-xbox:before {
+ content: "\f412"; }
+
+.fa-searchengin:before {
+ content: "\f3eb"; }
+
+.fa-tiktok:before {
+ content: "\e07b"; }
+
+.fa-square-facebook:before {
+ content: "\f082"; }
+
+.fa-facebook-square:before {
+ content: "\f082"; }
+
+.fa-renren:before {
+ content: "\f18b"; }
+
+.fa-linux:before {
+ content: "\f17c"; }
+
+.fa-glide:before {
+ content: "\f2a5"; }
+
+.fa-linkedin:before {
+ content: "\f08c"; }
+
+.fa-hubspot:before {
+ content: "\f3b2"; }
+
+.fa-deploydog:before {
+ content: "\f38e"; }
+
+.fa-twitch:before {
+ content: "\f1e8"; }
+
+.fa-ravelry:before {
+ content: "\f2d9"; }
+
+.fa-mixer:before {
+ content: "\e056"; }
+
+.fa-square-lastfm:before {
+ content: "\f203"; }
+
+.fa-lastfm-square:before {
+ content: "\f203"; }
+
+.fa-vimeo:before {
+ content: "\f40a"; }
+
+.fa-mendeley:before {
+ content: "\f7b3"; }
+
+.fa-uniregistry:before {
+ content: "\f404"; }
+
+.fa-figma:before {
+ content: "\f799"; }
+
+.fa-creative-commons-remix:before {
+ content: "\f4ee"; }
+
+.fa-cc-amazon-pay:before {
+ content: "\f42d"; }
+
+.fa-dropbox:before {
+ content: "\f16b"; }
+
+.fa-instagram:before {
+ content: "\f16d"; }
+
+.fa-cmplid:before {
+ content: "\e360"; }
+
+.fa-facebook:before {
+ content: "\f09a"; }
+
+.fa-gripfire:before {
+ content: "\f3ac"; }
+
+.fa-jedi-order:before {
+ content: "\f50e"; }
+
+.fa-uikit:before {
+ content: "\f403"; }
+
+.fa-fort-awesome-alt:before {
+ content: "\f3a3"; }
+
+.fa-phabricator:before {
+ content: "\f3db"; }
+
+.fa-ussunnah:before {
+ content: "\f407"; }
+
+.fa-earlybirds:before {
+ content: "\f39a"; }
+
+.fa-trade-federation:before {
+ content: "\f513"; }
+
+.fa-autoprefixer:before {
+ content: "\f41c"; }
+
+.fa-whatsapp:before {
+ content: "\f232"; }
+
+.fa-slideshare:before {
+ content: "\f1e7"; }
+
+.fa-google-play:before {
+ content: "\f3ab"; }
+
+.fa-viadeo:before {
+ content: "\f2a9"; }
+
+.fa-line:before {
+ content: "\f3c0"; }
+
+.fa-google-drive:before {
+ content: "\f3aa"; }
+
+.fa-servicestack:before {
+ content: "\f3ec"; }
+
+.fa-simplybuilt:before {
+ content: "\f215"; }
+
+.fa-bitbucket:before {
+ content: "\f171"; }
+
+.fa-imdb:before {
+ content: "\f2d8"; }
+
+.fa-deezer:before {
+ content: "\e077"; }
+
+.fa-raspberry-pi:before {
+ content: "\f7bb"; }
+
+.fa-jira:before {
+ content: "\f7b1"; }
+
+.fa-docker:before {
+ content: "\f395"; }
+
+.fa-screenpal:before {
+ content: "\e570"; }
+
+.fa-bluetooth:before {
+ content: "\f293"; }
+
+.fa-gitter:before {
+ content: "\f426"; }
+
+.fa-d-and-d:before {
+ content: "\f38d"; }
+
+.fa-microblog:before {
+ content: "\e01a"; }
+
+.fa-cc-diners-club:before {
+ content: "\f24c"; }
+
+.fa-gg-circle:before {
+ content: "\f261"; }
+
+.fa-pied-piper-hat:before {
+ content: "\f4e5"; }
+
+.fa-kickstarter-k:before {
+ content: "\f3bc"; }
+
+.fa-yandex:before {
+ content: "\f413"; }
+
+.fa-readme:before {
+ content: "\f4d5"; }
+
+.fa-html5:before {
+ content: "\f13b"; }
+
+.fa-sellsy:before {
+ content: "\f213"; }
+
+.fa-sass:before {
+ content: "\f41e"; }
+
+.fa-wirsindhandwerk:before {
+ content: "\e2d0"; }
+
+.fa-wsh:before {
+ content: "\e2d0"; }
+
+.fa-buromobelexperte:before {
+ content: "\f37f"; }
+
+.fa-salesforce:before {
+ content: "\f83b"; }
+
+.fa-octopus-deploy:before {
+ content: "\e082"; }
+
+.fa-medapps:before {
+ content: "\f3c6"; }
+
+.fa-ns8:before {
+ content: "\f3d5"; }
+
+.fa-pinterest-p:before {
+ content: "\f231"; }
+
+.fa-apper:before {
+ content: "\f371"; }
+
+.fa-fort-awesome:before {
+ content: "\f286"; }
+
+.fa-waze:before {
+ content: "\f83f"; }
+
+.fa-cc-jcb:before {
+ content: "\f24b"; }
+
+.fa-snapchat:before {
+ content: "\f2ab"; }
+
+.fa-snapchat-ghost:before {
+ content: "\f2ab"; }
+
+.fa-fantasy-flight-games:before {
+ content: "\f6dc"; }
+
+.fa-rust:before {
+ content: "\e07a"; }
+
+.fa-wix:before {
+ content: "\f5cf"; }
+
+.fa-square-behance:before {
+ content: "\f1b5"; }
+
+.fa-behance-square:before {
+ content: "\f1b5"; }
+
+.fa-supple:before {
+ content: "\f3f9"; }
+
+.fa-rebel:before {
+ content: "\f1d0"; }
+
+.fa-css3:before {
+ content: "\f13c"; }
+
+.fa-staylinked:before {
+ content: "\f3f5"; }
+
+.fa-kaggle:before {
+ content: "\f5fa"; }
+
+.fa-space-awesome:before {
+ content: "\e5ac"; }
+
+.fa-deviantart:before {
+ content: "\f1bd"; }
+
+.fa-cpanel:before {
+ content: "\f388"; }
+
+.fa-goodreads-g:before {
+ content: "\f3a9"; }
+
+.fa-square-git:before {
+ content: "\f1d2"; }
+
+.fa-git-square:before {
+ content: "\f1d2"; }
+
+.fa-square-tumblr:before {
+ content: "\f174"; }
+
+.fa-tumblr-square:before {
+ content: "\f174"; }
+
+.fa-trello:before {
+ content: "\f181"; }
+
+.fa-creative-commons-nc-jp:before {
+ content: "\f4ea"; }
+
+.fa-get-pocket:before {
+ content: "\f265"; }
+
+.fa-perbyte:before {
+ content: "\e083"; }
+
+.fa-grunt:before {
+ content: "\f3ad"; }
+
+.fa-weebly:before {
+ content: "\f5cc"; }
+
+.fa-connectdevelop:before {
+ content: "\f20e"; }
+
+.fa-leanpub:before {
+ content: "\f212"; }
+
+.fa-black-tie:before {
+ content: "\f27e"; }
+
+.fa-themeco:before {
+ content: "\f5c6"; }
+
+.fa-python:before {
+ content: "\f3e2"; }
+
+.fa-android:before {
+ content: "\f17b"; }
+
+.fa-bots:before {
+ content: "\e340"; }
+
+.fa-free-code-camp:before {
+ content: "\f2c5"; }
+
+.fa-hornbill:before {
+ content: "\f592"; }
+
+.fa-js:before {
+ content: "\f3b8"; }
+
+.fa-ideal:before {
+ content: "\e013"; }
+
+.fa-git:before {
+ content: "\f1d3"; }
+
+.fa-dev:before {
+ content: "\f6cc"; }
+
+.fa-sketch:before {
+ content: "\f7c6"; }
+
+.fa-yandex-international:before {
+ content: "\f414"; }
+
+.fa-cc-amex:before {
+ content: "\f1f3"; }
+
+.fa-uber:before {
+ content: "\f402"; }
+
+.fa-github:before {
+ content: "\f09b"; }
+
+.fa-php:before {
+ content: "\f457"; }
+
+.fa-alipay:before {
+ content: "\f642"; }
+
+.fa-youtube:before {
+ content: "\f167"; }
+
+.fa-skyatlas:before {
+ content: "\f216"; }
+
+.fa-firefox-browser:before {
+ content: "\e007"; }
+
+.fa-replyd:before {
+ content: "\f3e6"; }
+
+.fa-suse:before {
+ content: "\f7d6"; }
+
+.fa-jenkins:before {
+ content: "\f3b6"; }
+
+.fa-twitter:before {
+ content: "\f099"; }
+
+.fa-rockrms:before {
+ content: "\f3e9"; }
+
+.fa-pinterest:before {
+ content: "\f0d2"; }
+
+.fa-buffer:before {
+ content: "\f837"; }
+
+.fa-npm:before {
+ content: "\f3d4"; }
+
+.fa-yammer:before {
+ content: "\f840"; }
+
+.fa-btc:before {
+ content: "\f15a"; }
+
+.fa-dribbble:before {
+ content: "\f17d"; }
+
+.fa-stumbleupon-circle:before {
+ content: "\f1a3"; }
+
+.fa-internet-explorer:before {
+ content: "\f26b"; }
+
+.fa-stubber:before {
+ content: "\e5c7"; }
+
+.fa-telegram:before {
+ content: "\f2c6"; }
+
+.fa-telegram-plane:before {
+ content: "\f2c6"; }
+
+.fa-old-republic:before {
+ content: "\f510"; }
+
+.fa-odysee:before {
+ content: "\e5c6"; }
+
+.fa-square-whatsapp:before {
+ content: "\f40c"; }
+
+.fa-whatsapp-square:before {
+ content: "\f40c"; }
+
+.fa-node-js:before {
+ content: "\f3d3"; }
+
+.fa-edge-legacy:before {
+ content: "\e078"; }
+
+.fa-slack:before {
+ content: "\f198"; }
+
+.fa-slack-hash:before {
+ content: "\f198"; }
+
+.fa-medrt:before {
+ content: "\f3c8"; }
+
+.fa-usb:before {
+ content: "\f287"; }
+
+.fa-tumblr:before {
+ content: "\f173"; }
+
+.fa-vaadin:before {
+ content: "\f408"; }
+
+.fa-quora:before {
+ content: "\f2c4"; }
+
+.fa-reacteurope:before {
+ content: "\f75d"; }
+
+.fa-medium:before {
+ content: "\f23a"; }
+
+.fa-medium-m:before {
+ content: "\f23a"; }
+
+.fa-amilia:before {
+ content: "\f36d"; }
+
+.fa-mixcloud:before {
+ content: "\f289"; }
+
+.fa-flipboard:before {
+ content: "\f44d"; }
+
+.fa-viacoin:before {
+ content: "\f237"; }
+
+.fa-critical-role:before {
+ content: "\f6c9"; }
+
+.fa-sitrox:before {
+ content: "\e44a"; }
+
+.fa-discourse:before {
+ content: "\f393"; }
+
+.fa-joomla:before {
+ content: "\f1aa"; }
+
+.fa-mastodon:before {
+ content: "\f4f6"; }
+
+.fa-airbnb:before {
+ content: "\f834"; }
+
+.fa-wolf-pack-battalion:before {
+ content: "\f514"; }
+
+.fa-buy-n-large:before {
+ content: "\f8a6"; }
+
+.fa-gulp:before {
+ content: "\f3ae"; }
+
+.fa-creative-commons-sampling-plus:before {
+ content: "\f4f1"; }
+
+.fa-strava:before {
+ content: "\f428"; }
+
+.fa-ember:before {
+ content: "\f423"; }
+
+.fa-canadian-maple-leaf:before {
+ content: "\f785"; }
+
+.fa-teamspeak:before {
+ content: "\f4f9"; }
+
+.fa-pushed:before {
+ content: "\f3e1"; }
+
+.fa-wordpress-simple:before {
+ content: "\f411"; }
+
+.fa-nutritionix:before {
+ content: "\f3d6"; }
+
+.fa-wodu:before {
+ content: "\e088"; }
+
+.fa-google-pay:before {
+ content: "\e079"; }
+
+.fa-intercom:before {
+ content: "\f7af"; }
+
+.fa-zhihu:before {
+ content: "\f63f"; }
+
+.fa-korvue:before {
+ content: "\f42f"; }
+
+.fa-pix:before {
+ content: "\e43a"; }
+
+.fa-steam-symbol:before {
+ content: "\f3f6"; }
diff --git a/40-abschlusspraesentation/assets/fontawesome/css/brands.min.css b/40-abschlusspraesentation/assets/fontawesome/css/brands.min.css
new file mode 100644
index 0000000..f0536df
--- /dev/null
+++ b/40-abschlusspraesentation/assets/fontawesome/css/brands.min.css
@@ -0,0 +1,6 @@
+/*!
+ * Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com
+ * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
+ * Copyright 2023 Fonticons, Inc.
+ */
+:host,:root{--fa-style-family-brands:"Font Awesome 6 Brands";--fa-font-brands:normal 400 1em/1 "Font Awesome 6 Brands"}@font-face{font-family:"Font Awesome 6 Brands";font-style:normal;font-weight:400;font-display:block;src:url(../webfonts/fa-brands-400.woff2) format("woff2"),url(../webfonts/fa-brands-400.ttf) format("truetype")}.fa-brands,.fab{font-weight:400}.fa-monero:before{content:"\f3d0"}.fa-hooli:before{content:"\f427"}.fa-yelp:before{content:"\f1e9"}.fa-cc-visa:before{content:"\f1f0"}.fa-lastfm:before{content:"\f202"}.fa-shopware:before{content:"\f5b5"}.fa-creative-commons-nc:before{content:"\f4e8"}.fa-aws:before{content:"\f375"}.fa-redhat:before{content:"\f7bc"}.fa-yoast:before{content:"\f2b1"}.fa-cloudflare:before{content:"\e07d"}.fa-ups:before{content:"\f7e0"}.fa-wpexplorer:before{content:"\f2de"}.fa-dyalog:before{content:"\f399"}.fa-bity:before{content:"\f37a"}.fa-stackpath:before{content:"\f842"}.fa-buysellads:before{content:"\f20d"}.fa-first-order:before{content:"\f2b0"}.fa-modx:before{content:"\f285"}.fa-guilded:before{content:"\e07e"}.fa-vnv:before{content:"\f40b"}.fa-js-square:before,.fa-square-js:before{content:"\f3b9"}.fa-microsoft:before{content:"\f3ca"}.fa-qq:before{content:"\f1d6"}.fa-orcid:before{content:"\f8d2"}.fa-java:before{content:"\f4e4"}.fa-invision:before{content:"\f7b0"}.fa-creative-commons-pd-alt:before{content:"\f4ed"}.fa-centercode:before{content:"\f380"}.fa-glide-g:before{content:"\f2a6"}.fa-drupal:before{content:"\f1a9"}.fa-hire-a-helper:before{content:"\f3b0"}.fa-creative-commons-by:before{content:"\f4e7"}.fa-unity:before{content:"\e049"}.fa-whmcs:before{content:"\f40d"}.fa-rocketchat:before{content:"\f3e8"}.fa-vk:before{content:"\f189"}.fa-untappd:before{content:"\f405"}.fa-mailchimp:before{content:"\f59e"}.fa-css3-alt:before{content:"\f38b"}.fa-reddit-square:before,.fa-square-reddit:before{content:"\f1a2"}.fa-vimeo-v:before{content:"\f27d"}.fa-contao:before{content:"\f26d"}.fa-square-font-awesome:before{content:"\e5ad"}.fa-deskpro:before{content:"\f38f"}.fa-sistrix:before{content:"\f3ee"}.fa-instagram-square:before,.fa-square-instagram:before{content:"\e055"}.fa-battle-net:before{content:"\f835"}.fa-the-red-yeti:before{content:"\f69d"}.fa-hacker-news-square:before,.fa-square-hacker-news:before{content:"\f3af"}.fa-edge:before{content:"\f282"}.fa-napster:before{content:"\f3d2"}.fa-snapchat-square:before,.fa-square-snapchat:before{content:"\f2ad"}.fa-google-plus-g:before{content:"\f0d5"}.fa-artstation:before{content:"\f77a"}.fa-markdown:before{content:"\f60f"}.fa-sourcetree:before{content:"\f7d3"}.fa-google-plus:before{content:"\f2b3"}.fa-diaspora:before{content:"\f791"}.fa-foursquare:before{content:"\f180"}.fa-stack-overflow:before{content:"\f16c"}.fa-github-alt:before{content:"\f113"}.fa-phoenix-squadron:before{content:"\f511"}.fa-pagelines:before{content:"\f18c"}.fa-algolia:before{content:"\f36c"}.fa-red-river:before{content:"\f3e3"}.fa-creative-commons-sa:before{content:"\f4ef"}.fa-safari:before{content:"\f267"}.fa-google:before{content:"\f1a0"}.fa-font-awesome-alt:before,.fa-square-font-awesome-stroke:before{content:"\f35c"}.fa-atlassian:before{content:"\f77b"}.fa-linkedin-in:before{content:"\f0e1"}.fa-digital-ocean:before{content:"\f391"}.fa-nimblr:before{content:"\f5a8"}.fa-chromecast:before{content:"\f838"}.fa-evernote:before{content:"\f839"}.fa-hacker-news:before{content:"\f1d4"}.fa-creative-commons-sampling:before{content:"\f4f0"}.fa-adversal:before{content:"\f36a"}.fa-creative-commons:before{content:"\f25e"}.fa-watchman-monitoring:before{content:"\e087"}.fa-fonticons:before{content:"\f280"}.fa-weixin:before{content:"\f1d7"}.fa-shirtsinbulk:before{content:"\f214"}.fa-codepen:before{content:"\f1cb"}.fa-git-alt:before{content:"\f841"}.fa-lyft:before{content:"\f3c3"}.fa-rev:before{content:"\f5b2"}.fa-windows:before{content:"\f17a"}.fa-wizards-of-the-coast:before{content:"\f730"}.fa-square-viadeo:before,.fa-viadeo-square:before{content:"\f2aa"}.fa-meetup:before{content:"\f2e0"}.fa-centos:before{content:"\f789"}.fa-adn:before{content:"\f170"}.fa-cloudsmith:before{content:"\f384"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-dribbble-square:before,.fa-square-dribbble:before{content:"\f397"}.fa-codiepie:before{content:"\f284"}.fa-node:before{content:"\f419"}.fa-mix:before{content:"\f3cb"}.fa-steam:before{content:"\f1b6"}.fa-cc-apple-pay:before{content:"\f416"}.fa-scribd:before{content:"\f28a"}.fa-openid:before{content:"\f19b"}.fa-instalod:before{content:"\e081"}.fa-expeditedssl:before{content:"\f23e"}.fa-sellcast:before{content:"\f2da"}.fa-square-twitter:before,.fa-twitter-square:before{content:"\f081"}.fa-r-project:before{content:"\f4f7"}.fa-delicious:before{content:"\f1a5"}.fa-freebsd:before{content:"\f3a4"}.fa-vuejs:before{content:"\f41f"}.fa-accusoft:before{content:"\f369"}.fa-ioxhost:before{content:"\f208"}.fa-fonticons-fi:before{content:"\f3a2"}.fa-app-store:before{content:"\f36f"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-itunes-note:before{content:"\f3b5"}.fa-golang:before{content:"\e40f"}.fa-kickstarter:before{content:"\f3bb"}.fa-grav:before{content:"\f2d6"}.fa-weibo:before{content:"\f18a"}.fa-uncharted:before{content:"\e084"}.fa-firstdraft:before{content:"\f3a1"}.fa-square-youtube:before,.fa-youtube-square:before{content:"\f431"}.fa-wikipedia-w:before{content:"\f266"}.fa-rendact:before,.fa-wpressr:before{content:"\f3e4"}.fa-angellist:before{content:"\f209"}.fa-galactic-republic:before{content:"\f50c"}.fa-nfc-directional:before{content:"\e530"}.fa-skype:before{content:"\f17e"}.fa-joget:before{content:"\f3b7"}.fa-fedora:before{content:"\f798"}.fa-stripe-s:before{content:"\f42a"}.fa-meta:before{content:"\e49b"}.fa-laravel:before{content:"\f3bd"}.fa-hotjar:before{content:"\f3b1"}.fa-bluetooth-b:before{content:"\f294"}.fa-sticker-mule:before{content:"\f3f7"}.fa-creative-commons-zero:before{content:"\f4f3"}.fa-hips:before{content:"\f452"}.fa-behance:before{content:"\f1b4"}.fa-reddit:before{content:"\f1a1"}.fa-discord:before{content:"\f392"}.fa-chrome:before{content:"\f268"}.fa-app-store-ios:before{content:"\f370"}.fa-cc-discover:before{content:"\f1f2"}.fa-wpbeginner:before{content:"\f297"}.fa-confluence:before{content:"\f78d"}.fa-mdb:before{content:"\f8ca"}.fa-dochub:before{content:"\f394"}.fa-accessible-icon:before{content:"\f368"}.fa-ebay:before{content:"\f4f4"}.fa-amazon:before{content:"\f270"}.fa-unsplash:before{content:"\e07c"}.fa-yarn:before{content:"\f7e3"}.fa-square-steam:before,.fa-steam-square:before{content:"\f1b7"}.fa-500px:before{content:"\f26e"}.fa-square-vimeo:before,.fa-vimeo-square:before{content:"\f194"}.fa-asymmetrik:before{content:"\f372"}.fa-font-awesome-flag:before,.fa-font-awesome-logo-full:before,.fa-font-awesome:before{content:"\f2b4"}.fa-gratipay:before{content:"\f184"}.fa-apple:before{content:"\f179"}.fa-hive:before{content:"\e07f"}.fa-gitkraken:before{content:"\f3a6"}.fa-keybase:before{content:"\f4f5"}.fa-apple-pay:before{content:"\f415"}.fa-padlet:before{content:"\e4a0"}.fa-amazon-pay:before{content:"\f42c"}.fa-github-square:before,.fa-square-github:before{content:"\f092"}.fa-stumbleupon:before{content:"\f1a4"}.fa-fedex:before{content:"\f797"}.fa-phoenix-framework:before{content:"\f3dc"}.fa-shopify:before{content:"\e057"}.fa-neos:before{content:"\f612"}.fa-hackerrank:before{content:"\f5f7"}.fa-researchgate:before{content:"\f4f8"}.fa-swift:before{content:"\f8e1"}.fa-angular:before{content:"\f420"}.fa-speakap:before{content:"\f3f3"}.fa-angrycreative:before{content:"\f36e"}.fa-y-combinator:before{content:"\f23b"}.fa-empire:before{content:"\f1d1"}.fa-envira:before{content:"\f299"}.fa-gitlab-square:before,.fa-square-gitlab:before{content:"\e5ae"}.fa-studiovinari:before{content:"\f3f8"}.fa-pied-piper:before{content:"\f2ae"}.fa-wordpress:before{content:"\f19a"}.fa-product-hunt:before{content:"\f288"}.fa-firefox:before{content:"\f269"}.fa-linode:before{content:"\f2b8"}.fa-goodreads:before{content:"\f3a8"}.fa-odnoklassniki-square:before,.fa-square-odnoklassniki:before{content:"\f264"}.fa-jsfiddle:before{content:"\f1cc"}.fa-sith:before{content:"\f512"}.fa-themeisle:before{content:"\f2b2"}.fa-page4:before{content:"\f3d7"}.fa-hashnode:before{content:"\e499"}.fa-react:before{content:"\f41b"}.fa-cc-paypal:before{content:"\f1f4"}.fa-squarespace:before{content:"\f5be"}.fa-cc-stripe:before{content:"\f1f5"}.fa-creative-commons-share:before{content:"\f4f2"}.fa-bitcoin:before{content:"\f379"}.fa-keycdn:before{content:"\f3ba"}.fa-opera:before{content:"\f26a"}.fa-itch-io:before{content:"\f83a"}.fa-umbraco:before{content:"\f8e8"}.fa-galactic-senate:before{content:"\f50d"}.fa-ubuntu:before{content:"\f7df"}.fa-draft2digital:before{content:"\f396"}.fa-stripe:before{content:"\f429"}.fa-houzz:before{content:"\f27c"}.fa-gg:before{content:"\f260"}.fa-dhl:before{content:"\f790"}.fa-pinterest-square:before,.fa-square-pinterest:before{content:"\f0d3"}.fa-xing:before{content:"\f168"}.fa-blackberry:before{content:"\f37b"}.fa-creative-commons-pd:before{content:"\f4ec"}.fa-playstation:before{content:"\f3df"}.fa-quinscape:before{content:"\f459"}.fa-less:before{content:"\f41d"}.fa-blogger-b:before{content:"\f37d"}.fa-opencart:before{content:"\f23d"}.fa-vine:before{content:"\f1ca"}.fa-paypal:before{content:"\f1ed"}.fa-gitlab:before{content:"\f296"}.fa-typo3:before{content:"\f42b"}.fa-reddit-alien:before{content:"\f281"}.fa-yahoo:before{content:"\f19e"}.fa-dailymotion:before{content:"\e052"}.fa-affiliatetheme:before{content:"\f36b"}.fa-pied-piper-pp:before{content:"\f1a7"}.fa-bootstrap:before{content:"\f836"}.fa-odnoklassniki:before{content:"\f263"}.fa-nfc-symbol:before{content:"\e531"}.fa-ethereum:before{content:"\f42e"}.fa-speaker-deck:before{content:"\f83c"}.fa-creative-commons-nc-eu:before{content:"\f4e9"}.fa-patreon:before{content:"\f3d9"}.fa-avianex:before{content:"\f374"}.fa-ello:before{content:"\f5f1"}.fa-gofore:before{content:"\f3a7"}.fa-bimobject:before{content:"\f378"}.fa-facebook-f:before{content:"\f39e"}.fa-google-plus-square:before,.fa-square-google-plus:before{content:"\f0d4"}.fa-mandalorian:before{content:"\f50f"}.fa-first-order-alt:before{content:"\f50a"}.fa-osi:before{content:"\f41a"}.fa-google-wallet:before{content:"\f1ee"}.fa-d-and-d-beyond:before{content:"\f6ca"}.fa-periscope:before{content:"\f3da"}.fa-fulcrum:before{content:"\f50b"}.fa-cloudscale:before{content:"\f383"}.fa-forumbee:before{content:"\f211"}.fa-mizuni:before{content:"\f3cc"}.fa-schlix:before{content:"\f3ea"}.fa-square-xing:before,.fa-xing-square:before{content:"\f169"}.fa-bandcamp:before{content:"\f2d5"}.fa-wpforms:before{content:"\f298"}.fa-cloudversify:before{content:"\f385"}.fa-usps:before{content:"\f7e1"}.fa-megaport:before{content:"\f5a3"}.fa-magento:before{content:"\f3c4"}.fa-spotify:before{content:"\f1bc"}.fa-optin-monster:before{content:"\f23c"}.fa-fly:before{content:"\f417"}.fa-aviato:before{content:"\f421"}.fa-itunes:before{content:"\f3b4"}.fa-cuttlefish:before{content:"\f38c"}.fa-blogger:before{content:"\f37c"}.fa-flickr:before{content:"\f16e"}.fa-viber:before{content:"\f409"}.fa-soundcloud:before{content:"\f1be"}.fa-digg:before{content:"\f1a6"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-symfony:before{content:"\f83d"}.fa-maxcdn:before{content:"\f136"}.fa-etsy:before{content:"\f2d7"}.fa-facebook-messenger:before{content:"\f39f"}.fa-audible:before{content:"\f373"}.fa-think-peaks:before{content:"\f731"}.fa-bilibili:before{content:"\e3d9"}.fa-erlang:before{content:"\f39d"}.fa-cotton-bureau:before{content:"\f89e"}.fa-dashcube:before{content:"\f210"}.fa-42-group:before,.fa-innosoft:before{content:"\e080"}.fa-stack-exchange:before{content:"\f18d"}.fa-elementor:before{content:"\f430"}.fa-pied-piper-square:before,.fa-square-pied-piper:before{content:"\e01e"}.fa-creative-commons-nd:before{content:"\f4eb"}.fa-palfed:before{content:"\f3d8"}.fa-superpowers:before{content:"\f2dd"}.fa-resolving:before{content:"\f3e7"}.fa-xbox:before{content:"\f412"}.fa-searchengin:before{content:"\f3eb"}.fa-tiktok:before{content:"\e07b"}.fa-facebook-square:before,.fa-square-facebook:before{content:"\f082"}.fa-renren:before{content:"\f18b"}.fa-linux:before{content:"\f17c"}.fa-glide:before{content:"\f2a5"}.fa-linkedin:before{content:"\f08c"}.fa-hubspot:before{content:"\f3b2"}.fa-deploydog:before{content:"\f38e"}.fa-twitch:before{content:"\f1e8"}.fa-ravelry:before{content:"\f2d9"}.fa-mixer:before{content:"\e056"}.fa-lastfm-square:before,.fa-square-lastfm:before{content:"\f203"}.fa-vimeo:before{content:"\f40a"}.fa-mendeley:before{content:"\f7b3"}.fa-uniregistry:before{content:"\f404"}.fa-figma:before{content:"\f799"}.fa-creative-commons-remix:before{content:"\f4ee"}.fa-cc-amazon-pay:before{content:"\f42d"}.fa-dropbox:before{content:"\f16b"}.fa-instagram:before{content:"\f16d"}.fa-cmplid:before{content:"\e360"}.fa-facebook:before{content:"\f09a"}.fa-gripfire:before{content:"\f3ac"}.fa-jedi-order:before{content:"\f50e"}.fa-uikit:before{content:"\f403"}.fa-fort-awesome-alt:before{content:"\f3a3"}.fa-phabricator:before{content:"\f3db"}.fa-ussunnah:before{content:"\f407"}.fa-earlybirds:before{content:"\f39a"}.fa-trade-federation:before{content:"\f513"}.fa-autoprefixer:before{content:"\f41c"}.fa-whatsapp:before{content:"\f232"}.fa-slideshare:before{content:"\f1e7"}.fa-google-play:before{content:"\f3ab"}.fa-viadeo:before{content:"\f2a9"}.fa-line:before{content:"\f3c0"}.fa-google-drive:before{content:"\f3aa"}.fa-servicestack:before{content:"\f3ec"}.fa-simplybuilt:before{content:"\f215"}.fa-bitbucket:before{content:"\f171"}.fa-imdb:before{content:"\f2d8"}.fa-deezer:before{content:"\e077"}.fa-raspberry-pi:before{content:"\f7bb"}.fa-jira:before{content:"\f7b1"}.fa-docker:before{content:"\f395"}.fa-screenpal:before{content:"\e570"}.fa-bluetooth:before{content:"\f293"}.fa-gitter:before{content:"\f426"}.fa-d-and-d:before{content:"\f38d"}.fa-microblog:before{content:"\e01a"}.fa-cc-diners-club:before{content:"\f24c"}.fa-gg-circle:before{content:"\f261"}.fa-pied-piper-hat:before{content:"\f4e5"}.fa-kickstarter-k:before{content:"\f3bc"}.fa-yandex:before{content:"\f413"}.fa-readme:before{content:"\f4d5"}.fa-html5:before{content:"\f13b"}.fa-sellsy:before{content:"\f213"}.fa-sass:before{content:"\f41e"}.fa-wirsindhandwerk:before,.fa-wsh:before{content:"\e2d0"}.fa-buromobelexperte:before{content:"\f37f"}.fa-salesforce:before{content:"\f83b"}.fa-octopus-deploy:before{content:"\e082"}.fa-medapps:before{content:"\f3c6"}.fa-ns8:before{content:"\f3d5"}.fa-pinterest-p:before{content:"\f231"}.fa-apper:before{content:"\f371"}.fa-fort-awesome:before{content:"\f286"}.fa-waze:before{content:"\f83f"}.fa-cc-jcb:before{content:"\f24b"}.fa-snapchat-ghost:before,.fa-snapchat:before{content:"\f2ab"}.fa-fantasy-flight-games:before{content:"\f6dc"}.fa-rust:before{content:"\e07a"}.fa-wix:before{content:"\f5cf"}.fa-behance-square:before,.fa-square-behance:before{content:"\f1b5"}.fa-supple:before{content:"\f3f9"}.fa-rebel:before{content:"\f1d0"}.fa-css3:before{content:"\f13c"}.fa-staylinked:before{content:"\f3f5"}.fa-kaggle:before{content:"\f5fa"}.fa-space-awesome:before{content:"\e5ac"}.fa-deviantart:before{content:"\f1bd"}.fa-cpanel:before{content:"\f388"}.fa-goodreads-g:before{content:"\f3a9"}.fa-git-square:before,.fa-square-git:before{content:"\f1d2"}.fa-square-tumblr:before,.fa-tumblr-square:before{content:"\f174"}.fa-trello:before{content:"\f181"}.fa-creative-commons-nc-jp:before{content:"\f4ea"}.fa-get-pocket:before{content:"\f265"}.fa-perbyte:before{content:"\e083"}.fa-grunt:before{content:"\f3ad"}.fa-weebly:before{content:"\f5cc"}.fa-connectdevelop:before{content:"\f20e"}.fa-leanpub:before{content:"\f212"}.fa-black-tie:before{content:"\f27e"}.fa-themeco:before{content:"\f5c6"}.fa-python:before{content:"\f3e2"}.fa-android:before{content:"\f17b"}.fa-bots:before{content:"\e340"}.fa-free-code-camp:before{content:"\f2c5"}.fa-hornbill:before{content:"\f592"}.fa-js:before{content:"\f3b8"}.fa-ideal:before{content:"\e013"}.fa-git:before{content:"\f1d3"}.fa-dev:before{content:"\f6cc"}.fa-sketch:before{content:"\f7c6"}.fa-yandex-international:before{content:"\f414"}.fa-cc-amex:before{content:"\f1f3"}.fa-uber:before{content:"\f402"}.fa-github:before{content:"\f09b"}.fa-php:before{content:"\f457"}.fa-alipay:before{content:"\f642"}.fa-youtube:before{content:"\f167"}.fa-skyatlas:before{content:"\f216"}.fa-firefox-browser:before{content:"\e007"}.fa-replyd:before{content:"\f3e6"}.fa-suse:before{content:"\f7d6"}.fa-jenkins:before{content:"\f3b6"}.fa-twitter:before{content:"\f099"}.fa-rockrms:before{content:"\f3e9"}.fa-pinterest:before{content:"\f0d2"}.fa-buffer:before{content:"\f837"}.fa-npm:before{content:"\f3d4"}.fa-yammer:before{content:"\f840"}.fa-btc:before{content:"\f15a"}.fa-dribbble:before{content:"\f17d"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-internet-explorer:before{content:"\f26b"}.fa-stubber:before{content:"\e5c7"}.fa-telegram-plane:before,.fa-telegram:before{content:"\f2c6"}.fa-old-republic:before{content:"\f510"}.fa-odysee:before{content:"\e5c6"}.fa-square-whatsapp:before,.fa-whatsapp-square:before{content:"\f40c"}.fa-node-js:before{content:"\f3d3"}.fa-edge-legacy:before{content:"\e078"}.fa-slack-hash:before,.fa-slack:before{content:"\f198"}.fa-medrt:before{content:"\f3c8"}.fa-usb:before{content:"\f287"}.fa-tumblr:before{content:"\f173"}.fa-vaadin:before{content:"\f408"}.fa-quora:before{content:"\f2c4"}.fa-reacteurope:before{content:"\f75d"}.fa-medium-m:before,.fa-medium:before{content:"\f23a"}.fa-amilia:before{content:"\f36d"}.fa-mixcloud:before{content:"\f289"}.fa-flipboard:before{content:"\f44d"}.fa-viacoin:before{content:"\f237"}.fa-critical-role:before{content:"\f6c9"}.fa-sitrox:before{content:"\e44a"}.fa-discourse:before{content:"\f393"}.fa-joomla:before{content:"\f1aa"}.fa-mastodon:before{content:"\f4f6"}.fa-airbnb:before{content:"\f834"}.fa-wolf-pack-battalion:before{content:"\f514"}.fa-buy-n-large:before{content:"\f8a6"}.fa-gulp:before{content:"\f3ae"}.fa-creative-commons-sampling-plus:before{content:"\f4f1"}.fa-strava:before{content:"\f428"}.fa-ember:before{content:"\f423"}.fa-canadian-maple-leaf:before{content:"\f785"}.fa-teamspeak:before{content:"\f4f9"}.fa-pushed:before{content:"\f3e1"}.fa-wordpress-simple:before{content:"\f411"}.fa-nutritionix:before{content:"\f3d6"}.fa-wodu:before{content:"\e088"}.fa-google-pay:before{content:"\e079"}.fa-intercom:before{content:"\f7af"}.fa-zhihu:before{content:"\f63f"}.fa-korvue:before{content:"\f42f"}.fa-pix:before{content:"\e43a"}.fa-steam-symbol:before{content:"\f3f6"} \ No newline at end of file
diff --git a/40-abschlusspraesentation/assets/fontawesome/css/fontawesome.css b/40-abschlusspraesentation/assets/fontawesome/css/fontawesome.css
new file mode 100644
index 0000000..fd06905
--- /dev/null
+++ b/40-abschlusspraesentation/assets/fontawesome/css/fontawesome.css
@@ -0,0 +1,6372 @@
+/*!
+ * Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com
+ * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
+ * Copyright 2023 Fonticons, Inc.
+ */
+.fa {
+ font-family: var(--fa-style-family, "Font Awesome 6 Free");
+ font-weight: var(--fa-style, 900); }
+
+.fa,
+.fa-classic,
+.fa-sharp,
+.fas,
+.fa-solid,
+.far,
+.fa-regular,
+.fab,
+.fa-brands {
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+ display: var(--fa-display, inline-block);
+ font-style: normal;
+ font-variant: normal;
+ line-height: 1;
+ text-rendering: auto; }
+
+.fas,
+.fa-classic,
+.fa-solid,
+.far,
+.fa-regular {
+ font-family: 'Font Awesome 6 Free'; }
+
+.fab,
+.fa-brands {
+ font-family: 'Font Awesome 6 Brands'; }
+
+.fa-1x {
+ font-size: 1em; }
+
+.fa-2x {
+ font-size: 2em; }
+
+.fa-3x {
+ font-size: 3em; }
+
+.fa-4x {
+ font-size: 4em; }
+
+.fa-5x {
+ font-size: 5em; }
+
+.fa-6x {
+ font-size: 6em; }
+
+.fa-7x {
+ font-size: 7em; }
+
+.fa-8x {
+ font-size: 8em; }
+
+.fa-9x {
+ font-size: 9em; }
+
+.fa-10x {
+ font-size: 10em; }
+
+.fa-2xs {
+ font-size: 0.625em;
+ line-height: 0.1em;
+ vertical-align: 0.225em; }
+
+.fa-xs {
+ font-size: 0.75em;
+ line-height: 0.08333em;
+ vertical-align: 0.125em; }
+
+.fa-sm {
+ font-size: 0.875em;
+ line-height: 0.07143em;
+ vertical-align: 0.05357em; }
+
+.fa-lg {
+ font-size: 1.25em;
+ line-height: 0.05em;
+ vertical-align: -0.075em; }
+
+.fa-xl {
+ font-size: 1.5em;
+ line-height: 0.04167em;
+ vertical-align: -0.125em; }
+
+.fa-2xl {
+ font-size: 2em;
+ line-height: 0.03125em;
+ vertical-align: -0.1875em; }
+
+.fa-fw {
+ text-align: center;
+ width: 1.25em; }
+
+.fa-ul {
+ list-style-type: none;
+ margin-left: var(--fa-li-margin, 2.5em);
+ padding-left: 0; }
+ .fa-ul > li {
+ position: relative; }
+
+.fa-li {
+ left: calc(var(--fa-li-width, 2em) * -1);
+ position: absolute;
+ text-align: center;
+ width: var(--fa-li-width, 2em);
+ line-height: inherit; }
+
+.fa-border {
+ border-color: var(--fa-border-color, #eee);
+ border-radius: var(--fa-border-radius, 0.1em);
+ border-style: var(--fa-border-style, solid);
+ border-width: var(--fa-border-width, 0.08em);
+ padding: var(--fa-border-padding, 0.2em 0.25em 0.15em); }
+
+.fa-pull-left {
+ float: left;
+ margin-right: var(--fa-pull-margin, 0.3em); }
+
+.fa-pull-right {
+ float: right;
+ margin-left: var(--fa-pull-margin, 0.3em); }
+
+.fa-beat {
+ -webkit-animation-name: fa-beat;
+ animation-name: fa-beat;
+ -webkit-animation-delay: var(--fa-animation-delay, 0s);
+ animation-delay: var(--fa-animation-delay, 0s);
+ -webkit-animation-direction: var(--fa-animation-direction, normal);
+ animation-direction: var(--fa-animation-direction, normal);
+ -webkit-animation-duration: var(--fa-animation-duration, 1s);
+ animation-duration: var(--fa-animation-duration, 1s);
+ -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);
+ animation-iteration-count: var(--fa-animation-iteration-count, infinite);
+ -webkit-animation-timing-function: var(--fa-animation-timing, ease-in-out);
+ animation-timing-function: var(--fa-animation-timing, ease-in-out); }
+
+.fa-bounce {
+ -webkit-animation-name: fa-bounce;
+ animation-name: fa-bounce;
+ -webkit-animation-delay: var(--fa-animation-delay, 0s);
+ animation-delay: var(--fa-animation-delay, 0s);
+ -webkit-animation-direction: var(--fa-animation-direction, normal);
+ animation-direction: var(--fa-animation-direction, normal);
+ -webkit-animation-duration: var(--fa-animation-duration, 1s);
+ animation-duration: var(--fa-animation-duration, 1s);
+ -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);
+ animation-iteration-count: var(--fa-animation-iteration-count, infinite);
+ -webkit-animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.28, 0.84, 0.42, 1));
+ animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.28, 0.84, 0.42, 1)); }
+
+.fa-fade {
+ -webkit-animation-name: fa-fade;
+ animation-name: fa-fade;
+ -webkit-animation-delay: var(--fa-animation-delay, 0s);
+ animation-delay: var(--fa-animation-delay, 0s);
+ -webkit-animation-direction: var(--fa-animation-direction, normal);
+ animation-direction: var(--fa-animation-direction, normal);
+ -webkit-animation-duration: var(--fa-animation-duration, 1s);
+ animation-duration: var(--fa-animation-duration, 1s);
+ -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);
+ animation-iteration-count: var(--fa-animation-iteration-count, infinite);
+ -webkit-animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1));
+ animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1)); }
+
+.fa-beat-fade {
+ -webkit-animation-name: fa-beat-fade;
+ animation-name: fa-beat-fade;
+ -webkit-animation-delay: var(--fa-animation-delay, 0s);
+ animation-delay: var(--fa-animation-delay, 0s);
+ -webkit-animation-direction: var(--fa-animation-direction, normal);
+ animation-direction: var(--fa-animation-direction, normal);
+ -webkit-animation-duration: var(--fa-animation-duration, 1s);
+ animation-duration: var(--fa-animation-duration, 1s);
+ -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);
+ animation-iteration-count: var(--fa-animation-iteration-count, infinite);
+ -webkit-animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1));
+ animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1)); }
+
+.fa-flip {
+ -webkit-animation-name: fa-flip;
+ animation-name: fa-flip;
+ -webkit-animation-delay: var(--fa-animation-delay, 0s);
+ animation-delay: var(--fa-animation-delay, 0s);
+ -webkit-animation-direction: var(--fa-animation-direction, normal);
+ animation-direction: var(--fa-animation-direction, normal);
+ -webkit-animation-duration: var(--fa-animation-duration, 1s);
+ animation-duration: var(--fa-animation-duration, 1s);
+ -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);
+ animation-iteration-count: var(--fa-animation-iteration-count, infinite);
+ -webkit-animation-timing-function: var(--fa-animation-timing, ease-in-out);
+ animation-timing-function: var(--fa-animation-timing, ease-in-out); }
+
+.fa-shake {
+ -webkit-animation-name: fa-shake;
+ animation-name: fa-shake;
+ -webkit-animation-delay: var(--fa-animation-delay, 0s);
+ animation-delay: var(--fa-animation-delay, 0s);
+ -webkit-animation-direction: var(--fa-animation-direction, normal);
+ animation-direction: var(--fa-animation-direction, normal);
+ -webkit-animation-duration: var(--fa-animation-duration, 1s);
+ animation-duration: var(--fa-animation-duration, 1s);
+ -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);
+ animation-iteration-count: var(--fa-animation-iteration-count, infinite);
+ -webkit-animation-timing-function: var(--fa-animation-timing, linear);
+ animation-timing-function: var(--fa-animation-timing, linear); }
+
+.fa-spin {
+ -webkit-animation-name: fa-spin;
+ animation-name: fa-spin;
+ -webkit-animation-delay: var(--fa-animation-delay, 0s);
+ animation-delay: var(--fa-animation-delay, 0s);
+ -webkit-animation-direction: var(--fa-animation-direction, normal);
+ animation-direction: var(--fa-animation-direction, normal);
+ -webkit-animation-duration: var(--fa-animation-duration, 2s);
+ animation-duration: var(--fa-animation-duration, 2s);
+ -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);
+ animation-iteration-count: var(--fa-animation-iteration-count, infinite);
+ -webkit-animation-timing-function: var(--fa-animation-timing, linear);
+ animation-timing-function: var(--fa-animation-timing, linear); }
+
+.fa-spin-reverse {
+ --fa-animation-direction: reverse; }
+
+.fa-pulse,
+.fa-spin-pulse {
+ -webkit-animation-name: fa-spin;
+ animation-name: fa-spin;
+ -webkit-animation-direction: var(--fa-animation-direction, normal);
+ animation-direction: var(--fa-animation-direction, normal);
+ -webkit-animation-duration: var(--fa-animation-duration, 1s);
+ animation-duration: var(--fa-animation-duration, 1s);
+ -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);
+ animation-iteration-count: var(--fa-animation-iteration-count, infinite);
+ -webkit-animation-timing-function: var(--fa-animation-timing, steps(8));
+ animation-timing-function: var(--fa-animation-timing, steps(8)); }
+
+@media (prefers-reduced-motion: reduce) {
+ .fa-beat,
+ .fa-bounce,
+ .fa-fade,
+ .fa-beat-fade,
+ .fa-flip,
+ .fa-pulse,
+ .fa-shake,
+ .fa-spin,
+ .fa-spin-pulse {
+ -webkit-animation-delay: -1ms;
+ animation-delay: -1ms;
+ -webkit-animation-duration: 1ms;
+ animation-duration: 1ms;
+ -webkit-animation-iteration-count: 1;
+ animation-iteration-count: 1;
+ -webkit-transition-delay: 0s;
+ transition-delay: 0s;
+ -webkit-transition-duration: 0s;
+ transition-duration: 0s; } }
+
+@-webkit-keyframes fa-beat {
+ 0%, 90% {
+ -webkit-transform: scale(1);
+ transform: scale(1); }
+ 45% {
+ -webkit-transform: scale(var(--fa-beat-scale, 1.25));
+ transform: scale(var(--fa-beat-scale, 1.25)); } }
+
+@keyframes fa-beat {
+ 0%, 90% {
+ -webkit-transform: scale(1);
+ transform: scale(1); }
+ 45% {
+ -webkit-transform: scale(var(--fa-beat-scale, 1.25));
+ transform: scale(var(--fa-beat-scale, 1.25)); } }
+
+@-webkit-keyframes fa-bounce {
+ 0% {
+ -webkit-transform: scale(1, 1) translateY(0);
+ transform: scale(1, 1) translateY(0); }
+ 10% {
+ -webkit-transform: scale(var(--fa-bounce-start-scale-x, 1.1), var(--fa-bounce-start-scale-y, 0.9)) translateY(0);
+ transform: scale(var(--fa-bounce-start-scale-x, 1.1), var(--fa-bounce-start-scale-y, 0.9)) translateY(0); }
+ 30% {
+ -webkit-transform: scale(var(--fa-bounce-jump-scale-x, 0.9), var(--fa-bounce-jump-scale-y, 1.1)) translateY(var(--fa-bounce-height, -0.5em));
+ transform: scale(var(--fa-bounce-jump-scale-x, 0.9), var(--fa-bounce-jump-scale-y, 1.1)) translateY(var(--fa-bounce-height, -0.5em)); }
+ 50% {
+ -webkit-transform: scale(var(--fa-bounce-land-scale-x, 1.05), var(--fa-bounce-land-scale-y, 0.95)) translateY(0);
+ transform: scale(var(--fa-bounce-land-scale-x, 1.05), var(--fa-bounce-land-scale-y, 0.95)) translateY(0); }
+ 57% {
+ -webkit-transform: scale(1, 1) translateY(var(--fa-bounce-rebound, -0.125em));
+ transform: scale(1, 1) translateY(var(--fa-bounce-rebound, -0.125em)); }
+ 64% {
+ -webkit-transform: scale(1, 1) translateY(0);
+ transform: scale(1, 1) translateY(0); }
+ 100% {
+ -webkit-transform: scale(1, 1) translateY(0);
+ transform: scale(1, 1) translateY(0); } }
+
+@keyframes fa-bounce {
+ 0% {
+ -webkit-transform: scale(1, 1) translateY(0);
+ transform: scale(1, 1) translateY(0); }
+ 10% {
+ -webkit-transform: scale(var(--fa-bounce-start-scale-x, 1.1), var(--fa-bounce-start-scale-y, 0.9)) translateY(0);
+ transform: scale(var(--fa-bounce-start-scale-x, 1.1), var(--fa-bounce-start-scale-y, 0.9)) translateY(0); }
+ 30% {
+ -webkit-transform: scale(var(--fa-bounce-jump-scale-x, 0.9), var(--fa-bounce-jump-scale-y, 1.1)) translateY(var(--fa-bounce-height, -0.5em));
+ transform: scale(var(--fa-bounce-jump-scale-x, 0.9), var(--fa-bounce-jump-scale-y, 1.1)) translateY(var(--fa-bounce-height, -0.5em)); }
+ 50% {
+ -webkit-transform: scale(var(--fa-bounce-land-scale-x, 1.05), var(--fa-bounce-land-scale-y, 0.95)) translateY(0);
+ transform: scale(var(--fa-bounce-land-scale-x, 1.05), var(--fa-bounce-land-scale-y, 0.95)) translateY(0); }
+ 57% {
+ -webkit-transform: scale(1, 1) translateY(var(--fa-bounce-rebound, -0.125em));
+ transform: scale(1, 1) translateY(var(--fa-bounce-rebound, -0.125em)); }
+ 64% {
+ -webkit-transform: scale(1, 1) translateY(0);
+ transform: scale(1, 1) translateY(0); }
+ 100% {
+ -webkit-transform: scale(1, 1) translateY(0);
+ transform: scale(1, 1) translateY(0); } }
+
+@-webkit-keyframes fa-fade {
+ 50% {
+ opacity: var(--fa-fade-opacity, 0.4); } }
+
+@keyframes fa-fade {
+ 50% {
+ opacity: var(--fa-fade-opacity, 0.4); } }
+
+@-webkit-keyframes fa-beat-fade {
+ 0%, 100% {
+ opacity: var(--fa-beat-fade-opacity, 0.4);
+ -webkit-transform: scale(1);
+ transform: scale(1); }
+ 50% {
+ opacity: 1;
+ -webkit-transform: scale(var(--fa-beat-fade-scale, 1.125));
+ transform: scale(var(--fa-beat-fade-scale, 1.125)); } }
+
+@keyframes fa-beat-fade {
+ 0%, 100% {
+ opacity: var(--fa-beat-fade-opacity, 0.4);
+ -webkit-transform: scale(1);
+ transform: scale(1); }
+ 50% {
+ opacity: 1;
+ -webkit-transform: scale(var(--fa-beat-fade-scale, 1.125));
+ transform: scale(var(--fa-beat-fade-scale, 1.125)); } }
+
+@-webkit-keyframes fa-flip {
+ 50% {
+ -webkit-transform: rotate3d(var(--fa-flip-x, 0), var(--fa-flip-y, 1), var(--fa-flip-z, 0), var(--fa-flip-angle, -180deg));
+ transform: rotate3d(var(--fa-flip-x, 0), var(--fa-flip-y, 1), var(--fa-flip-z, 0), var(--fa-flip-angle, -180deg)); } }
+
+@keyframes fa-flip {
+ 50% {
+ -webkit-transform: rotate3d(var(--fa-flip-x, 0), var(--fa-flip-y, 1), var(--fa-flip-z, 0), var(--fa-flip-angle, -180deg));
+ transform: rotate3d(var(--fa-flip-x, 0), var(--fa-flip-y, 1), var(--fa-flip-z, 0), var(--fa-flip-angle, -180deg)); } }
+
+@-webkit-keyframes fa-shake {
+ 0% {
+ -webkit-transform: rotate(-15deg);
+ transform: rotate(-15deg); }
+ 4% {
+ -webkit-transform: rotate(15deg);
+ transform: rotate(15deg); }
+ 8%, 24% {
+ -webkit-transform: rotate(-18deg);
+ transform: rotate(-18deg); }
+ 12%, 28% {
+ -webkit-transform: rotate(18deg);
+ transform: rotate(18deg); }
+ 16% {
+ -webkit-transform: rotate(-22deg);
+ transform: rotate(-22deg); }
+ 20% {
+ -webkit-transform: rotate(22deg);
+ transform: rotate(22deg); }
+ 32% {
+ -webkit-transform: rotate(-12deg);
+ transform: rotate(-12deg); }
+ 36% {
+ -webkit-transform: rotate(12deg);
+ transform: rotate(12deg); }
+ 40%, 100% {
+ -webkit-transform: rotate(0deg);
+ transform: rotate(0deg); } }
+
+@keyframes fa-shake {
+ 0% {
+ -webkit-transform: rotate(-15deg);
+ transform: rotate(-15deg); }
+ 4% {
+ -webkit-transform: rotate(15deg);
+ transform: rotate(15deg); }
+ 8%, 24% {
+ -webkit-transform: rotate(-18deg);
+ transform: rotate(-18deg); }
+ 12%, 28% {
+ -webkit-transform: rotate(18deg);
+ transform: rotate(18deg); }
+ 16% {
+ -webkit-transform: rotate(-22deg);
+ transform: rotate(-22deg); }
+ 20% {
+ -webkit-transform: rotate(22deg);
+ transform: rotate(22deg); }
+ 32% {
+ -webkit-transform: rotate(-12deg);
+ transform: rotate(-12deg); }
+ 36% {
+ -webkit-transform: rotate(12deg);
+ transform: rotate(12deg); }
+ 40%, 100% {
+ -webkit-transform: rotate(0deg);
+ transform: rotate(0deg); } }
+
+@-webkit-keyframes fa-spin {
+ 0% {
+ -webkit-transform: rotate(0deg);
+ transform: rotate(0deg); }
+ 100% {
+ -webkit-transform: rotate(360deg);
+ transform: rotate(360deg); } }
+
+@keyframes fa-spin {
+ 0% {
+ -webkit-transform: rotate(0deg);
+ transform: rotate(0deg); }
+ 100% {
+ -webkit-transform: rotate(360deg);
+ transform: rotate(360deg); } }
+
+.fa-rotate-90 {
+ -webkit-transform: rotate(90deg);
+ transform: rotate(90deg); }
+
+.fa-rotate-180 {
+ -webkit-transform: rotate(180deg);
+ transform: rotate(180deg); }
+
+.fa-rotate-270 {
+ -webkit-transform: rotate(270deg);
+ transform: rotate(270deg); }
+
+.fa-flip-horizontal {
+ -webkit-transform: scale(-1, 1);
+ transform: scale(-1, 1); }
+
+.fa-flip-vertical {
+ -webkit-transform: scale(1, -1);
+ transform: scale(1, -1); }
+
+.fa-flip-both,
+.fa-flip-horizontal.fa-flip-vertical {
+ -webkit-transform: scale(-1, -1);
+ transform: scale(-1, -1); }
+
+.fa-rotate-by {
+ -webkit-transform: rotate(var(--fa-rotate-angle, none));
+ transform: rotate(var(--fa-rotate-angle, none)); }
+
+.fa-stack {
+ display: inline-block;
+ height: 2em;
+ line-height: 2em;
+ position: relative;
+ vertical-align: middle;
+ width: 2.5em; }
+
+.fa-stack-1x,
+.fa-stack-2x {
+ left: 0;
+ position: absolute;
+ text-align: center;
+ width: 100%;
+ z-index: var(--fa-stack-z-index, auto); }
+
+.fa-stack-1x {
+ line-height: inherit; }
+
+.fa-stack-2x {
+ font-size: 2em; }
+
+.fa-inverse {
+ color: var(--fa-inverse, #fff); }
+
+/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen
+readers do not read off random characters that represent icons */
+
+.fa-0::before {
+ content: "\30"; }
+
+.fa-1::before {
+ content: "\31"; }
+
+.fa-2::before {
+ content: "\32"; }
+
+.fa-3::before {
+ content: "\33"; }
+
+.fa-4::before {
+ content: "\34"; }
+
+.fa-5::before {
+ content: "\35"; }
+
+.fa-6::before {
+ content: "\36"; }
+
+.fa-7::before {
+ content: "\37"; }
+
+.fa-8::before {
+ content: "\38"; }
+
+.fa-9::before {
+ content: "\39"; }
+
+.fa-fill-drip::before {
+ content: "\f576"; }
+
+.fa-arrows-to-circle::before {
+ content: "\e4bd"; }
+
+.fa-circle-chevron-right::before {
+ content: "\f138"; }
+
+.fa-chevron-circle-right::before {
+ content: "\f138"; }
+
+.fa-at::before {
+ content: "\40"; }
+
+.fa-trash-can::before {
+ content: "\f2ed"; }
+
+.fa-trash-alt::before {
+ content: "\f2ed"; }
+
+.fa-text-height::before {
+ content: "\f034"; }
+
+.fa-user-xmark::before {
+ content: "\f235"; }
+
+.fa-user-times::before {
+ content: "\f235"; }
+
+.fa-stethoscope::before {
+ content: "\f0f1"; }
+
+.fa-message::before {
+ content: "\f27a"; }
+
+.fa-comment-alt::before {
+ content: "\f27a"; }
+
+.fa-info::before {
+ content: "\f129"; }
+
+.fa-down-left-and-up-right-to-center::before {
+ content: "\f422"; }
+
+.fa-compress-alt::before {
+ content: "\f422"; }
+
+.fa-explosion::before {
+ content: "\e4e9"; }
+
+.fa-file-lines::before {
+ content: "\f15c"; }
+
+.fa-file-alt::before {
+ content: "\f15c"; }
+
+.fa-file-text::before {
+ content: "\f15c"; }
+
+.fa-wave-square::before {
+ content: "\f83e"; }
+
+.fa-ring::before {
+ content: "\f70b"; }
+
+.fa-building-un::before {
+ content: "\e4d9"; }
+
+.fa-dice-three::before {
+ content: "\f527"; }
+
+.fa-calendar-days::before {
+ content: "\f073"; }
+
+.fa-calendar-alt::before {
+ content: "\f073"; }
+
+.fa-anchor-circle-check::before {
+ content: "\e4aa"; }
+
+.fa-building-circle-arrow-right::before {
+ content: "\e4d1"; }
+
+.fa-volleyball::before {
+ content: "\f45f"; }
+
+.fa-volleyball-ball::before {
+ content: "\f45f"; }
+
+.fa-arrows-up-to-line::before {
+ content: "\e4c2"; }
+
+.fa-sort-down::before {
+ content: "\f0dd"; }
+
+.fa-sort-desc::before {
+ content: "\f0dd"; }
+
+.fa-circle-minus::before {
+ content: "\f056"; }
+
+.fa-minus-circle::before {
+ content: "\f056"; }
+
+.fa-door-open::before {
+ content: "\f52b"; }
+
+.fa-right-from-bracket::before {
+ content: "\f2f5"; }
+
+.fa-sign-out-alt::before {
+ content: "\f2f5"; }
+
+.fa-atom::before {
+ content: "\f5d2"; }
+
+.fa-soap::before {
+ content: "\e06e"; }
+
+.fa-icons::before {
+ content: "\f86d"; }
+
+.fa-heart-music-camera-bolt::before {
+ content: "\f86d"; }
+
+.fa-microphone-lines-slash::before {
+ content: "\f539"; }
+
+.fa-microphone-alt-slash::before {
+ content: "\f539"; }
+
+.fa-bridge-circle-check::before {
+ content: "\e4c9"; }
+
+.fa-pump-medical::before {
+ content: "\e06a"; }
+
+.fa-fingerprint::before {
+ content: "\f577"; }
+
+.fa-hand-point-right::before {
+ content: "\f0a4"; }
+
+.fa-magnifying-glass-location::before {
+ content: "\f689"; }
+
+.fa-search-location::before {
+ content: "\f689"; }
+
+.fa-forward-step::before {
+ content: "\f051"; }
+
+.fa-step-forward::before {
+ content: "\f051"; }
+
+.fa-face-smile-beam::before {
+ content: "\f5b8"; }
+
+.fa-smile-beam::before {
+ content: "\f5b8"; }
+
+.fa-flag-checkered::before {
+ content: "\f11e"; }
+
+.fa-football::before {
+ content: "\f44e"; }
+
+.fa-football-ball::before {
+ content: "\f44e"; }
+
+.fa-school-circle-exclamation::before {
+ content: "\e56c"; }
+
+.fa-crop::before {
+ content: "\f125"; }
+
+.fa-angles-down::before {
+ content: "\f103"; }
+
+.fa-angle-double-down::before {
+ content: "\f103"; }
+
+.fa-users-rectangle::before {
+ content: "\e594"; }
+
+.fa-people-roof::before {
+ content: "\e537"; }
+
+.fa-people-line::before {
+ content: "\e534"; }
+
+.fa-beer-mug-empty::before {
+ content: "\f0fc"; }
+
+.fa-beer::before {
+ content: "\f0fc"; }
+
+.fa-diagram-predecessor::before {
+ content: "\e477"; }
+
+.fa-arrow-up-long::before {
+ content: "\f176"; }
+
+.fa-long-arrow-up::before {
+ content: "\f176"; }
+
+.fa-fire-flame-simple::before {
+ content: "\f46a"; }
+
+.fa-burn::before {
+ content: "\f46a"; }
+
+.fa-person::before {
+ content: "\f183"; }
+
+.fa-male::before {
+ content: "\f183"; }
+
+.fa-laptop::before {
+ content: "\f109"; }
+
+.fa-file-csv::before {
+ content: "\f6dd"; }
+
+.fa-menorah::before {
+ content: "\f676"; }
+
+.fa-truck-plane::before {
+ content: "\e58f"; }
+
+.fa-record-vinyl::before {
+ content: "\f8d9"; }
+
+.fa-face-grin-stars::before {
+ content: "\f587"; }
+
+.fa-grin-stars::before {
+ content: "\f587"; }
+
+.fa-bong::before {
+ content: "\f55c"; }
+
+.fa-spaghetti-monster-flying::before {
+ content: "\f67b"; }
+
+.fa-pastafarianism::before {
+ content: "\f67b"; }
+
+.fa-arrow-down-up-across-line::before {
+ content: "\e4af"; }
+
+.fa-spoon::before {
+ content: "\f2e5"; }
+
+.fa-utensil-spoon::before {
+ content: "\f2e5"; }
+
+.fa-jar-wheat::before {
+ content: "\e517"; }
+
+.fa-envelopes-bulk::before {
+ content: "\f674"; }
+
+.fa-mail-bulk::before {
+ content: "\f674"; }
+
+.fa-file-circle-exclamation::before {
+ content: "\e4eb"; }
+
+.fa-circle-h::before {
+ content: "\f47e"; }
+
+.fa-hospital-symbol::before {
+ content: "\f47e"; }
+
+.fa-pager::before {
+ content: "\f815"; }
+
+.fa-address-book::before {
+ content: "\f2b9"; }
+
+.fa-contact-book::before {
+ content: "\f2b9"; }
+
+.fa-strikethrough::before {
+ content: "\f0cc"; }
+
+.fa-k::before {
+ content: "\4b"; }
+
+.fa-landmark-flag::before {
+ content: "\e51c"; }
+
+.fa-pencil::before {
+ content: "\f303"; }
+
+.fa-pencil-alt::before {
+ content: "\f303"; }
+
+.fa-backward::before {
+ content: "\f04a"; }
+
+.fa-caret-right::before {
+ content: "\f0da"; }
+
+.fa-comments::before {
+ content: "\f086"; }
+
+.fa-paste::before {
+ content: "\f0ea"; }
+
+.fa-file-clipboard::before {
+ content: "\f0ea"; }
+
+.fa-code-pull-request::before {
+ content: "\e13c"; }
+
+.fa-clipboard-list::before {
+ content: "\f46d"; }
+
+.fa-truck-ramp-box::before {
+ content: "\f4de"; }
+
+.fa-truck-loading::before {
+ content: "\f4de"; }
+
+.fa-user-check::before {
+ content: "\f4fc"; }
+
+.fa-vial-virus::before {
+ content: "\e597"; }
+
+.fa-sheet-plastic::before {
+ content: "\e571"; }
+
+.fa-blog::before {
+ content: "\f781"; }
+
+.fa-user-ninja::before {
+ content: "\f504"; }
+
+.fa-person-arrow-up-from-line::before {
+ content: "\e539"; }
+
+.fa-scroll-torah::before {
+ content: "\f6a0"; }
+
+.fa-torah::before {
+ content: "\f6a0"; }
+
+.fa-broom-ball::before {
+ content: "\f458"; }
+
+.fa-quidditch::before {
+ content: "\f458"; }
+
+.fa-quidditch-broom-ball::before {
+ content: "\f458"; }
+
+.fa-toggle-off::before {
+ content: "\f204"; }
+
+.fa-box-archive::before {
+ content: "\f187"; }
+
+.fa-archive::before {
+ content: "\f187"; }
+
+.fa-person-drowning::before {
+ content: "\e545"; }
+
+.fa-arrow-down-9-1::before {
+ content: "\f886"; }
+
+.fa-sort-numeric-desc::before {
+ content: "\f886"; }
+
+.fa-sort-numeric-down-alt::before {
+ content: "\f886"; }
+
+.fa-face-grin-tongue-squint::before {
+ content: "\f58a"; }
+
+.fa-grin-tongue-squint::before {
+ content: "\f58a"; }
+
+.fa-spray-can::before {
+ content: "\f5bd"; }
+
+.fa-truck-monster::before {
+ content: "\f63b"; }
+
+.fa-w::before {
+ content: "\57"; }
+
+.fa-earth-africa::before {
+ content: "\f57c"; }
+
+.fa-globe-africa::before {
+ content: "\f57c"; }
+
+.fa-rainbow::before {
+ content: "\f75b"; }
+
+.fa-circle-notch::before {
+ content: "\f1ce"; }
+
+.fa-tablet-screen-button::before {
+ content: "\f3fa"; }
+
+.fa-tablet-alt::before {
+ content: "\f3fa"; }
+
+.fa-paw::before {
+ content: "\f1b0"; }
+
+.fa-cloud::before {
+ content: "\f0c2"; }
+
+.fa-trowel-bricks::before {
+ content: "\e58a"; }
+
+.fa-face-flushed::before {
+ content: "\f579"; }
+
+.fa-flushed::before {
+ content: "\f579"; }
+
+.fa-hospital-user::before {
+ content: "\f80d"; }
+
+.fa-tent-arrow-left-right::before {
+ content: "\e57f"; }
+
+.fa-gavel::before {
+ content: "\f0e3"; }
+
+.fa-legal::before {
+ content: "\f0e3"; }
+
+.fa-binoculars::before {
+ content: "\f1e5"; }
+
+.fa-microphone-slash::before {
+ content: "\f131"; }
+
+.fa-box-tissue::before {
+ content: "\e05b"; }
+
+.fa-motorcycle::before {
+ content: "\f21c"; }
+
+.fa-bell-concierge::before {
+ content: "\f562"; }
+
+.fa-concierge-bell::before {
+ content: "\f562"; }
+
+.fa-pen-ruler::before {
+ content: "\f5ae"; }
+
+.fa-pencil-ruler::before {
+ content: "\f5ae"; }
+
+.fa-people-arrows::before {
+ content: "\e068"; }
+
+.fa-people-arrows-left-right::before {
+ content: "\e068"; }
+
+.fa-mars-and-venus-burst::before {
+ content: "\e523"; }
+
+.fa-square-caret-right::before {
+ content: "\f152"; }
+
+.fa-caret-square-right::before {
+ content: "\f152"; }
+
+.fa-scissors::before {
+ content: "\f0c4"; }
+
+.fa-cut::before {
+ content: "\f0c4"; }
+
+.fa-sun-plant-wilt::before {
+ content: "\e57a"; }
+
+.fa-toilets-portable::before {
+ content: "\e584"; }
+
+.fa-hockey-puck::before {
+ content: "\f453"; }
+
+.fa-table::before {
+ content: "\f0ce"; }
+
+.fa-magnifying-glass-arrow-right::before {
+ content: "\e521"; }
+
+.fa-tachograph-digital::before {
+ content: "\f566"; }
+
+.fa-digital-tachograph::before {
+ content: "\f566"; }
+
+.fa-users-slash::before {
+ content: "\e073"; }
+
+.fa-clover::before {
+ content: "\e139"; }
+
+.fa-reply::before {
+ content: "\f3e5"; }
+
+.fa-mail-reply::before {
+ content: "\f3e5"; }
+
+.fa-star-and-crescent::before {
+ content: "\f699"; }
+
+.fa-house-fire::before {
+ content: "\e50c"; }
+
+.fa-square-minus::before {
+ content: "\f146"; }
+
+.fa-minus-square::before {
+ content: "\f146"; }
+
+.fa-helicopter::before {
+ content: "\f533"; }
+
+.fa-compass::before {
+ content: "\f14e"; }
+
+.fa-square-caret-down::before {
+ content: "\f150"; }
+
+.fa-caret-square-down::before {
+ content: "\f150"; }
+
+.fa-file-circle-question::before {
+ content: "\e4ef"; }
+
+.fa-laptop-code::before {
+ content: "\f5fc"; }
+
+.fa-swatchbook::before {
+ content: "\f5c3"; }
+
+.fa-prescription-bottle::before {
+ content: "\f485"; }
+
+.fa-bars::before {
+ content: "\f0c9"; }
+
+.fa-navicon::before {
+ content: "\f0c9"; }
+
+.fa-people-group::before {
+ content: "\e533"; }
+
+.fa-hourglass-end::before {
+ content: "\f253"; }
+
+.fa-hourglass-3::before {
+ content: "\f253"; }
+
+.fa-heart-crack::before {
+ content: "\f7a9"; }
+
+.fa-heart-broken::before {
+ content: "\f7a9"; }
+
+.fa-square-up-right::before {
+ content: "\f360"; }
+
+.fa-external-link-square-alt::before {
+ content: "\f360"; }
+
+.fa-face-kiss-beam::before {
+ content: "\f597"; }
+
+.fa-kiss-beam::before {
+ content: "\f597"; }
+
+.fa-film::before {
+ content: "\f008"; }
+
+.fa-ruler-horizontal::before {
+ content: "\f547"; }
+
+.fa-people-robbery::before {
+ content: "\e536"; }
+
+.fa-lightbulb::before {
+ content: "\f0eb"; }
+
+.fa-caret-left::before {
+ content: "\f0d9"; }
+
+.fa-circle-exclamation::before {
+ content: "\f06a"; }
+
+.fa-exclamation-circle::before {
+ content: "\f06a"; }
+
+.fa-school-circle-xmark::before {
+ content: "\e56d"; }
+
+.fa-arrow-right-from-bracket::before {
+ content: "\f08b"; }
+
+.fa-sign-out::before {
+ content: "\f08b"; }
+
+.fa-circle-chevron-down::before {
+ content: "\f13a"; }
+
+.fa-chevron-circle-down::before {
+ content: "\f13a"; }
+
+.fa-unlock-keyhole::before {
+ content: "\f13e"; }
+
+.fa-unlock-alt::before {
+ content: "\f13e"; }
+
+.fa-cloud-showers-heavy::before {
+ content: "\f740"; }
+
+.fa-headphones-simple::before {
+ content: "\f58f"; }
+
+.fa-headphones-alt::before {
+ content: "\f58f"; }
+
+.fa-sitemap::before {
+ content: "\f0e8"; }
+
+.fa-circle-dollar-to-slot::before {
+ content: "\f4b9"; }
+
+.fa-donate::before {
+ content: "\f4b9"; }
+
+.fa-memory::before {
+ content: "\f538"; }
+
+.fa-road-spikes::before {
+ content: "\e568"; }
+
+.fa-fire-burner::before {
+ content: "\e4f1"; }
+
+.fa-flag::before {
+ content: "\f024"; }
+
+.fa-hanukiah::before {
+ content: "\f6e6"; }
+
+.fa-feather::before {
+ content: "\f52d"; }
+
+.fa-volume-low::before {
+ content: "\f027"; }
+
+.fa-volume-down::before {
+ content: "\f027"; }
+
+.fa-comment-slash::before {
+ content: "\f4b3"; }
+
+.fa-cloud-sun-rain::before {
+ content: "\f743"; }
+
+.fa-compress::before {
+ content: "\f066"; }
+
+.fa-wheat-awn::before {
+ content: "\e2cd"; }
+
+.fa-wheat-alt::before {
+ content: "\e2cd"; }
+
+.fa-ankh::before {
+ content: "\f644"; }
+
+.fa-hands-holding-child::before {
+ content: "\e4fa"; }
+
+.fa-asterisk::before {
+ content: "\2a"; }
+
+.fa-square-check::before {
+ content: "\f14a"; }
+
+.fa-check-square::before {
+ content: "\f14a"; }
+
+.fa-peseta-sign::before {
+ content: "\e221"; }
+
+.fa-heading::before {
+ content: "\f1dc"; }
+
+.fa-header::before {
+ content: "\f1dc"; }
+
+.fa-ghost::before {
+ content: "\f6e2"; }
+
+.fa-list::before {
+ content: "\f03a"; }
+
+.fa-list-squares::before {
+ content: "\f03a"; }
+
+.fa-square-phone-flip::before {
+ content: "\f87b"; }
+
+.fa-phone-square-alt::before {
+ content: "\f87b"; }
+
+.fa-cart-plus::before {
+ content: "\f217"; }
+
+.fa-gamepad::before {
+ content: "\f11b"; }
+
+.fa-circle-dot::before {
+ content: "\f192"; }
+
+.fa-dot-circle::before {
+ content: "\f192"; }
+
+.fa-face-dizzy::before {
+ content: "\f567"; }
+
+.fa-dizzy::before {
+ content: "\f567"; }
+
+.fa-egg::before {
+ content: "\f7fb"; }
+
+.fa-house-medical-circle-xmark::before {
+ content: "\e513"; }
+
+.fa-campground::before {
+ content: "\f6bb"; }
+
+.fa-folder-plus::before {
+ content: "\f65e"; }
+
+.fa-futbol::before {
+ content: "\f1e3"; }
+
+.fa-futbol-ball::before {
+ content: "\f1e3"; }
+
+.fa-soccer-ball::before {
+ content: "\f1e3"; }
+
+.fa-paintbrush::before {
+ content: "\f1fc"; }
+
+.fa-paint-brush::before {
+ content: "\f1fc"; }
+
+.fa-lock::before {
+ content: "\f023"; }
+
+.fa-gas-pump::before {
+ content: "\f52f"; }
+
+.fa-hot-tub-person::before {
+ content: "\f593"; }
+
+.fa-hot-tub::before {
+ content: "\f593"; }
+
+.fa-map-location::before {
+ content: "\f59f"; }
+
+.fa-map-marked::before {
+ content: "\f59f"; }
+
+.fa-house-flood-water::before {
+ content: "\e50e"; }
+
+.fa-tree::before {
+ content: "\f1bb"; }
+
+.fa-bridge-lock::before {
+ content: "\e4cc"; }
+
+.fa-sack-dollar::before {
+ content: "\f81d"; }
+
+.fa-pen-to-square::before {
+ content: "\f044"; }
+
+.fa-edit::before {
+ content: "\f044"; }
+
+.fa-car-side::before {
+ content: "\f5e4"; }
+
+.fa-share-nodes::before {
+ content: "\f1e0"; }
+
+.fa-share-alt::before {
+ content: "\f1e0"; }
+
+.fa-heart-circle-minus::before {
+ content: "\e4ff"; }
+
+.fa-hourglass-half::before {
+ content: "\f252"; }
+
+.fa-hourglass-2::before {
+ content: "\f252"; }
+
+.fa-microscope::before {
+ content: "\f610"; }
+
+.fa-sink::before {
+ content: "\e06d"; }
+
+.fa-bag-shopping::before {
+ content: "\f290"; }
+
+.fa-shopping-bag::before {
+ content: "\f290"; }
+
+.fa-arrow-down-z-a::before {
+ content: "\f881"; }
+
+.fa-sort-alpha-desc::before {
+ content: "\f881"; }
+
+.fa-sort-alpha-down-alt::before {
+ content: "\f881"; }
+
+.fa-mitten::before {
+ content: "\f7b5"; }
+
+.fa-person-rays::before {
+ content: "\e54d"; }
+
+.fa-users::before {
+ content: "\f0c0"; }
+
+.fa-eye-slash::before {
+ content: "\f070"; }
+
+.fa-flask-vial::before {
+ content: "\e4f3"; }
+
+.fa-hand::before {
+ content: "\f256"; }
+
+.fa-hand-paper::before {
+ content: "\f256"; }
+
+.fa-om::before {
+ content: "\f679"; }
+
+.fa-worm::before {
+ content: "\e599"; }
+
+.fa-house-circle-xmark::before {
+ content: "\e50b"; }
+
+.fa-plug::before {
+ content: "\f1e6"; }
+
+.fa-chevron-up::before {
+ content: "\f077"; }
+
+.fa-hand-spock::before {
+ content: "\f259"; }
+
+.fa-stopwatch::before {
+ content: "\f2f2"; }
+
+.fa-face-kiss::before {
+ content: "\f596"; }
+
+.fa-kiss::before {
+ content: "\f596"; }
+
+.fa-bridge-circle-xmark::before {
+ content: "\e4cb"; }
+
+.fa-face-grin-tongue::before {
+ content: "\f589"; }
+
+.fa-grin-tongue::before {
+ content: "\f589"; }
+
+.fa-chess-bishop::before {
+ content: "\f43a"; }
+
+.fa-face-grin-wink::before {
+ content: "\f58c"; }
+
+.fa-grin-wink::before {
+ content: "\f58c"; }
+
+.fa-ear-deaf::before {
+ content: "\f2a4"; }
+
+.fa-deaf::before {
+ content: "\f2a4"; }
+
+.fa-deafness::before {
+ content: "\f2a4"; }
+
+.fa-hard-of-hearing::before {
+ content: "\f2a4"; }
+
+.fa-road-circle-check::before {
+ content: "\e564"; }
+
+.fa-dice-five::before {
+ content: "\f523"; }
+
+.fa-square-rss::before {
+ content: "\f143"; }
+
+.fa-rss-square::before {
+ content: "\f143"; }
+
+.fa-land-mine-on::before {
+ content: "\e51b"; }
+
+.fa-i-cursor::before {
+ content: "\f246"; }
+
+.fa-stamp::before {
+ content: "\f5bf"; }
+
+.fa-stairs::before {
+ content: "\e289"; }
+
+.fa-i::before {
+ content: "\49"; }
+
+.fa-hryvnia-sign::before {
+ content: "\f6f2"; }
+
+.fa-hryvnia::before {
+ content: "\f6f2"; }
+
+.fa-pills::before {
+ content: "\f484"; }
+
+.fa-face-grin-wide::before {
+ content: "\f581"; }
+
+.fa-grin-alt::before {
+ content: "\f581"; }
+
+.fa-tooth::before {
+ content: "\f5c9"; }
+
+.fa-v::before {
+ content: "\56"; }
+
+.fa-bangladeshi-taka-sign::before {
+ content: "\e2e6"; }
+
+.fa-bicycle::before {
+ content: "\f206"; }
+
+.fa-staff-snake::before {
+ content: "\e579"; }
+
+.fa-rod-asclepius::before {
+ content: "\e579"; }
+
+.fa-rod-snake::before {
+ content: "\e579"; }
+
+.fa-staff-aesculapius::before {
+ content: "\e579"; }
+
+.fa-head-side-cough-slash::before {
+ content: "\e062"; }
+
+.fa-truck-medical::before {
+ content: "\f0f9"; }
+
+.fa-ambulance::before {
+ content: "\f0f9"; }
+
+.fa-wheat-awn-circle-exclamation::before {
+ content: "\e598"; }
+
+.fa-snowman::before {
+ content: "\f7d0"; }
+
+.fa-mortar-pestle::before {
+ content: "\f5a7"; }
+
+.fa-road-barrier::before {
+ content: "\e562"; }
+
+.fa-school::before {
+ content: "\f549"; }
+
+.fa-igloo::before {
+ content: "\f7ae"; }
+
+.fa-joint::before {
+ content: "\f595"; }
+
+.fa-angle-right::before {
+ content: "\f105"; }
+
+.fa-horse::before {
+ content: "\f6f0"; }
+
+.fa-q::before {
+ content: "\51"; }
+
+.fa-g::before {
+ content: "\47"; }
+
+.fa-notes-medical::before {
+ content: "\f481"; }
+
+.fa-temperature-half::before {
+ content: "\f2c9"; }
+
+.fa-temperature-2::before {
+ content: "\f2c9"; }
+
+.fa-thermometer-2::before {
+ content: "\f2c9"; }
+
+.fa-thermometer-half::before {
+ content: "\f2c9"; }
+
+.fa-dong-sign::before {
+ content: "\e169"; }
+
+.fa-capsules::before {
+ content: "\f46b"; }
+
+.fa-poo-storm::before {
+ content: "\f75a"; }
+
+.fa-poo-bolt::before {
+ content: "\f75a"; }
+
+.fa-face-frown-open::before {
+ content: "\f57a"; }
+
+.fa-frown-open::before {
+ content: "\f57a"; }
+
+.fa-hand-point-up::before {
+ content: "\f0a6"; }
+
+.fa-money-bill::before {
+ content: "\f0d6"; }
+
+.fa-bookmark::before {
+ content: "\f02e"; }
+
+.fa-align-justify::before {
+ content: "\f039"; }
+
+.fa-umbrella-beach::before {
+ content: "\f5ca"; }
+
+.fa-helmet-un::before {
+ content: "\e503"; }
+
+.fa-bullseye::before {
+ content: "\f140"; }
+
+.fa-bacon::before {
+ content: "\f7e5"; }
+
+.fa-hand-point-down::before {
+ content: "\f0a7"; }
+
+.fa-arrow-up-from-bracket::before {
+ content: "\e09a"; }
+
+.fa-folder::before {
+ content: "\f07b"; }
+
+.fa-folder-blank::before {
+ content: "\f07b"; }
+
+.fa-file-waveform::before {
+ content: "\f478"; }
+
+.fa-file-medical-alt::before {
+ content: "\f478"; }
+
+.fa-radiation::before {
+ content: "\f7b9"; }
+
+.fa-chart-simple::before {
+ content: "\e473"; }
+
+.fa-mars-stroke::before {
+ content: "\f229"; }
+
+.fa-vial::before {
+ content: "\f492"; }
+
+.fa-gauge::before {
+ content: "\f624"; }
+
+.fa-dashboard::before {
+ content: "\f624"; }
+
+.fa-gauge-med::before {
+ content: "\f624"; }
+
+.fa-tachometer-alt-average::before {
+ content: "\f624"; }
+
+.fa-wand-magic-sparkles::before {
+ content: "\e2ca"; }
+
+.fa-magic-wand-sparkles::before {
+ content: "\e2ca"; }
+
+.fa-e::before {
+ content: "\45"; }
+
+.fa-pen-clip::before {
+ content: "\f305"; }
+
+.fa-pen-alt::before {
+ content: "\f305"; }
+
+.fa-bridge-circle-exclamation::before {
+ content: "\e4ca"; }
+
+.fa-user::before {
+ content: "\f007"; }
+
+.fa-school-circle-check::before {
+ content: "\e56b"; }
+
+.fa-dumpster::before {
+ content: "\f793"; }
+
+.fa-van-shuttle::before {
+ content: "\f5b6"; }
+
+.fa-shuttle-van::before {
+ content: "\f5b6"; }
+
+.fa-building-user::before {
+ content: "\e4da"; }
+
+.fa-square-caret-left::before {
+ content: "\f191"; }
+
+.fa-caret-square-left::before {
+ content: "\f191"; }
+
+.fa-highlighter::before {
+ content: "\f591"; }
+
+.fa-key::before {
+ content: "\f084"; }
+
+.fa-bullhorn::before {
+ content: "\f0a1"; }
+
+.fa-globe::before {
+ content: "\f0ac"; }
+
+.fa-synagogue::before {
+ content: "\f69b"; }
+
+.fa-person-half-dress::before {
+ content: "\e548"; }
+
+.fa-road-bridge::before {
+ content: "\e563"; }
+
+.fa-location-arrow::before {
+ content: "\f124"; }
+
+.fa-c::before {
+ content: "\43"; }
+
+.fa-tablet-button::before {
+ content: "\f10a"; }
+
+.fa-building-lock::before {
+ content: "\e4d6"; }
+
+.fa-pizza-slice::before {
+ content: "\f818"; }
+
+.fa-money-bill-wave::before {
+ content: "\f53a"; }
+
+.fa-chart-area::before {
+ content: "\f1fe"; }
+
+.fa-area-chart::before {
+ content: "\f1fe"; }
+
+.fa-house-flag::before {
+ content: "\e50d"; }
+
+.fa-person-circle-minus::before {
+ content: "\e540"; }
+
+.fa-ban::before {
+ content: "\f05e"; }
+
+.fa-cancel::before {
+ content: "\f05e"; }
+
+.fa-camera-rotate::before {
+ content: "\e0d8"; }
+
+.fa-spray-can-sparkles::before {
+ content: "\f5d0"; }
+
+.fa-air-freshener::before {
+ content: "\f5d0"; }
+
+.fa-star::before {
+ content: "\f005"; }
+
+.fa-repeat::before {
+ content: "\f363"; }
+
+.fa-cross::before {
+ content: "\f654"; }
+
+.fa-box::before {
+ content: "\f466"; }
+
+.fa-venus-mars::before {
+ content: "\f228"; }
+
+.fa-arrow-pointer::before {
+ content: "\f245"; }
+
+.fa-mouse-pointer::before {
+ content: "\f245"; }
+
+.fa-maximize::before {
+ content: "\f31e"; }
+
+.fa-expand-arrows-alt::before {
+ content: "\f31e"; }
+
+.fa-charging-station::before {
+ content: "\f5e7"; }
+
+.fa-shapes::before {
+ content: "\f61f"; }
+
+.fa-triangle-circle-square::before {
+ content: "\f61f"; }
+
+.fa-shuffle::before {
+ content: "\f074"; }
+
+.fa-random::before {
+ content: "\f074"; }
+
+.fa-person-running::before {
+ content: "\f70c"; }
+
+.fa-running::before {
+ content: "\f70c"; }
+
+.fa-mobile-retro::before {
+ content: "\e527"; }
+
+.fa-grip-lines-vertical::before {
+ content: "\f7a5"; }
+
+.fa-spider::before {
+ content: "\f717"; }
+
+.fa-hands-bound::before {
+ content: "\e4f9"; }
+
+.fa-file-invoice-dollar::before {
+ content: "\f571"; }
+
+.fa-plane-circle-exclamation::before {
+ content: "\e556"; }
+
+.fa-x-ray::before {
+ content: "\f497"; }
+
+.fa-spell-check::before {
+ content: "\f891"; }
+
+.fa-slash::before {
+ content: "\f715"; }
+
+.fa-computer-mouse::before {
+ content: "\f8cc"; }
+
+.fa-mouse::before {
+ content: "\f8cc"; }
+
+.fa-arrow-right-to-bracket::before {
+ content: "\f090"; }
+
+.fa-sign-in::before {
+ content: "\f090"; }
+
+.fa-shop-slash::before {
+ content: "\e070"; }
+
+.fa-store-alt-slash::before {
+ content: "\e070"; }
+
+.fa-server::before {
+ content: "\f233"; }
+
+.fa-virus-covid-slash::before {
+ content: "\e4a9"; }
+
+.fa-shop-lock::before {
+ content: "\e4a5"; }
+
+.fa-hourglass-start::before {
+ content: "\f251"; }
+
+.fa-hourglass-1::before {
+ content: "\f251"; }
+
+.fa-blender-phone::before {
+ content: "\f6b6"; }
+
+.fa-building-wheat::before {
+ content: "\e4db"; }
+
+.fa-person-breastfeeding::before {
+ content: "\e53a"; }
+
+.fa-right-to-bracket::before {
+ content: "\f2f6"; }
+
+.fa-sign-in-alt::before {
+ content: "\f2f6"; }
+
+.fa-venus::before {
+ content: "\f221"; }
+
+.fa-passport::before {
+ content: "\f5ab"; }
+
+.fa-heart-pulse::before {
+ content: "\f21e"; }
+
+.fa-heartbeat::before {
+ content: "\f21e"; }
+
+.fa-people-carry-box::before {
+ content: "\f4ce"; }
+
+.fa-people-carry::before {
+ content: "\f4ce"; }
+
+.fa-temperature-high::before {
+ content: "\f769"; }
+
+.fa-microchip::before {
+ content: "\f2db"; }
+
+.fa-crown::before {
+ content: "\f521"; }
+
+.fa-weight-hanging::before {
+ content: "\f5cd"; }
+
+.fa-xmarks-lines::before {
+ content: "\e59a"; }
+
+.fa-file-prescription::before {
+ content: "\f572"; }
+
+.fa-weight-scale::before {
+ content: "\f496"; }
+
+.fa-weight::before {
+ content: "\f496"; }
+
+.fa-user-group::before {
+ content: "\f500"; }
+
+.fa-user-friends::before {
+ content: "\f500"; }
+
+.fa-arrow-up-a-z::before {
+ content: "\f15e"; }
+
+.fa-sort-alpha-up::before {
+ content: "\f15e"; }
+
+.fa-chess-knight::before {
+ content: "\f441"; }
+
+.fa-face-laugh-squint::before {
+ content: "\f59b"; }
+
+.fa-laugh-squint::before {
+ content: "\f59b"; }
+
+.fa-wheelchair::before {
+ content: "\f193"; }
+
+.fa-circle-arrow-up::before {
+ content: "\f0aa"; }
+
+.fa-arrow-circle-up::before {
+ content: "\f0aa"; }
+
+.fa-toggle-on::before {
+ content: "\f205"; }
+
+.fa-person-walking::before {
+ content: "\f554"; }
+
+.fa-walking::before {
+ content: "\f554"; }
+
+.fa-l::before {
+ content: "\4c"; }
+
+.fa-fire::before {
+ content: "\f06d"; }
+
+.fa-bed-pulse::before {
+ content: "\f487"; }
+
+.fa-procedures::before {
+ content: "\f487"; }
+
+.fa-shuttle-space::before {
+ content: "\f197"; }
+
+.fa-space-shuttle::before {
+ content: "\f197"; }
+
+.fa-face-laugh::before {
+ content: "\f599"; }
+
+.fa-laugh::before {
+ content: "\f599"; }
+
+.fa-folder-open::before {
+ content: "\f07c"; }
+
+.fa-heart-circle-plus::before {
+ content: "\e500"; }
+
+.fa-code-fork::before {
+ content: "\e13b"; }
+
+.fa-city::before {
+ content: "\f64f"; }
+
+.fa-microphone-lines::before {
+ content: "\f3c9"; }
+
+.fa-microphone-alt::before {
+ content: "\f3c9"; }
+
+.fa-pepper-hot::before {
+ content: "\f816"; }
+
+.fa-unlock::before {
+ content: "\f09c"; }
+
+.fa-colon-sign::before {
+ content: "\e140"; }
+
+.fa-headset::before {
+ content: "\f590"; }
+
+.fa-store-slash::before {
+ content: "\e071"; }
+
+.fa-road-circle-xmark::before {
+ content: "\e566"; }
+
+.fa-user-minus::before {
+ content: "\f503"; }
+
+.fa-mars-stroke-up::before {
+ content: "\f22a"; }
+
+.fa-mars-stroke-v::before {
+ content: "\f22a"; }
+
+.fa-champagne-glasses::before {
+ content: "\f79f"; }
+
+.fa-glass-cheers::before {
+ content: "\f79f"; }
+
+.fa-clipboard::before {
+ content: "\f328"; }
+
+.fa-house-circle-exclamation::before {
+ content: "\e50a"; }
+
+.fa-file-arrow-up::before {
+ content: "\f574"; }
+
+.fa-file-upload::before {
+ content: "\f574"; }
+
+.fa-wifi::before {
+ content: "\f1eb"; }
+
+.fa-wifi-3::before {
+ content: "\f1eb"; }
+
+.fa-wifi-strong::before {
+ content: "\f1eb"; }
+
+.fa-bath::before {
+ content: "\f2cd"; }
+
+.fa-bathtub::before {
+ content: "\f2cd"; }
+
+.fa-underline::before {
+ content: "\f0cd"; }
+
+.fa-user-pen::before {
+ content: "\f4ff"; }
+
+.fa-user-edit::before {
+ content: "\f4ff"; }
+
+.fa-signature::before {
+ content: "\f5b7"; }
+
+.fa-stroopwafel::before {
+ content: "\f551"; }
+
+.fa-bold::before {
+ content: "\f032"; }
+
+.fa-anchor-lock::before {
+ content: "\e4ad"; }
+
+.fa-building-ngo::before {
+ content: "\e4d7"; }
+
+.fa-manat-sign::before {
+ content: "\e1d5"; }
+
+.fa-not-equal::before {
+ content: "\f53e"; }
+
+.fa-border-top-left::before {
+ content: "\f853"; }
+
+.fa-border-style::before {
+ content: "\f853"; }
+
+.fa-map-location-dot::before {
+ content: "\f5a0"; }
+
+.fa-map-marked-alt::before {
+ content: "\f5a0"; }
+
+.fa-jedi::before {
+ content: "\f669"; }
+
+.fa-square-poll-vertical::before {
+ content: "\f681"; }
+
+.fa-poll::before {
+ content: "\f681"; }
+
+.fa-mug-hot::before {
+ content: "\f7b6"; }
+
+.fa-car-battery::before {
+ content: "\f5df"; }
+
+.fa-battery-car::before {
+ content: "\f5df"; }
+
+.fa-gift::before {
+ content: "\f06b"; }
+
+.fa-dice-two::before {
+ content: "\f528"; }
+
+.fa-chess-queen::before {
+ content: "\f445"; }
+
+.fa-glasses::before {
+ content: "\f530"; }
+
+.fa-chess-board::before {
+ content: "\f43c"; }
+
+.fa-building-circle-check::before {
+ content: "\e4d2"; }
+
+.fa-person-chalkboard::before {
+ content: "\e53d"; }
+
+.fa-mars-stroke-right::before {
+ content: "\f22b"; }
+
+.fa-mars-stroke-h::before {
+ content: "\f22b"; }
+
+.fa-hand-back-fist::before {
+ content: "\f255"; }
+
+.fa-hand-rock::before {
+ content: "\f255"; }
+
+.fa-square-caret-up::before {
+ content: "\f151"; }
+
+.fa-caret-square-up::before {
+ content: "\f151"; }
+
+.fa-cloud-showers-water::before {
+ content: "\e4e4"; }
+
+.fa-chart-bar::before {
+ content: "\f080"; }
+
+.fa-bar-chart::before {
+ content: "\f080"; }
+
+.fa-hands-bubbles::before {
+ content: "\e05e"; }
+
+.fa-hands-wash::before {
+ content: "\e05e"; }
+
+.fa-less-than-equal::before {
+ content: "\f537"; }
+
+.fa-train::before {
+ content: "\f238"; }
+
+.fa-eye-low-vision::before {
+ content: "\f2a8"; }
+
+.fa-low-vision::before {
+ content: "\f2a8"; }
+
+.fa-crow::before {
+ content: "\f520"; }
+
+.fa-sailboat::before {
+ content: "\e445"; }
+
+.fa-window-restore::before {
+ content: "\f2d2"; }
+
+.fa-square-plus::before {
+ content: "\f0fe"; }
+
+.fa-plus-square::before {
+ content: "\f0fe"; }
+
+.fa-torii-gate::before {
+ content: "\f6a1"; }
+
+.fa-frog::before {
+ content: "\f52e"; }
+
+.fa-bucket::before {
+ content: "\e4cf"; }
+
+.fa-image::before {
+ content: "\f03e"; }
+
+.fa-microphone::before {
+ content: "\f130"; }
+
+.fa-cow::before {
+ content: "\f6c8"; }
+
+.fa-caret-up::before {
+ content: "\f0d8"; }
+
+.fa-screwdriver::before {
+ content: "\f54a"; }
+
+.fa-folder-closed::before {
+ content: "\e185"; }
+
+.fa-house-tsunami::before {
+ content: "\e515"; }
+
+.fa-square-nfi::before {
+ content: "\e576"; }
+
+.fa-arrow-up-from-ground-water::before {
+ content: "\e4b5"; }
+
+.fa-martini-glass::before {
+ content: "\f57b"; }
+
+.fa-glass-martini-alt::before {
+ content: "\f57b"; }
+
+.fa-rotate-left::before {
+ content: "\f2ea"; }
+
+.fa-rotate-back::before {
+ content: "\f2ea"; }
+
+.fa-rotate-backward::before {
+ content: "\f2ea"; }
+
+.fa-undo-alt::before {
+ content: "\f2ea"; }
+
+.fa-table-columns::before {
+ content: "\f0db"; }
+
+.fa-columns::before {
+ content: "\f0db"; }
+
+.fa-lemon::before {
+ content: "\f094"; }
+
+.fa-head-side-mask::before {
+ content: "\e063"; }
+
+.fa-handshake::before {
+ content: "\f2b5"; }
+
+.fa-gem::before {
+ content: "\f3a5"; }
+
+.fa-dolly::before {
+ content: "\f472"; }
+
+.fa-dolly-box::before {
+ content: "\f472"; }
+
+.fa-smoking::before {
+ content: "\f48d"; }
+
+.fa-minimize::before {
+ content: "\f78c"; }
+
+.fa-compress-arrows-alt::before {
+ content: "\f78c"; }
+
+.fa-monument::before {
+ content: "\f5a6"; }
+
+.fa-snowplow::before {
+ content: "\f7d2"; }
+
+.fa-angles-right::before {
+ content: "\f101"; }
+
+.fa-angle-double-right::before {
+ content: "\f101"; }
+
+.fa-cannabis::before {
+ content: "\f55f"; }
+
+.fa-circle-play::before {
+ content: "\f144"; }
+
+.fa-play-circle::before {
+ content: "\f144"; }
+
+.fa-tablets::before {
+ content: "\f490"; }
+
+.fa-ethernet::before {
+ content: "\f796"; }
+
+.fa-euro-sign::before {
+ content: "\f153"; }
+
+.fa-eur::before {
+ content: "\f153"; }
+
+.fa-euro::before {
+ content: "\f153"; }
+
+.fa-chair::before {
+ content: "\f6c0"; }
+
+.fa-circle-check::before {
+ content: "\f058"; }
+
+.fa-check-circle::before {
+ content: "\f058"; }
+
+.fa-circle-stop::before {
+ content: "\f28d"; }
+
+.fa-stop-circle::before {
+ content: "\f28d"; }
+
+.fa-compass-drafting::before {
+ content: "\f568"; }
+
+.fa-drafting-compass::before {
+ content: "\f568"; }
+
+.fa-plate-wheat::before {
+ content: "\e55a"; }
+
+.fa-icicles::before {
+ content: "\f7ad"; }
+
+.fa-person-shelter::before {
+ content: "\e54f"; }
+
+.fa-neuter::before {
+ content: "\f22c"; }
+
+.fa-id-badge::before {
+ content: "\f2c1"; }
+
+.fa-marker::before {
+ content: "\f5a1"; }
+
+.fa-face-laugh-beam::before {
+ content: "\f59a"; }
+
+.fa-laugh-beam::before {
+ content: "\f59a"; }
+
+.fa-helicopter-symbol::before {
+ content: "\e502"; }
+
+.fa-universal-access::before {
+ content: "\f29a"; }
+
+.fa-circle-chevron-up::before {
+ content: "\f139"; }
+
+.fa-chevron-circle-up::before {
+ content: "\f139"; }
+
+.fa-lari-sign::before {
+ content: "\e1c8"; }
+
+.fa-volcano::before {
+ content: "\f770"; }
+
+.fa-person-walking-dashed-line-arrow-right::before {
+ content: "\e553"; }
+
+.fa-sterling-sign::before {
+ content: "\f154"; }
+
+.fa-gbp::before {
+ content: "\f154"; }
+
+.fa-pound-sign::before {
+ content: "\f154"; }
+
+.fa-viruses::before {
+ content: "\e076"; }
+
+.fa-square-person-confined::before {
+ content: "\e577"; }
+
+.fa-user-tie::before {
+ content: "\f508"; }
+
+.fa-arrow-down-long::before {
+ content: "\f175"; }
+
+.fa-long-arrow-down::before {
+ content: "\f175"; }
+
+.fa-tent-arrow-down-to-line::before {
+ content: "\e57e"; }
+
+.fa-certificate::before {
+ content: "\f0a3"; }
+
+.fa-reply-all::before {
+ content: "\f122"; }
+
+.fa-mail-reply-all::before {
+ content: "\f122"; }
+
+.fa-suitcase::before {
+ content: "\f0f2"; }
+
+.fa-person-skating::before {
+ content: "\f7c5"; }
+
+.fa-skating::before {
+ content: "\f7c5"; }
+
+.fa-filter-circle-dollar::before {
+ content: "\f662"; }
+
+.fa-funnel-dollar::before {
+ content: "\f662"; }
+
+.fa-camera-retro::before {
+ content: "\f083"; }
+
+.fa-circle-arrow-down::before {
+ content: "\f0ab"; }
+
+.fa-arrow-circle-down::before {
+ content: "\f0ab"; }
+
+.fa-file-import::before {
+ content: "\f56f"; }
+
+.fa-arrow-right-to-file::before {
+ content: "\f56f"; }
+
+.fa-square-arrow-up-right::before {
+ content: "\f14c"; }
+
+.fa-external-link-square::before {
+ content: "\f14c"; }
+
+.fa-box-open::before {
+ content: "\f49e"; }
+
+.fa-scroll::before {
+ content: "\f70e"; }
+
+.fa-spa::before {
+ content: "\f5bb"; }
+
+.fa-location-pin-lock::before {
+ content: "\e51f"; }
+
+.fa-pause::before {
+ content: "\f04c"; }
+
+.fa-hill-avalanche::before {
+ content: "\e507"; }
+
+.fa-temperature-empty::before {
+ content: "\f2cb"; }
+
+.fa-temperature-0::before {
+ content: "\f2cb"; }
+
+.fa-thermometer-0::before {
+ content: "\f2cb"; }
+
+.fa-thermometer-empty::before {
+ content: "\f2cb"; }
+
+.fa-bomb::before {
+ content: "\f1e2"; }
+
+.fa-registered::before {
+ content: "\f25d"; }
+
+.fa-address-card::before {
+ content: "\f2bb"; }
+
+.fa-contact-card::before {
+ content: "\f2bb"; }
+
+.fa-vcard::before {
+ content: "\f2bb"; }
+
+.fa-scale-unbalanced-flip::before {
+ content: "\f516"; }
+
+.fa-balance-scale-right::before {
+ content: "\f516"; }
+
+.fa-subscript::before {
+ content: "\f12c"; }
+
+.fa-diamond-turn-right::before {
+ content: "\f5eb"; }
+
+.fa-directions::before {
+ content: "\f5eb"; }
+
+.fa-burst::before {
+ content: "\e4dc"; }
+
+.fa-house-laptop::before {
+ content: "\e066"; }
+
+.fa-laptop-house::before {
+ content: "\e066"; }
+
+.fa-face-tired::before {
+ content: "\f5c8"; }
+
+.fa-tired::before {
+ content: "\f5c8"; }
+
+.fa-money-bills::before {
+ content: "\e1f3"; }
+
+.fa-smog::before {
+ content: "\f75f"; }
+
+.fa-crutch::before {
+ content: "\f7f7"; }
+
+.fa-cloud-arrow-up::before {
+ content: "\f0ee"; }
+
+.fa-cloud-upload::before {
+ content: "\f0ee"; }
+
+.fa-cloud-upload-alt::before {
+ content: "\f0ee"; }
+
+.fa-palette::before {
+ content: "\f53f"; }
+
+.fa-arrows-turn-right::before {
+ content: "\e4c0"; }
+
+.fa-vest::before {
+ content: "\e085"; }
+
+.fa-ferry::before {
+ content: "\e4ea"; }
+
+.fa-arrows-down-to-people::before {
+ content: "\e4b9"; }
+
+.fa-seedling::before {
+ content: "\f4d8"; }
+
+.fa-sprout::before {
+ content: "\f4d8"; }
+
+.fa-left-right::before {
+ content: "\f337"; }
+
+.fa-arrows-alt-h::before {
+ content: "\f337"; }
+
+.fa-boxes-packing::before {
+ content: "\e4c7"; }
+
+.fa-circle-arrow-left::before {
+ content: "\f0a8"; }
+
+.fa-arrow-circle-left::before {
+ content: "\f0a8"; }
+
+.fa-group-arrows-rotate::before {
+ content: "\e4f6"; }
+
+.fa-bowl-food::before {
+ content: "\e4c6"; }
+
+.fa-candy-cane::before {
+ content: "\f786"; }
+
+.fa-arrow-down-wide-short::before {
+ content: "\f160"; }
+
+.fa-sort-amount-asc::before {
+ content: "\f160"; }
+
+.fa-sort-amount-down::before {
+ content: "\f160"; }
+
+.fa-cloud-bolt::before {
+ content: "\f76c"; }
+
+.fa-thunderstorm::before {
+ content: "\f76c"; }
+
+.fa-text-slash::before {
+ content: "\f87d"; }
+
+.fa-remove-format::before {
+ content: "\f87d"; }
+
+.fa-face-smile-wink::before {
+ content: "\f4da"; }
+
+.fa-smile-wink::before {
+ content: "\f4da"; }
+
+.fa-file-word::before {
+ content: "\f1c2"; }
+
+.fa-file-powerpoint::before {
+ content: "\f1c4"; }
+
+.fa-arrows-left-right::before {
+ content: "\f07e"; }
+
+.fa-arrows-h::before {
+ content: "\f07e"; }
+
+.fa-house-lock::before {
+ content: "\e510"; }
+
+.fa-cloud-arrow-down::before {
+ content: "\f0ed"; }
+
+.fa-cloud-download::before {
+ content: "\f0ed"; }
+
+.fa-cloud-download-alt::before {
+ content: "\f0ed"; }
+
+.fa-children::before {
+ content: "\e4e1"; }
+
+.fa-chalkboard::before {
+ content: "\f51b"; }
+
+.fa-blackboard::before {
+ content: "\f51b"; }
+
+.fa-user-large-slash::before {
+ content: "\f4fa"; }
+
+.fa-user-alt-slash::before {
+ content: "\f4fa"; }
+
+.fa-envelope-open::before {
+ content: "\f2b6"; }
+
+.fa-handshake-simple-slash::before {
+ content: "\e05f"; }
+
+.fa-handshake-alt-slash::before {
+ content: "\e05f"; }
+
+.fa-mattress-pillow::before {
+ content: "\e525"; }
+
+.fa-guarani-sign::before {
+ content: "\e19a"; }
+
+.fa-arrows-rotate::before {
+ content: "\f021"; }
+
+.fa-refresh::before {
+ content: "\f021"; }
+
+.fa-sync::before {
+ content: "\f021"; }
+
+.fa-fire-extinguisher::before {
+ content: "\f134"; }
+
+.fa-cruzeiro-sign::before {
+ content: "\e152"; }
+
+.fa-greater-than-equal::before {
+ content: "\f532"; }
+
+.fa-shield-halved::before {
+ content: "\f3ed"; }
+
+.fa-shield-alt::before {
+ content: "\f3ed"; }
+
+.fa-book-atlas::before {
+ content: "\f558"; }
+
+.fa-atlas::before {
+ content: "\f558"; }
+
+.fa-virus::before {
+ content: "\e074"; }
+
+.fa-envelope-circle-check::before {
+ content: "\e4e8"; }
+
+.fa-layer-group::before {
+ content: "\f5fd"; }
+
+.fa-arrows-to-dot::before {
+ content: "\e4be"; }
+
+.fa-archway::before {
+ content: "\f557"; }
+
+.fa-heart-circle-check::before {
+ content: "\e4fd"; }
+
+.fa-house-chimney-crack::before {
+ content: "\f6f1"; }
+
+.fa-house-damage::before {
+ content: "\f6f1"; }
+
+.fa-file-zipper::before {
+ content: "\f1c6"; }
+
+.fa-file-archive::before {
+ content: "\f1c6"; }
+
+.fa-square::before {
+ content: "\f0c8"; }
+
+.fa-martini-glass-empty::before {
+ content: "\f000"; }
+
+.fa-glass-martini::before {
+ content: "\f000"; }
+
+.fa-couch::before {
+ content: "\f4b8"; }
+
+.fa-cedi-sign::before {
+ content: "\e0df"; }
+
+.fa-italic::before {
+ content: "\f033"; }
+
+.fa-church::before {
+ content: "\f51d"; }
+
+.fa-comments-dollar::before {
+ content: "\f653"; }
+
+.fa-democrat::before {
+ content: "\f747"; }
+
+.fa-z::before {
+ content: "\5a"; }
+
+.fa-person-skiing::before {
+ content: "\f7c9"; }
+
+.fa-skiing::before {
+ content: "\f7c9"; }
+
+.fa-road-lock::before {
+ content: "\e567"; }
+
+.fa-a::before {
+ content: "\41"; }
+
+.fa-temperature-arrow-down::before {
+ content: "\e03f"; }
+
+.fa-temperature-down::before {
+ content: "\e03f"; }
+
+.fa-feather-pointed::before {
+ content: "\f56b"; }
+
+.fa-feather-alt::before {
+ content: "\f56b"; }
+
+.fa-p::before {
+ content: "\50"; }
+
+.fa-snowflake::before {
+ content: "\f2dc"; }
+
+.fa-newspaper::before {
+ content: "\f1ea"; }
+
+.fa-rectangle-ad::before {
+ content: "\f641"; }
+
+.fa-ad::before {
+ content: "\f641"; }
+
+.fa-circle-arrow-right::before {
+ content: "\f0a9"; }
+
+.fa-arrow-circle-right::before {
+ content: "\f0a9"; }
+
+.fa-filter-circle-xmark::before {
+ content: "\e17b"; }
+
+.fa-locust::before {
+ content: "\e520"; }
+
+.fa-sort::before {
+ content: "\f0dc"; }
+
+.fa-unsorted::before {
+ content: "\f0dc"; }
+
+.fa-list-ol::before {
+ content: "\f0cb"; }
+
+.fa-list-1-2::before {
+ content: "\f0cb"; }
+
+.fa-list-numeric::before {
+ content: "\f0cb"; }
+
+.fa-person-dress-burst::before {
+ content: "\e544"; }
+
+.fa-money-check-dollar::before {
+ content: "\f53d"; }
+
+.fa-money-check-alt::before {
+ content: "\f53d"; }
+
+.fa-vector-square::before {
+ content: "\f5cb"; }
+
+.fa-bread-slice::before {
+ content: "\f7ec"; }
+
+.fa-language::before {
+ content: "\f1ab"; }
+
+.fa-face-kiss-wink-heart::before {
+ content: "\f598"; }
+
+.fa-kiss-wink-heart::before {
+ content: "\f598"; }
+
+.fa-filter::before {
+ content: "\f0b0"; }
+
+.fa-question::before {
+ content: "\3f"; }
+
+.fa-file-signature::before {
+ content: "\f573"; }
+
+.fa-up-down-left-right::before {
+ content: "\f0b2"; }
+
+.fa-arrows-alt::before {
+ content: "\f0b2"; }
+
+.fa-house-chimney-user::before {
+ content: "\e065"; }
+
+.fa-hand-holding-heart::before {
+ content: "\f4be"; }
+
+.fa-puzzle-piece::before {
+ content: "\f12e"; }
+
+.fa-money-check::before {
+ content: "\f53c"; }
+
+.fa-star-half-stroke::before {
+ content: "\f5c0"; }
+
+.fa-star-half-alt::before {
+ content: "\f5c0"; }
+
+.fa-code::before {
+ content: "\f121"; }
+
+.fa-whiskey-glass::before {
+ content: "\f7a0"; }
+
+.fa-glass-whiskey::before {
+ content: "\f7a0"; }
+
+.fa-building-circle-exclamation::before {
+ content: "\e4d3"; }
+
+.fa-magnifying-glass-chart::before {
+ content: "\e522"; }
+
+.fa-arrow-up-right-from-square::before {
+ content: "\f08e"; }
+
+.fa-external-link::before {
+ content: "\f08e"; }
+
+.fa-cubes-stacked::before {
+ content: "\e4e6"; }
+
+.fa-won-sign::before {
+ content: "\f159"; }
+
+.fa-krw::before {
+ content: "\f159"; }
+
+.fa-won::before {
+ content: "\f159"; }
+
+.fa-virus-covid::before {
+ content: "\e4a8"; }
+
+.fa-austral-sign::before {
+ content: "\e0a9"; }
+
+.fa-f::before {
+ content: "\46"; }
+
+.fa-leaf::before {
+ content: "\f06c"; }
+
+.fa-road::before {
+ content: "\f018"; }
+
+.fa-taxi::before {
+ content: "\f1ba"; }
+
+.fa-cab::before {
+ content: "\f1ba"; }
+
+.fa-person-circle-plus::before {
+ content: "\e541"; }
+
+.fa-chart-pie::before {
+ content: "\f200"; }
+
+.fa-pie-chart::before {
+ content: "\f200"; }
+
+.fa-bolt-lightning::before {
+ content: "\e0b7"; }
+
+.fa-sack-xmark::before {
+ content: "\e56a"; }
+
+.fa-file-excel::before {
+ content: "\f1c3"; }
+
+.fa-file-contract::before {
+ content: "\f56c"; }
+
+.fa-fish-fins::before {
+ content: "\e4f2"; }
+
+.fa-building-flag::before {
+ content: "\e4d5"; }
+
+.fa-face-grin-beam::before {
+ content: "\f582"; }
+
+.fa-grin-beam::before {
+ content: "\f582"; }
+
+.fa-object-ungroup::before {
+ content: "\f248"; }
+
+.fa-poop::before {
+ content: "\f619"; }
+
+.fa-location-pin::before {
+ content: "\f041"; }
+
+.fa-map-marker::before {
+ content: "\f041"; }
+
+.fa-kaaba::before {
+ content: "\f66b"; }
+
+.fa-toilet-paper::before {
+ content: "\f71e"; }
+
+.fa-helmet-safety::before {
+ content: "\f807"; }
+
+.fa-hard-hat::before {
+ content: "\f807"; }
+
+.fa-hat-hard::before {
+ content: "\f807"; }
+
+.fa-eject::before {
+ content: "\f052"; }
+
+.fa-circle-right::before {
+ content: "\f35a"; }
+
+.fa-arrow-alt-circle-right::before {
+ content: "\f35a"; }
+
+.fa-plane-circle-check::before {
+ content: "\e555"; }
+
+.fa-face-rolling-eyes::before {
+ content: "\f5a5"; }
+
+.fa-meh-rolling-eyes::before {
+ content: "\f5a5"; }
+
+.fa-object-group::before {
+ content: "\f247"; }
+
+.fa-chart-line::before {
+ content: "\f201"; }
+
+.fa-line-chart::before {
+ content: "\f201"; }
+
+.fa-mask-ventilator::before {
+ content: "\e524"; }
+
+.fa-arrow-right::before {
+ content: "\f061"; }
+
+.fa-signs-post::before {
+ content: "\f277"; }
+
+.fa-map-signs::before {
+ content: "\f277"; }
+
+.fa-cash-register::before {
+ content: "\f788"; }
+
+.fa-person-circle-question::before {
+ content: "\e542"; }
+
+.fa-h::before {
+ content: "\48"; }
+
+.fa-tarp::before {
+ content: "\e57b"; }
+
+.fa-screwdriver-wrench::before {
+ content: "\f7d9"; }
+
+.fa-tools::before {
+ content: "\f7d9"; }
+
+.fa-arrows-to-eye::before {
+ content: "\e4bf"; }
+
+.fa-plug-circle-bolt::before {
+ content: "\e55b"; }
+
+.fa-heart::before {
+ content: "\f004"; }
+
+.fa-mars-and-venus::before {
+ content: "\f224"; }
+
+.fa-house-user::before {
+ content: "\e1b0"; }
+
+.fa-home-user::before {
+ content: "\e1b0"; }
+
+.fa-dumpster-fire::before {
+ content: "\f794"; }
+
+.fa-house-crack::before {
+ content: "\e3b1"; }
+
+.fa-martini-glass-citrus::before {
+ content: "\f561"; }
+
+.fa-cocktail::before {
+ content: "\f561"; }
+
+.fa-face-surprise::before {
+ content: "\f5c2"; }
+
+.fa-surprise::before {
+ content: "\f5c2"; }
+
+.fa-bottle-water::before {
+ content: "\e4c5"; }
+
+.fa-circle-pause::before {
+ content: "\f28b"; }
+
+.fa-pause-circle::before {
+ content: "\f28b"; }
+
+.fa-toilet-paper-slash::before {
+ content: "\e072"; }
+
+.fa-apple-whole::before {
+ content: "\f5d1"; }
+
+.fa-apple-alt::before {
+ content: "\f5d1"; }
+
+.fa-kitchen-set::before {
+ content: "\e51a"; }
+
+.fa-r::before {
+ content: "\52"; }
+
+.fa-temperature-quarter::before {
+ content: "\f2ca"; }
+
+.fa-temperature-1::before {
+ content: "\f2ca"; }
+
+.fa-thermometer-1::before {
+ content: "\f2ca"; }
+
+.fa-thermometer-quarter::before {
+ content: "\f2ca"; }
+
+.fa-cube::before {
+ content: "\f1b2"; }
+
+.fa-bitcoin-sign::before {
+ content: "\e0b4"; }
+
+.fa-shield-dog::before {
+ content: "\e573"; }
+
+.fa-solar-panel::before {
+ content: "\f5ba"; }
+
+.fa-lock-open::before {
+ content: "\f3c1"; }
+
+.fa-elevator::before {
+ content: "\e16d"; }
+
+.fa-money-bill-transfer::before {
+ content: "\e528"; }
+
+.fa-money-bill-trend-up::before {
+ content: "\e529"; }
+
+.fa-house-flood-water-circle-arrow-right::before {
+ content: "\e50f"; }
+
+.fa-square-poll-horizontal::before {
+ content: "\f682"; }
+
+.fa-poll-h::before {
+ content: "\f682"; }
+
+.fa-circle::before {
+ content: "\f111"; }
+
+.fa-backward-fast::before {
+ content: "\f049"; }
+
+.fa-fast-backward::before {
+ content: "\f049"; }
+
+.fa-recycle::before {
+ content: "\f1b8"; }
+
+.fa-user-astronaut::before {
+ content: "\f4fb"; }
+
+.fa-plane-slash::before {
+ content: "\e069"; }
+
+.fa-trademark::before {
+ content: "\f25c"; }
+
+.fa-basketball::before {
+ content: "\f434"; }
+
+.fa-basketball-ball::before {
+ content: "\f434"; }
+
+.fa-satellite-dish::before {
+ content: "\f7c0"; }
+
+.fa-circle-up::before {
+ content: "\f35b"; }
+
+.fa-arrow-alt-circle-up::before {
+ content: "\f35b"; }
+
+.fa-mobile-screen-button::before {
+ content: "\f3cd"; }
+
+.fa-mobile-alt::before {
+ content: "\f3cd"; }
+
+.fa-volume-high::before {
+ content: "\f028"; }
+
+.fa-volume-up::before {
+ content: "\f028"; }
+
+.fa-users-rays::before {
+ content: "\e593"; }
+
+.fa-wallet::before {
+ content: "\f555"; }
+
+.fa-clipboard-check::before {
+ content: "\f46c"; }
+
+.fa-file-audio::before {
+ content: "\f1c7"; }
+
+.fa-burger::before {
+ content: "\f805"; }
+
+.fa-hamburger::before {
+ content: "\f805"; }
+
+.fa-wrench::before {
+ content: "\f0ad"; }
+
+.fa-bugs::before {
+ content: "\e4d0"; }
+
+.fa-rupee-sign::before {
+ content: "\f156"; }
+
+.fa-rupee::before {
+ content: "\f156"; }
+
+.fa-file-image::before {
+ content: "\f1c5"; }
+
+.fa-circle-question::before {
+ content: "\f059"; }
+
+.fa-question-circle::before {
+ content: "\f059"; }
+
+.fa-plane-departure::before {
+ content: "\f5b0"; }
+
+.fa-handshake-slash::before {
+ content: "\e060"; }
+
+.fa-book-bookmark::before {
+ content: "\e0bb"; }
+
+.fa-code-branch::before {
+ content: "\f126"; }
+
+.fa-hat-cowboy::before {
+ content: "\f8c0"; }
+
+.fa-bridge::before {
+ content: "\e4c8"; }
+
+.fa-phone-flip::before {
+ content: "\f879"; }
+
+.fa-phone-alt::before {
+ content: "\f879"; }
+
+.fa-truck-front::before {
+ content: "\e2b7"; }
+
+.fa-cat::before {
+ content: "\f6be"; }
+
+.fa-anchor-circle-exclamation::before {
+ content: "\e4ab"; }
+
+.fa-truck-field::before {
+ content: "\e58d"; }
+
+.fa-route::before {
+ content: "\f4d7"; }
+
+.fa-clipboard-question::before {
+ content: "\e4e3"; }
+
+.fa-panorama::before {
+ content: "\e209"; }
+
+.fa-comment-medical::before {
+ content: "\f7f5"; }
+
+.fa-teeth-open::before {
+ content: "\f62f"; }
+
+.fa-file-circle-minus::before {
+ content: "\e4ed"; }
+
+.fa-tags::before {
+ content: "\f02c"; }
+
+.fa-wine-glass::before {
+ content: "\f4e3"; }
+
+.fa-forward-fast::before {
+ content: "\f050"; }
+
+.fa-fast-forward::before {
+ content: "\f050"; }
+
+.fa-face-meh-blank::before {
+ content: "\f5a4"; }
+
+.fa-meh-blank::before {
+ content: "\f5a4"; }
+
+.fa-square-parking::before {
+ content: "\f540"; }
+
+.fa-parking::before {
+ content: "\f540"; }
+
+.fa-house-signal::before {
+ content: "\e012"; }
+
+.fa-bars-progress::before {
+ content: "\f828"; }
+
+.fa-tasks-alt::before {
+ content: "\f828"; }
+
+.fa-faucet-drip::before {
+ content: "\e006"; }
+
+.fa-cart-flatbed::before {
+ content: "\f474"; }
+
+.fa-dolly-flatbed::before {
+ content: "\f474"; }
+
+.fa-ban-smoking::before {
+ content: "\f54d"; }
+
+.fa-smoking-ban::before {
+ content: "\f54d"; }
+
+.fa-terminal::before {
+ content: "\f120"; }
+
+.fa-mobile-button::before {
+ content: "\f10b"; }
+
+.fa-house-medical-flag::before {
+ content: "\e514"; }
+
+.fa-basket-shopping::before {
+ content: "\f291"; }
+
+.fa-shopping-basket::before {
+ content: "\f291"; }
+
+.fa-tape::before {
+ content: "\f4db"; }
+
+.fa-bus-simple::before {
+ content: "\f55e"; }
+
+.fa-bus-alt::before {
+ content: "\f55e"; }
+
+.fa-eye::before {
+ content: "\f06e"; }
+
+.fa-face-sad-cry::before {
+ content: "\f5b3"; }
+
+.fa-sad-cry::before {
+ content: "\f5b3"; }
+
+.fa-audio-description::before {
+ content: "\f29e"; }
+
+.fa-person-military-to-person::before {
+ content: "\e54c"; }
+
+.fa-file-shield::before {
+ content: "\e4f0"; }
+
+.fa-user-slash::before {
+ content: "\f506"; }
+
+.fa-pen::before {
+ content: "\f304"; }
+
+.fa-tower-observation::before {
+ content: "\e586"; }
+
+.fa-file-code::before {
+ content: "\f1c9"; }
+
+.fa-signal::before {
+ content: "\f012"; }
+
+.fa-signal-5::before {
+ content: "\f012"; }
+
+.fa-signal-perfect::before {
+ content: "\f012"; }
+
+.fa-bus::before {
+ content: "\f207"; }
+
+.fa-heart-circle-xmark::before {
+ content: "\e501"; }
+
+.fa-house-chimney::before {
+ content: "\e3af"; }
+
+.fa-home-lg::before {
+ content: "\e3af"; }
+
+.fa-window-maximize::before {
+ content: "\f2d0"; }
+
+.fa-face-frown::before {
+ content: "\f119"; }
+
+.fa-frown::before {
+ content: "\f119"; }
+
+.fa-prescription::before {
+ content: "\f5b1"; }
+
+.fa-shop::before {
+ content: "\f54f"; }
+
+.fa-store-alt::before {
+ content: "\f54f"; }
+
+.fa-floppy-disk::before {
+ content: "\f0c7"; }
+
+.fa-save::before {
+ content: "\f0c7"; }
+
+.fa-vihara::before {
+ content: "\f6a7"; }
+
+.fa-scale-unbalanced::before {
+ content: "\f515"; }
+
+.fa-balance-scale-left::before {
+ content: "\f515"; }
+
+.fa-sort-up::before {
+ content: "\f0de"; }
+
+.fa-sort-asc::before {
+ content: "\f0de"; }
+
+.fa-comment-dots::before {
+ content: "\f4ad"; }
+
+.fa-commenting::before {
+ content: "\f4ad"; }
+
+.fa-plant-wilt::before {
+ content: "\e5aa"; }
+
+.fa-diamond::before {
+ content: "\f219"; }
+
+.fa-face-grin-squint::before {
+ content: "\f585"; }
+
+.fa-grin-squint::before {
+ content: "\f585"; }
+
+.fa-hand-holding-dollar::before {
+ content: "\f4c0"; }
+
+.fa-hand-holding-usd::before {
+ content: "\f4c0"; }
+
+.fa-bacterium::before {
+ content: "\e05a"; }
+
+.fa-hand-pointer::before {
+ content: "\f25a"; }
+
+.fa-drum-steelpan::before {
+ content: "\f56a"; }
+
+.fa-hand-scissors::before {
+ content: "\f257"; }
+
+.fa-hands-praying::before {
+ content: "\f684"; }
+
+.fa-praying-hands::before {
+ content: "\f684"; }
+
+.fa-arrow-rotate-right::before {
+ content: "\f01e"; }
+
+.fa-arrow-right-rotate::before {
+ content: "\f01e"; }
+
+.fa-arrow-rotate-forward::before {
+ content: "\f01e"; }
+
+.fa-redo::before {
+ content: "\f01e"; }
+
+.fa-biohazard::before {
+ content: "\f780"; }
+
+.fa-location-crosshairs::before {
+ content: "\f601"; }
+
+.fa-location::before {
+ content: "\f601"; }
+
+.fa-mars-double::before {
+ content: "\f227"; }
+
+.fa-child-dress::before {
+ content: "\e59c"; }
+
+.fa-users-between-lines::before {
+ content: "\e591"; }
+
+.fa-lungs-virus::before {
+ content: "\e067"; }
+
+.fa-face-grin-tears::before {
+ content: "\f588"; }
+
+.fa-grin-tears::before {
+ content: "\f588"; }
+
+.fa-phone::before {
+ content: "\f095"; }
+
+.fa-calendar-xmark::before {
+ content: "\f273"; }
+
+.fa-calendar-times::before {
+ content: "\f273"; }
+
+.fa-child-reaching::before {
+ content: "\e59d"; }
+
+.fa-head-side-virus::before {
+ content: "\e064"; }
+
+.fa-user-gear::before {
+ content: "\f4fe"; }
+
+.fa-user-cog::before {
+ content: "\f4fe"; }
+
+.fa-arrow-up-1-9::before {
+ content: "\f163"; }
+
+.fa-sort-numeric-up::before {
+ content: "\f163"; }
+
+.fa-door-closed::before {
+ content: "\f52a"; }
+
+.fa-shield-virus::before {
+ content: "\e06c"; }
+
+.fa-dice-six::before {
+ content: "\f526"; }
+
+.fa-mosquito-net::before {
+ content: "\e52c"; }
+
+.fa-bridge-water::before {
+ content: "\e4ce"; }
+
+.fa-person-booth::before {
+ content: "\f756"; }
+
+.fa-text-width::before {
+ content: "\f035"; }
+
+.fa-hat-wizard::before {
+ content: "\f6e8"; }
+
+.fa-pen-fancy::before {
+ content: "\f5ac"; }
+
+.fa-person-digging::before {
+ content: "\f85e"; }
+
+.fa-digging::before {
+ content: "\f85e"; }
+
+.fa-trash::before {
+ content: "\f1f8"; }
+
+.fa-gauge-simple::before {
+ content: "\f629"; }
+
+.fa-gauge-simple-med::before {
+ content: "\f629"; }
+
+.fa-tachometer-average::before {
+ content: "\f629"; }
+
+.fa-book-medical::before {
+ content: "\f7e6"; }
+
+.fa-poo::before {
+ content: "\f2fe"; }
+
+.fa-quote-right::before {
+ content: "\f10e"; }
+
+.fa-quote-right-alt::before {
+ content: "\f10e"; }
+
+.fa-shirt::before {
+ content: "\f553"; }
+
+.fa-t-shirt::before {
+ content: "\f553"; }
+
+.fa-tshirt::before {
+ content: "\f553"; }
+
+.fa-cubes::before {
+ content: "\f1b3"; }
+
+.fa-divide::before {
+ content: "\f529"; }
+
+.fa-tenge-sign::before {
+ content: "\f7d7"; }
+
+.fa-tenge::before {
+ content: "\f7d7"; }
+
+.fa-headphones::before {
+ content: "\f025"; }
+
+.fa-hands-holding::before {
+ content: "\f4c2"; }
+
+.fa-hands-clapping::before {
+ content: "\e1a8"; }
+
+.fa-republican::before {
+ content: "\f75e"; }
+
+.fa-arrow-left::before {
+ content: "\f060"; }
+
+.fa-person-circle-xmark::before {
+ content: "\e543"; }
+
+.fa-ruler::before {
+ content: "\f545"; }
+
+.fa-align-left::before {
+ content: "\f036"; }
+
+.fa-dice-d6::before {
+ content: "\f6d1"; }
+
+.fa-restroom::before {
+ content: "\f7bd"; }
+
+.fa-j::before {
+ content: "\4a"; }
+
+.fa-users-viewfinder::before {
+ content: "\e595"; }
+
+.fa-file-video::before {
+ content: "\f1c8"; }
+
+.fa-up-right-from-square::before {
+ content: "\f35d"; }
+
+.fa-external-link-alt::before {
+ content: "\f35d"; }
+
+.fa-table-cells::before {
+ content: "\f00a"; }
+
+.fa-th::before {
+ content: "\f00a"; }
+
+.fa-file-pdf::before {
+ content: "\f1c1"; }
+
+.fa-book-bible::before {
+ content: "\f647"; }
+
+.fa-bible::before {
+ content: "\f647"; }
+
+.fa-o::before {
+ content: "\4f"; }
+
+.fa-suitcase-medical::before {
+ content: "\f0fa"; }
+
+.fa-medkit::before {
+ content: "\f0fa"; }
+
+.fa-user-secret::before {
+ content: "\f21b"; }
+
+.fa-otter::before {
+ content: "\f700"; }
+
+.fa-person-dress::before {
+ content: "\f182"; }
+
+.fa-female::before {
+ content: "\f182"; }
+
+.fa-comment-dollar::before {
+ content: "\f651"; }
+
+.fa-business-time::before {
+ content: "\f64a"; }
+
+.fa-briefcase-clock::before {
+ content: "\f64a"; }
+
+.fa-table-cells-large::before {
+ content: "\f009"; }
+
+.fa-th-large::before {
+ content: "\f009"; }
+
+.fa-book-tanakh::before {
+ content: "\f827"; }
+
+.fa-tanakh::before {
+ content: "\f827"; }
+
+.fa-phone-volume::before {
+ content: "\f2a0"; }
+
+.fa-volume-control-phone::before {
+ content: "\f2a0"; }
+
+.fa-hat-cowboy-side::before {
+ content: "\f8c1"; }
+
+.fa-clipboard-user::before {
+ content: "\f7f3"; }
+
+.fa-child::before {
+ content: "\f1ae"; }
+
+.fa-lira-sign::before {
+ content: "\f195"; }
+
+.fa-satellite::before {
+ content: "\f7bf"; }
+
+.fa-plane-lock::before {
+ content: "\e558"; }
+
+.fa-tag::before {
+ content: "\f02b"; }
+
+.fa-comment::before {
+ content: "\f075"; }
+
+.fa-cake-candles::before {
+ content: "\f1fd"; }
+
+.fa-birthday-cake::before {
+ content: "\f1fd"; }
+
+.fa-cake::before {
+ content: "\f1fd"; }
+
+.fa-envelope::before {
+ content: "\f0e0"; }
+
+.fa-angles-up::before {
+ content: "\f102"; }
+
+.fa-angle-double-up::before {
+ content: "\f102"; }
+
+.fa-paperclip::before {
+ content: "\f0c6"; }
+
+.fa-arrow-right-to-city::before {
+ content: "\e4b3"; }
+
+.fa-ribbon::before {
+ content: "\f4d6"; }
+
+.fa-lungs::before {
+ content: "\f604"; }
+
+.fa-arrow-up-9-1::before {
+ content: "\f887"; }
+
+.fa-sort-numeric-up-alt::before {
+ content: "\f887"; }
+
+.fa-litecoin-sign::before {
+ content: "\e1d3"; }
+
+.fa-border-none::before {
+ content: "\f850"; }
+
+.fa-circle-nodes::before {
+ content: "\e4e2"; }
+
+.fa-parachute-box::before {
+ content: "\f4cd"; }
+
+.fa-indent::before {
+ content: "\f03c"; }
+
+.fa-truck-field-un::before {
+ content: "\e58e"; }
+
+.fa-hourglass::before {
+ content: "\f254"; }
+
+.fa-hourglass-empty::before {
+ content: "\f254"; }
+
+.fa-mountain::before {
+ content: "\f6fc"; }
+
+.fa-user-doctor::before {
+ content: "\f0f0"; }
+
+.fa-user-md::before {
+ content: "\f0f0"; }
+
+.fa-circle-info::before {
+ content: "\f05a"; }
+
+.fa-info-circle::before {
+ content: "\f05a"; }
+
+.fa-cloud-meatball::before {
+ content: "\f73b"; }
+
+.fa-camera::before {
+ content: "\f030"; }
+
+.fa-camera-alt::before {
+ content: "\f030"; }
+
+.fa-square-virus::before {
+ content: "\e578"; }
+
+.fa-meteor::before {
+ content: "\f753"; }
+
+.fa-car-on::before {
+ content: "\e4dd"; }
+
+.fa-sleigh::before {
+ content: "\f7cc"; }
+
+.fa-arrow-down-1-9::before {
+ content: "\f162"; }
+
+.fa-sort-numeric-asc::before {
+ content: "\f162"; }
+
+.fa-sort-numeric-down::before {
+ content: "\f162"; }
+
+.fa-hand-holding-droplet::before {
+ content: "\f4c1"; }
+
+.fa-hand-holding-water::before {
+ content: "\f4c1"; }
+
+.fa-water::before {
+ content: "\f773"; }
+
+.fa-calendar-check::before {
+ content: "\f274"; }
+
+.fa-braille::before {
+ content: "\f2a1"; }
+
+.fa-prescription-bottle-medical::before {
+ content: "\f486"; }
+
+.fa-prescription-bottle-alt::before {
+ content: "\f486"; }
+
+.fa-landmark::before {
+ content: "\f66f"; }
+
+.fa-truck::before {
+ content: "\f0d1"; }
+
+.fa-crosshairs::before {
+ content: "\f05b"; }
+
+.fa-person-cane::before {
+ content: "\e53c"; }
+
+.fa-tent::before {
+ content: "\e57d"; }
+
+.fa-vest-patches::before {
+ content: "\e086"; }
+
+.fa-check-double::before {
+ content: "\f560"; }
+
+.fa-arrow-down-a-z::before {
+ content: "\f15d"; }
+
+.fa-sort-alpha-asc::before {
+ content: "\f15d"; }
+
+.fa-sort-alpha-down::before {
+ content: "\f15d"; }
+
+.fa-money-bill-wheat::before {
+ content: "\e52a"; }
+
+.fa-cookie::before {
+ content: "\f563"; }
+
+.fa-arrow-rotate-left::before {
+ content: "\f0e2"; }
+
+.fa-arrow-left-rotate::before {
+ content: "\f0e2"; }
+
+.fa-arrow-rotate-back::before {
+ content: "\f0e2"; }
+
+.fa-arrow-rotate-backward::before {
+ content: "\f0e2"; }
+
+.fa-undo::before {
+ content: "\f0e2"; }
+
+.fa-hard-drive::before {
+ content: "\f0a0"; }
+
+.fa-hdd::before {
+ content: "\f0a0"; }
+
+.fa-face-grin-squint-tears::before {
+ content: "\f586"; }
+
+.fa-grin-squint-tears::before {
+ content: "\f586"; }
+
+.fa-dumbbell::before {
+ content: "\f44b"; }
+
+.fa-rectangle-list::before {
+ content: "\f022"; }
+
+.fa-list-alt::before {
+ content: "\f022"; }
+
+.fa-tarp-droplet::before {
+ content: "\e57c"; }
+
+.fa-house-medical-circle-check::before {
+ content: "\e511"; }
+
+.fa-person-skiing-nordic::before {
+ content: "\f7ca"; }
+
+.fa-skiing-nordic::before {
+ content: "\f7ca"; }
+
+.fa-calendar-plus::before {
+ content: "\f271"; }
+
+.fa-plane-arrival::before {
+ content: "\f5af"; }
+
+.fa-circle-left::before {
+ content: "\f359"; }
+
+.fa-arrow-alt-circle-left::before {
+ content: "\f359"; }
+
+.fa-train-subway::before {
+ content: "\f239"; }
+
+.fa-subway::before {
+ content: "\f239"; }
+
+.fa-chart-gantt::before {
+ content: "\e0e4"; }
+
+.fa-indian-rupee-sign::before {
+ content: "\e1bc"; }
+
+.fa-indian-rupee::before {
+ content: "\e1bc"; }
+
+.fa-inr::before {
+ content: "\e1bc"; }
+
+.fa-crop-simple::before {
+ content: "\f565"; }
+
+.fa-crop-alt::before {
+ content: "\f565"; }
+
+.fa-money-bill-1::before {
+ content: "\f3d1"; }
+
+.fa-money-bill-alt::before {
+ content: "\f3d1"; }
+
+.fa-left-long::before {
+ content: "\f30a"; }
+
+.fa-long-arrow-alt-left::before {
+ content: "\f30a"; }
+
+.fa-dna::before {
+ content: "\f471"; }
+
+.fa-virus-slash::before {
+ content: "\e075"; }
+
+.fa-minus::before {
+ content: "\f068"; }
+
+.fa-subtract::before {
+ content: "\f068"; }
+
+.fa-chess::before {
+ content: "\f439"; }
+
+.fa-arrow-left-long::before {
+ content: "\f177"; }
+
+.fa-long-arrow-left::before {
+ content: "\f177"; }
+
+.fa-plug-circle-check::before {
+ content: "\e55c"; }
+
+.fa-street-view::before {
+ content: "\f21d"; }
+
+.fa-franc-sign::before {
+ content: "\e18f"; }
+
+.fa-volume-off::before {
+ content: "\f026"; }
+
+.fa-hands-asl-interpreting::before {
+ content: "\f2a3"; }
+
+.fa-american-sign-language-interpreting::before {
+ content: "\f2a3"; }
+
+.fa-asl-interpreting::before {
+ content: "\f2a3"; }
+
+.fa-hands-american-sign-language-interpreting::before {
+ content: "\f2a3"; }
+
+.fa-gear::before {
+ content: "\f013"; }
+
+.fa-cog::before {
+ content: "\f013"; }
+
+.fa-droplet-slash::before {
+ content: "\f5c7"; }
+
+.fa-tint-slash::before {
+ content: "\f5c7"; }
+
+.fa-mosque::before {
+ content: "\f678"; }
+
+.fa-mosquito::before {
+ content: "\e52b"; }
+
+.fa-star-of-david::before {
+ content: "\f69a"; }
+
+.fa-person-military-rifle::before {
+ content: "\e54b"; }
+
+.fa-cart-shopping::before {
+ content: "\f07a"; }
+
+.fa-shopping-cart::before {
+ content: "\f07a"; }
+
+.fa-vials::before {
+ content: "\f493"; }
+
+.fa-plug-circle-plus::before {
+ content: "\e55f"; }
+
+.fa-place-of-worship::before {
+ content: "\f67f"; }
+
+.fa-grip-vertical::before {
+ content: "\f58e"; }
+
+.fa-arrow-turn-up::before {
+ content: "\f148"; }
+
+.fa-level-up::before {
+ content: "\f148"; }
+
+.fa-u::before {
+ content: "\55"; }
+
+.fa-square-root-variable::before {
+ content: "\f698"; }
+
+.fa-square-root-alt::before {
+ content: "\f698"; }
+
+.fa-clock::before {
+ content: "\f017"; }
+
+.fa-clock-four::before {
+ content: "\f017"; }
+
+.fa-backward-step::before {
+ content: "\f048"; }
+
+.fa-step-backward::before {
+ content: "\f048"; }
+
+.fa-pallet::before {
+ content: "\f482"; }
+
+.fa-faucet::before {
+ content: "\e005"; }
+
+.fa-baseball-bat-ball::before {
+ content: "\f432"; }
+
+.fa-s::before {
+ content: "\53"; }
+
+.fa-timeline::before {
+ content: "\e29c"; }
+
+.fa-keyboard::before {
+ content: "\f11c"; }
+
+.fa-caret-down::before {
+ content: "\f0d7"; }
+
+.fa-house-chimney-medical::before {
+ content: "\f7f2"; }
+
+.fa-clinic-medical::before {
+ content: "\f7f2"; }
+
+.fa-temperature-three-quarters::before {
+ content: "\f2c8"; }
+
+.fa-temperature-3::before {
+ content: "\f2c8"; }
+
+.fa-thermometer-3::before {
+ content: "\f2c8"; }
+
+.fa-thermometer-three-quarters::before {
+ content: "\f2c8"; }
+
+.fa-mobile-screen::before {
+ content: "\f3cf"; }
+
+.fa-mobile-android-alt::before {
+ content: "\f3cf"; }
+
+.fa-plane-up::before {
+ content: "\e22d"; }
+
+.fa-piggy-bank::before {
+ content: "\f4d3"; }
+
+.fa-battery-half::before {
+ content: "\f242"; }
+
+.fa-battery-3::before {
+ content: "\f242"; }
+
+.fa-mountain-city::before {
+ content: "\e52e"; }
+
+.fa-coins::before {
+ content: "\f51e"; }
+
+.fa-khanda::before {
+ content: "\f66d"; }
+
+.fa-sliders::before {
+ content: "\f1de"; }
+
+.fa-sliders-h::before {
+ content: "\f1de"; }
+
+.fa-folder-tree::before {
+ content: "\f802"; }
+
+.fa-network-wired::before {
+ content: "\f6ff"; }
+
+.fa-map-pin::before {
+ content: "\f276"; }
+
+.fa-hamsa::before {
+ content: "\f665"; }
+
+.fa-cent-sign::before {
+ content: "\e3f5"; }
+
+.fa-flask::before {
+ content: "\f0c3"; }
+
+.fa-person-pregnant::before {
+ content: "\e31e"; }
+
+.fa-wand-sparkles::before {
+ content: "\f72b"; }
+
+.fa-ellipsis-vertical::before {
+ content: "\f142"; }
+
+.fa-ellipsis-v::before {
+ content: "\f142"; }
+
+.fa-ticket::before {
+ content: "\f145"; }
+
+.fa-power-off::before {
+ content: "\f011"; }
+
+.fa-right-long::before {
+ content: "\f30b"; }
+
+.fa-long-arrow-alt-right::before {
+ content: "\f30b"; }
+
+.fa-flag-usa::before {
+ content: "\f74d"; }
+
+.fa-laptop-file::before {
+ content: "\e51d"; }
+
+.fa-tty::before {
+ content: "\f1e4"; }
+
+.fa-teletype::before {
+ content: "\f1e4"; }
+
+.fa-diagram-next::before {
+ content: "\e476"; }
+
+.fa-person-rifle::before {
+ content: "\e54e"; }
+
+.fa-house-medical-circle-exclamation::before {
+ content: "\e512"; }
+
+.fa-closed-captioning::before {
+ content: "\f20a"; }
+
+.fa-person-hiking::before {
+ content: "\f6ec"; }
+
+.fa-hiking::before {
+ content: "\f6ec"; }
+
+.fa-venus-double::before {
+ content: "\f226"; }
+
+.fa-images::before {
+ content: "\f302"; }
+
+.fa-calculator::before {
+ content: "\f1ec"; }
+
+.fa-people-pulling::before {
+ content: "\e535"; }
+
+.fa-n::before {
+ content: "\4e"; }
+
+.fa-cable-car::before {
+ content: "\f7da"; }
+
+.fa-tram::before {
+ content: "\f7da"; }
+
+.fa-cloud-rain::before {
+ content: "\f73d"; }
+
+.fa-building-circle-xmark::before {
+ content: "\e4d4"; }
+
+.fa-ship::before {
+ content: "\f21a"; }
+
+.fa-arrows-down-to-line::before {
+ content: "\e4b8"; }
+
+.fa-download::before {
+ content: "\f019"; }
+
+.fa-face-grin::before {
+ content: "\f580"; }
+
+.fa-grin::before {
+ content: "\f580"; }
+
+.fa-delete-left::before {
+ content: "\f55a"; }
+
+.fa-backspace::before {
+ content: "\f55a"; }
+
+.fa-eye-dropper::before {
+ content: "\f1fb"; }
+
+.fa-eye-dropper-empty::before {
+ content: "\f1fb"; }
+
+.fa-eyedropper::before {
+ content: "\f1fb"; }
+
+.fa-file-circle-check::before {
+ content: "\e5a0"; }
+
+.fa-forward::before {
+ content: "\f04e"; }
+
+.fa-mobile::before {
+ content: "\f3ce"; }
+
+.fa-mobile-android::before {
+ content: "\f3ce"; }
+
+.fa-mobile-phone::before {
+ content: "\f3ce"; }
+
+.fa-face-meh::before {
+ content: "\f11a"; }
+
+.fa-meh::before {
+ content: "\f11a"; }
+
+.fa-align-center::before {
+ content: "\f037"; }
+
+.fa-book-skull::before {
+ content: "\f6b7"; }
+
+.fa-book-dead::before {
+ content: "\f6b7"; }
+
+.fa-id-card::before {
+ content: "\f2c2"; }
+
+.fa-drivers-license::before {
+ content: "\f2c2"; }
+
+.fa-outdent::before {
+ content: "\f03b"; }
+
+.fa-dedent::before {
+ content: "\f03b"; }
+
+.fa-heart-circle-exclamation::before {
+ content: "\e4fe"; }
+
+.fa-house::before {
+ content: "\f015"; }
+
+.fa-home::before {
+ content: "\f015"; }
+
+.fa-home-alt::before {
+ content: "\f015"; }
+
+.fa-home-lg-alt::before {
+ content: "\f015"; }
+
+.fa-calendar-week::before {
+ content: "\f784"; }
+
+.fa-laptop-medical::before {
+ content: "\f812"; }
+
+.fa-b::before {
+ content: "\42"; }
+
+.fa-file-medical::before {
+ content: "\f477"; }
+
+.fa-dice-one::before {
+ content: "\f525"; }
+
+.fa-kiwi-bird::before {
+ content: "\f535"; }
+
+.fa-arrow-right-arrow-left::before {
+ content: "\f0ec"; }
+
+.fa-exchange::before {
+ content: "\f0ec"; }
+
+.fa-rotate-right::before {
+ content: "\f2f9"; }
+
+.fa-redo-alt::before {
+ content: "\f2f9"; }
+
+.fa-rotate-forward::before {
+ content: "\f2f9"; }
+
+.fa-utensils::before {
+ content: "\f2e7"; }
+
+.fa-cutlery::before {
+ content: "\f2e7"; }
+
+.fa-arrow-up-wide-short::before {
+ content: "\f161"; }
+
+.fa-sort-amount-up::before {
+ content: "\f161"; }
+
+.fa-mill-sign::before {
+ content: "\e1ed"; }
+
+.fa-bowl-rice::before {
+ content: "\e2eb"; }
+
+.fa-skull::before {
+ content: "\f54c"; }
+
+.fa-tower-broadcast::before {
+ content: "\f519"; }
+
+.fa-broadcast-tower::before {
+ content: "\f519"; }
+
+.fa-truck-pickup::before {
+ content: "\f63c"; }
+
+.fa-up-long::before {
+ content: "\f30c"; }
+
+.fa-long-arrow-alt-up::before {
+ content: "\f30c"; }
+
+.fa-stop::before {
+ content: "\f04d"; }
+
+.fa-code-merge::before {
+ content: "\f387"; }
+
+.fa-upload::before {
+ content: "\f093"; }
+
+.fa-hurricane::before {
+ content: "\f751"; }
+
+.fa-mound::before {
+ content: "\e52d"; }
+
+.fa-toilet-portable::before {
+ content: "\e583"; }
+
+.fa-compact-disc::before {
+ content: "\f51f"; }
+
+.fa-file-arrow-down::before {
+ content: "\f56d"; }
+
+.fa-file-download::before {
+ content: "\f56d"; }
+
+.fa-caravan::before {
+ content: "\f8ff"; }
+
+.fa-shield-cat::before {
+ content: "\e572"; }
+
+.fa-bolt::before {
+ content: "\f0e7"; }
+
+.fa-zap::before {
+ content: "\f0e7"; }
+
+.fa-glass-water::before {
+ content: "\e4f4"; }
+
+.fa-oil-well::before {
+ content: "\e532"; }
+
+.fa-vault::before {
+ content: "\e2c5"; }
+
+.fa-mars::before {
+ content: "\f222"; }
+
+.fa-toilet::before {
+ content: "\f7d8"; }
+
+.fa-plane-circle-xmark::before {
+ content: "\e557"; }
+
+.fa-yen-sign::before {
+ content: "\f157"; }
+
+.fa-cny::before {
+ content: "\f157"; }
+
+.fa-jpy::before {
+ content: "\f157"; }
+
+.fa-rmb::before {
+ content: "\f157"; }
+
+.fa-yen::before {
+ content: "\f157"; }
+
+.fa-ruble-sign::before {
+ content: "\f158"; }
+
+.fa-rouble::before {
+ content: "\f158"; }
+
+.fa-rub::before {
+ content: "\f158"; }
+
+.fa-ruble::before {
+ content: "\f158"; }
+
+.fa-sun::before {
+ content: "\f185"; }
+
+.fa-guitar::before {
+ content: "\f7a6"; }
+
+.fa-face-laugh-wink::before {
+ content: "\f59c"; }
+
+.fa-laugh-wink::before {
+ content: "\f59c"; }
+
+.fa-horse-head::before {
+ content: "\f7ab"; }
+
+.fa-bore-hole::before {
+ content: "\e4c3"; }
+
+.fa-industry::before {
+ content: "\f275"; }
+
+.fa-circle-down::before {
+ content: "\f358"; }
+
+.fa-arrow-alt-circle-down::before {
+ content: "\f358"; }
+
+.fa-arrows-turn-to-dots::before {
+ content: "\e4c1"; }
+
+.fa-florin-sign::before {
+ content: "\e184"; }
+
+.fa-arrow-down-short-wide::before {
+ content: "\f884"; }
+
+.fa-sort-amount-desc::before {
+ content: "\f884"; }
+
+.fa-sort-amount-down-alt::before {
+ content: "\f884"; }
+
+.fa-less-than::before {
+ content: "\3c"; }
+
+.fa-angle-down::before {
+ content: "\f107"; }
+
+.fa-car-tunnel::before {
+ content: "\e4de"; }
+
+.fa-head-side-cough::before {
+ content: "\e061"; }
+
+.fa-grip-lines::before {
+ content: "\f7a4"; }
+
+.fa-thumbs-down::before {
+ content: "\f165"; }
+
+.fa-user-lock::before {
+ content: "\f502"; }
+
+.fa-arrow-right-long::before {
+ content: "\f178"; }
+
+.fa-long-arrow-right::before {
+ content: "\f178"; }
+
+.fa-anchor-circle-xmark::before {
+ content: "\e4ac"; }
+
+.fa-ellipsis::before {
+ content: "\f141"; }
+
+.fa-ellipsis-h::before {
+ content: "\f141"; }
+
+.fa-chess-pawn::before {
+ content: "\f443"; }
+
+.fa-kit-medical::before {
+ content: "\f479"; }
+
+.fa-first-aid::before {
+ content: "\f479"; }
+
+.fa-person-through-window::before {
+ content: "\e5a9"; }
+
+.fa-toolbox::before {
+ content: "\f552"; }
+
+.fa-hands-holding-circle::before {
+ content: "\e4fb"; }
+
+.fa-bug::before {
+ content: "\f188"; }
+
+.fa-credit-card::before {
+ content: "\f09d"; }
+
+.fa-credit-card-alt::before {
+ content: "\f09d"; }
+
+.fa-car::before {
+ content: "\f1b9"; }
+
+.fa-automobile::before {
+ content: "\f1b9"; }
+
+.fa-hand-holding-hand::before {
+ content: "\e4f7"; }
+
+.fa-book-open-reader::before {
+ content: "\f5da"; }
+
+.fa-book-reader::before {
+ content: "\f5da"; }
+
+.fa-mountain-sun::before {
+ content: "\e52f"; }
+
+.fa-arrows-left-right-to-line::before {
+ content: "\e4ba"; }
+
+.fa-dice-d20::before {
+ content: "\f6cf"; }
+
+.fa-truck-droplet::before {
+ content: "\e58c"; }
+
+.fa-file-circle-xmark::before {
+ content: "\e5a1"; }
+
+.fa-temperature-arrow-up::before {
+ content: "\e040"; }
+
+.fa-temperature-up::before {
+ content: "\e040"; }
+
+.fa-medal::before {
+ content: "\f5a2"; }
+
+.fa-bed::before {
+ content: "\f236"; }
+
+.fa-square-h::before {
+ content: "\f0fd"; }
+
+.fa-h-square::before {
+ content: "\f0fd"; }
+
+.fa-podcast::before {
+ content: "\f2ce"; }
+
+.fa-temperature-full::before {
+ content: "\f2c7"; }
+
+.fa-temperature-4::before {
+ content: "\f2c7"; }
+
+.fa-thermometer-4::before {
+ content: "\f2c7"; }
+
+.fa-thermometer-full::before {
+ content: "\f2c7"; }
+
+.fa-bell::before {
+ content: "\f0f3"; }
+
+.fa-superscript::before {
+ content: "\f12b"; }
+
+.fa-plug-circle-xmark::before {
+ content: "\e560"; }
+
+.fa-star-of-life::before {
+ content: "\f621"; }
+
+.fa-phone-slash::before {
+ content: "\f3dd"; }
+
+.fa-paint-roller::before {
+ content: "\f5aa"; }
+
+.fa-handshake-angle::before {
+ content: "\f4c4"; }
+
+.fa-hands-helping::before {
+ content: "\f4c4"; }
+
+.fa-location-dot::before {
+ content: "\f3c5"; }
+
+.fa-map-marker-alt::before {
+ content: "\f3c5"; }
+
+.fa-file::before {
+ content: "\f15b"; }
+
+.fa-greater-than::before {
+ content: "\3e"; }
+
+.fa-person-swimming::before {
+ content: "\f5c4"; }
+
+.fa-swimmer::before {
+ content: "\f5c4"; }
+
+.fa-arrow-down::before {
+ content: "\f063"; }
+
+.fa-droplet::before {
+ content: "\f043"; }
+
+.fa-tint::before {
+ content: "\f043"; }
+
+.fa-eraser::before {
+ content: "\f12d"; }
+
+.fa-earth-americas::before {
+ content: "\f57d"; }
+
+.fa-earth::before {
+ content: "\f57d"; }
+
+.fa-earth-america::before {
+ content: "\f57d"; }
+
+.fa-globe-americas::before {
+ content: "\f57d"; }
+
+.fa-person-burst::before {
+ content: "\e53b"; }
+
+.fa-dove::before {
+ content: "\f4ba"; }
+
+.fa-battery-empty::before {
+ content: "\f244"; }
+
+.fa-battery-0::before {
+ content: "\f244"; }
+
+.fa-socks::before {
+ content: "\f696"; }
+
+.fa-inbox::before {
+ content: "\f01c"; }
+
+.fa-section::before {
+ content: "\e447"; }
+
+.fa-gauge-high::before {
+ content: "\f625"; }
+
+.fa-tachometer-alt::before {
+ content: "\f625"; }
+
+.fa-tachometer-alt-fast::before {
+ content: "\f625"; }
+
+.fa-envelope-open-text::before {
+ content: "\f658"; }
+
+.fa-hospital::before {
+ content: "\f0f8"; }
+
+.fa-hospital-alt::before {
+ content: "\f0f8"; }
+
+.fa-hospital-wide::before {
+ content: "\f0f8"; }
+
+.fa-wine-bottle::before {
+ content: "\f72f"; }
+
+.fa-chess-rook::before {
+ content: "\f447"; }
+
+.fa-bars-staggered::before {
+ content: "\f550"; }
+
+.fa-reorder::before {
+ content: "\f550"; }
+
+.fa-stream::before {
+ content: "\f550"; }
+
+.fa-dharmachakra::before {
+ content: "\f655"; }
+
+.fa-hotdog::before {
+ content: "\f80f"; }
+
+.fa-person-walking-with-cane::before {
+ content: "\f29d"; }
+
+.fa-blind::before {
+ content: "\f29d"; }
+
+.fa-drum::before {
+ content: "\f569"; }
+
+.fa-ice-cream::before {
+ content: "\f810"; }
+
+.fa-heart-circle-bolt::before {
+ content: "\e4fc"; }
+
+.fa-fax::before {
+ content: "\f1ac"; }
+
+.fa-paragraph::before {
+ content: "\f1dd"; }
+
+.fa-check-to-slot::before {
+ content: "\f772"; }
+
+.fa-vote-yea::before {
+ content: "\f772"; }
+
+.fa-star-half::before {
+ content: "\f089"; }
+
+.fa-boxes-stacked::before {
+ content: "\f468"; }
+
+.fa-boxes::before {
+ content: "\f468"; }
+
+.fa-boxes-alt::before {
+ content: "\f468"; }
+
+.fa-link::before {
+ content: "\f0c1"; }
+
+.fa-chain::before {
+ content: "\f0c1"; }
+
+.fa-ear-listen::before {
+ content: "\f2a2"; }
+
+.fa-assistive-listening-systems::before {
+ content: "\f2a2"; }
+
+.fa-tree-city::before {
+ content: "\e587"; }
+
+.fa-play::before {
+ content: "\f04b"; }
+
+.fa-font::before {
+ content: "\f031"; }
+
+.fa-rupiah-sign::before {
+ content: "\e23d"; }
+
+.fa-magnifying-glass::before {
+ content: "\f002"; }
+
+.fa-search::before {
+ content: "\f002"; }
+
+.fa-table-tennis-paddle-ball::before {
+ content: "\f45d"; }
+
+.fa-ping-pong-paddle-ball::before {
+ content: "\f45d"; }
+
+.fa-table-tennis::before {
+ content: "\f45d"; }
+
+.fa-person-dots-from-line::before {
+ content: "\f470"; }
+
+.fa-diagnoses::before {
+ content: "\f470"; }
+
+.fa-trash-can-arrow-up::before {
+ content: "\f82a"; }
+
+.fa-trash-restore-alt::before {
+ content: "\f82a"; }
+
+.fa-naira-sign::before {
+ content: "\e1f6"; }
+
+.fa-cart-arrow-down::before {
+ content: "\f218"; }
+
+.fa-walkie-talkie::before {
+ content: "\f8ef"; }
+
+.fa-file-pen::before {
+ content: "\f31c"; }
+
+.fa-file-edit::before {
+ content: "\f31c"; }
+
+.fa-receipt::before {
+ content: "\f543"; }
+
+.fa-square-pen::before {
+ content: "\f14b"; }
+
+.fa-pen-square::before {
+ content: "\f14b"; }
+
+.fa-pencil-square::before {
+ content: "\f14b"; }
+
+.fa-suitcase-rolling::before {
+ content: "\f5c1"; }
+
+.fa-person-circle-exclamation::before {
+ content: "\e53f"; }
+
+.fa-chevron-down::before {
+ content: "\f078"; }
+
+.fa-battery-full::before {
+ content: "\f240"; }
+
+.fa-battery::before {
+ content: "\f240"; }
+
+.fa-battery-5::before {
+ content: "\f240"; }
+
+.fa-skull-crossbones::before {
+ content: "\f714"; }
+
+.fa-code-compare::before {
+ content: "\e13a"; }
+
+.fa-list-ul::before {
+ content: "\f0ca"; }
+
+.fa-list-dots::before {
+ content: "\f0ca"; }
+
+.fa-school-lock::before {
+ content: "\e56f"; }
+
+.fa-tower-cell::before {
+ content: "\e585"; }
+
+.fa-down-long::before {
+ content: "\f309"; }
+
+.fa-long-arrow-alt-down::before {
+ content: "\f309"; }
+
+.fa-ranking-star::before {
+ content: "\e561"; }
+
+.fa-chess-king::before {
+ content: "\f43f"; }
+
+.fa-person-harassing::before {
+ content: "\e549"; }
+
+.fa-brazilian-real-sign::before {
+ content: "\e46c"; }
+
+.fa-landmark-dome::before {
+ content: "\f752"; }
+
+.fa-landmark-alt::before {
+ content: "\f752"; }
+
+.fa-arrow-up::before {
+ content: "\f062"; }
+
+.fa-tv::before {
+ content: "\f26c"; }
+
+.fa-television::before {
+ content: "\f26c"; }
+
+.fa-tv-alt::before {
+ content: "\f26c"; }
+
+.fa-shrimp::before {
+ content: "\e448"; }
+
+.fa-list-check::before {
+ content: "\f0ae"; }
+
+.fa-tasks::before {
+ content: "\f0ae"; }
+
+.fa-jug-detergent::before {
+ content: "\e519"; }
+
+.fa-circle-user::before {
+ content: "\f2bd"; }
+
+.fa-user-circle::before {
+ content: "\f2bd"; }
+
+.fa-user-shield::before {
+ content: "\f505"; }
+
+.fa-wind::before {
+ content: "\f72e"; }
+
+.fa-car-burst::before {
+ content: "\f5e1"; }
+
+.fa-car-crash::before {
+ content: "\f5e1"; }
+
+.fa-y::before {
+ content: "\59"; }
+
+.fa-person-snowboarding::before {
+ content: "\f7ce"; }
+
+.fa-snowboarding::before {
+ content: "\f7ce"; }
+
+.fa-truck-fast::before {
+ content: "\f48b"; }
+
+.fa-shipping-fast::before {
+ content: "\f48b"; }
+
+.fa-fish::before {
+ content: "\f578"; }
+
+.fa-user-graduate::before {
+ content: "\f501"; }
+
+.fa-circle-half-stroke::before {
+ content: "\f042"; }
+
+.fa-adjust::before {
+ content: "\f042"; }
+
+.fa-clapperboard::before {
+ content: "\e131"; }
+
+.fa-circle-radiation::before {
+ content: "\f7ba"; }
+
+.fa-radiation-alt::before {
+ content: "\f7ba"; }
+
+.fa-baseball::before {
+ content: "\f433"; }
+
+.fa-baseball-ball::before {
+ content: "\f433"; }
+
+.fa-jet-fighter-up::before {
+ content: "\e518"; }
+
+.fa-diagram-project::before {
+ content: "\f542"; }
+
+.fa-project-diagram::before {
+ content: "\f542"; }
+
+.fa-copy::before {
+ content: "\f0c5"; }
+
+.fa-volume-xmark::before {
+ content: "\f6a9"; }
+
+.fa-volume-mute::before {
+ content: "\f6a9"; }
+
+.fa-volume-times::before {
+ content: "\f6a9"; }
+
+.fa-hand-sparkles::before {
+ content: "\e05d"; }
+
+.fa-grip::before {
+ content: "\f58d"; }
+
+.fa-grip-horizontal::before {
+ content: "\f58d"; }
+
+.fa-share-from-square::before {
+ content: "\f14d"; }
+
+.fa-share-square::before {
+ content: "\f14d"; }
+
+.fa-child-combatant::before {
+ content: "\e4e0"; }
+
+.fa-child-rifle::before {
+ content: "\e4e0"; }
+
+.fa-gun::before {
+ content: "\e19b"; }
+
+.fa-square-phone::before {
+ content: "\f098"; }
+
+.fa-phone-square::before {
+ content: "\f098"; }
+
+.fa-plus::before {
+ content: "\2b"; }
+
+.fa-add::before {
+ content: "\2b"; }
+
+.fa-expand::before {
+ content: "\f065"; }
+
+.fa-computer::before {
+ content: "\e4e5"; }
+
+.fa-xmark::before {
+ content: "\f00d"; }
+
+.fa-close::before {
+ content: "\f00d"; }
+
+.fa-multiply::before {
+ content: "\f00d"; }
+
+.fa-remove::before {
+ content: "\f00d"; }
+
+.fa-times::before {
+ content: "\f00d"; }
+
+.fa-arrows-up-down-left-right::before {
+ content: "\f047"; }
+
+.fa-arrows::before {
+ content: "\f047"; }
+
+.fa-chalkboard-user::before {
+ content: "\f51c"; }
+
+.fa-chalkboard-teacher::before {
+ content: "\f51c"; }
+
+.fa-peso-sign::before {
+ content: "\e222"; }
+
+.fa-building-shield::before {
+ content: "\e4d8"; }
+
+.fa-baby::before {
+ content: "\f77c"; }
+
+.fa-users-line::before {
+ content: "\e592"; }
+
+.fa-quote-left::before {
+ content: "\f10d"; }
+
+.fa-quote-left-alt::before {
+ content: "\f10d"; }
+
+.fa-tractor::before {
+ content: "\f722"; }
+
+.fa-trash-arrow-up::before {
+ content: "\f829"; }
+
+.fa-trash-restore::before {
+ content: "\f829"; }
+
+.fa-arrow-down-up-lock::before {
+ content: "\e4b0"; }
+
+.fa-lines-leaning::before {
+ content: "\e51e"; }
+
+.fa-ruler-combined::before {
+ content: "\f546"; }
+
+.fa-copyright::before {
+ content: "\f1f9"; }
+
+.fa-equals::before {
+ content: "\3d"; }
+
+.fa-blender::before {
+ content: "\f517"; }
+
+.fa-teeth::before {
+ content: "\f62e"; }
+
+.fa-shekel-sign::before {
+ content: "\f20b"; }
+
+.fa-ils::before {
+ content: "\f20b"; }
+
+.fa-shekel::before {
+ content: "\f20b"; }
+
+.fa-sheqel::before {
+ content: "\f20b"; }
+
+.fa-sheqel-sign::before {
+ content: "\f20b"; }
+
+.fa-map::before {
+ content: "\f279"; }
+
+.fa-rocket::before {
+ content: "\f135"; }
+
+.fa-photo-film::before {
+ content: "\f87c"; }
+
+.fa-photo-video::before {
+ content: "\f87c"; }
+
+.fa-folder-minus::before {
+ content: "\f65d"; }
+
+.fa-store::before {
+ content: "\f54e"; }
+
+.fa-arrow-trend-up::before {
+ content: "\e098"; }
+
+.fa-plug-circle-minus::before {
+ content: "\e55e"; }
+
+.fa-sign-hanging::before {
+ content: "\f4d9"; }
+
+.fa-sign::before {
+ content: "\f4d9"; }
+
+.fa-bezier-curve::before {
+ content: "\f55b"; }
+
+.fa-bell-slash::before {
+ content: "\f1f6"; }
+
+.fa-tablet::before {
+ content: "\f3fb"; }
+
+.fa-tablet-android::before {
+ content: "\f3fb"; }
+
+.fa-school-flag::before {
+ content: "\e56e"; }
+
+.fa-fill::before {
+ content: "\f575"; }
+
+.fa-angle-up::before {
+ content: "\f106"; }
+
+.fa-drumstick-bite::before {
+ content: "\f6d7"; }
+
+.fa-holly-berry::before {
+ content: "\f7aa"; }
+
+.fa-chevron-left::before {
+ content: "\f053"; }
+
+.fa-bacteria::before {
+ content: "\e059"; }
+
+.fa-hand-lizard::before {
+ content: "\f258"; }
+
+.fa-notdef::before {
+ content: "\e1fe"; }
+
+.fa-disease::before {
+ content: "\f7fa"; }
+
+.fa-briefcase-medical::before {
+ content: "\f469"; }
+
+.fa-genderless::before {
+ content: "\f22d"; }
+
+.fa-chevron-right::before {
+ content: "\f054"; }
+
+.fa-retweet::before {
+ content: "\f079"; }
+
+.fa-car-rear::before {
+ content: "\f5de"; }
+
+.fa-car-alt::before {
+ content: "\f5de"; }
+
+.fa-pump-soap::before {
+ content: "\e06b"; }
+
+.fa-video-slash::before {
+ content: "\f4e2"; }
+
+.fa-battery-quarter::before {
+ content: "\f243"; }
+
+.fa-battery-2::before {
+ content: "\f243"; }
+
+.fa-radio::before {
+ content: "\f8d7"; }
+
+.fa-baby-carriage::before {
+ content: "\f77d"; }
+
+.fa-carriage-baby::before {
+ content: "\f77d"; }
+
+.fa-traffic-light::before {
+ content: "\f637"; }
+
+.fa-thermometer::before {
+ content: "\f491"; }
+
+.fa-vr-cardboard::before {
+ content: "\f729"; }
+
+.fa-hand-middle-finger::before {
+ content: "\f806"; }
+
+.fa-percent::before {
+ content: "\25"; }
+
+.fa-percentage::before {
+ content: "\25"; }
+
+.fa-truck-moving::before {
+ content: "\f4df"; }
+
+.fa-glass-water-droplet::before {
+ content: "\e4f5"; }
+
+.fa-display::before {
+ content: "\e163"; }
+
+.fa-face-smile::before {
+ content: "\f118"; }
+
+.fa-smile::before {
+ content: "\f118"; }
+
+.fa-thumbtack::before {
+ content: "\f08d"; }
+
+.fa-thumb-tack::before {
+ content: "\f08d"; }
+
+.fa-trophy::before {
+ content: "\f091"; }
+
+.fa-person-praying::before {
+ content: "\f683"; }
+
+.fa-pray::before {
+ content: "\f683"; }
+
+.fa-hammer::before {
+ content: "\f6e3"; }
+
+.fa-hand-peace::before {
+ content: "\f25b"; }
+
+.fa-rotate::before {
+ content: "\f2f1"; }
+
+.fa-sync-alt::before {
+ content: "\f2f1"; }
+
+.fa-spinner::before {
+ content: "\f110"; }
+
+.fa-robot::before {
+ content: "\f544"; }
+
+.fa-peace::before {
+ content: "\f67c"; }
+
+.fa-gears::before {
+ content: "\f085"; }
+
+.fa-cogs::before {
+ content: "\f085"; }
+
+.fa-warehouse::before {
+ content: "\f494"; }
+
+.fa-arrow-up-right-dots::before {
+ content: "\e4b7"; }
+
+.fa-splotch::before {
+ content: "\f5bc"; }
+
+.fa-face-grin-hearts::before {
+ content: "\f584"; }
+
+.fa-grin-hearts::before {
+ content: "\f584"; }
+
+.fa-dice-four::before {
+ content: "\f524"; }
+
+.fa-sim-card::before {
+ content: "\f7c4"; }
+
+.fa-transgender::before {
+ content: "\f225"; }
+
+.fa-transgender-alt::before {
+ content: "\f225"; }
+
+.fa-mercury::before {
+ content: "\f223"; }
+
+.fa-arrow-turn-down::before {
+ content: "\f149"; }
+
+.fa-level-down::before {
+ content: "\f149"; }
+
+.fa-person-falling-burst::before {
+ content: "\e547"; }
+
+.fa-award::before {
+ content: "\f559"; }
+
+.fa-ticket-simple::before {
+ content: "\f3ff"; }
+
+.fa-ticket-alt::before {
+ content: "\f3ff"; }
+
+.fa-building::before {
+ content: "\f1ad"; }
+
+.fa-angles-left::before {
+ content: "\f100"; }
+
+.fa-angle-double-left::before {
+ content: "\f100"; }
+
+.fa-qrcode::before {
+ content: "\f029"; }
+
+.fa-clock-rotate-left::before {
+ content: "\f1da"; }
+
+.fa-history::before {
+ content: "\f1da"; }
+
+.fa-face-grin-beam-sweat::before {
+ content: "\f583"; }
+
+.fa-grin-beam-sweat::before {
+ content: "\f583"; }
+
+.fa-file-export::before {
+ content: "\f56e"; }
+
+.fa-arrow-right-from-file::before {
+ content: "\f56e"; }
+
+.fa-shield::before {
+ content: "\f132"; }
+
+.fa-shield-blank::before {
+ content: "\f132"; }
+
+.fa-arrow-up-short-wide::before {
+ content: "\f885"; }
+
+.fa-sort-amount-up-alt::before {
+ content: "\f885"; }
+
+.fa-house-medical::before {
+ content: "\e3b2"; }
+
+.fa-golf-ball-tee::before {
+ content: "\f450"; }
+
+.fa-golf-ball::before {
+ content: "\f450"; }
+
+.fa-circle-chevron-left::before {
+ content: "\f137"; }
+
+.fa-chevron-circle-left::before {
+ content: "\f137"; }
+
+.fa-house-chimney-window::before {
+ content: "\e00d"; }
+
+.fa-pen-nib::before {
+ content: "\f5ad"; }
+
+.fa-tent-arrow-turn-left::before {
+ content: "\e580"; }
+
+.fa-tents::before {
+ content: "\e582"; }
+
+.fa-wand-magic::before {
+ content: "\f0d0"; }
+
+.fa-magic::before {
+ content: "\f0d0"; }
+
+.fa-dog::before {
+ content: "\f6d3"; }
+
+.fa-carrot::before {
+ content: "\f787"; }
+
+.fa-moon::before {
+ content: "\f186"; }
+
+.fa-wine-glass-empty::before {
+ content: "\f5ce"; }
+
+.fa-wine-glass-alt::before {
+ content: "\f5ce"; }
+
+.fa-cheese::before {
+ content: "\f7ef"; }
+
+.fa-yin-yang::before {
+ content: "\f6ad"; }
+
+.fa-music::before {
+ content: "\f001"; }
+
+.fa-code-commit::before {
+ content: "\f386"; }
+
+.fa-temperature-low::before {
+ content: "\f76b"; }
+
+.fa-person-biking::before {
+ content: "\f84a"; }
+
+.fa-biking::before {
+ content: "\f84a"; }
+
+.fa-broom::before {
+ content: "\f51a"; }
+
+.fa-shield-heart::before {
+ content: "\e574"; }
+
+.fa-gopuram::before {
+ content: "\f664"; }
+
+.fa-earth-oceania::before {
+ content: "\e47b"; }
+
+.fa-globe-oceania::before {
+ content: "\e47b"; }
+
+.fa-square-xmark::before {
+ content: "\f2d3"; }
+
+.fa-times-square::before {
+ content: "\f2d3"; }
+
+.fa-xmark-square::before {
+ content: "\f2d3"; }
+
+.fa-hashtag::before {
+ content: "\23"; }
+
+.fa-up-right-and-down-left-from-center::before {
+ content: "\f424"; }
+
+.fa-expand-alt::before {
+ content: "\f424"; }
+
+.fa-oil-can::before {
+ content: "\f613"; }
+
+.fa-t::before {
+ content: "\54"; }
+
+.fa-hippo::before {
+ content: "\f6ed"; }
+
+.fa-chart-column::before {
+ content: "\e0e3"; }
+
+.fa-infinity::before {
+ content: "\f534"; }
+
+.fa-vial-circle-check::before {
+ content: "\e596"; }
+
+.fa-person-arrow-down-to-line::before {
+ content: "\e538"; }
+
+.fa-voicemail::before {
+ content: "\f897"; }
+
+.fa-fan::before {
+ content: "\f863"; }
+
+.fa-person-walking-luggage::before {
+ content: "\e554"; }
+
+.fa-up-down::before {
+ content: "\f338"; }
+
+.fa-arrows-alt-v::before {
+ content: "\f338"; }
+
+.fa-cloud-moon-rain::before {
+ content: "\f73c"; }
+
+.fa-calendar::before {
+ content: "\f133"; }
+
+.fa-trailer::before {
+ content: "\e041"; }
+
+.fa-bahai::before {
+ content: "\f666"; }
+
+.fa-haykal::before {
+ content: "\f666"; }
+
+.fa-sd-card::before {
+ content: "\f7c2"; }
+
+.fa-dragon::before {
+ content: "\f6d5"; }
+
+.fa-shoe-prints::before {
+ content: "\f54b"; }
+
+.fa-circle-plus::before {
+ content: "\f055"; }
+
+.fa-plus-circle::before {
+ content: "\f055"; }
+
+.fa-face-grin-tongue-wink::before {
+ content: "\f58b"; }
+
+.fa-grin-tongue-wink::before {
+ content: "\f58b"; }
+
+.fa-hand-holding::before {
+ content: "\f4bd"; }
+
+.fa-plug-circle-exclamation::before {
+ content: "\e55d"; }
+
+.fa-link-slash::before {
+ content: "\f127"; }
+
+.fa-chain-broken::before {
+ content: "\f127"; }
+
+.fa-chain-slash::before {
+ content: "\f127"; }
+
+.fa-unlink::before {
+ content: "\f127"; }
+
+.fa-clone::before {
+ content: "\f24d"; }
+
+.fa-person-walking-arrow-loop-left::before {
+ content: "\e551"; }
+
+.fa-arrow-up-z-a::before {
+ content: "\f882"; }
+
+.fa-sort-alpha-up-alt::before {
+ content: "\f882"; }
+
+.fa-fire-flame-curved::before {
+ content: "\f7e4"; }
+
+.fa-fire-alt::before {
+ content: "\f7e4"; }
+
+.fa-tornado::before {
+ content: "\f76f"; }
+
+.fa-file-circle-plus::before {
+ content: "\e494"; }
+
+.fa-book-quran::before {
+ content: "\f687"; }
+
+.fa-quran::before {
+ content: "\f687"; }
+
+.fa-anchor::before {
+ content: "\f13d"; }
+
+.fa-border-all::before {
+ content: "\f84c"; }
+
+.fa-face-angry::before {
+ content: "\f556"; }
+
+.fa-angry::before {
+ content: "\f556"; }
+
+.fa-cookie-bite::before {
+ content: "\f564"; }
+
+.fa-arrow-trend-down::before {
+ content: "\e097"; }
+
+.fa-rss::before {
+ content: "\f09e"; }
+
+.fa-feed::before {
+ content: "\f09e"; }
+
+.fa-draw-polygon::before {
+ content: "\f5ee"; }
+
+.fa-scale-balanced::before {
+ content: "\f24e"; }
+
+.fa-balance-scale::before {
+ content: "\f24e"; }
+
+.fa-gauge-simple-high::before {
+ content: "\f62a"; }
+
+.fa-tachometer::before {
+ content: "\f62a"; }
+
+.fa-tachometer-fast::before {
+ content: "\f62a"; }
+
+.fa-shower::before {
+ content: "\f2cc"; }
+
+.fa-desktop::before {
+ content: "\f390"; }
+
+.fa-desktop-alt::before {
+ content: "\f390"; }
+
+.fa-m::before {
+ content: "\4d"; }
+
+.fa-table-list::before {
+ content: "\f00b"; }
+
+.fa-th-list::before {
+ content: "\f00b"; }
+
+.fa-comment-sms::before {
+ content: "\f7cd"; }
+
+.fa-sms::before {
+ content: "\f7cd"; }
+
+.fa-book::before {
+ content: "\f02d"; }
+
+.fa-user-plus::before {
+ content: "\f234"; }
+
+.fa-check::before {
+ content: "\f00c"; }
+
+.fa-battery-three-quarters::before {
+ content: "\f241"; }
+
+.fa-battery-4::before {
+ content: "\f241"; }
+
+.fa-house-circle-check::before {
+ content: "\e509"; }
+
+.fa-angle-left::before {
+ content: "\f104"; }
+
+.fa-diagram-successor::before {
+ content: "\e47a"; }
+
+.fa-truck-arrow-right::before {
+ content: "\e58b"; }
+
+.fa-arrows-split-up-and-left::before {
+ content: "\e4bc"; }
+
+.fa-hand-fist::before {
+ content: "\f6de"; }
+
+.fa-fist-raised::before {
+ content: "\f6de"; }
+
+.fa-cloud-moon::before {
+ content: "\f6c3"; }
+
+.fa-briefcase::before {
+ content: "\f0b1"; }
+
+.fa-person-falling::before {
+ content: "\e546"; }
+
+.fa-image-portrait::before {
+ content: "\f3e0"; }
+
+.fa-portrait::before {
+ content: "\f3e0"; }
+
+.fa-user-tag::before {
+ content: "\f507"; }
+
+.fa-rug::before {
+ content: "\e569"; }
+
+.fa-earth-europe::before {
+ content: "\f7a2"; }
+
+.fa-globe-europe::before {
+ content: "\f7a2"; }
+
+.fa-cart-flatbed-suitcase::before {
+ content: "\f59d"; }
+
+.fa-luggage-cart::before {
+ content: "\f59d"; }
+
+.fa-rectangle-xmark::before {
+ content: "\f410"; }
+
+.fa-rectangle-times::before {
+ content: "\f410"; }
+
+.fa-times-rectangle::before {
+ content: "\f410"; }
+
+.fa-window-close::before {
+ content: "\f410"; }
+
+.fa-baht-sign::before {
+ content: "\e0ac"; }
+
+.fa-book-open::before {
+ content: "\f518"; }
+
+.fa-book-journal-whills::before {
+ content: "\f66a"; }
+
+.fa-journal-whills::before {
+ content: "\f66a"; }
+
+.fa-handcuffs::before {
+ content: "\e4f8"; }
+
+.fa-triangle-exclamation::before {
+ content: "\f071"; }
+
+.fa-exclamation-triangle::before {
+ content: "\f071"; }
+
+.fa-warning::before {
+ content: "\f071"; }
+
+.fa-database::before {
+ content: "\f1c0"; }
+
+.fa-share::before {
+ content: "\f064"; }
+
+.fa-arrow-turn-right::before {
+ content: "\f064"; }
+
+.fa-mail-forward::before {
+ content: "\f064"; }
+
+.fa-bottle-droplet::before {
+ content: "\e4c4"; }
+
+.fa-mask-face::before {
+ content: "\e1d7"; }
+
+.fa-hill-rockslide::before {
+ content: "\e508"; }
+
+.fa-right-left::before {
+ content: "\f362"; }
+
+.fa-exchange-alt::before {
+ content: "\f362"; }
+
+.fa-paper-plane::before {
+ content: "\f1d8"; }
+
+.fa-road-circle-exclamation::before {
+ content: "\e565"; }
+
+.fa-dungeon::before {
+ content: "\f6d9"; }
+
+.fa-align-right::before {
+ content: "\f038"; }
+
+.fa-money-bill-1-wave::before {
+ content: "\f53b"; }
+
+.fa-money-bill-wave-alt::before {
+ content: "\f53b"; }
+
+.fa-life-ring::before {
+ content: "\f1cd"; }
+
+.fa-hands::before {
+ content: "\f2a7"; }
+
+.fa-sign-language::before {
+ content: "\f2a7"; }
+
+.fa-signing::before {
+ content: "\f2a7"; }
+
+.fa-calendar-day::before {
+ content: "\f783"; }
+
+.fa-water-ladder::before {
+ content: "\f5c5"; }
+
+.fa-ladder-water::before {
+ content: "\f5c5"; }
+
+.fa-swimming-pool::before {
+ content: "\f5c5"; }
+
+.fa-arrows-up-down::before {
+ content: "\f07d"; }
+
+.fa-arrows-v::before {
+ content: "\f07d"; }
+
+.fa-face-grimace::before {
+ content: "\f57f"; }
+
+.fa-grimace::before {
+ content: "\f57f"; }
+
+.fa-wheelchair-move::before {
+ content: "\e2ce"; }
+
+.fa-wheelchair-alt::before {
+ content: "\e2ce"; }
+
+.fa-turn-down::before {
+ content: "\f3be"; }
+
+.fa-level-down-alt::before {
+ content: "\f3be"; }
+
+.fa-person-walking-arrow-right::before {
+ content: "\e552"; }
+
+.fa-square-envelope::before {
+ content: "\f199"; }
+
+.fa-envelope-square::before {
+ content: "\f199"; }
+
+.fa-dice::before {
+ content: "\f522"; }
+
+.fa-bowling-ball::before {
+ content: "\f436"; }
+
+.fa-brain::before {
+ content: "\f5dc"; }
+
+.fa-bandage::before {
+ content: "\f462"; }
+
+.fa-band-aid::before {
+ content: "\f462"; }
+
+.fa-calendar-minus::before {
+ content: "\f272"; }
+
+.fa-circle-xmark::before {
+ content: "\f057"; }
+
+.fa-times-circle::before {
+ content: "\f057"; }
+
+.fa-xmark-circle::before {
+ content: "\f057"; }
+
+.fa-gifts::before {
+ content: "\f79c"; }
+
+.fa-hotel::before {
+ content: "\f594"; }
+
+.fa-earth-asia::before {
+ content: "\f57e"; }
+
+.fa-globe-asia::before {
+ content: "\f57e"; }
+
+.fa-id-card-clip::before {
+ content: "\f47f"; }
+
+.fa-id-card-alt::before {
+ content: "\f47f"; }
+
+.fa-magnifying-glass-plus::before {
+ content: "\f00e"; }
+
+.fa-search-plus::before {
+ content: "\f00e"; }
+
+.fa-thumbs-up::before {
+ content: "\f164"; }
+
+.fa-user-clock::before {
+ content: "\f4fd"; }
+
+.fa-hand-dots::before {
+ content: "\f461"; }
+
+.fa-allergies::before {
+ content: "\f461"; }
+
+.fa-file-invoice::before {
+ content: "\f570"; }
+
+.fa-window-minimize::before {
+ content: "\f2d1"; }
+
+.fa-mug-saucer::before {
+ content: "\f0f4"; }
+
+.fa-coffee::before {
+ content: "\f0f4"; }
+
+.fa-brush::before {
+ content: "\f55d"; }
+
+.fa-mask::before {
+ content: "\f6fa"; }
+
+.fa-magnifying-glass-minus::before {
+ content: "\f010"; }
+
+.fa-search-minus::before {
+ content: "\f010"; }
+
+.fa-ruler-vertical::before {
+ content: "\f548"; }
+
+.fa-user-large::before {
+ content: "\f406"; }
+
+.fa-user-alt::before {
+ content: "\f406"; }
+
+.fa-train-tram::before {
+ content: "\e5b4"; }
+
+.fa-user-nurse::before {
+ content: "\f82f"; }
+
+.fa-syringe::before {
+ content: "\f48e"; }
+
+.fa-cloud-sun::before {
+ content: "\f6c4"; }
+
+.fa-stopwatch-20::before {
+ content: "\e06f"; }
+
+.fa-square-full::before {
+ content: "\f45c"; }
+
+.fa-magnet::before {
+ content: "\f076"; }
+
+.fa-jar::before {
+ content: "\e516"; }
+
+.fa-note-sticky::before {
+ content: "\f249"; }
+
+.fa-sticky-note::before {
+ content: "\f249"; }
+
+.fa-bug-slash::before {
+ content: "\e490"; }
+
+.fa-arrow-up-from-water-pump::before {
+ content: "\e4b6"; }
+
+.fa-bone::before {
+ content: "\f5d7"; }
+
+.fa-user-injured::before {
+ content: "\f728"; }
+
+.fa-face-sad-tear::before {
+ content: "\f5b4"; }
+
+.fa-sad-tear::before {
+ content: "\f5b4"; }
+
+.fa-plane::before {
+ content: "\f072"; }
+
+.fa-tent-arrows-down::before {
+ content: "\e581"; }
+
+.fa-exclamation::before {
+ content: "\21"; }
+
+.fa-arrows-spin::before {
+ content: "\e4bb"; }
+
+.fa-print::before {
+ content: "\f02f"; }
+
+.fa-turkish-lira-sign::before {
+ content: "\e2bb"; }
+
+.fa-try::before {
+ content: "\e2bb"; }
+
+.fa-turkish-lira::before {
+ content: "\e2bb"; }
+
+.fa-dollar-sign::before {
+ content: "\24"; }
+
+.fa-dollar::before {
+ content: "\24"; }
+
+.fa-usd::before {
+ content: "\24"; }
+
+.fa-x::before {
+ content: "\58"; }
+
+.fa-magnifying-glass-dollar::before {
+ content: "\f688"; }
+
+.fa-search-dollar::before {
+ content: "\f688"; }
+
+.fa-users-gear::before {
+ content: "\f509"; }
+
+.fa-users-cog::before {
+ content: "\f509"; }
+
+.fa-person-military-pointing::before {
+ content: "\e54a"; }
+
+.fa-building-columns::before {
+ content: "\f19c"; }
+
+.fa-bank::before {
+ content: "\f19c"; }
+
+.fa-institution::before {
+ content: "\f19c"; }
+
+.fa-museum::before {
+ content: "\f19c"; }
+
+.fa-university::before {
+ content: "\f19c"; }
+
+.fa-umbrella::before {
+ content: "\f0e9"; }
+
+.fa-trowel::before {
+ content: "\e589"; }
+
+.fa-d::before {
+ content: "\44"; }
+
+.fa-stapler::before {
+ content: "\e5af"; }
+
+.fa-masks-theater::before {
+ content: "\f630"; }
+
+.fa-theater-masks::before {
+ content: "\f630"; }
+
+.fa-kip-sign::before {
+ content: "\e1c4"; }
+
+.fa-hand-point-left::before {
+ content: "\f0a5"; }
+
+.fa-handshake-simple::before {
+ content: "\f4c6"; }
+
+.fa-handshake-alt::before {
+ content: "\f4c6"; }
+
+.fa-jet-fighter::before {
+ content: "\f0fb"; }
+
+.fa-fighter-jet::before {
+ content: "\f0fb"; }
+
+.fa-square-share-nodes::before {
+ content: "\f1e1"; }
+
+.fa-share-alt-square::before {
+ content: "\f1e1"; }
+
+.fa-barcode::before {
+ content: "\f02a"; }
+
+.fa-plus-minus::before {
+ content: "\e43c"; }
+
+.fa-video::before {
+ content: "\f03d"; }
+
+.fa-video-camera::before {
+ content: "\f03d"; }
+
+.fa-graduation-cap::before {
+ content: "\f19d"; }
+
+.fa-mortar-board::before {
+ content: "\f19d"; }
+
+.fa-hand-holding-medical::before {
+ content: "\e05c"; }
+
+.fa-person-circle-check::before {
+ content: "\e53e"; }
+
+.fa-turn-up::before {
+ content: "\f3bf"; }
+
+.fa-level-up-alt::before {
+ content: "\f3bf"; }
+
+.sr-only,
+.fa-sr-only {
+ position: absolute;
+ width: 1px;
+ height: 1px;
+ padding: 0;
+ margin: -1px;
+ overflow: hidden;
+ clip: rect(0, 0, 0, 0);
+ white-space: nowrap;
+ border-width: 0; }
+
+.sr-only-focusable:not(:focus),
+.fa-sr-only-focusable:not(:focus) {
+ position: absolute;
+ width: 1px;
+ height: 1px;
+ padding: 0;
+ margin: -1px;
+ overflow: hidden;
+ clip: rect(0, 0, 0, 0);
+ white-space: nowrap;
+ border-width: 0; }
diff --git a/40-abschlusspraesentation/assets/fontawesome/css/fontawesome.min.css b/40-abschlusspraesentation/assets/fontawesome/css/fontawesome.min.css
new file mode 100644
index 0000000..fe742a7
--- /dev/null
+++ b/40-abschlusspraesentation/assets/fontawesome/css/fontawesome.min.css
@@ -0,0 +1,9 @@
+/*!
+ * Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com
+ * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
+ * Copyright 2023 Fonticons, Inc.
+ */
+.fa{font-family:var(--fa-style-family,"Font Awesome 6 Free");font-weight:var(--fa-style,900)}.fa,.fa-brands,.fa-classic,.fa-regular,.fa-sharp,.fa-solid,.fab,.far,.fas{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;display:var(--fa-display,inline-block);font-style:normal;font-variant:normal;line-height:1;text-rendering:auto}.fa-classic,.fa-regular,.fa-solid,.far,.fas{font-family:"Font Awesome 6 Free"}.fa-brands,.fab{font-family:"Font Awesome 6 Brands"}.fa-1x{font-size:1em}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-6x{font-size:6em}.fa-7x{font-size:7em}.fa-8x{font-size:8em}.fa-9x{font-size:9em}.fa-10x{font-size:10em}.fa-2xs{font-size:.625em;line-height:.1em;vertical-align:.225em}.fa-xs{font-size:.75em;line-height:.08333em;vertical-align:.125em}.fa-sm{font-size:.875em;line-height:.07143em;vertical-align:.05357em}.fa-lg{font-size:1.25em;line-height:.05em;vertical-align:-.075em}.fa-xl{font-size:1.5em;line-height:.04167em;vertical-align:-.125em}.fa-2xl{font-size:2em;line-height:.03125em;vertical-align:-.1875em}.fa-fw{text-align:center;width:1.25em}.fa-ul{list-style-type:none;margin-left:var(--fa-li-margin,2.5em);padding-left:0}.fa-ul>li{position:relative}.fa-li{left:calc(var(--fa-li-width, 2em)*-1);position:absolute;text-align:center;width:var(--fa-li-width,2em);line-height:inherit}.fa-border{border-radius:var(--fa-border-radius,.1em);border:var(--fa-border-width,.08em) var(--fa-border-style,solid) var(--fa-border-color,#eee);padding:var(--fa-border-padding,.2em .25em .15em)}.fa-pull-left{float:left;margin-right:var(--fa-pull-margin,.3em)}.fa-pull-right{float:right;margin-left:var(--fa-pull-margin,.3em)}.fa-beat{-webkit-animation-name:fa-beat;animation-name:fa-beat;-webkit-animation-delay:var(--fa-animation-delay,0s);animation-delay:var(--fa-animation-delay,0s);-webkit-animation-direction:var(--fa-animation-direction,normal);animation-direction:var(--fa-animation-direction,normal);-webkit-animation-duration:var(--fa-animation-duration,1s);animation-duration:var(--fa-animation-duration,1s);-webkit-animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-iteration-count:var(--fa-animation-iteration-count,infinite);-webkit-animation-timing-function:var(--fa-animation-timing,ease-in-out);animation-timing-function:var(--fa-animation-timing,ease-in-out)}.fa-bounce{-webkit-animation-name:fa-bounce;animation-name:fa-bounce;-webkit-animation-delay:var(--fa-animation-delay,0s);animation-delay:var(--fa-animation-delay,0s);-webkit-animation-direction:var(--fa-animation-direction,normal);animation-direction:var(--fa-animation-direction,normal);-webkit-animation-duration:var(--fa-animation-duration,1s);animation-duration:var(--fa-animation-duration,1s);-webkit-animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-iteration-count:var(--fa-animation-iteration-count,infinite);-webkit-animation-timing-function:var(--fa-animation-timing,cubic-bezier(.28,.84,.42,1));animation-timing-function:var(--fa-animation-timing,cubic-bezier(.28,.84,.42,1))}.fa-fade{-webkit-animation-name:fa-fade;animation-name:fa-fade;-webkit-animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-iteration-count:var(--fa-animation-iteration-count,infinite);-webkit-animation-timing-function:var(--fa-animation-timing,cubic-bezier(.4,0,.6,1));animation-timing-function:var(--fa-animation-timing,cubic-bezier(.4,0,.6,1))}.fa-beat-fade,.fa-fade{-webkit-animation-delay:var(--fa-animation-delay,0s);animation-delay:var(--fa-animation-delay,0s);-webkit-animation-direction:var(--fa-animation-direction,normal);animation-direction:var(--fa-animation-direction,normal);-webkit-animation-duration:var(--fa-animation-duration,1s);animation-duration:var(--fa-animation-duration,1s)}.fa-beat-fade{-webkit-animation-name:fa-beat-fade;animation-name:fa-beat-fade;-webkit-animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-iteration-count:var(--fa-animation-iteration-count,infinite);-webkit-animation-timing-function:var(--fa-animation-timing,cubic-bezier(.4,0,.6,1));animation-timing-function:var(--fa-animation-timing,cubic-bezier(.4,0,.6,1))}.fa-flip{-webkit-animation-name:fa-flip;animation-name:fa-flip;-webkit-animation-delay:var(--fa-animation-delay,0s);animation-delay:var(--fa-animation-delay,0s);-webkit-animation-direction:var(--fa-animation-direction,normal);animation-direction:var(--fa-animation-direction,normal);-webkit-animation-duration:var(--fa-animation-duration,1s);animation-duration:var(--fa-animation-duration,1s);-webkit-animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-iteration-count:var(--fa-animation-iteration-count,infinite);-webkit-animation-timing-function:var(--fa-animation-timing,ease-in-out);animation-timing-function:var(--fa-animation-timing,ease-in-out)}.fa-shake{-webkit-animation-name:fa-shake;animation-name:fa-shake;-webkit-animation-duration:var(--fa-animation-duration,1s);animation-duration:var(--fa-animation-duration,1s);-webkit-animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-iteration-count:var(--fa-animation-iteration-count,infinite);-webkit-animation-timing-function:var(--fa-animation-timing,linear);animation-timing-function:var(--fa-animation-timing,linear)}.fa-shake,.fa-spin{-webkit-animation-delay:var(--fa-animation-delay,0s);animation-delay:var(--fa-animation-delay,0s);-webkit-animation-direction:var(--fa-animation-direction,normal);animation-direction:var(--fa-animation-direction,normal)}.fa-spin{-webkit-animation-name:fa-spin;animation-name:fa-spin;-webkit-animation-duration:var(--fa-animation-duration,2s);animation-duration:var(--fa-animation-duration,2s);-webkit-animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-iteration-count:var(--fa-animation-iteration-count,infinite);-webkit-animation-timing-function:var(--fa-animation-timing,linear);animation-timing-function:var(--fa-animation-timing,linear)}.fa-spin-reverse{--fa-animation-direction:reverse}.fa-pulse,.fa-spin-pulse{-webkit-animation-name:fa-spin;animation-name:fa-spin;-webkit-animation-direction:var(--fa-animation-direction,normal);animation-direction:var(--fa-animation-direction,normal);-webkit-animation-duration:var(--fa-animation-duration,1s);animation-duration:var(--fa-animation-duration,1s);-webkit-animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-iteration-count:var(--fa-animation-iteration-count,infinite);-webkit-animation-timing-function:var(--fa-animation-timing,steps(8));animation-timing-function:var(--fa-animation-timing,steps(8))}@media (prefers-reduced-motion:reduce){.fa-beat,.fa-beat-fade,.fa-bounce,.fa-fade,.fa-flip,.fa-pulse,.fa-shake,.fa-spin,.fa-spin-pulse{-webkit-animation-delay:-1ms;animation-delay:-1ms;-webkit-animation-duration:1ms;animation-duration:1ms;-webkit-animation-iteration-count:1;animation-iteration-count:1;-webkit-transition-delay:0s;transition-delay:0s;-webkit-transition-duration:0s;transition-duration:0s}}@-webkit-keyframes fa-beat{0%,90%{-webkit-transform:scale(1);transform:scale(1)}45%{-webkit-transform:scale(var(--fa-beat-scale,1.25));transform:scale(var(--fa-beat-scale,1.25))}}@keyframes fa-beat{0%,90%{-webkit-transform:scale(1);transform:scale(1)}45%{-webkit-transform:scale(var(--fa-beat-scale,1.25));transform:scale(var(--fa-beat-scale,1.25))}}@-webkit-keyframes fa-bounce{0%{-webkit-transform:scale(1) translateY(0);transform:scale(1) translateY(0)}10%{-webkit-transform:scale(var(--fa-bounce-start-scale-x,1.1),var(--fa-bounce-start-scale-y,.9)) translateY(0);transform:scale(var(--fa-bounce-start-scale-x,1.1),var(--fa-bounce-start-scale-y,.9)) translateY(0)}30%{-webkit-transform:scale(var(--fa-bounce-jump-scale-x,.9),var(--fa-bounce-jump-scale-y,1.1)) translateY(var(--fa-bounce-height,-.5em));transform:scale(var(--fa-bounce-jump-scale-x,.9),var(--fa-bounce-jump-scale-y,1.1)) translateY(var(--fa-bounce-height,-.5em))}50%{-webkit-transform:scale(var(--fa-bounce-land-scale-x,1.05),var(--fa-bounce-land-scale-y,.95)) translateY(0);transform:scale(var(--fa-bounce-land-scale-x,1.05),var(--fa-bounce-land-scale-y,.95)) translateY(0)}57%{-webkit-transform:scale(1) translateY(var(--fa-bounce-rebound,-.125em));transform:scale(1) translateY(var(--fa-bounce-rebound,-.125em))}64%{-webkit-transform:scale(1) translateY(0);transform:scale(1) translateY(0)}to{-webkit-transform:scale(1) translateY(0);transform:scale(1) translateY(0)}}@keyframes fa-bounce{0%{-webkit-transform:scale(1) translateY(0);transform:scale(1) translateY(0)}10%{-webkit-transform:scale(var(--fa-bounce-start-scale-x,1.1),var(--fa-bounce-start-scale-y,.9)) translateY(0);transform:scale(var(--fa-bounce-start-scale-x,1.1),var(--fa-bounce-start-scale-y,.9)) translateY(0)}30%{-webkit-transform:scale(var(--fa-bounce-jump-scale-x,.9),var(--fa-bounce-jump-scale-y,1.1)) translateY(var(--fa-bounce-height,-.5em));transform:scale(var(--fa-bounce-jump-scale-x,.9),var(--fa-bounce-jump-scale-y,1.1)) translateY(var(--fa-bounce-height,-.5em))}50%{-webkit-transform:scale(var(--fa-bounce-land-scale-x,1.05),var(--fa-bounce-land-scale-y,.95)) translateY(0);transform:scale(var(--fa-bounce-land-scale-x,1.05),var(--fa-bounce-land-scale-y,.95)) translateY(0)}57%{-webkit-transform:scale(1) translateY(var(--fa-bounce-rebound,-.125em));transform:scale(1) translateY(var(--fa-bounce-rebound,-.125em))}64%{-webkit-transform:scale(1) translateY(0);transform:scale(1) translateY(0)}to{-webkit-transform:scale(1) translateY(0);transform:scale(1) translateY(0)}}@-webkit-keyframes fa-fade{50%{opacity:var(--fa-fade-opacity,.4)}}@keyframes fa-fade{50%{opacity:var(--fa-fade-opacity,.4)}}@-webkit-keyframes fa-beat-fade{0%,to{opacity:var(--fa-beat-fade-opacity,.4);-webkit-transform:scale(1);transform:scale(1)}50%{opacity:1;-webkit-transform:scale(var(--fa-beat-fade-scale,1.125));transform:scale(var(--fa-beat-fade-scale,1.125))}}@keyframes fa-beat-fade{0%,to{opacity:var(--fa-beat-fade-opacity,.4);-webkit-transform:scale(1);transform:scale(1)}50%{opacity:1;-webkit-transform:scale(var(--fa-beat-fade-scale,1.125));transform:scale(var(--fa-beat-fade-scale,1.125))}}@-webkit-keyframes fa-flip{50%{-webkit-transform:rotate3d(var(--fa-flip-x,0),var(--fa-flip-y,1),var(--fa-flip-z,0),var(--fa-flip-angle,-180deg));transform:rotate3d(var(--fa-flip-x,0),var(--fa-flip-y,1),var(--fa-flip-z,0),var(--fa-flip-angle,-180deg))}}@keyframes fa-flip{50%{-webkit-transform:rotate3d(var(--fa-flip-x,0),var(--fa-flip-y,1),var(--fa-flip-z,0),var(--fa-flip-angle,-180deg));transform:rotate3d(var(--fa-flip-x,0),var(--fa-flip-y,1),var(--fa-flip-z,0),var(--fa-flip-angle,-180deg))}}@-webkit-keyframes fa-shake{0%{-webkit-transform:rotate(-15deg);transform:rotate(-15deg)}4%{-webkit-transform:rotate(15deg);transform:rotate(15deg)}8%,24%{-webkit-transform:rotate(-18deg);transform:rotate(-18deg)}12%,28%{-webkit-transform:rotate(18deg);transform:rotate(18deg)}16%{-webkit-transform:rotate(-22deg);transform:rotate(-22deg)}20%{-webkit-transform:rotate(22deg);transform:rotate(22deg)}32%{-webkit-transform:rotate(-12deg);transform:rotate(-12deg)}36%{-webkit-transform:rotate(12deg);transform:rotate(12deg)}40%,to{-webkit-transform:rotate(0deg);transform:rotate(0deg)}}@keyframes fa-shake{0%{-webkit-transform:rotate(-15deg);transform:rotate(-15deg)}4%{-webkit-transform:rotate(15deg);transform:rotate(15deg)}8%,24%{-webkit-transform:rotate(-18deg);transform:rotate(-18deg)}12%,28%{-webkit-transform:rotate(18deg);transform:rotate(18deg)}16%{-webkit-transform:rotate(-22deg);transform:rotate(-22deg)}20%{-webkit-transform:rotate(22deg);transform:rotate(22deg)}32%{-webkit-transform:rotate(-12deg);transform:rotate(-12deg)}36%{-webkit-transform:rotate(12deg);transform:rotate(12deg)}40%,to{-webkit-transform:rotate(0deg);transform:rotate(0deg)}}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}.fa-rotate-90{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-webkit-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-webkit-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-webkit-transform:scaleX(-1);transform:scaleX(-1)}.fa-flip-vertical{-webkit-transform:scaleY(-1);transform:scaleY(-1)}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical{-webkit-transform:scale(-1);transform:scale(-1)}.fa-rotate-by{-webkit-transform:rotate(var(--fa-rotate-angle,none));transform:rotate(var(--fa-rotate-angle,none))}.fa-stack{display:inline-block;height:2em;line-height:2em;position:relative;vertical-align:middle;width:2.5em}.fa-stack-1x,.fa-stack-2x{left:0;position:absolute;text-align:center;width:100%;z-index:var(--fa-stack-z-index,auto)}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:var(--fa-inverse,#fff)}
+
+.fa-0:before{content:"\30"}.fa-1:before{content:"\31"}.fa-2:before{content:"\32"}.fa-3:before{content:"\33"}.fa-4:before{content:"\34"}.fa-5:before{content:"\35"}.fa-6:before{content:"\36"}.fa-7:before{content:"\37"}.fa-8:before{content:"\38"}.fa-9:before{content:"\39"}.fa-fill-drip:before{content:"\f576"}.fa-arrows-to-circle:before{content:"\e4bd"}.fa-chevron-circle-right:before,.fa-circle-chevron-right:before{content:"\f138"}.fa-at:before{content:"\40"}.fa-trash-alt:before,.fa-trash-can:before{content:"\f2ed"}.fa-text-height:before{content:"\f034"}.fa-user-times:before,.fa-user-xmark:before{content:"\f235"}.fa-stethoscope:before{content:"\f0f1"}.fa-comment-alt:before,.fa-message:before{content:"\f27a"}.fa-info:before{content:"\f129"}.fa-compress-alt:before,.fa-down-left-and-up-right-to-center:before{content:"\f422"}.fa-explosion:before{content:"\e4e9"}.fa-file-alt:before,.fa-file-lines:before,.fa-file-text:before{content:"\f15c"}.fa-wave-square:before{content:"\f83e"}.fa-ring:before{content:"\f70b"}.fa-building-un:before{content:"\e4d9"}.fa-dice-three:before{content:"\f527"}.fa-calendar-alt:before,.fa-calendar-days:before{content:"\f073"}.fa-anchor-circle-check:before{content:"\e4aa"}.fa-building-circle-arrow-right:before{content:"\e4d1"}.fa-volleyball-ball:before,.fa-volleyball:before{content:"\f45f"}.fa-arrows-up-to-line:before{content:"\e4c2"}.fa-sort-desc:before,.fa-sort-down:before{content:"\f0dd"}.fa-circle-minus:before,.fa-minus-circle:before{content:"\f056"}.fa-door-open:before{content:"\f52b"}.fa-right-from-bracket:before,.fa-sign-out-alt:before{content:"\f2f5"}.fa-atom:before{content:"\f5d2"}.fa-soap:before{content:"\e06e"}.fa-heart-music-camera-bolt:before,.fa-icons:before{content:"\f86d"}.fa-microphone-alt-slash:before,.fa-microphone-lines-slash:before{content:"\f539"}.fa-bridge-circle-check:before{content:"\e4c9"}.fa-pump-medical:before{content:"\e06a"}.fa-fingerprint:before{content:"\f577"}.fa-hand-point-right:before{content:"\f0a4"}.fa-magnifying-glass-location:before,.fa-search-location:before{content:"\f689"}.fa-forward-step:before,.fa-step-forward:before{content:"\f051"}.fa-face-smile-beam:before,.fa-smile-beam:before{content:"\f5b8"}.fa-flag-checkered:before{content:"\f11e"}.fa-football-ball:before,.fa-football:before{content:"\f44e"}.fa-school-circle-exclamation:before{content:"\e56c"}.fa-crop:before{content:"\f125"}.fa-angle-double-down:before,.fa-angles-down:before{content:"\f103"}.fa-users-rectangle:before{content:"\e594"}.fa-people-roof:before{content:"\e537"}.fa-people-line:before{content:"\e534"}.fa-beer-mug-empty:before,.fa-beer:before{content:"\f0fc"}.fa-diagram-predecessor:before{content:"\e477"}.fa-arrow-up-long:before,.fa-long-arrow-up:before{content:"\f176"}.fa-burn:before,.fa-fire-flame-simple:before{content:"\f46a"}.fa-male:before,.fa-person:before{content:"\f183"}.fa-laptop:before{content:"\f109"}.fa-file-csv:before{content:"\f6dd"}.fa-menorah:before{content:"\f676"}.fa-truck-plane:before{content:"\e58f"}.fa-record-vinyl:before{content:"\f8d9"}.fa-face-grin-stars:before,.fa-grin-stars:before{content:"\f587"}.fa-bong:before{content:"\f55c"}.fa-pastafarianism:before,.fa-spaghetti-monster-flying:before{content:"\f67b"}.fa-arrow-down-up-across-line:before{content:"\e4af"}.fa-spoon:before,.fa-utensil-spoon:before{content:"\f2e5"}.fa-jar-wheat:before{content:"\e517"}.fa-envelopes-bulk:before,.fa-mail-bulk:before{content:"\f674"}.fa-file-circle-exclamation:before{content:"\e4eb"}.fa-circle-h:before,.fa-hospital-symbol:before{content:"\f47e"}.fa-pager:before{content:"\f815"}.fa-address-book:before,.fa-contact-book:before{content:"\f2b9"}.fa-strikethrough:before{content:"\f0cc"}.fa-k:before{content:"\4b"}.fa-landmark-flag:before{content:"\e51c"}.fa-pencil-alt:before,.fa-pencil:before{content:"\f303"}.fa-backward:before{content:"\f04a"}.fa-caret-right:before{content:"\f0da"}.fa-comments:before{content:"\f086"}.fa-file-clipboard:before,.fa-paste:before{content:"\f0ea"}.fa-code-pull-request:before{content:"\e13c"}.fa-clipboard-list:before{content:"\f46d"}.fa-truck-loading:before,.fa-truck-ramp-box:before{content:"\f4de"}.fa-user-check:before{content:"\f4fc"}.fa-vial-virus:before{content:"\e597"}.fa-sheet-plastic:before{content:"\e571"}.fa-blog:before{content:"\f781"}.fa-user-ninja:before{content:"\f504"}.fa-person-arrow-up-from-line:before{content:"\e539"}.fa-scroll-torah:before,.fa-torah:before{content:"\f6a0"}.fa-broom-ball:before,.fa-quidditch-broom-ball:before,.fa-quidditch:before{content:"\f458"}.fa-toggle-off:before{content:"\f204"}.fa-archive:before,.fa-box-archive:before{content:"\f187"}.fa-person-drowning:before{content:"\e545"}.fa-arrow-down-9-1:before,.fa-sort-numeric-desc:before,.fa-sort-numeric-down-alt:before{content:"\f886"}.fa-face-grin-tongue-squint:before,.fa-grin-tongue-squint:before{content:"\f58a"}.fa-spray-can:before{content:"\f5bd"}.fa-truck-monster:before{content:"\f63b"}.fa-w:before{content:"\57"}.fa-earth-africa:before,.fa-globe-africa:before{content:"\f57c"}.fa-rainbow:before{content:"\f75b"}.fa-circle-notch:before{content:"\f1ce"}.fa-tablet-alt:before,.fa-tablet-screen-button:before{content:"\f3fa"}.fa-paw:before{content:"\f1b0"}.fa-cloud:before{content:"\f0c2"}.fa-trowel-bricks:before{content:"\e58a"}.fa-face-flushed:before,.fa-flushed:before{content:"\f579"}.fa-hospital-user:before{content:"\f80d"}.fa-tent-arrow-left-right:before{content:"\e57f"}.fa-gavel:before,.fa-legal:before{content:"\f0e3"}.fa-binoculars:before{content:"\f1e5"}.fa-microphone-slash:before{content:"\f131"}.fa-box-tissue:before{content:"\e05b"}.fa-motorcycle:before{content:"\f21c"}.fa-bell-concierge:before,.fa-concierge-bell:before{content:"\f562"}.fa-pen-ruler:before,.fa-pencil-ruler:before{content:"\f5ae"}.fa-people-arrows-left-right:before,.fa-people-arrows:before{content:"\e068"}.fa-mars-and-venus-burst:before{content:"\e523"}.fa-caret-square-right:before,.fa-square-caret-right:before{content:"\f152"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-sun-plant-wilt:before{content:"\e57a"}.fa-toilets-portable:before{content:"\e584"}.fa-hockey-puck:before{content:"\f453"}.fa-table:before{content:"\f0ce"}.fa-magnifying-glass-arrow-right:before{content:"\e521"}.fa-digital-tachograph:before,.fa-tachograph-digital:before{content:"\f566"}.fa-users-slash:before{content:"\e073"}.fa-clover:before{content:"\e139"}.fa-mail-reply:before,.fa-reply:before{content:"\f3e5"}.fa-star-and-crescent:before{content:"\f699"}.fa-house-fire:before{content:"\e50c"}.fa-minus-square:before,.fa-square-minus:before{content:"\f146"}.fa-helicopter:before{content:"\f533"}.fa-compass:before{content:"\f14e"}.fa-caret-square-down:before,.fa-square-caret-down:before{content:"\f150"}.fa-file-circle-question:before{content:"\e4ef"}.fa-laptop-code:before{content:"\f5fc"}.fa-swatchbook:before{content:"\f5c3"}.fa-prescription-bottle:before{content:"\f485"}.fa-bars:before,.fa-navicon:before{content:"\f0c9"}.fa-people-group:before{content:"\e533"}.fa-hourglass-3:before,.fa-hourglass-end:before{content:"\f253"}.fa-heart-broken:before,.fa-heart-crack:before{content:"\f7a9"}.fa-external-link-square-alt:before,.fa-square-up-right:before{content:"\f360"}.fa-face-kiss-beam:before,.fa-kiss-beam:before{content:"\f597"}.fa-film:before{content:"\f008"}.fa-ruler-horizontal:before{content:"\f547"}.fa-people-robbery:before{content:"\e536"}.fa-lightbulb:before{content:"\f0eb"}.fa-caret-left:before{content:"\f0d9"}.fa-circle-exclamation:before,.fa-exclamation-circle:before{content:"\f06a"}.fa-school-circle-xmark:before{content:"\e56d"}.fa-arrow-right-from-bracket:before,.fa-sign-out:before{content:"\f08b"}.fa-chevron-circle-down:before,.fa-circle-chevron-down:before{content:"\f13a"}.fa-unlock-alt:before,.fa-unlock-keyhole:before{content:"\f13e"}.fa-cloud-showers-heavy:before{content:"\f740"}.fa-headphones-alt:before,.fa-headphones-simple:before{content:"\f58f"}.fa-sitemap:before{content:"\f0e8"}.fa-circle-dollar-to-slot:before,.fa-donate:before{content:"\f4b9"}.fa-memory:before{content:"\f538"}.fa-road-spikes:before{content:"\e568"}.fa-fire-burner:before{content:"\e4f1"}.fa-flag:before{content:"\f024"}.fa-hanukiah:before{content:"\f6e6"}.fa-feather:before{content:"\f52d"}.fa-volume-down:before,.fa-volume-low:before{content:"\f027"}.fa-comment-slash:before{content:"\f4b3"}.fa-cloud-sun-rain:before{content:"\f743"}.fa-compress:before{content:"\f066"}.fa-wheat-alt:before,.fa-wheat-awn:before{content:"\e2cd"}.fa-ankh:before{content:"\f644"}.fa-hands-holding-child:before{content:"\e4fa"}.fa-asterisk:before{content:"\2a"}.fa-check-square:before,.fa-square-check:before{content:"\f14a"}.fa-peseta-sign:before{content:"\e221"}.fa-header:before,.fa-heading:before{content:"\f1dc"}.fa-ghost:before{content:"\f6e2"}.fa-list-squares:before,.fa-list:before{content:"\f03a"}.fa-phone-square-alt:before,.fa-square-phone-flip:before{content:"\f87b"}.fa-cart-plus:before{content:"\f217"}.fa-gamepad:before{content:"\f11b"}.fa-circle-dot:before,.fa-dot-circle:before{content:"\f192"}.fa-dizzy:before,.fa-face-dizzy:before{content:"\f567"}.fa-egg:before{content:"\f7fb"}.fa-house-medical-circle-xmark:before{content:"\e513"}.fa-campground:before{content:"\f6bb"}.fa-folder-plus:before{content:"\f65e"}.fa-futbol-ball:before,.fa-futbol:before,.fa-soccer-ball:before{content:"\f1e3"}.fa-paint-brush:before,.fa-paintbrush:before{content:"\f1fc"}.fa-lock:before{content:"\f023"}.fa-gas-pump:before{content:"\f52f"}.fa-hot-tub-person:before,.fa-hot-tub:before{content:"\f593"}.fa-map-location:before,.fa-map-marked:before{content:"\f59f"}.fa-house-flood-water:before{content:"\e50e"}.fa-tree:before{content:"\f1bb"}.fa-bridge-lock:before{content:"\e4cc"}.fa-sack-dollar:before{content:"\f81d"}.fa-edit:before,.fa-pen-to-square:before{content:"\f044"}.fa-car-side:before{content:"\f5e4"}.fa-share-alt:before,.fa-share-nodes:before{content:"\f1e0"}.fa-heart-circle-minus:before{content:"\e4ff"}.fa-hourglass-2:before,.fa-hourglass-half:before{content:"\f252"}.fa-microscope:before{content:"\f610"}.fa-sink:before{content:"\e06d"}.fa-bag-shopping:before,.fa-shopping-bag:before{content:"\f290"}.fa-arrow-down-z-a:before,.fa-sort-alpha-desc:before,.fa-sort-alpha-down-alt:before{content:"\f881"}.fa-mitten:before{content:"\f7b5"}.fa-person-rays:before{content:"\e54d"}.fa-users:before{content:"\f0c0"}.fa-eye-slash:before{content:"\f070"}.fa-flask-vial:before{content:"\e4f3"}.fa-hand-paper:before,.fa-hand:before{content:"\f256"}.fa-om:before{content:"\f679"}.fa-worm:before{content:"\e599"}.fa-house-circle-xmark:before{content:"\e50b"}.fa-plug:before{content:"\f1e6"}.fa-chevron-up:before{content:"\f077"}.fa-hand-spock:before{content:"\f259"}.fa-stopwatch:before{content:"\f2f2"}.fa-face-kiss:before,.fa-kiss:before{content:"\f596"}.fa-bridge-circle-xmark:before{content:"\e4cb"}.fa-face-grin-tongue:before,.fa-grin-tongue:before{content:"\f589"}.fa-chess-bishop:before{content:"\f43a"}.fa-face-grin-wink:before,.fa-grin-wink:before{content:"\f58c"}.fa-deaf:before,.fa-deafness:before,.fa-ear-deaf:before,.fa-hard-of-hearing:before{content:"\f2a4"}.fa-road-circle-check:before{content:"\e564"}.fa-dice-five:before{content:"\f523"}.fa-rss-square:before,.fa-square-rss:before{content:"\f143"}.fa-land-mine-on:before{content:"\e51b"}.fa-i-cursor:before{content:"\f246"}.fa-stamp:before{content:"\f5bf"}.fa-stairs:before{content:"\e289"}.fa-i:before{content:"\49"}.fa-hryvnia-sign:before,.fa-hryvnia:before{content:"\f6f2"}.fa-pills:before{content:"\f484"}.fa-face-grin-wide:before,.fa-grin-alt:before{content:"\f581"}.fa-tooth:before{content:"\f5c9"}.fa-v:before{content:"\56"}.fa-bangladeshi-taka-sign:before{content:"\e2e6"}.fa-bicycle:before{content:"\f206"}.fa-rod-asclepius:before,.fa-rod-snake:before,.fa-staff-aesculapius:before,.fa-staff-snake:before{content:"\e579"}.fa-head-side-cough-slash:before{content:"\e062"}.fa-ambulance:before,.fa-truck-medical:before{content:"\f0f9"}.fa-wheat-awn-circle-exclamation:before{content:"\e598"}.fa-snowman:before{content:"\f7d0"}.fa-mortar-pestle:before{content:"\f5a7"}.fa-road-barrier:before{content:"\e562"}.fa-school:before{content:"\f549"}.fa-igloo:before{content:"\f7ae"}.fa-joint:before{content:"\f595"}.fa-angle-right:before{content:"\f105"}.fa-horse:before{content:"\f6f0"}.fa-q:before{content:"\51"}.fa-g:before{content:"\47"}.fa-notes-medical:before{content:"\f481"}.fa-temperature-2:before,.fa-temperature-half:before,.fa-thermometer-2:before,.fa-thermometer-half:before{content:"\f2c9"}.fa-dong-sign:before{content:"\e169"}.fa-capsules:before{content:"\f46b"}.fa-poo-bolt:before,.fa-poo-storm:before{content:"\f75a"}.fa-face-frown-open:before,.fa-frown-open:before{content:"\f57a"}.fa-hand-point-up:before{content:"\f0a6"}.fa-money-bill:before{content:"\f0d6"}.fa-bookmark:before{content:"\f02e"}.fa-align-justify:before{content:"\f039"}.fa-umbrella-beach:before{content:"\f5ca"}.fa-helmet-un:before{content:"\e503"}.fa-bullseye:before{content:"\f140"}.fa-bacon:before{content:"\f7e5"}.fa-hand-point-down:before{content:"\f0a7"}.fa-arrow-up-from-bracket:before{content:"\e09a"}.fa-folder-blank:before,.fa-folder:before{content:"\f07b"}.fa-file-medical-alt:before,.fa-file-waveform:before{content:"\f478"}.fa-radiation:before{content:"\f7b9"}.fa-chart-simple:before{content:"\e473"}.fa-mars-stroke:before{content:"\f229"}.fa-vial:before{content:"\f492"}.fa-dashboard:before,.fa-gauge-med:before,.fa-gauge:before,.fa-tachometer-alt-average:before{content:"\f624"}.fa-magic-wand-sparkles:before,.fa-wand-magic-sparkles:before{content:"\e2ca"}.fa-e:before{content:"\45"}.fa-pen-alt:before,.fa-pen-clip:before{content:"\f305"}.fa-bridge-circle-exclamation:before{content:"\e4ca"}.fa-user:before{content:"\f007"}.fa-school-circle-check:before{content:"\e56b"}.fa-dumpster:before{content:"\f793"}.fa-shuttle-van:before,.fa-van-shuttle:before{content:"\f5b6"}.fa-building-user:before{content:"\e4da"}.fa-caret-square-left:before,.fa-square-caret-left:before{content:"\f191"}.fa-highlighter:before{content:"\f591"}.fa-key:before{content:"\f084"}.fa-bullhorn:before{content:"\f0a1"}.fa-globe:before{content:"\f0ac"}.fa-synagogue:before{content:"\f69b"}.fa-person-half-dress:before{content:"\e548"}.fa-road-bridge:before{content:"\e563"}.fa-location-arrow:before{content:"\f124"}.fa-c:before{content:"\43"}.fa-tablet-button:before{content:"\f10a"}.fa-building-lock:before{content:"\e4d6"}.fa-pizza-slice:before{content:"\f818"}.fa-money-bill-wave:before{content:"\f53a"}.fa-area-chart:before,.fa-chart-area:before{content:"\f1fe"}.fa-house-flag:before{content:"\e50d"}.fa-person-circle-minus:before{content:"\e540"}.fa-ban:before,.fa-cancel:before{content:"\f05e"}.fa-camera-rotate:before{content:"\e0d8"}.fa-air-freshener:before,.fa-spray-can-sparkles:before{content:"\f5d0"}.fa-star:before{content:"\f005"}.fa-repeat:before{content:"\f363"}.fa-cross:before{content:"\f654"}.fa-box:before{content:"\f466"}.fa-venus-mars:before{content:"\f228"}.fa-arrow-pointer:before,.fa-mouse-pointer:before{content:"\f245"}.fa-expand-arrows-alt:before,.fa-maximize:before{content:"\f31e"}.fa-charging-station:before{content:"\f5e7"}.fa-shapes:before,.fa-triangle-circle-square:before{content:"\f61f"}.fa-random:before,.fa-shuffle:before{content:"\f074"}.fa-person-running:before,.fa-running:before{content:"\f70c"}.fa-mobile-retro:before{content:"\e527"}.fa-grip-lines-vertical:before{content:"\f7a5"}.fa-spider:before{content:"\f717"}.fa-hands-bound:before{content:"\e4f9"}.fa-file-invoice-dollar:before{content:"\f571"}.fa-plane-circle-exclamation:before{content:"\e556"}.fa-x-ray:before{content:"\f497"}.fa-spell-check:before{content:"\f891"}.fa-slash:before{content:"\f715"}.fa-computer-mouse:before,.fa-mouse:before{content:"\f8cc"}.fa-arrow-right-to-bracket:before,.fa-sign-in:before{content:"\f090"}.fa-shop-slash:before,.fa-store-alt-slash:before{content:"\e070"}.fa-server:before{content:"\f233"}.fa-virus-covid-slash:before{content:"\e4a9"}.fa-shop-lock:before{content:"\e4a5"}.fa-hourglass-1:before,.fa-hourglass-start:before{content:"\f251"}.fa-blender-phone:before{content:"\f6b6"}.fa-building-wheat:before{content:"\e4db"}.fa-person-breastfeeding:before{content:"\e53a"}.fa-right-to-bracket:before,.fa-sign-in-alt:before{content:"\f2f6"}.fa-venus:before{content:"\f221"}.fa-passport:before{content:"\f5ab"}.fa-heart-pulse:before,.fa-heartbeat:before{content:"\f21e"}.fa-people-carry-box:before,.fa-people-carry:before{content:"\f4ce"}.fa-temperature-high:before{content:"\f769"}.fa-microchip:before{content:"\f2db"}.fa-crown:before{content:"\f521"}.fa-weight-hanging:before{content:"\f5cd"}.fa-xmarks-lines:before{content:"\e59a"}.fa-file-prescription:before{content:"\f572"}.fa-weight-scale:before,.fa-weight:before{content:"\f496"}.fa-user-friends:before,.fa-user-group:before{content:"\f500"}.fa-arrow-up-a-z:before,.fa-sort-alpha-up:before{content:"\f15e"}.fa-chess-knight:before{content:"\f441"}.fa-face-laugh-squint:before,.fa-laugh-squint:before{content:"\f59b"}.fa-wheelchair:before{content:"\f193"}.fa-arrow-circle-up:before,.fa-circle-arrow-up:before{content:"\f0aa"}.fa-toggle-on:before{content:"\f205"}.fa-person-walking:before,.fa-walking:before{content:"\f554"}.fa-l:before{content:"\4c"}.fa-fire:before{content:"\f06d"}.fa-bed-pulse:before,.fa-procedures:before{content:"\f487"}.fa-shuttle-space:before,.fa-space-shuttle:before{content:"\f197"}.fa-face-laugh:before,.fa-laugh:before{content:"\f599"}.fa-folder-open:before{content:"\f07c"}.fa-heart-circle-plus:before{content:"\e500"}.fa-code-fork:before{content:"\e13b"}.fa-city:before{content:"\f64f"}.fa-microphone-alt:before,.fa-microphone-lines:before{content:"\f3c9"}.fa-pepper-hot:before{content:"\f816"}.fa-unlock:before{content:"\f09c"}.fa-colon-sign:before{content:"\e140"}.fa-headset:before{content:"\f590"}.fa-store-slash:before{content:"\e071"}.fa-road-circle-xmark:before{content:"\e566"}.fa-user-minus:before{content:"\f503"}.fa-mars-stroke-up:before,.fa-mars-stroke-v:before{content:"\f22a"}.fa-champagne-glasses:before,.fa-glass-cheers:before{content:"\f79f"}.fa-clipboard:before{content:"\f328"}.fa-house-circle-exclamation:before{content:"\e50a"}.fa-file-arrow-up:before,.fa-file-upload:before{content:"\f574"}.fa-wifi-3:before,.fa-wifi-strong:before,.fa-wifi:before{content:"\f1eb"}.fa-bath:before,.fa-bathtub:before{content:"\f2cd"}.fa-underline:before{content:"\f0cd"}.fa-user-edit:before,.fa-user-pen:before{content:"\f4ff"}.fa-signature:before{content:"\f5b7"}.fa-stroopwafel:before{content:"\f551"}.fa-bold:before{content:"\f032"}.fa-anchor-lock:before{content:"\e4ad"}.fa-building-ngo:before{content:"\e4d7"}.fa-manat-sign:before{content:"\e1d5"}.fa-not-equal:before{content:"\f53e"}.fa-border-style:before,.fa-border-top-left:before{content:"\f853"}.fa-map-location-dot:before,.fa-map-marked-alt:before{content:"\f5a0"}.fa-jedi:before{content:"\f669"}.fa-poll:before,.fa-square-poll-vertical:before{content:"\f681"}.fa-mug-hot:before{content:"\f7b6"}.fa-battery-car:before,.fa-car-battery:before{content:"\f5df"}.fa-gift:before{content:"\f06b"}.fa-dice-two:before{content:"\f528"}.fa-chess-queen:before{content:"\f445"}.fa-glasses:before{content:"\f530"}.fa-chess-board:before{content:"\f43c"}.fa-building-circle-check:before{content:"\e4d2"}.fa-person-chalkboard:before{content:"\e53d"}.fa-mars-stroke-h:before,.fa-mars-stroke-right:before{content:"\f22b"}.fa-hand-back-fist:before,.fa-hand-rock:before{content:"\f255"}.fa-caret-square-up:before,.fa-square-caret-up:before{content:"\f151"}.fa-cloud-showers-water:before{content:"\e4e4"}.fa-bar-chart:before,.fa-chart-bar:before{content:"\f080"}.fa-hands-bubbles:before,.fa-hands-wash:before{content:"\e05e"}.fa-less-than-equal:before{content:"\f537"}.fa-train:before{content:"\f238"}.fa-eye-low-vision:before,.fa-low-vision:before{content:"\f2a8"}.fa-crow:before{content:"\f520"}.fa-sailboat:before{content:"\e445"}.fa-window-restore:before{content:"\f2d2"}.fa-plus-square:before,.fa-square-plus:before{content:"\f0fe"}.fa-torii-gate:before{content:"\f6a1"}.fa-frog:before{content:"\f52e"}.fa-bucket:before{content:"\e4cf"}.fa-image:before{content:"\f03e"}.fa-microphone:before{content:"\f130"}.fa-cow:before{content:"\f6c8"}.fa-caret-up:before{content:"\f0d8"}.fa-screwdriver:before{content:"\f54a"}.fa-folder-closed:before{content:"\e185"}.fa-house-tsunami:before{content:"\e515"}.fa-square-nfi:before{content:"\e576"}.fa-arrow-up-from-ground-water:before{content:"\e4b5"}.fa-glass-martini-alt:before,.fa-martini-glass:before{content:"\f57b"}.fa-rotate-back:before,.fa-rotate-backward:before,.fa-rotate-left:before,.fa-undo-alt:before{content:"\f2ea"}.fa-columns:before,.fa-table-columns:before{content:"\f0db"}.fa-lemon:before{content:"\f094"}.fa-head-side-mask:before{content:"\e063"}.fa-handshake:before{content:"\f2b5"}.fa-gem:before{content:"\f3a5"}.fa-dolly-box:before,.fa-dolly:before{content:"\f472"}.fa-smoking:before{content:"\f48d"}.fa-compress-arrows-alt:before,.fa-minimize:before{content:"\f78c"}.fa-monument:before{content:"\f5a6"}.fa-snowplow:before{content:"\f7d2"}.fa-angle-double-right:before,.fa-angles-right:before{content:"\f101"}.fa-cannabis:before{content:"\f55f"}.fa-circle-play:before,.fa-play-circle:before{content:"\f144"}.fa-tablets:before{content:"\f490"}.fa-ethernet:before{content:"\f796"}.fa-eur:before,.fa-euro-sign:before,.fa-euro:before{content:"\f153"}.fa-chair:before{content:"\f6c0"}.fa-check-circle:before,.fa-circle-check:before{content:"\f058"}.fa-circle-stop:before,.fa-stop-circle:before{content:"\f28d"}.fa-compass-drafting:before,.fa-drafting-compass:before{content:"\f568"}.fa-plate-wheat:before{content:"\e55a"}.fa-icicles:before{content:"\f7ad"}.fa-person-shelter:before{content:"\e54f"}.fa-neuter:before{content:"\f22c"}.fa-id-badge:before{content:"\f2c1"}.fa-marker:before{content:"\f5a1"}.fa-face-laugh-beam:before,.fa-laugh-beam:before{content:"\f59a"}.fa-helicopter-symbol:before{content:"\e502"}.fa-universal-access:before{content:"\f29a"}.fa-chevron-circle-up:before,.fa-circle-chevron-up:before{content:"\f139"}.fa-lari-sign:before{content:"\e1c8"}.fa-volcano:before{content:"\f770"}.fa-person-walking-dashed-line-arrow-right:before{content:"\e553"}.fa-gbp:before,.fa-pound-sign:before,.fa-sterling-sign:before{content:"\f154"}.fa-viruses:before{content:"\e076"}.fa-square-person-confined:before{content:"\e577"}.fa-user-tie:before{content:"\f508"}.fa-arrow-down-long:before,.fa-long-arrow-down:before{content:"\f175"}.fa-tent-arrow-down-to-line:before{content:"\e57e"}.fa-certificate:before{content:"\f0a3"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-suitcase:before{content:"\f0f2"}.fa-person-skating:before,.fa-skating:before{content:"\f7c5"}.fa-filter-circle-dollar:before,.fa-funnel-dollar:before{content:"\f662"}.fa-camera-retro:before{content:"\f083"}.fa-arrow-circle-down:before,.fa-circle-arrow-down:before{content:"\f0ab"}.fa-arrow-right-to-file:before,.fa-file-import:before{content:"\f56f"}.fa-external-link-square:before,.fa-square-arrow-up-right:before{content:"\f14c"}.fa-box-open:before{content:"\f49e"}.fa-scroll:before{content:"\f70e"}.fa-spa:before{content:"\f5bb"}.fa-location-pin-lock:before{content:"\e51f"}.fa-pause:before{content:"\f04c"}.fa-hill-avalanche:before{content:"\e507"}.fa-temperature-0:before,.fa-temperature-empty:before,.fa-thermometer-0:before,.fa-thermometer-empty:before{content:"\f2cb"}.fa-bomb:before{content:"\f1e2"}.fa-registered:before{content:"\f25d"}.fa-address-card:before,.fa-contact-card:before,.fa-vcard:before{content:"\f2bb"}.fa-balance-scale-right:before,.fa-scale-unbalanced-flip:before{content:"\f516"}.fa-subscript:before{content:"\f12c"}.fa-diamond-turn-right:before,.fa-directions:before{content:"\f5eb"}.fa-burst:before{content:"\e4dc"}.fa-house-laptop:before,.fa-laptop-house:before{content:"\e066"}.fa-face-tired:before,.fa-tired:before{content:"\f5c8"}.fa-money-bills:before{content:"\e1f3"}.fa-smog:before{content:"\f75f"}.fa-crutch:before{content:"\f7f7"}.fa-cloud-arrow-up:before,.fa-cloud-upload-alt:before,.fa-cloud-upload:before{content:"\f0ee"}.fa-palette:before{content:"\f53f"}.fa-arrows-turn-right:before{content:"\e4c0"}.fa-vest:before{content:"\e085"}.fa-ferry:before{content:"\e4ea"}.fa-arrows-down-to-people:before{content:"\e4b9"}.fa-seedling:before,.fa-sprout:before{content:"\f4d8"}.fa-arrows-alt-h:before,.fa-left-right:before{content:"\f337"}.fa-boxes-packing:before{content:"\e4c7"}.fa-arrow-circle-left:before,.fa-circle-arrow-left:before{content:"\f0a8"}.fa-group-arrows-rotate:before{content:"\e4f6"}.fa-bowl-food:before{content:"\e4c6"}.fa-candy-cane:before{content:"\f786"}.fa-arrow-down-wide-short:before,.fa-sort-amount-asc:before,.fa-sort-amount-down:before{content:"\f160"}.fa-cloud-bolt:before,.fa-thunderstorm:before{content:"\f76c"}.fa-remove-format:before,.fa-text-slash:before{content:"\f87d"}.fa-face-smile-wink:before,.fa-smile-wink:before{content:"\f4da"}.fa-file-word:before{content:"\f1c2"}.fa-file-powerpoint:before{content:"\f1c4"}.fa-arrows-h:before,.fa-arrows-left-right:before{content:"\f07e"}.fa-house-lock:before{content:"\e510"}.fa-cloud-arrow-down:before,.fa-cloud-download-alt:before,.fa-cloud-download:before{content:"\f0ed"}.fa-children:before{content:"\e4e1"}.fa-blackboard:before,.fa-chalkboard:before{content:"\f51b"}.fa-user-alt-slash:before,.fa-user-large-slash:before{content:"\f4fa"}.fa-envelope-open:before{content:"\f2b6"}.fa-handshake-alt-slash:before,.fa-handshake-simple-slash:before{content:"\e05f"}.fa-mattress-pillow:before{content:"\e525"}.fa-guarani-sign:before{content:"\e19a"}.fa-arrows-rotate:before,.fa-refresh:before,.fa-sync:before{content:"\f021"}.fa-fire-extinguisher:before{content:"\f134"}.fa-cruzeiro-sign:before{content:"\e152"}.fa-greater-than-equal:before{content:"\f532"}.fa-shield-alt:before,.fa-shield-halved:before{content:"\f3ed"}.fa-atlas:before,.fa-book-atlas:before{content:"\f558"}.fa-virus:before{content:"\e074"}.fa-envelope-circle-check:before{content:"\e4e8"}.fa-layer-group:before{content:"\f5fd"}.fa-arrows-to-dot:before{content:"\e4be"}.fa-archway:before{content:"\f557"}.fa-heart-circle-check:before{content:"\e4fd"}.fa-house-chimney-crack:before,.fa-house-damage:before{content:"\f6f1"}.fa-file-archive:before,.fa-file-zipper:before{content:"\f1c6"}.fa-square:before{content:"\f0c8"}.fa-glass-martini:before,.fa-martini-glass-empty:before{content:"\f000"}.fa-couch:before{content:"\f4b8"}.fa-cedi-sign:before{content:"\e0df"}.fa-italic:before{content:"\f033"}.fa-church:before{content:"\f51d"}.fa-comments-dollar:before{content:"\f653"}.fa-democrat:before{content:"\f747"}.fa-z:before{content:"\5a"}.fa-person-skiing:before,.fa-skiing:before{content:"\f7c9"}.fa-road-lock:before{content:"\e567"}.fa-a:before{content:"\41"}.fa-temperature-arrow-down:before,.fa-temperature-down:before{content:"\e03f"}.fa-feather-alt:before,.fa-feather-pointed:before{content:"\f56b"}.fa-p:before{content:"\50"}.fa-snowflake:before{content:"\f2dc"}.fa-newspaper:before{content:"\f1ea"}.fa-ad:before,.fa-rectangle-ad:before{content:"\f641"}.fa-arrow-circle-right:before,.fa-circle-arrow-right:before{content:"\f0a9"}.fa-filter-circle-xmark:before{content:"\e17b"}.fa-locust:before{content:"\e520"}.fa-sort:before,.fa-unsorted:before{content:"\f0dc"}.fa-list-1-2:before,.fa-list-numeric:before,.fa-list-ol:before{content:"\f0cb"}.fa-person-dress-burst:before{content:"\e544"}.fa-money-check-alt:before,.fa-money-check-dollar:before{content:"\f53d"}.fa-vector-square:before{content:"\f5cb"}.fa-bread-slice:before{content:"\f7ec"}.fa-language:before{content:"\f1ab"}.fa-face-kiss-wink-heart:before,.fa-kiss-wink-heart:before{content:"\f598"}.fa-filter:before{content:"\f0b0"}.fa-question:before{content:"\3f"}.fa-file-signature:before{content:"\f573"}.fa-arrows-alt:before,.fa-up-down-left-right:before{content:"\f0b2"}.fa-house-chimney-user:before{content:"\e065"}.fa-hand-holding-heart:before{content:"\f4be"}.fa-puzzle-piece:before{content:"\f12e"}.fa-money-check:before{content:"\f53c"}.fa-star-half-alt:before,.fa-star-half-stroke:before{content:"\f5c0"}.fa-code:before{content:"\f121"}.fa-glass-whiskey:before,.fa-whiskey-glass:before{content:"\f7a0"}.fa-building-circle-exclamation:before{content:"\e4d3"}.fa-magnifying-glass-chart:before{content:"\e522"}.fa-arrow-up-right-from-square:before,.fa-external-link:before{content:"\f08e"}.fa-cubes-stacked:before{content:"\e4e6"}.fa-krw:before,.fa-won-sign:before,.fa-won:before{content:"\f159"}.fa-virus-covid:before{content:"\e4a8"}.fa-austral-sign:before{content:"\e0a9"}.fa-f:before{content:"\46"}.fa-leaf:before{content:"\f06c"}.fa-road:before{content:"\f018"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-person-circle-plus:before{content:"\e541"}.fa-chart-pie:before,.fa-pie-chart:before{content:"\f200"}.fa-bolt-lightning:before{content:"\e0b7"}.fa-sack-xmark:before{content:"\e56a"}.fa-file-excel:before{content:"\f1c3"}.fa-file-contract:before{content:"\f56c"}.fa-fish-fins:before{content:"\e4f2"}.fa-building-flag:before{content:"\e4d5"}.fa-face-grin-beam:before,.fa-grin-beam:before{content:"\f582"}.fa-object-ungroup:before{content:"\f248"}.fa-poop:before{content:"\f619"}.fa-location-pin:before,.fa-map-marker:before{content:"\f041"}.fa-kaaba:before{content:"\f66b"}.fa-toilet-paper:before{content:"\f71e"}.fa-hard-hat:before,.fa-hat-hard:before,.fa-helmet-safety:before{content:"\f807"}.fa-eject:before{content:"\f052"}.fa-arrow-alt-circle-right:before,.fa-circle-right:before{content:"\f35a"}.fa-plane-circle-check:before{content:"\e555"}.fa-face-rolling-eyes:before,.fa-meh-rolling-eyes:before{content:"\f5a5"}.fa-object-group:before{content:"\f247"}.fa-chart-line:before,.fa-line-chart:before{content:"\f201"}.fa-mask-ventilator:before{content:"\e524"}.fa-arrow-right:before{content:"\f061"}.fa-map-signs:before,.fa-signs-post:before{content:"\f277"}.fa-cash-register:before{content:"\f788"}.fa-person-circle-question:before{content:"\e542"}.fa-h:before{content:"\48"}.fa-tarp:before{content:"\e57b"}.fa-screwdriver-wrench:before,.fa-tools:before{content:"\f7d9"}.fa-arrows-to-eye:before{content:"\e4bf"}.fa-plug-circle-bolt:before{content:"\e55b"}.fa-heart:before{content:"\f004"}.fa-mars-and-venus:before{content:"\f224"}.fa-home-user:before,.fa-house-user:before{content:"\e1b0"}.fa-dumpster-fire:before{content:"\f794"}.fa-house-crack:before{content:"\e3b1"}.fa-cocktail:before,.fa-martini-glass-citrus:before{content:"\f561"}.fa-face-surprise:before,.fa-surprise:before{content:"\f5c2"}.fa-bottle-water:before{content:"\e4c5"}.fa-circle-pause:before,.fa-pause-circle:before{content:"\f28b"}.fa-toilet-paper-slash:before{content:"\e072"}.fa-apple-alt:before,.fa-apple-whole:before{content:"\f5d1"}.fa-kitchen-set:before{content:"\e51a"}.fa-r:before{content:"\52"}.fa-temperature-1:before,.fa-temperature-quarter:before,.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:"\f2ca"}.fa-cube:before{content:"\f1b2"}.fa-bitcoin-sign:before{content:"\e0b4"}.fa-shield-dog:before{content:"\e573"}.fa-solar-panel:before{content:"\f5ba"}.fa-lock-open:before{content:"\f3c1"}.fa-elevator:before{content:"\e16d"}.fa-money-bill-transfer:before{content:"\e528"}.fa-money-bill-trend-up:before{content:"\e529"}.fa-house-flood-water-circle-arrow-right:before{content:"\e50f"}.fa-poll-h:before,.fa-square-poll-horizontal:before{content:"\f682"}.fa-circle:before{content:"\f111"}.fa-backward-fast:before,.fa-fast-backward:before{content:"\f049"}.fa-recycle:before{content:"\f1b8"}.fa-user-astronaut:before{content:"\f4fb"}.fa-plane-slash:before{content:"\e069"}.fa-trademark:before{content:"\f25c"}.fa-basketball-ball:before,.fa-basketball:before{content:"\f434"}.fa-satellite-dish:before{content:"\f7c0"}.fa-arrow-alt-circle-up:before,.fa-circle-up:before{content:"\f35b"}.fa-mobile-alt:before,.fa-mobile-screen-button:before{content:"\f3cd"}.fa-volume-high:before,.fa-volume-up:before{content:"\f028"}.fa-users-rays:before{content:"\e593"}.fa-wallet:before{content:"\f555"}.fa-clipboard-check:before{content:"\f46c"}.fa-file-audio:before{content:"\f1c7"}.fa-burger:before,.fa-hamburger:before{content:"\f805"}.fa-wrench:before{content:"\f0ad"}.fa-bugs:before{content:"\e4d0"}.fa-rupee-sign:before,.fa-rupee:before{content:"\f156"}.fa-file-image:before{content:"\f1c5"}.fa-circle-question:before,.fa-question-circle:before{content:"\f059"}.fa-plane-departure:before{content:"\f5b0"}.fa-handshake-slash:before{content:"\e060"}.fa-book-bookmark:before{content:"\e0bb"}.fa-code-branch:before{content:"\f126"}.fa-hat-cowboy:before{content:"\f8c0"}.fa-bridge:before{content:"\e4c8"}.fa-phone-alt:before,.fa-phone-flip:before{content:"\f879"}.fa-truck-front:before{content:"\e2b7"}.fa-cat:before{content:"\f6be"}.fa-anchor-circle-exclamation:before{content:"\e4ab"}.fa-truck-field:before{content:"\e58d"}.fa-route:before{content:"\f4d7"}.fa-clipboard-question:before{content:"\e4e3"}.fa-panorama:before{content:"\e209"}.fa-comment-medical:before{content:"\f7f5"}.fa-teeth-open:before{content:"\f62f"}.fa-file-circle-minus:before{content:"\e4ed"}.fa-tags:before{content:"\f02c"}.fa-wine-glass:before{content:"\f4e3"}.fa-fast-forward:before,.fa-forward-fast:before{content:"\f050"}.fa-face-meh-blank:before,.fa-meh-blank:before{content:"\f5a4"}.fa-parking:before,.fa-square-parking:before{content:"\f540"}.fa-house-signal:before{content:"\e012"}.fa-bars-progress:before,.fa-tasks-alt:before{content:"\f828"}.fa-faucet-drip:before{content:"\e006"}.fa-cart-flatbed:before,.fa-dolly-flatbed:before{content:"\f474"}.fa-ban-smoking:before,.fa-smoking-ban:before{content:"\f54d"}.fa-terminal:before{content:"\f120"}.fa-mobile-button:before{content:"\f10b"}.fa-house-medical-flag:before{content:"\e514"}.fa-basket-shopping:before,.fa-shopping-basket:before{content:"\f291"}.fa-tape:before{content:"\f4db"}.fa-bus-alt:before,.fa-bus-simple:before{content:"\f55e"}.fa-eye:before{content:"\f06e"}.fa-face-sad-cry:before,.fa-sad-cry:before{content:"\f5b3"}.fa-audio-description:before{content:"\f29e"}.fa-person-military-to-person:before{content:"\e54c"}.fa-file-shield:before{content:"\e4f0"}.fa-user-slash:before{content:"\f506"}.fa-pen:before{content:"\f304"}.fa-tower-observation:before{content:"\e586"}.fa-file-code:before{content:"\f1c9"}.fa-signal-5:before,.fa-signal-perfect:before,.fa-signal:before{content:"\f012"}.fa-bus:before{content:"\f207"}.fa-heart-circle-xmark:before{content:"\e501"}.fa-home-lg:before,.fa-house-chimney:before{content:"\e3af"}.fa-window-maximize:before{content:"\f2d0"}.fa-face-frown:before,.fa-frown:before{content:"\f119"}.fa-prescription:before{content:"\f5b1"}.fa-shop:before,.fa-store-alt:before{content:"\f54f"}.fa-floppy-disk:before,.fa-save:before{content:"\f0c7"}.fa-vihara:before{content:"\f6a7"}.fa-balance-scale-left:before,.fa-scale-unbalanced:before{content:"\f515"}.fa-sort-asc:before,.fa-sort-up:before{content:"\f0de"}.fa-comment-dots:before,.fa-commenting:before{content:"\f4ad"}.fa-plant-wilt:before{content:"\e5aa"}.fa-diamond:before{content:"\f219"}.fa-face-grin-squint:before,.fa-grin-squint:before{content:"\f585"}.fa-hand-holding-dollar:before,.fa-hand-holding-usd:before{content:"\f4c0"}.fa-bacterium:before{content:"\e05a"}.fa-hand-pointer:before{content:"\f25a"}.fa-drum-steelpan:before{content:"\f56a"}.fa-hand-scissors:before{content:"\f257"}.fa-hands-praying:before,.fa-praying-hands:before{content:"\f684"}.fa-arrow-right-rotate:before,.fa-arrow-rotate-forward:before,.fa-arrow-rotate-right:before,.fa-redo:before{content:"\f01e"}.fa-biohazard:before{content:"\f780"}.fa-location-crosshairs:before,.fa-location:before{content:"\f601"}.fa-mars-double:before{content:"\f227"}.fa-child-dress:before{content:"\e59c"}.fa-users-between-lines:before{content:"\e591"}.fa-lungs-virus:before{content:"\e067"}.fa-face-grin-tears:before,.fa-grin-tears:before{content:"\f588"}.fa-phone:before{content:"\f095"}.fa-calendar-times:before,.fa-calendar-xmark:before{content:"\f273"}.fa-child-reaching:before{content:"\e59d"}.fa-head-side-virus:before{content:"\e064"}.fa-user-cog:before,.fa-user-gear:before{content:"\f4fe"}.fa-arrow-up-1-9:before,.fa-sort-numeric-up:before{content:"\f163"}.fa-door-closed:before{content:"\f52a"}.fa-shield-virus:before{content:"\e06c"}.fa-dice-six:before{content:"\f526"}.fa-mosquito-net:before{content:"\e52c"}.fa-bridge-water:before{content:"\e4ce"}.fa-person-booth:before{content:"\f756"}.fa-text-width:before{content:"\f035"}.fa-hat-wizard:before{content:"\f6e8"}.fa-pen-fancy:before{content:"\f5ac"}.fa-digging:before,.fa-person-digging:before{content:"\f85e"}.fa-trash:before{content:"\f1f8"}.fa-gauge-simple-med:before,.fa-gauge-simple:before,.fa-tachometer-average:before{content:"\f629"}.fa-book-medical:before{content:"\f7e6"}.fa-poo:before{content:"\f2fe"}.fa-quote-right-alt:before,.fa-quote-right:before{content:"\f10e"}.fa-shirt:before,.fa-t-shirt:before,.fa-tshirt:before{content:"\f553"}.fa-cubes:before{content:"\f1b3"}.fa-divide:before{content:"\f529"}.fa-tenge-sign:before,.fa-tenge:before{content:"\f7d7"}.fa-headphones:before{content:"\f025"}.fa-hands-holding:before{content:"\f4c2"}.fa-hands-clapping:before{content:"\e1a8"}.fa-republican:before{content:"\f75e"}.fa-arrow-left:before{content:"\f060"}.fa-person-circle-xmark:before{content:"\e543"}.fa-ruler:before{content:"\f545"}.fa-align-left:before{content:"\f036"}.fa-dice-d6:before{content:"\f6d1"}.fa-restroom:before{content:"\f7bd"}.fa-j:before{content:"\4a"}.fa-users-viewfinder:before{content:"\e595"}.fa-file-video:before{content:"\f1c8"}.fa-external-link-alt:before,.fa-up-right-from-square:before{content:"\f35d"}.fa-table-cells:before,.fa-th:before{content:"\f00a"}.fa-file-pdf:before{content:"\f1c1"}.fa-bible:before,.fa-book-bible:before{content:"\f647"}.fa-o:before{content:"\4f"}.fa-medkit:before,.fa-suitcase-medical:before{content:"\f0fa"}.fa-user-secret:before{content:"\f21b"}.fa-otter:before{content:"\f700"}.fa-female:before,.fa-person-dress:before{content:"\f182"}.fa-comment-dollar:before{content:"\f651"}.fa-briefcase-clock:before,.fa-business-time:before{content:"\f64a"}.fa-table-cells-large:before,.fa-th-large:before{content:"\f009"}.fa-book-tanakh:before,.fa-tanakh:before{content:"\f827"}.fa-phone-volume:before,.fa-volume-control-phone:before{content:"\f2a0"}.fa-hat-cowboy-side:before{content:"\f8c1"}.fa-clipboard-user:before{content:"\f7f3"}.fa-child:before{content:"\f1ae"}.fa-lira-sign:before{content:"\f195"}.fa-satellite:before{content:"\f7bf"}.fa-plane-lock:before{content:"\e558"}.fa-tag:before{content:"\f02b"}.fa-comment:before{content:"\f075"}.fa-birthday-cake:before,.fa-cake-candles:before,.fa-cake:before{content:"\f1fd"}.fa-envelope:before{content:"\f0e0"}.fa-angle-double-up:before,.fa-angles-up:before{content:"\f102"}.fa-paperclip:before{content:"\f0c6"}.fa-arrow-right-to-city:before{content:"\e4b3"}.fa-ribbon:before{content:"\f4d6"}.fa-lungs:before{content:"\f604"}.fa-arrow-up-9-1:before,.fa-sort-numeric-up-alt:before{content:"\f887"}.fa-litecoin-sign:before{content:"\e1d3"}.fa-border-none:before{content:"\f850"}.fa-circle-nodes:before{content:"\e4e2"}.fa-parachute-box:before{content:"\f4cd"}.fa-indent:before{content:"\f03c"}.fa-truck-field-un:before{content:"\e58e"}.fa-hourglass-empty:before,.fa-hourglass:before{content:"\f254"}.fa-mountain:before{content:"\f6fc"}.fa-user-doctor:before,.fa-user-md:before{content:"\f0f0"}.fa-circle-info:before,.fa-info-circle:before{content:"\f05a"}.fa-cloud-meatball:before{content:"\f73b"}.fa-camera-alt:before,.fa-camera:before{content:"\f030"}.fa-square-virus:before{content:"\e578"}.fa-meteor:before{content:"\f753"}.fa-car-on:before{content:"\e4dd"}.fa-sleigh:before{content:"\f7cc"}.fa-arrow-down-1-9:before,.fa-sort-numeric-asc:before,.fa-sort-numeric-down:before{content:"\f162"}.fa-hand-holding-droplet:before,.fa-hand-holding-water:before{content:"\f4c1"}.fa-water:before{content:"\f773"}.fa-calendar-check:before{content:"\f274"}.fa-braille:before{content:"\f2a1"}.fa-prescription-bottle-alt:before,.fa-prescription-bottle-medical:before{content:"\f486"}.fa-landmark:before{content:"\f66f"}.fa-truck:before{content:"\f0d1"}.fa-crosshairs:before{content:"\f05b"}.fa-person-cane:before{content:"\e53c"}.fa-tent:before{content:"\e57d"}.fa-vest-patches:before{content:"\e086"}.fa-check-double:before{content:"\f560"}.fa-arrow-down-a-z:before,.fa-sort-alpha-asc:before,.fa-sort-alpha-down:before{content:"\f15d"}.fa-money-bill-wheat:before{content:"\e52a"}.fa-cookie:before{content:"\f563"}.fa-arrow-left-rotate:before,.fa-arrow-rotate-back:before,.fa-arrow-rotate-backward:before,.fa-arrow-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-hard-drive:before,.fa-hdd:before{content:"\f0a0"}.fa-face-grin-squint-tears:before,.fa-grin-squint-tears:before{content:"\f586"}.fa-dumbbell:before{content:"\f44b"}.fa-list-alt:before,.fa-rectangle-list:before{content:"\f022"}.fa-tarp-droplet:before{content:"\e57c"}.fa-house-medical-circle-check:before{content:"\e511"}.fa-person-skiing-nordic:before,.fa-skiing-nordic:before{content:"\f7ca"}.fa-calendar-plus:before{content:"\f271"}.fa-plane-arrival:before{content:"\f5af"}.fa-arrow-alt-circle-left:before,.fa-circle-left:before{content:"\f359"}.fa-subway:before,.fa-train-subway:before{content:"\f239"}.fa-chart-gantt:before{content:"\e0e4"}.fa-indian-rupee-sign:before,.fa-indian-rupee:before,.fa-inr:before{content:"\e1bc"}.fa-crop-alt:before,.fa-crop-simple:before{content:"\f565"}.fa-money-bill-1:before,.fa-money-bill-alt:before{content:"\f3d1"}.fa-left-long:before,.fa-long-arrow-alt-left:before{content:"\f30a"}.fa-dna:before{content:"\f471"}.fa-virus-slash:before{content:"\e075"}.fa-minus:before,.fa-subtract:before{content:"\f068"}.fa-chess:before{content:"\f439"}.fa-arrow-left-long:before,.fa-long-arrow-left:before{content:"\f177"}.fa-plug-circle-check:before{content:"\e55c"}.fa-street-view:before{content:"\f21d"}.fa-franc-sign:before{content:"\e18f"}.fa-volume-off:before{content:"\f026"}.fa-american-sign-language-interpreting:before,.fa-asl-interpreting:before,.fa-hands-american-sign-language-interpreting:before,.fa-hands-asl-interpreting:before{content:"\f2a3"}.fa-cog:before,.fa-gear:before{content:"\f013"}.fa-droplet-slash:before,.fa-tint-slash:before{content:"\f5c7"}.fa-mosque:before{content:"\f678"}.fa-mosquito:before{content:"\e52b"}.fa-star-of-david:before{content:"\f69a"}.fa-person-military-rifle:before{content:"\e54b"}.fa-cart-shopping:before,.fa-shopping-cart:before{content:"\f07a"}.fa-vials:before{content:"\f493"}.fa-plug-circle-plus:before{content:"\e55f"}.fa-place-of-worship:before{content:"\f67f"}.fa-grip-vertical:before{content:"\f58e"}.fa-arrow-turn-up:before,.fa-level-up:before{content:"\f148"}.fa-u:before{content:"\55"}.fa-square-root-alt:before,.fa-square-root-variable:before{content:"\f698"}.fa-clock-four:before,.fa-clock:before{content:"\f017"}.fa-backward-step:before,.fa-step-backward:before{content:"\f048"}.fa-pallet:before{content:"\f482"}.fa-faucet:before{content:"\e005"}.fa-baseball-bat-ball:before{content:"\f432"}.fa-s:before{content:"\53"}.fa-timeline:before{content:"\e29c"}.fa-keyboard:before{content:"\f11c"}.fa-caret-down:before{content:"\f0d7"}.fa-clinic-medical:before,.fa-house-chimney-medical:before{content:"\f7f2"}.fa-temperature-3:before,.fa-temperature-three-quarters:before,.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:"\f2c8"}.fa-mobile-android-alt:before,.fa-mobile-screen:before{content:"\f3cf"}.fa-plane-up:before{content:"\e22d"}.fa-piggy-bank:before{content:"\f4d3"}.fa-battery-3:before,.fa-battery-half:before{content:"\f242"}.fa-mountain-city:before{content:"\e52e"}.fa-coins:before{content:"\f51e"}.fa-khanda:before{content:"\f66d"}.fa-sliders-h:before,.fa-sliders:before{content:"\f1de"}.fa-folder-tree:before{content:"\f802"}.fa-network-wired:before{content:"\f6ff"}.fa-map-pin:before{content:"\f276"}.fa-hamsa:before{content:"\f665"}.fa-cent-sign:before{content:"\e3f5"}.fa-flask:before{content:"\f0c3"}.fa-person-pregnant:before{content:"\e31e"}.fa-wand-sparkles:before{content:"\f72b"}.fa-ellipsis-v:before,.fa-ellipsis-vertical:before{content:"\f142"}.fa-ticket:before{content:"\f145"}.fa-power-off:before{content:"\f011"}.fa-long-arrow-alt-right:before,.fa-right-long:before{content:"\f30b"}.fa-flag-usa:before{content:"\f74d"}.fa-laptop-file:before{content:"\e51d"}.fa-teletype:before,.fa-tty:before{content:"\f1e4"}.fa-diagram-next:before{content:"\e476"}.fa-person-rifle:before{content:"\e54e"}.fa-house-medical-circle-exclamation:before{content:"\e512"}.fa-closed-captioning:before{content:"\f20a"}.fa-hiking:before,.fa-person-hiking:before{content:"\f6ec"}.fa-venus-double:before{content:"\f226"}.fa-images:before{content:"\f302"}.fa-calculator:before{content:"\f1ec"}.fa-people-pulling:before{content:"\e535"}.fa-n:before{content:"\4e"}.fa-cable-car:before,.fa-tram:before{content:"\f7da"}.fa-cloud-rain:before{content:"\f73d"}.fa-building-circle-xmark:before{content:"\e4d4"}.fa-ship:before{content:"\f21a"}.fa-arrows-down-to-line:before{content:"\e4b8"}.fa-download:before{content:"\f019"}.fa-face-grin:before,.fa-grin:before{content:"\f580"}.fa-backspace:before,.fa-delete-left:before{content:"\f55a"}.fa-eye-dropper-empty:before,.fa-eye-dropper:before,.fa-eyedropper:before{content:"\f1fb"}.fa-file-circle-check:before{content:"\e5a0"}.fa-forward:before{content:"\f04e"}.fa-mobile-android:before,.fa-mobile-phone:before,.fa-mobile:before{content:"\f3ce"}.fa-face-meh:before,.fa-meh:before{content:"\f11a"}.fa-align-center:before{content:"\f037"}.fa-book-dead:before,.fa-book-skull:before{content:"\f6b7"}.fa-drivers-license:before,.fa-id-card:before{content:"\f2c2"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-heart-circle-exclamation:before{content:"\e4fe"}.fa-home-alt:before,.fa-home-lg-alt:before,.fa-home:before,.fa-house:before{content:"\f015"}.fa-calendar-week:before{content:"\f784"}.fa-laptop-medical:before{content:"\f812"}.fa-b:before{content:"\42"}.fa-file-medical:before{content:"\f477"}.fa-dice-one:before{content:"\f525"}.fa-kiwi-bird:before{content:"\f535"}.fa-arrow-right-arrow-left:before,.fa-exchange:before{content:"\f0ec"}.fa-redo-alt:before,.fa-rotate-forward:before,.fa-rotate-right:before{content:"\f2f9"}.fa-cutlery:before,.fa-utensils:before{content:"\f2e7"}.fa-arrow-up-wide-short:before,.fa-sort-amount-up:before{content:"\f161"}.fa-mill-sign:before{content:"\e1ed"}.fa-bowl-rice:before{content:"\e2eb"}.fa-skull:before{content:"\f54c"}.fa-broadcast-tower:before,.fa-tower-broadcast:before{content:"\f519"}.fa-truck-pickup:before{content:"\f63c"}.fa-long-arrow-alt-up:before,.fa-up-long:before{content:"\f30c"}.fa-stop:before{content:"\f04d"}.fa-code-merge:before{content:"\f387"}.fa-upload:before{content:"\f093"}.fa-hurricane:before{content:"\f751"}.fa-mound:before{content:"\e52d"}.fa-toilet-portable:before{content:"\e583"}.fa-compact-disc:before{content:"\f51f"}.fa-file-arrow-down:before,.fa-file-download:before{content:"\f56d"}.fa-caravan:before{content:"\f8ff"}.fa-shield-cat:before{content:"\e572"}.fa-bolt:before,.fa-zap:before{content:"\f0e7"}.fa-glass-water:before{content:"\e4f4"}.fa-oil-well:before{content:"\e532"}.fa-vault:before{content:"\e2c5"}.fa-mars:before{content:"\f222"}.fa-toilet:before{content:"\f7d8"}.fa-plane-circle-xmark:before{content:"\e557"}.fa-cny:before,.fa-jpy:before,.fa-rmb:before,.fa-yen-sign:before,.fa-yen:before{content:"\f157"}.fa-rouble:before,.fa-rub:before,.fa-ruble-sign:before,.fa-ruble:before{content:"\f158"}.fa-sun:before{content:"\f185"}.fa-guitar:before{content:"\f7a6"}.fa-face-laugh-wink:before,.fa-laugh-wink:before{content:"\f59c"}.fa-horse-head:before{content:"\f7ab"}.fa-bore-hole:before{content:"\e4c3"}.fa-industry:before{content:"\f275"}.fa-arrow-alt-circle-down:before,.fa-circle-down:before{content:"\f358"}.fa-arrows-turn-to-dots:before{content:"\e4c1"}.fa-florin-sign:before{content:"\e184"}.fa-arrow-down-short-wide:before,.fa-sort-amount-desc:before,.fa-sort-amount-down-alt:before{content:"\f884"}.fa-less-than:before{content:"\3c"}.fa-angle-down:before{content:"\f107"}.fa-car-tunnel:before{content:"\e4de"}.fa-head-side-cough:before{content:"\e061"}.fa-grip-lines:before{content:"\f7a4"}.fa-thumbs-down:before{content:"\f165"}.fa-user-lock:before{content:"\f502"}.fa-arrow-right-long:before,.fa-long-arrow-right:before{content:"\f178"}.fa-anchor-circle-xmark:before{content:"\e4ac"}.fa-ellipsis-h:before,.fa-ellipsis:before{content:"\f141"}.fa-chess-pawn:before{content:"\f443"}.fa-first-aid:before,.fa-kit-medical:before{content:"\f479"}.fa-person-through-window:before{content:"\e5a9"}.fa-toolbox:before{content:"\f552"}.fa-hands-holding-circle:before{content:"\e4fb"}.fa-bug:before{content:"\f188"}.fa-credit-card-alt:before,.fa-credit-card:before{content:"\f09d"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-hand-holding-hand:before{content:"\e4f7"}.fa-book-open-reader:before,.fa-book-reader:before{content:"\f5da"}.fa-mountain-sun:before{content:"\e52f"}.fa-arrows-left-right-to-line:before{content:"\e4ba"}.fa-dice-d20:before{content:"\f6cf"}.fa-truck-droplet:before{content:"\e58c"}.fa-file-circle-xmark:before{content:"\e5a1"}.fa-temperature-arrow-up:before,.fa-temperature-up:before{content:"\e040"}.fa-medal:before{content:"\f5a2"}.fa-bed:before{content:"\f236"}.fa-h-square:before,.fa-square-h:before{content:"\f0fd"}.fa-podcast:before{content:"\f2ce"}.fa-temperature-4:before,.fa-temperature-full:before,.fa-thermometer-4:before,.fa-thermometer-full:before{content:"\f2c7"}.fa-bell:before{content:"\f0f3"}.fa-superscript:before{content:"\f12b"}.fa-plug-circle-xmark:before{content:"\e560"}.fa-star-of-life:before{content:"\f621"}.fa-phone-slash:before{content:"\f3dd"}.fa-paint-roller:before{content:"\f5aa"}.fa-hands-helping:before,.fa-handshake-angle:before{content:"\f4c4"}.fa-location-dot:before,.fa-map-marker-alt:before{content:"\f3c5"}.fa-file:before{content:"\f15b"}.fa-greater-than:before{content:"\3e"}.fa-person-swimming:before,.fa-swimmer:before{content:"\f5c4"}.fa-arrow-down:before{content:"\f063"}.fa-droplet:before,.fa-tint:before{content:"\f043"}.fa-eraser:before{content:"\f12d"}.fa-earth-america:before,.fa-earth-americas:before,.fa-earth:before,.fa-globe-americas:before{content:"\f57d"}.fa-person-burst:before{content:"\e53b"}.fa-dove:before{content:"\f4ba"}.fa-battery-0:before,.fa-battery-empty:before{content:"\f244"}.fa-socks:before{content:"\f696"}.fa-inbox:before{content:"\f01c"}.fa-section:before{content:"\e447"}.fa-gauge-high:before,.fa-tachometer-alt-fast:before,.fa-tachometer-alt:before{content:"\f625"}.fa-envelope-open-text:before{content:"\f658"}.fa-hospital-alt:before,.fa-hospital-wide:before,.fa-hospital:before{content:"\f0f8"}.fa-wine-bottle:before{content:"\f72f"}.fa-chess-rook:before{content:"\f447"}.fa-bars-staggered:before,.fa-reorder:before,.fa-stream:before{content:"\f550"}.fa-dharmachakra:before{content:"\f655"}.fa-hotdog:before{content:"\f80f"}.fa-blind:before,.fa-person-walking-with-cane:before{content:"\f29d"}.fa-drum:before{content:"\f569"}.fa-ice-cream:before{content:"\f810"}.fa-heart-circle-bolt:before{content:"\e4fc"}.fa-fax:before{content:"\f1ac"}.fa-paragraph:before{content:"\f1dd"}.fa-check-to-slot:before,.fa-vote-yea:before{content:"\f772"}.fa-star-half:before{content:"\f089"}.fa-boxes-alt:before,.fa-boxes-stacked:before,.fa-boxes:before{content:"\f468"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-assistive-listening-systems:before,.fa-ear-listen:before{content:"\f2a2"}.fa-tree-city:before{content:"\e587"}.fa-play:before{content:"\f04b"}.fa-font:before{content:"\f031"}.fa-rupiah-sign:before{content:"\e23d"}.fa-magnifying-glass:before,.fa-search:before{content:"\f002"}.fa-ping-pong-paddle-ball:before,.fa-table-tennis-paddle-ball:before,.fa-table-tennis:before{content:"\f45d"}.fa-diagnoses:before,.fa-person-dots-from-line:before{content:"\f470"}.fa-trash-can-arrow-up:before,.fa-trash-restore-alt:before{content:"\f82a"}.fa-naira-sign:before{content:"\e1f6"}.fa-cart-arrow-down:before{content:"\f218"}.fa-walkie-talkie:before{content:"\f8ef"}.fa-file-edit:before,.fa-file-pen:before{content:"\f31c"}.fa-receipt:before{content:"\f543"}.fa-pen-square:before,.fa-pencil-square:before,.fa-square-pen:before{content:"\f14b"}.fa-suitcase-rolling:before{content:"\f5c1"}.fa-person-circle-exclamation:before{content:"\e53f"}.fa-chevron-down:before{content:"\f078"}.fa-battery-5:before,.fa-battery-full:before,.fa-battery:before{content:"\f240"}.fa-skull-crossbones:before{content:"\f714"}.fa-code-compare:before{content:"\e13a"}.fa-list-dots:before,.fa-list-ul:before{content:"\f0ca"}.fa-school-lock:before{content:"\e56f"}.fa-tower-cell:before{content:"\e585"}.fa-down-long:before,.fa-long-arrow-alt-down:before{content:"\f309"}.fa-ranking-star:before{content:"\e561"}.fa-chess-king:before{content:"\f43f"}.fa-person-harassing:before{content:"\e549"}.fa-brazilian-real-sign:before{content:"\e46c"}.fa-landmark-alt:before,.fa-landmark-dome:before{content:"\f752"}.fa-arrow-up:before{content:"\f062"}.fa-television:before,.fa-tv-alt:before,.fa-tv:before{content:"\f26c"}.fa-shrimp:before{content:"\e448"}.fa-list-check:before,.fa-tasks:before{content:"\f0ae"}.fa-jug-detergent:before{content:"\e519"}.fa-circle-user:before,.fa-user-circle:before{content:"\f2bd"}.fa-user-shield:before{content:"\f505"}.fa-wind:before{content:"\f72e"}.fa-car-burst:before,.fa-car-crash:before{content:"\f5e1"}.fa-y:before{content:"\59"}.fa-person-snowboarding:before,.fa-snowboarding:before{content:"\f7ce"}.fa-shipping-fast:before,.fa-truck-fast:before{content:"\f48b"}.fa-fish:before{content:"\f578"}.fa-user-graduate:before{content:"\f501"}.fa-adjust:before,.fa-circle-half-stroke:before{content:"\f042"}.fa-clapperboard:before{content:"\e131"}.fa-circle-radiation:before,.fa-radiation-alt:before{content:"\f7ba"}.fa-baseball-ball:before,.fa-baseball:before{content:"\f433"}.fa-jet-fighter-up:before{content:"\e518"}.fa-diagram-project:before,.fa-project-diagram:before{content:"\f542"}.fa-copy:before{content:"\f0c5"}.fa-volume-mute:before,.fa-volume-times:before,.fa-volume-xmark:before{content:"\f6a9"}.fa-hand-sparkles:before{content:"\e05d"}.fa-grip-horizontal:before,.fa-grip:before{content:"\f58d"}.fa-share-from-square:before,.fa-share-square:before{content:"\f14d"}.fa-child-combatant:before,.fa-child-rifle:before{content:"\e4e0"}.fa-gun:before{content:"\e19b"}.fa-phone-square:before,.fa-square-phone:before{content:"\f098"}.fa-add:before,.fa-plus:before{content:"\2b"}.fa-expand:before{content:"\f065"}.fa-computer:before{content:"\e4e5"}.fa-close:before,.fa-multiply:before,.fa-remove:before,.fa-times:before,.fa-xmark:before{content:"\f00d"}.fa-arrows-up-down-left-right:before,.fa-arrows:before{content:"\f047"}.fa-chalkboard-teacher:before,.fa-chalkboard-user:before{content:"\f51c"}.fa-peso-sign:before{content:"\e222"}.fa-building-shield:before{content:"\e4d8"}.fa-baby:before{content:"\f77c"}.fa-users-line:before{content:"\e592"}.fa-quote-left-alt:before,.fa-quote-left:before{content:"\f10d"}.fa-tractor:before{content:"\f722"}.fa-trash-arrow-up:before,.fa-trash-restore:before{content:"\f829"}.fa-arrow-down-up-lock:before{content:"\e4b0"}.fa-lines-leaning:before{content:"\e51e"}.fa-ruler-combined:before{content:"\f546"}.fa-copyright:before{content:"\f1f9"}.fa-equals:before{content:"\3d"}.fa-blender:before{content:"\f517"}.fa-teeth:before{content:"\f62e"}.fa-ils:before,.fa-shekel-sign:before,.fa-shekel:before,.fa-sheqel-sign:before,.fa-sheqel:before{content:"\f20b"}.fa-map:before{content:"\f279"}.fa-rocket:before{content:"\f135"}.fa-photo-film:before,.fa-photo-video:before{content:"\f87c"}.fa-folder-minus:before{content:"\f65d"}.fa-store:before{content:"\f54e"}.fa-arrow-trend-up:before{content:"\e098"}.fa-plug-circle-minus:before{content:"\e55e"}.fa-sign-hanging:before,.fa-sign:before{content:"\f4d9"}.fa-bezier-curve:before{content:"\f55b"}.fa-bell-slash:before{content:"\f1f6"}.fa-tablet-android:before,.fa-tablet:before{content:"\f3fb"}.fa-school-flag:before{content:"\e56e"}.fa-fill:before{content:"\f575"}.fa-angle-up:before{content:"\f106"}.fa-drumstick-bite:before{content:"\f6d7"}.fa-holly-berry:before{content:"\f7aa"}.fa-chevron-left:before{content:"\f053"}.fa-bacteria:before{content:"\e059"}.fa-hand-lizard:before{content:"\f258"}.fa-notdef:before{content:"\e1fe"}.fa-disease:before{content:"\f7fa"}.fa-briefcase-medical:before{content:"\f469"}.fa-genderless:before{content:"\f22d"}.fa-chevron-right:before{content:"\f054"}.fa-retweet:before{content:"\f079"}.fa-car-alt:before,.fa-car-rear:before{content:"\f5de"}.fa-pump-soap:before{content:"\e06b"}.fa-video-slash:before{content:"\f4e2"}.fa-battery-2:before,.fa-battery-quarter:before{content:"\f243"}.fa-radio:before{content:"\f8d7"}.fa-baby-carriage:before,.fa-carriage-baby:before{content:"\f77d"}.fa-traffic-light:before{content:"\f637"}.fa-thermometer:before{content:"\f491"}.fa-vr-cardboard:before{content:"\f729"}.fa-hand-middle-finger:before{content:"\f806"}.fa-percent:before,.fa-percentage:before{content:"\25"}.fa-truck-moving:before{content:"\f4df"}.fa-glass-water-droplet:before{content:"\e4f5"}.fa-display:before{content:"\e163"}.fa-face-smile:before,.fa-smile:before{content:"\f118"}.fa-thumb-tack:before,.fa-thumbtack:before{content:"\f08d"}.fa-trophy:before{content:"\f091"}.fa-person-praying:before,.fa-pray:before{content:"\f683"}.fa-hammer:before{content:"\f6e3"}.fa-hand-peace:before{content:"\f25b"}.fa-rotate:before,.fa-sync-alt:before{content:"\f2f1"}.fa-spinner:before{content:"\f110"}.fa-robot:before{content:"\f544"}.fa-peace:before{content:"\f67c"}.fa-cogs:before,.fa-gears:before{content:"\f085"}.fa-warehouse:before{content:"\f494"}.fa-arrow-up-right-dots:before{content:"\e4b7"}.fa-splotch:before{content:"\f5bc"}.fa-face-grin-hearts:before,.fa-grin-hearts:before{content:"\f584"}.fa-dice-four:before{content:"\f524"}.fa-sim-card:before{content:"\f7c4"}.fa-transgender-alt:before,.fa-transgender:before{content:"\f225"}.fa-mercury:before{content:"\f223"}.fa-arrow-turn-down:before,.fa-level-down:before{content:"\f149"}.fa-person-falling-burst:before{content:"\e547"}.fa-award:before{content:"\f559"}.fa-ticket-alt:before,.fa-ticket-simple:before{content:"\f3ff"}.fa-building:before{content:"\f1ad"}.fa-angle-double-left:before,.fa-angles-left:before{content:"\f100"}.fa-qrcode:before{content:"\f029"}.fa-clock-rotate-left:before,.fa-history:before{content:"\f1da"}.fa-face-grin-beam-sweat:before,.fa-grin-beam-sweat:before{content:"\f583"}.fa-arrow-right-from-file:before,.fa-file-export:before{content:"\f56e"}.fa-shield-blank:before,.fa-shield:before{content:"\f132"}.fa-arrow-up-short-wide:before,.fa-sort-amount-up-alt:before{content:"\f885"}.fa-house-medical:before{content:"\e3b2"}.fa-golf-ball-tee:before,.fa-golf-ball:before{content:"\f450"}.fa-chevron-circle-left:before,.fa-circle-chevron-left:before{content:"\f137"}.fa-house-chimney-window:before{content:"\e00d"}.fa-pen-nib:before{content:"\f5ad"}.fa-tent-arrow-turn-left:before{content:"\e580"}.fa-tents:before{content:"\e582"}.fa-magic:before,.fa-wand-magic:before{content:"\f0d0"}.fa-dog:before{content:"\f6d3"}.fa-carrot:before{content:"\f787"}.fa-moon:before{content:"\f186"}.fa-wine-glass-alt:before,.fa-wine-glass-empty:before{content:"\f5ce"}.fa-cheese:before{content:"\f7ef"}.fa-yin-yang:before{content:"\f6ad"}.fa-music:before{content:"\f001"}.fa-code-commit:before{content:"\f386"}.fa-temperature-low:before{content:"\f76b"}.fa-biking:before,.fa-person-biking:before{content:"\f84a"}.fa-broom:before{content:"\f51a"}.fa-shield-heart:before{content:"\e574"}.fa-gopuram:before{content:"\f664"}.fa-earth-oceania:before,.fa-globe-oceania:before{content:"\e47b"}.fa-square-xmark:before,.fa-times-square:before,.fa-xmark-square:before{content:"\f2d3"}.fa-hashtag:before{content:"\23"}.fa-expand-alt:before,.fa-up-right-and-down-left-from-center:before{content:"\f424"}.fa-oil-can:before{content:"\f613"}.fa-t:before{content:"\54"}.fa-hippo:before{content:"\f6ed"}.fa-chart-column:before{content:"\e0e3"}.fa-infinity:before{content:"\f534"}.fa-vial-circle-check:before{content:"\e596"}.fa-person-arrow-down-to-line:before{content:"\e538"}.fa-voicemail:before{content:"\f897"}.fa-fan:before{content:"\f863"}.fa-person-walking-luggage:before{content:"\e554"}.fa-arrows-alt-v:before,.fa-up-down:before{content:"\f338"}.fa-cloud-moon-rain:before{content:"\f73c"}.fa-calendar:before{content:"\f133"}.fa-trailer:before{content:"\e041"}.fa-bahai:before,.fa-haykal:before{content:"\f666"}.fa-sd-card:before{content:"\f7c2"}.fa-dragon:before{content:"\f6d5"}.fa-shoe-prints:before{content:"\f54b"}.fa-circle-plus:before,.fa-plus-circle:before{content:"\f055"}.fa-face-grin-tongue-wink:before,.fa-grin-tongue-wink:before{content:"\f58b"}.fa-hand-holding:before{content:"\f4bd"}.fa-plug-circle-exclamation:before{content:"\e55d"}.fa-chain-broken:before,.fa-chain-slash:before,.fa-link-slash:before,.fa-unlink:before{content:"\f127"}.fa-clone:before{content:"\f24d"}.fa-person-walking-arrow-loop-left:before{content:"\e551"}.fa-arrow-up-z-a:before,.fa-sort-alpha-up-alt:before{content:"\f882"}.fa-fire-alt:before,.fa-fire-flame-curved:before{content:"\f7e4"}.fa-tornado:before{content:"\f76f"}.fa-file-circle-plus:before{content:"\e494"}.fa-book-quran:before,.fa-quran:before{content:"\f687"}.fa-anchor:before{content:"\f13d"}.fa-border-all:before{content:"\f84c"}.fa-angry:before,.fa-face-angry:before{content:"\f556"}.fa-cookie-bite:before{content:"\f564"}.fa-arrow-trend-down:before{content:"\e097"}.fa-feed:before,.fa-rss:before{content:"\f09e"}.fa-draw-polygon:before{content:"\f5ee"}.fa-balance-scale:before,.fa-scale-balanced:before{content:"\f24e"}.fa-gauge-simple-high:before,.fa-tachometer-fast:before,.fa-tachometer:before{content:"\f62a"}.fa-shower:before{content:"\f2cc"}.fa-desktop-alt:before,.fa-desktop:before{content:"\f390"}.fa-m:before{content:"\4d"}.fa-table-list:before,.fa-th-list:before{content:"\f00b"}.fa-comment-sms:before,.fa-sms:before{content:"\f7cd"}.fa-book:before{content:"\f02d"}.fa-user-plus:before{content:"\f234"}.fa-check:before{content:"\f00c"}.fa-battery-4:before,.fa-battery-three-quarters:before{content:"\f241"}.fa-house-circle-check:before{content:"\e509"}.fa-angle-left:before{content:"\f104"}.fa-diagram-successor:before{content:"\e47a"}.fa-truck-arrow-right:before{content:"\e58b"}.fa-arrows-split-up-and-left:before{content:"\e4bc"}.fa-fist-raised:before,.fa-hand-fist:before{content:"\f6de"}.fa-cloud-moon:before{content:"\f6c3"}.fa-briefcase:before{content:"\f0b1"}.fa-person-falling:before{content:"\e546"}.fa-image-portrait:before,.fa-portrait:before{content:"\f3e0"}.fa-user-tag:before{content:"\f507"}.fa-rug:before{content:"\e569"}.fa-earth-europe:before,.fa-globe-europe:before{content:"\f7a2"}.fa-cart-flatbed-suitcase:before,.fa-luggage-cart:before{content:"\f59d"}.fa-rectangle-times:before,.fa-rectangle-xmark:before,.fa-times-rectangle:before,.fa-window-close:before{content:"\f410"}.fa-baht-sign:before{content:"\e0ac"}.fa-book-open:before{content:"\f518"}.fa-book-journal-whills:before,.fa-journal-whills:before{content:"\f66a"}.fa-handcuffs:before{content:"\e4f8"}.fa-exclamation-triangle:before,.fa-triangle-exclamation:before,.fa-warning:before{content:"\f071"}.fa-database:before{content:"\f1c0"}.fa-arrow-turn-right:before,.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-bottle-droplet:before{content:"\e4c4"}.fa-mask-face:before{content:"\e1d7"}.fa-hill-rockslide:before{content:"\e508"}.fa-exchange-alt:before,.fa-right-left:before{content:"\f362"}.fa-paper-plane:before{content:"\f1d8"}.fa-road-circle-exclamation:before{content:"\e565"}.fa-dungeon:before{content:"\f6d9"}.fa-align-right:before{content:"\f038"}.fa-money-bill-1-wave:before,.fa-money-bill-wave-alt:before{content:"\f53b"}.fa-life-ring:before{content:"\f1cd"}.fa-hands:before,.fa-sign-language:before,.fa-signing:before{content:"\f2a7"}.fa-calendar-day:before{content:"\f783"}.fa-ladder-water:before,.fa-swimming-pool:before,.fa-water-ladder:before{content:"\f5c5"}.fa-arrows-up-down:before,.fa-arrows-v:before{content:"\f07d"}.fa-face-grimace:before,.fa-grimace:before{content:"\f57f"}.fa-wheelchair-alt:before,.fa-wheelchair-move:before{content:"\e2ce"}.fa-level-down-alt:before,.fa-turn-down:before{content:"\f3be"}.fa-person-walking-arrow-right:before{content:"\e552"}.fa-envelope-square:before,.fa-square-envelope:before{content:"\f199"}.fa-dice:before{content:"\f522"}.fa-bowling-ball:before{content:"\f436"}.fa-brain:before{content:"\f5dc"}.fa-band-aid:before,.fa-bandage:before{content:"\f462"}.fa-calendar-minus:before{content:"\f272"}.fa-circle-xmark:before,.fa-times-circle:before,.fa-xmark-circle:before{content:"\f057"}.fa-gifts:before{content:"\f79c"}.fa-hotel:before{content:"\f594"}.fa-earth-asia:before,.fa-globe-asia:before{content:"\f57e"}.fa-id-card-alt:before,.fa-id-card-clip:before{content:"\f47f"}.fa-magnifying-glass-plus:before,.fa-search-plus:before{content:"\f00e"}.fa-thumbs-up:before{content:"\f164"}.fa-user-clock:before{content:"\f4fd"}.fa-allergies:before,.fa-hand-dots:before{content:"\f461"}.fa-file-invoice:before{content:"\f570"}.fa-window-minimize:before{content:"\f2d1"}.fa-coffee:before,.fa-mug-saucer:before{content:"\f0f4"}.fa-brush:before{content:"\f55d"}.fa-mask:before{content:"\f6fa"}.fa-magnifying-glass-minus:before,.fa-search-minus:before{content:"\f010"}.fa-ruler-vertical:before{content:"\f548"}.fa-user-alt:before,.fa-user-large:before{content:"\f406"}.fa-train-tram:before{content:"\e5b4"}.fa-user-nurse:before{content:"\f82f"}.fa-syringe:before{content:"\f48e"}.fa-cloud-sun:before{content:"\f6c4"}.fa-stopwatch-20:before{content:"\e06f"}.fa-square-full:before{content:"\f45c"}.fa-magnet:before{content:"\f076"}.fa-jar:before{content:"\e516"}.fa-note-sticky:before,.fa-sticky-note:before{content:"\f249"}.fa-bug-slash:before{content:"\e490"}.fa-arrow-up-from-water-pump:before{content:"\e4b6"}.fa-bone:before{content:"\f5d7"}.fa-user-injured:before{content:"\f728"}.fa-face-sad-tear:before,.fa-sad-tear:before{content:"\f5b4"}.fa-plane:before{content:"\f072"}.fa-tent-arrows-down:before{content:"\e581"}.fa-exclamation:before{content:"\21"}.fa-arrows-spin:before{content:"\e4bb"}.fa-print:before{content:"\f02f"}.fa-try:before,.fa-turkish-lira-sign:before,.fa-turkish-lira:before{content:"\e2bb"}.fa-dollar-sign:before,.fa-dollar:before,.fa-usd:before{content:"\24"}.fa-x:before{content:"\58"}.fa-magnifying-glass-dollar:before,.fa-search-dollar:before{content:"\f688"}.fa-users-cog:before,.fa-users-gear:before{content:"\f509"}.fa-person-military-pointing:before{content:"\e54a"}.fa-bank:before,.fa-building-columns:before,.fa-institution:before,.fa-museum:before,.fa-university:before{content:"\f19c"}.fa-umbrella:before{content:"\f0e9"}.fa-trowel:before{content:"\e589"}.fa-d:before{content:"\44"}.fa-stapler:before{content:"\e5af"}.fa-masks-theater:before,.fa-theater-masks:before{content:"\f630"}.fa-kip-sign:before{content:"\e1c4"}.fa-hand-point-left:before{content:"\f0a5"}.fa-handshake-alt:before,.fa-handshake-simple:before{content:"\f4c6"}.fa-fighter-jet:before,.fa-jet-fighter:before{content:"\f0fb"}.fa-share-alt-square:before,.fa-square-share-nodes:before{content:"\f1e1"}.fa-barcode:before{content:"\f02a"}.fa-plus-minus:before{content:"\e43c"}.fa-video-camera:before,.fa-video:before{content:"\f03d"}.fa-graduation-cap:before,.fa-mortar-board:before{content:"\f19d"}.fa-hand-holding-medical:before{content:"\e05c"}.fa-person-circle-check:before{content:"\e53e"}.fa-level-up-alt:before,.fa-turn-up:before{content:"\f3bf"}
+.fa-sr-only,.fa-sr-only-focusable:not(:focus),.sr-only,.sr-only-focusable:not(:focus){position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0} \ No newline at end of file
diff --git a/40-abschlusspraesentation/assets/fontawesome/css/regular.css b/40-abschlusspraesentation/assets/fontawesome/css/regular.css
new file mode 100644
index 0000000..f31fd04
--- /dev/null
+++ b/40-abschlusspraesentation/assets/fontawesome/css/regular.css
@@ -0,0 +1,19 @@
+/*!
+ * Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com
+ * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
+ * Copyright 2023 Fonticons, Inc.
+ */
+:root, :host {
+ --fa-style-family-classic: 'Font Awesome 6 Free';
+ --fa-font-regular: normal 400 1em/1 'Font Awesome 6 Free'; }
+
+@font-face {
+ font-family: 'Font Awesome 6 Free';
+ font-style: normal;
+ font-weight: 400;
+ font-display: block;
+ src: url("../webfonts/fa-regular-400.woff2") format("woff2"), url("../webfonts/fa-regular-400.ttf") format("truetype"); }
+
+.far,
+.fa-regular {
+ font-weight: 400; }
diff --git a/40-abschlusspraesentation/assets/fontawesome/css/regular.min.css b/40-abschlusspraesentation/assets/fontawesome/css/regular.min.css
new file mode 100644
index 0000000..f3a35c2
--- /dev/null
+++ b/40-abschlusspraesentation/assets/fontawesome/css/regular.min.css
@@ -0,0 +1,6 @@
+/*!
+ * Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com
+ * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
+ * Copyright 2023 Fonticons, Inc.
+ */
+:host,:root{--fa-style-family-classic:"Font Awesome 6 Free";--fa-font-regular:normal 400 1em/1 "Font Awesome 6 Free"}@font-face{font-family:"Font Awesome 6 Free";font-style:normal;font-weight:400;font-display:block;src:url(../webfonts/fa-regular-400.woff2) format("woff2"),url(../webfonts/fa-regular-400.ttf) format("truetype")}.fa-regular,.far{font-weight:400} \ No newline at end of file
diff --git a/40-abschlusspraesentation/assets/fontawesome/css/solid.css b/40-abschlusspraesentation/assets/fontawesome/css/solid.css
new file mode 100644
index 0000000..f2dc866
--- /dev/null
+++ b/40-abschlusspraesentation/assets/fontawesome/css/solid.css
@@ -0,0 +1,19 @@
+/*!
+ * Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com
+ * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
+ * Copyright 2023 Fonticons, Inc.
+ */
+:root, :host {
+ --fa-style-family-classic: 'Font Awesome 6 Free';
+ --fa-font-solid: normal 900 1em/1 'Font Awesome 6 Free'; }
+
+@font-face {
+ font-family: 'Font Awesome 6 Free';
+ font-style: normal;
+ font-weight: 900;
+ font-display: block;
+ src: url("../webfonts/fa-solid-900.woff2") format("woff2"), url("../webfonts/fa-solid-900.ttf") format("truetype"); }
+
+.fas,
+.fa-solid {
+ font-weight: 900; }
diff --git a/40-abschlusspraesentation/assets/fontawesome/css/solid.min.css b/40-abschlusspraesentation/assets/fontawesome/css/solid.min.css
new file mode 100644
index 0000000..8d69ffe
--- /dev/null
+++ b/40-abschlusspraesentation/assets/fontawesome/css/solid.min.css
@@ -0,0 +1,6 @@
+/*!
+ * Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com
+ * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
+ * Copyright 2023 Fonticons, Inc.
+ */
+:host,:root{--fa-style-family-classic:"Font Awesome 6 Free";--fa-font-solid:normal 900 1em/1 "Font Awesome 6 Free"}@font-face{font-family:"Font Awesome 6 Free";font-style:normal;font-weight:900;font-display:block;src:url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.ttf) format("truetype")}.fa-solid,.fas{font-weight:900} \ No newline at end of file
diff --git a/40-abschlusspraesentation/assets/fontawesome/webfonts/fa-brands-400.ttf b/40-abschlusspraesentation/assets/fontawesome/webfonts/fa-brands-400.ttf
new file mode 100644
index 0000000..774d51a
--- /dev/null
+++ b/40-abschlusspraesentation/assets/fontawesome/webfonts/fa-brands-400.ttf
Binary files differ
diff --git a/40-abschlusspraesentation/assets/fontawesome/webfonts/fa-brands-400.woff2 b/40-abschlusspraesentation/assets/fontawesome/webfonts/fa-brands-400.woff2
new file mode 100644
index 0000000..71e3185
--- /dev/null
+++ b/40-abschlusspraesentation/assets/fontawesome/webfonts/fa-brands-400.woff2
Binary files differ
diff --git a/40-abschlusspraesentation/assets/fontawesome/webfonts/fa-regular-400.ttf b/40-abschlusspraesentation/assets/fontawesome/webfonts/fa-regular-400.ttf
new file mode 100644
index 0000000..8a9d634
--- /dev/null
+++ b/40-abschlusspraesentation/assets/fontawesome/webfonts/fa-regular-400.ttf
Binary files differ
diff --git a/40-abschlusspraesentation/assets/fontawesome/webfonts/fa-regular-400.woff2 b/40-abschlusspraesentation/assets/fontawesome/webfonts/fa-regular-400.woff2
new file mode 100644
index 0000000..7f02168
--- /dev/null
+++ b/40-abschlusspraesentation/assets/fontawesome/webfonts/fa-regular-400.woff2
Binary files differ
diff --git a/40-abschlusspraesentation/assets/fontawesome/webfonts/fa-solid-900.ttf b/40-abschlusspraesentation/assets/fontawesome/webfonts/fa-solid-900.ttf
new file mode 100644
index 0000000..993dbe1
--- /dev/null
+++ b/40-abschlusspraesentation/assets/fontawesome/webfonts/fa-solid-900.ttf
Binary files differ
diff --git a/40-abschlusspraesentation/assets/fontawesome/webfonts/fa-solid-900.woff2 b/40-abschlusspraesentation/assets/fontawesome/webfonts/fa-solid-900.woff2
new file mode 100644
index 0000000..5c16cd3
--- /dev/null
+++ b/40-abschlusspraesentation/assets/fontawesome/webfonts/fa-solid-900.woff2
Binary files differ
diff --git a/40-abschlusspraesentation/assets/fontawesome/webfonts/fa-v4compatibility.ttf b/40-abschlusspraesentation/assets/fontawesome/webfonts/fa-v4compatibility.ttf
new file mode 100644
index 0000000..ab6ae22
--- /dev/null
+++ b/40-abschlusspraesentation/assets/fontawesome/webfonts/fa-v4compatibility.ttf
Binary files differ
diff --git a/40-abschlusspraesentation/assets/fontawesome/webfonts/fa-v4compatibility.woff2 b/40-abschlusspraesentation/assets/fontawesome/webfonts/fa-v4compatibility.woff2
new file mode 100644
index 0000000..9027e38
--- /dev/null
+++ b/40-abschlusspraesentation/assets/fontawesome/webfonts/fa-v4compatibility.woff2
Binary files differ
diff --git a/40-abschlusspraesentation/assets/gitlab.svg b/40-abschlusspraesentation/assets/gitlab.svg
new file mode 100644
index 0000000..1e6d027
--- /dev/null
+++ b/40-abschlusspraesentation/assets/gitlab.svg
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg width="494px" height="455px" viewBox="0 0 494 455" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
+ <!-- Generator: Sketch 3.2.2 (9983) - http://www.bohemiancoding.com/sketch -->
+ <title>logo</title>
+ <desc>Created with Sketch.</desc>
+ <defs>
+ <path id="path-1" d="M0,1173.3333 L1999.99995,1173.3333 L1999.99995,0 L0,0 L0,1173.3333 L0,1173.3333 Z"/>
+ </defs>
+ <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
+ <g id="gitlab_logo" sketch:type="MSLayerGroup" transform="translate(-359.000000, -360.000000)">
+ <g id="g10" transform="translate(999.999975, 587.666648) scale(1, -1) translate(-999.999975, -587.666648) translate(0.000000, 0.999996)">
+ <g id="g16">
+ <g id="g18-Clipped">
+ <mask id="mask-2" sketch:name="path22" fill="white">
+ <use xlink:href="#path-1"/>
+ </mask>
+ <g id="path22"/>
+ <g id="g18" mask="url(#mask-2)">
+ <g transform="translate(358.666658, 358.666658)">
+ <g id="g44" transform="translate(0.532000, 0.774933)">
+ <path d="M491.999988,194.666662 L464.441322,279.481326 L409.82399,447.578655 C407.014656,456.226655 394.778657,456.226655 391.96799,447.578655 L337.349325,279.481326 L155.982663,279.481326 L101.362664,447.578655 C98.5533309,456.226655 86.3173312,456.226655 83.5066646,447.578655 L28.8893326,279.481326 L1.33199997,194.666662 C-1.18266664,186.930662 1.57199996,178.455996 8.1519998,173.674662 L246.665327,0.385333324 L485.179988,173.674662 C491.759988,178.455996 494.513321,186.930662 491.999988,194.666662" id="path46" fill="#FC6D26" sketch:type="MSShapeGroup"/>
+ </g>
+ <g id="g48" transform="translate(155.197863, 1.160267)">
+ <path d="M91.9999977,0 L91.9999977,0 L182.683995,279.095993 L1.31599997,279.095993 L91.9999977,0 L91.9999977,0 Z" id="path50" fill="#E24329" sketch:type="MSShapeGroup"/>
+ </g>
+ <g id="g52" transform="translate(247.197860, 1.160267)">
+ <g id="path54"/>
+ </g>
+ <g id="g56" transform="translate(28.531199, 1.160800)">
+ <path d="M218.666661,0 L127.982663,279.09466 L0.890666644,279.09466 L218.666661,0 L218.666661,0 Z" id="path58" fill="#FC6D26" sketch:type="MSShapeGroup"/>
+ </g>
+ <g id="g60" transform="translate(247.197860, 1.160800)">
+ <g id="path62"/>
+ </g>
+ <g id="g64" transform="translate(0.088533, 0.255867)">
+ <path d="M29.3333326,279.999993 L29.3333326,279.999993 L1.77466662,195.185328 C-0.738666648,187.449329 2.01466662,178.974662 8.59599979,174.194662 L247.109327,0.905333311 L29.3333326,279.999993 L29.3333326,279.999993 Z" id="path66" fill="#FCA326" sketch:type="MSShapeGroup"/>
+ </g>
+ <g id="g68" transform="translate(247.197860, 1.160267)">
+ <g id="path70"/>
+ </g>
+ <g id="g72" transform="translate(29.421866, 280.255593)">
+ <path d="M0,0 L127.091997,0 L72.4733315,168.097329 C69.6626649,176.746662 57.4266652,176.746662 54.617332,168.097329 L0,0 L0,0 Z" id="path74" fill="#E24329" sketch:type="MSShapeGroup"/>
+ </g>
+ <g id="g76" transform="translate(247.197860, 1.160800)">
+ <path d="M0,0 L90.6839977,279.09466 L217.775995,279.09466 L0,0 L0,0 Z" id="path78" fill="#FC6D26" sketch:type="MSShapeGroup"/>
+ </g>
+ <g id="g80" transform="translate(246.307061, 0.255867)">
+ <path d="M218.666661,279.999993 L218.666661,279.999993 L246.225327,195.185328 C248.73866,187.449329 245.985327,178.974662 239.403994,174.194662 L0.890666644,0.905333311 L218.666661,279.999993 L218.666661,279.999993 Z" id="path82" fill="#FCA326" sketch:type="MSShapeGroup"/>
+ </g>
+ <g id="g84" transform="translate(336.973725, 280.255593)">
+ <path d="M127.999997,0 L0.907999977,0 L55.5266653,168.097329 C58.3373319,176.746662 70.5733316,176.746662 73.3826648,168.097329 L127.999997,0 L127.999997,0 Z" id="path86" fill="#E24329" sketch:type="MSShapeGroup"/>
+ </g>
+ </g>
+ </g>
+ </g>
+ </g>
+ </g>
+ </g>
+ </g>
+</svg> \ No newline at end of file
diff --git a/40-abschlusspraesentation/assets/jmeter.svg b/40-abschlusspraesentation/assets/jmeter.svg
new file mode 100644
index 0000000..86a96b7
--- /dev/null
+++ b/40-abschlusspraesentation/assets/jmeter.svg
@@ -0,0 +1,159 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="260.47894" height="88.297905" id="svg2" version="1.1" inkscape:version="0.48.4 r9939" sodipodi:docname="logo.svg">
+ <title id="title3100">JMeter Logo</title>
+ <defs id="colors">
+ <linearGradient id="Label.foreground" fallback="textText">
+ <stop offset="0" stop-color="#000000"/>
+ <stop offset="1" stop-color="#000000"/>
+ </linearGradient>
+ <linearGradient id="Label.disabledForeground" fallback="textInactiveText Button.disabledText">
+ <stop offset="0" stop-color="#4d4d4d"/>
+ <stop offset="1" stop-color="#4d4d4d"/>
+ </linearGradient>
+ </defs>
+ <defs id="defs4">
+ <linearGradient inkscape:collect="always" xlink:href="#SVGID_1_" id="linearGradient3736" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.4226,-0.9063,0.9063,0.4226,4226.9761,-6584.5938)" x1="-7708.7969" y1="-803.36011" x2="-7633.1528" y2="-714.90741"/>
+ <linearGradient inkscape:collect="always" xlink:href="#SVGID_2_" id="linearGradient3738" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.4226,-0.9063,0.9063,0.4226,4226.9761,-6584.5938)" x1="-8268.6387" y1="-813.12323" x2="-7728.9585" y2="-813.12323"/>
+ <linearGradient inkscape:collect="always" xlink:href="#SVGID_3_" id="linearGradient3740" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.4226,-0.9063,0.9063,0.4226,4226.9761,-6584.5938)" x1="-8203.4922" y1="-758.99402" x2="-7881.895" y2="-758.99402"/>
+ <linearGradient inkscape:collect="always" xlink:href="#SVGID_4_" id="linearGradient3742" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.4226,-0.9063,0.9063,0.4226,4226.9761,-6584.5938)" x1="-8238.3281" y1="-818.15222" x2="-7698.647" y2="-818.15222"/>
+ <linearGradient inkscape:collect="always" xlink:href="#SVGID_5_" id="linearGradient3744" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.4226,-0.9063,0.9063,0.4226,4226.9761,-6584.5938)" x1="-8198.9678" y1="-810.85059" x2="-7915.3501" y2="-810.85059"/>
+ <linearGradient inkscape:collect="always" xlink:href="#SVGID_6_" id="linearGradient3746" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.4226,-0.9063,0.9063,0.4226,4226.9761,-6584.5938)" x1="-8238.3281" y1="-762.29712" x2="-7698.647" y2="-762.29712"/>
+ <linearGradient inkscape:collect="always" xlink:href="#SVGID_7_" id="linearGradient3748" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.4226,-0.9063,0.9063,0.4226,4226.9761,-6584.5938)" x1="-8271.8057" y1="-765.07068" x2="-7732.125" y2="-765.07068"/>
+ <linearGradient inkscape:collect="always" xlink:href="#SVGID_8_" id="linearGradient3750" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.4226,-0.9063,0.9063,0.4226,4226.9761,-6584.5938)" x1="-8238.3281" y1="-745.68481" x2="-7698.647" y2="-745.68481"/>
+ <linearGradient inkscape:collect="always" xlink:href="#SVGID_9_" id="linearGradient3752" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.4226,-0.9063,0.9063,0.4226,4226.9761,-6584.5938)" x1="-8238.3281" y1="-747.58557" x2="-7698.647" y2="-747.58557"/>
+ <linearGradient inkscape:collect="always" xlink:href="#SVGID_10_" id="linearGradient3754" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.4226,-0.9063,0.9063,0.4226,4226.9761,-6584.5938)" x1="-7935.1431" y1="-747.9668" x2="-7815.856" y2="-747.9668"/>
+ <linearGradient inkscape:collect="always" xlink:href="#SVGID_5_" id="linearGradient9387" x1="580.10394" y1="215.96693" x2="634.46875" y2="215.96693" gradientUnits="userSpaceOnUse"/>
+ <linearGradient inkscape:collect="always" xlink:href="#SVGID_5_" id="linearGradient9389" x1="496.00687" y1="216.75172" x2="574.69977" y2="216.75172" gradientUnits="userSpaceOnUse"/>
+ <linearGradient inkscape:collect="always" xlink:href="#SVGID_5_" id="linearGradient9391" x1="433.14154" y1="208.23689" x2="491.82263" y2="208.23689" gradientUnits="userSpaceOnUse"/>
+ <linearGradient inkscape:collect="always" xlink:href="#SVGID_5_" id="linearGradient9393" x1="351.91241" y1="216.75172" x2="430.60532" y2="216.75172" gradientUnits="userSpaceOnUse"/>
+ <linearGradient inkscape:collect="always" xlink:href="#SVGID_5_" id="linearGradient9395" x1="225.43741" y1="203.29279" x2="344.31088" y2="203.29279" gradientUnits="userSpaceOnUse"/>
+ </defs>
+ <sodipodi:namedview id="base" pagecolor="#ffffff" bordercolor="#666666" borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="0.49497475" inkscape:cx="-887.52247" inkscape:cy="148.89888" inkscape:document-units="px" inkscape:current-layer="layer1" showgrid="false" showguides="true" inkscape:guide-bbox="true" inkscape:window-width="1366" inkscape:window-height="713" inkscape:window-x="0" inkscape:window-y="27" inkscape:window-maximized="1" fit-margin-top="0" fit-margin-left="0" fit-margin-right="0" fit-margin-bottom="0"/>
+ <metadata id="metadata7">
+ <rdf:RDF>
+ <cc:Work rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
+ <dc:title>JMeter Logo</dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g inkscape:label="Ebene 1" inkscape:groupmode="layer" id="layer1" transform="translate(-433.58814,-211.85279)">
+ <g id="g3347" transform="matrix(0.61056696,0,0,0.61056696,-671.81995,122.75139)"/>
+ <g id="g3349" transform="matrix(0.61056696,0,0,0.61056696,-671.81995,122.75139)"/>
+ <g id="g3351" transform="matrix(0.61056696,0,0,0.61056696,-671.81995,122.75139)"/>
+ <g id="g3353" transform="matrix(0.61056696,0,0,0.61056696,-671.81995,122.75139)"/>
+ <g id="g3355" transform="matrix(0.61056696,0,0,0.61056696,-671.81995,122.75139)"/>
+ <g id="g3357" transform="matrix(0.61056696,0,0,0.61056696,-671.81995,122.75139)"/>
+ <g id="g3203" transform="matrix(0.16486497,0,0,0.16486497,427.12543,209.04631)">
+ <linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="-7708.7969" y1="-803.36011" x2="-7633.1528" y2="-714.90741" gradientTransform="matrix(0.4226,-0.9063,0.9063,0.4226,4226.9761,-6584.5938)">
+ <stop offset="0" style="stop-color:#F69923" id="stop3206"/>
+ <stop offset="0.3123" style="stop-color:#F79A23" id="stop3208"/>
+ <stop offset="0.8383" style="stop-color:#E97826" id="stop3210"/>
+ </linearGradient>
+ <path style="fill:url(#linearGradient3736)" inkscape:connector-curvature="0" d="m 267.1,19.6 c -8.4,5 -22.4,19 -39,39.3 l 15.3,28.9 c 10.7,-15.4 21.7,-29.2 32.7,-41 0.8,-0.9 1.3,-1.4 1.3,-1.4 -0.4,0.5 -0.9,0.9 -1.3,1.4 -3.6,3.9 -14.4,16.5 -30.7,41.6 15.7,-0.8 39.8,-4 59.5,-7.4 5.9,-32.8 -5.7,-47.8 -5.7,-47.8 0,0 -14.8,-23.9 -32.1,-13.6 z" id="path3212"/>
+ <path style="fill:none" inkscape:connector-curvature="0" d="m 241.1,184.4 c 0.1,0 0.2,0 0.3,-0.1 l -2.2,0.2 c -0.1,0.1 -0.3,0.1 -0.4,0.2 0.8,-0.1 1.6,-0.2 2.3,-0.3 z" id="path3214"/>
+ <path style="fill:none" inkscape:connector-curvature="0" d="m 225.5,236.1 c -1.2,0.3 -2.5,0.5 -3.8,0.7 1.3,-0.2 2.6,-0.4 3.8,-0.7 z" id="path3216"/>
+ <path style="fill:none" inkscape:connector-curvature="0" d="m 119.3,352.2 c 0.2,-0.4 0.3,-0.9 0.5,-1.3 3.4,-8.9 6.7,-17.5 10,-26 3.7,-9.4 7.4,-18.6 11,-27.5 3.8,-9.3 7.6,-18.4 11.3,-27.1 3.9,-9.2 7.7,-18 11.5,-26.5 3.1,-6.9 6.1,-13.6 9.1,-20.1 1,-2.2 2,-4.3 3,-6.4 2,-4.2 3.9,-8.3 5.8,-12.3 1.8,-3.7 3.5,-7.3 5.2,-10.9 0.6,-1.2 1.2,-2.4 1.7,-3.5 0.1,-0.2 0.2,-0.4 0.3,-0.6 l -1.9,0.2 -1.5,-2.9 c -0.1,0.3 -0.3,0.6 -0.4,0.9 -2.7,5.3 -5.4,10.7 -8,16.2 -1.5,3.1 -3,6.3 -4.6,9.5 -4.2,8.8 -8.3,17.6 -12.3,26.6 -4.1,9 -8.1,18.1 -12,27.1 -3.9,8.9 -7.6,17.8 -11.3,26.7 -3.7,8.9 -7.3,17.7 -10.8,26.5 -3.7,9.2 -7.3,18.3 -10.7,27.3 -0.8,2 -1.6,4.1 -2.3,6.1 -2.8,7.3 -5.5,14.4 -8.1,21.5 l 2.4,4.7 2.1,-0.2 c 0.1,-0.2 0.2,-0.4 0.2,-0.6 3.1,-9.5 6.5,-18.6 9.8,-27.4 z" id="path3218"/>
+ <path style="fill:none" inkscape:connector-curvature="0" d="m 220.7,236.9 0,0 c 0,0 0,0 0,0 0,0 0,0 0,0 z" id="path3220"/>
+ <path style="fill:#be202e" inkscape:connector-curvature="0" d="m 215.6,262.2 c -2,0.4 -4,0.7 -6,1 0,0 0,0 0,0 1,-0.1 2.1,-0.3 3.1,-0.5 1,-0.1 2,-0.3 2.9,-0.5 z" id="path3222"/>
+ <path style="opacity:0.35;fill:#be202e" inkscape:connector-curvature="0" d="m 215.6,262.2 c -2,0.4 -4,0.7 -6,1 0,0 0,0 0,0 1,-0.1 2.1,-0.3 3.1,-0.5 1,-0.1 2,-0.3 2.9,-0.5 z" id="path3224"/>
+ <path style="fill:#be202e" inkscape:connector-curvature="0" d="m 220.8,236.9 c 0,0 0,0 0,0 -0.1,0 -0.1,0 0,0 0.3,0 0.6,-0.1 0.9,-0.1 1.3,-0.2 2.6,-0.4 3.8,-0.7 -1.5,0.3 -3.1,0.5 -4.7,0.8 l 0,0 0,0 z" id="path3226"/>
+ <path style="opacity:0.35;fill:#be202e" inkscape:connector-curvature="0" d="m 220.8,236.9 c 0,0 0,0 0,0 -0.1,0 -0.1,0 0,0 0.3,0 0.6,-0.1 0.9,-0.1 1.3,-0.2 2.6,-0.4 3.8,-0.7 -1.5,0.3 -3.1,0.5 -4.7,0.8 l 0,0 0,0 z" id="path3228"/>
+ <linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="-8268.6387" y1="-813.12323" x2="-7728.9585" y2="-813.12323" gradientTransform="matrix(0.4226,-0.9063,0.9063,0.4226,4226.9761,-6584.5938)">
+ <stop offset="0.3233" style="stop-color:#9E2064" id="stop3231"/>
+ <stop offset="0.6302" style="stop-color:#C92037" id="stop3233"/>
+ <stop offset="0.7514" style="stop-color:#CD2335" id="stop3235"/>
+ <stop offset="1" style="stop-color:#E97826" id="stop3237"/>
+ </linearGradient>
+ <path style="fill:url(#linearGradient3738)" inkscape:connector-curvature="0" d="m 198.2,162.4 c 4.7,-8.7 9.4,-17.2 14.1,-25.5 4.9,-8.6 9.9,-16.9 15,-25 0.3,-0.5 0.6,-1 0.9,-1.4 5,-7.9 10,-15.5 15.1,-22.8 L 228,58.9 c -1.1,1.4 -2.3,2.8 -3.5,4.3 -4.4,5.5 -9,11.4 -13.7,17.7 -5.3,7.1 -10.7,14.6 -16.3,22.5 -5.1,7.3 -10.3,15 -15.5,22.9 -4.4,6.8 -8.8,13.7 -13.2,20.8 -0.2,0.3 -0.3,0.5 -0.5,0.8 l 19.9,39.3 c 4.4,-8.3 8.7,-16.6 13,-24.8 z" id="path3239"/>
+ <linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="-8203.4922" y1="-758.99402" x2="-7881.895" y2="-758.99402" gradientTransform="matrix(0.4226,-0.9063,0.9063,0.4226,4226.9761,-6584.5938)">
+ <stop offset="0" style="stop-color:#282662" id="stop3242"/>
+ <stop offset="9.548390e-02" style="stop-color:#662E8D" id="stop3244"/>
+ <stop offset="0.7882" style="stop-color:#9F2064" id="stop3246"/>
+ <stop offset="0.9487" style="stop-color:#CD2032" id="stop3248"/>
+ </linearGradient>
+ <path style="fill:url(#linearGradient3740)" inkscape:connector-curvature="0" d="m 107.5,384.1 c -2.6,7.2 -5.3,14.6 -7.9,22.2 0,0.1 -0.1,0.2 -0.1,0.3 -0.4,1.1 -0.8,2.1 -1.1,3.2 -1.8,5.1 -3.3,9.7 -6.9,20.1 5.9,2.7 10.6,9.7 15,17.7 -0.5,-8.3 -3.9,-16.1 -10.4,-22.1 28.9,1.3 53.9,-6 66.7,-27.2 1.1,-1.9 2.2,-3.9 3.2,-6 -5.9,7.4 -13.1,10.6 -26.8,9.8 0,0 -0.1,0 -0.1,0 0,0 0.1,0 0.1,0 20.1,-9 30.2,-17.7 39.1,-32 2.1,-3.4 4.2,-7.1 6.3,-11.2 -17.6,18.1 -38,23.2 -59.5,19.3 L 109,380 c -0.5,1.4 -1,2.7 -1.5,4.1 z" id="path3250"/>
+ <linearGradient id="SVGID_4_" gradientUnits="userSpaceOnUse" x1="-8238.3281" y1="-818.15222" x2="-7698.647" y2="-818.15222" gradientTransform="matrix(0.4226,-0.9063,0.9063,0.4226,4226.9761,-6584.5938)">
+ <stop offset="0.3233" style="stop-color:#9E2064" id="stop3253"/>
+ <stop offset="0.6302" style="stop-color:#C92037" id="stop3255"/>
+ <stop offset="0.7514" style="stop-color:#CD2335" id="stop3257"/>
+ <stop offset="1" style="stop-color:#E97826" id="stop3259"/>
+ </linearGradient>
+ <path style="fill:url(#linearGradient3742)" inkscape:connector-curvature="0" d="m 115,348 c 3.5,-9 7.1,-18.1 10.7,-27.3 3.5,-8.8 7.1,-17.6 10.8,-26.5 3.7,-8.9 7.5,-17.8 11.3,-26.7 3.9,-9.1 7.9,-18.1 12,-27.1 4,-8.9 8.2,-17.8 12.3,-26.6 1.5,-3.2 3,-6.3 4.6,-9.5 2.6,-5.4 5.3,-10.8 8,-16.2 0.1,-0.3 0.3,-0.6 0.4,-0.9 L 165.4,148 c -0.3,0.5 -0.6,1.1 -1,1.6 -4.6,7.6 -9.3,15.3 -13.8,23.2 -4.6,8 -9.1,16.1 -13.5,24.4 -3.7,7 -7.3,14 -10.9,21.1 -0.7,1.4 -1.4,2.9 -2.1,4.3 -4.3,8.9 -8.3,17.6 -11.8,25.9 -4,9.4 -7.5,18.4 -10.6,26.9 -2,5.6 -3.9,11 -5.6,16.2 -1.4,4.4 -2.7,8.9 -4,13.3 -3,10.4 -5.5,20.8 -7.6,31.2 l 20,39.5 c 2.6,-7.1 5.4,-14.2 8.1,-21.5 0.8,-2 1.6,-4 2.4,-6.1 z" id="path3261"/>
+ <linearGradient id="SVGID_5_" gradientUnits="userSpaceOnUse" x1="-8198.9678" y1="-810.85059" x2="-7915.3501" y2="-810.85059" gradientTransform="matrix(0.4226,-0.9063,0.9063,0.4226,4226.9761,-6584.5938)">
+ <stop offset="0" style="stop-color:#282662" id="stop3264"/>
+ <stop offset="9.548390e-02" style="stop-color:#662E8D" id="stop3266"/>
+ <stop offset="0.7882" style="stop-color:#9F2064" id="stop3268"/>
+ <stop offset="0.9487" style="stop-color:#CD2032" id="stop3270"/>
+ </linearGradient>
+ <path style="fill:url(#linearGradient3744)" inkscape:connector-curvature="0" d="m 84.2,337.5 c -2.5,12.6 -4.3,25.2 -5.2,37.8 0,0.4 -0.1,0.9 -0.1,1.3 -6.2,-10 -23,-19.8 -22.9,-19.7 12,17.4 21.1,34.6 22.4,51.5 -6.4,1.3 -15.2,-0.6 -25.3,-4.3 10.6,9.7 18.5,12.4 21.6,13.1 -9.7,0.6 -19.8,7.3 -30,15 14.9,-6.1 27,-8.5 35.6,-6.5 -13.7,38.7 -27.4,81.5 -41.1,126.9 4.2,-1.2 6.7,-4.1 8.1,-7.9 2.4,-8.2 18.7,-62.2 44.1,-133.1 0.7,-2 1.5,-4 2.2,-6.1 0.2,-0.6 0.4,-1.1 0.6,-1.7 2.7,-7.4 5.5,-15 8.4,-22.8 0.7,-1.8 1.3,-3.5 2,-5.3 0,0 0,-0.1 0,-0.1 l -20,-39.5 c -0.2,0.5 -0.3,0.9 -0.4,1.4 z" id="path3272"/>
+ <linearGradient id="SVGID_6_" gradientUnits="userSpaceOnUse" x1="-8238.3281" y1="-762.29712" x2="-7698.647" y2="-762.29712" gradientTransform="matrix(0.4226,-0.9063,0.9063,0.4226,4226.9761,-6584.5938)">
+ <stop offset="0.3233" style="stop-color:#9E2064" id="stop3275"/>
+ <stop offset="0.6302" style="stop-color:#C92037" id="stop3277"/>
+ <stop offset="0.7514" style="stop-color:#CD2335" id="stop3279"/>
+ <stop offset="1" style="stop-color:#E97826" id="stop3281"/>
+ </linearGradient>
+ <path style="fill:url(#linearGradient3746)" inkscape:connector-curvature="0" d="m 188.4,190.6 c -0.6,1.2 -1.1,2.3 -1.7,3.5 -1.7,3.6 -3.5,7.2 -5.2,10.9 -1.9,4 -3.8,8.1 -5.8,12.3 -1,2.1 -2,4.2 -3,6.4 -3,6.5 -6,13.2 -9.1,20.1 -3.8,8.5 -7.6,17.3 -11.5,26.5 -3.7,8.7 -7.5,17.8 -11.3,27.1 -3.6,8.9 -7.3,18 -11,27.5 -3.3,8.4 -6.6,17.1 -10,26 -0.2,0.4 -0.3,0.9 -0.5,1.3 -3.3,8.8 -6.7,17.9 -10.1,27.2 -0.1,0.2 -0.2,0.4 -0.2,0.6 l 16.1,-1.8 c -0.3,-0.1 -0.6,-0.1 -1,-0.2 19.3,-2.4 44.9,-16.8 61.4,-34.6 7.6,-8.2 14.5,-17.8 20.9,-29.1 4.8,-8.4 9.2,-17.7 13.5,-28.1 3.7,-9 7.3,-18.8 10.7,-29.4 -4.4,2.3 -9.5,4 -15.1,5.2 -1,0.2 -2,0.4 -3,0.6 -1,0.2 -2,0.3 -3.1,0.5 l 0,0 0,0 c 0,0 0,0 0,0 18,-6.9 29.3,-20.2 37.5,-36.6 -4.7,3.2 -12.4,7.4 -21.6,9.5 -1.2,0.3 -2.5,0.5 -3.8,0.7 -0.3,0 -0.6,0.1 -1,0.1 l 0,0 0,0 c 0,0 0,0 0,0 0,0 0,0 0,0 l 0,0 c 6.2,-2.6 11.5,-5.5 16.1,-9 1,-0.7 1.9,-1.5 2.8,-2.3 1.4,-1.2 2.7,-2.5 4,-3.8 0.8,-0.9 1.6,-1.7 2.4,-2.6 1.8,-2.1 3.5,-4.4 5,-6.9 0.5,-0.8 1,-1.5 1.4,-2.3 0.6,-1.2 1.2,-2.3 1.7,-3.4 2.5,-5 4.5,-9.5 6.1,-13.5 0.8,-2 1.5,-3.8 2.1,-5.5 0.2,-0.7 0.5,-1.3 0.7,-2 0.6,-1.9 1.2,-3.6 1.6,-5.1 0.6,-2.2 1,-4 1.2,-5.3 l 0,0 0,0 c -0.6,0.5 -1.3,1 -2.1,1.4 -5.4,3.2 -14.7,6.2 -22.2,7.6 l 14.8,-1.6 -14.8,1.6 c -0.1,0 -0.2,0 -0.3,0.1 -0.7,0.1 -1.5,0.2 -2.3,0.4 0.1,-0.1 0.3,-0.1 0.4,-0.2 l -50.6,5.5 c 0.1,0.4 0,0.6 -0.1,0.7 z" id="path3283"/>
+ <linearGradient id="SVGID_7_" gradientUnits="userSpaceOnUse" x1="-8271.8057" y1="-765.07068" x2="-7732.125" y2="-765.07068" gradientTransform="matrix(0.4226,-0.9063,0.9063,0.4226,4226.9761,-6584.5938)">
+ <stop offset="0.3233" style="stop-color:#9E2064" id="stop3286"/>
+ <stop offset="0.6302" style="stop-color:#C92037" id="stop3288"/>
+ <stop offset="0.7514" style="stop-color:#CD2335" id="stop3290"/>
+ <stop offset="1" style="stop-color:#E97826" id="stop3292"/>
+ </linearGradient>
+ <path style="fill:url(#linearGradient3748)" inkscape:connector-curvature="0" d="m 245.4,88.4 c -4.5,6.9 -9.4,14.8 -14.7,23.6 -0.3,0.5 -0.6,0.9 -0.8,1.4 -4.6,7.7 -9.4,16.1 -14.5,25.4 -4.4,8 -9,16.5 -13.8,25.8 -4.2,8 -8.4,16.5 -12.9,25.5 l 50.6,-5.5 c 14.7,-6.8 21.3,-12.9 27.7,-21.8 1.7,-2.4 3.4,-5 5.1,-7.7 5.2,-8.1 10.3,-17 14.8,-25.9 4.4,-8.6 8.3,-17.1 11.2,-24.7 1.9,-4.9 3.4,-9.4 4.5,-13.4 0.9,-3.5 1.6,-6.8 2.2,-10 -19.6,3.3 -43.7,6.5 -59.4,7.3 z" id="path3294"/>
+ <path style="fill:#be202e" inkscape:connector-curvature="0" d="m 212.7,262.8 c -1,0.2 -2,0.3 -3.1,0.5 l 0,0 c 1,-0.2 2,-0.4 3.1,-0.5 z" id="path3296"/>
+ <path style="opacity:0.35;fill:#be202e" inkscape:connector-curvature="0" d="m 212.7,262.8 c -1,0.2 -2,0.3 -3.1,0.5 l 0,0 c 1,-0.2 2,-0.4 3.1,-0.5 z" id="path3298"/>
+ <linearGradient id="SVGID_8_" gradientUnits="userSpaceOnUse" x1="-8238.3281" y1="-745.68481" x2="-7698.647" y2="-745.68481" gradientTransform="matrix(0.4226,-0.9063,0.9063,0.4226,4226.9761,-6584.5938)">
+ <stop offset="0.3233" style="stop-color:#9E2064" id="stop3301"/>
+ <stop offset="0.6302" style="stop-color:#C92037" id="stop3303"/>
+ <stop offset="0.7514" style="stop-color:#CD2335" id="stop3305"/>
+ <stop offset="1" style="stop-color:#E97826" id="stop3307"/>
+ </linearGradient>
+ <path style="fill:url(#linearGradient3750)" inkscape:connector-curvature="0" d="m 212.7,262.8 c -1,0.2 -2,0.3 -3.1,0.5 l 0,0 c 1,-0.2 2,-0.4 3.1,-0.5 z" id="path3309"/>
+ <path style="fill:#be202e" inkscape:connector-curvature="0" d="m 220.7,236.9 c 0.3,0 0.6,-0.1 1,-0.1 -0.3,0 -0.6,0.1 -1,0.1 l 0,0 z" id="path3311"/>
+ <path style="opacity:0.35;fill:#be202e" inkscape:connector-curvature="0" d="m 220.7,236.9 c 0.3,0 0.6,-0.1 1,-0.1 -0.3,0 -0.6,0.1 -1,0.1 l 0,0 z" id="path3313"/>
+ <linearGradient id="SVGID_9_" gradientUnits="userSpaceOnUse" x1="-8238.3281" y1="-747.58557" x2="-7698.647" y2="-747.58557" gradientTransform="matrix(0.4226,-0.9063,0.9063,0.4226,4226.9761,-6584.5938)">
+ <stop offset="0.3233" style="stop-color:#9E2064" id="stop3316"/>
+ <stop offset="0.6302" style="stop-color:#C92037" id="stop3318"/>
+ <stop offset="0.7514" style="stop-color:#CD2335" id="stop3320"/>
+ <stop offset="1" style="stop-color:#E97826" id="stop3322"/>
+ </linearGradient>
+ <path style="fill:url(#linearGradient3752)" inkscape:connector-curvature="0" d="m 220.7,236.9 c 0.3,0 0.6,-0.1 1,-0.1 -0.3,0 -0.6,0.1 -1,0.1 l 0,0 z" id="path3324"/>
+ <path style="fill:#be202e" inkscape:connector-curvature="0" d="m 220.8,236.9 c 0,0 0,0 0,0 l 0,0 0,0 0,0 c 0,0 0,0 0,0 z" id="path3326"/>
+ <path style="opacity:0.35;fill:#be202e" inkscape:connector-curvature="0" d="m 220.8,236.9 c 0,0 0,0 0,0 l 0,0 0,0 0,0 c 0,0 0,0 0,0 z" id="path3328"/>
+ <linearGradient id="SVGID_10_" gradientUnits="userSpaceOnUse" x1="-7935.1431" y1="-747.9668" x2="-7815.856" y2="-747.9668" gradientTransform="matrix(0.4226,-0.9063,0.9063,0.4226,4226.9761,-6584.5938)">
+ <stop offset="0.3233" style="stop-color:#9E2064" id="stop3331"/>
+ <stop offset="0.6302" style="stop-color:#C92037" id="stop3333"/>
+ <stop offset="0.7514" style="stop-color:#CD2335" id="stop3335"/>
+ <stop offset="1" style="stop-color:#E97826" id="stop3337"/>
+ </linearGradient>
+ <path style="fill:url(#linearGradient3754)" inkscape:connector-curvature="0" d="m 220.8,236.9 c 0,0 0,0 0,0 l 0,0 0,0 0,0 c 0,0 0,0 0,0 z" id="path3339"/>
+ </g>
+ <path id="path3343" d="m 467.34728,239.32927 v 1.20513 h -0.33894 v -1.20513 h -0.42681 v -0.28873 h 1.18002 v 0.28873 h -0.41427 z" inkscape:connector-curvature="0" style="fill:#b0afb0"/>
+ <path id="path3345" d="m 469.34328,239.59289 -0.40171,0.81597 h -0.20085 l -0.40172,-0.81597 v 0.94151 h -0.32638 v -1.49386 h 0.45192 l 0.38916,0.81597 0.38916,-0.81597 h 0.45192 v 1.49386 h -0.32639 v -0.94151 z" inkscape:connector-curvature="0" style="fill:#b0afb0"/>
+ <path inkscape:connector-curvature="0" id="path3718" style="font-size:160.72227478px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#d22128;fill-opacity:1;stroke:#d22128;stroke-width:1.22876537;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;font-family:Droid Sans;-inkscape-font-specification:Droid Sans Bold" d="m 481.04365,297.79747 c -1.39288,-10e-6 -2.61433,-0.075 -3.66436,-0.225 -1.05002,-0.12859 -1.93932,-0.28931 -2.66792,-0.48216 l 0,-8.29303 c 0.79288,0.17143 1.62861,0.32143 2.5072,0.45001 0.85716,0.12857 1.80004,0.19285 2.82863,0.19286 0.98574,-1e-5 1.89647,-0.10715 2.7322,-0.32144 0.85717,-0.21429 1.59646,-0.5893 2.21791,-1.12502 0.64287,-0.5143 1.13573,-1.21074 1.4786,-2.08933 0.36429,-0.87859 0.54644,-1.98218 0.54644,-3.31079 l 0,-45.6117 9.96451,0 0,45.29027 c -2e-5,2.70006 -0.39646,5.0251 -1.18932,6.97515 -0.77146,1.95003 -1.86433,3.55721 -3.27864,4.82153 -1.39289,1.28573 -3.06436,2.22861 -5.01439,2.82864 -1.95005,0.59999 -4.10367,0.9 -6.46086,0.90001"/>
+ <path fill="url(#Label.foreground)" stroke="url(#Label.foreground)" style="font-size:160.72227478px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill-opacity:1;stroke-width:1.22876537;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;font-family:Droid Sans;-inkscape-font-specification:Droid Sans Bold" d="m 502.3266,236.98674 0,46.98748 8.90855,0 0,-21.86178 c -4e-5,-0.6 -0.017,-1.27231 -0.0384,-2.02235 -1e-5,-0.74999 -0.0211,-1.528 -0.064,-2.34233 -0.0215,-0.81427 -0.0467,-1.63457 -0.0896,-2.47033 -0.0215,-0.8357 -0.0596,-1.65183 -0.10239,-2.44473 -0.0857,-1.84287 -0.19144,-3.74994 -0.31999,-5.72144 l 0.29439,0 10.31651,36.86296 9.15174,0 11.12289,-36.79896 0.25599,0 c -0.0643,1.95007 -0.13192,3.81903 -0.21759,5.61904 -0.0215,0.77148 -0.0596,1.56646 -0.1024,2.38073 -0.0215,0.81433 -0.0426,1.61349 -0.064,2.40633 -0.0215,0.79291 -0.0426,1.54561 -0.064,2.25274 -4e-5,0.70718 -4e-5,1.33722 0,1.89435 l 0,22.24577 9.29254,0 0,-46.98748 -13.56762,0 -10.80289,35.92859 -0.192,0 -10.15011,-35.92859 -13.56762,0 z m 93.29657,3.40471 -2.82872,7.57739 -5.38864,3.2895 0,4.14709 4.68466,0 0,17.31791 c 0,2.31434 0.27482,4.24255 0.83198,5.78544 0.57858,1.52146 1.36939,2.73925 2.35513,3.66069 0.98573,0.90002 2.15706,1.54285 3.50711,1.90715 1.35001,0.36429 2.80034,0.53758 4.36467,0.53758 1.60716,0 3.09143,-0.15215 4.44148,-0.47358 1.37143,-0.30001 2.50883,-0.69333 3.4303,-1.16477 l 0,-7.29579 c -0.90004,0.32144 -1.78376,0.59209 -2.66232,0.80637 -0.85719,0.2143 -1.77484,0.32 -2.73913,0.31999 -1.11432,10e-6 -2.01501,-0.33406 -2.70072,-0.99837 -0.68575,-0.66429 -1.02399,-1.69182 -1.02397,-3.08471 l 0,-17.31791 8.74215,0 0,-7.3598 -8.74215,0 0,-7.65418 -6.27183,0 z m -25.16409,6.9758 c -2.44292,4e-5 -4.66709,0.39753 -6.68141,1.19037 -1.99291,0.7929 -3.70972,1.97258 -5.14546,3.5583 -1.41432,1.56435 -2.52223,3.53067 -3.3151,5.88783 -0.79288,2.35722 -1.19037,5.10572 -1.19037,8.25577 0,3.10722 0.4356,5.82624 1.29277,8.14057 0.87858,2.29291 2.09637,4.19999 3.66069,5.72144 1.56431,1.50004 3.4291,2.61629 5.59344,3.36631 2.16432,0.75001 4.53231,1.12636 7.1038,1.12636 1.32858,0 2.54637,-0.0464 3.6607,-0.15359 1.11429,-0.0857 2.15878,-0.2337 3.12311,-0.44799 0.96428,-0.21429 1.86914,-0.48077 2.72633,-0.78078 0.87856,-0.32143 1.75393,-0.70195 2.61112,-1.15196 l 0,-7.59019 c -0.94291,0.47145 -1.86473,0.89008 -2.76472,1.25436 -0.90005,0.34287 -1.8177,0.63467 -2.73912,0.87038 -0.92148,0.23573 -1.86861,0.42181 -2.85432,0.55038 -0.96433,0.10716 -1.99186,0.15361 -3.08471,0.1536 -1.3072,1e-5 -2.47853,-0.19442 -3.50711,-0.60158 -1.00718,-0.40715 -1.88255,-0.99073 -2.61112,-1.74075 -0.70718,-0.77144 -1.25682,-1.71024 -1.66396,-2.80313 -0.38573,-1.11429 -0.59713,-2.35322 -0.63998,-3.72469 l 21.91299,0 0,-4.76147 c -4e-5,-2.61431 -0.35942,-4.92305 -1.08797,-6.9374 -0.70719,-2.03573 -1.73472,-3.75254 -3.08472,-5.14546 -1.32862,-1.39285 -2.96087,-2.44151 -4.88946,-3.14871 -1.90721,-0.72855 -4.04682,-1.08793 -6.42542,-1.08797 z m 59.01914,0 c -2.44292,4e-5 -4.6671,0.39753 -6.68141,1.19037 -1.99291,0.7929 -3.70972,1.97258 -5.14546,3.5583 -1.41432,1.56435 -2.52223,3.53067 -3.3151,5.88783 -0.79288,2.35722 -1.19037,5.10572 -1.19037,8.25577 0,3.10722 0.4356,5.82624 1.29276,8.14057 0.87859,2.29291 2.09637,4.19999 3.6607,5.72144 1.56431,1.50004 3.4291,2.61629 5.59344,3.36631 2.16432,0.75001 4.5323,1.12636 7.1038,1.12636 1.32858,0 2.54637,-0.0464 3.6607,-0.15359 1.11429,-0.0857 2.15878,-0.2337 3.12311,-0.44799 0.96428,-0.21429 1.86914,-0.48077 2.72633,-0.78078 0.87856,-0.32143 1.75393,-0.70195 2.61112,-1.15196 l 0,-7.59019 c -0.94291,0.47145 -1.86473,0.89008 -2.76472,1.25436 -0.90005,0.34287 -1.8177,0.63467 -2.73912,0.87038 -0.92148,0.23573 -1.86861,0.42181 -2.85432,0.55038 -0.96433,0.10716 -1.99186,0.15361 -3.08471,0.1536 -1.3072,1e-5 -2.47853,-0.19442 -3.50711,-0.60158 -1.00718,-0.40715 -1.86975,-0.99073 -2.59832,-1.74075 -0.70717,-0.77144 -1.26962,-1.71024 -1.67676,-2.80313 -0.38573,-1.11429 -0.59713,-2.35322 -0.63998,-3.72469 l 21.91299,0 0,-4.76147 c -4e-5,-2.61431 -0.35942,-4.92305 -1.08797,-6.9374 -0.7072,-2.03573 -1.73472,-3.75254 -3.08472,-5.14546 -1.32862,-1.39285 -2.96088,-2.44151 -4.88946,-3.14871 -1.90721,-0.72855 -4.04682,-1.08793 -6.42542,-1.08797 z m 36.85016,0 c -1.20004,4e-5 -2.26985,0.14802 -3.21271,0.44799 -0.92147,0.27861 -1.75873,0.68028 -2.50872,1.21597 -0.72861,0.51433 -1.38395,1.15716 -1.98395,1.90714 -0.60003,0.75005 -1.16247,1.57452 -1.67675,2.49593 l -0.48639,0 -1.44636,-5.38865 -7.42379,0 0,35.92859 9.80453,0 0,-18.29068 c -2e-5,-1.69288 0.20721,-3.11789 0.61438,-4.27508 0.42856,-1.17858 1.01631,-2.12154 1.76635,-2.82872 0.77143,-0.72856 1.68908,-1.2529 2.73912,-1.57436 1.07143,-0.32141 2.22997,-0.48636 3.4943,-0.48639 0.21427,5e-5 0.48492,0.017 0.80638,0.0384 0.32141,3e-5 0.63851,0.0212 0.95997,0.064 0.34284,0.0215 0.67274,0.0596 0.97278,0.1024 0.29997,0.0429 0.53251,0.0852 0.70398,0.12799 l 0,-9.20294 c -0.12861,-0.0428 -0.31887,-0.0681 -0.57599,-0.0896 -0.23574,-0.0428 -0.5064,-0.0809 -0.80637,-0.1024 -0.27861,-0.0428 -0.57457,-0.064 -0.89598,-0.064 -0.30003,-0.0214 -0.58765,-0.0256 -0.84478,-0.0256 z m -95.8053,6.97581 c 1.02857,2e-5 1.92926,0.19029 2.70072,0.57598 0.77143,0.38575 1.41843,0.91425 1.93275,1.59995 0.51427,0.66433 0.89479,1.45932 1.15197,2.38074 0.25712,0.92147 0.40092,1.92785 0.42239,3.02071 l -12.50525,0 c 0.17142,-2.61431 0.82259,-4.52556 1.95834,-5.74704 1.15716,-1.22142 2.60331,-1.83032 4.33908,-1.83034 z m 59.01914,0 c 1.02857,2e-5 1.92926,0.19029 2.70072,0.57598 0.77143,0.38575 1.41843,0.91425 1.93275,1.59995 0.51427,0.66433 0.89479,1.45932 1.15197,2.38074 0.25712,0.92147 0.40092,1.92785 0.42238,3.02071 l -12.50524,0 c 0.17142,-2.61431 0.82259,-4.52556 1.95834,-5.74704 1.15715,-1.22142 2.60331,-1.83032 4.33908,-1.83034 z" id="path3720" inkscape:connector-curvature="0"/>
+ <g style="font-size:35.26461411px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#4d4d4d;fill-opacity:1;stroke:none;font-family:sans-serif;-inkscape-font-specification:Sans Bold" id="text3756" transform="matrix(0.40958848,0,0,0.40958848,409.7852,177.21243)">
+ <path d="m 658.02758,171.06244 -5.32069,0 0,-20.73174 -6.31939,0 0,-4.44251 17.94225,0 0,4.44251 -6.30217,0 0,20.73174" fill="url(#Label.disabledForeground)" style="font-family:Droid Sans;-inkscape-font-specification:Droid Sans Bold" id="path3879" inkscape:connector-curvature="0"/>
+ <path d="m 678.32884,171.06244 -5.52732,-19.75025 -0.15497,0 c 0.0689,1.05612 0.12627,2.07778 0.17219,3.06499 0.0229,0.42475 0.0402,0.86097 0.0517,1.30865 0.023,0.44771 0.0402,0.88966 0.0517,1.32586 0.023,0.43623 0.0344,0.85523 0.0344,1.25699 0.0115,0.4018 0.0172,0.76339 0.0172,1.08481 l 0,11.70895 -4.76967,0 0,-25.17425 7.26643,0 5.44122,19.2509 0.10332,0 5.7856,-19.2509 7.26644,0 0,25.17425 -4.97631,0 0,-11.91558 c -2e-5,-0.29845 -2e-5,-0.6371 0,-1.01593 0.0115,-0.3788 0.0229,-0.78058 0.0344,-1.20533 0.0115,-0.42472 0.0229,-0.8552 0.0344,-1.29143 0.0229,-0.4362 0.0401,-0.86094 0.0517,-1.27421 0.0459,-0.96425 0.0861,-1.96869 0.12053,-3.01333 l -0.13775,0 -5.95779,19.71581 -4.90743,0" fill="url(#Label.disabledForeground)" style="font-family:Droid Sans;-inkscape-font-specification:Droid Sans Bold" id="path3881" inkscape:connector-curvature="0"/>
+ </g>
+ <g id="g8126" transform="matrix(0.14276681,0,0,0.14276681,453.68012,190.16516)">
+ <g id="g8128">
+ <path style="fill:#d22128" inkscape:connector-curvature="0" d="m 232.6,277.3 49.3,-117.8 h 9.5 l 49.3,117.8 H 328.3 L 313,240.5 h -53 l -15.1,36.8 h -12.3 z m 54.1,-104.2 -24.2,58.2 h 47.8 l -23.6,-58.2 z" id="path8130"/>
+ <path style="fill:#d22128" inkscape:connector-curvature="0" d="M 353.3,277.3 V 159.5 h 48.8 c 20.2,0 34.8,18.7 34.8,37 0,19.2 -13.6,37.3 -33.8,37.3 h -38.3 v 43.5 h -11.5 z m 11.5,-53.8 h 37.7 c 13.9,0 22.9,-12.8 22.9,-27 0,-14.8 -10.9,-26.7 -23.9,-26.7 h -36.7 v 53.7 z" id="path8132"/>
+ <path style="fill:#d22128" inkscape:connector-curvature="0" d="m 430.5,277.3 49.3,-117.8 h 9.5 l 49.3,117.8 H 526 l -15.3,-36.8 h -52.9 l -15.1,36.8 h -12.2 z m 54.1,-104.2 -24.2,58.2 h 47.8 l -23.6,-58.2 z" id="path8134"/>
+ <path style="fill:#d22128" inkscape:connector-curvature="0" d="m 594.2,158.8 c 20.9,0 36.2,10.6 43.5,25.7 l -9.3,5.6 c -7.5,-15.6 -22.1,-20.9 -34.8,-20.9 -28.2,0 -43.6,25.2 -43.6,48.9 0,26 19.1,49.6 44.1,49.6 13.3,0 28.9,-6.6 36.3,-21.9 l 9.6,5 c -7.6,17.6 -28.5,27.4 -46.6,27.4 -32.3,0 -55.1,-30.9 -55.1,-60.7 0,-28.3 20.4,-58.7 55.9,-58.7 z" id="path8136"/>
+ <path style="fill:#d22128" inkscape:connector-curvature="0" d="m 749.1,159.5 v 117.8 h -11.6 v -55.1 h -69.8 v 55.1 H 656.3 V 159.5 h 11.4 v 52.4 h 69.8 v -52.4 h 11.6 z" id="path8138"/>
+ <path style="fill:#d22128" inkscape:connector-curvature="0" d="m 854.8,267 v 10.3 H 775.7 V 159.5 h 77.6 v 10.3 h -66.2 v 42.5 h 57.7 v 9.8 H 787.1 V 267 h 67.7 z" id="path8140"/>
+ </g>
+ </g>
+ <g id="g8326" transform="translate(132.42046,222.12974)"/>
+ <g id="g8328" transform="translate(132.42046,222.12974)"/>
+ <g id="g8330" transform="translate(132.42046,222.12974)"/>
+ <g id="g8332" transform="translate(132.42046,222.12974)"/>
+ <g id="g8334" transform="translate(132.42046,222.12974)"/>
+ <g id="g8336" transform="translate(132.42046,222.12974)"/>
+ </g>
+</svg> \ No newline at end of file
diff --git a/40-abschlusspraesentation/assets/latex.svg b/40-abschlusspraesentation/assets/latex.svg
new file mode 100644
index 0000000..df40243
--- /dev/null
+++ b/40-abschlusspraesentation/assets/latex.svg
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg height="500" overflow="scroll" width="1200" xmlns="http://www.w3.org/2000/svg">
+ <path d="m5.46 4.23h-.25c-.1 1.02-.24 2.26-2 2.26h-.81c-.47 0-.49-.07-.49-.4v-5.31c0-.34 0-.48.94-.48h.33v-.3c-.36.03-1.26.03-1.67.03-.39 0-1.17 0-1.51-.03v.3h.23c.77 0 .79.11.79.47v5.25c0 .36-.02.47-.79.47h-.23v.31h5.19z" transform="matrix(45 0 0 45 40 47.65)"/>
+ <path d="m2.81.16c-.04-.12-.06-.16-.19-.16s-.16.04-.2.16l-1.61 4.08c-.07.17-.19.48-.81.48v.25h1.55v-.25c-.31 0-.5-.14-.5-.34 0-.05.01-.07.03-.14 0 0 .34-.86.34-.86h1.98l.4 1.02c.02.04.04.09.04.12 0 .2-.38.2-.57.2v.25h1.97v-.25h-.14c-.47 0-.52-.07-.59-.27 0 0-1.7-4.29-1.7-4.29zm-.4.71.89 2.26h-1.78z" transform="matrix(45 0 0 45 151.6 40)"/>
+ <path d="m6.27 0h-6.09s-.18 2.24-.18 2.24h.24c.14-1.61.29-1.94 1.8-1.94.18 0 .44 0 .54.02.21.04.21.15.21.38v5.25c0 .34 0 .48-1.05.48h-.4v.31c.41-.03 1.42-.03 1.88-.03s1.49 0 1.9.03v-.31h-.4c-1.05 0-1.05-.14-1.05-.48v-5.25c0-.2 0-.34.18-.38.11-.02.38-.02.57-.02 1.5 0 1.65.33 1.79 1.94h.25s-.19-2.24-.19-2.24z" transform="matrix(45 0 0 45 356.35 50.35)"/>
+ <path d="m6.16 4.2h-.25c-.25 1.53-.48 2.26-2.19 2.26h-1.32c-.47 0-.49-.07-.49-.4v-2.66h.89c.97 0 1.08.32 1.08 1.17h.25v-2.64h-.25c0 .85-.11 1.16-1.08 1.16h-.89v-2.39c0-.33.02-.4.49-.4h1.28c1.53 0 1.79.55 1.95 1.94h.25l-.28-2.24h-5.6v.3h.23c.77 0 .79.11.79.47v5.22c0 .36-.02.47-.79.47h-.23v.31h5.74z" transform="matrix(45 0 0 45 602.5 150.25)"/>
+ <path d="m3.76 2.95 1.37-2c.21-.32.55-.64 1.44-.65v-.3h-2.38v.3c.4.01.62.23.62.46 0 .1-.02.12-.09.23 0 0-1.14 1.68-1.14 1.68l-1.28-1.92c-.02-.03-.07-.11-.07-.15 0-.12.22-.29.64-.3v-.3c-.34.03-1.07.03-1.45.03-.31 0-.93-.01-1.3-.03v.3h.19c.55 0 .74.07.93.35 0 0 1.83 2.77 1.83 2.77l-1.63 2.41c-.14.2-.44.66-1.44.66v.31h2.38v-.31c-.46-.01-.63-.28-.63-.46 0-.09.03-.13.1-.24l1.41-2.09 1.58 2.38c.02.04.05.08.05.11 0 .12-.22.29-.65.3v.31c.35-.03 1.08-.03 1.45-.03.42 0 .88.01 1.3.03v-.31h-.19c-.52 0-.73-.05-.94-.36 0 0-2.1-3.18-2.1-3.18z" transform="matrix(45 0 0 45 845.95 47.65)"/>
+</svg> \ No newline at end of file
diff --git a/40-abschlusspraesentation/assets/lets-encrypt.svg b/40-abschlusspraesentation/assets/lets-encrypt.svg
new file mode 100644
index 0000000..7b792dc
--- /dev/null
+++ b/40-abschlusspraesentation/assets/lets-encrypt.svg
@@ -0,0 +1 @@
+<svg height="2500" viewBox=".58270974 .25870974 63.77358058 67.21369903" width="2390" xmlns="http://www.w3.org/2000/svg"><g fill="none"><path d="m46.489 36.568h-8.04v-4.128a5.986 5.986 0 0 0 -5.98-5.979 5.986 5.986 0 0 0 -5.979 5.979v4.128h-8.04v-4.128c0-7.73 6.289-14.02 14.02-14.02s14.02 6.289 14.02 14.02v4.128z" fill="#f9a11d"/><path d="m49.732 36.568h-34.525a2.688 2.688 0 0 0 -2.68 2.68v25.54a2.688 2.688 0 0 0 2.68 2.68h34.525a2.688 2.688 0 0 0 2.68-2.68v-25.54a2.688 2.688 0 0 0 -2.68-2.68zm-15.513 16.769v3.461a1.75 1.75 0 0 1 -3.498 0v-3.46a3.552 3.552 0 1 1 3.498-.001z" fill="#2c3c69"/><path d="m11.707 32.76h-8.331a2.446 2.446 0 1 1 0-4.892h8.331a2.446 2.446 0 1 1 0 4.892zm5.868-13.105a2.433 2.433 0 0 1 -1.552-.557l-6.59-5.419a2.446 2.446 0 0 1 3.108-3.779l6.59 5.419a2.446 2.446 0 0 1 -1.556 4.336zm14.894-5.76a2.446 2.446 0 0 1 -2.446-2.446v-8.397a2.446 2.446 0 1 1 4.892 0v8.397a2.446 2.446 0 0 1 -2.446 2.446zm14.894 5.76a2.447 2.447 0 0 1 -1.556-4.336l6.59-5.419a2.447 2.447 0 0 1 3.108 3.779l-6.59 5.419c-.437.36-.986.558-1.552.557zm14.2 13.105h-8.41a2.446 2.446 0 1 1 0-4.892h8.41a2.446 2.446 0 1 1 0 4.892z" fill="#f9a11d"/></g></svg> \ No newline at end of file
diff --git a/40-abschlusspraesentation/assets/logo.png b/40-abschlusspraesentation/assets/logo.png
new file mode 100644
index 0000000..18c090b
--- /dev/null
+++ b/40-abschlusspraesentation/assets/logo.png
Binary files differ
diff --git a/40-abschlusspraesentation/assets/logo.svg b/40-abschlusspraesentation/assets/logo.svg
new file mode 100644
index 0000000..e199f82
--- /dev/null
+++ b/40-abschlusspraesentation/assets/logo.svg
@@ -0,0 +1,234 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ version="1.2"
+ width="91.420494mm"
+ height="52.000076mm"
+ viewBox="0 0 9142.0494 5200.0076"
+ preserveAspectRatio="xMidYMid"
+ fill-rule="evenodd"
+ stroke-width="28.222"
+ stroke-linejoin="round"
+ xml:space="preserve"
+ id="svg206"
+ sodipodi:docname="logo.svg"
+ inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview
+ id="namedview213"
+ pagecolor="#505050"
+ bordercolor="#eeeeee"
+ borderopacity="1"
+ inkscape:showpageshadow="0"
+ inkscape:pageopacity="0"
+ inkscape:pagecheckerboard="0"
+ inkscape:deskcolor="#505050"
+ inkscape:document-units="mm"
+ showgrid="false"
+ inkscape:zoom="1.4318132"
+ inkscape:cx="246.19134"
+ inkscape:cy="111.39721"
+ inkscape:window-width="1246"
+ inkscape:window-height="1059"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="svg206" />
+ <defs
+ class="ClipPathGroup"
+ id="defs8" />
+ <defs
+ id="defs51"><font
+ id="EmbeddedFont_1"
+ horiz-adv-x="2048"
+ horiz-origin-x="0"
+ horiz-origin-y="0"
+ vert-origin-x="512"
+ vert-origin-y="768"
+ vert-adv-y="1024">
+ <font-face
+ font-family="Noto Sans Display Light embedded"
+ units-per-em="2048"
+ font-weight="normal"
+ font-style="normal"
+ ascent="2170"
+ descent="609"
+ id="font-face10" />
+ <missing-glyph
+ horiz-adv-x="2048"
+ d="M 0,0 L 2047,0 2047,2047 0,2047 0,0 Z"
+ id="missing-glyph12" />
+ <glyph
+ unicode="y"
+ horiz-adv-x="927"
+ d="M 2,1089 L 127,1089 367,413 C 388,352 407,298 422,250 437,203 449,161 457,124 L 463,124 C 471,156 483,196 498,246 513,296 530,350 551,409 L 786,1089 913,1089 453,-193 C 418,-290 377,-364 328,-416 279,-468 213,-494 131,-494 107,-494 84,-493 63,-490 43,-487 25,-482 8,-476 L 8,-377 C 23,-383 40,-387 57,-391 75,-394 95,-396 117,-396 170,-396 214,-378 249,-342 284,-307 314,-252 340,-179 L 403,4 2,1089 Z"
+ id="glyph14" />
+ <glyph
+ unicode="t"
+ horiz-adv-x="610"
+ d="M 465,80 C 494,80 521,82 547,87 573,91 595,97 614,105 L 614,11 C 594,3 569,-5 541,-11 512,-17 481,-20 449,-20 363,-20 296,5 249,56 202,106 178,189 178,304 L 178,996 27,996 27,1061 178,1100 219,1350 295,1350 295,1090 608,1090 608,996 295,996 295,310 C 295,157 352,80 465,80 Z"
+ id="glyph16" />
+ <glyph
+ unicode="s"
+ horiz-adv-x="742"
+ d="M 817,289 C 817,191 782,115 713,61 643,7 545,-20 418,-20 347,-20 284,-14 228,-1 173,12 126,29 88,50 L 88,162 C 134,138 186,118 244,102 301,86 360,78 420,78 520,78 592,96 636,133 680,169 702,218 702,281 702,341 679,387 632,419 585,451 515,484 422,519 359,542 303,565 255,589 207,613 169,643 142,680 116,717 102,768 102,832 102,919 136,987 204,1037 271,1086 361,1110 473,1110 535,1110 592,1104 646,1092 700,1080 750,1063 795,1043 L 754,946 C 713,964 667,980 617,993 568,1006 518,1012 469,1012 388,1012 326,997 283,967 239,937 217,893 217,836 217,792 228,758 249,733 270,707 301,686 342,668 383,650 433,630 492,609 553,585 608,562 657,537 707,512 745,481 774,443 803,405 817,353 817,289 Z"
+ id="glyph18" />
+ <glyph
+ unicode="r"
+ horiz-adv-x="583"
+ d="M 596,1108 C 646,1108 692,1102 733,1091 L 717,983 C 674,995 632,1001 590,1001 497,1001 423,964 368,890 312,817 285,719 285,598 L 285,-1 168,-1 168,1089 266,1089 279,886 285,886 C 311,948 350,1000 402,1043 455,1086 520,1108 596,1108 Z"
+ id="glyph20" />
+ <glyph
+ unicode="o"
+ horiz-adv-x="927"
+ d="M 1030,547 C 1030,433 1012,333 976,248 940,164 887,98 818,51 749,4 665,-20 565,-20 471,-20 390,3 322,50 253,96 201,162 164,247 127,333 109,433 109,547 109,723 150,861 232,961 315,1061 429,1110 575,1110 672,1110 755,1087 822,1040 890,993 941,927 977,842 1012,757 1030,659 1030,547 Z M 229,547 C 229,407 257,294 312,208 368,123 453,80 567,80 685,80 771,123 826,209 882,295 909,408 909,547 909,637 898,717 875,787 851,856 815,911 766,951 717,990 653,1010 573,1010 459,1010 373,969 315,887 258,805 229,692 229,547 Z"
+ id="glyph22" />
+ <glyph
+ unicode="n"
+ horiz-adv-x="847"
+ d="M 633,1110 C 749,1110 838,1078 900,1014 962,950 993,850 993,713 L 993,1 877,1 877,705 C 877,809 854,885 810,935 766,985 701,1010 616,1010 395,1010 285,871 285,594 L 285,1 168,1 168,1090 262,1090 279,901 287,901 C 314,962 357,1011 416,1051 474,1091 547,1110 633,1110 Z"
+ id="glyph24" />
+ <glyph
+ unicode="m"
+ horiz-adv-x="1430"
+ d="M 1245,1110 C 1348,1110 1427,1080 1485,1018 1542,957 1571,860 1571,727 L 1571,1 1454,1 1454,723 C 1454,820 1434,892 1393,939 1352,986 1296,1010 1227,1010 1130,1010 1056,980 1005,919 953,858 928,764 928,637 L 928,1 811,1 811,723 C 811,820 791,892 750,939 709,986 653,1010 584,1010 487,1010 413,978 361,914 310,850 285,751 285,619 L 285,1 168,1 168,1090 262,1090 279,918 287,918 C 313,971 352,1016 403,1054 455,1092 521,1110 600,1110 675,1110 739,1093 791,1059 842,1025 879,975 899,908 L 907,908 C 936,972 980,1022 1038,1057 1097,1093 1166,1110 1245,1110 Z"
+ id="glyph26" />
+ <glyph
+ unicode="i"
+ horiz-adv-x="187"
+ d="M 227,1493 C 279,1493 305,1464 305,1405 305,1345 279,1315 227,1315 175,1315 150,1345 150,1405 150,1464 175,1493 227,1493 Z M 285,1090 L 285,0 168,0 168,1090 285,1090 Z"
+ id="glyph28" />
+ <glyph
+ unicode="h"
+ horiz-adv-x="847"
+ d="M 285,1059 C 285,1031 284,1003 283,977 281,951 279,926 276,901 L 285,901 C 312,962 355,1011 413,1051 471,1091 543,1110 629,1110 746,1110 836,1078 899,1014 962,950 993,850 993,713 L 993,1 877,1 877,705 C 877,809 854,885 810,935 766,985 701,1010 616,1010 395,1010 285,871 285,594 L 285,1 168,1 168,1557 285,1557 285,1059 Z"
+ id="glyph30" />
+ <glyph
+ unicode="f"
+ horiz-adv-x="689"
+ d="M 575,995 L 332,995 332,-1 213,-1 213,995 27,995 27,1058 213,1093 213,1202 C 213,1445 316,1566 522,1566 559,1566 593,1563 623,1557 653,1551 680,1544 705,1536 L 678,1439 C 655,1448 630,1454 603,1460 577,1465 550,1468 524,1468 456,1468 407,1447 377,1405 347,1362 332,1295 332,1202 L 332,1089 575,1089 575,995 Z"
+ id="glyph32" />
+ <glyph
+ unicode="e"
+ horiz-adv-x="874"
+ d="M 559,1110 C 646,1110 720,1089 779,1046 839,1003 883,944 913,869 943,794 958,708 958,611 L 958,531 229,531 C 231,386 262,275 325,198 387,121 476,82 592,82 656,82 712,88 759,100 806,111 858,130 915,156 L 915,50 C 865,25 814,7 764,-4 713,-15 655,-20 588,-20 434,-20 315,30 232,129 150,229 109,365 109,537 109,648 126,746 162,832 197,918 249,986 315,1036 382,1085 464,1110 559,1110 Z M 559,1012 C 465,1012 389,979 333,912 276,845 243,750 233,627 L 838,627 C 838,742 815,835 769,906 723,977 653,1012 559,1012 Z"
+ id="glyph34" />
+ <glyph
+ unicode="d"
+ horiz-adv-x="900"
+ d="M 535,-20 C 398,-20 293,27 219,120 145,214 109,352 109,535 109,722 147,865 224,963 301,1061 408,1110 545,1110 629,1110 698,1090 752,1050 805,1010 845,961 872,904 L 881,904 C 879,935 878,970 876,1009 873,1048 872,1084 872,1117 L 872,1557 989,1557 989,0 895,0 879,191 872,191 C 845,132 805,82 751,41 697,0 625,-20 535,-20 Z M 553,80 C 669,80 752,119 801,195 850,271 875,382 875,527 L 875,545 C 875,695 850,810 801,890 752,970 671,1010 559,1010 451,1010 369,969 313,886 257,804 229,686 229,533 229,385 256,273 309,196 363,119 444,80 553,80 Z"
+ id="glyph36" />
+ <glyph
+ unicode="c"
+ horiz-adv-x="768"
+ d="M 580,-20 C 429,-20 313,29 231,127 150,226 109,363 109,539 109,662 129,766 170,850 211,935 269,1000 343,1044 417,1088 504,1110 602,1110 651,1110 698,1106 742,1096 787,1087 825,1074 858,1057 L 825,957 C 791,972 754,984 714,993 673,1002 636,1006 600,1006 481,1006 390,964 326,881 261,798 229,685 229,541 229,405 258,294 314,210 371,126 459,84 580,84 630,84 678,90 723,101 768,112 809,125 846,142 L 846,37 C 812,20 773,6 729,-5 685,-15 636,-20 580,-20 Z"
+ id="glyph38" />
+ <glyph
+ unicode="a"
+ horiz-adv-x="822"
+ d="M 535,1108 C 651,1108 737,1078 795,1018 852,958 881,863 881,734 L 881,0 793,0 772,185 766,185 C 729,123 684,74 631,36 578,-1 503,-20 408,-20 311,-20 233,6 176,59 119,111 90,187 90,285 90,394 132,477 215,533 298,589 420,621 580,629 L 764,639 764,715 C 764,822 744,897 705,942 665,987 606,1010 528,1010 477,1010 426,1002 378,987 329,972 281,953 231,928 L 195,1022 C 242,1047 295,1067 352,1084 410,1100 470,1108 535,1108 Z M 594,543 C 466,536 370,512 307,470 244,429 213,367 213,285 213,217 232,165 271,131 310,96 363,78 430,78 535,78 617,111 676,176 735,240 764,330 764,445 L 764,551 594,543 Z"
+ id="glyph40" />
+ <glyph
+ unicode="S"
+ horiz-adv-x="875"
+ d="M 956,381 C 956,294 936,220 894,160 852,100 796,55 724,25 652,-5 571,-20 479,-20 396,-20 324,-14 262,-2 201,11 147,26 102,46 L 102,162 C 152,142 209,124 273,109 338,94 409,87 485,87 589,87 673,110 738,158 803,206 836,278 836,373 836,431 823,478 798,515 772,553 734,586 682,614 630,642 565,670 485,699 410,726 345,757 291,791 236,825 194,868 164,919 134,970 119,1035 119,1112 119,1192 138,1259 176,1314 214,1369 267,1411 333,1440 399,1469 474,1483 559,1483 626,1483 689,1476 750,1463 810,1449 868,1430 924,1405 L 883,1303 C 772,1352 663,1377 555,1377 462,1377 386,1354 328,1310 269,1266 240,1200 240,1114 240,1052 252,1001 278,964 303,926 340,895 389,869 438,843 498,817 567,791 648,762 717,731 775,698 833,664 878,623 909,573 941,523 956,459 956,381 Z"
+ id="glyph42" />
+ <glyph
+ unicode="P"
+ horiz-adv-x="848"
+ d="M 539,1462 C 869,1462 1034,1325 1034,1049 1034,908 992,798 907,718 823,638 690,598 510,598 L 311,598 311,0 193,0 193,1462 539,1462 Z M 528,1358 L 311,1358 311,702 498,702 C 629,702 730,727 803,776 875,825 911,914 911,1043 911,1152 880,1232 818,1282 756,1333 659,1358 528,1358 Z"
+ id="glyph44" />
+ <glyph
+ unicode="E"
+ horiz-adv-x="769"
+ d="M 950,0 L 193,0 193,1462 950,1462 950,1356 311,1356 311,821 913,821 913,715 311,715 311,107 950,107 950,0 Z"
+ id="glyph46" />
+ <glyph
+ unicode=" "
+ horiz-adv-x="503"
+ id="glyph48" />
+ </font></defs>
+ <defs
+ class="TextShapeIndex"
+ id="defs55" />
+ <defs
+ class="EmbeddedBulletChars"
+ id="defs87" />
+
+ <g
+ id="id10"
+ clip-path="none"
+ transform="translate(-693.24341,-2550)">
+
+ <text
+ class="SVGTextShape"
+ id="text151"
+ x="217.60002"
+ y="-56.506969"
+ style="letter-spacing:4.7625px;word-spacing:104.775px"><tspan
+ class="TextParagraph"
+ font-family="'Noto Sans Display Light', sans-serif"
+ font-size="494px"
+ font-weight="400"
+ id="tspan149"><tspan
+ class="TextPosition"
+ x="650.59998"
+ y="7647.4932"
+ id="tspan147"><tspan
+ fill="#808080"
+ stroke="none"
+ style="white-space:pre"
+ id="tspan145"
+ dx="2.1199999">Podcast Synchronisation made Efficient</tspan></tspan></tspan></text>
+ </g><g
+ id="g1277"
+ transform="translate(-693.24341,-2550)"><path
+ id="path131-3"
+ d="m 6694.0006,4763 c -559.5515,4.407 -980.3924,428.0893 -986.038,985.9863 18.2894,552.8957 454.3127,974.1166 989.0352,986.0379 v -235.0244 c -406.8751,-27.3888 -715.1078,-362.1649 -719.0259,-748.0163 12.7874,-421.0793 236.9242,-746.3999 750.0318,-749.98 895.0688,1.4728 1915.5158,0 2730.9957,0 V 4763 Z"
+ style="fill:#0084d1;fill-opacity:1"
+ clip-path="none" /><path
+ id="path131"
+ d="m 6685.0183,2562.996 c -559.5515,4.407 -980.3924,428.0893 -986.038,985.9863 18.2894,552.8957 454.3127,974.1167 989.0352,986.038 v -235.0244 c -406.8751,-27.3888 -715.1078,-362.165 -719.0259,-748.0164 12.7874,-421.0792 236.9242,-746.3998 750.0318,-749.98 895.0688,1.4728 1915.5158,0 2730.996,0 V 2562.996 Z"
+ style="fill:#0084d1;fill-opacity:1"
+ clip-path="none" /></g><g
+ id="g1263"
+ transform="translate(-693.24341,-2550)"><path
+ fill="none"
+ stroke="#069a2e"
+ stroke-width="265"
+ stroke-linejoin="round"
+ d="m 2793,5962 c 1283,0 429,-2762 1712,-2762"
+ id="path124" /><path
+ id="path110-6"
+ d="M 3198.0212,6550 V 6300.0411 H 2448.0411 V 6050.0305 5550.0094 H 2198.0305 V 6300.0411 6550 H 2448.0411 2698 Z"
+ style="fill:#069a2e;fill-opacity:1" /><path
+ id="path110"
+ d="m 4111.997,2550.0252 v 249.9589 h 749.9801 v 250.0106 500.0211 h 250.0106 v -750.0317 -249.9589 h -250.0106 -249.9589 z"
+ style="fill:#069a2e;fill-opacity:1" /></g>
+ <g
+ id="g1249"
+ transform="translate(-693.24341,-2550)"><path
+ fill="#ff8000"
+ stroke="none"
+ d="M 2215,4164 C 2412.6918,3832.6035 2379.3124,3383.7591 2135.4189,3084.8193 1956.8564,2857.4026 1671.3097,2718.8851 1382,2721 c 0,-52.6667 0,-105.3333 0,-158 -60.1303,-1.0792 190.6585,-1.2724 121.9814,2.7933 434.6311,30.3756 832.6257,336.7309 974.9655,748.2365 148.7336,402.6249 41.0263,883.7477 -266.0719,1183.8452 C 1996.6852,4716.1853 1689.0048,4838.6187 1382,4830 c 0,-61.6667 0,-123.3333 0,-185 338.199,2.9253 666.226,-186.816 833,-481 z"
+ id="path193" /><path
+ fill="#ff8000"
+ stroke="none"
+ d="m 1936,3979 c 175.8129,-283.3241 59.7943,-700.6319 -239.8255,-849.407 -94.2713,-50.9942 -201.887,-77.9344 -309.1745,-74.593 0,-57 0,-114 0,-171 396.3865,-24.0968 777.5367,297.6517 818.5878,693.1841 44.0348,337.5467 -149.4277,694.9971 -466.4953,826.9493 -110.1027,49.0687 -231.5272,73.543 -352.0925,67.8666 0,-61.6667 0,-123.3333 0,-185 220.6353,7.5804 440.8554,-115.3286 549,-308 z"
+ id="path186" /><path
+ fill="#ff8000"
+ stroke="none"
+ d="m 1659,3822 c 86.3933,-138.0398 18.2474,-344.669 -134.6962,-402.3205 C 1483.44,3402.2177 1438.3524,3394.2432 1394,3398 c 0,-56.6667 0,-113.3333 0,-170 223.1964,-19.6143 444.7886,153.3254 478.4886,375.1817 32.646,181.6951 -54.6854,381.4331 -217.3127,472.2205 -78.2316,46.131 -170.3991,69.3119 -261.1759,62.5978 0,-58.3333 0,-116.6667 0,-175 105.6736,9.5509 212.8962,-49.2218 265,-141 z"
+ id="path179" /><rect
+ class="BoundingBox"
+ stroke="none"
+ fill="none"
+ x="700"
+ y="2550"
+ width="501"
+ height="4001"
+ id="rect136"
+ style="fill:#ff8000;fill-opacity:1" /></g>
+
+</svg>
diff --git a/40-abschlusspraesentation/assets/mariadb.svg b/40-abschlusspraesentation/assets/mariadb.svg
new file mode 100644
index 0000000..ddbe283
--- /dev/null
+++ b/40-abschlusspraesentation/assets/mariadb.svg
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" id="Layer_1" data-name="Layer 1" viewBox="0 0 309.88 252.72">
+ <defs>
+ <style>.cls-1{fill:#003545;}</style>
+ </defs>
+ <title>MDB-VLogo_RGB</title>
+ <path class="cls-1" d="M61.74,214.91,73,258.46h-8.5L57,227.09,42.86,258.46H35.68L21.62,227.27,13.9,258.46H5.58l11.16-43.55H24.1l15.2,33.72,15.14-33.72Z" transform="translate(-5.58 -6.4)"></path>
+ <path class="cls-1" d="M105.11,231.74v-5.07h8.21v31.79h-8.21v-5.12c-2.17,3.68-6.63,5.79-12.06,5.79-11.35,0-17.68-8-17.68-17.2,0-8.87,6-16,16.47-16C97.81,226,102.76,228,105.11,231.74Zm-21,10.62c0,5.85,3.68,10.86,10.8,10.86,6.87,0,10.61-4.89,10.61-10.68s-3.86-10.74-11-10.74C87.68,231.8,84.12,236.74,84.12,242.36Z" transform="translate(-5.58 -6.4)"></path>
+ <path class="cls-1" d="M131.83,258.46h-8.2V226.67h8.2v7.12A12.58,12.58,0,0,1,143.29,226a14.84,14.84,0,0,1,5.13.84l-1.75,6a18,18,0,0,0-4.34-.6c-5.92,0-10.5,4.46-10.5,11Z" transform="translate(-5.58 -6.4)"></path>
+ <path class="cls-1" d="M152.52,218.28a4.17,4.17,0,0,1,4.4-4.28,4.33,4.33,0,0,1,4.47,4.41,4.15,4.15,0,0,1-4.47,4.22A4.22,4.22,0,0,1,152.52,218.28Zm.36,8.39h8.21V249.9c0,1.44.3,2.47,1.5,2.47a8.85,8.85,0,0,0,1.57-.18l1.27,6a14.36,14.36,0,0,1-5.43,1c-3.44,0-7.12-1-7.12-8.81Z" transform="translate(-5.58 -6.4)"></path>
+ <path class="cls-1" d="M197.76,231.74v-5.07H206v31.79h-8.21v-5.12c-2.17,3.68-6.63,5.79-12.06,5.79-11.34,0-17.68-8-17.68-17.2,0-8.87,6-16,16.47-16C190.46,226,195.41,228,197.76,231.74Zm-21,10.62c0,5.85,3.68,10.86,10.8,10.86,6.88,0,10.62-4.89,10.62-10.68s-3.87-10.74-11-10.74C180.33,231.8,176.77,236.74,176.77,242.36Z" transform="translate(-5.58 -6.4)"></path>
+ <path class="cls-1" d="M218.57,214.91h19.67c16.53,0,24.79,9.11,24.67,21.77.12,13.16-9,21.78-23.22,21.78H218.57Zm5.43,3.86v35.89h15c13.15,0,18.16-8.87,18.16-18.1,0-10.43-6.27-17.79-18.16-17.79Z" transform="translate(-5.58 -6.4)"></path>
+ <path class="cls-1" d="M296.45,258.46h-25V214.91H294c8.62,0,16.83,1.62,16.71,11.28,0,6.81-4.23,8.69-8.69,9.41,6.33.54,10.14,4.58,10.14,11.1C312.2,256.47,303.63,258.46,296.45,258.46Zm-1.87-24.55c8.63,0,10.56-3.32,10.56-7.54,0-6.34-3.86-7.78-10.56-7.78H276.66v15.32Zm.24,3.68H276.66v17.19H295.6c5.31,0,10.92-1.75,10.92-8.44C306.52,238.62,300.07,237.59,294.82,237.59Z" transform="translate(-5.58 -6.4)"></path>
+ <path class="cls-1" d="M314.08,7.35a4.18,4.18,0,0,0-2.84-.95c-2.83,0-6.49,1.92-8.46,2.95l-.78.4a26.86,26.86,0,0,1-10.57,2.66c-3.76.12-7,.34-11.22.78-25,2.57-36.15,21.73-46.89,40.26C227.47,63.53,221.43,74,213.15,82a54.4,54.4,0,0,1-5.45,4.63C199.13,93,188.37,97.55,180,100.77c-8.06,3.08-16.86,5.85-25.36,8.53-7.79,2.45-15.14,4.77-21.9,7.28-3.05,1.13-5.64,2-7.93,2.76-6.16,2-10.6,3.53-17.09,8-2.53,1.73-5.07,3.6-6.79,5a71.62,71.62,0,0,0-13.55,14.27A84.25,84.25,0,0,1,76,160.27c-1.37,1.34-3.8,2-7.44,2-4.26,0-9.43-.88-14.9-1.81-5.64-1-11.47-1.95-16.47-1.95-4.06,0-7.17.66-9.49,2,0,0-3.91,2.28-5.56,5.23l1.62.73a33.21,33.21,0,0,1,6.92,5,34.72,34.72,0,0,0,7.2,5.12A6.18,6.18,0,0,1,40.1,178c-.68,1-1.68,2.29-2.73,3.67-5.77,7.55-9.14,12.32-7.21,14.92a6.07,6.07,0,0,0,3,.68c12.58,0,19.34-3.27,27.89-7.41,2.48-1.2,5-2.43,8-3.7,5-2.17,10.38-5.63,16.09-9.29C92.61,172,100.42,167,108,164.59a62.3,62.3,0,0,1,19.23-2.7c8,0,16.42,1.07,24.54,2.11,6.05.78,12.32,1.58,18.47,1.95,2.39.14,4.6.21,6.75.21a78.21,78.21,0,0,0,8.61-.45l.69-.24c4.31-2.65,6.33-8.34,8.29-13.84,1.26-3.54,2.32-6.72,4-8.74a2.55,2.55,0,0,1,.32-.27.4.4,0,0,1,.49.08s0,.05,0,.16c-1,21.51-9.66,35.17-18.42,47.31l-5.85,6.27s8.19,0,12.85-1.8c17-5.08,29.83-16.28,39.17-34.14a145.7,145.7,0,0,0,6.17-14.09c.16-.4,1.63-1.14,1.49.93-.05.61-.09,1.29-.14,2h0c0,.42,0,.85-.08,1.28-.24,3-.95,9.34-.95,9.34l5.25-2.81c12.66-8,22.42-24.14,29.82-49.25,3.08-10.46,5.34-20.85,7.33-30,2.38-11,4.43-20.43,6.78-24.09,3.69-5.74,9.32-9.62,14.77-13.39.74-.51,1.49-1,2.22-1.54,6.85-4.81,13.66-10.36,15.16-20.71l0-.23C316.05,10.22,315.13,8.25,314.08,7.35Z" transform="translate(-5.58 -6.4)"></path>
+</svg> \ No newline at end of file
diff --git a/40-abschlusspraesentation/assets/performance.svg b/40-abschlusspraesentation/assets/performance.svg
new file mode 100644
index 0000000..6fdde42
--- /dev/null
+++ b/40-abschlusspraesentation/assets/performance.svg
@@ -0,0 +1,466 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ version="1.1"
+ id="svg9"
+ width="1885.2369"
+ height="1071.5426"
+ viewBox="0 0 1885.2369 1071.5426"
+ sodipodi:docname="tachodiagramm.svg"
+ xml:space="preserve"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg"><defs
+ id="defs13" /><sodipodi:namedview
+ id="namedview11"
+ pagecolor="#ffffff"
+ bordercolor="#000000"
+ borderopacity="0.25"
+ inkscape:showpageshadow="2"
+ inkscape:pageopacity="0.0"
+ inkscape:pagecheckerboard="0"
+ inkscape:deskcolor="#d1d1d1"
+ showgrid="false" /><g
+ inkscape:groupmode="layer"
+ inkscape:label="Image"
+ id="g15"
+ transform="translate(0,233.48718)"><image
+ width="1021"
+ height="548"
+ preserveAspectRatio="none"
+ style="image-rendering:optimizeQuality"
+ xlink:href="data:image/png;base64,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 /8XUA5gDVf3AohH2A1Mk6J9Q02Farwh3IryOCv4Ie+qGZcPEsiYJxZt86CBMGmbF9rStInyamgz/ cq+DWOck10y/2P6mr6NpaHq/e00zwI3P+DhD5leJ7Zz0PNXZlnGG7Y+wvcnPRJ377aT301G6eg0y e8sa9A+au79KhPNRmd9bud8vlle+BtkZ+L/73NQDpkHID805+qhDUyvP+z72z6kFMAdR0a+qH1gk 5ukHpmiP03dIbcZw+DF3L7Zt3Vp890tfT9+pL4KWQ9cdufP18F9+cnHMox5S/Lcv/nnxiNOeVtzv lIemdzUvtv2eD39gce1lVxY/2XBF+u5wsa3/6wcf2/mzvQYdg3j/M9/w8tQbLvY3lrNi5crs7Ynw MI5VuT3x9eIvnlf58897+2vvtN394njHz8e5qFpGrO9RL/251JuvOF51z18pzktca73HLke892mn v3Sia75c9wvf8/u11l2axzlqYr9L5ec9rsfcz8a44ljFNXKXex451nbHtja1neV5y7lW47qsK87R OPeQXv33kzriZ8b5PD7pv78wa33zvAab/sxNa3mDjnssL96z6CLkv+C6xa8wv/HtXy22XnZ96u2y x1EHFvs+a3QgGCF/VPFXiSkB9n/Jw4uD3vyUncsqX2te8Yidr2LbtqJYuWK3de/z9AcUqx5+j9Sr FsP879zmS6/dsQFbiz2PPjj9CzBMhPyCfmjOt757eXHehRtTb7SfXHNT8dqXPyX1AOZgz4N2/PJ/ QeoAdFzc0/avX9gEkGPF9h1SmyV24afOLr5/9r8W3/vKBcXFZ52XvrtLhEJRYTvLivmP/O6f7dyW MGh7YjSFJkc56LLy/IVPvuHdO7/2imMWmj6PveutunbCtNY9Tzn7HXr3Pcx7/4d9zsO0z1V8rquu z/8/e3cC50R5/3H8l+zFDXIfgisggoKCiCcqnlXbqm2toraWaltrb3v330Na7aG1tbWntVpsa6XW 1mo964WKihxyKjeugICIyA17Zf/57T6pYXaSzCSTzJPk827ntTNPdpPJJLvu8n1+vyeZnkNQXR7S /RxR+lj5+FlSiJ9fxfoeRP7M2LKkdSt1Wo3vpCF91y9MNEfuUoX8WrXf5cpjpObkg81Ieq3BvWn3 3/PWD6X9uuTPdWrtGDB+UOt+pnMHyhFBPxCshUvXythzrzVH3qyacYMMO6ivOQKAEGyaRrtrAKWj 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 LY9Xb1cEz8NmlE+736MuTWF41D3aUG1T2c6m/oljDFuyvzRO+5reU+/7sr+rok71e6HtigMzJOgH AGCqLN//S+/54ntWlun/xo3fKEpqhuzDv9OandL6x69PPzj+B+nQ/3hoUQq0MWlQ1SYoO3/TpuLZ YBHkTGNG8ahloPuoQ9chf9Wk9Y3rOE4gXNfn9Yv+66KOw/R1fUYpA8wuxTWYpL9iIE/XdaqLOs6q z0Pbvd/n3Sz7clr6/BtTZasAmIEIrcsHo+mn7gyaVR3haD1ozdVmX/MIhevaLpc+yT7qg8LrEO2P oLr6aOqTNoFw2a/VYzbJDcOrptHvUadB/VVtU9nOuuirtu0q5bQv7udh13NYnXL2859TOx+2TfEc AACm5qqbv1s8W30+/bVPp9M+fVq65vvXDN6H/9pvp/Sjhhn+2zx+t8eni/76ovT8Jzy/KAGqHvf4 x6etW7emNWvWpGuvvbYo3V6Eu+Ms014V5/nc5z6XHrjrrgPPE+Jcz3r2s4tXo+379KenF/zpn45s QxsRDD3lqU9N6w84ICsQizrs/shHpuuuu26i80dY+qrXvCY9/OEPL0ry/P1b31o8Gyz6PeoZxqlv 9MnLXv7yVtcmR/X6bbn44qK0vbJ+4/RfVfl5GFSX8t6I97WVc+xow6j6x8+76rN3vPvdv7gvJlHW Ke6rXbfda5PUqxT1i/s2+vuwV7+6KJ2d8nPz0XPPLUryRDuG1T/6btjfr7Ifcvqgr/s3p45x3HG+ J4b9LSrbHmH6qM/FINW/MbP6jgB6EPv3xyNcddUd/6TZxo3FEzoRg5/POqt4MUCEoU97WvGiIgLj ekB65pnFkwznnLP970dI+4IXFC8aTHq+JnG+m24aL+iNfhk0WCL6K/4d6xsDJnYMEsv1j1rWftr9 XjVOf8Xxr766+R5qMkn7on45/R51Ou64lF72sjtex7+XVn8nru2jH128mG9rbt+meA4AAFNz2KVn FM9Wj29+/5vpXRe9K93w4xuKkpoI+GMWf8MM/vBrv/pr6Y37vzE9c89nFiXAanHSCSdst9f/oO0A IqwpVyoo9+HuIrSJ84eyDk3nr597kvOuy5ixEedrmrVd7at6Pcs6Tlq/NmI1h0u21WdY34Vq3cJq DtvKPgvRb4Put1Dec5MO3MnR5lqGrj4P01BtW9PnJkR7ptHPtDfr7wigB+edd8eD7Vn5oB+xZ3mE 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 "
+ id="image17" /><g
+ id="g282"
+ transform="matrix(1.7172275,0,0,1.7925507,1086.8521,-233.48719)"><path
+ style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none"
+ d="M 9.4628906e-6,4.9755859e-6 V 282.35519 H 464.11212 V 4.9755859e-6 Z"
+ id="path14" /><path
+ style="fill:none;stroke:#002060;stroke-width:0.999983px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 44.119259,226.11615 H 449.43237 M 44.119259,200.83658 H 449.43237 M 44.119259,175.71701 H 449.43237 M 44.119259,150.43744 H 449.43237 M 44.119259,125.15787 H 449.43237 M 44.119259,99.878305 H 449.43237 M 44.119259,74.758735 H 449.43237 M 44.119259,49.439165 H 449.43237"
+ id="path16" /><path
+ style="fill:#ffc000;fill-opacity:1;fill-rule:evenodd;stroke:none"
+ d="M 225.59617,79.318655 V 251.43572 h 42.35928 V 79.318655 Z"
+ id="path18" /><path
+ style="fill:#ff0000;fill-opacity:1;fill-rule:evenodd;stroke:none"
+ d="m 360.71388,249.31576 v 2.11996 h 42.35928 v -2.11996 z"
+ id="path20" /><path
+ style="fill:#00b050;fill-opacity:1;fill-rule:evenodd;stroke:none"
+ d="m 90.438469,223.71619 v 27.69953 h 42.399281 v -27.69953 z"
+ id="path22" /><path
+ style="fill:none;stroke:#d9d9d9;stroke-width:0.999983px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 44.119259,251.43572 H 449.43237"
+ id="path24" /><text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;line-height:125%;font-family:Calibri;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
+ x="26.967316"
+ y="254.85612"
+ id="text30"><tspan
+ sodipodi:role="line"
+ x="26.967316"
+ y="254.85612"
+ id="tspan28"><tspan
+ dx="0"
+ dy="0"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;font-family:Calibri;fill:#002060"
+ id="tspan26">0</tspan></tspan></text><text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;line-height:125%;font-family:Calibri;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
+ x="8.7276306"
+ y="229.61049"
+ id="text36"><tspan
+ sodipodi:role="line"
+ x="8.7276306"
+ y="229.61049"
+ id="tspan34"><tspan
+ dx="0"
+ dy="0"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;font-family:Calibri;fill:#002060"
+ id="tspan32">1000</tspan></tspan></text><text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;line-height:125%;font-family:Calibri;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
+ x="8.7276306"
+ y="204.36479"
+ id="text42"><tspan
+ sodipodi:role="line"
+ x="8.7276306"
+ y="204.36479"
+ id="tspan40"><tspan
+ dx="0"
+ dy="0"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;font-family:Calibri;fill:#002060"
+ id="tspan38">2000</tspan></tspan></text><text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;line-height:125%;font-family:Calibri;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
+ x="8.7276306"
+ y="179.11916"
+ id="text48"><tspan
+ sodipodi:role="line"
+ x="8.7276306"
+ y="179.11916"
+ id="tspan46"><tspan
+ dx="0"
+ dy="0"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;font-family:Calibri;fill:#002060"
+ id="tspan44">3000</tspan></tspan></text><text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;line-height:125%;font-family:Calibri;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
+ x="8.7276306"
+ y="153.87352"
+ id="text54"><tspan
+ sodipodi:role="line"
+ x="8.7276306"
+ y="153.87352"
+ id="tspan52"><tspan
+ dx="0"
+ dy="0"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;font-family:Calibri;fill:#002060"
+ id="tspan50">4000</tspan></tspan></text><text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;line-height:125%;font-family:Calibri;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
+ x="8.7276306"
+ y="128.62794"
+ id="text60"><tspan
+ sodipodi:role="line"
+ x="8.7276306"
+ y="128.62794"
+ id="tspan58"><tspan
+ dx="0"
+ dy="0"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;font-family:Calibri;fill:#002060"
+ id="tspan56">5000</tspan></tspan></text><text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;line-height:125%;font-family:Calibri;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
+ x="8.7276306"
+ y="103.38228"
+ id="text66"><tspan
+ sodipodi:role="line"
+ x="8.7276306"
+ y="103.38228"
+ id="tspan64"><tspan
+ dx="0"
+ dy="0"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;font-family:Calibri;fill:#002060"
+ id="tspan62">6000</tspan></tspan></text><text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;line-height:125%;font-family:Calibri;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
+ x="8.7276306"
+ y="78.136612"
+ id="text72"><tspan
+ sodipodi:role="line"
+ x="8.7276306"
+ y="78.136612"
+ id="tspan70"><tspan
+ dx="0"
+ dy="0"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;font-family:Calibri;fill:#002060"
+ id="tspan68">7000</tspan></tspan></text><text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;line-height:125%;font-family:Calibri;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
+ x="8.7276306"
+ y="52.890945"
+ id="text78"><tspan
+ sodipodi:role="line"
+ x="8.7276306"
+ y="52.890945"
+ id="tspan76"><tspan
+ dx="0"
+ dy="0"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;font-family:Calibri;fill:#002060"
+ id="tspan74">8000</tspan></tspan></text><text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;line-height:125%;font-family:Calibri;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
+ x="88.143829"
+ y="270.4585"
+ id="text84"><tspan
+ sodipodi:role="line"
+ x="88.143829"
+ y="270.4585"
+ id="tspan82"><tspan
+ dx="0"
+ dy="0"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;font-family:Calibri;fill:#002060"
+ id="tspan80">&lt;= 500ms</tspan></tspan></text><text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;line-height:125%;font-family:Calibri;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
+ x="187.71622"
+ y="270.4585"
+ id="text90"><tspan
+ sodipodi:role="line"
+ x="187.71622"
+ y="270.4585"
+ id="tspan88"><tspan
+ dx="0"
+ dy="0"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;font-family:Calibri;fill:#002060"
+ id="tspan86">&gt; 500ms and &lt;= 1500ms</tspan></tspan></text><text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;line-height:125%;font-family:Calibri;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
+ x="358.30728"
+ y="270.4585"
+ id="text96"><tspan
+ sodipodi:role="line"
+ x="358.30728"
+ y="270.4585"
+ id="tspan94"><tspan
+ dx="0"
+ dy="0"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;font-family:Calibri;fill:#002060"
+ id="tspan92">&gt; 1500ms</tspan></tspan></text><text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:700;font-size:18.75px;line-height:125%;font-family:Calibri;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
+ x="151.11063"
+ y="27.823105"
+ id="text102"><tspan
+ sodipodi:role="line"
+ x="151.11063"
+ y="27.823105"
+ id="tspan100"><tspan
+ dx="0"
+ dy="0"
+ style="font-style:normal;font-variant:normal;font-weight:700;font-size:18.75px;font-family:Calibri;fill:#002060"
+ id="tspan98">Dual</tspan></tspan></text><text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:700;font-size:18.75px;line-height:125%;font-family:Calibri;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
+ x="186.94998"
+ y="27.823105"
+ id="text108"><tspan
+ sodipodi:role="line"
+ x="186.94998"
+ y="27.823105"
+ id="tspan106"><tspan
+ dx="0"
+ dy="0"
+ style="font-style:normal;font-variant:normal;font-weight:700;font-size:18.75px;font-family:Calibri;fill:#002060"
+ id="tspan104">-</tspan></tspan></text><text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:700;font-size:18.75px;line-height:125%;font-family:Calibri;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
+ x="192.70987"
+ y="27.823105"
+ id="text114"><tspan
+ sodipodi:role="line"
+ x="192.70987"
+ y="27.823105"
+ id="tspan112"><tspan
+ dx="0"
+ dy="0"
+ style="font-style:normal;font-variant:normal;font-weight:700;font-size:18.75px;font-family:Calibri;fill:#002060"
+ id="tspan110">core system old</tspan></tspan></text></g><g
+ id="g497"
+ transform="matrix(1.7202411,0,0,1.7905349,1086.8522,331.19939)"><path
+ style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none"
+ d="M 9.4628906e-6,5.5859375e-6 V 283.0752 H 464.11212 V 5.5859375e-6 Z"
+ id="path453" /><path
+ style="fill:none;stroke:#660033;stroke-width:0.999983px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 44.119259,226.79616 H 449.43237 M 44.119259,201.51659 H 449.43237 M 44.119259,176.07702 H 449.43237 M 44.119259,150.79745 H 449.43237 M 44.119259,125.51788 H 449.43237 M 44.119259,100.07831 H 449.43237 M 44.119259,74.798736 H 449.43237 M 44.119259,49.439166 H 449.43237"
+ id="path455" /><path
+ style="fill:#00b050;fill-opacity:1;fill-rule:evenodd;stroke:none"
+ d="M 90.478469,106.4182 V 252.13573 H 132.83775 V 106.4182 Z"
+ id="path457" /><path
+ style="fill:#ffc000;fill-opacity:1;fill-rule:evenodd;stroke:none"
+ d="m 225.59617,208.75646 v 43.39926 h 42.35928 v -43.39926 z"
+ id="path459" /><path
+ style="fill:#ff0000;fill-opacity:1;fill-rule:evenodd;stroke:none"
+ d="m 360.71388,238.63595 v 13.51977 h 42.35928 v -13.51977 z"
+ id="path461" /><path
+ style="fill:none;stroke:#d9d9d9;stroke-width:0.999983px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 44.119259,252.15572 H 449.43237"
+ id="path463" /><text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;line-height:125%;font-family:Calibri;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
+ x="26.967316"
+ y="255.58441"
+ id="text469"><tspan
+ sodipodi:role="line"
+ x="26.967316"
+ y="255.58441"
+ id="tspan467"><tspan
+ dx="0"
+ dy="0"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;font-family:Calibri;fill:#800000"
+ id="tspan465">0</tspan></tspan></text><text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;line-height:125%;font-family:Calibri;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
+ x="8.7276306"
+ y="230.24667"
+ id="text475"><tspan
+ sodipodi:role="line"
+ x="8.7276306"
+ y="230.24667"
+ id="tspan473"><tspan
+ dx="0"
+ dy="0"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;font-family:Calibri;fill:#800000"
+ id="tspan471">1000</tspan></tspan></text><text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;line-height:125%;font-family:Calibri;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
+ x="8.7276306"
+ y="204.90894"
+ id="text481"><tspan
+ sodipodi:role="line"
+ x="8.7276306"
+ y="204.90894"
+ id="tspan479"><tspan
+ dx="0"
+ dy="0"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;font-family:Calibri;fill:#800000"
+ id="tspan477">2000</tspan></tspan></text><text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;line-height:125%;font-family:Calibri;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
+ x="8.7276306"
+ y="179.57126"
+ id="text487"><tspan
+ sodipodi:role="line"
+ x="8.7276306"
+ y="179.57126"
+ id="tspan485"><tspan
+ dx="0"
+ dy="0"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;font-family:Calibri;fill:#800000"
+ id="tspan483">3000</tspan></tspan></text><text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;line-height:125%;font-family:Calibri;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
+ x="8.7276306"
+ y="154.23352"
+ id="text493"><tspan
+ sodipodi:role="line"
+ x="8.7276306"
+ y="154.23352"
+ id="tspan491"><tspan
+ dx="0"
+ dy="0"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;font-family:Calibri;fill:#800000"
+ id="tspan489">4000</tspan></tspan></text><text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;line-height:125%;font-family:Calibri;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
+ x="8.7276306"
+ y="128.89587"
+ id="text499"><tspan
+ sodipodi:role="line"
+ x="8.7276306"
+ y="128.89587"
+ id="tspan497"><tspan
+ dx="0"
+ dy="0"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;font-family:Calibri;fill:#800000"
+ id="tspan495">5000</tspan></tspan></text><text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;line-height:125%;font-family:Calibri;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
+ x="8.7276306"
+ y="103.55814"
+ id="text505"><tspan
+ sodipodi:role="line"
+ x="8.7276306"
+ y="103.55814"
+ id="tspan503"><tspan
+ dx="0"
+ dy="0"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;font-family:Calibri;fill:#800000"
+ id="tspan501">6000</tspan></tspan></text><text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;line-height:125%;font-family:Calibri;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
+ x="8.7276306"
+ y="78.220428"
+ id="text511"><tspan
+ sodipodi:role="line"
+ x="8.7276306"
+ y="78.220428"
+ id="tspan509"><tspan
+ dx="0"
+ dy="0"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;font-family:Calibri;fill:#800000"
+ id="tspan507">7000</tspan></tspan></text><text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;line-height:125%;font-family:Calibri;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
+ x="8.7276306"
+ y="52.88269"
+ id="text517"><tspan
+ sodipodi:role="line"
+ x="8.7276306"
+ y="52.88269"
+ id="tspan515"><tspan
+ dx="0"
+ dy="0"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;font-family:Calibri;fill:#800000"
+ id="tspan513">8000</tspan></tspan></text><text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;line-height:125%;font-family:Calibri;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
+ x="88.143829"
+ y="271.1868"
+ id="text523"><tspan
+ sodipodi:role="line"
+ x="88.143829"
+ y="271.1868"
+ id="tspan521"><tspan
+ dx="0"
+ dy="0"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;font-family:Calibri;fill:#800000"
+ id="tspan519">&lt;= 500ms</tspan></tspan></text><text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;line-height:125%;font-family:Calibri;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
+ x="187.71622"
+ y="271.1868"
+ id="text529"><tspan
+ sodipodi:role="line"
+ x="187.71622"
+ y="271.1868"
+ id="tspan527"><tspan
+ dx="0"
+ dy="0"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;font-family:Calibri;fill:#800000"
+ id="tspan525">&gt; 500ms and &lt;= 1500ms</tspan></tspan></text><text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;line-height:125%;font-family:Calibri;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
+ x="358.30728"
+ y="271.1868"
+ id="text535"><tspan
+ sodipodi:role="line"
+ x="358.30728"
+ y="271.1868"
+ id="tspan533"><tspan
+ dx="0"
+ dy="0"
+ style="font-style:normal;font-variant:normal;font-weight:400;font-size:12px;font-family:Calibri;fill:#800000"
+ id="tspan531">&gt; 1500ms</tspan></tspan></text><text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:700;font-size:18.75px;line-height:125%;font-family:Calibri;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
+ x="124.55106"
+ y="27.814804"
+ id="text541"><tspan
+ sodipodi:role="line"
+ x="124.55106"
+ y="27.814804"
+ id="tspan539"><tspan
+ dx="0"
+ dy="0"
+ style="font-style:normal;font-variant:normal;font-weight:700;font-size:18.75px;font-family:Calibri;fill:#800000"
+ id="tspan537">Dual</tspan></tspan></text><text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:700;font-size:18.75px;line-height:125%;font-family:Calibri;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
+ x="160.39047"
+ y="27.814804"
+ id="text547"><tspan
+ sodipodi:role="line"
+ x="160.39047"
+ y="27.814804"
+ id="tspan545"><tspan
+ dx="0"
+ dy="0"
+ style="font-style:normal;font-variant:normal;font-weight:700;font-size:18.75px;font-family:Calibri;fill:#800000"
+ id="tspan543">-</tspan></tspan></text><text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:700;font-size:18.75px;line-height:125%;font-family:Calibri;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
+ x="166.15036"
+ y="27.814804"
+ id="text553"><tspan
+ sodipodi:role="line"
+ x="166.15036"
+ y="27.814804"
+ id="tspan551"><tspan
+ dx="0"
+ dy="0"
+ style="font-style:normal;font-variant:normal;font-weight:700;font-size:18.75px;font-family:Calibri;fill:#800000"
+ id="tspan549">core system optimized</tspan></tspan></text></g></g></svg>
diff --git a/40-abschlusspraesentation/assets/plantuml.svg b/40-abschlusspraesentation/assets/plantuml.svg
new file mode 100644
index 0000000..ed3689a
--- /dev/null
+++ b/40-abschlusspraesentation/assets/plantuml.svg
@@ -0,0 +1,41 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="206 266 800 400" style="&#xA;">
+<defs>
+<linearGradient id="c" x1="-750.5" x2="-729.5" y1="319.06" y2="319.06" gradientTransform="translate(1104.2 304.47)" gradientUnits="userSpaceOnUse">
+<stop stop-color="gray" offset="0"/>
+<stop stop-color="gray" stop-opacity="0" offset="1"/>
+</linearGradient>
+<linearGradient id="a" x1="-621.5" x2="-600.5" y1="348.3" y2="348.3" gradientTransform="translate(1075.2 275.22)" gradientUnits="userSpaceOnUse">
+<stop stop-color="gray" offset="0"/>
+<stop stop-color="gray" stop-opacity="0" offset="1"/>
+</linearGradient>
+<linearGradient id="b" x1="-521.5" x2="-500.5" y1="348.3" y2="348.3" gradientTransform="translate(1075.2 275.22)" gradientUnits="userSpaceOnUse">
+<stop stop-color="gray" offset="0"/>
+<stop stop-color="gray" stop-opacity="0" offset="1"/>
+</linearGradient>
+<linearGradient id="e" x1="-560.5" x2="-474.5" y1="114.1" y2="114.1" gradientTransform="translate(1104.2 304.47)" gradientUnits="userSpaceOnUse">
+<stop stop-color="gray" offset="0"/>
+<stop stop-color="gray" stop-opacity="0" offset="1"/>
+</linearGradient>
+<linearGradient id="d" x1="188.68" x2="304.68" y1="603.53" y2="603.53" gradientUnits="userSpaceOnUse">
+<stop stop-color="#0074bd" offset="0"/>
+<stop stop-color="#0074bd" stop-opacity="0" offset="1"/>
+</linearGradient>
+<linearGradient id="f" x1="543.68" x2="594.68" y1="488.42" y2="488.42" gradientUnits="userSpaceOnUse">
+<stop stop-color="#0074bd" offset="0"/>
+<stop stop-color="#0074bd" stop-opacity="0" offset="1"/>
+</linearGradient>
+</defs>
+ <g style="&#xA;">
+<path d="m479.18 493.53 115 70-90 50-115-70 90-50z" fill="#16003a" stroke="#000"/>
+<path d="m379.18 493.53 115 70-90 50-115-70 90-50z" fill="#ffba39" stroke="#000"/>
+<path d="m279.18 493.53 115 70-90 50-115-70 90-50z" fill="#991039" stroke="#000"/>
+<path d="m594 563.3-49.822-29.778v-120l50 30-0.178 119.78z" fill="url(#f)" stroke="#000"/>
+<path d="m594.18 443.63 35-20.1-50-30-35 20 50 30.1z" fill="url(#e)" stroke="#000"/>
+<path d="m189.18 543.53 115 70v50l-115-70v-50z" fill="url(#d)" stroke="#000"/>
+<path d="m304.18 663.53v-50l90-50 10 50 90-50 10 50 90-50v-120l35-20v240h-325z" fill="#fff" stroke="#000"/>
+<path d="m598.39 365.54c10.048 11.566-2.634 21.965-2.634 21.965s25.497-13.16 13.79-29.648c-10.938-15.369-19.324-23.003 26.076-49.333 0 0-71.267 17.795-37.232 57.016z" clip-rule="evenodd" fill="#ea2d2e" fill-rule="evenodd"/>
+<path d="m609.54 266s21.628 21.64-20.52 54.906c-33.798 26.696-7.705 41.912-0.011 59.305-19.73-17.8-34.203-33.472-24.496-48.056 14.255-21.405 53.751-31.786 45.027-66.155z" clip-rule="evenodd" fill="#ea2d2e" fill-rule="evenodd"/>
+<rect x="354.18" y="613.53" width="20" height="20" ry="5" fill="url(#c)" stroke="#000"/>
+<rect x="554.18" y="613.53" width="20" height="20" ry="5" fill="url(#b)" stroke="#000"/>
+ <rect x="454.18" y="613.53" width="20" height="20" ry="5" fill="url(#a)" stroke="#000"/></g>
+</svg> \ No newline at end of file
diff --git a/40-abschlusspraesentation/assets/spring.svg b/40-abschlusspraesentation/assets/spring.svg
new file mode 100644
index 0000000..50db89e
--- /dev/null
+++ b/40-abschlusspraesentation/assets/spring.svg
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ id="Layer_1"
+ viewBox="0 0 767.8 768"
+ width="2499"
+ height="2500"
+ version="1.1"
+ sodipodi:docname="spring.svg"
+ inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg">
+ <defs
+ id="defs9" />
+ <sodipodi:namedview
+ id="namedview7"
+ pagecolor="#505050"
+ bordercolor="#eeeeee"
+ borderopacity="1"
+ inkscape:showpageshadow="0"
+ inkscape:pageopacity="0"
+ inkscape:pagecheckerboard="0"
+ inkscape:deskcolor="#505050"
+ showgrid="false"
+ inkscape:zoom="0.15266261"
+ inkscape:cx="-268.56608"
+ inkscape:cy="1054.6131"
+ inkscape:window-width="1422"
+ inkscape:window-height="888"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="Layer_1" />
+ <style
+ id="style2">.st0{fill:#77bc1f}</style>
+ <path
+ class="st0"
+ d="M698.3 40c-10.8 25.8-24.5 50.3-41 72.8C585.1 40.6 487.1 0 385 0 173.8 0 0 174 0 385.5 0 491 43.2 592 119.6 664.8l14.2 12.6c69.4 58.5 157.3 90.7 248 90.7 200.8 0 369.6-157.4 383.9-358 10.5-98.2-18.3-222.4-67.4-370.1zm-524 627c-6.2 7.7-15.7 12.2-25.6 12.2-18.1 0-32.9-14.9-32.9-33s14.9-33 32.9-33c7.5 0 14.9 2.6 20.7 7.4 14.1 11.4 16.3 32.3 4.9 46.4zm522.4-115.4c-95 126.7-297.9 84-428 90.1 0 0-23.1 1.4-46.3 5.2 0 0 8.7-3.7 20-8 91.3-31.8 134.5-38 190-66.5 104.5-53.2 207.8-169.6 229.3-290.7C621.9 398.2 501.3 498.3 391.4 539c-75.3 27.8-211.3 54.8-211.3 54.8l-5.5-2.9C82 545.8 79.2 345.1 247.5 280.3c73.7-28.4 144.2-12.8 223.8-31.8 85-20.2 183.3-84 223.3-167.2 44.8 133.1 98.7 341.5 2.1 470.3z"
+ id="path4" />
+ <path
+ style="fill:#ffffff;fill-rule:evenodd;stroke-width:68.2718"
+ d="m 773.12139,2088.0024 c 38.33764,-15.1924 148.55693,-51.2417 285.40461,-93.3471 200.559,-61.7079 263.0679,-85.2803 359.4653,-135.5559 290.6235,-151.5732 553.3324,-435.6749 673.7454,-728.6095 22.5337,-54.8187 41.6478,-113.6415 52.7324,-162.28181 12.7232,-55.83085 10.6923,-57.52283 -9.3604,-7.79801 -102.9177,255.20572 -327.9304,500.75772 -617.7677,674.15792 -156.1121,93.3967 -299.7879,146.8463 -587.06643,218.3977 -129.95701,32.3679 -325.25452,76.2251 -339.4328,76.2251 -3.20202,0 -14.30285,-4.2586 -24.66852,-9.4635 -79.22159,-39.7795 -142.81255,-120.2412 -175.25508,-221.7504 -16.16565,-50.5806 -22.72208,-89.4587 -24.99559,-148.2179 -3.10558,-80.264 6.06856,-144.3013 31.76095,-221.6977 62.58251,-188.5251 205.89902,-334.35133 404.93262,-412.02362 106.59444,-41.59819 196.91767,-56.14707 427.51395,-68.86221 248.5994,-13.7078 370.2867,-41.16629 534.682,-120.64993 210.2105,-101.63487 382.1749,-253.5692 476.1396,-420.67995 l 19.9929,-35.55614 16.2634,50.00701 c 184.4696,567.21109 212.773,991.12214 86.7978,1300.00704 -42.681,104.6518 -111.9442,204.7037 -186.4773,269.3698 -83.4709,72.4206 -190.771,126.285 -316.6972,158.9812 -162.6393,42.2285 -336.4564,51.7151 -728.2446,39.746 -165.68363,-5.0617 -249.45841,-3.7447 -328.75722,5.1683 -61.86171,6.953 -62.16275,6.8984 -30.70809,-5.5664 z"
+ id="path376"
+ transform="matrix(0.3072429,0,0,0.3072429,0,-0.05362145)" />
+ <path
+ style="fill:#ffffff;fill-rule:evenodd;stroke-width:68.2718"
+ d="m 449.321,2203.1692 c -35.77696,-12.0846 -65.90537,-51.8623 -69.0614,-91.1798 -2.71694,-33.8474 5.9762,-56.6121 31.26541,-81.8746 30.90557,-30.873 63.08532,-39.0038 105.04796,-26.5422 26.55181,7.885 57.63704,38.6838 66.75717,66.1419 16.16535,48.6693 -6.13888,104.1132 -51.02277,126.8324 -19.68211,9.9626 -62.88943,13.4105 -82.98637,6.6223 z"
+ id="path378"
+ transform="matrix(0.3072429,0,0,0.3072429,0,-0.05362145)" />
+</svg>
diff --git a/40-abschlusspraesentation/assets/tachodiagramm.svg b/40-abschlusspraesentation/assets/tachodiagramm.svg
new file mode 100644
index 0000000..b68d8e8
--- /dev/null
+++ b/40-abschlusspraesentation/assets/tachodiagramm.svg
@@ -0,0 +1,1683 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ version="1.1"
+ id="svg9"
+ width="1021"
+ height="548"
+ viewBox="0 0 1021 548"
+ sodipodi:docname="Tachodiagramm.png"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg">
+ <defs
+ id="defs13" />
+ <sodipodi:namedview
+ id="namedview11"
+ pagecolor="#ffffff"
+ bordercolor="#000000"
+ borderopacity="0.25"
+ inkscape:showpageshadow="2"
+ inkscape:pageopacity="0.0"
+ inkscape:pagecheckerboard="0"
+ inkscape:deskcolor="#d1d1d1"
+ showgrid="false" />
+ <g
+ inkscape:groupmode="layer"
+ inkscape:label="Image"
+ id="g15">
+ <image
+ width="1021"
+ height="548"
+ preserveAspectRatio="none"
+ style="image-rendering:optimizeQuality"
+ xlink:href="data:image/png;base64,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
+/8XUA5gDVf3AohH2A1Mk6J9Q02Farwh3IryOCv4Ie+qGZcPEsiYJxZt86CBMGmbF9rStInyamgz/
+cq+DWOck10y/2P6mr6NpaHq/e00zwI3P+DhD5leJ7Zz0PNXZlnGG7Y+wvcnPRJ377aT301G6eg0y
+e8sa9A+au79KhPNRmd9bud8vlle+BtkZ+L/73NQDpkHID805+qhDUyvP+z72z6kFMAdR0a+qH1gk
+5ukHpmiP03dIbcZw+DF3L7Zt3Vp890tfT9+pL4KWQ9cdufP18F9+cnHMox5S/Lcv/nnxiNOeVtzv
+lIemdzUvtv2eD39gce1lVxY/2XBF+u5wsa3/6wcf2/mzvQYdg3j/M9/w8tQbLvY3lrNi5crs7Ynw
+MI5VuT3x9eIvnlf58897+2vvtN394njHz8e5qFpGrO9RL/251JuvOF51z18pzktca73HLke892mn
+v3Sia75c9wvf8/u11l2axzlqYr9L5ec9rsfcz8a44ljFNXKXex451nbHtja1neV5y7lW47qsK87R
+OPeQXv33kzriZ8b5PD7pv78wa33zvAab/sxNa3mDjnssL96z6CLkv+C6xa8wv/HtXy22XnZ96u2y
+x1EHFvs+a3QgGCF/VPFXiSkB9n/Jw4uD3vyUncsqX2te8Yidr2LbtqJYuWK3de/z9AcUqx5+j9Sr
+FsP879zmS6/dsQFbiz2PPjj9CzBMhPyCfmjOt757eXHehRtTb7SfXHNT8dqXPyX1AOZgz4N2/PJ/
+QeoAdFzc0/avX9gEkGPF9h1SmyV24afOLr5/9r8W3/vKBcXFZ52XvrtLhEJRYTvLivmP/O6f7dyW
+MGh7YjSFJkc56LLy/IVPvuHdO7/2imMWmj6PveutunbCtNY9Tzn7HXr3Pcx7/4d9zsO0z1V8rquu
+z/8/e3cC50R5/3H8l+zFDXIfgisggoKCiCcqnlXbqm2toraWaltrb3v330Na7aG1tbWntVpsa6XW
+1mo964WKihxyKjeugICIyA17Zf/57T6pYXaSzCSTzJPk827ntTNPdpPJJLvu8n1+vyeZnkNQXR7S
+/RxR+lj5+FlSiJ9fxfoeRP7M2LKkdSt1Wo3vpCF91y9MNEfuUoX8WrXf5cpjpObkg81Ieq3BvWn3
+3/PWD6X9uuTPdWrtGDB+UOt+pnMHyhFBPxCshUvXythzrzVH3qyacYMMO6ivOQKAEGyaRrtrAKWj
+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
+LY9Xb1cEz8NmlE+736MuTWF41D3aUG1T2c6m/oljDFuyvzRO+5reU+/7sr+rok71e6HtigMzJOgH
+AGCqLN//S+/54ntWlun/xo3fKEpqhuzDv9OandL6x69PPzj+B+nQ/3hoUQq0MWlQ1SYoO3/TpuLZ
+YBHkTGNG8ahloPuoQ9chf9Wk9Y3rOE4gXNfn9Yv+66KOw/R1fUYpA8wuxTWYpL9iIE/XdaqLOs6q
+z0Pbvd/n3Sz7clr6/BtTZasAmIEIrcsHo+mn7gyaVR3haD1ozdVmX/MIhevaLpc+yT7qg8LrEO2P
+oLr6aOqTNoFw2a/VYzbJDcOrptHvUadB/VVtU9nOuuirtu0q5bQv7udh13NYnXL2859TOx+2TfEc
+AACm5qqbv1s8W30+/bVPp9M+fVq65vvXDN6H/9pvp/Sjhhn+2zx+t8eni/76ovT8Jzy/KAGqHvf4
+x6etW7emNWvWpGuvvbYo3V6Eu+Ms014V5/nc5z6XHrjrrgPPE+Jcz3r2s4tXo+379KenF/zpn45s
+QxsRDD3lqU9N6w84ICsQizrs/shHpuuuu26i80dY+qrXvCY9/OEPL0ry/P1b31o8Gyz6PeoZxqlv
+9MnLXv7yVtcmR/X6bbn44qK0vbJ+4/RfVfl5GFSX8t6I97WVc+xow6j6x8+76rN3vPvdv7gvJlHW
+Ke6rXbfda5PUqxT1i/s2+vuwV7+6KJ2d8nPz0XPPLUryRDuG1T/6btjfr7Ifcvqgr/s3p45x3HG+
+J4b9LSrbHmH6qM/FINW/MbP6jgB6EPv3xyNcddUd/6TZxo3FEzoRg5/POqt4MUCEoU97WvGiIgLj
+ekB65pnFkwznnLP970dI+4IXFC8aTHq+JnG+m24aL+iNfhk0WCL6K/4d6xsDJnYMEsv1j1rWftr9
+XjVOf8Xxr766+R5qMkn7on45/R51Ou64lF72sjtex7+XVn8nru2jH128mG9rbt+meA4AAFNz2KVn
+FM9Wj29+/5vpXRe9K93w4xuKkpoI+GMWf8MM/vBrv/pr6Y37vzE9c89nFiXAanHSCSdst9f/oO0A
+IqwpVyoo9+HuIrSJ84eyDk3nr597kvOuy5ixEedrmrVd7at6Pcs6Tlq/NmI1h0u21WdY34Vq3cJq
+DtvKPgvRb4Put1Dec5MO3MnR5lqGrj4P01BtW9PnJkR7ptHPtDfr7wigB+edd8eD7Vn5oB+xZ3mE
+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
+"
+ id="image17" />
+ </g>
+</svg>
diff --git a/40-abschlusspraesentation/assets/ui-components/full (Kopie 1).png b/40-abschlusspraesentation/assets/ui-components/full (Kopie 1).png
new file mode 100644
index 0000000..ccb1e83
--- /dev/null
+++ b/40-abschlusspraesentation/assets/ui-components/full (Kopie 1).png
Binary files differ
diff --git a/40-abschlusspraesentation/assets/ui-components/full.png b/40-abschlusspraesentation/assets/ui-components/full.png
new file mode 100644
index 0000000..ccb1e83
--- /dev/null
+++ b/40-abschlusspraesentation/assets/ui-components/full.png
Binary files differ
diff --git a/40-abschlusspraesentation/assets/ui-components/layer1.png b/40-abschlusspraesentation/assets/ui-components/layer1.png
new file mode 100644
index 0000000..565bcdd
--- /dev/null
+++ b/40-abschlusspraesentation/assets/ui-components/layer1.png
Binary files differ
diff --git a/40-abschlusspraesentation/assets/ui-components/layer2.png b/40-abschlusspraesentation/assets/ui-components/layer2.png
new file mode 100644
index 0000000..674711f
--- /dev/null
+++ b/40-abschlusspraesentation/assets/ui-components/layer2.png
Binary files differ
diff --git a/40-abschlusspraesentation/assets/ui-components/layer3.png b/40-abschlusspraesentation/assets/ui-components/layer3.png
new file mode 100644
index 0000000..63f1a32
--- /dev/null
+++ b/40-abschlusspraesentation/assets/ui-components/layer3.png
Binary files differ
diff --git a/40-abschlusspraesentation/assets/vue.svg b/40-abschlusspraesentation/assets/vue.svg
new file mode 100644
index 0000000..271db25
--- /dev/null
+++ b/40-abschlusspraesentation/assets/vue.svg
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.1" viewBox="0 0 261.76 226.69" xmlns="http://www.w3.org/2000/svg"><g transform="matrix(1.3333 0 0 -1.3333 -76.311 313.34)"><g transform="translate(178.06 235.01)"><path d="m0 0-22.669-39.264-22.669 39.264h-75.491l98.16-170.02 98.16 170.02z" fill="#41b883"/></g><g transform="translate(178.06 235.01)"><path d="m0 0-22.669-39.264-22.669 39.264h-36.227l58.896-102.01 58.896 102.01z" fill="#34495e"/></g></g></svg> \ No newline at end of file
diff --git a/40-abschlusspraesentation/package-lock.json b/40-abschlusspraesentation/package-lock.json
new file mode 100644
index 0000000..700c27b
--- /dev/null
+++ b/40-abschlusspraesentation/package-lock.json
@@ -0,0 +1,4126 @@
+{
+ "name": "abschlusspraesentation",
+ "version": "1.0.0",
+ "lockfileVersion": 2,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "abschlusspraesentation",
+ "version": "1.0.0",
+ "license": "ISC",
+ "dependencies": {
+ "reveal-md": "^5.4.1"
+ }
+ },
+ "node_modules/@sindresorhus/is": {
+ "version": "0.14.0",
+ "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz",
+ "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/@szmarczak/http-timer": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz",
+ "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==",
+ "dependencies": {
+ "defer-to-connect": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/accepts": {
+ "version": "1.3.8",
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
+ "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
+ "dependencies": {
+ "mime-types": "~2.1.34",
+ "negotiator": "0.6.3"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/agent-base": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz",
+ "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==",
+ "optional": true,
+ "dependencies": {
+ "es6-promisify": "^5.0.0"
+ },
+ "engines": {
+ "node": ">= 4.0.0"
+ }
+ },
+ "node_modules/ansi-align": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz",
+ "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==",
+ "dependencies": {
+ "string-width": "^4.1.0"
+ }
+ },
+ "node_modules/ansi-regex": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/anymatch": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+ "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
+ "dependencies": {
+ "normalize-path": "^3.0.0",
+ "picomatch": "^2.0.4"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/argparse": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+ "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+ "dependencies": {
+ "sprintf-js": "~1.0.2"
+ }
+ },
+ "node_modules/array-flatten": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
+ "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="
+ },
+ "node_modules/async-limiter": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz",
+ "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==",
+ "optional": true
+ },
+ "node_modules/balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
+ },
+ "node_modules/binary-extensions": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
+ "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/body-parser": {
+ "version": "1.20.1",
+ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz",
+ "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==",
+ "dependencies": {
+ "bytes": "3.1.2",
+ "content-type": "~1.0.4",
+ "debug": "2.6.9",
+ "depd": "2.0.0",
+ "destroy": "1.2.0",
+ "http-errors": "2.0.0",
+ "iconv-lite": "0.4.24",
+ "on-finished": "2.4.1",
+ "qs": "6.11.0",
+ "raw-body": "2.5.1",
+ "type-is": "~1.6.18",
+ "unpipe": "1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8",
+ "npm": "1.2.8000 || >= 1.4.16"
+ }
+ },
+ "node_modules/body-parser/node_modules/debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dependencies": {
+ "ms": "2.0.0"
+ }
+ },
+ "node_modules/body-parser/node_modules/ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
+ },
+ "node_modules/boxen": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz",
+ "integrity": "sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==",
+ "dependencies": {
+ "ansi-align": "^3.0.0",
+ "camelcase": "^6.2.0",
+ "chalk": "^4.1.0",
+ "cli-boxes": "^2.2.1",
+ "string-width": "^4.2.2",
+ "type-fest": "^0.20.2",
+ "widest-line": "^3.1.0",
+ "wrap-ansi": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/brace-expansion": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+ "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+ "dependencies": {
+ "balanced-match": "^1.0.0"
+ }
+ },
+ "node_modules/braces": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
+ "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+ "dependencies": {
+ "fill-range": "^7.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/buffer-crc32": {
+ "version": "0.2.13",
+ "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
+ "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==",
+ "optional": true,
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/buffer-from": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
+ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
+ "optional": true
+ },
+ "node_modules/bytes": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
+ "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/cacheable-request": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz",
+ "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==",
+ "dependencies": {
+ "clone-response": "^1.0.2",
+ "get-stream": "^5.1.0",
+ "http-cache-semantics": "^4.0.0",
+ "keyv": "^3.0.0",
+ "lowercase-keys": "^2.0.0",
+ "normalize-url": "^4.1.0",
+ "responselike": "^1.0.2"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/cacheable-request/node_modules/get-stream": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
+ "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
+ "dependencies": {
+ "pump": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/cacheable-request/node_modules/lowercase-keys": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz",
+ "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/call-bind": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
+ "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
+ "dependencies": {
+ "function-bind": "^1.1.1",
+ "get-intrinsic": "^1.0.2"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/camelcase": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
+ "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/chokidar": {
+ "version": "3.5.3",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
+ "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://paulmillr.com/funding/"
+ }
+ ],
+ "dependencies": {
+ "anymatch": "~3.1.2",
+ "braces": "~3.0.2",
+ "glob-parent": "~5.1.2",
+ "is-binary-path": "~2.1.0",
+ "is-glob": "~4.0.1",
+ "normalize-path": "~3.0.0",
+ "readdirp": "~3.6.0"
+ },
+ "engines": {
+ "node": ">= 8.10.0"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/ci-info": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz",
+ "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ=="
+ },
+ "node_modules/cli-boxes": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz",
+ "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==",
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/clone-response": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz",
+ "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==",
+ "dependencies": {
+ "mimic-response": "^1.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
+ },
+ "node_modules/commander": {
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz",
+ "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==",
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
+ "optional": true
+ },
+ "node_modules/concat-stream": {
+ "version": "1.6.2",
+ "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
+ "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
+ "engines": [
+ "node >= 0.8"
+ ],
+ "optional": true,
+ "dependencies": {
+ "buffer-from": "^1.0.0",
+ "inherits": "^2.0.3",
+ "readable-stream": "^2.2.2",
+ "typedarray": "^0.0.6"
+ }
+ },
+ "node_modules/configstore": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz",
+ "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==",
+ "dependencies": {
+ "dot-prop": "^5.2.0",
+ "graceful-fs": "^4.1.2",
+ "make-dir": "^3.0.0",
+ "unique-string": "^2.0.0",
+ "write-file-atomic": "^3.0.0",
+ "xdg-basedir": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/content-disposition": {
+ "version": "0.5.4",
+ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
+ "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
+ "dependencies": {
+ "safe-buffer": "5.2.1"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/content-type": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
+ "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/cookie": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
+ "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/cookie-signature": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
+ "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
+ },
+ "node_modules/core-util-is": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
+ "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
+ "optional": true
+ },
+ "node_modules/crypto-random-string": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz",
+ "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/debug": {
+ "version": "4.3.4",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
+ "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
+ "dependencies": {
+ "ms": "2.1.2"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/decompress-response": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz",
+ "integrity": "sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==",
+ "dependencies": {
+ "mimic-response": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/deep-extend": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
+ "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
+ "engines": {
+ "node": ">=4.0.0"
+ }
+ },
+ "node_modules/defer-to-connect": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz",
+ "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ=="
+ },
+ "node_modules/define-lazy-prop": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz",
+ "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/depd": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+ "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/destroy": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
+ "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==",
+ "engines": {
+ "node": ">= 0.8",
+ "npm": "1.2.8000 || >= 1.4.16"
+ }
+ },
+ "node_modules/dot-prop": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz",
+ "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==",
+ "dependencies": {
+ "is-obj": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/duplexer3": {
+ "version": "0.1.5",
+ "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.5.tgz",
+ "integrity": "sha512-1A8za6ws41LQgv9HrE/66jyC5yuSjQ3L/KOpFtoBilsAK2iA2wuS5rTt1OCzIvtS2V7nVmedsUU+DGRcjBmOYA=="
+ },
+ "node_modules/ee-first": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
+ },
+ "node_modules/emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
+ },
+ "node_modules/encodeurl": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
+ "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/end-of-stream": {
+ "version": "1.4.4",
+ "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
+ "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
+ "dependencies": {
+ "once": "^1.4.0"
+ }
+ },
+ "node_modules/es6-promise": {
+ "version": "4.2.8",
+ "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz",
+ "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==",
+ "optional": true
+ },
+ "node_modules/es6-promisify": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz",
+ "integrity": "sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==",
+ "optional": true,
+ "dependencies": {
+ "es6-promise": "^4.0.3"
+ }
+ },
+ "node_modules/escape-goat": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz",
+ "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/escape-html": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+ "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="
+ },
+ "node_modules/esprima": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
+ "bin": {
+ "esparse": "bin/esparse.js",
+ "esvalidate": "bin/esvalidate.js"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/etag": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+ "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/express": {
+ "version": "4.18.2",
+ "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz",
+ "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==",
+ "dependencies": {
+ "accepts": "~1.3.8",
+ "array-flatten": "1.1.1",
+ "body-parser": "1.20.1",
+ "content-disposition": "0.5.4",
+ "content-type": "~1.0.4",
+ "cookie": "0.5.0",
+ "cookie-signature": "1.0.6",
+ "debug": "2.6.9",
+ "depd": "2.0.0",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "finalhandler": "1.2.0",
+ "fresh": "0.5.2",
+ "http-errors": "2.0.0",
+ "merge-descriptors": "1.0.1",
+ "methods": "~1.1.2",
+ "on-finished": "2.4.1",
+ "parseurl": "~1.3.3",
+ "path-to-regexp": "0.1.7",
+ "proxy-addr": "~2.0.7",
+ "qs": "6.11.0",
+ "range-parser": "~1.2.1",
+ "safe-buffer": "5.2.1",
+ "send": "0.18.0",
+ "serve-static": "1.15.0",
+ "setprototypeof": "1.2.0",
+ "statuses": "2.0.1",
+ "type-is": "~1.6.18",
+ "utils-merge": "1.0.1",
+ "vary": "~1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.10.0"
+ }
+ },
+ "node_modules/express/node_modules/debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dependencies": {
+ "ms": "2.0.0"
+ }
+ },
+ "node_modules/express/node_modules/ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
+ },
+ "node_modules/extract-zip": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.7.0.tgz",
+ "integrity": "sha512-xoh5G1W/PB0/27lXgMQyIhP5DSY/LhoCsOyZgb+6iMmRtCwVBo55uKaMoEYrDCKQhWvqEip5ZPKAc6eFNyf/MA==",
+ "optional": true,
+ "dependencies": {
+ "concat-stream": "^1.6.2",
+ "debug": "^2.6.9",
+ "mkdirp": "^0.5.4",
+ "yauzl": "^2.10.0"
+ },
+ "bin": {
+ "extract-zip": "cli.js"
+ }
+ },
+ "node_modules/extract-zip/node_modules/debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "optional": true,
+ "dependencies": {
+ "ms": "2.0.0"
+ }
+ },
+ "node_modules/extract-zip/node_modules/ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+ "optional": true
+ },
+ "node_modules/fd-slicer": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
+ "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==",
+ "optional": true,
+ "dependencies": {
+ "pend": "~1.2.0"
+ }
+ },
+ "node_modules/fill-range": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
+ "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+ "dependencies": {
+ "to-regex-range": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/finalhandler": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
+ "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==",
+ "dependencies": {
+ "debug": "2.6.9",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "on-finished": "2.4.1",
+ "parseurl": "~1.3.3",
+ "statuses": "2.0.1",
+ "unpipe": "~1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/finalhandler/node_modules/debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dependencies": {
+ "ms": "2.0.0"
+ }
+ },
+ "node_modules/finalhandler/node_modules/ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
+ },
+ "node_modules/forwarded": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
+ "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/fresh": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
+ "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/fs-extra": {
+ "version": "11.1.0",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.0.tgz",
+ "integrity": "sha512-0rcTq621PD5jM/e0a3EJoGC/1TC5ZBCERW82LQuwfGnCa1V8w7dpYH1yNu+SLb6E5dkeCBzKEyLGlFrnr+dUyw==",
+ "dependencies": {
+ "graceful-fs": "^4.2.0",
+ "jsonfile": "^6.0.1",
+ "universalify": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=14.14"
+ }
+ },
+ "node_modules/fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
+ },
+ "node_modules/fsevents": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
+ "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
+ "hasInstallScript": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/function-bind": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
+ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
+ },
+ "node_modules/get-intrinsic": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz",
+ "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==",
+ "dependencies": {
+ "function-bind": "^1.1.1",
+ "has": "^1.0.3",
+ "has-symbols": "^1.0.3"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/get-stream": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
+ "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==",
+ "dependencies": {
+ "pump": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/glob": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz",
+ "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==",
+ "dependencies": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^5.0.1",
+ "once": "^1.3.0"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/global-dirs": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.1.tgz",
+ "integrity": "sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==",
+ "dependencies": {
+ "ini": "2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/got": {
+ "version": "9.6.0",
+ "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz",
+ "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==",
+ "dependencies": {
+ "@sindresorhus/is": "^0.14.0",
+ "@szmarczak/http-timer": "^1.1.2",
+ "cacheable-request": "^6.0.0",
+ "decompress-response": "^3.3.0",
+ "duplexer3": "^0.1.4",
+ "get-stream": "^4.1.0",
+ "lowercase-keys": "^1.0.1",
+ "mimic-response": "^1.0.1",
+ "p-cancelable": "^1.0.0",
+ "to-readable-stream": "^1.0.0",
+ "url-parse-lax": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8.6"
+ }
+ },
+ "node_modules/graceful-fs": {
+ "version": "4.2.11",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
+ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="
+ },
+ "node_modules/has": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
+ "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
+ "dependencies": {
+ "function-bind": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4.0"
+ }
+ },
+ "node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/has-symbols": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
+ "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-yarn": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz",
+ "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/highlight.js": {
+ "version": "11.7.0",
+ "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.7.0.tgz",
+ "integrity": "sha512-1rRqesRFhMO/PRF+G86evnyJkCgaZFOI+Z6kdj15TA18funfoqJXvgPCLSf0SWq3SRfg1j3HlDs8o4s3EGq1oQ==",
+ "engines": {
+ "node": ">=12.0.0"
+ }
+ },
+ "node_modules/http-cache-semantics": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz",
+ "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ=="
+ },
+ "node_modules/http-errors": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
+ "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
+ "dependencies": {
+ "depd": "2.0.0",
+ "inherits": "2.0.4",
+ "setprototypeof": "1.2.0",
+ "statuses": "2.0.1",
+ "toidentifier": "1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/https-proxy-agent": {
+ "version": "2.2.4",
+ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz",
+ "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==",
+ "optional": true,
+ "dependencies": {
+ "agent-base": "^4.3.0",
+ "debug": "^3.1.0"
+ },
+ "engines": {
+ "node": ">= 4.5.0"
+ }
+ },
+ "node_modules/https-proxy-agent/node_modules/debug": {
+ "version": "3.2.7",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+ "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
+ "optional": true,
+ "dependencies": {
+ "ms": "^2.1.1"
+ }
+ },
+ "node_modules/iconv-lite": {
+ "version": "0.4.24",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/import-lazy": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz",
+ "integrity": "sha512-m7ZEHgtw69qOGw+jwxXkHlrlIPdTGkyh66zXZ1ajZbxkDBNjSY/LGbmjc7h0s2ELsUDTAhFr55TrPSSqJGPG0A==",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/imurmurhash": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+ "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
+ "engines": {
+ "node": ">=0.8.19"
+ }
+ },
+ "node_modules/inflight": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
+ "dependencies": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
+ },
+ "node_modules/ini": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz",
+ "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/ipaddr.js": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
+ "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/is-binary-path": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+ "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+ "dependencies": {
+ "binary-extensions": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-ci": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz",
+ "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==",
+ "dependencies": {
+ "ci-info": "^2.0.0"
+ },
+ "bin": {
+ "is-ci": "bin.js"
+ }
+ },
+ "node_modules/is-docker": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz",
+ "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==",
+ "bin": {
+ "is-docker": "cli.js"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-fullwidth-code-point": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-glob": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+ "dependencies": {
+ "is-extglob": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-installed-globally": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz",
+ "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==",
+ "dependencies": {
+ "global-dirs": "^3.0.0",
+ "is-path-inside": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/is-npm": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-5.0.0.tgz",
+ "integrity": "sha512-WW/rQLOazUq+ST/bCAVBp/2oMERWLsR7OrKyt052dNDk4DHcDE0/7QSXITlmi+VBcV13DfIbysG3tZJm5RfdBA==",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
+ "node_modules/is-obj": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz",
+ "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-path-inside": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
+ "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-typedarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
+ "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA=="
+ },
+ "node_modules/is-wsl": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz",
+ "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==",
+ "dependencies": {
+ "is-docker": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-yarn-global": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz",
+ "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw=="
+ },
+ "node_modules/isarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+ "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
+ "optional": true
+ },
+ "node_modules/js-yaml": {
+ "version": "3.14.1",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
+ "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
+ "dependencies": {
+ "argparse": "^1.0.7",
+ "esprima": "^4.0.0"
+ },
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
+ }
+ },
+ "node_modules/json-buffer": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz",
+ "integrity": "sha512-CuUqjv0FUZIdXkHPI8MezCnFCdaTAacej1TZYulLoAg1h/PhwkdXFN4V/gzY4g+fMBCOV2xF+rp7t2XD2ns/NQ=="
+ },
+ "node_modules/jsonfile": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
+ "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
+ "dependencies": {
+ "universalify": "^2.0.0"
+ },
+ "optionalDependencies": {
+ "graceful-fs": "^4.1.6"
+ }
+ },
+ "node_modules/keyv": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz",
+ "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==",
+ "dependencies": {
+ "json-buffer": "3.0.0"
+ }
+ },
+ "node_modules/latest-version": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz",
+ "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==",
+ "dependencies": {
+ "package-json": "^6.3.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/livereload": {
+ "version": "0.9.3",
+ "resolved": "https://registry.npmjs.org/livereload/-/livereload-0.9.3.tgz",
+ "integrity": "sha512-q7Z71n3i4X0R9xthAryBdNGVGAO2R5X+/xXpmKeuPMrteg+W2U8VusTKV3YiJbXZwKsOlFlHe+go6uSNjfxrZw==",
+ "dependencies": {
+ "chokidar": "^3.5.0",
+ "livereload-js": "^3.3.1",
+ "opts": ">= 1.2.0",
+ "ws": "^7.4.3"
+ },
+ "bin": {
+ "livereload": "bin/livereload.js"
+ },
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
+ "node_modules/livereload-js": {
+ "version": "3.4.1",
+ "resolved": "https://registry.npmjs.org/livereload-js/-/livereload-js-3.4.1.tgz",
+ "integrity": "sha512-5MP0uUeVCec89ZbNOT/i97Mc+q3SxXmiUGhRFOTmhrGPn//uWVQdCvcLJDy64MSBR5MidFdOR7B9viumoavy6g=="
+ },
+ "node_modules/lodash": {
+ "version": "4.17.21",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
+ },
+ "node_modules/lowercase-keys": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz",
+ "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/lru-cache": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+ "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+ "dependencies": {
+ "yallist": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/make-dir": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
+ "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
+ "dependencies": {
+ "semver": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/make-dir/node_modules/semver": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "bin": {
+ "semver": "bin/semver.js"
+ }
+ },
+ "node_modules/media-typer": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
+ "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/merge-descriptors": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
+ "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w=="
+ },
+ "node_modules/methods": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
+ "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mime": {
+ "version": "2.6.0",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz",
+ "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==",
+ "optional": true,
+ "bin": {
+ "mime": "cli.js"
+ },
+ "engines": {
+ "node": ">=4.0.0"
+ }
+ },
+ "node_modules/mime-db": {
+ "version": "1.52.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+ "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mime-types": {
+ "version": "2.1.35",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+ "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+ "dependencies": {
+ "mime-db": "1.52.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mimic-response": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz",
+ "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/minimatch": {
+ "version": "5.1.6",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
+ "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
+ "dependencies": {
+ "brace-expansion": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/minimist": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
+ "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/mkdirp": {
+ "version": "0.5.6",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
+ "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
+ "optional": true,
+ "dependencies": {
+ "minimist": "^1.2.6"
+ },
+ "bin": {
+ "mkdirp": "bin/cmd.js"
+ }
+ },
+ "node_modules/ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+ },
+ "node_modules/mustache": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz",
+ "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==",
+ "bin": {
+ "mustache": "bin/mustache"
+ }
+ },
+ "node_modules/negotiator": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
+ "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/normalize-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/normalize-url": {
+ "version": "4.5.1",
+ "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz",
+ "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/object-inspect": {
+ "version": "1.12.3",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz",
+ "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/on-finished": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
+ "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
+ "dependencies": {
+ "ee-first": "1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+ "dependencies": {
+ "wrappy": "1"
+ }
+ },
+ "node_modules/open": {
+ "version": "8.4.2",
+ "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz",
+ "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==",
+ "dependencies": {
+ "define-lazy-prop": "^2.0.0",
+ "is-docker": "^2.1.1",
+ "is-wsl": "^2.2.0"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/opts": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/opts/-/opts-2.0.2.tgz",
+ "integrity": "sha512-k41FwbcLnlgnFh69f4qdUfvDQ+5vaSDnVPFI/y5XuhKRq97EnVVneO9F1ESVCdiVu4fCS2L8usX3mU331hB7pg=="
+ },
+ "node_modules/p-cancelable": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz",
+ "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/package-json": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz",
+ "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==",
+ "dependencies": {
+ "got": "^9.6.0",
+ "registry-auth-token": "^4.0.0",
+ "registry-url": "^5.0.0",
+ "semver": "^6.2.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/package-json/node_modules/semver": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "bin": {
+ "semver": "bin/semver.js"
+ }
+ },
+ "node_modules/parseurl": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+ "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
+ "optional": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/path-to-regexp": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
+ "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ=="
+ },
+ "node_modules/pend": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
+ "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==",
+ "optional": true
+ },
+ "node_modules/picomatch": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+ "engines": {
+ "node": ">=8.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/prepend-http": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz",
+ "integrity": "sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA==",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/process-nextick-args": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
+ "optional": true
+ },
+ "node_modules/progress": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
+ "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
+ "optional": true,
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/proxy-addr": {
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
+ "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
+ "dependencies": {
+ "forwarded": "0.2.0",
+ "ipaddr.js": "1.9.1"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/proxy-from-env": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
+ "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
+ "optional": true
+ },
+ "node_modules/pump": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
+ "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
+ "dependencies": {
+ "end-of-stream": "^1.1.0",
+ "once": "^1.3.1"
+ }
+ },
+ "node_modules/pupa": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz",
+ "integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==",
+ "dependencies": {
+ "escape-goat": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/puppeteer": {
+ "version": "1.20.0",
+ "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-1.20.0.tgz",
+ "integrity": "sha512-bt48RDBy2eIwZPrkgbcwHtb51mj2nKvHOPMaSH2IsWiv7lOG9k9zhaRzpDZafrk05ajMc3cu+lSQYYOfH2DkVQ==",
+ "deprecated": "< 19.4.0 is no longer supported",
+ "hasInstallScript": true,
+ "optional": true,
+ "dependencies": {
+ "debug": "^4.1.0",
+ "extract-zip": "^1.6.6",
+ "https-proxy-agent": "^2.2.1",
+ "mime": "^2.0.3",
+ "progress": "^2.0.1",
+ "proxy-from-env": "^1.0.0",
+ "rimraf": "^2.6.1",
+ "ws": "^6.1.0"
+ },
+ "engines": {
+ "node": ">=6.4.0"
+ }
+ },
+ "node_modules/puppeteer/node_modules/ws": {
+ "version": "6.2.2",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.2.tgz",
+ "integrity": "sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw==",
+ "optional": true,
+ "dependencies": {
+ "async-limiter": "~1.0.0"
+ }
+ },
+ "node_modules/qs": {
+ "version": "6.11.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
+ "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
+ "dependencies": {
+ "side-channel": "^1.0.4"
+ },
+ "engines": {
+ "node": ">=0.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/range-parser": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
+ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/raw-body": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
+ "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
+ "dependencies": {
+ "bytes": "3.1.2",
+ "http-errors": "2.0.0",
+ "iconv-lite": "0.4.24",
+ "unpipe": "1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/rc": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
+ "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
+ "dependencies": {
+ "deep-extend": "^0.6.0",
+ "ini": "~1.3.0",
+ "minimist": "^1.2.0",
+ "strip-json-comments": "~2.0.1"
+ },
+ "bin": {
+ "rc": "cli.js"
+ }
+ },
+ "node_modules/rc/node_modules/ini": {
+ "version": "1.3.8",
+ "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
+ "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="
+ },
+ "node_modules/readable-stream": {
+ "version": "2.3.8",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
+ "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
+ "optional": true,
+ "dependencies": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "node_modules/readable-stream/node_modules/safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+ "optional": true
+ },
+ "node_modules/readdirp": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+ "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+ "dependencies": {
+ "picomatch": "^2.2.1"
+ },
+ "engines": {
+ "node": ">=8.10.0"
+ }
+ },
+ "node_modules/registry-auth-token": {
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.2.tgz",
+ "integrity": "sha512-PC5ZysNb42zpFME6D/XlIgtNGdTl8bBOCw90xQLVMpzuuubJKYDWFAEuUNc+Cn8Z8724tg2SDhDRrkVEsqfDMg==",
+ "dependencies": {
+ "rc": "1.2.8"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/registry-url": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz",
+ "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==",
+ "dependencies": {
+ "rc": "^1.2.8"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/responselike": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz",
+ "integrity": "sha512-/Fpe5guzJk1gPqdJLJR5u7eG/gNY4nImjbRDaVWVMRhne55TCmj2i9Q+54PBRfatRC8v/rIiv9BN0pMd9OV5EQ==",
+ "dependencies": {
+ "lowercase-keys": "^1.0.0"
+ }
+ },
+ "node_modules/reveal-md": {
+ "version": "5.4.1",
+ "resolved": "https://registry.npmjs.org/reveal-md/-/reveal-md-5.4.1.tgz",
+ "integrity": "sha512-pSNiE7ryND/yopuIktKaESTahSMPI2dLPIYLUCAksan6M4v8V5b1GjDaFCgF1wC0qcTZqUS34I8HBYoMStb/AQ==",
+ "dependencies": {
+ "debug": "4.3.4",
+ "express": "4.18.2",
+ "fs-extra": "11.1.0",
+ "glob": "8.1.0",
+ "highlight.js": "11.7.0",
+ "livereload": "0.9.3",
+ "lodash": "4.17.21",
+ "mustache": "4.2.0",
+ "open": "8.4.2",
+ "reveal.js": "4.4.0",
+ "serve-favicon": "2.5.0",
+ "try-require": "1.2.1",
+ "update-notifier": "5.1.0",
+ "yaml-front-matter": "4.1.1",
+ "yargs-parser": "21.1.1"
+ },
+ "bin": {
+ "reveal-md": "bin/reveal-md.js"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "optionalDependencies": {
+ "puppeteer": "1.20.0"
+ }
+ },
+ "node_modules/reveal.js": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/reveal.js/-/reveal.js-4.4.0.tgz",
+ "integrity": "sha512-jIV6C9V2NEUjGzU8L6dUFGpk1KJmq7/EzP2fOW67ggc2c0Cp/PdprWxZ9Qgp46F0T2ZWDCjQ1p3Ytzy5jA6a2w==",
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
+ "node_modules/rimraf": {
+ "version": "2.7.1",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
+ "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
+ "optional": true,
+ "dependencies": {
+ "glob": "^7.1.3"
+ },
+ "bin": {
+ "rimraf": "bin.js"
+ }
+ },
+ "node_modules/rimraf/node_modules/brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "optional": true,
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/rimraf/node_modules/glob": {
+ "version": "7.2.3",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+ "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+ "optional": true,
+ "dependencies": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.1.1",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ },
+ "engines": {
+ "node": "*"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/rimraf/node_modules/minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "optional": true,
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ]
+ },
+ "node_modules/safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
+ },
+ "node_modules/semver": {
+ "version": "7.3.8",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
+ "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
+ "dependencies": {
+ "lru-cache": "^6.0.0"
+ },
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/semver-diff": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz",
+ "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==",
+ "dependencies": {
+ "semver": "^6.3.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/semver-diff/node_modules/semver": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "bin": {
+ "semver": "bin/semver.js"
+ }
+ },
+ "node_modules/send": {
+ "version": "0.18.0",
+ "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
+ "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
+ "dependencies": {
+ "debug": "2.6.9",
+ "depd": "2.0.0",
+ "destroy": "1.2.0",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "fresh": "0.5.2",
+ "http-errors": "2.0.0",
+ "mime": "1.6.0",
+ "ms": "2.1.3",
+ "on-finished": "2.4.1",
+ "range-parser": "~1.2.1",
+ "statuses": "2.0.1"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/send/node_modules/debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dependencies": {
+ "ms": "2.0.0"
+ }
+ },
+ "node_modules/send/node_modules/debug/node_modules/ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
+ },
+ "node_modules/send/node_modules/mime": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+ "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
+ "bin": {
+ "mime": "cli.js"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/send/node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
+ },
+ "node_modules/serve-favicon": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/serve-favicon/-/serve-favicon-2.5.0.tgz",
+ "integrity": "sha512-FMW2RvqNr03x+C0WxTyu6sOv21oOjkq5j8tjquWccwa6ScNyGFOGJVpuS1NmTVGBAHS07xnSKotgf2ehQmf9iA==",
+ "dependencies": {
+ "etag": "~1.8.1",
+ "fresh": "0.5.2",
+ "ms": "2.1.1",
+ "parseurl": "~1.3.2",
+ "safe-buffer": "5.1.1"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/serve-favicon/node_modules/ms": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
+ "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
+ },
+ "node_modules/serve-favicon/node_modules/safe-buffer": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
+ "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg=="
+ },
+ "node_modules/serve-static": {
+ "version": "1.15.0",
+ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz",
+ "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==",
+ "dependencies": {
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "parseurl": "~1.3.3",
+ "send": "0.18.0"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/setprototypeof": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
+ "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
+ },
+ "node_modules/side-channel": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
+ "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
+ "dependencies": {
+ "call-bind": "^1.0.0",
+ "get-intrinsic": "^1.0.2",
+ "object-inspect": "^1.9.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/signal-exit": {
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
+ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="
+ },
+ "node_modules/sprintf-js": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+ "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g=="
+ },
+ "node_modules/statuses": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
+ "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/string_decoder": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "optional": true,
+ "dependencies": {
+ "safe-buffer": "~5.1.0"
+ }
+ },
+ "node_modules/string_decoder/node_modules/safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+ "optional": true
+ },
+ "node_modules/string-width": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+ "dependencies": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/strip-ansi": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/strip-json-comments": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
+ "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/to-readable-stream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz",
+ "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "dependencies": {
+ "is-number": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=8.0"
+ }
+ },
+ "node_modules/toidentifier": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
+ "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
+ "engines": {
+ "node": ">=0.6"
+ }
+ },
+ "node_modules/try-require": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/try-require/-/try-require-1.2.1.tgz",
+ "integrity": "sha512-aMzrGUIA/R2LwUgvsOusx+GTy8ERyNjpBzbWgS1Qx4oTFlXCMxY3PyyXbPE1pvrvK/CXpO+BBREEqrTkNroC+A=="
+ },
+ "node_modules/type-fest": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
+ "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/type-is": {
+ "version": "1.6.18",
+ "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
+ "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
+ "dependencies": {
+ "media-typer": "0.3.0",
+ "mime-types": "~2.1.24"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/typedarray": {
+ "version": "0.0.6",
+ "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
+ "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==",
+ "optional": true
+ },
+ "node_modules/typedarray-to-buffer": {
+ "version": "3.1.5",
+ "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz",
+ "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==",
+ "dependencies": {
+ "is-typedarray": "^1.0.0"
+ }
+ },
+ "node_modules/unique-string": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz",
+ "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==",
+ "dependencies": {
+ "crypto-random-string": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/universalify": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
+ "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==",
+ "engines": {
+ "node": ">= 10.0.0"
+ }
+ },
+ "node_modules/unpipe": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+ "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/update-notifier": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-5.1.0.tgz",
+ "integrity": "sha512-ItnICHbeMh9GqUy31hFPrD1kcuZ3rpxDZbf4KUDavXwS0bW5m7SLbDQpGX3UYr072cbrF5hFUs3r5tUsPwjfHw==",
+ "dependencies": {
+ "boxen": "^5.0.0",
+ "chalk": "^4.1.0",
+ "configstore": "^5.0.1",
+ "has-yarn": "^2.1.0",
+ "import-lazy": "^2.1.0",
+ "is-ci": "^2.0.0",
+ "is-installed-globally": "^0.4.0",
+ "is-npm": "^5.0.0",
+ "is-yarn-global": "^0.3.0",
+ "latest-version": "^5.1.0",
+ "pupa": "^2.1.1",
+ "semver": "^7.3.4",
+ "semver-diff": "^3.1.1",
+ "xdg-basedir": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/yeoman/update-notifier?sponsor=1"
+ }
+ },
+ "node_modules/url-parse-lax": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz",
+ "integrity": "sha512-NjFKA0DidqPa5ciFcSrXnAltTtzz84ogy+NebPvfEgAck0+TNg4UJ4IN+fB7zRZfbgUf0syOo9MDxFkDSMuFaQ==",
+ "dependencies": {
+ "prepend-http": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
+ "optional": true
+ },
+ "node_modules/utils-merge": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
+ "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==",
+ "engines": {
+ "node": ">= 0.4.0"
+ }
+ },
+ "node_modules/vary": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+ "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/widest-line": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz",
+ "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==",
+ "dependencies": {
+ "string-width": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/wrap-ansi": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+ "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+ "dependencies": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+ }
+ },
+ "node_modules/wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
+ },
+ "node_modules/write-file-atomic": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz",
+ "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==",
+ "dependencies": {
+ "imurmurhash": "^0.1.4",
+ "is-typedarray": "^1.0.0",
+ "signal-exit": "^3.0.2",
+ "typedarray-to-buffer": "^3.1.5"
+ }
+ },
+ "node_modules/ws": {
+ "version": "7.5.9",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz",
+ "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==",
+ "engines": {
+ "node": ">=8.3.0"
+ },
+ "peerDependencies": {
+ "bufferutil": "^4.0.1",
+ "utf-8-validate": "^5.0.2"
+ },
+ "peerDependenciesMeta": {
+ "bufferutil": {
+ "optional": true
+ },
+ "utf-8-validate": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/xdg-basedir": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz",
+ "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/yallist": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
+ },
+ "node_modules/yaml-front-matter": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/yaml-front-matter/-/yaml-front-matter-4.1.1.tgz",
+ "integrity": "sha512-ULGbghCLsN8Hs8vfExlqrJIe8Hl2TUjD7/zsIGMP8U+dgRXEsDXk4yydxeZJgdGiimP1XB7zhmhOB4/HyfqOyQ==",
+ "dependencies": {
+ "commander": "^6.2.0",
+ "js-yaml": "^3.14.1"
+ },
+ "bin": {
+ "yaml-front-matter": "bin/js-yaml-front.js"
+ }
+ },
+ "node_modules/yargs-parser": {
+ "version": "21.1.1",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
+ "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/yauzl": {
+ "version": "2.10.0",
+ "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
+ "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==",
+ "optional": true,
+ "dependencies": {
+ "buffer-crc32": "~0.2.3",
+ "fd-slicer": "~1.1.0"
+ }
+ }
+ },
+ "dependencies": {
+ "@sindresorhus/is": {
+ "version": "0.14.0",
+ "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz",
+ "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ=="
+ },
+ "@szmarczak/http-timer": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz",
+ "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==",
+ "requires": {
+ "defer-to-connect": "^1.0.1"
+ }
+ },
+ "accepts": {
+ "version": "1.3.8",
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
+ "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
+ "requires": {
+ "mime-types": "~2.1.34",
+ "negotiator": "0.6.3"
+ }
+ },
+ "agent-base": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz",
+ "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==",
+ "optional": true,
+ "requires": {
+ "es6-promisify": "^5.0.0"
+ }
+ },
+ "ansi-align": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz",
+ "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==",
+ "requires": {
+ "string-width": "^4.1.0"
+ }
+ },
+ "ansi-regex": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="
+ },
+ "ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "requires": {
+ "color-convert": "^2.0.1"
+ }
+ },
+ "anymatch": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+ "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
+ "requires": {
+ "normalize-path": "^3.0.0",
+ "picomatch": "^2.0.4"
+ }
+ },
+ "argparse": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+ "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+ "requires": {
+ "sprintf-js": "~1.0.2"
+ }
+ },
+ "array-flatten": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
+ "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="
+ },
+ "async-limiter": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz",
+ "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==",
+ "optional": true
+ },
+ "balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
+ },
+ "binary-extensions": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
+ "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA=="
+ },
+ "body-parser": {
+ "version": "1.20.1",
+ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz",
+ "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==",
+ "requires": {
+ "bytes": "3.1.2",
+ "content-type": "~1.0.4",
+ "debug": "2.6.9",
+ "depd": "2.0.0",
+ "destroy": "1.2.0",
+ "http-errors": "2.0.0",
+ "iconv-lite": "0.4.24",
+ "on-finished": "2.4.1",
+ "qs": "6.11.0",
+ "raw-body": "2.5.1",
+ "type-is": "~1.6.18",
+ "unpipe": "1.0.0"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
+ }
+ }
+ },
+ "boxen": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz",
+ "integrity": "sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==",
+ "requires": {
+ "ansi-align": "^3.0.0",
+ "camelcase": "^6.2.0",
+ "chalk": "^4.1.0",
+ "cli-boxes": "^2.2.1",
+ "string-width": "^4.2.2",
+ "type-fest": "^0.20.2",
+ "widest-line": "^3.1.0",
+ "wrap-ansi": "^7.0.0"
+ }
+ },
+ "brace-expansion": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+ "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+ "requires": {
+ "balanced-match": "^1.0.0"
+ }
+ },
+ "braces": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
+ "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+ "requires": {
+ "fill-range": "^7.0.1"
+ }
+ },
+ "buffer-crc32": {
+ "version": "0.2.13",
+ "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
+ "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==",
+ "optional": true
+ },
+ "buffer-from": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
+ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
+ "optional": true
+ },
+ "bytes": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
+ "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="
+ },
+ "cacheable-request": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz",
+ "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==",
+ "requires": {
+ "clone-response": "^1.0.2",
+ "get-stream": "^5.1.0",
+ "http-cache-semantics": "^4.0.0",
+ "keyv": "^3.0.0",
+ "lowercase-keys": "^2.0.0",
+ "normalize-url": "^4.1.0",
+ "responselike": "^1.0.2"
+ },
+ "dependencies": {
+ "get-stream": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
+ "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
+ "requires": {
+ "pump": "^3.0.0"
+ }
+ },
+ "lowercase-keys": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz",
+ "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA=="
+ }
+ }
+ },
+ "call-bind": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
+ "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
+ "requires": {
+ "function-bind": "^1.1.1",
+ "get-intrinsic": "^1.0.2"
+ }
+ },
+ "camelcase": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
+ "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA=="
+ },
+ "chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "requires": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ }
+ },
+ "chokidar": {
+ "version": "3.5.3",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
+ "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
+ "requires": {
+ "anymatch": "~3.1.2",
+ "braces": "~3.0.2",
+ "fsevents": "~2.3.2",
+ "glob-parent": "~5.1.2",
+ "is-binary-path": "~2.1.0",
+ "is-glob": "~4.0.1",
+ "normalize-path": "~3.0.0",
+ "readdirp": "~3.6.0"
+ }
+ },
+ "ci-info": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz",
+ "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ=="
+ },
+ "cli-boxes": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz",
+ "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw=="
+ },
+ "clone-response": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz",
+ "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==",
+ "requires": {
+ "mimic-response": "^1.0.0"
+ }
+ },
+ "color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "requires": {
+ "color-name": "~1.1.4"
+ }
+ },
+ "color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
+ },
+ "commander": {
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz",
+ "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA=="
+ },
+ "concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
+ "optional": true
+ },
+ "concat-stream": {
+ "version": "1.6.2",
+ "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
+ "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
+ "optional": true,
+ "requires": {
+ "buffer-from": "^1.0.0",
+ "inherits": "^2.0.3",
+ "readable-stream": "^2.2.2",
+ "typedarray": "^0.0.6"
+ }
+ },
+ "configstore": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz",
+ "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==",
+ "requires": {
+ "dot-prop": "^5.2.0",
+ "graceful-fs": "^4.1.2",
+ "make-dir": "^3.0.0",
+ "unique-string": "^2.0.0",
+ "write-file-atomic": "^3.0.0",
+ "xdg-basedir": "^4.0.0"
+ }
+ },
+ "content-disposition": {
+ "version": "0.5.4",
+ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
+ "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
+ "requires": {
+ "safe-buffer": "5.2.1"
+ }
+ },
+ "content-type": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
+ "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA=="
+ },
+ "cookie": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
+ "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw=="
+ },
+ "cookie-signature": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
+ "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
+ },
+ "core-util-is": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
+ "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
+ "optional": true
+ },
+ "crypto-random-string": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz",
+ "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA=="
+ },
+ "debug": {
+ "version": "4.3.4",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
+ "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
+ "requires": {
+ "ms": "2.1.2"
+ }
+ },
+ "decompress-response": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz",
+ "integrity": "sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==",
+ "requires": {
+ "mimic-response": "^1.0.0"
+ }
+ },
+ "deep-extend": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
+ "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA=="
+ },
+ "defer-to-connect": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz",
+ "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ=="
+ },
+ "define-lazy-prop": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz",
+ "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og=="
+ },
+ "depd": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+ "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="
+ },
+ "destroy": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
+ "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg=="
+ },
+ "dot-prop": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz",
+ "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==",
+ "requires": {
+ "is-obj": "^2.0.0"
+ }
+ },
+ "duplexer3": {
+ "version": "0.1.5",
+ "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.5.tgz",
+ "integrity": "sha512-1A8za6ws41LQgv9HrE/66jyC5yuSjQ3L/KOpFtoBilsAK2iA2wuS5rTt1OCzIvtS2V7nVmedsUU+DGRcjBmOYA=="
+ },
+ "ee-first": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
+ },
+ "emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
+ },
+ "encodeurl": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
+ "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w=="
+ },
+ "end-of-stream": {
+ "version": "1.4.4",
+ "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
+ "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
+ "requires": {
+ "once": "^1.4.0"
+ }
+ },
+ "es6-promise": {
+ "version": "4.2.8",
+ "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz",
+ "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==",
+ "optional": true
+ },
+ "es6-promisify": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz",
+ "integrity": "sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==",
+ "optional": true,
+ "requires": {
+ "es6-promise": "^4.0.3"
+ }
+ },
+ "escape-goat": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz",
+ "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q=="
+ },
+ "escape-html": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+ "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="
+ },
+ "esprima": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
+ },
+ "etag": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+ "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="
+ },
+ "express": {
+ "version": "4.18.2",
+ "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz",
+ "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==",
+ "requires": {
+ "accepts": "~1.3.8",
+ "array-flatten": "1.1.1",
+ "body-parser": "1.20.1",
+ "content-disposition": "0.5.4",
+ "content-type": "~1.0.4",
+ "cookie": "0.5.0",
+ "cookie-signature": "1.0.6",
+ "debug": "2.6.9",
+ "depd": "2.0.0",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "finalhandler": "1.2.0",
+ "fresh": "0.5.2",
+ "http-errors": "2.0.0",
+ "merge-descriptors": "1.0.1",
+ "methods": "~1.1.2",
+ "on-finished": "2.4.1",
+ "parseurl": "~1.3.3",
+ "path-to-regexp": "0.1.7",
+ "proxy-addr": "~2.0.7",
+ "qs": "6.11.0",
+ "range-parser": "~1.2.1",
+ "safe-buffer": "5.2.1",
+ "send": "0.18.0",
+ "serve-static": "1.15.0",
+ "setprototypeof": "1.2.0",
+ "statuses": "2.0.1",
+ "type-is": "~1.6.18",
+ "utils-merge": "1.0.1",
+ "vary": "~1.1.2"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
+ }
+ }
+ },
+ "extract-zip": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.7.0.tgz",
+ "integrity": "sha512-xoh5G1W/PB0/27lXgMQyIhP5DSY/LhoCsOyZgb+6iMmRtCwVBo55uKaMoEYrDCKQhWvqEip5ZPKAc6eFNyf/MA==",
+ "optional": true,
+ "requires": {
+ "concat-stream": "^1.6.2",
+ "debug": "^2.6.9",
+ "mkdirp": "^0.5.4",
+ "yauzl": "^2.10.0"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "optional": true,
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+ "optional": true
+ }
+ }
+ },
+ "fd-slicer": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
+ "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==",
+ "optional": true,
+ "requires": {
+ "pend": "~1.2.0"
+ }
+ },
+ "fill-range": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
+ "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+ "requires": {
+ "to-regex-range": "^5.0.1"
+ }
+ },
+ "finalhandler": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
+ "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==",
+ "requires": {
+ "debug": "2.6.9",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "on-finished": "2.4.1",
+ "parseurl": "~1.3.3",
+ "statuses": "2.0.1",
+ "unpipe": "~1.0.0"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
+ }
+ }
+ },
+ "forwarded": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
+ "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="
+ },
+ "fresh": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
+ "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q=="
+ },
+ "fs-extra": {
+ "version": "11.1.0",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.0.tgz",
+ "integrity": "sha512-0rcTq621PD5jM/e0a3EJoGC/1TC5ZBCERW82LQuwfGnCa1V8w7dpYH1yNu+SLb6E5dkeCBzKEyLGlFrnr+dUyw==",
+ "requires": {
+ "graceful-fs": "^4.2.0",
+ "jsonfile": "^6.0.1",
+ "universalify": "^2.0.0"
+ }
+ },
+ "fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
+ },
+ "fsevents": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
+ "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
+ "optional": true
+ },
+ "function-bind": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
+ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
+ },
+ "get-intrinsic": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz",
+ "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==",
+ "requires": {
+ "function-bind": "^1.1.1",
+ "has": "^1.0.3",
+ "has-symbols": "^1.0.3"
+ }
+ },
+ "get-stream": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
+ "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==",
+ "requires": {
+ "pump": "^3.0.0"
+ }
+ },
+ "glob": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz",
+ "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==",
+ "requires": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^5.0.1",
+ "once": "^1.3.0"
+ }
+ },
+ "glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "requires": {
+ "is-glob": "^4.0.1"
+ }
+ },
+ "global-dirs": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.1.tgz",
+ "integrity": "sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==",
+ "requires": {
+ "ini": "2.0.0"
+ }
+ },
+ "got": {
+ "version": "9.6.0",
+ "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz",
+ "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==",
+ "requires": {
+ "@sindresorhus/is": "^0.14.0",
+ "@szmarczak/http-timer": "^1.1.2",
+ "cacheable-request": "^6.0.0",
+ "decompress-response": "^3.3.0",
+ "duplexer3": "^0.1.4",
+ "get-stream": "^4.1.0",
+ "lowercase-keys": "^1.0.1",
+ "mimic-response": "^1.0.1",
+ "p-cancelable": "^1.0.0",
+ "to-readable-stream": "^1.0.0",
+ "url-parse-lax": "^3.0.0"
+ }
+ },
+ "graceful-fs": {
+ "version": "4.2.11",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
+ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="
+ },
+ "has": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
+ "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
+ "requires": {
+ "function-bind": "^1.1.1"
+ }
+ },
+ "has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
+ },
+ "has-symbols": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
+ "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A=="
+ },
+ "has-yarn": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz",
+ "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw=="
+ },
+ "highlight.js": {
+ "version": "11.7.0",
+ "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.7.0.tgz",
+ "integrity": "sha512-1rRqesRFhMO/PRF+G86evnyJkCgaZFOI+Z6kdj15TA18funfoqJXvgPCLSf0SWq3SRfg1j3HlDs8o4s3EGq1oQ=="
+ },
+ "http-cache-semantics": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz",
+ "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ=="
+ },
+ "http-errors": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
+ "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
+ "requires": {
+ "depd": "2.0.0",
+ "inherits": "2.0.4",
+ "setprototypeof": "1.2.0",
+ "statuses": "2.0.1",
+ "toidentifier": "1.0.1"
+ }
+ },
+ "https-proxy-agent": {
+ "version": "2.2.4",
+ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz",
+ "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==",
+ "optional": true,
+ "requires": {
+ "agent-base": "^4.3.0",
+ "debug": "^3.1.0"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "3.2.7",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+ "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
+ "optional": true,
+ "requires": {
+ "ms": "^2.1.1"
+ }
+ }
+ }
+ },
+ "iconv-lite": {
+ "version": "0.4.24",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+ "requires": {
+ "safer-buffer": ">= 2.1.2 < 3"
+ }
+ },
+ "import-lazy": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz",
+ "integrity": "sha512-m7ZEHgtw69qOGw+jwxXkHlrlIPdTGkyh66zXZ1ajZbxkDBNjSY/LGbmjc7h0s2ELsUDTAhFr55TrPSSqJGPG0A=="
+ },
+ "imurmurhash": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+ "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="
+ },
+ "inflight": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
+ "requires": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
+ },
+ "ini": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz",
+ "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA=="
+ },
+ "ipaddr.js": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
+ "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="
+ },
+ "is-binary-path": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+ "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+ "requires": {
+ "binary-extensions": "^2.0.0"
+ }
+ },
+ "is-ci": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz",
+ "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==",
+ "requires": {
+ "ci-info": "^2.0.0"
+ }
+ },
+ "is-docker": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz",
+ "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ=="
+ },
+ "is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="
+ },
+ "is-fullwidth-code-point": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="
+ },
+ "is-glob": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+ "requires": {
+ "is-extglob": "^2.1.1"
+ }
+ },
+ "is-installed-globally": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz",
+ "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==",
+ "requires": {
+ "global-dirs": "^3.0.0",
+ "is-path-inside": "^3.0.2"
+ }
+ },
+ "is-npm": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-5.0.0.tgz",
+ "integrity": "sha512-WW/rQLOazUq+ST/bCAVBp/2oMERWLsR7OrKyt052dNDk4DHcDE0/7QSXITlmi+VBcV13DfIbysG3tZJm5RfdBA=="
+ },
+ "is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="
+ },
+ "is-obj": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz",
+ "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w=="
+ },
+ "is-path-inside": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
+ "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ=="
+ },
+ "is-typedarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
+ "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA=="
+ },
+ "is-wsl": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz",
+ "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==",
+ "requires": {
+ "is-docker": "^2.0.0"
+ }
+ },
+ "is-yarn-global": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz",
+ "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw=="
+ },
+ "isarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+ "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
+ "optional": true
+ },
+ "js-yaml": {
+ "version": "3.14.1",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
+ "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
+ "requires": {
+ "argparse": "^1.0.7",
+ "esprima": "^4.0.0"
+ }
+ },
+ "json-buffer": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz",
+ "integrity": "sha512-CuUqjv0FUZIdXkHPI8MezCnFCdaTAacej1TZYulLoAg1h/PhwkdXFN4V/gzY4g+fMBCOV2xF+rp7t2XD2ns/NQ=="
+ },
+ "jsonfile": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
+ "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
+ "requires": {
+ "graceful-fs": "^4.1.6",
+ "universalify": "^2.0.0"
+ }
+ },
+ "keyv": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz",
+ "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==",
+ "requires": {
+ "json-buffer": "3.0.0"
+ }
+ },
+ "latest-version": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz",
+ "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==",
+ "requires": {
+ "package-json": "^6.3.0"
+ }
+ },
+ "livereload": {
+ "version": "0.9.3",
+ "resolved": "https://registry.npmjs.org/livereload/-/livereload-0.9.3.tgz",
+ "integrity": "sha512-q7Z71n3i4X0R9xthAryBdNGVGAO2R5X+/xXpmKeuPMrteg+W2U8VusTKV3YiJbXZwKsOlFlHe+go6uSNjfxrZw==",
+ "requires": {
+ "chokidar": "^3.5.0",
+ "livereload-js": "^3.3.1",
+ "opts": ">= 1.2.0",
+ "ws": "^7.4.3"
+ }
+ },
+ "livereload-js": {
+ "version": "3.4.1",
+ "resolved": "https://registry.npmjs.org/livereload-js/-/livereload-js-3.4.1.tgz",
+ "integrity": "sha512-5MP0uUeVCec89ZbNOT/i97Mc+q3SxXmiUGhRFOTmhrGPn//uWVQdCvcLJDy64MSBR5MidFdOR7B9viumoavy6g=="
+ },
+ "lodash": {
+ "version": "4.17.21",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
+ },
+ "lowercase-keys": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz",
+ "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA=="
+ },
+ "lru-cache": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+ "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+ "requires": {
+ "yallist": "^4.0.0"
+ }
+ },
+ "make-dir": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
+ "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
+ "requires": {
+ "semver": "^6.0.0"
+ },
+ "dependencies": {
+ "semver": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
+ }
+ }
+ },
+ "media-typer": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
+ "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ=="
+ },
+ "merge-descriptors": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
+ "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w=="
+ },
+ "methods": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
+ "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w=="
+ },
+ "mime": {
+ "version": "2.6.0",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz",
+ "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==",
+ "optional": true
+ },
+ "mime-db": {
+ "version": "1.52.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+ "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="
+ },
+ "mime-types": {
+ "version": "2.1.35",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+ "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+ "requires": {
+ "mime-db": "1.52.0"
+ }
+ },
+ "mimic-response": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz",
+ "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ=="
+ },
+ "minimatch": {
+ "version": "5.1.6",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
+ "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
+ "requires": {
+ "brace-expansion": "^2.0.1"
+ }
+ },
+ "minimist": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
+ "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="
+ },
+ "mkdirp": {
+ "version": "0.5.6",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
+ "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
+ "optional": true,
+ "requires": {
+ "minimist": "^1.2.6"
+ }
+ },
+ "ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+ },
+ "mustache": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz",
+ "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ=="
+ },
+ "negotiator": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
+ "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="
+ },
+ "normalize-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="
+ },
+ "normalize-url": {
+ "version": "4.5.1",
+ "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz",
+ "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA=="
+ },
+ "object-inspect": {
+ "version": "1.12.3",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz",
+ "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g=="
+ },
+ "on-finished": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
+ "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
+ "requires": {
+ "ee-first": "1.1.1"
+ }
+ },
+ "once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+ "requires": {
+ "wrappy": "1"
+ }
+ },
+ "open": {
+ "version": "8.4.2",
+ "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz",
+ "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==",
+ "requires": {
+ "define-lazy-prop": "^2.0.0",
+ "is-docker": "^2.1.1",
+ "is-wsl": "^2.2.0"
+ }
+ },
+ "opts": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/opts/-/opts-2.0.2.tgz",
+ "integrity": "sha512-k41FwbcLnlgnFh69f4qdUfvDQ+5vaSDnVPFI/y5XuhKRq97EnVVneO9F1ESVCdiVu4fCS2L8usX3mU331hB7pg=="
+ },
+ "p-cancelable": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz",
+ "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw=="
+ },
+ "package-json": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz",
+ "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==",
+ "requires": {
+ "got": "^9.6.0",
+ "registry-auth-token": "^4.0.0",
+ "registry-url": "^5.0.0",
+ "semver": "^6.2.0"
+ },
+ "dependencies": {
+ "semver": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
+ }
+ }
+ },
+ "parseurl": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+ "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="
+ },
+ "path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
+ "optional": true
+ },
+ "path-to-regexp": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
+ "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ=="
+ },
+ "pend": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
+ "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==",
+ "optional": true
+ },
+ "picomatch": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="
+ },
+ "prepend-http": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz",
+ "integrity": "sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA=="
+ },
+ "process-nextick-args": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
+ "optional": true
+ },
+ "progress": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
+ "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
+ "optional": true
+ },
+ "proxy-addr": {
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
+ "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
+ "requires": {
+ "forwarded": "0.2.0",
+ "ipaddr.js": "1.9.1"
+ }
+ },
+ "proxy-from-env": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
+ "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
+ "optional": true
+ },
+ "pump": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
+ "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
+ "requires": {
+ "end-of-stream": "^1.1.0",
+ "once": "^1.3.1"
+ }
+ },
+ "pupa": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz",
+ "integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==",
+ "requires": {
+ "escape-goat": "^2.0.0"
+ }
+ },
+ "puppeteer": {
+ "version": "1.20.0",
+ "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-1.20.0.tgz",
+ "integrity": "sha512-bt48RDBy2eIwZPrkgbcwHtb51mj2nKvHOPMaSH2IsWiv7lOG9k9zhaRzpDZafrk05ajMc3cu+lSQYYOfH2DkVQ==",
+ "optional": true,
+ "requires": {
+ "debug": "^4.1.0",
+ "extract-zip": "^1.6.6",
+ "https-proxy-agent": "^2.2.1",
+ "mime": "^2.0.3",
+ "progress": "^2.0.1",
+ "proxy-from-env": "^1.0.0",
+ "rimraf": "^2.6.1",
+ "ws": "^6.1.0"
+ },
+ "dependencies": {
+ "ws": {
+ "version": "6.2.2",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.2.tgz",
+ "integrity": "sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw==",
+ "optional": true,
+ "requires": {
+ "async-limiter": "~1.0.0"
+ }
+ }
+ }
+ },
+ "qs": {
+ "version": "6.11.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
+ "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
+ "requires": {
+ "side-channel": "^1.0.4"
+ }
+ },
+ "range-parser": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
+ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="
+ },
+ "raw-body": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
+ "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
+ "requires": {
+ "bytes": "3.1.2",
+ "http-errors": "2.0.0",
+ "iconv-lite": "0.4.24",
+ "unpipe": "1.0.0"
+ }
+ },
+ "rc": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
+ "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
+ "requires": {
+ "deep-extend": "^0.6.0",
+ "ini": "~1.3.0",
+ "minimist": "^1.2.0",
+ "strip-json-comments": "~2.0.1"
+ },
+ "dependencies": {
+ "ini": {
+ "version": "1.3.8",
+ "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
+ "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="
+ }
+ }
+ },
+ "readable-stream": {
+ "version": "2.3.8",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
+ "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
+ "optional": true,
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ },
+ "dependencies": {
+ "safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+ "optional": true
+ }
+ }
+ },
+ "readdirp": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+ "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+ "requires": {
+ "picomatch": "^2.2.1"
+ }
+ },
+ "registry-auth-token": {
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.2.tgz",
+ "integrity": "sha512-PC5ZysNb42zpFME6D/XlIgtNGdTl8bBOCw90xQLVMpzuuubJKYDWFAEuUNc+Cn8Z8724tg2SDhDRrkVEsqfDMg==",
+ "requires": {
+ "rc": "1.2.8"
+ }
+ },
+ "registry-url": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz",
+ "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==",
+ "requires": {
+ "rc": "^1.2.8"
+ }
+ },
+ "responselike": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz",
+ "integrity": "sha512-/Fpe5guzJk1gPqdJLJR5u7eG/gNY4nImjbRDaVWVMRhne55TCmj2i9Q+54PBRfatRC8v/rIiv9BN0pMd9OV5EQ==",
+ "requires": {
+ "lowercase-keys": "^1.0.0"
+ }
+ },
+ "reveal-md": {
+ "version": "5.4.1",
+ "resolved": "https://registry.npmjs.org/reveal-md/-/reveal-md-5.4.1.tgz",
+ "integrity": "sha512-pSNiE7ryND/yopuIktKaESTahSMPI2dLPIYLUCAksan6M4v8V5b1GjDaFCgF1wC0qcTZqUS34I8HBYoMStb/AQ==",
+ "requires": {
+ "debug": "4.3.4",
+ "express": "4.18.2",
+ "fs-extra": "11.1.0",
+ "glob": "8.1.0",
+ "highlight.js": "11.7.0",
+ "livereload": "0.9.3",
+ "lodash": "4.17.21",
+ "mustache": "4.2.0",
+ "open": "8.4.2",
+ "puppeteer": "1.20.0",
+ "reveal.js": "4.4.0",
+ "serve-favicon": "2.5.0",
+ "try-require": "1.2.1",
+ "update-notifier": "5.1.0",
+ "yaml-front-matter": "4.1.1",
+ "yargs-parser": "21.1.1"
+ }
+ },
+ "reveal.js": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/reveal.js/-/reveal.js-4.4.0.tgz",
+ "integrity": "sha512-jIV6C9V2NEUjGzU8L6dUFGpk1KJmq7/EzP2fOW67ggc2c0Cp/PdprWxZ9Qgp46F0T2ZWDCjQ1p3Ytzy5jA6a2w=="
+ },
+ "rimraf": {
+ "version": "2.7.1",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
+ "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
+ "optional": true,
+ "requires": {
+ "glob": "^7.1.3"
+ },
+ "dependencies": {
+ "brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "optional": true,
+ "requires": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "glob": {
+ "version": "7.2.3",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+ "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+ "optional": true,
+ "requires": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.1.1",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ },
+ "minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "optional": true,
+ "requires": {
+ "brace-expansion": "^1.1.7"
+ }
+ }
+ }
+ },
+ "safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
+ },
+ "safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
+ },
+ "semver": {
+ "version": "7.3.8",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
+ "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
+ "requires": {
+ "lru-cache": "^6.0.0"
+ }
+ },
+ "semver-diff": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz",
+ "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==",
+ "requires": {
+ "semver": "^6.3.0"
+ },
+ "dependencies": {
+ "semver": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
+ }
+ }
+ },
+ "send": {
+ "version": "0.18.0",
+ "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
+ "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
+ "requires": {
+ "debug": "2.6.9",
+ "depd": "2.0.0",
+ "destroy": "1.2.0",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "fresh": "0.5.2",
+ "http-errors": "2.0.0",
+ "mime": "1.6.0",
+ "ms": "2.1.3",
+ "on-finished": "2.4.1",
+ "range-parser": "~1.2.1",
+ "statuses": "2.0.1"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "requires": {
+ "ms": "2.0.0"
+ },
+ "dependencies": {
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
+ }
+ }
+ },
+ "mime": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+ "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="
+ },
+ "ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
+ }
+ }
+ },
+ "serve-favicon": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/serve-favicon/-/serve-favicon-2.5.0.tgz",
+ "integrity": "sha512-FMW2RvqNr03x+C0WxTyu6sOv21oOjkq5j8tjquWccwa6ScNyGFOGJVpuS1NmTVGBAHS07xnSKotgf2ehQmf9iA==",
+ "requires": {
+ "etag": "~1.8.1",
+ "fresh": "0.5.2",
+ "ms": "2.1.1",
+ "parseurl": "~1.3.2",
+ "safe-buffer": "5.1.1"
+ },
+ "dependencies": {
+ "ms": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
+ "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
+ },
+ "safe-buffer": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
+ "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg=="
+ }
+ }
+ },
+ "serve-static": {
+ "version": "1.15.0",
+ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz",
+ "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==",
+ "requires": {
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "parseurl": "~1.3.3",
+ "send": "0.18.0"
+ }
+ },
+ "setprototypeof": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
+ "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
+ },
+ "side-channel": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
+ "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
+ "requires": {
+ "call-bind": "^1.0.0",
+ "get-intrinsic": "^1.0.2",
+ "object-inspect": "^1.9.0"
+ }
+ },
+ "signal-exit": {
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
+ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="
+ },
+ "sprintf-js": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+ "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g=="
+ },
+ "statuses": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
+ "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="
+ },
+ "string_decoder": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "optional": true,
+ "requires": {
+ "safe-buffer": "~5.1.0"
+ },
+ "dependencies": {
+ "safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+ "optional": true
+ }
+ }
+ },
+ "string-width": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+ "requires": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.1"
+ }
+ },
+ "strip-ansi": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "requires": {
+ "ansi-regex": "^5.0.1"
+ }
+ },
+ "strip-json-comments": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
+ "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ=="
+ },
+ "supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "requires": {
+ "has-flag": "^4.0.0"
+ }
+ },
+ "to-readable-stream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz",
+ "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q=="
+ },
+ "to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "requires": {
+ "is-number": "^7.0.0"
+ }
+ },
+ "toidentifier": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
+ "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="
+ },
+ "try-require": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/try-require/-/try-require-1.2.1.tgz",
+ "integrity": "sha512-aMzrGUIA/R2LwUgvsOusx+GTy8ERyNjpBzbWgS1Qx4oTFlXCMxY3PyyXbPE1pvrvK/CXpO+BBREEqrTkNroC+A=="
+ },
+ "type-fest": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
+ "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ=="
+ },
+ "type-is": {
+ "version": "1.6.18",
+ "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
+ "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
+ "requires": {
+ "media-typer": "0.3.0",
+ "mime-types": "~2.1.24"
+ }
+ },
+ "typedarray": {
+ "version": "0.0.6",
+ "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
+ "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==",
+ "optional": true
+ },
+ "typedarray-to-buffer": {
+ "version": "3.1.5",
+ "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz",
+ "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==",
+ "requires": {
+ "is-typedarray": "^1.0.0"
+ }
+ },
+ "unique-string": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz",
+ "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==",
+ "requires": {
+ "crypto-random-string": "^2.0.0"
+ }
+ },
+ "universalify": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
+ "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ=="
+ },
+ "unpipe": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+ "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="
+ },
+ "update-notifier": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-5.1.0.tgz",
+ "integrity": "sha512-ItnICHbeMh9GqUy31hFPrD1kcuZ3rpxDZbf4KUDavXwS0bW5m7SLbDQpGX3UYr072cbrF5hFUs3r5tUsPwjfHw==",
+ "requires": {
+ "boxen": "^5.0.0",
+ "chalk": "^4.1.0",
+ "configstore": "^5.0.1",
+ "has-yarn": "^2.1.0",
+ "import-lazy": "^2.1.0",
+ "is-ci": "^2.0.0",
+ "is-installed-globally": "^0.4.0",
+ "is-npm": "^5.0.0",
+ "is-yarn-global": "^0.3.0",
+ "latest-version": "^5.1.0",
+ "pupa": "^2.1.1",
+ "semver": "^7.3.4",
+ "semver-diff": "^3.1.1",
+ "xdg-basedir": "^4.0.0"
+ }
+ },
+ "url-parse-lax": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz",
+ "integrity": "sha512-NjFKA0DidqPa5ciFcSrXnAltTtzz84ogy+NebPvfEgAck0+TNg4UJ4IN+fB7zRZfbgUf0syOo9MDxFkDSMuFaQ==",
+ "requires": {
+ "prepend-http": "^2.0.0"
+ }
+ },
+ "util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
+ "optional": true
+ },
+ "utils-merge": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
+ "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA=="
+ },
+ "vary": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+ "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="
+ },
+ "widest-line": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz",
+ "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==",
+ "requires": {
+ "string-width": "^4.0.0"
+ }
+ },
+ "wrap-ansi": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+ "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+ "requires": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ }
+ },
+ "wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
+ },
+ "write-file-atomic": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz",
+ "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==",
+ "requires": {
+ "imurmurhash": "^0.1.4",
+ "is-typedarray": "^1.0.0",
+ "signal-exit": "^3.0.2",
+ "typedarray-to-buffer": "^3.1.5"
+ }
+ },
+ "ws": {
+ "version": "7.5.9",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz",
+ "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==",
+ "requires": {}
+ },
+ "xdg-basedir": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz",
+ "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q=="
+ },
+ "yallist": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
+ },
+ "yaml-front-matter": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/yaml-front-matter/-/yaml-front-matter-4.1.1.tgz",
+ "integrity": "sha512-ULGbghCLsN8Hs8vfExlqrJIe8Hl2TUjD7/zsIGMP8U+dgRXEsDXk4yydxeZJgdGiimP1XB7zhmhOB4/HyfqOyQ==",
+ "requires": {
+ "commander": "^6.2.0",
+ "js-yaml": "^3.14.1"
+ }
+ },
+ "yargs-parser": {
+ "version": "21.1.1",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
+ "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="
+ },
+ "yauzl": {
+ "version": "2.10.0",
+ "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
+ "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==",
+ "optional": true,
+ "requires": {
+ "buffer-crc32": "~0.2.3",
+ "fd-slicer": "~1.1.0"
+ }
+ }
+ }
+}
diff --git a/40-abschlusspraesentation/package.json b/40-abschlusspraesentation/package.json
new file mode 100644
index 0000000..612e8e1
--- /dev/null
+++ b/40-abschlusspraesentation/package.json
@@ -0,0 +1,23 @@
+{
+ "name": "abschlusspraesentation",
+ "version": "1.0.0",
+ "description": "## Getting started",
+ "main": "script.js",
+ "scripts": {
+ "build": "reveal-md presentatioin.md --static public --static-dirs assets",
+ "dev": "reveal-md presentation.md -w"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git+ssh://git@gitlab.com/pse-squared/abschlusspraesentation.git"
+ },
+ "author": "",
+ "license": "ISC",
+ "bugs": {
+ "url": "https://gitlab.com/pse-squared/abschlusspraesentation/issues"
+ },
+ "homepage": "https://gitlab.com/pse-squared/abschlusspraesentation#readme",
+ "dependencies": {
+ "reveal-md": "^5.4.1"
+ }
+}
diff --git a/40-abschlusspraesentation/presentation.md b/40-abschlusspraesentation/presentation.md
new file mode 100644
index 0000000..22b197a
--- /dev/null
+++ b/40-abschlusspraesentation/presentation.md
@@ -0,0 +1,222 @@
+---
+theme: white
+css:
+ - style.css
+ - assets/fontawesome/css/all.min.css
+scripts:
+ - script.js
+highlightTheme: base16/solarized-light
+revealOptions:
+ transition: 'slide'
+---
+
+<img src="assets/logo.svg" />
+<span style="font-size: 16px; line-height: 1 !important; color: #888; letter-spacing: -.5px; font-weight: light;">
+<br>
+M.Sc. Hans-Peter Lehmann,
+M.Sc. Daniel Seemaier <br>
+Daniel Hönlinger,
+Gero Beckmann,
+Immanuel Reitz,
+Julius Friesen,
+Lukas Schmidheissler
+</span>
+
+Note:
+- Guten Morgen + Herzlich Willkommen
+- Abschlusspräsentation
+- Praxis zur Software-Entwicklung
+- Podcast Synchronisatin made Efficient
+- PSE²
+- Wir sind
+
+---
+
+#### Übersicht
+
+<img style="width: 70%;" src="assets/component6.svg" />
+
+Note:
+- Podcast Sync Server
+- Podcatcher syncen Abos + Hörfortschritte mit anderen Geräten
+- GPodder überfüllt
+- Server mit Spring, MariaDB
+- Metadaten von Podcast-Server
+- Mail
+- Frontend mit Vue, Bootstrap
+
+----
+### Anforderungen
+
+<div style="display: inline-block; text-align: left;">
+🚀 50 Anfragen/Sekunde<br>
+✉️ Registrieren per E-Mail<br>
+📰 Metadaten aus RSS <br>
+🔐 Persönliche Daten schützen<br>
+🔗 Kompatibilität mit GPodder<br>
+</div>
+
+---
+
+Klassendiagramm
+
+<div class="r-stack">
+ <img class="fragment" height="550" src="assets/diagrams/packageDiagram1.svg">
+ <img class="fragment" height="550" src="assets/diagrams/packageDiagram2.svg">
+ <img class="fragment" height="550" src="assets/diagrams/packageDiagram3.svg">
+ <img class="fragment" height="550" src="assets/diagrams/packageDiagram4.svg">
+</div>
+
+Note:
+- Schichtenmodell
+- HTTP-Anfrage
+- Controller parse
+- Service: Daten verarbeiten
+- DAO: Datenbank
+
+----
+
+Web-Komponenten
+
+<div class="r-stack">
+ <img class="fragment" src="assets/ui-components/layer1.png">
+ <img class="fragment" src="assets/ui-components/layer2.png">
+ <img class="fragment" src="assets/ui-components/layer3.png">
+ <img class="fragment" src="assets/ui-components/full.png">
+</div>
+
+Note:
+- Wiederverwendbare Komponenten.
+- Wie lang her? / Wie lange dauert?
+- Abonnement
+- Seite
+- Web-Anwendung
+
+---
+
+<img width="200px" src="assets/docker.webp" />
+<img width="200px" src="assets/gitlab.svg" />
+<img width="200px" src="assets/jmeter.svg" />
+<img width="200px" src="assets/latex.svg" />
+<img width="200px" src="assets/plantuml.svg" />
+<img width="200px" src="assets/lets-encrypt.svg" />
+<img width="200px" src="assets/checkstyle.png" />
+
+Note:
+- Neben Spring/Vue
+- Orga: GitLab (Issues)
+- Dokumenten-erstellung: LaTeX, PlantUML (Diagramme)
+- Analyse: Checkstyle, JMeter (Lasttest)
+- Deploy: Docker, Letsencrypt
+
+----
+<!-- .slide: data-background-image="assets/coffee.gif" -->
+
+# Koffein!!!
+
+Note:
+wie bei jedem PSE: dauert länger
+
+-> Kaffee / Mate Begleiter
+
+---
+<!-- .slide: data-auto-animate -->
+
+#### Das Projekt in Zahlen
+
+<pre data-id="code-animation"><code data-line-numbers="|3-4|6-7|9-10">
+class Statistics {
+ long SLOCDashboard = 2403;
+ long SLOCServer = 5986;
+
+ long commitsDashboard = 247;
+ long commitsServer = 435;
+
+ long filesDashboard = 38;
+ long filesServer = 72;
+}
+</code></pre>
+
+----
+<!-- .slide: data-auto-animate -->
+
+#### Das Projekt in Zahlen
+
+<pre data-id="code-animation"><code data-line-numbers="14-21">
+class Statistics {
+ long SLOCDashboard = 2403;
+ long SLOCServer = 5986;
+
+ long commitsDashboard = 247;
+ long commitsServer = 435;
+
+ long filesDashboard = 38;
+ long filesServer = 72;
+
+ long total(long a,b) { return a + b }
+
+ total(SLOCDashboard, SLOCServer);
+ total(commitsDashboard, commitsServer);
+ total(filesDashboard, filesServer);
+ /*
+ * SLOC Total: 8389
+ * commits Total: 687
+ * files Total: 110
+ */
+}
+
+</code></pre>
+
+----
+
+### Leistungsmessung
+
+<div style="display: flex; flex-direction: row; ">
+ <img style="flex-basis: 55%; flex-grow: 0; flex-shrink: 0; width: 40%;" src="assets/tachodiagramm.svg">
+ <div style="flex-basis: 45%; flex-grow: 0; flex-shrink: 0;">
+ <img src="assets/balken-old.svg">
+ <img src="assets/balken-optimized.svg">
+ </div>
+</div>
+
+Note:
+- Lasttest kategorisiern Requests in Wertebereiche
+- dual core erreicht Ziel nicht
+- mehr Kerne besser
+- Optimierungen nach Impl-Phase:
+- Docker, kompilieren zu JAR, Parameter
+
+----
+
+## Commit-Verlauf
+
+<img class="r-stretch" src="assets/commits.svg" />
+
+Note:
+- 3 Treffen/Woche
+- Klausurpausen
+- Längen Nächte zu Abgaben
+
+---
+
+## Fazit
+
+<div style="display: inline-block; text-align: left;">
+🌊 Wasserfallmodell mit Rückkopplung<br>
+✊ Mut für Neues<br>
+🗓️ Teamarbeit und Organisation<br>
+🧠 Lernerfahrung<br>
+
+
+Note:
+- Rückkopplung: Verbesserungen nach Abgabe
+- Mut: Komfortzone, Erfahrungen in Web-Entwicklung
+- Teamarbeit: 3 Treffen/Woche a 5 Std, Bib Buchen
+- Lernerfahrungen: LaTeX, Git, Web, Server/Domain aufsetzen, Docker
+- Vorschau
+
+</div>
+
+---
+<!-- .slide: data-background-iframe="http://pse-squared.de" data-background-interactive -->
+
diff --git a/40-abschlusspraesentation/script.js b/40-abschlusspraesentation/script.js
new file mode 100644
index 0000000..f7e7a9d
--- /dev/null
+++ b/40-abschlusspraesentation/script.js
@@ -0,0 +1,16 @@
+
+// setTimeout(function() {
+//
+// $(".boat").throwable({
+// containment: "parent",
+// impulse: {
+// f: 52,
+// p: {
+// x: Math.random(),
+// y: Math.random()
+// }
+// }
+// });
+//
+// }, 3000);
+
diff --git a/40-abschlusspraesentation/style.css b/40-abschlusspraesentation/style.css
new file mode 100644
index 0000000..58acdb6
--- /dev/null
+++ b/40-abschlusspraesentation/style.css
@@ -0,0 +1,29 @@
+.container {
+ display: inline-block;
+ vertical-align: top;
+ overflow: hidden;
+}
+.fragment.write-effect {
+ display: inline-block;
+ overflow: hidden;
+ border-right: .15em solid orange;
+ white-space: nowrap;
+ width: 0%;
+}
+
+.fragment.write-effect.visible {
+ animation: typing 1s forwards;
+}
+
+@keyframes typing {
+ from { width: 0% }
+ to { width: 100% }
+}
+#bubble-chart {
+ display: block;
+ position: absolute;
+ top: 0px;
+ left: 0px;
+ width: 100%;
+ height: 100%;
+}