diff --git a/.gitignore b/.gitignore index cc1aaa5..5561367 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ infoZettelOrg/*.pdf infoZettelOrg/aushang/*.pdf +infoZettelOrg/kyuZettel/*.pdf photoalben/ !photoalben/**/*.php diff --git a/coronaZeit/coronaNewsletterReceiverEmails.txt b/coronaZeit/coronaNewsletterReceiverEmails.txt new file mode 100644 index 0000000..0a1029b --- /dev/null +++ b/coronaZeit/coronaNewsletterReceiverEmails.txt @@ -0,0 +1,15 @@ +kenan.allejji@hotmail.com +churicnate@yahoo.com +alled82@gmx.de +j.felke@gmx.net +akf21182@aol.com +cathleen.fritsch@web.de +s.stohldreier@p-side.de +dani17184@web.de +mohamad.zahra1986@gmail.com +post@was7.de +soffienatall@gmail.com +rolfdaerr@gmx.de +stephanie.brittnacher@gmail.com +jana-roesch@gmx.at +nick.weidensager@web.de diff --git a/coronaZeit/mdNewsletter.d/2020-05-10-WiederaufnahmeTraining.md b/coronaZeit/mdNewsletter.d/2020-05-10-WiederaufnahmeTraining.md new file mode 100644 index 0000000..8a6b6f4 --- /dev/null +++ b/coronaZeit/mdNewsletter.d/2020-05-10-WiederaufnahmeTraining.md @@ -0,0 +1,71 @@ +--- +title: Wiederaufnahme des Trainings - cwsvJudoNewsletter-2020-05-10 +... + +*Sorry, falls diese Mail mehrfach ankommt. Es gab ein paar Probleme im +Verteiler* + +# Hallo an alle! + +Im Zuge der Lockerungen der Maßnahmen gegen die Ausbreitung Coronas ist +seit 04.05.2020 zumindest im **Freien**, in **kleinen Gruppen** und +**mit Abstand** ein Training wieder möglich. Dank Eurer Rückmeldungen +weiß ich, dass auch in unserer Gruppe das Interesse an einer +Wiederaufnahme des Trainings groß ist. + +Das Training der Judoka wird ab Fr., dem 15.05.2020, langsam wieder +angefahren. An dieser Stelle möchte ich das langsam besonders +hervorheben. Denn ein gewohntes Training wird es nicht sein. Es wird +alle Trainierende ein gewisses Maß an Selbstbeherrschung kosten, die +aufgestellten Regeln auch einzuhalten. Aber schließlich liegt uns der +Sport am Herzen, sodass es auch die Motivation gibt, sich daran zu +halten. Und auch auf die Einhaltung zu achten! Denn wenn es uns nicht +gelingt, unter den vorgegebenen Bedingungen zu trainieren, dann muss +- so leid es mir dann auch tut - die Konsequenz gezogen werden und das +Training wieder ausgesetzt werden. + +# Wie wird es am 15.05.2020 ablaufen + +Der 15.05.2020 wird ein Testlauf werden, ob es möglich ist unter den +erschwerenden Bedingungen ein Training durchzuführen. Wenn es uns nicht +gelingt, uns an die Rahmenbedingungen anzupassen, kann das Training +nicht wieder aufgenommen werden. + +- Um die Gruppengröße von Anfang an zu reduzieren, wird nach streng +nach Alter getrennt: + - Die Jahrgänge 2009 und jünger (U13 und jünger) trainieren von + 16:00-17:15 Uhr. + - Die Jahrgänge 2008 und älter (U15 aufwärts) trainieren von + 17:30-19:00 Uhr. +- Das Training wird draußen stattfinden. + - Es wird keine Umkleidemöglichkeit geben. Also bereits in + **wettergerechter** Trainingskleidung erscheinen. + - Bei schlechtem Wetter wird das Training nicht stattfinden. +- Das Training wird in Gruppen von max. 5 Leuten stattfinden + - D.h. ab 5 Personen werden die Leute in kleinere Gruppen mit + eigenem Übungsleiter aufgeteilt. Sollten nicht genügend + Übungsleiter vorhanden sein, müssen Leute vom Training + ausgeschlossen weren. +- Auf den Mindestabstand von 1,5 m und Trainingsabstand von 2 m wird +von allen Teilnehmenden geachtet. + - Das geht bereits vor dem Training los! Bitte nicht gesammelt in + einem Pulk auf dem Sportplatz warten. + - Auf Körperkontakt untereinander wird grudsätzlich verzichtet. +- Sportler, die zu "Risikogruppen" gehören (z.B. bei entsprechendem +Alter oder Vorerkrankungen) sollten eine Teilnahme am Training gut +überdenken. + - Zumindestens sollten sie den jeweiligen Übungsleiter informieren, + damit gegebenfalls zumindest der Sicherheitsabstand vergrößert + werden kann. + +Ich gehe davon aus, dass uns allen klar ist, dass es insbesondere für +die Kinder hart wird, sich sich an diese Rahmenbedingungen anzupassen. +Und auch, dass es vielleicht nicht alle schaffen. Noch dazu, wenn die +Lieblingsspiele im Trainingsplan fehlen. Die Alternative allerdings +wäre, wie bisher gar kein Training. Vor diesem Hintergrund habe ich +mich entschieden, es zumindest zu versuchen. + +Um Planen zu können, bitte ich dringend, mir mitzuteilen, wer am +15.05.2020 teilnimmt. + +MsG marko diff --git a/coronaZeit/mdNewsletter.d/2020-05-17-weitererTrainingsverlauf.md b/coronaZeit/mdNewsletter.d/2020-05-17-weitererTrainingsverlauf.md new file mode 100644 index 0000000..06138ad --- /dev/null +++ b/coronaZeit/mdNewsletter.d/2020-05-17-weitererTrainingsverlauf.md @@ -0,0 +1,35 @@ +--- +title: Weiterer Trainingsverlauf +--- + +Hallo an alle, + +nachdem der Probelauf am letzten Freitag (15.05.) ohne große +Zwischenfälle erfolgt ist, wird der nächste Trainingstag am Freitag, +den 22.05.2020 erfolgen. Die Rahmenbedingungen bleiben dieselben: + +- Das Training wird draußen stattfinden. +- Es wird keine Umkleidemöglichkeiten geben. + - Deshalb bereits in angemessener Trainingskleidung kommen. +- Es wird nach Jahrgängen getrennt: + - Die Jahrgänge 2009 und jünger (U13 und jünger) trainieren von + 16:00-17:15 Uhr. + - Die Jahrgänge 2008 und älter (U15 aufwärts) trainieren von + 17:30-19:00 Uhr. +- Trainiert wird in Gruppen von bis zu 5 Mann. + +Um im Fall der Fälle eine Nachverfolgung der Ansteckungswege zu +ermöglichen werde ich die Teilnahme am Training dokumentieren und bei +Anfrage den entsprechenden Behörden zur Verfügung stellen. + +Auch wenn theoretisch wieder drinnen trainiert werden kann, werden wir +das Training bis auf weiteres nach draußen verlegen, wo mehr Platz und +auch mehr frische Luft ist. + +Ab dem 27.05.2020 soll auch das Mittwochtraining wieder anlaufen. Um +dieses Training wie gewohnt für alle Altersklassen stattfinden zu +lassen, bräuchte ich allerdings Unterstützung, da das Training immer +nur in Gruppen von maximal 5 Man stattfinden kann. Deshalb hier die +Anfrage an unsere volljährigen Mitglieder, ob sie mich bei der Aufsicht +der kleineren Gruppen unterstützen können. + diff --git a/coronaZeit/mdNewsletter.d/2020-05-24-LangsamAberSicher.md b/coronaZeit/mdNewsletter.d/2020-05-24-LangsamAberSicher.md new file mode 100644 index 0000000..5411603 --- /dev/null +++ b/coronaZeit/mdNewsletter.d/2020-05-24-LangsamAberSicher.md @@ -0,0 +1,30 @@ +--- +title: Langsam aber sicher - coronaNewsletter-2020-05-24 +--- + +Nach dem Motto "langsam aber sicher" sind wir in den letzten beiden +Wochen zu einem regelmäßigen Trainingsbetrieb zurück gekehrt. Diese +Entwicklung wird in der nächsten Woche weiter geführt. Wir werden auch +das Mittwochtraining wieder anlaufen lassen, so dass sich die folgenden +Trainingszeiten ergeben: + +- Mittwoch 16:00-17:30 Uhr +- Freitag: + - 16:00-17:30 Uhr (Jahrgänge 2010 und jünger) + - 17:45-19:15 Uhr (Jahrgänge 2009 und älter) + +Das Training wird wegen besseren Platz- und Luftverhältnissen weiterhin +im Freien stattfinden. Nur bei zu schlechten Wetterverhältnissen werden +wir uns in das Dojo zurückziehen. Wegen schlechten Wetters ausfallen +lassen müssen wir das Training **nicht** mehr. + +Wir werden uns die meiste Zeit auf dem Rasen aufhalten und auch jede +Menge Übungen im Boden durchführen. Mit Grasflecken auf der +Trainingskleidung muss also gerechnet werden. + +Der Gürtel (Obi) wird einen wichtigen Bestandteil des Trainings bilden. +Deshalb ist es gut, wenn jeder seinen eigenen zum Training mitbringt. + +Aufgrund der beschränkten Platzverhältisse in den Umkleidekabinen wird +gebeten, bereits in Trainingskleidung zu erscheinen um das +Kleiderwechseln auf engem Raum zu vermeiden. diff --git a/coronaZeit/mdNewsletter.d/2020-10-30-LmachRekorde.md b/coronaZeit/mdNewsletter.d/2020-10-30-LmachRekorde.md new file mode 100644 index 0000000..4695f94 --- /dev/null +++ b/coronaZeit/mdNewsletter.d/2020-10-30-LmachRekorde.md @@ -0,0 +1,9 @@ +--- +title: Rekordjagd kann beginnen - coronaNewsletter-2020-11-31 +--- + +In unserem [kleinen "Achievement System"][1] können nun in den +einzelnen Kategorien Rekorde aufgestellt werden. + +[1]: http://cwsvjudo.bplaced.net/machs + diff --git a/coronaZeit/mdNewsletter.d/2020-10-30-LockdownDieZweite.md b/coronaZeit/mdNewsletter.d/2020-10-30-LockdownDieZweite.md new file mode 100644 index 0000000..c52fbd4 --- /dev/null +++ b/coronaZeit/mdNewsletter.d/2020-10-30-LockdownDieZweite.md @@ -0,0 +1,42 @@ +--- +title: Aussetzung des Trainingsbetriebes - coronaNewsletter-2020-10-31 +--- + +Der eine oder andere hat es bestimmt schon mitbekommen: Ab Montag, dem +02.10.2020 wird der Trainingsbetrieb vorerst ausgesetzt. Die vorerst +letzte Trainingseinheit findet am Sonntag, 01.11.2020 von 14-17:00 Uhr +statt. + +Zur Motivation, sich in dieser Zeit trotzdem sportlich zu betätigen, +habe ich unter ein [kleines "Achievement System"][1] zusammengebastelt. + +[1]: http://cwsvjudo.bplaced.net/machs + +Die Zugangsdaten sollten dieselben sein, wie für den Wettkampfplaner. +Wer noch keine hat, kann sich bei mir melden. + +In diesem sind kleine Herausforderungen gesammelt, die es zu meistern +gilt. Hat man eine Aufgabe geschafft, kann man dies (von den Eltern) im +Achievementsystem vermerken lassen und die nächste Stufe angehen. +Allerdings erst am nächsten Tag, denn täglich darf nur eine Aufgabe +eingetragen werden. (Fast) jede gelöste Aufgabe schaltet die +nächsthöhere Schwierigkeitsstufe frei. Bei einigen Aufgaben besteht die +Möglichkeit, einen Rekord aufzustellen. Von diesen hätte ich dann aber +gerne ein Video. + +Gerade in dieser Einzeltrainingszeit wäre es schön zu sehen, dass man +zwar getrennt, aber dennoch nicht alleine traininert. Deshalb wäre es +schön, mir immer wieder mal Bildmaterial von den Aufgaben zukommen zu +lassen. Ich würde davon gerne eine kleine Collage zusammenstellen. Für +den Upload von Bildern und Videos sollte bei jedem Judoka ein Link +(inklusive Passwort) zu einem Cloud Speicher. + +Wenn jemand Ideen und/oder Vorschläge für das Achievementsystem hat, +z.B. + +- neue Herausforderungen +- Gestaltung +- Bedienung + +hat, kann er die gerne an mich geben. Ich werde dannversuchen, es +möglichts zeitnah einzubauen. diff --git a/coronaZeit/mdNewsletter.d/2020-11-08-machRekorde.md b/coronaZeit/mdNewsletter.d/2020-11-08-machRekorde.md new file mode 100644 index 0000000..2e3d6c7 --- /dev/null +++ b/coronaZeit/mdNewsletter.d/2020-11-08-machRekorde.md @@ -0,0 +1,26 @@ +--- +title: Rekordjagd kann beginnen - coronaNewsletter-2020-11-08 +--- + +In unserem [kleinen "Achievement System"][1] kann nun auf Rekordejagd +gegangen werden. + +[1]: http://cwsvjudo.bplaced.net/machs + +Ein Rekord kann pro Altersklasse und Achievementkategorie aufgestellt +werden. Dabei gilt der Rekord in einer Altersklasse auch mit in den +höheren/älteren Altersklassen. Dass heißt die U18 muss sich z.B. auch +gegen die Rekorde der U11 messen. Aber natürlich nicht umgekehrt. +Teilweise kann es sein, dass das Alter der Judoka noch eingetragen +werden muss. + +Einige Judoka sind schon sehr engagiert bei der Sache und haben schon +einige Achievements gesammelt. Ich hoffe, mit der nun eröffneten +Rekordejagd auch den Ehrgeiz der anderen geweckt zu haben. + +Als nächstes sollen im Achievementsystem noch weitere, zusätzliche +Achievementgruppen hinzukommen. Wer eine gute Idee hat, kann sie gerne +an mich herantragen. + +Bleibt gesund +marko diff --git a/coronaZeit/mdNewsletter.d/2020-11-18-RekordeVsAchievements.md b/coronaZeit/mdNewsletter.d/2020-11-18-RekordeVsAchievements.md new file mode 100644 index 0000000..8c341ba --- /dev/null +++ b/coronaZeit/mdNewsletter.d/2020-11-18-RekordeVsAchievements.md @@ -0,0 +1,39 @@ +--- +title: Rekorde und Achievements - coronaNewsletter-2020-11-18 +--- + +Offenbar gibt es in unserem [Achievement System][1] einige +Unklarheiten, was genau mit den Rekorden gemeint ist. + +[1]: http://cwsvjudo.bplaced.net/machs + +Deshalb möchte ich hier versuchen, es nocheinmal genauer zu erklären. +Dazu muss ich allerdings erstmal mit den Achievements beginnen: + +In unserem Achievementsystem gibt es verschiedene Kategorien. In jeder +Kategorie gibt es Aufgaben mit steigendem Schwierigkeitsgrad. Von +diesen Aufgaben kann jeder Judoka täglich eine bewältigen und sich +diese von den Eltern bestätigen lassen. Eine solche Aufgabe wird +Achievement genannt. Achievements sind also eine Art persönliche Liste +an Übungen, die man bereits beherrscht. + +Zusätzlich kann jeder Judoka versuchen in einer Kategorie einen Rekord +aufzustellen. Dieser Rekord ist dann "offiziell" und gilt für alle +Judoka (in der entsprechenden Altersklasse). Aufgrund dieses +"offiziellen" Charakters sollen diese Rekorde dokumentiert werden. Dazu +soll ein Video des Aufstellens des Rekordes dienen. Diese Videos müssen +vor der Meldung des Rekordes in den persönlichen Bereich hochgeladen +werden. Ein entsprechender Link sollte im Rekord-Melde-Dialog mit +angezeigt werden. Die Videos des Rekordes sollen dann später in der +Bestenliste mit verlinkt werden. + +Ich habe in letzter Zeit immer wieder Rekordmeldungen ohne +entsprechendes Video erhalten. Und ohne, dass das die entsprechenden +Achievements mit gegeben worden. Deshalb wollte ich nocheinmal den +Unterschied zwischen beiden klarstellen. + +Falls es Unklarheiten, Verbesserungen oder Fehlermeldungen zur App gibt +möchte ich jeden dazu aufrufen, diese mir mitzuteilen. + +Bleibt gesund +marko diff --git a/coronaZeit/mdNewsletter.d/2020-12-19-Videotrainig.md b/coronaZeit/mdNewsletter.d/2020-12-19-Videotrainig.md new file mode 100644 index 0000000..205e2fe --- /dev/null +++ b/coronaZeit/mdNewsletter.d/2020-12-19-Videotrainig.md @@ -0,0 +1,39 @@ +--- +title: Training per Videokonferenz - coronaNewsletter-2020-12-19 +--- + +Die trainingsfreie dauert nunmehr viel zu lange! Zeit nach neuen +Möglichkeiten zu suchen. Mittlerweile haben die Meisten sicher schon +Kontakt mit Homeoffice oder Homeschooling gehabt. Und damit vielleicht +auch mit Videokonferenzen. Ich möchte versuchen auch eine +Trainingseinheit über Videokonferenz abzuhalten. Dazu habe ich einen +[Raum auf einem eigenen Server][1] aufgesetzt. + +[1]: https://meet.cwsvjudo.dedyn.io/onlineTraining + +Das Passwort für den Raum wird `cwsvjudo` sein (alles klein und +hintereinenader). Die Videokonferenz kann (theoretisch) komplett im +Browser ausgeführt werden. Die Installation einer App sollte unnötig +sein. Wer die zugehörige App benutzen möchte: + +- iOS: [https://itunes.apple.com/us/app/jitsi-meet/id1165103905] +- Android: [https://play.google.com/store/apps/details?id=org.jitsi.meet] +- Android (F-Droid): [https://f-droid.org/en/packages/org.jitsi.meet/] + +sollte darauf achten, in den Einstellungen die Server-Url auf +[https://meet.cwsvjudo.dedyn.io/] zu ändern. + +Als ersten Test lade ich Interessierte am 19. und 20.12.2020 um jeweils +19:00 Uhr zu einem kleinen Probelauf ein. Dabei soll es sich in erster +Linie um einen Techniktest handeln. Als Termin für das erste +Onlinetraining schwebt mir + + Mittwoch, der 23.12.2020 16:00 Uhr + +vor. Also zur üblichen Trainingszeit. Die Übungen werden zwar am Platz +ausgeführt werden, ein wenig Platz um sich herum sollte aber vorhanden +sein. + + +Man sieht sich +marko diff --git a/coronaZeit/mdNewsletter.d/2020-12-24-Jahresabschluss.md b/coronaZeit/mdNewsletter.d/2020-12-24-Jahresabschluss.md new file mode 100644 index 0000000..a829a91 --- /dev/null +++ b/coronaZeit/mdNewsletter.d/2020-12-24-Jahresabschluss.md @@ -0,0 +1,35 @@ +--- +title: Jahresabschluss - coronaNewsletter 2020-12-25 +... + +Zum Abschluss eines nur suboptimalen Jahres 2020 kann noch +einmal trainiert werden. Beim letzten Onlinetraining lief noch +nicht alles glatt. Das hält uns allerdings nicht davon ab, +am Mittwoch, dem 30.12.2020 noch einmal eine Trainingseinheit +per Videoschalte durchzuführen: + +- Mittwoch, 30.12.2020, 16:00 Uhr bis ca. 17:00 Uhr +- [Link](https://meet.cwsvjudo.dedyn.io/onlineTraining) +- Passwort: cwsvjudo + +Im Anschluss an diese Trainingeinheit wird es noch eine paar +Spiele und eine Geschichte zum mitentscheiden geben. Die Dauer +des ganzen schätze ich auf bis zu 2 Stunden. + +Ich wäre dafür, trotz der Bandbreitenprobleme beim letzten Mal +trotzdem nochmal mit eingeschalteter Kamera anzufangen. Sollte +die Verbindungsqualität nicht ausreichen könnten wir dann +erstmal versuchen, die Videouqualität herunterzudrehen (wer +die Option findet) und können im Extremfall immer noch das +Bild abschalten. + +Wer Kritik oder Verbesserungsvorschläge hat (insbesondere +diejenigen, die während des letzten online Trainings verlustig +gegangen sind): Her damit! + +Zum Abschluss noch eine schöne Restweihnacht und natürlich +Gesundheit. + +Wir sehen uns beim Training! + +marko diff --git a/coronaZeit/mdNewsletter.d/2021-01-03-Jahresbegin.md b/coronaZeit/mdNewsletter.d/2021-01-03-Jahresbegin.md new file mode 100644 index 0000000..98380c5 --- /dev/null +++ b/coronaZeit/mdNewsletter.d/2021-01-03-Jahresbegin.md @@ -0,0 +1,26 @@ +--- +title: Neues Jahr - coronaNewsletter 2021-01-03 +--- + +Hallo liebe Eltern, +hallo liebe Judoka, + +für das neue Jahr wünsche ich Euch allen nur das Beste :). + +Wir lassen das neue Jahr beginnen, wie wir das alte haben ausklingen +lassen - mit einer Trainingseinheit am Mittwoch: + +- Mittwoch, 06.01.2021, 17:30 Uhr +- [Link](https://meet.cwsvjudo.dedyn.io/onlineTraining) +- Passwort: cwsvjudo +- Gürtel bereithalten + +Leider scheinen unsere Leitungen ja für eine Videoverbindung aller +Teilnehmer gleichzeitig nicht auszureichen. Wir belassen es diesmal +also bei einer Sprechverbindung. Nur die, die die Übungen zeigen lassen +ihre Kameras an. Wir werden in Zukunft aber auch noch andere Varianten +ausprobieren. + +Wir sehen uns beim Training! + +marko diff --git a/coronaZeit/mdNewsletter.d/2021-01-10-BigBlueButton.md b/coronaZeit/mdNewsletter.d/2021-01-10-BigBlueButton.md new file mode 100644 index 0000000..37ef5a9 --- /dev/null +++ b/coronaZeit/mdNewsletter.d/2021-01-10-BigBlueButton.md @@ -0,0 +1,22 @@ +--- +title: Online Training am 13. Januar 2021 - coronaNewsletter 2021-01-10 +--- + +Hallo liebe Eltern, +hallo liebe Judoka, + +wie bereits angekündigt, werden wir beim nächsten Training mit +BigBlueButton mal eine andere Software ausprobieren. Die Trainingszeit +wird die selbe sein: + +- Mittwoch, 13.01.2021, 17:30 Uhr +- [Link](https://webroom.hrz.tu-chemnitz.de/gl/nic-s0t-f4i-biq) +- Passwort: 320360 +- Wieder den Gürtel bereithalten + +Grundsätzlich läuft auch diese Version komplett im Browser, sodass +keine zusätzliche Software installiert werden muss. + +Ich hoffe auf rege Teilnahme, + +marko diff --git a/coronaZeit/mdNewsletter.d/2021-02-01-NeueTatami.md b/coronaZeit/mdNewsletter.d/2021-02-01-NeueTatami.md new file mode 100644 index 0000000..fa406e9 --- /dev/null +++ b/coronaZeit/mdNewsletter.d/2021-02-01-NeueTatami.md @@ -0,0 +1,32 @@ +--- +title: Online Training am 03. Februar 2021 - coronaNewsletter 2021-02-01 +--- + +Hallo liebe Eltern, +Hallo liebe Judoka, + +unsere Karateka haben eine Aktion gestartet, um via Crowdfunding +Spenden für neue Matten in unserem Dojo zu sammeln. Dazu müssen wir +zwischen dem 01.02.21 und dem 22.02.21 um 20:00 Uhr insgesamt 5000 € +zusammen bekommen. Der Deutsche Olympische Sportbund fördert jede +Spende nochmal mit 10 €. Je nach Spendenhöhe gibt es nette Givebacks +als Dankeschön: [Jetzt unterstützen](http://www.fairplaid.org/cwsv96) + +Bitte helft mit einer kleinen Spende und/oder indem ihr ein bisschen +Werbung für diese Aktion macht. + +Am Mittwoch wird natürlich wieder trainiert werden. Kleiner Teaser: +Diesmal werden wir auf eine kleine Reise gehen ;) + +- Mittwoch, 20.01.2021, 17:30 Uhr +- [Link](https://webroom.hrz.tu-chemnitz.de/gl/nic-s0t-f4i-biq) +- Passwort: 320360 +- Wieder den Gürtel bereithalten + +Ruhig am Anfang zur Begrüßung das Video mal einschalten. Zum einem, +damit wir die Verbindung mal stressen, um zu sehen, was geht. Und zum +anderen der Atmosphäre wegen :) + +Wir sehen uns beim Training + +marko diff --git a/coronaZeit/mdNewsletter.d/2021-02-10-nurTraining.md b/coronaZeit/mdNewsletter.d/2021-02-10-nurTraining.md new file mode 100644 index 0000000..a2da04e --- /dev/null +++ b/coronaZeit/mdNewsletter.d/2021-02-10-nurTraining.md @@ -0,0 +1,21 @@ +--- +title: Online Training am 10. Februar 2021 - coronaNewsletter 2021-02-01 +--- + +Hallo liebe Eltern, +Hallo liebe Judoka, + +am Mittwoch wird natürlich wieder trainiert werden: + +- Mittwoch, 20.10.2021, 17:30 Uhr +- [Link](https://webroom.hrz.tu-chemnitz.de/gl/nic-s0t-f4i-biq) +- Passwort: 320360 +- Wieder den Gürtel bereithalten + +Ruhig am Anfang zur Begrüßung das Video mal einschalten. Zum einem, +damit wir die Verbindung mal stressen, um zu sehen, was geht. Und zum +anderen der Atmosphäre wegen :) + +Wir sehen uns beim Training + +marko diff --git a/coronaZeit/mdNewsletter.d/2021-02-13-mitmachen.md b/coronaZeit/mdNewsletter.d/2021-02-13-mitmachen.md new file mode 100644 index 0000000..b74224d --- /dev/null +++ b/coronaZeit/mdNewsletter.d/2021-02-13-mitmachen.md @@ -0,0 +1,52 @@ +--- +title: Online Training am 24. Februar 2021 - coronaNewsletter 2021-02-24 +--- + +Hallo liebe Eltern, +Hallo liebe Judoka, + +heute gibt es eine Mitmach-Mail: + +- zu allererst natürlich das Training: + - Mittwoch, 13.02.2021, 17:30 Uhr + - [Link](https://webroom.hrz.tu-chemnitz.de/gl/nic-s0t-f4i-biq) + - Passwort: 320360 +- Drei Fragezeichen: + - Bei den letzten Trainings haben sich viele zu früh ausgeloggt und + haben dadurch die Drei Fragezeichen Geschichte verpasst. Deshalb + zur Erinnerung: Nach dem sportlichen Teil kommt noch die Drei + Fragezeichen Geschichte. Dieses Mal das große Finale der + Piratengeschichte! +- Neue Matten für unser Dojo: + - Diese Woche noch läuft das von unseren Karateka initierte + Crowdfunding für neue Matten in unserem Dojo und wir sind auf einem + guten Weg. Wer also noch etwas geben möchte, kann dies unter + [diesem Link](http://www.fairplaid.org/cwsv96). +- Videos für die Trainingsfolien: + - Um die Übungen während des Onlinetrainings schneller zu erfassen, + wären Videos der einzelnen Übungen hilfreich. Deshalb der Aufruf an + unsere Judoka, von den Übungen kurze Demonstrations-Videos zu + drehen. Für die derzeitig Runde wären das z.B.: + - Kniebeuge + - Wendeltreppe (im Liegestütz zur Seite austreten, Drehung in + der Hüfte und Austreten zur anderen Seite) + - Luftsitzen (also Wandsitzen ohne Wand) + - Kniehebelauf am Ort + - Gleichgewichtsübungen: Baumpose, Austreten nach vorne, zur + Seite und nach hinten, Standwaage + - Nachstellschritt hin und her + - Brustschwimmen am Boden + - Rudern + - Marcel-Liegestütze (Liegestütze mit Pause unten, ohne + Absetzen) + - Rückenstrecker (im Vierfüßler gleichzeitig diagonal den Arm + und Bein heben) + - Kobra (Wechsel zwischen Kerze und Schwebesitz) +- Neue Übungen: + -Für unser Onlinetraining werden immer wieder kleine Übungen + gesucht. Idealerweise welche, die nicht viel Platz benötigen, und + am Ort ausgeführt werden können. + +So, das war's dann auch schon ;) + +marko diff --git a/coronaZeit/mdNewsletter.d/2021-02-21-mitmachen2.md b/coronaZeit/mdNewsletter.d/2021-02-21-mitmachen2.md new file mode 100644 index 0000000..4f2e8f2 --- /dev/null +++ b/coronaZeit/mdNewsletter.d/2021-02-21-mitmachen2.md @@ -0,0 +1,33 @@ +--- +title: coronaNewsletter 2021-02-21 +--- + +Hallo liebe Eltern, +Hallo liebe Judoka, + +zumindest bei drei Mitmach-Sachen haben erfreulich viele mitgemacht: + +Beim Training sind wir mitunter bei einer zweistelligen Anzahl +angelangt. Aufgrund des großen Erfolges wird das Training deshalb auch +diese Woche wieder stattfinden: + +- Mittwoch, 24.02.2021, 17:30 Uhr +- [Link](https://webroom.hrz.tu-chemnitz.de/gl/nic-s0t-f4i-biq) +- Passwort: 320360 + +Danke an alle Spender für das Crowdfunding für neue Matten in unserem +Dojo. Das Spendenziel wurde erreicht und das nächste Training wird +aller Voraussicht nach auf neuen Matten stattfinden. + +Auch für die Drei Fragezeichen hatten letztes Mal mehr Leute Geduld. + +Wo sich leider noch keiner zum Mitmachen überreden lassen hat, sind +kurze Videoclips mit Übungen zu unseren Trainingsfolien. Um einen +zusätzlichen Anreiz zu schaffen, gibt es in unserem Achievementsystem +das Achievement "Filmemacher". Vielleicht ja ein neuer Anreiz, das +Achivementsystmem mal wieder zu benutzen. + + +Wir sehen uns beim Training, + +marko diff --git a/coronaZeit/mdNewsletter.d/2021-03-02-traininigsverlegung.md b/coronaZeit/mdNewsletter.d/2021-03-02-traininigsverlegung.md new file mode 100644 index 0000000..af3bd6b --- /dev/null +++ b/coronaZeit/mdNewsletter.d/2021-03-02-traininigsverlegung.md @@ -0,0 +1,29 @@ +--- +title: coronaNewsletter 2021-03-02 +--- + +Hallo liebe Eltern, +Hallo liebe Judoka, + +zunächst einmal der Termin/Link für das nächste Training: + +- Mittwoch, 03.02.2021, 17:30 Uhr +- [Link](https://webroom.hrz.tu-chemnitz.de/gl/nic-s0t-f4i-biq) +- Passwort: 320360 + +Und als zweites eine Bitte um Feedback. In der Schulzeit ist es +ungünstig, in der Wochenmitte ein Training zu haben, das bis (nach) +19:00 Uhr geht. Deshalb die Frage, ob es möglich wäre, den +Trainingsbeginn um eine halbe Stunde vorzuverlegen. Eine andere +Variante wäre, das Training auf den Freitag zu verlegen. Allerdings +besteht gerade für Kinder im Homeshooling die Gefahr einer gewissen +Videokonferenz-Müdigkeit. Wie seht ihr als Judoka und Eltern die +Sache: + +- Mittwochs eine halbe Stunde eher? +- Training am Freitag? + + +Wir sehen uns beim Training, + +marko diff --git a/coronaZeit/mdNewsletter.d/2021-03-06-eherTraining.md b/coronaZeit/mdNewsletter.d/2021-03-06-eherTraining.md new file mode 100644 index 0000000..a2eef2b --- /dev/null +++ b/coronaZeit/mdNewsletter.d/2021-03-06-eherTraining.md @@ -0,0 +1,32 @@ +--- +title: coronaNewsletter 2021-03-06 +--- + +Hallo liebe Eltern, +Hallo liebe Judoka, + +danke für eure Rückmeldungen zu meiner kleinen Umfrage. Als Ergebnis +wird das nächste Training bereit 17:00 Uhr starten: + +- Mittwoch, 10.03.2021, 17:00 Uhr +- [Link](https://webroom.hrz.tu-chemnitz.de/gl/nic-s0t-f4i-biq) +- Passwort: 320360 + +Es gab auch viele, die gerne ein Training am Freitag gehabt hätten. Wir +behalten uns diese Option auch in der Hinterhand. Zunächst sehen wir +aber mal, wie das zeitigere Training am Mittwoch aufgenommen wird. + +Sollte sich bei Euch noch einmal etwas ändern, was das für/gegen ein +Training Mittwoch/Freitag spricht, könnt Ihr Euch auch gerne weider bei +mir melden. + +Zum Schluss möchte ich auch von meiner Seite mal meine Anerkennung +zum Ausdruck bringen, dass wir den Willen und die Ausdauer haben, das +Onlinetraining durchzuziehen. Auch den Akteuren, die nicht vor der +Kamera, sondern im Hintergrund dazu beitragen, den Kindern (und mir) +trotz der derzeitigen Situation ein wöchentliches Training zu +ermöglichen. + +Vielen Dank, + +marko diff --git a/coronaZeit/mdNewsletter.d/2021-03-14-Treppenlauf.md b/coronaZeit/mdNewsletter.d/2021-03-14-Treppenlauf.md new file mode 100644 index 0000000..9b11a43 --- /dev/null +++ b/coronaZeit/mdNewsletter.d/2021-03-14-Treppenlauf.md @@ -0,0 +1,39 @@ +--- +title: coronaNewsletter 2021-03-14 +--- + +Hallo liebe Eltern, +Hallo liebe Judoka, + +auch diese woche wird das Training wieder 17:00 Uhr starten: + +- Mittwoch, 17.03.2021, 17:00 Uhr +- [Link](https://webroom.hrz.tu-chemnitz.de/gl/nic-s0t-f4i-biq) +- Passwort: 320360 + +Laut derzeitiger Regelung und derzeitigen Zahlen ist für Chemnitz das +Training im Freien für bis zu 20 Kindern erlaubt. An der Zeit als, sich +Gedanken über das nächste Präsenztraining zu machen. Dabei sollte man +aber immer im Hinterkopf haben, dass die Regelungen - je nach +Entwicklung der Zahlen - auch wieder verschärft werden können. + +Für diese Woche ist mir die Witterung derzeit noch zu kalt, um draußen +zu schwitzen. Aber für die Woche drauf habe ich geplant, mal ein +Präsenztraining anzubieten: + +- Freitag, 26.03.2021 16:00 Uhr +- Sportplatz Straße Usti nad Labem 42 +- Trainingsinhalt: Treppenlauf und Tsukuri (Wurfeingänge, der Obi wird +also benötigt) + +Ich bitte für das Präsenztraining (26.3.) darum, dass sich vorher und +rechtzeitig im [Wettkampfplaner](http://cwsvjudo.bplaced.net/pages/desktop/wkParticipo/login.php) +eingeschrieben wird. Sollte das Training also nicht stattfinden, kann +ich auf diese Weise den eingeschriebenen Teilnehmern Bescheid geben. +Verfolgt auch den Wetterbericht und kommt in dem Wetter angemessener +Trainingskleidung. + + +Wir sehen uns beim Training, + +marko diff --git a/coronaZeit/mdNewsletter.d/2021-03-21-keinTreppenlauf.md b/coronaZeit/mdNewsletter.d/2021-03-21-keinTreppenlauf.md new file mode 100644 index 0000000..3065385 --- /dev/null +++ b/coronaZeit/mdNewsletter.d/2021-03-21-keinTreppenlauf.md @@ -0,0 +1,31 @@ +--- +title: coronaNewsletter 2021-03-21 +--- + +Hallo liebe Eltern, +Hallo liebe Judoka, + +leider war das Fenster, welches gemeinsames Training zumindest im +Freien gestattet hätte, nur äußerst kurz geöffnet. Seit +[Freitag (17.03)](https://chemnitz.de/chemnitz/de/unsere-stadt/ordnung-und-sicherheit/allgemeinverfuegungen/20210317_av_aufhebung_alkoholkonsum.html) +sind die Lockerungen wieder zurückgenommen. Das heißt, das für Freitag +d. 26.3. geplante Präsenztreppenlauftraining kann in dieser Form nicht +stattfinden. Aber wie bereits angekündigt, wird der 26.03. trotzdem als +Trainingstag erhalten bleiben. Diese Woche wird es also zwei +Trainingseinheiten geben: + +- Mittwoch, 24.03.2021, 17:00 Uhr + - [Link](https://webroom.hrz.tu-chemnitz.de/gl/nic-s0t-f4i-biq) + - Passwort: 320360 +- Freitag, 26.03.2021, 16:00 Uhr + - [Link](https://webroom.hrz.tu-chemnitz.de/gl/nic-s0t-f4i-biq) + - Passwort: 320360 + +Allerdings in beiden Fällen eben als Online-Variante. + +Berichtigung: In unserem [Wettkampfplaner](http://cwsvjudo.bplaced.net/pages/desktop/wkParticipo) +stand fälschlicherweise der 27.03. Wurde mittlerweile berichtigt. + +Wir sehen uns beim Training, + +marko diff --git a/coronaZeit/mdNewsletter.d/2021-03-27-Osterferien.md b/coronaZeit/mdNewsletter.d/2021-03-27-Osterferien.md new file mode 100644 index 0000000..e5a51b9 --- /dev/null +++ b/coronaZeit/mdNewsletter.d/2021-03-27-Osterferien.md @@ -0,0 +1,36 @@ +--- +title: coronaNewsletter 2021-03-27 +--- + +Hallo liebe Eltern, +Hallo liebe Judoka, + + +natürlich wird es (wie immer) auch in in den Ferien die Möglichkeit +zum trainieren geben: + +- Mittwoch, 31.03.2021, 17:00 Uhr + - [Link](https://webroom.hrz.tu-chemnitz.de/gl/nic-s0t-f4i-biq) + - Passwort: 320360 +- Freitag, 02.04.2021, 16:00 Uhr + - [Link](https://webroom.hrz.tu-chemnitz.de/gl/nic-s0t-f4i-biq) + - Passwort: 320360 + +Die Beteiligung beim Freitagtraining blieb leider etwas hinter den +Erwartungen zurück. In den Ferien wird es trotzdem noch einmal eines +geben. Bitte beachten, dass das Training am Freitag bereits 16:00 Uhr +beginnt. + +Da die Videoübertragung beim letzten Training nicht so optimal war, +hier nochmal das Video mit der [Wochenendherausforderung][1]: + + + +[1]: http://cwsvjudo.bplaced.net/machs/videos.d/groups/aufspringen.webm + +Wir sehen uns beim Training, + +marko diff --git a/coronaZeit/mdNewsletter.d/2021-04-08-Osterferien.md b/coronaZeit/mdNewsletter.d/2021-04-08-Osterferien.md new file mode 100644 index 0000000..002ded2 --- /dev/null +++ b/coronaZeit/mdNewsletter.d/2021-04-08-Osterferien.md @@ -0,0 +1,16 @@ +--- +title: coronaNewsletter 2021-04-08 +--- + +Hallo liebe Eltern, +Hallo liebe Judoka, + +kurz zur Erinnerung: Das Training am Freitag morgen beginnt um vier: + +- Freitag, 09.04.2021, 16:00 Uhr + - [Link](https://webroom.hrz.tu-chemnitz.de/gl/nic-s0t-f4i-biq) + - Passwort: 320360 + +Wir sehen uns beim Training, + +marko diff --git a/coronaZeit/mdNewsletter.d/2021-04-10-nachOsterferien.md b/coronaZeit/mdNewsletter.d/2021-04-10-nachOsterferien.md new file mode 100644 index 0000000..ff9105a --- /dev/null +++ b/coronaZeit/mdNewsletter.d/2021-04-10-nachOsterferien.md @@ -0,0 +1,47 @@ +--- +title: coronaNewsletter 2021-04-10 +--- + +Hallo liebe Eltern, +Hallo liebe Judoka, + + +auch nach den Osterferien wird das Training zweimal die Woche - am +Mittwoch und am Freitag - fortgesetzt. Allerdings wird auch das +Freitagtraining auf 17:00 Uhr gelegt: + +- Mittwoch, 14.04.2021, 17:00 Uhr + - [Link](https://webroom.hrz.tu-chemnitz.de/gl/nic-s0t-f4i-biq) + - Passwort: 320360 +- Freitag, 16.04.2021, 17:00 Uhr + - [Link](https://webroom.hrz.tu-chemnitz.de/gl/nic-s0t-f4i-biq) + - Passwort: 320360 + +Hier auch noch die beiden Videos der beiden Teile ([I][1], [II][2]) der +Herausforderung dieses Wochenendes: + + + + + +[1]: http://cwsvjudo.bplaced.net/machs/videos.d/groups/wechselVierfuesslerKrebs.webm +[2]: http://cwsvjudo.bplaced.net/machs/videos.d/groups/breakdance.webm + +Mal sehen, wer beim nächsten Training die Übung zeigen kann ;) + +Auch wen derzeit das Training im Außenbereich mit bis zu 20 Kindern +erlaubt wäre, habe ich mich entschlossen, diese Mal noch etwas zu +warten. Erstens bis das Wetter wieder etwas wärmer geworden ist und +zweitens bis die Situation etwas vorhersehbarer wird (um eine ähnliche +Situation wie letztes Mal zu vermeiden). + + +Wir sehen uns beim Training, + +marko diff --git a/coronaZeit/mdNewsletter.d/2021-04-17-mitJacke.md b/coronaZeit/mdNewsletter.d/2021-04-17-mitJacke.md new file mode 100644 index 0000000..7541c0d --- /dev/null +++ b/coronaZeit/mdNewsletter.d/2021-04-17-mitJacke.md @@ -0,0 +1,26 @@ +--- +title: coronaNewsletter 2021-04-17 +--- + +Hallo liebe Eltern, +Hallo liebe Judoka, + + +für die nächsten Trainingseinheiten wird auch die Judojacke benötigt. +In der allergrößten Not tut es auch der Gürtel oder eine normale aber +reißfeste (!!) Jacke. + +- Mittwoch, 14.04.2021, 17:00 Uhr + - [Link](https://webroom.hrz.tu-chemnitz.de/gl/nic-s0t-f4i-biq) + - Passwort: 320360 +- Freitag, 16.04.2021, 17:00 Uhr + - [Link](https://webroom.hrz.tu-chemnitz.de/gl/nic-s0t-f4i-biq) + - Passwort: 320360 + +Und für die, die sich tatsächlich an der Wochenendherausforderung +versuchen wollen, hier der Link zum Video: [Bring Sally up](https://www.youtube.com/watch?v=koMp3ei4xJw) + + +Wir sehen uns beim Training, + +marko diff --git a/coronaZeit/myAddresses.txt b/coronaZeit/myAddresses.txt new file mode 100644 index 0000000..81a89d5 --- /dev/null +++ b/coronaZeit/myAddresses.txt @@ -0,0 +1,4 @@ +cwsvjudo@arcor.de +marko.bunzel@arcor.de +cwsvjudo@gmail.com +judo.cwsv@t-online.de diff --git a/coronaZeit/tools/sendMail.py b/coronaZeit/tools/sendMail.py new file mode 100755 index 0000000..c686b54 --- /dev/null +++ b/coronaZeit/tools/sendMail.py @@ -0,0 +1,111 @@ +#! /usr/bin/env python3 + +import smtplib, ssl +from email import utils +from email.mime.text import MIMEText +from email.mime.multipart import MIMEMultipart +import pypandoc +import json +import argparse +import yaml +from datetime import datetime + +def get_yaml(f): + '''Extracts the yamlHeader from a Markdown file''' + pointer = f.tell() + if f.readline() != '---\n': + f.seek(pointer) + return '' + readline = iter(f.readline, '') + readline = iter(readline.__next__, '---\n') + return ''.join(readline) + + +argParser = argparse.ArgumentParser( + description="Send an Markdown-File as eMail" +) +argParser.add_argument( + "mdFilePath", + help="Path to MarkdownFile to send" +) +argParser.add_argument( + "--EmailAddressFilePath", + default=None, + help="File with eMailAddresses, one per line, to wich to send the eMail TO" +) +argParser.add_argument( + "--toEmailAddress", + default=None, + help="address, to wich to send the eMail TO" +) + +# StandardValues +receiverEmails = [ + "cwsvjudo@arcor.de", + "marko.bunzel@arcor.de", + "cwsvjudo@gmail.com", + "judo.cwsv@t-online.de", +] +config = { + 'smtp' : + { + 'serverAddress' : "mail.arcor.de", + 'serverPort' : 465, + 'login' : "cwsvjudo", + 'password' : "***REMOVED***" + }, + 'senderEmailAddress': "cwsvjudo@arcor.de" +} + + +if __name__=="__main__": + argv = argParser.parse_args() + + # Loading the EmailAdresses from a file + if argv.EmailAddressFilePath: + receiverEmails = [] + with open(argv.EmailAddressFilePath) as inFile: + for line in inFile: + receiverEmails.append(line) + + if argv.toEmailAddress: + receiverEmails = [argv.toEmailAddress] + + # read markdownfile as header and text + mdHeader =[] + mdText = [] + with open(argv.mdFilePath) as f: + mdHeader = yaml.load(get_yaml(f)) + + # Create the plain-text and HTML version of your message + text = pypandoc.convert_file(argv.mdFilePath, "markdown", extra_args=["--self-contained", "--resource-path=../aufgaben"]) + html = pypandoc.convert_file(argv.mdFilePath, "html", extra_args=["--self-contained", "--resource-path=../aufgaben"]) + + # Turn these into plain/html MIMEText objects + txtMimeText = MIMEText(text, "plain") + htmlMimeText = MIMEText(html, "html") + + # Create a secure SSL context + context = ssl.create_default_context() + with smtplib.SMTP_SSL(config['smtp']['serverAddress'], config['smtp']['serverPort'], context=context) as server: + server.login(config['smtp']['login'], config['smtp']['password']) + for receiverEmail in receiverEmails: + # create the mail + message = MIMEMultipart("alternative") + # Setting header data + message["Subject"] = mdHeader['title'] + message["From"] = config['senderEmailAddress'] + message["Reply-To"] = config['senderEmailAddress'] + message["Date"] = str(utils.formatdate(localtime=True)) + # only set the to-header one time: setting it multiple + # times results in a multiple to-entries in the header! + # Meanig the mail has to be recreated for each to address. + # @todo Find a way to reuse the created mail for every recipent + message["To"] = receiverEmail + + # Add HTML/plain-text parts to MIMEMultipart message + # The email client will try to render the last part first + message.attach(htmlMimeText) + message.attach(txtMimeText) + + server.sendmail(config['senderEmailAddress'], receiverEmail, message.as_string()) diff --git a/homepage/cloudsync.sh b/homepage/cloudsync.sh new file mode 100755 index 0000000..7c26b73 --- /dev/null +++ b/homepage/cloudsync.sh @@ -0,0 +1,5 @@ + +sudo mount -t davfs -o uid=$(id -u marko),gid=$(id -g marko) https://webdav.magentacloud.de ~/mnt/cwsvJudo@magenta/ +rsync -av ~/mnt/cwsvJudo@magenta/machs/ machs.cloudMirror/ + + diff --git a/homepage/machs/achievementBuilder.php b/homepage/machs/achievementBuilder.php new file mode 100644 index 0000000..33c686b --- /dev/null +++ b/homepage/machs/achievementBuilder.php @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + machs + + + + + + + + + + + +

AchievementBuilder

+Add AchievementGroup"); + echo(achievementGroup::htmlAddAchievementGroupForm()); + + echo("

Update Achievements

"); + foreach($achievementGroups as $g){ + echo("

".$g->getName()."

"); + echo($g->htmlEditAchievementGroupForm()); + + $achievements = $g->getAchievements(); + if(empty($achievements)){ + echo("

Auto Add Achievements

".achievementGroup::htmlAutoAddAchievementsForm($g->getId())); + } + foreach($achievements as $a){ + echo("

".$a['name']."

"); + echo(htmlUpdateAchievementBox( + $a['id'], + $a['name'], + $a['rootId'], + $a['achievementGroupId'], + $a['level'], + $a['description'], + $a['imgUrl'] + )); + } + echo("

Add achievement

"); + echo(htmlAddAchievementBox()); + } +?> + + + diff --git a/homepage/machs/auth.php b/homepage/machs/auth.php new file mode 100644 index 0000000..93147fc --- /dev/null +++ b/homepage/machs/auth.php @@ -0,0 +1,16 @@ +". + "Datum: ".date("Y-m-d")."
". + "Angemeldet als ".htmlspecialchars($_SESSION['user']['username']).".
". + "Sitzung beenden". + ""; + } +?> diff --git a/homepage/machs/config.php b/homepage/machs/config.php new file mode 100644 index 0000000..d3b7012 --- /dev/null +++ b/homepage/machs/config.php @@ -0,0 +1,8 @@ + diff --git a/homepage/machs/images.d/Judo_Safari.png b/homepage/machs/images.d/Judo_Safari.png new file mode 100644 index 0000000..1f9e678 Binary files /dev/null and b/homepage/machs/images.d/Judo_Safari.png differ diff --git a/homepage/machs/images.d/original_Safari_Adler.jpg b/homepage/machs/images.d/original_Safari_Adler.jpg new file mode 100644 index 0000000..03e6cce Binary files /dev/null and b/homepage/machs/images.d/original_Safari_Adler.jpg differ diff --git a/homepage/machs/images.d/original_Safari_Bär.jpg b/homepage/machs/images.d/original_Safari_Bär.jpg new file mode 100644 index 0000000..d1fd8ce Binary files /dev/null and b/homepage/machs/images.d/original_Safari_Bär.jpg differ diff --git a/homepage/machs/images.d/original_Safari_Fuchs.jpg b/homepage/machs/images.d/original_Safari_Fuchs.jpg new file mode 100644 index 0000000..57bbb47 Binary files /dev/null and b/homepage/machs/images.d/original_Safari_Fuchs.jpg differ diff --git a/homepage/machs/images.d/original_Safari_Känguru.jpg b/homepage/machs/images.d/original_Safari_Känguru.jpg new file mode 100644 index 0000000..4148959 Binary files /dev/null and b/homepage/machs/images.d/original_Safari_Känguru.jpg differ diff --git a/homepage/machs/images.d/original_Safari_Panther.jpg b/homepage/machs/images.d/original_Safari_Panther.jpg new file mode 100644 index 0000000..b1299dc Binary files /dev/null and b/homepage/machs/images.d/original_Safari_Panther.jpg differ diff --git a/homepage/machs/images.d/original_Safari_Schlange.jpg b/homepage/machs/images.d/original_Safari_Schlange.jpg new file mode 100644 index 0000000..13d77d5 Binary files /dev/null and b/homepage/machs/images.d/original_Safari_Schlange.jpg differ diff --git a/homepage/machs/images.d/seilspringen.svg b/homepage/machs/images.d/seilspringen.svg new file mode 100644 index 0000000..5035465 --- /dev/null +++ b/homepage/machs/images.d/seilspringen.svg @@ -0,0 +1,461 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/homepage/machs/images.d/wechselLiegeUnterarmstuetz.gif b/homepage/machs/images.d/wechselLiegeUnterarmstuetz.gif new file mode 100644 index 0000000..c3feeff Binary files /dev/null and b/homepage/machs/images.d/wechselLiegeUnterarmstuetz.gif differ diff --git a/homepage/machs/index.php b/homepage/machs/index.php new file mode 100644 index 0000000..4daa4dd --- /dev/null +++ b/homepage/machs/index.php @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + Achievements + + + + + + + + + + + + + Eigene Achievements" ); + echo( "
"); + foreach($achievementGroups as $g){ + echo($g->asHtmlCard($_SESSION['user']['userId'])); + } + echo("
" ); + } + ?> + + ".$k['vorname']." ".$k['name']."" ); + echo( "
"); + foreach($achievementGroups as $g){ + echo($g->asHtmlCard($k['kidId'], ['noForm'=>false])); + } + echo("
" ); + } + } + ?> + + + diff --git a/homepage/machs/lib/achievementsLib.php b/homepage/machs/lib/achievementsLib.php new file mode 100644 index 0000000..10b50e9 --- /dev/null +++ b/homepage/machs/lib/achievementsLib.php @@ -0,0 +1,264 @@ +"; + if( !empty($anRetMessage['error']) ){ + $retHtmlString .= "
"; + $retHtmlString .= "ERROR:
"; + $retHtmlString .= $anRetMessage['error']; + $retHtmlString .= "
"; + } + if( !empty($anRetMessage['warning']) ){ + $retHtmlString .= "
"; + $retHtmlString .= "WARNING:
"; + $retHtmlString .= $anRetMessage['warning']; + $retHtmlString .= "
"; + } + if( !empty($anRetMessage['notice']) ){ + $retHtmlString .= "
"; + $retHtmlString .= "Info:
"; + $retHtmlString .= $anRetMessage['notice']; + $retHtmlString .= "
"; + } + if( !empty($anRetMessage['success']) ){ + $retHtmlString .= "
"; + $retHtmlString .= "SUCCESS:
"; + $retHtmlString .= $anRetMessage['success']; + $retHtmlString .= "
"; + } + $retHtmlString .= ""; +} +// print_r($anRetMessage); +return $retHtmlString; +} + +// one time only function to convert the list of kids within the user +// table itself to an extra entry in a "vormundschafts" table +function convertToVormundschaft($db){ + $query = << array('value' => $user['id'], 'data_type' => PDO::PARAM_INT), + ':kidId' => array('value' => $kidId, 'data_type' => PDO::PARAM_INT), + ); + dbQuery($db, $query, $params); + } + } +return; +} + +/// get all available achievements +function getAchievementList($db){ +$results = null; + try{ + $results = dbQuery( + $db, + "SELECT * FROM cwsvjudo.achievements;" + ); + } + catch(PDOException $db_error){ + print "Error!: " . $db_error->getMessage() . "
queryString: ".$queryString."
"; var_dump($bindArray); + } +return $results; +} + +function getAchievementGroups($db){ +return achievementList2achievementGroups( getAchievementList($db) ); +} + +function arrayKeyed2htmlTableString($anArray, $keyList, $withCaption = false){ +$ret = ""; + if( !is_array($anArray) ) + return ""; + $ret .= ""; + if($withCaption) { + $ret .= ""; + foreach( $keyList as $caption ){ + $ret .= ""; + } + $ret .= ""; + } + foreach($anArray as $row){ + if( !is_array($anArray) ) + continue; + $ret .= ""; + foreach( $keyList as $key ) + $ret .= ""; + $ret .= ""; + } + $ret .= "
".$caption."
".$row[$key]."
"; +return $ret; +} + +function getUsersAchievements($db, $userId){ + $query = <<user` WHERE `userId` = :userId; +SQL; + $params = [':userId' => array('value'=>$userId, 'data_type'=>PDO::PARAM_INT)]; + $result = dbQuery($db, $query, $params); +return $result; +} + +function achievementList2achievementGroups ( $list ){ +$groups = []; + foreach($list as $a){ + if(!array_key_exists($a['rootId'], $groups) ){ + $groups[ $a['rootId'] ] = array(); + } + $groups[ $a['rootId'] ][ $a['level']] = $a; + } + foreach($groups as $key=>$g){ + ksort($groups[$key]); + } + ksort($groups); +return $groups; +} + +function htmlUsersUploadBox($db, $userId){ +$html = ""; + $userData = getUserData($db, $userId); + $html .= "
"; + $html .= "
Upload Link
".$userData['machsUploadUrl']."
"; + $html .= "
Upload Passwort
".$userData['machsUploadPw']."
"; + $html .= "
"; +return $html; +} + +function htmlAchievementListForUser($db, $achievementGroups, $userId, $usersAchievmentIds, $noForm=false){ +//var_dump($db, $achievementGroups, $userId, $usersAchievmentIds); +$ids=[]; +foreach($usersAchievmentIds as $a){ + $ids[]=$a['achievementId']; +} +record::setDbConnection($db); +$userData = record::getUserData($userId); +$retHtml = ""; + if(!canUserGetAchievementToday( $db, $userId) ){ + $retHtml .= "
Heute wurde schon ein Achievement erreicht!
"; + } + $retHtml .= "
"; + foreach($achievementGroups as $g){ + $records = record::getGroupsRecords($g->getId(), record::birthday2ageClass($userData[0]['gebDatum'])); + $retHtml .= "
"; + $retHtml .= "
    "; +// see, if there is a record for this group + $imgUrl = null; + foreach($g->achievements as $a){ + if($a['imgUrl'] != null){ + $imgUrl = $a['imgUrl']; + } + if(in_array($a['id'], $ids)){ + $retHtml .= "
  • ✓ ".$a['name'].": ".$a['description']; + $retHtml .= "
  • "; + } + else{ + $retHtml .= "
  • ".$a['name'].": ".$a['description']; + //if(isUserAdmin($db, $_SESSION['user']['userId'])){ + if(!$noForm){ + if( canUserGetAchievementToday( $db, $userId) or isUserAdmin($db, $_SESSION['user']['userId']) ){ + $retHtml .= "
    "; + $retHtml .= ""; + $retHtml .= ""; + $retHtml .= ""; + $retHtml .= ""; + $retHtml .= ""; + $retHtml .= "
    "; + } + } + if( $imgUrl != null ) + $retHtml .= "
    "; + $retHtml .= "
  • "; + break; + } + } + // show the current record + if( validateDate($userData[0]['gebDatum'])){ + $retHtml.=record::arrayRecord2htmlCard($records[0], $userData[0], $g->getId(), "li"); + } + else{ + $retHtml.="
    Rekorde können erst angezeigt werden, wenn das Geburtsdatum korrekt gesetzt wurde!
    "; + } + $retHtml .= "
"; + $retHtml .= "
"; + } + $retHtml .= "
"; +return $retHtml; +} + +function getRecords($db, $groupId){ + $query = <<['value'=>$groupId, 'data_type'=>PDO::PARAM_INT]]; +return dbQuery($db, $query, $params); +} + +function setUserDataBox($userId){ +$html = ""; + $html .= "
"; + $html .= ""; + $html .= ""; + $html .= ""; + $html .= ""; + $html .= ""; + $html .= "
"; +return $html; +} + +function htmlAddAchievementBox(){ +$html = ""; + $html .= "
"; + $html .= ""; + $html .= ""; + $html .= ""; + $html .= ""; + $html .= ""; + $html .= ""; + $html .= ""; + $html .= ""; + $html .= ""; + $html .= "
"; +return $html; +} + +function htmlUpdateAchievementBox($achievementId, $name, $rootId, $achievementGroupId, $level, $description, $imgUrl){ +$html = ""; + $html .= "
"; + $html .= ""; + $html .= ""; + $html .= "
achievementId: ".$achievementId; + $html .= ""; + $html .= "
"; + $html .= ""; + $html .= ""; + $html .= ""; + $html .= ""; + $html .= ""; + $html .= ""; + $html .= ""; + $html .= ""; + $html .= ""; + $html .= ""; + $html .= ""; + $html .= ""; +return $html; +} + +?> diff --git a/homepage/machs/lib/api.php b/homepage/machs/lib/api.php new file mode 100644 index 0000000..72f2ae7 --- /dev/null +++ b/homepage/machs/lib/api.php @@ -0,0 +1,166 @@ +setDbConnection($db); + $g->loadAchievementGroupFromDb($post['achievementGroupId']); + $g->autoAddAchievements( + $post['messageTemplate'], + $post['from'], + $post['to'], + $post['step'] + ); + } + + if($post['action']=="updateAchievement"){ + updateAchievement( + $db, + $post['achievementId'], + $post['name'], + $post['rootId'], + $post['achievementGroupId'], + $post['level'], + $post['description'], + $post['imgUrl'] + ); + } + + if($post['action']=="updateAchievementGroup"){ + updateAchievement( + $db, + $post['achievementGroupId'], + $post['name'], + $post['rootId'], + $post['unlockingAchievementId'], + $post['imgUrl'] + ); + } + + if($post['action']=="setBday"){ + setBday( + $db, + $post['userId'], + $post['bday'] + ); + } + if($post['action']=="setRecord"){ + $u = getUserData($db, $post['userId']); + $g = new achievementGroup; + $g->setDbConnection($db); + $g->loadAchievementGroupFromDb($post['achievementGroupId']); + sendEmail( + "cwsvjudo@arcor.de", + $u['vorname']." ".$u['name']." got ".$post['value']." in ".$g->getName(), + "[machs] Rekord eingetragen" + ); + setRecord( + $db, + $post['userId'], + $post['achievementGroupId'], + $post['value'] + ); + } + if($post['action']=="reportRecord"){ +# $u = getUserData($db, $post['userId']); +# $ag = new achievementGroup; +# achievementGroup::setDbConnection($db); +# $ag->loadAchievementGroupFromDb($post['achievementGroupId']); + $m = $post['userId']." hat in ".$post['achievementGroupId']." ".$post['value']." geschafft!"; +# $m = $u['vorname']." ".$u['name']." hat in ".$ag->getName()." ".$post['value']." geschafft!"; + sendEmail("cwsvjudo@arcor.de", $m, "[machs] Rekordmeldung"); + } + if($post['redirectLocation']) + $redirectLocation = $post['redirectLocation']; + header("Location: ".$redirectLocation); + } +return; +} + +function sendEmail($toEmail, $emailText, $emailSubject){ + try{ + $date=new DateTime(); + mail( + $toEmail, + $emailSubject, + $emailText + ); + } + catch(Exception $e) { + echo 'Message: ' .$e->getMessage(); + } +} + +function attendancesAssocArray2text($attendancesAssocArray){ + $ret = ""; + foreach($attendancesAssocArray as $date => $attendees){ + $ret .= $date."\n"; + foreach($attendees as $a){ + $ret .= "\n"; + $ret .= "Name: ".$a['name'].", ".$a['vorname']."\n"; + $ret .= "PLZ: ".$a['corona_PLZ']."\n"; + $ret .= "Tel.: ".$a['corona_telephon']."\n"; + $ret .= "eMail: ".$a['corona_eMail']."\n"; + } + $ret .= "\n"; + } +return $ret; +} + +function attendancesAssocArray2mdList($attendancesAssocArray, $date=null){ + if($date == null) + $date=new DateTime(); + $ret = "# Anwesenheitsliste zur Corona-Kontaktverfolgung der Abteilung Judo des CWSV vom ".$date->format("Y-m-d")."\n\n"; + foreach($attendancesAssocArray as $d => $attendees){ + $ret .= "## ".$d."\n"; + $i=0; + foreach($attendees as $a){ + $i += 1; + $ret .= "\n"; + $ret .= $i." ".$a['name'].", ".$a['vorname']."\n"; + $ret .= " - PLZ: ".$a['corona_PLZ']."\n"; + $ret .= " - Tel.: ".$a['corona_telephon']."\n"; + $ret .= " - eMail: ".$a['corona_eMail']."\n"; + } + $ret .= "\n"; + } +return $ret; +} +?> diff --git a/homepage/machs/lib/db.php b/homepage/machs/lib/db.php new file mode 100644 index 0000000..059ce33 --- /dev/null +++ b/homepage/machs/lib/db.php @@ -0,0 +1,420 @@ +getMessage() ); + } +return $dbConnection; +} + +function createDb($dbConnection){ +<< array('value'=>$anUserId, 'data_type'=>PDO::PARAM_INT), +/// ':attributeId'=> array('value'=>$anAttributeId, 'data_type'=>PDO::PARAM_INT) ) +/// @param $someOption +function dbQuery($aDbConnection, $aQueryString, $aBindArray = array(), $someOptions = array()){ +// Standardbelegungen +if( empty($someOptions['dbCharset' ]) ) $someOptions['dbCharset' ] = "ISO-8859-1"; +if( empty($someOptions['outCharset']) ) $someOptions['outCharset'] = "UTF-8"; +if( empty($someOptions['dontFetch' ]) ) $someOptions['dontFetch' ] = false; +/// @toDo: Bisher wird nur die Rückgabe konvertiert. Eigentlich muss +/// doch auch die Eingabe konvertiert werden. Aber das jetzt +/// umzustellen wird schwer! Die User m Wettkampfplaner sind ja z.B. +/// als UTF8 in latin1(?) gespeichert. +/// @toDo: Die Standardwerte sollten vielleicht aus einer config +/// kommen, nicht hardcoded + try{ + $pdoStatement = $aDbConnection->prepare( $aQueryString ); + foreach( $aBindArray as $bindName => $bind ){ + if( $bind['data_type'] == PDO::PARAM_STR) + $bind['value'] = iconv( + $someOptions['outCharset'], + $someOptions['dbCharset'], + $bind['value'] + ); + $pdoStatement->bindValue( + $bindName, + $bind['value'], + (isset($bind['data_type'])?$bind['data_type']:PDO::PARAM_STR) + ); + } + $pdoResult = $pdoStatement->execute(); + if(!$pdoResult){ + echo("Error during dbQuery!\n"); + echo("DB-Error:\n"); var_dump($aDbConnection->errorInfo()); +// var_dump($aQueryString); +// var_dump($aBindArray); +// echo($pdoStatement.errorInfo()); + } + if($someOptions['dontFetch']){ + $ret = NULL; + } + else{ + $ret = $pdoStatement->fetchAll(PDO::FETCH_ASSOC); + } + } + catch(PDOException $db_error){ + print "Error!: " . $db_error->getMessage() . "
"; + return null; + } +// Zeichensatzkonvertierung + if( is_array($ret) ){ + foreach($ret as &$entry){ + array_walk( + $entry, + function (&$value, $key, $someOptions) { + $value = iconv($someOptions['dbCharset'], $someOptions['outCharset'], $value); + }, + $someOptions + ); + } + } +//var_dump($ret); +//var_dump($aQueryString); +//var_dump($aBindArray); +return $ret; +} + +function getLastAttendances($db, $minDate=null){ +if ($minDate == null){ + $minDate = new DateTime; + $minDate->sub(new DateInterval("P1M")); // from the current date subtract a *P*eriod of *1* *M*onth +} + + $query = << array('value' => $minDate->format('Y-m-d'), 'data_type' => PDO::PARAM_STR) + ); + $options = array(); + $ret = dbQuery($db, $query, $params, $options); +return $ret; +} + +function getUsersWithAttribute($dbConnection, $attributeName){ + $query = <<userAttributes` + ON `cwsvjudo`.`wkParticipo_Users`.`id` =`cwsvjudo`.`wkParticipo_user<=>userAttributes`.`userId` +WHERE `cwsvjudo`.`wkParticipo_user<=>userAttributes`.`attributeId` IN ( + SELECT `id` FROM `cwsvjudo`.`wkParticipo_userAttributes` WHERE `name` = :attributeName +); +SQL; + $params = array( + ':attributeName' => array('value'=>$attributeName, 'data_type'=>PDO::PARAM_STR) + ); +return dbQuery($dbConnection, $query, $params); +} + +function giveUserAnUserAttribute($dbConnection, $userId, $attributeName){ + $query = <<userAttributes` (`userId`, `attributeId`) +SELECT :userId, `id` +FROM `cwsvjudo`.`wkParticipo_userAttributes` +WHERE `name` = :attributeName; +SQL; + $params = array( + ':userId' => array('value'=>$userId, 'data_type'=>PDO::PARAM_INT), + ':attributeName' => array('value'=>$attributeName, 'data_type'=>PDO::PARAM_STR) + ); +return dbQuery($dbConnection, $query, $params); +} + +function hasUserAttribute($dbConnection, $userId, $attributeName){ + $query = <<userAttributes`.userId, `wkParticipo_userAttributes`.name +FROM `wkParticipo_user<=>userAttributes` LEFT JOIN `wkParticipo_userAttributes` +ON `wkParticipo_user<=>userAttributes`.`attributeId` = `wkParticipo_userAttributes`.`id` +WHERE `wkParticipo_userAttributes`.name = :attributeName AND userId=:userId;", +SQL; + $params = array( + ':userId' => array('value'=>$userId, 'data_type'=>PDO::PARAM_INT), + ':attributeName' => array('value'=>$attributeName, 'data_type'=>PDO::PARAM_STR) + ); + $attributedUsers = dbQuery($dbConnection, $query, $params); + foreach($attributedUsers as $u) + if($u['userId']==$userId) + return true; +return false; +} + +function giveJudokasAttendence($dbConnection, $date, $ids){ + $values = array(); + try{ + foreach( $ids as $id){ + array_push( $values, "(\"".$date."\", ".$id.")");; + } + $query = "INSERT INTO `cwsvjudo`.`anwesenheit` (`date`, `userId`) VALUES ".join(",", $values).";"; + dbQuery($dbConnection, $query, array(), ['dontFetch' => true]); + } + catch(PDOException $db_error){ + print "Error!: " . $db_error->getMessage() . "
"; + return null; + } +} + +function getUsersKidsIds($db, $userId){ + $query = <<['value'=>$userId, 'data_type'=>PDO::PARAM_INT]]; + $result = dbQuery($db, $query, $params); +return $result; +} + +function getUsersKids($db, $userId){ + $query = <<['value'=>$userId, 'data_type'=>PDO::PARAM_INT]]; + $result = dbQuery($db, $query, $params); +return $result; +} + +// updates corona data of an user +function updateCoronaData($db, $userId, $columnName, $columnValue){ + $coronaColumnNames = ["corona_PLZ", "corona_telephon", "corona_eMail"]; + + if( !in_array( $columnName, $coronaColumnNames) ){ + return; + } + $query = "UPDATE `cwsvjudo`.`wkParticipo_Users` SET `".$columnName."`=:val WHERE `id`=:id;"; + $params = array( + ':val' => array('value'=>$columnValue, 'data_type'=>PDO::PARAM_STR), + ':id' => array('value'=>$userId, 'data_type'=>PDO::PARAM_INT) + ); + dbQuery($db, $query, $params); +return; +} + +function addCoronaUser($db, $name, $vorname, $corona_PLZ, $corona_telephon, $corona_eMail){ + $query = << array('value'=>$name, 'data_type'=>PDO::PARAM_STR), + ':vorname' => array('value'=>$vorname, 'data_type'=>PDO::PARAM_STR), + ':plz' => array('value'=>$corona_PLZ, 'data_type'=>PDO::PARAM_STR), + ':telephon' => array('value'=>$corona_telephon, 'data_type'=>PDO::PARAM_STR), + ':email' => array('value'=>$corona_eMail, 'data_type'=>PDO::PARAM_STR), + ); + dbQuery($db, $query, $params); + + $newId = $db->lastInsertId(); + giveUserAnUserAttribute($db, $newId, "inTraining"); +return; +} + +function giveUserAnAchievement($db, $userId, $achievementId){ + $query = <<user` (`userId`, `achievementId`) VALUE (:userId, :achievementId); +SQL; + $params = [':userId'=>['value'=>$userId, 'data_type'=>PDO::PARAM_INT], 'achievementId'=>['value'=>$achievementId, 'data_type'=>PDO::PARAM_INT]]; + dbQuery($db, $query, $params); +return; +} + +function isUserAdmin($dbConn, $userId){ + $adminUsers = + dbQuery( + $dbConn, + "SELECT `wkParticipo_user<=>userAttributes`.userId, `wkParticipo_userAttributes`.name from `wkParticipo_user<=>userAttributes` LEFT JOIN `wkParticipo_userAttributes` ON `wkParticipo_user<=>userAttributes`.attributeId = `wkParticipo_userAttributes`.id WHERE `wkParticipo_userAttributes`.name = :attributeName;", + array(":attributeName"=>array('value'=>"isAdmin", 'data_type'=>PDO::PARAM_STR)) + ); + foreach($adminUsers as $adminUser) + if($adminUser['userId']==$userId) + return true; +return false; +} + +function getUserData($db, $userId){ + $query = <<['value'=>$userId, 'data_type'=>PDO::PARAM_INT]]; + $userData = dbQuery($db, $query, $params); +return $userData[0]; +} + +function getAchievements($db){ + $query = <<['value'=>$id, 'data_type'=>PDO::PARAM_INT]]; +return dbQuery($db, $query, $params); +} + +function addAchievement($db, $name, $rootId, $achievementGroupId, $level, $description, $imgUrl){ +// var_dump($db); + if($rootId=="") + $rootId=null; + if($imgUrl=="") + $imgUrl=null; + $query = << ['value'=>$name, 'data_type'=>PDO::PARAM_STR], + ':rootId' => ['value'=>$rootId, 'data_type'=>PDO::PARAM_INT], + ':achievementGroupId' => ['value'=>$achievementGroupId, 'data_type'=>PDO::PARAM_INT], + ':level' => ['value'=>$level, 'data_type'=>PDO::PARAM_INT], + ':description' => ['value'=>$description, 'data_type'=>PDO::PARAM_STR], + ':imgUrl' => ['value'=>$imgUrl, 'data_type'=>PDO::PARAM_STR], + ]; + dbQuery($db, $query, $params, ['dontFetch'=>true]); +return; +} + +function addAchievementGroup($db, $name, $unlockingAchievementId, $imgUrl){ + if($unlockingAchievementId=="") + $unlockingAchievementId=null; + if($imgUrl=="") + $imgUrl=null; + $query = << ['value'=>$name, 'data_type'=>PDO::PARAM_STR], + ':unlockingAchievementId' => ['value'=>$unlockingAchievementId, 'data_type'=>PDO::PARAM_INT], + ':imgUrl' => ['value'=>$imgUrl, 'data_type'=>PDO::PARAM_STR], + ]; + dbQuery($db, $query, $params, ['dontFetch'=>true]); +return; +} + +function updateAchievement($db, $achievementId, $name, $rootId, $achievementGroupId, $level, $description, $imgUrl){ + if($rootId=="") + $rootId=null; + if($imgUrl=="") + $imgUrl=null; + $query = << ['value'=>$name, 'data_type'=>PDO::PARAM_STR], + ':achievementGroupId' => ['value'=>$achievementGroupId, 'data_type'=>PDO::PARAM_INT], + ':rootId' => ['value'=>$rootId, 'data_type'=>PDO::PARAM_INT], + ':level' => ['value'=>$level, 'data_type'=>PDO::PARAM_INT], + ':description' => ['value'=>$description, 'data_type'=>PDO::PARAM_STR], + ':imgUrl' => ['value'=>$imgUrl, 'data_type'=>PDO::PARAM_STR], + ':achievementId' => ['value'=>$achievementId, 'data_type'=>PDO::PARAM_INT], + ]; + dbQuery($db, $query, $params, ['dontFetch'=>true]); +return; +} + +function updateAchievementGroup($db, $achievementGroupId, $name, $unlockingAchievementId, $imgUrl){ + if($unlockingAchievementId=="") + $unlockingAchievementId=null; + if($imgUrl=="") + $imgUrl=null; + $query = << ['value'=>$achievementGroupId, 'data_type'=>PDO::PARAM_INT], + ':name' => ['value'=>$name, 'data_type'=>PDO::PARAM_STR], + ':unlockingAchievementId' => ['value'=>$unlockingAchievementId, 'data_type'=>PDO::PARAM_INT], + ':imgUrl' => ['value'=>$imgUrl, 'data_type'=>PDO::PARAM_STR], + ]; + dbQuery($db, $query, $params, ['dontFetch'=>true]); +return; +} + +function setBday($db, $userId, $bday){ + $query = << ['value'=>$bday, 'data_type'=>PDO::PARAM_STR], + ':userId' => ['value'=>$userId, 'data_type'=>PDO::PARAM_INT] + ]; + dbQuery($db, $query, $params, ['dontFetch'=>true]); +return; +} + +function setRecord($db, $userId, $achievementGroupId, $value){ +$u = getUserData($db, $userId); + $query = << ['value'=>$achievementGroupId, 'data_type'=>PDO::PARAM_INT], + ':ageClass' => ['value'=>record::birthday2ageClass($u['gebDatum']), 'data_type'=>PDO::PARAM_INT], + ':userId' => ['value'=>$userId, 'data_type'=>PDO::PARAM_INT], + ':value' => ['value'=>$value, 'data_type'=>PDO::PARAM_INT], + ]; + dbQuery($db, $query, $params, ['dontFetch'=>true]); +//var_dump($userId, $achievementGroupId, $value); +//var_dump($query, $params); +return; +} + +function canUserGetAchievementToday($db, $userId){ + $achievements = getUsersAchievements($db, $userId); + foreach($achievements as $a){ + if( date('Ymd') == date('Ymd', strtotime($a['timestamp'])) ){ + return false; + } + } +return true; +} + +?> diff --git a/homepage/machs/lib/machs/achievementGroup.php b/homepage/machs/lib/machs/achievementGroup.php new file mode 100644 index 0000000..ee5af83 --- /dev/null +++ b/homepage/machs/lib/machs/achievementGroup.php @@ -0,0 +1,422 @@ +setAchievementGroupData( + $r['id'], + $r['name'], + $r['unlockingAchievementId'], + $r['imageUrl'], + $r['canHaveRecords'] + ); + $groups[$gid]->getAchievements(['force'=>true]); + } + return $groups; + } + + //getter functions for the (primitive) member variables + function getId(){return $this->id;} + function getName(){return $this->name;} + function getUnlockingAchievementId(){return $this->unlockingAchievementId;} + function getImageUrl(){return $this->imageUrl;} + function canHaveRecords(){return $this->canHaveRecords;} + + /// returns list of achievements + /// - returns the previously loaded achievements + /// - reloads them if null or forced + function getAchievements($options=[]){ + // standards for Options: + $force = $options['force']??false; // load the achievements from the db even if ther already are some in the group->achievements member + if(($this->achievements == null) or ($force)){ + $query = <<['value'=>$this->id, 'data_type'=>PDO::PARAM_INT]]; + $this->achievements = dbQuery(self::$db, $query, $params); + } + return $this->achievements; + } // end getAchievements + + /// Load the achievementgroup $id from the db (into this) + function loadAchievementGroupFromDb($id){ + $query = <<['value'=>$id, 'data_type'=>PDO::PARAM_INT]]; + $result = dbQuery(self::$db, $query, $params); + + $this->setAchievementGroupData( + $result[0]['id'], + $result[0]['name'], + $result[0]['unlockingAchievementId'], + $result[0]['imageUrl'], + $result[0]['canHaveRecords'] + ); + $this->getAchievements(['force'=>true]); + } + + /// Set the member data of the group + function setAchievementGroupData($id, $name, $unlockingAchievementId=null, $imageUrl=null, $canHaveRecords=null){ + $this->id = (int)$id; + $this->name = $name; + $this->unlockingAchievementId = ($unlockingAchievementId == null ? null : (int)$unlockingAchievementId); + $this->imageUrl = $imageUrl; + $this->canHaveRecords = (bool)$canHaveRecords; +# echo("bool(".$canHaveRecords.")=".$this->canHaveRecords."\n"); +# var_dump($canHaveRecords, $this->canHaveRecords); + } + + /// get the next achievement, the user has to accomplish in that group + function getUsersNextAchievement($userId){ + $groupsAchievements = $this->getAchievements(); + if(count($this->getAchievements()) < 1) + return null; + $usersAchievementsIds = collectKeysValues( + $this->getUsersAchievements($userId), + 'achievementId' + ); + $usersNextAchievement = null; + foreach($groupsAchievements as $ga){ + if(!in_array($ga['id'], $usersAchievementsIds)){ + if($usersNextAchievement == null){ + $usersNextAchievement = $ga; + continue; + } + if( $usersNextAchievement['level'] > $ga['level'] ){ + $usersNextAchievement = $ga; + }; + } + } + return $usersNextAchievement; + } + + /// get all achievements, that unlock something + static function getUnlockingAchievements(){ + // get all achievements + } + + /// gets all achievements a user reached in that group as Array + function getUsersAchievements($userId, $options=[]){ + $getAll = $options['getAll']??false; // ignore restriction to this group + + $query = <<user` + JOIN `cwsvjudo`.`achievements` + ON `cwsvjudo`.`achievements<=>user`.`achievementId` = `cwsvjudo`.`achievements`.`id` + JOIN `cwsvjudo`.`machs_achievementGroups` + ON `cwsvjudo`.`achievements`.`achievementGroupId` = `cwsvjudo`.`machs_achievementGroups`.`id` +WHERE `cwsvjudo`.`achievements<=>user`.`userid` = :userId +SQL; + if(!$getAll){ + $query.=" AND `cwsvjudo`.`machs_achievementGroups`.`id` = :achievementGroupId "; + $query.="ORDER BY `cwsvjudo`.`achievements`.`level` DESC"; + } + $query.=";"; + $params[':userId'] = array('value'=>$userId, 'data_type'=>PDO::PARAM_INT); + if(!$getAll) + $params[':achievementGroupId'] = array('value'=>$this->getId(), 'data_type'=>PDO::PARAM_INT); + $result = dbQuery($this->getDbConnection(), $query, $params); +# var_dump($query); +# var_dump($result); + return $result; + } + + /// returns the materialize card html code of the Achievementgroup + /// + /// @param $uId id of the user the achievements should be + function asHtmlCard($uId, $options=[]){ + // Setting standard options + $noForm = $options['noForm']??true; // for deactivating the give achievement form + + $retHtml = ""; + + $userData = record::getUserData($uId); + $usersAchievements = $this->getUsersAchievements( $uId, ['getAll'=>true] ); + $usersAchievementIds=[null]; + foreach($usersAchievements as $a){ + $usersAchievementIds[]=(int)$a['achievementId']; + } + // If the user hasn't have the needed Achievement + if(!in_array($this->getUnlockingAchievementId(), $usersAchievementIds)) + return ""; + + $records = record::getGroupsRecords( + $this->getId(), + record::birthday2ageClass($userData[0]['gebDatum']) + ); + $achievements = $this->getAchievements(); + + $retHtml .= "
";/// @todo gehört eigentlich nicht mit zur karte + $retHtml .= "
"; + + // image + title + if($this->imageUrl != null){ + $retHtml .= "
imageUrl."\">"; + $retHtml .= "".$this->name.""; + $retHtml .= "
"; + } + else + $retHtml .= "".$this->name.""; + + // content + $retHtml .= "
"; + // - das nächste achievement + // - als collapsible (list): des users erreichte achievements + + $usersAchievements = $this->getUsersAchievements($uId); + $usersNextAchievement = $this->getUsersNextAchievement($uId); + $retHtml .= "
Nächstes Achievement
"; + $retHtml .= "
  • "; + $retHtml .= "
    "; + if(count($usersAchievements)>0) + $retHtml .= "﹀ "; + $retHtml .= $usersNextAchievement['name'].": ".$usersNextAchievement['description']."
    "; + + if(count($usersAchievements)>0){ + $retHtml .= "
      "; + foreach($this->getUsersAchievements($uId) as $a) + $retHtml .= "
    • ✓ ".$a['achievementName'].": ".$a['description']."
    • "; + $retHtml .= "
    ";// end body + } + $retHtml .= "
";// end collapsible + + // show the current record + if($this->canHaveRecords()){ + $retHtml .= "
Aktueller Rekord
"; + if( validateDate($userData[0]['gebDatum'])){ + $retHtml.=record::arrayRecord2collapsible($records[0], $userData[0], $this->getId(), $noForm); + } + else{ + $retHtml.="
Rekorde können erst angezeigt werden, wenn das Geburtsdatum korrekt gesetzt wurde!
"; + } + } + + $retHtml .= $this->listUnlockableGroups(); + + $retHtml .= "
";// end card-content + + if(!$noForm){ + $retHtml .= "
"; + $retHtml .= "
"; + $retHtml .= ""; + $retHtml .= ""; + $retHtml .= ""; + $retHtml .= ""; + if( canUserGetAchievementToday( $this->getDbConnection(), $uId) or isUserAdmin($this->getDbConnection(), $_SESSION['user']['userId']) ){ +// $retHtml .= ""; + $retHtml .= ""; + } + else{ + $retHtml .= ""; + } + $retHtml .= "
"; + $retHtml .= "
";// end card-action + } + $retHtml .= "
";// end card + $retHtml .= "
";// end col + return $retHtml; + }// end asHtmlCard + + /// create html code for a for to add an achievementGroup + static function htmlAddAchievementGroupForm(){ + $html = ""; + $html .= "
"; + $html .= ""; + $html .= ""; + $html .= ""; + $html .= ""; + $html .= ""; + $html .= ""; + $html .= "
"; + return $html; + } + + /// create html code for a for to edit an achievementGroup + function htmlEditAchievementGroupForm(){ + $html = ""; + $html .= "Edit ".$this->getName(); + $html .= "
"; + $html .= ""; + $html .= ""; + $html .= "getId()."\"/>"; + $html .= ""; + $html .= "getName()."\"/>"; + $html .= ""; + $html .= "getUnlockingAchievementId()."\"/>"; + $html .= ""; + $html .= "getImageUrl()."\"/>"; + $html .= ""; + $html .= "
"; + return $html; + } + + static function htmlAutoAddAchievementsForm($achievementGroupId, $messageTemplate=null, $from=null, $to=null, $step=null){ + $html = ""; + $html .= "
"; + + $html .= ""; + $html .= ""; + $html .= ""; + + $html .= ""; + $html .= ""; + + $html .= ""; + $html .= ""; + $html .= ""; + $html .= ""; + $html .= ""; + $html .= ""; + + $html .= ""; + $html .= "
"; + return $html; + } + + /// auto generate the achievements for this group + /// @todo only for empty groups? + function autoAddAchievements($messageTemplate, $from, $to, $step){ + if(count($this->getAchievements()) > 0){ + echo("Won't auto-add Achievements to non-empty AchievementGroup!"); + var_dump($this->getAchievements()); + return; + } + $level = 1; + if($step > 0){ + for ($value = (int)$from; $value <= (int)$to; $value+=(int)$step) { + $name = $this->getName()." ".intToRomanRepresentation($level++); + $description = str_replace("%value%", (string)$value, $messageTemplate); + $this->addAchievement($name, $description, $level); + } + } + else{ + for ($value = (int)$from; $value >= (int)$to; $value+=(int)$step) { + $name = $this->getName()." ".intToRomanRepresentation($level++); + $description = str_replace("%value%", (string)$value, $messageTemplate); + $this->addAchievement($name, $description, $level); + } + } + } + + // adds an achievement to the group (in the db!) + function addAchievement($name, $description, $level, $rootId=null){ + addAchievement( + $this->getDbConnection(), + $name, + $rootId, + $this->getId(), + $level, + $description, + null + ); + } + + function usersAchievementList($uId){ + $usersAchievements = $this->getUsersAchievements($userId); + $retHtml .= "
    "; + $retHtml .= "
  • "; + $body = "
      "; + foreach($achievements as $a){ + if(in_array((int)$a['id'], $usersAchievementIds)){ + $body .= "
    • ✓ ".$a['name'].": ".$a['description']; + $body .= "
    • "; + } + else{ + $body .= "
    "; + break; + } + } + $header = "
    ".$a['name'].": ".$a['description']."
    "; + $retHtml .= $header.$body; + $retHtml .= "
  • "; + $retHtml .= "
";// end collapsible +} + + function listUnlockableGroups(){ + $achievementGroups = achievementGroup::getAllAchievementGroups(); + $achievements = []; + foreach($this->getAchievements() as $a) + $achievements[(int)$a['id']] = $a; + $retHtml ="
"; + foreach($achievementGroups as $g){ + if(array_key_exists( $g->getUnlockingAchievementId(), $achievements)){ + $retHtml .= "
Mit Level ".intToRomanRepresentation($achievements[(int)$g->getUnlockingAchievementId()]['level'])." wird ".$g->getName()." freigeschaltet!
"; + } + } + $retHtml .= "
"; + return $retHtml; + } +} + +/// convert an int number to roman representation +/// @param int $number +/// @return string +function intToRomanRepresentation($number){ + $map = array('M' => 1000, 'CM' => 900, 'D' => 500, 'CD' => 400, 'C' => 100, 'XC' => 90, 'L' => 50, 'XL' => 40, 'X' => 10, 'IX' => 9, 'V' => 5, 'IV' => 4, 'I' => 1); + $returnValue = ''; + while ($number > 0) { + foreach ($map as $roman => $int) { + if($number >= $int) { + $number -= $int; + $returnValue .= $roman; + break; + } + } + } + return $returnValue; +} + +/// in an array of arrays collect all values with specific key +function collectKeysValues($array, $key){ + $values = []; + foreach($array as $a) + $values[]=$a[$key]; + return $values; +} +?> diff --git a/homepage/machs/lib/machs/materializeInit.php b/homepage/machs/lib/machs/materializeInit.php new file mode 100644 index 0000000..775f066 --- /dev/null +++ b/homepage/machs/lib/machs/materializeInit.php @@ -0,0 +1,18 @@ + + diff --git a/homepage/machs/lib/machs/sidenav.php b/homepage/machs/lib/machs/sidenav.php new file mode 100644 index 0000000..4938c34 --- /dev/null +++ b/homepage/machs/lib/machs/sidenav.php @@ -0,0 +1,16 @@ + + +☰ MeinACHievementSystem + diff --git a/homepage/machs/lib/record.php b/homepage/machs/lib/record.php new file mode 100644 index 0000000..6cb5dbe --- /dev/null +++ b/homepage/machs/lib/record.php @@ -0,0 +1,340 @@ +user` +JOIN `wkParticipo_Users` + ON `wkParticipo_Users`.`id` = `achievements<=>user`.`userId` +GROUP BY `wkParticipo_Users`.`id` +ORDER BY `COUNT(*)` DESC; +SQL; + return dbQuery(self::$db, $query); + } + + public static function getAllRecords(){ + $query = <<['value'=>$userId, 'data_type'=>PDO::PARAM_INT]]); + } + + // request the records of a group together with its holder + // @param $groupId id of the group of achievements where the records are wanted + // @param $ageClass the age class (as int only) for which the record is holding + // + // a record of an achievement group consists of: + // - a value + // - an age class + public static function getGroupsRecords($groupId, $ageClass=null){ + $query = "SELECT *, `cwsvjudo`.`machs_records`.`id` as `recordId`, `cwsvjudo`.`wkParticipo_Users`.`name` as `userName` FROM `cwsvjudo`.`machs_records` "; + $query.= " JOIN `cwsvjudo`.`wkParticipo_Users` "; + $query.= " ON `cwsvjudo`.`machs_records`.`userId` = `cwsvjudo`.`wkParticipo_Users`.`id` "; + $query.= " JOIN `cwsvjudo`.`machs_achievementGroups` "; + $query.= " ON `cwsvjudo`.`machs_achievementGroups`.`id` = `cwsvjudo`.`machs_records`.`achievementGroupId` "; + $query.= " WHERE `cwsvjudo`.`machs_records`.`achievementGroupId` = :groupId "; + $params =[ + 'groupId'=>[ 'value'=>$groupId, 'data_type'=>PDO::PARAM_INT ] + ]; + if($ageClass != null){ + $query.= " AND `cwsvjudo`.`machs_records`.`ageClass` <= :ageClass "; + $params['ageClass'] = [ 'value'=>$ageClass, 'data_type'=>PDO::PARAM_INT ]; + } + $query.= "ORDER BY `cwsvjudo`.`machs_records`.`value` DESC;"; + return dbQuery(self::$db, $query, $params); + } + + /// @param $r record as associative array + public static function arrayRecord2htmlDl($r){ + $retHtml = "
"; + foreach(self::$colNames as $i) + $retHtml.= "
".$i."
".$r[$i]."
"; + $retHtml.= "
"; + return $retHtml; + } + + public static function arrayRecord2htmlCardAction($r, $u, $gid){ + $retHtml.= "Rekord melden"; + $retHtml.= "
"; + $retHtml.= "
"; + $retHtml.= "Rekorde stellen in jeder Achievementgruppe und Altersklasse die Bestleistung unter allen Judoka dar. Rekorde können unabhänging vom eigenen, aktuellen Achievementstand aufgestellt werden."; + $retHtml.= "Die Rekorde der jüngeren gelten auch für die älteren, aber nicht umgekehrt. "; + $retHtml.= "Damit ein Rekord auch eingetragen wird, muss er mit einem Nachweis in Videoform gemeldet werden."; + $retHtml.= "

Rekord melden

"; + $retHtml.= "Um einen Rekord zu melden, lade ein Video des Rekordes hoch:"; + $retHtml.= htmlUsersUploadBox(self::$db, $u['id']); + $retHtml.= "Anschließend kannst Du den Rekord melden:"; + $retHtml.= "
"; + if(isUserAdmin(record::$db, $_SESSION['user']['userId'])){ + $retHtml.= ""; + } + else{ + $retHtml.= ""; + } + $retHtml.= ""; + $retHtml.= ""; + $retHtml.= $u['vorname']." ".$u['name']." hat geschafft."; + + if(isUserAdmin(record::$db, $_SESSION['user']['userId'])){ + $retHtml.= ""; + } + else{ + $retHtml.= ""; + } + $retHtml.= "
"; + $retHtml.= "
"; + $retHtml.= "
"; + $retHtml.= "Zurück"; + $retHtml.= "
"; + $retHtml.= "
"; +// $retHtml.= "
"; + return $retHtml; + } + + /// @param $r record joined with it's holder as associative array + /// @param $u user for whom the record is shown + public static function arrayRecord2collapsible($r, $u, $gid, $noForm=true){ + $currentRecord = ""; + if(empty($r)){ + $currentRecord.= "Noch kein Rekord für die Altersklasse U".record::birthday2ageClass($u['gebDatum']); + } + else{ + $currentRecord.= $r['vorname']." ".$r['userName']." mit ".$r['value']." in der U".$r['ageClass']; + } + + $recordRequest = record::arrayRecord2htmlCardAction($r, $u, $gid, $noForm); + + return << +
  • +
    ﹀ $currentRecord
    +
    $recordRequest
    +
  • + +COLLAPSIBLE; + } + + /// @param $r record joined with it's holder as associative array + /// @param $u user for whom the record is shown + public static function arrayRecord2htmlCard($r, $u, $gid, $noForm=true, $frameTag="div"){ + $group = new achievementGroup; + $group->loadAchievementGroupFromDb($gid); + + $retHtml.= ""; + var_dump($group->canHaveRecords()); + if($group->canHaveRecords()){ + $retHtml = "<".$frameTag." class=\"card\">"; + $retHtml.= "
    "; + $retHtml.= "Zu schlagender Rekord"; + + if(empty($r)){ + $retHtml.= "Noch kein Rekord für die Altersklasse U".record::birthday2ageClass($u['gebDatum']); + } + else{ +// $retHtml.=record::arrayRecord2collapsible($records[0], $userData[0], $this->getId(), $noForm); + $retHtml.=record::arrayRecord2collapsible($r, $u, $gid, $noForm); + //$retHtml.= $r['vorname']." ".$r['name']." mit ".$r['value']." in der U".$r['ageClass']; + } + $retHtml.= "
    ";//end card-content + +// if(!$noForm){ +// $retHtml.= record::arrayRecord2htmlCardAction($r, $u, $gid, $noForm); +// } + $retHtml.= ""; + } + return $retHtml; + } + + + + + public static function birthday2ageClass($birthdateString){ + $birthDate = DateTime::createFromFormat("Y-m-d", $birthdateString); + $birthYear= (int)$birthDate->format("Y"); + $thisYear = (int)date('Y'); + return $thisYear - $birthYear + 1; + } + + // get an ageClasses records including its holders + public static function getRecordsOfAgeClass($ageClass, $achievementGroup, $options=[]){ + $query = <<['value'=>$ageClass, 'data_type'=>PDO::PARAM_INT], + ':achievementGroupId'=>['value'=>$achievementGroupId, 'data_type'=>PDO::PARAM_INT], + ]; + $returns = query($this->getDbConnection(), $query, $params); + return $records; + } + + // returns all age classes with records + public static function getAgeClassesWithRecord($achievementGroupId=null){ + $params = null; + $query="SELECT DISTINCT `ageClass` FROM `cwsvjudo`.`machs_records` "; + if($achievementGroupId != null){ + $query.="WHERE `achievementGroupId` = :achievementGroupId "; + $params=[]; + $params[':achievementGroupId'] = ['value'=>$achievementGroupId, 'data_type'=>PDO::PARAM_INT]; + } + $query.="ORDER BY `ageClass`"; + $ageClasses = dbQuery(self::$db, $query, $params); + return $ageClasses; + } + + // load the achievement from the DB + public function loadFromDb($id){ + $query = "SELECT * from `cwsvjudo`.`machs_records` WHERE `id`=:id;"; + $params = [':id'=>['value'=>$id, 'data_type'=>PDO::PARAM_INT]]; + $achievements = query($this->getDbConnection(), $query, $params); + $this->setFromAssocArray($achievements[0]); + } + // set the members of the record via an associative array (like the ones, that are returned by dbquery) + public function setFromAssocArray($assocArray){ + $this->id = (int)$assocArray['id']; + $this->achievementGroupId = (int)$assocArray['achievementGroupId']; + $this->ageClass = (int)$assocArray['ageClass']; + $this->userId = (int)$assocArray['userId']; + $this->timestap = $assocArray['userId']; + $this->value = $assocArray['value']; + } + + static public function htmlRanking($recordList){ + if(empty($recordList)) + return ""; + $html = ""; + $html.= ""; + foreach($recordList as $record){ + $html.=""; + } + $html.= "
    JudokaRekordVideo
    ".$record['vorname']." ".$record['name']."".$record['value']."Video
    "; + return $html; + } +} + +/// Als String gegebene Altersklassen als Jahrgangsintervalle +/// ausdrücken +function akListString2jgArray($akListString, $year = NULL ){ +$ret = array(); + if($year==NULL) + $year=date("Y"); + else{ + if( !((int)$year == $year && (int)$year >= 0) ) + $year=date("Y"); + } + + $year = (int)$year; + + foreach(explode(" ", $akListString) as $ak) + array_push( + $ret, + akString2jgIntervall($ak, $year) + ); +return $ret; +} + +/// Aus einer als String gegebenen Altersklasse ein Jahrgangsintervall +/// machen +function akString2jgIntervall($akString, $year=null){ +if($year==NULL) + $year=date("Y"); +else{ + if( !((int)$year == $year && (int)$year >= 0) ) + $year=date("Y"); +} + +$ret= array(NULL, NULL); + + // Speziell für die Ux-Altersklassen + // Es fehlt noch das <=U + $akUmatchString = "/(.*)U(.*)/"; + $matches = array(); + preg_match($akUmatchString, $akString, $matches); + // Wenn wir nicht den gesamten akString Matchen ist etwas schief + // gelaufen + if($matches[0]==$akString){ + // Das ausgelesene Alter der Ux sollte eine positive Integer sein, + // sonst ist was schiefgelaufen + $ageLimit = (int)$matches[2]; + if( ($ageLimit == $matches[2] && $ageLimit > 0) ){ + $ret[0] = $year-$ageLimit+1; + + if($matches[1] == "") + $ret[1] = $year-$ageLimit+2; + else{ + if($matches[1] == "-") + $ret[1] = $year-$ageLimit+3; + else{ + if($matches[1] == "--") + $ret[1] = $year-$ageLimit+4; + } + } + } + return $ret; + } + + // Speziell Altersklassen der Form Jg.x-y + $akUmatchString = "/Jg\.(.*)\-(.*)/"; + $matches = array(); + preg_match($akUmatchString, $akString, $matches); + // Wenn wir nicht den gesamten akString Matchen ist etwas schief + // gelaufen + if($matches[0]==$akString){ + $ret[0]=(int)$matches[1]; + $ret[1]=(int)$matches[2]; + + return $ret; + } +return $ret; +} + +function validateDate($date, $format = 'Y-m-d') +{ + $d = DateTime::createFromFormat($format, $date); + // The Y ( 4 digits year ) returns TRUE for any integer with any number of digits so changing the comparison from == to === fixes the issue. + return $d && $d->format($format) === $date; +} +?> diff --git a/homepage/machs/local/.htaccess b/homepage/machs/local/.htaccess new file mode 100644 index 0000000..3a42882 --- /dev/null +++ b/homepage/machs/local/.htaccess @@ -0,0 +1 @@ +Deny from all diff --git a/homepage/machs/local/achievementsConf.php b/homepage/machs/local/achievementsConf.php new file mode 100644 index 0000000..3517089 --- /dev/null +++ b/homepage/machs/local/achievementsConf.php @@ -0,0 +1,10 @@ + diff --git a/homepage/machs/local/dbConf.php b/homepage/machs/local/dbConf.php new file mode 100644 index 0000000..97efeba --- /dev/null +++ b/homepage/machs/local/dbConf.php @@ -0,0 +1,8 @@ + diff --git a/homepage/machs/login.php b/homepage/machs/login.php new file mode 100644 index 0000000..2c8cc71 --- /dev/null +++ b/homepage/machs/login.php @@ -0,0 +1,113 @@ +connect_error) { + $message['error'] = 'Datenbankverbindung fehlgeschlagen: ' . $mysqli->connect_error; + } else { + $query = sprintf( + "SELECT id, loginName, pwHash, config FROM wkParticipo_Users WHERE loginName = '%s'", + $mysqli->real_escape_string($_POST['f']['username']) + ); + $result = $mysqli->query($query); + if ($row = $result->fetch_array(MYSQLI_ASSOC)) { + if( password_verify( $_POST['f']['password'], $row['pwHash']) ){ + session_start(); + $_SESSION = array( + 'login' => true, + 'user' => array( + 'username' => $row['loginName'], + 'userId' => $row['id'], + 'userConfig' => json_decode($row['config'], true) + ), + ); + $message['success'] = 'Anmeldung erfolgreich, weiter zum Inhalt.'; + PHPCount::AddHit("machs-Login ".$_POST['f']['username']); + header('Location: http://' . $_SERVER['HTTP_HOST'] . '/machs?user=' . $_POST['f']['username']); + } else { + sleep(1); + $message['error'] = 'Das Kennwort ist nicht korrekt.'; + } + } + } +return $message; +} + + +if (isset($_SESSION['login'])) { + header('Location: http://' . $_SERVER['HTTP_HOST'] . '/index.php'); +} +else{ + if (!empty($_POST)) { + if ( + empty($_POST['f']['username']) || + empty($_POST['f']['password']) + ) { + $message['error'] = 'Es wurden nicht alle Felder ausgefüllt.'; + } else { + + $message = checkCredentials($_POST['f']['username'], $_POST['f']['password'], $db_server, $db_user, $db_password, $db_name); + if( !isset($message['error']) ) + $message['notice'] = "Achievement-System der Judoka des Chemnitzer WSV"; + } + } +} + +?> + + + + + + + + + + + + Login des Achievementsystemes der Judoka des Chemnitzer WSV + + + + +

    Achievementsystem der Judoka des Chemnitzer WSV

    + +
    +
    + Benutzerdaten +
    + + /> +
    +
    + + +
    +
    +
    +
    + +
    +
    +
    Hinweise +
      +
    • Logindaten sind über den Übungsleiter zu beantragen.
    • +
    • Dieses Projekt ist in mehr oder weniger aktiven Entwicklung. Sollte mal was nicht funktionieren, kann es sein, dass ich gerade daran herumschreibe. Also ruhig zu einem späteren Zeitpunkt noch einmal probieren.
    • +
    +
    +
    + + diff --git a/homepage/machs/logout.php b/homepage/machs/logout.php new file mode 100644 index 0000000..f6ee446 --- /dev/null +++ b/homepage/machs/logout.php @@ -0,0 +1,18 @@ + diff --git a/homepage/machs/machs-config.php b/homepage/machs/machs-config.php new file mode 100644 index 0000000..2048a00 --- /dev/null +++ b/homepage/machs/machs-config.php @@ -0,0 +1,12 @@ + diff --git a/homepage/machs/machs.php b/homepage/machs/machs.php new file mode 100644 index 0000000..a7e9f04 --- /dev/null +++ b/homepage/machs/machs.php @@ -0,0 +1,23 @@ + diff --git a/homepage/machs/readMe.md b/homepage/machs/readMe.md new file mode 100644 index 0000000..0dfef94 --- /dev/null +++ b/homepage/machs/readMe.md @@ -0,0 +1,11 @@ +Animated gif erstellen: + +``` +convert \ + -delay 100 \ + -loop 5 \ + -resize 256x \ + -fuzz 10% \ + -layers optimize \ + frame-* wechselLiegeUnterarmstuetz.gif +``` diff --git a/homepage/machs/records.php b/homepage/machs/records.php new file mode 100644 index 0000000..f25e162 --- /dev/null +++ b/homepage/machs/records.php @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + Achievements + + + + + + + + + + +Rekorde"); +foreach($achievementGroups as $group){ + $ageClasses = record::getAgeClassesWithRecord($group->getId()); + if(empty($ageClasses)) + continue; + echo("

    ".$group->getName()."

    "); + foreach($ageClasses as $ageClass){ + $ageClass = $ageClass['ageClass']; + echo("

    Altersklasse U".$ageClass."

    "); + $records = record::getGroupsRecords($group->getId(), $ageClass); + echo(record::htmlRanking($records)); + } +} +?> + + + diff --git a/homepage/machs/setUserData.php b/homepage/machs/setUserData.php new file mode 100644 index 0000000..5ac43cd --- /dev/null +++ b/homepage/machs/setUserData.php @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + Benutzerdaten ändern + + + + + + + + + + + + +

    Benutzerdaten ändern

    + ".$k['vorname']." ".$k['name']."" ); + echo( htmlUsersUploadBox($dbConnection, $_SESSION['user']['userId']) ); + echo( setUserDataBox($k['kidId']) ); + } + } + ?> + + + diff --git a/homepage/machs/topAchievers.php b/homepage/machs/topAchievers.php new file mode 100644 index 0000000..cf85e5a --- /dev/null +++ b/homepage/machs/topAchievers.php @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + Top-Achievers + + + + + + + + + + +"); +foreach( record::getTopAchievers() as $t ){ +// var_dump($t); + echo("".$t['vorname']."".$t['name']."".$t['COUNT(*)'].""); +} +echo(""); + +?> + + + + diff --git a/homepage/mams/.htaccess b/homepage/mams/.htaccess new file mode 100644 index 0000000..34b4883 --- /dev/null +++ b/homepage/mams/.htaccess @@ -0,0 +1,6 @@ +AuthType Basic +AuthName "tempDirectory" +AuthUserFile /users/cwsvjudo/www/.htusers +#AuthGroupFile /users/cwsvjudo/www/.htgroups +Require user marko +#Require group admin diff --git a/homepage/mams/index.php b/homepage/mams/index.php new file mode 100644 index 0000000..b6c87d1 --- /dev/null +++ b/homepage/mams/index.php @@ -0,0 +1,100 @@ + + +
    + + + + + + + +
    + +

    Corona-Anwesenheitsliste der Judoka des Chemnitzer WSV

    +

    Anwesenheiten hinzufügen

    +
    +
    + + " /> + + +
    +
    +

    Anwesenheiten

    +

    Sende Anwesenheitsliste an eMail

    +
    + + + + +
    + $attendees){ + echo("

    ".$date."

    "); + echo(""); + echo(""); + echo(""); + echo(""); + echo(""); + echo(""); + echo(""); + echo(""); + foreach($attendees as $a){ + echo(""); + echo(""); + echo(""); + echo(""); + echo(""); + echo(""); + echo(""); + } + echo("
    namevornamePLZTelefoneMail
    ".$a['name']."".$a['vorname']."".( $a['corona_PLZ'] ? $a['corona_PLZ'] : "
    ")."
    ".( $a['corona_telephon'] ? $a['corona_telephon'] : "
    ")."
    ".( $a['corona_eMail'] ? $a['corona_eMail'] : "
    ")."
    "); + } + ?> +

    Trainee hinzufügen

    +
    + + + + + + + +
    + + diff --git a/homepage/mams/lib/.htaccess b/homepage/mams/lib/.htaccess new file mode 100644 index 0000000..3a42882 --- /dev/null +++ b/homepage/mams/lib/.htaccess @@ -0,0 +1 @@ +Deny from all diff --git a/homepage/mams/lib/api.php b/homepage/mams/lib/api.php new file mode 100644 index 0000000..3b54862 --- /dev/null +++ b/homepage/mams/lib/api.php @@ -0,0 +1,81 @@ +format("Y-m-d"), + $emailText + ); + } + catch(Exception $e) { + echo 'Message: ' .$e->getMessage(); + } +} + +function attendancesAssocArray2text($attendancesAssocArray){ + $ret = ""; + foreach($attendancesAssocArray as $date => $attendees){ + $ret .= $date."\n"; + foreach($attendees as $a){ + $ret .= "\n"; + $ret .= "Name: ".$a['name'].", ".$a['vorname']."\n"; + $ret .= "PLZ: ".$a['corona_PLZ']."\n"; + $ret .= "Tel.: ".$a['corona_telephon']."\n"; + $ret .= "eMail: ".$a['corona_eMail']."\n"; + } + $ret .= "\n"; + } +return $ret; +} + +function attendancesAssocArray2mdList($attendancesAssocArray, $date=null){ + if($date == null) + $date=new DateTime(); + $ret = "# Anwesenheitsliste zur Corona-Kontaktverfolgung der Abteilung Judo des CWSV vom ".$date->format("Y-m-d")."\n\n"; + foreach($attendancesAssocArray as $d => $attendees){ + $ret .= "## ".$d."\n"; + $i=0; + foreach($attendees as $a){ + $i += 1; + $ret .= "\n"; + $ret .= $i." ".$a['name'].", ".$a['vorname']."\n"; + $ret .= " - PLZ: ".$a['corona_PLZ']."\n"; + $ret .= " - Tel.: ".$a['corona_telephon']."\n"; + $ret .= " - eMail: ".$a['corona_eMail']."\n"; + } + $ret .= "\n"; + } +return $ret; +} +?> diff --git a/homepage/mams/lib/db.php b/homepage/mams/lib/db.php new file mode 100644 index 0000000..9200ae9 --- /dev/null +++ b/homepage/mams/lib/db.php @@ -0,0 +1,193 @@ +getMessage() ); + } +return $dbConnection; +} + +function createDb($dbConnection){ +<< array('value'=>$anUserId, 'data_type'=>PDO::PARAM_INT), +/// ':attributeId'=> array('value'=>$anAttributeId, 'data_type'=>PDO::PARAM_INT) ) +/// @param $someOption +function dbQuery($aDbConnection, $aQueryString, $aBindArray = array(), $someOptions = array()){ +// Standardbelegungen +if( empty($someOptions['dbCharset' ]) ) $someOptions['dbCharset' ] = "ISO-8859-1"; +if( empty($someOptions['outCharset']) ) $someOptions['outCharset'] = "UTF-8"; +if( empty($someOptions['dontFetch' ]) ) $someOptions['dontFetch' ] = false; +/// @toDo: Bisher wird nur die Rückgabe konvertiert. Eigentlich muss +/// doch auch die Eingabe konvertiert werden. Aber das jetzt +/// umzustellen wird schwer! Die User m Wettkampfplaner sind ja z.B. +/// als UTF8 in latin1(?) gespeichert. +/// @toDo: Die Standardwerte sollten vielleicht aus einer config +/// kommen, nicht hardcoded + try{ + $pdoStatement = $aDbConnection->prepare( $aQueryString ); + foreach( $aBindArray as $bindName => $bind ){ + $pdoStatement->bindValue( + $bindName, + $bind['value'], + (isset($bind['data_type'])?$bind['data_type']:PDO::PARAM_STR) + ); + } + $pdoResult = $pdoStatement->execute(); + if(!$pdoResult){ + echo("Error during dbQuery!\n"); + echo($aDbConnection->errorInfo(); + echo(PDOStatement::errorInfo(); + } + if($someOptions['dontFetch']){ + $ret = NULL; + } + else{ + $ret = $pdoStatement->fetchAll(PDO::FETCH_ASSOC); + } + } + catch(PDOException $db_error){ + print "Error!: " . $db_error->getMessage() . "
    "; + return null; + } +// Zeichensatzkonvertierung + if( is_array($ret) ){ + foreach($ret as &$entry){ + array_walk( + $entry, + function (&$value, $key, $someOptions) { + $value = iconv($someOptions['dbCharset'], $someOptions['outCharset'], $value); + }, + $someOptions + ); + } + } +//var_dump($ret); +//var_dump($aQueryString); +//var_dump($aBindArray); +return $ret; +} + +function getLastAttendances($db, $minDate=null){ +if ($minDate == null){ + $minDate = new DateTime; + $minDate->sub(new DateInterval("P1M")); // from the current date subtract a *P*eriod of *1* *M*onth +} + + $query = << array('value' => $minDate->format('Y-m-d'), 'data_type' => PDO::PARAM_STR) + ); + $options = array(); + $ret = dbQuery($db, $query, $params, $options); +return $ret; +} + +function getUsersWithAttribute($dbConnection, $attributeName){ + $query = <<userAttributes` + ON `cwsvjudo`.`wkParticipo_Users`.`id` =`cwsvjudo`.`wkParticipo_user<=>userAttributes`.`userId` +WHERE `cwsvjudo`.`wkParticipo_user<=>userAttributes`.`attributeId` IN ( + SELECT `id` FROM `cwsvjudo`.`wkParticipo_userAttributes` WHERE `name` = :attributeName +); +SQL; + $params = array( + ':attributeName' => array('value'=>$attributeName, 'data_type'=>PDO::PARAM_STR) + ); +return dbQuery($dbConnection, $query, $params); +} + +function giveUserAnUserAttribute($dbConnection, $userId, $attributeName){ + $query = <<userAttributes` (`userId`, `attributeId`) +SELECT :userId, `id` +FROM `cwsvjudo`.`wkParticipo_userAttributes` +WHERE `name` = :attributeName; +SQL; + $params = array( + ':userId' => array('value'=>$userId, 'data_type'=>PDO::PARAM_INT), + ':attributeName' => array('value'=>$attributeName, 'data_type'=>PDO::PARAM_STR) + ); +return dbQuery($dbConnection, $query, $params); +} + +function giveJudokasAttendence($dbConnection, $date, $ids){ + $values = array(); + try{ + foreach( $ids as $id){ + array_push( $values, "(\"".$date."\", ".$id.")");; + } + $query = "INSERT INTO `cwsvjudo`.`anwesenheit` (`date`, `userId`) VALUES ".join(",", $values).";"; + dbQuery($dbConnection, $query, array(), ['dontFetch' => true]); + } + catch(PDOException $db_error){ + print "Error!: " . $db_error->getMessage() . "
    "; + return null; + } +} + +// updates corona data of an user +function updateCoronaData($db, $userId, $columnName, $columnValue){ + $coronaColumnNames = ["corona_PLZ", "corona_telephon", "corona_eMail"]; + + if( !in_array( $columnName, $coronaColumnNames) ){ + return; + } + $query = "UPDATE `cwsvjudo`.`wkParticipo_Users` SET `".$columnName."`=:val WHERE `id`=:id;"; + $params = array( + ':val' => array('value'=>$columnValue, 'data_type'=>PDO::PARAM_STR), + ':id' => array('value'=>$userId, 'data_type'=>PDO::PARAM_INT) + ); + dbQuery($db, $query, $params); +return; +} + +function addCoronaUser($db, $name, $vorname, $corona_PLZ, $corona_telephon, $corona_eMail){ + $query = << array('value'=>$name, 'data_type'=>PDO::PARAM_STR), + ':vorname' => array('value'=>$vorname, 'data_type'=>PDO::PARAM_STR), + ':plz' => array('value'=>$corona_PLZ, 'data_type'=>PDO::PARAM_STR), + ':telephon' => array('value'=>$corona_telephon, 'data_type'=>PDO::PARAM_STR), + ':email' => array('value'=>$corona_eMail, 'data_type'=>PDO::PARAM_STR), + ); + dbQuery($db, $query, $params); + + $newId = $db->lastInsertId(); + giveUserAnUserAttribute($db, $newId, "inTraining"); +return; +} +?> diff --git a/homepage/mams/local/.htaccess b/homepage/mams/local/.htaccess new file mode 100644 index 0000000..3a42882 --- /dev/null +++ b/homepage/mams/local/.htaccess @@ -0,0 +1 @@ +Deny from all diff --git a/homepage/mams/local/cwsvJudo.config.php b/homepage/mams/local/cwsvJudo.config.php new file mode 100644 index 0000000..3998c08 --- /dev/null +++ b/homepage/mams/local/cwsvJudo.config.php @@ -0,0 +1,6 @@ + diff --git a/homepage/redesign2018/markdownExperiment/src/galleryHelper/findFiles.py b/homepage/redesign2018/markdownExperiment/src/galleryHelper/findFiles.py new file mode 100755 index 0000000..bdddbc8 --- /dev/null +++ b/homepage/redesign2018/markdownExperiment/src/galleryHelper/findFiles.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python +# -*- coding: UTF-8 -*- + +import os +import argparse +import magic +import json + +argParser = argparse.ArgumentParser(description="Finds files recursively") +argParser.add_argument("--baseDirectory", default=os.getcwd()) + +argv = argParser.parse_args() + +argv.baseDirectory = os.path.expanduser(argv.baseDirectory) + +f = [] +for (dirpath, dirnames, filenames) in os.walk(argv.baseDirectory): + f.extend( + [ + { + "path": os.path.relpath(os.path.join(dirpath, filename), argv.baseDirectory), + "mimetype": magic.from_file( os.path.join(dirpath, filename), mime=True), + "filetype": magic.from_file( os.path.join(dirpath, filename) ) + } + for filename in filenames + ] + ) + +print( "Found: " + str(f) ) +print( "Found: \n" + json.dumps( f, sort_keys=True, indent=4, separators=(",",": ") ) ) + diff --git a/homepage/wkParticipo/abbildungen/060-066.DeAshiBarei.png b/homepage/wkParticipo/abbildungen/060-066.DeAshiBarei.png new file mode 100644 index 0000000..b59b654 Binary files /dev/null and b/homepage/wkParticipo/abbildungen/060-066.DeAshiBarei.png differ diff --git a/homepage/wkParticipo/abbildungen/067-072.HizaGuruma.png b/homepage/wkParticipo/abbildungen/067-072.HizaGuruma.png new file mode 100644 index 0000000..df6dc06 Binary files /dev/null and b/homepage/wkParticipo/abbildungen/067-072.HizaGuruma.png differ diff --git a/homepage/wkParticipo/abbildungen/073-078.png b/homepage/wkParticipo/abbildungen/073-078.png new file mode 100644 index 0000000..ff40ef9 Binary files /dev/null and b/homepage/wkParticipo/abbildungen/073-078.png differ diff --git a/homepage/wkParticipo/abbildungen/177-181.TaiOtoshi.png b/homepage/wkParticipo/abbildungen/177-181.TaiOtoshi.png new file mode 100644 index 0000000..66a2dcb Binary files /dev/null and b/homepage/wkParticipo/abbildungen/177-181.TaiOtoshi.png differ diff --git a/homepage/wkParticipo/abbildungen/182-184.TaiOtoshi.png b/homepage/wkParticipo/abbildungen/182-184.TaiOtoshi.png new file mode 100644 index 0000000..b46dee2 Binary files /dev/null and b/homepage/wkParticipo/abbildungen/182-184.TaiOtoshi.png differ diff --git a/homepage/wkParticipo/abbildungen/185-187.TaiOtoshi.png b/homepage/wkParticipo/abbildungen/185-187.TaiOtoshi.png new file mode 100644 index 0000000..f260f6d Binary files /dev/null and b/homepage/wkParticipo/abbildungen/185-187.TaiOtoshi.png differ diff --git a/homepage/wkParticipo/abbildungen/188-190.TaiOtoshi.png b/homepage/wkParticipo/abbildungen/188-190.TaiOtoshi.png new file mode 100644 index 0000000..6570e92 Binary files /dev/null and b/homepage/wkParticipo/abbildungen/188-190.TaiOtoshi.png differ diff --git a/homepage/wkParticipo/abbildungen/SeoiNage.125-128.png b/homepage/wkParticipo/abbildungen/SeoiNage.125-128.png new file mode 100644 index 0000000..fa7f2c0 Binary files /dev/null and b/homepage/wkParticipo/abbildungen/SeoiNage.125-128.png differ diff --git a/homepage/wkParticipo/abbildungen/SeoiNage.129-131.png b/homepage/wkParticipo/abbildungen/SeoiNage.129-131.png new file mode 100644 index 0000000..51b0d05 Binary files /dev/null and b/homepage/wkParticipo/abbildungen/SeoiNage.129-131.png differ diff --git a/homepage/wkParticipo/addEvent.php b/homepage/wkParticipo/addEvent.php index de4df97..9d05fed 100644 --- a/homepage/wkParticipo/addEvent.php +++ b/homepage/wkParticipo/addEvent.php @@ -12,12 +12,13 @@ $message['error'] = 'Datenbankverbindung fehlgeschlagen: ' . $mysqli->connect_error; } $query = sprintf( - "INSERT INTO wkParticipo_Events (wkId, meldefrist) - SELECT * FROM (SELECT '%s', '%s') as new_event + "INSERT INTO wkParticipo_Events (wkId, datum, meldefrist) + SELECT * FROM (SELECT '%s', '%s', '%s') as new_event WHERE NOT EXISTS ( SELECT wkId FROM wkParticipo_Events WHERE wkId = '%s' ) LIMIT 1;", $mysqli->real_escape_string($_POST['f']['wkId']), + $mysqli->real_escape_string($_POST['f']['datum']), $mysqli->real_escape_string($_POST['f']['meldefrist']), $mysqli->real_escape_string($_POST['f']['wkId']) ); @@ -54,8 +55,14 @@
    Benutzerdaten -
    />
    -
    />
    +
    + + /> +
    +
    + + /> +
    diff --git a/homepage/wkParticipo/addFahrt.php b/homepage/wkParticipo/addFahrt.php index 5e354b7..7888b56 100644 --- a/homepage/wkParticipo/addFahrt.php +++ b/homepage/wkParticipo/addFahrt.php @@ -66,7 +66,13 @@ Wettkampfplaner - Meldung - + Wettkampfplaner - Meldung - + diff --git a/homepage/wkParticipo/admin/index.php b/homepage/wkParticipo/admin/index.php index ad967ae..12a3ad8 100644 --- a/homepage/wkParticipo/admin/index.php +++ b/homepage/wkParticipo/admin/index.php @@ -15,10 +15,11 @@

    Inhalt

    -

    Neuen Benutzer anlegen.

    -

    Neuen Event anlegen.

    -

    User anzeigen.

    -

    Events anzeigen.

    +

    Neuen Benutzer anlegen

    +

    Neuen Event anlegen

    +

    User anzeigen

    +

    Events anzeigen

    +

    Newsletter manuel senden

    ">Attribute verteilen

    diff --git a/homepage/wkParticipo/admin/listEvents.php b/homepage/wkParticipo/admin/listEvents.php index 5c370a9..5a5f906 100644 --- a/homepage/wkParticipo/admin/listEvents.php +++ b/homepage/wkParticipo/admin/listEvents.php @@ -25,7 +25,8 @@ echo $message['error']; die(); } - $eventList = getAllEvents($mysqli); +// $eventList = getAllEvents($mysqli); + $eventList = getCommingWkEvents($mysqli); foreach($eventList as $event){ // $wkData = getWkData($mysqli, $event['wkId']); $wkData = getWkEventData($mysqli, $event['id']); @@ -49,12 +50,6 @@ } ?> - - - diff --git a/homepage/wkParticipo/admin/showUser.php b/homepage/wkParticipo/admin/showUser.php index 2f856ab..8bded86 100644 --- a/homepage/wkParticipo/admin/showUser.php +++ b/homepage/wkParticipo/admin/showUser.php @@ -3,9 +3,12 @@ require_once('../auth.php'); require_once('../local/db.php.inc'); require_once('../lib/wkParticipoLib.inc.php'); + require_once('../lib/wkParticipo-user.php'); $message = array(); $eventData = array(); + + $user = new participo\user(); if(empty($_POST)){ $message['error'] = "Fehler: leeres POST!"; @@ -16,6 +19,11 @@ } else{ if( (string)(int)$_POST['f']['userId'] == $_POST['f']['userId'] ){ + $user->loadFromDb(getCwsvJudoDbConn(), $_POST['f']['userId']); + var_dump($_POST); + var_dump($user); + var_dump($user->toAssoc()); + $mysqli = @new mysqli($db_server, $db_user, $db_password, $db_name); if ($mysqli->connect_error) { $message['error'] = 'Datenbankverbindung fehlgeschlagen: ' . $mysqli->connect_error; diff --git a/homepage/wkParticipo/api.php b/homepage/wkParticipo/api.php new file mode 100644 index 0000000..85ed495 --- /dev/null +++ b/homepage/wkParticipo/api.php @@ -0,0 +1,140 @@ +"#FFAE00", 'highlightColor'=>"#FF8100", 'buttonColor'=>"#291670"]){ +//$colorTypes = ["backgroundColor", "highlightColor", "buttonColor"]; +$defaultColors =[ // unterstützte Farben und ihre Standardbelegung + 'backgroundColor'=> "#FFAE00", // Hintergrundfarbe + 'highlightColor'=>"#FF8100", // Markierungen zum hervorheben + 'buttonColor'=>"#291670" // Interaktionsflächen +]; + + // Abfragen der gesamten Konfiguration des Users + $tmpBindArray = array( + ":userId"=>array('value'=>$userId, 'data_type'=>PDO::PARAM_INT) + ); +// echo("DBG: setColors-userId".strval($userId)); +// echo("DBG: setColors-BindArray");var_dump($tmpBindArray); + $usersConfig = dbQuery( + $dbConn, + "SELECT config FROM `wkParticipo_Users` WHERE id = :userId;", + //"SELECT * FROM `wkParticipo_Users` WHERE id = :userId;", + array( + ":userId"=>array('value'=>(int)$userId, 'data_type'=>PDO::PARAM_INT) + ) + ); +// echo("DBG: setUserColors-usersConfig"); var_dump($usersConfig); +// - json-formatierten Konfigurationsstring in ein Assoziatives Array +// laden +// - Im Fehlerfalle ein leeres Array weitergeben + try{ + $usersConfig = json_decode($usersConfig[0]['config'], true); + if( empty($usersConfig) ) + throw new Exception("No usersConfig available!"); + } + catch(Exception $e) { + echo("Message: " .$e->getMessage()); + $usersConfig = array(); + } + + // Nicht mehr unterstützte Farben entfernen + foreach($usersConfig['colors'] as $colorType=>$colorValue){ +// echo("DBG: setUserColors-colorType: ".$colorType); +// echo("DBG: setUserColors-defaultColors:"); var_dump($defaultColors); + if( !array_key_exists($colorType, $defaultColors) ){ + //echo("DBG: ".$colorType." is no defaultColor! DefaultColors are\n");var_dump($defaultColors); + unset($usersConfig['colors'][$colorType]); + } + } + +// - Neue Farben setzen, sofern sie validiert werden können +// - Es werden nur Farben übernommen, die auch unterstützt werden + foreach($defaultColors as $key=>$value){ // Alle unterstützten Farben testen + if( !preg_match("/^#(?:[0-9a-fA-F]{3}){1,2}$/", $wantedColors[$key]) ){ + //echo("DBG: ".$wantedColors[$key]." doesn't regmatches to a color!"); + $usersConfig['colors'][$key] = $value; + } + else{ + $usersConfig['colors'][$key] = $wantedColors[$key]; + } + } + +// Die aktualiserte Fassung der Konfiguration abspeicher + +//echo("DBG: update\n"); var_dump($usersConfig); + dbQuery( + $dbConn, + "UPDATE `wkParticipo_Users` SET config = :jsonConfig WHERE id = :userId;", + array( + ":jsonConfig"=>array('value'=>json_encode($usersConfig), 'data_type'=>PDO::PARAM_STR), + ":userId"=>array('value'=>$userId, 'data_type'=>PDO::PARAM_INT) + ) + ); + +// Auch die aktuellen sessionDaten noch anpassen + $_SESSION['user']['userConfig']['colors'] = $usersConfig['colors']; +} + +function apiActionSetUserColors($parameter){ +//echo("DBG: apiActionSetColors-parameter:");var_dump($parameter); +// Inputvalidierung +try{ + if( !is_positive_integer($parameter['userId']) ) + throw new Exception("EXP: userId has to be a positive integer, but is !"); + if( !is_array($parameter['colors']) ) + throw new Exception("EXP: colors not given in an array!"); + + setUserColors(getCwsvJudoDbConn(), $parameter['userId'], $parameter['colors']); +} +catch(Exception $e){ + echo("apiActionSetUserColors - ".$e->getMessage()."\n"); + echo("parameter:"); var_dump($parameter); +} +return; +} + +// Als allererstes den Header setzen, damit wir auch Fehlermeldungen +// ausgeben können +if(isset($_POST['backtoUrl'])){ + if (filter_var($_POST['backtoUrl'], FILTER_VALIDATE_URL)) { + header("Location: ".$_POST['backtoUrl']); + } else { + header("Location: ".$defaultValues['backtoUrl']); + } +} + +//echo("DBG: api-POST"); var_dump($_POST); +/// @todo übersichtlichere Variante gewüscht +if($_POST['action'] == "setUserColors"){ + apiActionSetUserColors(array('userId'=>$_POST['parameter']['userId'], 'colors'=>$_POST['parameter']['colors'])); +} + +?> diff --git a/homepage/wkParticipo/graphiken/HaltestelleAmSuedring.png b/homepage/wkParticipo/graphiken/HaltestelleAmSuedring.png new file mode 100644 index 0000000..6bdc781 Binary files /dev/null and b/homepage/wkParticipo/graphiken/HaltestelleAmSuedring.png differ diff --git a/homepage/wkParticipo/index.php b/homepage/wkParticipo/index.php index 956f689..7a6000e 100644 --- a/homepage/wkParticipo/index.php +++ b/homepage/wkParticipo/index.php @@ -18,26 +18,6 @@ setlocale (LC_ALL, 'de_DE@euro', 'de_DE', 'de', 'ge'); if ($mysqlConn->connect_error) { $sqlMessage['error'] .= 'Datenbankverbindung fehlgeschlagen: ' . $mysqlConn->connect_error; } -// var_dump($_SESSION); - -/// Stellt den cssCode mit den Variablendefinitionen bereit -function colorThemeCss($colorArray = ['backgroundColor'=>"#FFAE00", 'highlightColor'=>"#FF8100", 'buttonColor'=>"#291670"]){ -$colorTypes = ["backgroundColor", "highlightColor", "buttonColor"]; -$defaultColors =['backgroundColor'=> "#FFAE00", 'highlightColor'=>"#FF8100", 'buttonColor'=>"#291670"]; - - foreach($colorTypes as $key){ - if( !preg_match("/^#(?:[0-9a-fA-F]{3}){1,2}$/", $key) ){ - $colorThemeCss[$key] = $defaultColors[$key]; - } - } - $ret = ":root{"; - - foreach($colorArray as $key=>$value){ - $ret .= "--".$key.": ".$value."; "; - } - $ret .= "}"; -return $ret; -} ?> @@ -54,23 +34,8 @@ return $ret; @@ -80,9 +45,9 @@ return $ret;

    Wettkampf­planung - Übersicht

    - - +
    + +
    + Farben + + + + + + +
    + + + + +
    diff --git a/infoZettelOrg/2019-12-16-Weihnachtsfeier+Dojouebernachtung.md b/infoZettelOrg/2019-12-16-Weihnachtsfeier+Dojouebernachtung.md new file mode 100644 index 0000000..13fce59 --- /dev/null +++ b/infoZettelOrg/2019-12-16-Weihnachtsfeier+Dojouebernachtung.md @@ -0,0 +1,45 @@ +# Jahrendezettel + +## Weihnachtsfeier + +- Donnerstag, 19.12.2019 +- 17.00-20.00 Uhr +- Flachbau auf Sportplatz Str. Usti nad Labem 42 + +## Dojoübernachtung + +- Freitag, 27.12.2019 + - 16:00-19:00 Uhr Training + - danach Abendbrot (tiefer Teller und Löffel benötigt!) + - ca. 20:00 Uhr Videoanalyse der Wettkämpfe 2019 + Zeiplan und Programm ist noch offen für Änderungen + Da dies eine Übernachtung wird, wird die entsprechende + Ausrüstung benötigt (Schlafsack, Schlafsachen, Kuscheltier, + Duschzeug, ...) +- Samstag, 28.12.2019 + - 8:30 Uhr Frühstück + - danach Zusammenpacken und Wegräumen der Matten (helfende Hände + erwünscht) + - 10:00 Uhr Abholung + +## Letzter und erster Trainingstag + +- Letzter Trainingstag 2019: + - Freitag, 20.12.2019 +- Erster Trainingstag 2020: + - ~~Freitag, 03.01.2020~~ Mittwoch, 08.01.2020 + +## Passbestellung + +Für das kommende Jahr sind auch wieder die neuen Jahresmarken fällig, +also bis spätestens zur Weihnachtsfeier mitbringen: + +- Pass: 9,00 € (nur wer noch gar keinen hat; zusätzlich ein Passbild +(digital per Email) zusammen mit den nötigen Daten: Name, Geburtsdatum, +Geburtsort und Nationalität) +- Kyumarke: 12,00 € (wer von letztem Jahr keine mehr übrig hat) +- Jahresmarke: 18,00 € + + + +MsG marko diff --git a/infoZettelOrg/2020-01-12-Elternabend2020-1.md b/infoZettelOrg/2020-01-12-Elternabend2020-1.md new file mode 100644 index 0000000..0efa244 --- /dev/null +++ b/infoZettelOrg/2020-01-12-Elternabend2020-1.md @@ -0,0 +1,41 @@ +# Infozettel + +## Einladung zum Elternabend am Mo., 27.01.2020 + +Am 27.01.20 (Mo.) möchte ich recht herzlich zum ersten Elternabend 2020 +laden um eventuelle Fragen zu klären und ganz allgemein Feedback +auszutauschen. + +Es wäre schön, wenn ich Rückmeldungen bekomme, wer anwesend sein kann +oder nicht. + +- Datum: 27.01.2020 (Montag) +- Ort: Beratungsraum im Flachbau Str. Usti nad Labem 42 +- Zeit: 18:00 Uhr + +## Baumaßnahmen + +In den nächsten Wochen werden im Sportplatzgebäude mehrere +Umbaumaßnahmen durchgeführt. Im Zuge dessen kann es im Gang und in den +Umkleiden zu Verunreinigungen kommen. Desshalb möchte ich nocheinmal +darauf hinweisen, dass für den Gang zum Dojo unbedingt Schuhe zu tragen +sind. + +## Pässe und Marken 2020 + +Für die Teilnahme an (den meisten) Wettkämpfen und für die offizielle +Anerkennung der gemachten Gürtelprüfungen gibt es vom Verband einen +sogenannten Judopass. In ihm werden die bestandenen Kuyprüfungen und +die jährliche Mitgliedschaft im Verband mit Marken dokumentiert. + +Wer noch keinen hat, bitte dafür mitbringen: + +- 18,00 € Jahresmarke +- 12,00 € Kyumarke +- 9,00 € für den Pass, zusätzlich: + - per Email (an \href{mailto:cwsvjudo@arcor.de}{cwsvjudo@arcor.de}) + - ein Passbild (digital, kann man auch selber machen) + - Passdaten: Name, Geburtsdatum, Geburtsort und Nationalität + + +MsG marko diff --git a/infoZettelOrg/2020-01-27-Elternabend.md b/infoZettelOrg/2020-01-27-Elternabend.md new file mode 100644 index 0000000..dbd3b21 --- /dev/null +++ b/infoZettelOrg/2020-01-27-Elternabend.md @@ -0,0 +1,93 @@ +--- +documentclass: scrartcl +... + +# 2020-01-27 Elternabend 2020-1 + +## Einleitung + +- Begrüßung +- Elternabend: + - geplant immer 2-mal im Jahr, letztes Jahr z.B. nur einmal + - Vergebung: ursprünglich war 17:00 Uhr propagiert (aber ich + persönlich brauchte auch mehr Zeit zw. Arbeit und Elternabend) + - was wäre denn eine Wunschzeit? + + +## Trainingsumstrukturierung + +- Mittwochtraining bleibt wie gehabt (16:00-17:45) +- Freitag soll es drei Übungseinheiten geben: + - 16:00-17:15 Anfänger/"kleine" Kinder + - Colin, Dominic, Emily, MiaSophie, NicoR, Paul, Tobias + - 17:00-18:30 fortgeschrittene/disziplinierte/große Kinder + - Lea, MiaSky, Mihail, Nico, Romy + - 18:15-19:45 Jugend+Erwachsene + - Arthur, Rio, Lucas, Natalia, Nick, Rio, Rolf, Sebastian, + Thomas + - Überlappungen gewollt (gemeinsames Spiel) +- Um das sacken zu lassen, wäre mein Vorschlag: ab April + +## Publikumswünsche + +- Zeit geben für was auf dem Herzen brennt + +## Vereinsinternes + +- T-Shirts: Unterstützungsanfrage (Sponsor, Durchführung ...) +- Spenden: Bitte direkt an den Verein, wir kriegen das wieder heraus +- Wegfall Weihnachtsfeier + -als Ersatz: Neujahrsfeier? + +### Training + +- es ist Training + - heißt, ich werde immer auf der Suche nach Vertretung sein, und + dabei auch kreativ sein +- Kraftkreis jeden ersten Freitag im Monat + - offen für alle + - offen für Vorschläge +- Sommerferien draußen, Treppenlauf +- Ferien: + - mich an Ferien erinnern + - Freitag Kinder gemeinsam + +## Wissen + +### Judopass + +- Passbild, Jahresmarke, Kyumarke +- Wettkampferfolge + +### Wettkämpfe + +- Mitarbeit und warum ich da so hinterher bin + - mag es nicht etwas nicht zu wissen + - will keine Chance liegen lassen +- der Wettkapfplaner + - wieder: Mitarbeit! Es ist extra im Wettkampfplaner die + Möglichkeit gegeben, auch abzusagen. +- Fahrangebote +- Startgeld + - als Sponsoring gerne willkommen + +### Altersklassen + +- Was heisst Uxx? +- Unterschied DJB und JVS +- Kyubeschränkung + +### Wunschtermine + +- eigentlich ja zu allen mit soviel wie möglich + - 10 Turniere für jedes Kind +- Generationenturnier, weil für alle +- Krümelrandoris, weil für Anfänger +- RKP +- OttoGoshiLiga (alle Termine) +- Judosafari + + +## Diskussion + +- Kritik, Fragen, Wünsche diff --git a/infoZettelOrg/2020-02-29-KyuSonderTraining.md b/infoZettelOrg/2020-02-29-KyuSonderTraining.md new file mode 100644 index 0000000..ebe8563 --- /dev/null +++ b/infoZettelOrg/2020-02-29-KyuSonderTraining.md @@ -0,0 +1,25 @@ +# Infozettel + +## Kyuprüfung am 06.03.2020 + +Da es einige in unserer Gruppe gibt, die für ihre Wettkampfeinsätze den +gelben Gürtel benötigen, findet unsere nächste Kyuprüfung bereits am +06.03.2020 statt. Um den Prüfer nicht nur wegen zwei Prüflingen kommen +zu lassen, wäre es gut, wenn noch ein paar mehr das Programm für ihre +nächste Prüfung beherrschen. Der Zeitplan dafür ist allerdings +einigermaßen knapp. Deshalb wird es ein extra Kyutraining geben. + +## Extra Kyutraining + +- 29.02.2020 + 01.03.2020 +- 14:00 -- 18:00 Uhr +- in unserem Dojo + +Ich möchte allerdings nochmals darauf hinweisen, dass der Zeitplan sehr +ambitioniert ist. Eine Garantie - auch mit den zusätzlichen Einheiten - +das Programm des Kyus rechtzeitig zu beherrschen, gibt es nicht. + +Es wird aber noch vor den Sommerferien noch eine Kyuprüfung geben. + + +MsG marko diff --git a/infoZettelOrg/2020-03-06-Fruehjahrskruemelrandori.md b/infoZettelOrg/2020-03-06-Fruehjahrskruemelrandori.md new file mode 100644 index 0000000..8e53710 --- /dev/null +++ b/infoZettelOrg/2020-03-06-Fruehjahrskruemelrandori.md @@ -0,0 +1,32 @@ +# 24. Frühjahrskrümeltrandori des Judoclubs Antonsthal-Schwarzenberg + +## Wettkampfdaten + +- Altersklassen: Jg.2010-2014 +- Datum: 06.03.2020 +- Ort: Dreifelder-TH der Goethe-Oberschule Breitenbrunn, Dorfberg 10 +- Wiegen: 9:15--9:45 Uhr +- Wettkampfbeginn: ca. 10:15 Uhr + + +## Treffpunkt + +- Ort: P+R Parkplatz Südring/Stollberger Straße +- Abfahrt: 8:00 Uhr +- Kindersitz nicht vergessen! + + +## Nicht vergessen + +- Judopass +- Judogi (d. h. Jacke, Hose und Gürtel) +- *Hallenschuhe* (Auch die Fans!) +- Essen/Trinken +- Warme Socken und Pullover + +Das Betreten der Sportstätten in Straßenschuhen ist (auch den Fans) +nicht gestattet. Bitte Ersatzschuhe (Badelatschen/Hallenschuhe) +mitbringen. Sonst muss in Socken gegangen werden! + + +MsG marko diff --git a/infoZettelOrg/2020-03-15-MaedchenPokalWerdau.md b/infoZettelOrg/2020-03-15-MaedchenPokalWerdau.md new file mode 100644 index 0000000..0ac6bf0 --- /dev/null +++ b/infoZettelOrg/2020-03-15-MaedchenPokalWerdau.md @@ -0,0 +1,33 @@ +# 16. Werdauer Mädchenpokal + +## Wettkampfdaten + +- Altersklassen: U11w U13w U15w U18w Frauen +- Datum: 15.03.2020 +- Ort: Mehrzweckhalle Langenhessen, Seelingstädter Str. 7, 08412 Werdau +OT Langenhessen +- Wiegen: 8:30--9:30 Uhr +- Wettkampfbeginn: ca. 10:00 Uhr + + +## Treffpunkt + +- Ort: P+R Parkplatz Südring/Stollberger Straße +- Abfahrt: 7:30 Uhr +- Kindersitz nicht vergessen! + + +## Nicht vergessen + +- Judopass +- Judogi (d. h. Jacke, Hose und Gürtel) +- *Hallenschuhe* +- Essen/Trinken +- Warme Socken und Pullover + +Das Betreten der Sportstätten in Straßenschuhen ist (auch den Fans) +nicht gestattet. Bitte Ersatzschuhe (Badelatschen/Hallenschuhe) +mitbringen. Sonst muss in Socken gegangen werden! + + +MsG marko diff --git a/infoZettelOrg/2020-09-19--20-LemU13U15.md b/infoZettelOrg/2020-09-19--20-LemU13U15.md new file mode 100644 index 0000000..6864271 --- /dev/null +++ b/infoZettelOrg/2020-09-19--20-LemU13U15.md @@ -0,0 +1,43 @@ +# Offene Landeseinzelmeisterschaften U13/U15 2020 + +## Wichtig: + +- Spätestens am Wettkampftag benötige ich die ausgefüllten und +unterschriebenen Gesundheitsbestätigungen! +- Bei Betreten der Halle muss ich Kontaktdaten für eine etwaige +Rückverfolgung abgeben. Ich gehe davon aus, dass ich die Erlaubnis habe +diese Daten weiterzugeben. + +## Wettkampfdaten + +- Altersklassen: U13, U15 +- Datum: + - U13: 19.09.2020 + - U15: 20.09.2020 +- Ort: Göltzschtalhalle Rodewisch, Hüllebrandweg 1 (ehemals +Schillerstr. 4), 08228 Rodewisch +- Erwärmung möglich ab: 9:30 Uhr +- Wettkampferöffnung: ca. 9:30 Uhr + + +## Treffpunkt + +- Ort: P+R Parkplatz Südring/Stollberger Straße +- Abfahrt: Nach Vereinbarung! + - Um ein gestaffeltes Eintreffen zu ermöglichen, wird am 14.09.2020 + ein Zeitplan für die verschiedenen Gewichtsklassen veröffentlicht. +- Kindersitz (falls nötig) nicht vergessen! + +## Nicht vergessen + +- Judopass +- Judogi (d. h. Jacke, Hose und Gürtel) +- *Hallenschuhe* (Auch die Fans!) +- Essen/Trinken +- Warme Socken und Pullover + +Das Betreten der Sportstätten in Straßenschuhen ist (auch den Fans) +nicht gestattet. Bitte Ersatzschuhe (Badelatschen/Hallenschuhe) +mitbringen. Sonst muss in Socken gegangen werden! + +MsG marko diff --git a/infoZettelOrg/2020-10-27-keinElternabend.md b/infoZettelOrg/2020-10-27-keinElternabend.md new file mode 100644 index 0000000..c505942 --- /dev/null +++ b/infoZettelOrg/2020-10-27-keinElternabend.md @@ -0,0 +1,85 @@ +# Absage Elternabend + +Zur Kontaktverminderung wird der für den 03.11.2020 geplante +Elternabend nicht als Präsenzveranstaltung stattfinden. Statdessen gibt +es die nötigen Informationen von mir hier in aller Kürze. Falls es von +Seiten der Eltern Fragen gibt, können diese ruhig an mich gestellt +werden. Ich würde diese dann mal gesammelt beantworten und an alle +weiterleiten. + +Nach der [Allgemeinverfügung vom 23.10.2020][1] ist: + +- bis zur Sportfläche eine Mund-Nasen-Bedeckung zu tragen +- zum Zwecke der Kontaktverfolgung jedem Trainierenden die PLZ, +die Telefonnummer und die Emailadresse zu erfassen und bei Bedarf +auch an die Ämter weiterzuleiten. Ich bitte darum, mir diese Daten +zeitnah zukommen zu lassen: + - Name (d. Teilnehmenden): + - PLZ: + - Telefonnummer(n): + - eMail-Adresse(n): +- auf Zuschauer/Besucher während der Trainingseinheit zu verzichten + - das umfasst leider auch Eltern + + +[1]: https://chemnitz.de/chemnitz/de/unsere-stadt/ordnung-und-sicherheit/allgemeinverfuegungen/20201023_allgemeinverfuegung_infektionsschutzgesetz.html + +## Neue Trainingseinteilung ab 09.11.2020 + +Um die Menge der gleichzeitig Trainierenden im Dojo möglichst klein zu +halten, sollen die Judoka gleichmäßiger über alle Trainingseinheiten +verteilt werden. Dazu wird freitags eine neue Trainingseinheit +eingeführt. Das Freitagtraining wird ab dem 09.11.2020 wie folgt +ablaufen: + +- 16:00-17:00 Uhr bis 7 Jahre +- 16:45-18:15 Uhr bis 11 Jahre +- 18:00-19:30 Uhr ab 12 Jahre + +Das Mittwochtraining soll nach Möglichkeit mit den Judoka ab der AK U11 +besetzt werden. Ich bitte hier um Rücksprache, wer gerne am +Mittwochtraining teilnehmen möchte. Sollte es notwendig werden, muss +die Teilnehmerzahl mittwochs begrenzt werden. Um Überschüsse +abzufangen, wird eine zusätzliche Trainingseinheit am Sonntag +eingeführt. Auch hier bitte ich um Rücksprache. Zum einen für eine +zeitliche Planung, zum anderen, bei wem überhaupt die Möglichkeit +besteht, Sonntags zu trainieren. + +## Zur Erinnerung + +Dieser (und vorrige) Infozettel sind auch in unserem Wettkampfplaner +verfügbar. Auch wenn es derzeit nicht viele Wettkämpfe zu planen gibt, +plane ich, ihn für Informationen und Terminplanung, wie das +Sonntagstraining einzusetzen. Wer also (noch) keinen Zugang hat, kann +sich mit mir mal kurzschließen, um ihn zu erhalten. + +MsG marko + +\pagebreak + + +## Informationen für den Übungsleiter + +Name (d. Trainierenden): +\newline +\newline + +### Corona (notwendig für Trainingsteilnahme!) + +PLZ:\ +\ + +Telefon:\ +\ + +eMail:\ +\ + +### Interesse an folgenden Trainingseinheiten + +- Mittwoch: +- Freitag: +- Sonntag: + +Vorschlag/Vorstellung für den zeitlichen Rahmen des Sonntagstrainings: + diff --git a/infoZettelOrg/Makefile b/infoZettelOrg/Makefile index 0b5eb04..be7b182 100644 --- a/infoZettelOrg/Makefile +++ b/infoZettelOrg/Makefile @@ -1,4 +1,6 @@ infoZettel=$(patsubst %.md,%.pdf,$(wildcard *.md)) +infoZettel-2x2=$(patsubst %.md,%-2x2.pdf,$(wildcard *.md)) +kyuZettel=$(patsubst %.md,%.pdf,$(wildcard kyuZettel/*.md)) aushaenge=$(patsubst %.md,%.pdf,$(wildcard aushang/*.md)) infoZettelUploads=$(addprefix uploadTouch/, $(wildcard *.md)) $(addprefix uploadTouch/, $(wildcard *.pdf)) @@ -6,11 +8,15 @@ infoZettelUploads=$(addprefix uploadTouch/, $(wildcard *.md)) $(addprefix upload #all: infoZettel infoZettelUpload aushaenge all: infoZettelUpload aushaenge - - .PHONY: infoZettel infoZettel: $(infoZettel) +.PHONY: infoZettel-2x2 +infoZettel-2x2: infoZettel $(infoZettel-2x2) + +.PHONY: kyuZettel +kyuZettel: $(kyuZettel) + .PHONY: aushaenge aushaenge: $(aushaenge) @@ -22,7 +28,7 @@ aushaenge: $(aushaenge) --variable classoption="DIV=28" \ --variable classoption="BCOR=0mm" \ --variable classoption="paper=A6" \ - --variable classoption="fontsize=12pt" \ + --variable classoption="fontsize=10pt" \ --variable classoption="parskip=never" \ --variable classoption="headsepline=true" \ --variable classoption="headheight=1cm" \ @@ -31,6 +37,9 @@ aushaenge: $(aushaenge) --output=$@ \ $^ +%-2x2.pdf: %.pdf + pdfnup --no-landscape --nup 2x2 --suffix '2x2' $^ '1,1,1,1,2,2,2,2' --outfile $@ + aushang/%.pdf: aushang/%.md pandoc \ --template=pandocTemplate-cwsvJudoAushang.latex \ diff --git a/infoZettelOrg/2019-01-22-Elternabend2019-1.md b/infoZettelOrg/archiv/archiv.2019/2019-01-22-Elternabend2019-1.md similarity index 100% rename from infoZettelOrg/2019-01-22-Elternabend2019-1.md rename to infoZettelOrg/archiv/archiv.2019/2019-01-22-Elternabend2019-1.md diff --git a/infoZettelOrg/2019-01-29-Elternabend-2019-1.md b/infoZettelOrg/archiv/archiv.2019/2019-01-29-Elternabend-2019-1.md similarity index 100% rename from infoZettelOrg/2019-01-29-Elternabend-2019-1.md rename to infoZettelOrg/archiv/archiv.2019/2019-01-29-Elternabend-2019-1.md diff --git a/infoZettelOrg/2019-02-28-Kyupruefung2019.md b/infoZettelOrg/archiv/archiv.2019/2019-02-28-Kyupruefung2019.md similarity index 100% rename from infoZettelOrg/2019-02-28-Kyupruefung2019.md rename to infoZettelOrg/archiv/archiv.2019/2019-02-28-Kyupruefung2019.md diff --git a/infoZettelOrg/2019-03-09-Fruehjahrskruemelrandori.md b/infoZettelOrg/archiv/archiv.2019/2019-03-09-Fruehjahrskruemelrandori.md similarity index 100% rename from infoZettelOrg/2019-03-09-Fruehjahrskruemelrandori.md rename to infoZettelOrg/archiv/archiv.2019/2019-03-09-Fruehjahrskruemelrandori.md diff --git a/infoZettelOrg/2019-03-21-Trainingsortverlegung.md b/infoZettelOrg/archiv/archiv.2019/2019-03-21-Trainingsortverlegung.md similarity index 100% rename from infoZettelOrg/2019-03-21-Trainingsortverlegung.md rename to infoZettelOrg/archiv/archiv.2019/2019-03-21-Trainingsortverlegung.md diff --git a/infoZettelOrg/2019-03-29_Trainingsverlegung-Aushang.md b/infoZettelOrg/archiv/archiv.2019/2019-03-29_Trainingsverlegung-Aushang.md similarity index 100% rename from infoZettelOrg/2019-03-29_Trainingsverlegung-Aushang.md rename to infoZettelOrg/archiv/archiv.2019/2019-03-29_Trainingsverlegung-Aushang.md diff --git a/infoZettelOrg/2019-04-03-OGL+GT.md b/infoZettelOrg/archiv/archiv.2019/2019-04-03-OGL+GT.md similarity index 100% rename from infoZettelOrg/2019-04-03-OGL+GT.md rename to infoZettelOrg/archiv/archiv.2019/2019-04-03-OGL+GT.md diff --git a/infoZettelOrg/2019-04-06-Vogtlandpokal.md b/infoZettelOrg/archiv/archiv.2019/2019-04-06-Vogtlandpokal.md similarity index 100% rename from infoZettelOrg/2019-04-06-Vogtlandpokal.md rename to infoZettelOrg/archiv/archiv.2019/2019-04-06-Vogtlandpokal.md diff --git a/infoZettelOrg/2019-04-13-LemU13.md b/infoZettelOrg/archiv/archiv.2019/2019-04-13-LemU13.md similarity index 100% rename from infoZettelOrg/2019-04-13-LemU13.md rename to infoZettelOrg/archiv/archiv.2019/2019-04-13-LemU13.md diff --git a/infoZettelOrg/2019-04-13-Werdaupokal.md b/infoZettelOrg/archiv/archiv.2019/2019-04-13-Werdaupokal.md similarity index 100% rename from infoZettelOrg/2019-04-13-Werdaupokal.md rename to infoZettelOrg/archiv/archiv.2019/2019-04-13-Werdaupokal.md diff --git a/infoZettelOrg/2019-05-04_OGL-2019-1.md b/infoZettelOrg/archiv/archiv.2019/2019-05-04_OGL-2019-1.md similarity index 100% rename from infoZettelOrg/2019-05-04_OGL-2019-1.md rename to infoZettelOrg/archiv/archiv.2019/2019-05-04_OGL-2019-1.md diff --git a/infoZettelOrg/2019-05-18_GenerationenturnierXII.md b/infoZettelOrg/archiv/archiv.2019/2019-05-18_GenerationenturnierXII.md similarity index 100% rename from infoZettelOrg/2019-05-18_GenerationenturnierXII.md rename to infoZettelOrg/archiv/archiv.2019/2019-05-18_GenerationenturnierXII.md diff --git a/infoZettelOrg/2019-06-29--30-LJS2019.md b/infoZettelOrg/archiv/archiv.2019/2019-06-29--30-LJS2019.md similarity index 100% rename from infoZettelOrg/2019-06-29--30-LJS2019.md rename to infoZettelOrg/archiv/archiv.2019/2019-06-29--30-LJS2019.md diff --git a/infoZettelOrg/2019-07-04_Sommerabschluss.md b/infoZettelOrg/archiv/archiv.2019/2019-07-04_Sommerabschluss.md similarity index 100% rename from infoZettelOrg/2019-07-04_Sommerabschluss.md rename to infoZettelOrg/archiv/archiv.2019/2019-07-04_Sommerabschluss.md diff --git a/infoZettelOrg/2019-09-07--08-BambiniJugendturnier.md b/infoZettelOrg/archiv/archiv.2019/2019-09-07--08-BambiniJugendturnier.md similarity index 100% rename from infoZettelOrg/2019-09-07--08-BambiniJugendturnier.md rename to infoZettelOrg/archiv/archiv.2019/2019-09-07--08-BambiniJugendturnier.md diff --git a/infoZettelOrg/2019-09-12-LokpokalSparkassencup.md b/infoZettelOrg/archiv/archiv.2019/2019-09-12-LokpokalSparkassencup.md similarity index 100% rename from infoZettelOrg/2019-09-12-LokpokalSparkassencup.md rename to infoZettelOrg/archiv/archiv.2019/2019-09-12-LokpokalSparkassencup.md diff --git a/infoZettelOrg/2019-09-27_OGL-2019-4.md b/infoZettelOrg/archiv/archiv.2019/2019-09-27_OGL-2019-4.md similarity index 100% rename from infoZettelOrg/2019-09-27_OGL-2019-4.md rename to infoZettelOrg/archiv/archiv.2019/2019-09-27_OGL-2019-4.md diff --git a/infoZettelOrg/2019-10-05-HKR.md b/infoZettelOrg/archiv/archiv.2019/2019-10-05-HKR.md similarity index 100% rename from infoZettelOrg/2019-10-05-HKR.md rename to infoZettelOrg/archiv/archiv.2019/2019-10-05-HKR.md diff --git a/infoZettelOrg/2019-10-26-RudiSchulz.md b/infoZettelOrg/archiv/archiv.2019/2019-10-26-RudiSchulz.md similarity index 100% rename from infoZettelOrg/2019-10-26-RudiSchulz.md rename to infoZettelOrg/archiv/archiv.2019/2019-10-26-RudiSchulz.md diff --git a/infoZettelOrg/2019-11-23-Rkp.md b/infoZettelOrg/archiv/archiv.2019/2019-11-23-Rkp.md similarity index 100% rename from infoZettelOrg/2019-11-23-Rkp.md rename to infoZettelOrg/archiv/archiv.2019/2019-11-23-Rkp.md diff --git a/infoZettelOrg/2019-12-07-NikolausturnierWerdau.md b/infoZettelOrg/archiv/archiv.2019/2019-12-07-NikolausturnierWerdau.md similarity index 100% rename from infoZettelOrg/2019-12-07-NikolausturnierWerdau.md rename to infoZettelOrg/archiv/archiv.2019/2019-12-07-NikolausturnierWerdau.md diff --git a/infoZettelOrg/archiv/archiv.2019/2019-12-27-Treppenlauf.md b/infoZettelOrg/archiv/archiv.2019/2019-12-27-Treppenlauf.md new file mode 100644 index 0000000..c1de9d9 --- /dev/null +++ b/infoZettelOrg/archiv/archiv.2019/2019-12-27-Treppenlauf.md @@ -0,0 +1,18 @@ +# Neujahrtreppenlauf + +Da die Pause bis zum ersten Training einigen etwas zu lang war, habe +ich mich breitschlagen lassen, noch zwei Trainingseinheiten Trepenlauf +anzubieten: + +- 3. Januar 2020 +- 5. Januar 2020 +- beide Male 10:00 Uhr bis ca. 11:00 Uhr +- an "unserer Treppe" + - wer nicht weiß, wo die ist: 9:50 Uhr am Tor Sportplatz + +Achtung: + +- Wettergerechte Kleidung anziehen, wir sind draußen! +- Laufschuhe mitbringen! +- In Laufkleidung kommen, wir werden keine Umkleiden zur Verfügung +haben! diff --git a/infoZettelOrg/qrcode.sty b/infoZettelOrg/qrcode.sty new file mode 100644 index 0000000..6330464 --- /dev/null +++ b/infoZettelOrg/qrcode.sty @@ -0,0 +1,3051 @@ +%% +%% This is file `qrcode.sty', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% qrcode.dtx (with options: `package') +%% +%% This is a generated file. +%% +%% Copyright (C) 2015 by Anders Hendrickson +%% +%% This work may be distributed and/or modified under the +%% conditions of the LaTeX Project Public License, either version 1.3 +%% of this license or (at your option) any later version. +%% The latest version of this license is in +%% http://www.latex-project.org/lppl.txt +%% and version 1.3 or later is part of all distributions of LaTeX +%% version 2005/12/01 or later. +%% +\NeedsTeXFormat{LaTeX2e}[1999/12/01] +\ProvidesPackage{qrcode} + [2015/01/08 v1.51 QR code generation] +%%PACKAGE LOADING +\RequirePackage{xcolor}% +\RequirePackage{xkeyval}% + +%%INITIAL CODE +\newif\ifqr@draft@mode +\newif\ifqr@forget@mode + +%%DECLARATION OF OPTIONS +\define@boolkey{qr}[qr@]{draft}[true]{\ifqr@draft\qr@draft@modetrue\else\qr@draft@modefalse\fi}% +\define@boolkey{qr}[qr@]{final}[true]{\ifqr@final\qr@draft@modefalse\else\qr@draft@modetrue\fi}% +\define@boolkey{qr}[qr@]{forget}[true]{\ifqr@forget\qr@forget@modetrue\else\qr@forget@modefalse\fi}% +\define@boolkey{qr}[qr@]{hyperlink}[true]{}% %This creates \ifqr@hyperlink. +\define@boolkey{qr}[qr@]{hyperlinks}[true]{\ifqr@hyperlinks\qr@hyperlinktrue\else\qr@hyperlinkfalse\fi}% +\define@boolkey{qr}[qr@]{link}[true]{\ifqr@link\qr@hyperlinktrue\else\qr@hyperlinkfalse\fi}% +\define@boolkey{qr}[qr@]{nolink}[true]{\ifqr@nolink\qr@hyperlinkfalse\else\qr@hyperlinktrue\fi}% %Make nolink an antonym. +\define@boolkey{qr}[qr@]{links}[true]{\ifqr@links\qr@hyperlinktrue\else\qr@hyperlinkfalse\fi}% +\define@boolkey{qr}[qr@]{nolinks}[true]{\ifqr@nolinks\qr@hyperlinkfalse\else\qr@hyperlinktrue\fi}% %Make nolinks an antonym. + +%%EXECUTION OF OPTIONS +\qr@draft@modefalse +\qr@forget@modefalse +\qr@hyperlinktrue + +\ProcessOptionsX + +\newcounter{qr@i}% +\newcounter{qr@j}% +\newcount\qr@a +\newcount\qr@b +\newcount\qr@c + +\let\xa=\expandafter + +\newlinechar=`\^^J + +\def\qr@relax{\relax}% + +\def\qr@preface@macro#1#2{% + % #1 = macro name + % #2 = text to add to front of macro + \def\qr@tempb{#2}% + \xa\xa\xa\def\xa\xa\xa#1\xa\xa\xa{\xa\qr@tempb #1}% +}% + +\def\qr@g@preface@macro#1#2{% + % #1 = macro to be appended to + % #2 = code to add + \edef\qr@tempb{#2}% + \xa\xa\xa\gdef\xa\xa\xa#1\xa\xa\xa{\xa\qr@tempb#1}% +} + +\def\qr@getstringlength#1{% + \bgroup + \qr@a=0% + \xdef\qr@thestring{#1}% + \xa\qr@stringlength@recursive\xa(\qr@thestring\relax\relax)% + \xdef\qr@stringlength{\the\qr@a}% + \egroup +}% + +\def\qr@stringlength@recursive(#1#2){% + \def\qr@testi{#1}% + \ifx\qr@testi\qr@relax + %we are done. + \let\qr@next=\relax% + \else + \advance\qr@a by 1% + \def\qr@next{\qr@stringlength@recursive(#2)}% + \fi + \qr@next +}% +\newcount\qr@for@depth% +\newcount\qr@for@maxdepth% +\qr@for@depth=0% +\qr@for@maxdepth=0% +\newcount\qr@for@start% +\newcount\qr@for@end% +\newcount\qr@for@step% +\def\qr@allocate@new@for@counter{% + \global\advance\qr@for@maxdepth by 1% + \newcount\qr@newforcount% + \xa\global\xa\let\csname qr@for@var@\the\qr@for@maxdepth\endcsname=\qr@newforcount% +}% + +\newif\ifqr@loopshouldrun +\def\qr@for #1=#2to#3by#4#{% + \qr@for@int{#1}{#2}{#3}{#4}% +}% +\long\def\qr@for@int#1#2#3#4#5{% + \bgroup + %Because we're working within a TeX group, + %any values of \qr@for@start, \qr@for@end, and \qr@for@step from an outer loop + %will be restored after the \egroup. + % + %For the \qr@for@var itself, however, we need a different counter, + %because the user's text within the loop might need to access the variable from the outer loop. + \advance\qr@for@depth by 1\relax% This is a local change. + \ifnum\qr@for@depth>\qr@for@maxdepth% + %This is the first time we have gone to this depth of nesting! + %We should only be over by one. + \qr@allocate@new@for@counter% + \fi + \xa\let\xa\qr@for@var\xa=\csname qr@for@var@\the\qr@for@depth\endcsname% + %Now \qr@for@var points to the same register as \qr@for@var@3 or something. + %The next line lets the user-level variable (e.g., \i or \j) point to the same count register. + \let#1=\qr@for@var% + %Now establish the looping parameters. + \edef\qr@for@start@text{#2}% + \edef\qr@for@end@text{#3}% + \edef\qr@for@step@text{#4}% + \def\qr@for@body{\bgroup #5\egroup}% + \xa\qr@for@start\qr@for@start@text\relax% + \xa\qr@for@end \qr@for@end@text\relax% + \xa\qr@for@step \qr@for@step@text\relax% + % + %Next, test whether the loop should run at all. + % * "\qr@for \i = 1 to 0 by 1" should fail. + % * "\qr@for \i = 3 to 5 by -1" should fail. + % * "\qr@for \i = 6 to 2 by 1" should fail. + % * "\qr@for \i = 4 to 4 by -1" should run. + % * "\qr@for \i = 4 to 4 by 1" should run. + % * "\qr@for \i = 5 to 7 by 0" should fail. + %The loop should fail if (step)=0 or if (step) and (end-start) have opposite signs. + %The loop will fail if (step=0) or (step)*(end-start)<0. + % TODO: "\qr@for \i = 5 to 5 by 0" should run (just one iteration). + \qr@loopshouldruntrue + \ifnum\qr@for@step=0\relax + \qr@loopshouldrunfalse + \fi + \qr@a=\qr@for@end% + \advance\qr@a by -\qr@for@start% + \multiply\qr@a by \qr@for@step% + \ifnum\qr@a<0\relax + \qr@loopshouldrunfalse + \fi + \ifqr@loopshouldrun + \qr@for@var=\qr@for@start% + \ifnum\qr@for@step>0\relax + \def\qr@for@recursive{% + \qr@for@body% + \advance\qr@for@var by \qr@for@step% + \ifnum\qr@for@var>\qr@for@end% + \let\qr@for@next=\relax% + \else% + \let\qr@for@next=\qr@for@recursive% + \fi% + \qr@for@next% + }% + \else + \def\qr@for@recursive{% + \qr@for@body% + \advance\qr@for@var by \qr@for@step% + \ifnum\qr@for@var<\qr@for@end% + \let\qr@for@next=\relax% + \else% + \let\qr@for@next=\qr@for@recursive% + \fi% + \qr@for@next% + }% + \fi + \qr@for@recursive% + \fi + \egroup +}% +\def\qr@padatfront#1#2{% + % #1 = macro containing text to pad + % #2 = desired number of characters + % Pads a number with initial zeros. + \qr@getstringlength{#1}% + \qr@a=\qr@stringlength\relax% + \advance\qr@a by 1\relax% + \qr@for \i = \qr@a to #2 by 1\relax% + {\qr@g@preface@macro{#1}{0}}% +} + +\qr@a=-1\relax% +\def\qr@savehexsymbols(#1#2){% + \advance\qr@a by 1\relax% + \xa\def\csname qr@hexchar@\the\qr@a\endcsname{#1}% + \xa\edef\csname qr@hextodecimal@#1\endcsname{\the\qr@a}% + \ifnum\qr@a=15\relax + %Done. + \let\qr@next=\relax% + \else + \def\qr@next{\qr@savehexsymbols(#2)}% + \fi% + \qr@next% +}% +\qr@savehexsymbols(0123456789abcdef\relax\relax)% + +\def\qr@decimaltobase#1#2#3{% + % #1 = macro to store result + % #2 = decimal representation of a positive integer + % #3 = new base + \bgroup + \edef\qr@newbase{#3}% + \gdef\qr@base@result{}% + \qr@a=#2\relax% + \qr@decimaltobase@recursive% + \xdef#1{\qr@base@result}% + \egroup +} +\def\qr@decimaltobase@recursive{% + \qr@b=\qr@a% + \divide\qr@b by \qr@newbase\relax + \multiply\qr@b by -\qr@newbase\relax + \advance\qr@b by \qr@a\relax% + \divide\qr@a by \qr@newbase\relax% + \ifnum\qr@b<10\relax + \edef\qr@newdigit{\the\qr@b}% + \else + \edef\qr@newdigit{\csname qr@hexchar@\the\qr@b\endcsname}% + \fi + \edef\qr@argument{{\noexpand\qr@base@result}{\qr@newdigit}}% + \xa\qr@g@preface@macro\qr@argument% + \ifnum\qr@a=0\relax + \relax + \else + \xa\qr@decimaltobase@recursive + \fi +} + +\newcommand\qr@decimaltohex[3][0]{% + % #1 (opt.) = number of hex digits to create + % #2 = macro to store result + % #3 = decimal digits to convert + \qr@decimaltobase{#2}{#3}{16}% + \qr@padatfront{#2}{#1}% +} + +\newcommand\qr@decimaltobinary[3][0]{% + % #1 (opt.) = number of bits to create + % #2 = macro to store result + % #3 = decimal digits to convert + \qr@decimaltobase{#2}{#3}{2}% + \qr@padatfront{#2}{#1}% +} + +\qr@for \i = 0 to 15 by 1% + {% + \qr@decimaltohex[1]{\qr@hexchar}{\the\i}% + \qr@decimaltobinary[4]{\qr@bits}{\the\i}% + \xa\xdef\csname qr@b2h@\qr@bits\endcsname{\qr@hexchar}% + \xa\xdef\csname qr@h2b@\qr@hexchar\endcsname{\qr@bits}% + }% + +\newcommand\qr@binarytohex[3][\relax]{% + % #1 (optional) = # digits desired + % #2 = macro to save to + % #3 = binary string (must be multiple of 4 bits) + \def\qr@test@i{#1}% + \ifx\qr@test@i\qr@relax% + %No argument specified + \def\qr@desireddigits{0}% + \else + \def\qr@desireddigits{#1}% + \fi + \gdef\qr@base@result{}% + \edef\qr@argument{(#3\relax\relax\relax\relax\relax)}% + \xa\qr@binarytohex@int\qr@argument% + \qr@padatfront{\qr@base@result}{\qr@desireddigits}% + \xdef#2{\qr@base@result}% +} +\def\qr@binarytohex@int(#1#2#3#4#5){% + % #1#2#3#4 = 4 bits + % #5 = remainder, including \relax\relax\relax\relax\relax terminator + \def\qr@test@i{#1}% + \ifx\qr@test@i\qr@relax% + %Done. + \def\qr@next{\relax}% + \else% + \xdef\qr@base@result{\qr@base@result\csname qr@b2h@#1#2#3#4\endcsname}% + \def\qr@next{\qr@binarytohex@int(#5)}% + \fi% + \qr@next% +} + +\newcommand\qr@hextobinary[3][\relax]{% + % #1 (optional) = # bits desired + % #2 = macro to save to + % #3 = hexadecimal string + \bgroup + \def\qr@test@i{#1}% + \ifx\qr@test@i\qr@relax% + %No argument specified + \def\qr@desireddigits{0}% + \else + \def\qr@desireddigits{#1}% + \fi + \gdef\qr@base@result{}% + \edef\qr@argument{(#3\relax\relax)}% + \xa\qr@hextobinary@int\qr@argument% + \qr@padatfront{\qr@base@result}{\qr@desireddigits}% + \xdef#2{\qr@base@result}% + \egroup +} +\def\qr@hextobinary@int(#1#2){% + % #1 = hexadecimal character + % #2 = remainder, including \relax\relax terminator + \def\qr@test@@i{#1}% + \ifx\qr@test@@i\qr@relax% + %Done. + \def\qr@next{\relax}% + \else% + \xdef\qr@base@result{\qr@base@result\csname qr@h2b@#1\endcsname}% + \def\qr@next{\qr@hextobinary@int(#2)}% + \fi% + \qr@next% +} + +\def\qr@hextodecimal#1#2{% + \edef\qr@argument{#2}% + \xa\qr@a\xa=\xa\number\xa"\qr@argument\relax% + \edef#1{\the\qr@a}% +} + +\def\qr@hextodecimal#1#2{% + % #1 = macro to store result + % #2 = hexadecimal representation of a positive integer + \bgroup + \qr@a=0\relax% + \edef\qr@argument{(#2\relax)}% + \xa\qr@hextodecimal@recursive\qr@argument% + \xdef#1{\the\qr@a}% + \egroup +} +\def\qr@hextodecimal@recursive(#1#2){% + % #1 = first hex char + % #2 = remainder + \advance \qr@a by \csname qr@hextodecimal@#1\endcsname\relax% + \edef\qr@testii{#2}% + \ifx\qr@testii\qr@relax% + %Done. + \let\qr@next=\relax% + \else + %There's at least one more digit. + \multiply\qr@a by 16\relax + \edef\qr@next{\noexpand\qr@hextodecimal@recursive(#2)}% + \fi% + \qr@next% +} +{\catcode`\ =12\relax\gdef\qr@otherspace{ }}% +{\catcode`\%=12\relax\gdef\qr@otherpercent{%}}% +{\catcode`\#=12\relax\gdef\qr@otherpound{#}}% +{\catcode`\|=0\relax|catcode`|\=12|relax|gdef|qr@otherbackslash{\}}% +{\catcode`\^^J=12\relax\gdef\qr@otherlf{^^J}}% +\bgroup + \catcode`\<=1\relax + \catcode`\>=2\relax + \catcode`\{=12\relax\gdef\qr@otherleftbrace<{>% + \catcode`\}=12\relax\gdef\qr@otherrightbrace<}>% +\egroup% +{\catcode`\&=12\relax\gdef\qr@otherampersand{&}}% +{\catcode`\~=12\relax\gdef\qr@othertilde{~}}% +{\catcode`\^=12\relax\gdef\qr@othercaret{^}}% +{\catcode`\_=12\relax\gdef\qr@otherunderscore{_}}% +{\catcode`\$=12\relax\gdef\qr@otherdollar{$}}% + +{\catcode`\^^M=13\relax\gdef\qr@verbatimlinefeeds{\let^^M=\qr@otherlf}} +\def\qr@verbatimcatcodes{% + \catcode`\#=12\relax + \catcode`\$=12\relax + \catcode`\&=12\relax + \catcode`\^=12\relax + \catcode`\_=12\relax + \catcode`\~=12\relax + \catcode`\%=12\relax + \catcode`\ =12\relax + \catcode`\^^M=13\relax\qr@verbatimlinefeeds}% + +\def\qr@setescapedspecials{% + \let\ =\qr@otherspace% + \let\%=\qr@otherpercent% + \let\#=\qr@otherpound% + \let\&=\qr@otherampersand% + \let\^=\qr@othercaret% + \let\_=\qr@otherunderscore% + \let\~=\qr@othertilde% + \let\$=\qr@otherdollar% + \let\\=\qr@otherbackslash% + \let\{=\qr@otherleftbrace% + \let\}=\qr@otherrightbrace% + \let\?=\qr@otherlf% +}% +\def\qr@creatematrix#1{% + \xa\gdef\csname #1\endcsname##1##2{% + \csname #1@##1@##2\endcsname + }% +}% + +\def\qr@storetomatrix#1#2#3#4{% + % #1 = matrix name + % #2 = row number + % #3 = column number + % #4 = value of matrix entry + \xa\gdef\csname #1@#2@#3\endcsname{#4}% +}% + +\def\qr@estoretomatrix#1#2#3#4{% + % This version performs exactly one expansion on #4. + % #1 = matrix name + % #2 = row number + % #3 = column number + % #4 = value of matrix + \xa\xa\xa\gdef\xa\xa\csname #1@#2@#3\endcsname\xa{#4}% +}% + +\def\qr@matrixentry#1#2#3{% + % #1 = matrix name + % #2 = row number + % #3 = column number + \csname #1@#2@#3\endcsname% +}% + +\def\qr@createsquareblankmatrix#1#2{% + \qr@creatematrix{#1}% + \xa\gdef\csname #1@numrows\endcsname{#2}% + \xa\gdef\csname #1@numcols\endcsname{#2}% + \qr@for \i = 1 to #2 by 1% + {\qr@for \j = 1 to #2 by 1% + {\qr@storetomatrix{#1}{\the\i}{\the\j}{\qr@blank}}}% +}% + +\def\qr@numberofrowsinmatrix#1{% + \csname #1@numrows\endcsname% +}% + +\def\qr@numberofcolsinmatrix#1{% + \csname #1@numcols\endcsname% +}% + +\def\qr@setnumberofrows#1#2{% + \xa\xdef\csname #1@numrows\endcsname{#2}% +}% + +\def\qr@setnumberofcols#1#2{% + \xa\xdef\csname #1@numcols\endcsname{#2}% +}% + +\newlength\qr@desiredheight +\setlength\qr@desiredheight{2cm}% +\newlength\qr@modulesize +\newlength\qr@minipagewidth + +\def\qr@printmatrix#1{% + \def\qr@black{\rule{\qr@modulesize}{\qr@modulesize}}% + \def\qr@white{\rule{\qr@modulesize}{0pt}}% + \def\qr@black@fixed{\rule{\qr@modulesize}{\qr@modulesize}}% + \def\qr@white@fixed{\rule{\qr@modulesize}{0pt}}% + \def\qr@black@format{\rule{\qr@modulesize}{\qr@modulesize}}% + \def\qr@white@format{\rule{\qr@modulesize}{0pt}}% + %Set module size + \setlength{\qr@modulesize}{\qr@desiredheight}% + \divide\qr@modulesize by \qr@size\relax% + % + \setlength{\qr@minipagewidth}{\qr@modulesize}% + \multiply\qr@minipagewidth by \qr@size\relax% + \ifqr@tight + \else + \advance\qr@minipagewidth by 8\qr@modulesize% + \fi + \begin{minipage}{\qr@minipagewidth}% + \baselineskip=\qr@modulesize% + \ifqr@tight\else\rule{0pt}{4\qr@modulesize}\par\fi% %Blank space at top. + \qr@for \i = 1 to \qr@numberofrowsinmatrix{#1} by 1% + {\ifqr@tight\else\rule{4\qr@modulesize}{0pt}\fi% %Blank space at left. + \qr@for \j = 1 to \qr@numberofcolsinmatrix{#1} by 1% + {\qr@matrixentry{#1}{\the\i}{\the\j}}% + \par}% + \ifqr@tight\else\rule{0pt}{4\qr@modulesize}\par\fi% + \end{minipage}% +}% + +\def\qr@printsavedbinarymatrix#1{% + \edef\qr@binarystring{#1\relax\relax}% + %Set module size + \setlength{\qr@modulesize}{\qr@desiredheight}% + \divide\qr@modulesize by \qr@size\relax% + % + \setlength{\qr@minipagewidth}{\qr@modulesize}% + \multiply\qr@minipagewidth by \qr@size\relax% + \ifqr@tight + \else + \advance\qr@minipagewidth by 8\qr@modulesize% + \fi + \begin{minipage}{\qr@minipagewidth}% + \baselineskip=\qr@modulesize% + \ifqr@tight\else\rule{0pt}{4\qr@modulesize}\par\fi% %Blank space at top. + \qr@for \i = 1 to \qr@size by 1% + {\ifqr@tight\else\rule{4\qr@modulesize}{0pt}\fi% %Blank space at left. + \qr@for \j = 1 to \qr@size by 1% + {\edef\qr@theargument{(\qr@binarystring)}% + \xa\qr@printsavedbinarymatrix@int\qr@theargument + }% + \par}% + \ifqr@tight\else\rule{0pt}{4\qr@modulesize}\par\fi% + \end{minipage}% +}% + +\def\qr@printsavedbinarymatrix@int(#1#2){% + % #1 = first bit, either 1 or 0. + % #2 = remainder of string, terminating with \relax\relax + % There's no need to check for EOF here, because + % we'll only call this n^2 times. + \ifcase #1\relax + \rule{\qr@modulesize}{0pt}% % 0: white square + \or + \rule{\qr@modulesize}{\qr@modulesize}% % 1: black square + \fi + \xdef\qr@binarystring{#2}% +}% + +\def\qr@createliteralmatrix#1#2#3{% + % #1 = matrix name + % #2 = m, the number of rows and columns in the square matrix + % #3 = a string of m^2 tokens to be written into the matrix + \qr@creatematrix{#1}% + \xa\xdef\csname #1@numrows\endcsname{#2}% + \xa\xdef\csname #1@numcols\endcsname{#2}% + \gdef\qr@literalmatrix@tokens{#3}% + \qr@for \i = 1 to #2 by 1% + {\qr@for \j = 1 to #2 by 1% + {\xa\qr@createliteralmatrix@int\xa(\qr@literalmatrix@tokens)% + \qr@estoretomatrix{#1}{\the\i}{\the\j}{\qr@entrytext}% + }% + }% +} +\def\qr@createliteralmatrix@int(#1#2){% + \def\qr@entrytext{#1}% + \gdef\qr@literalmatrix@tokens{#2}% +} + +\qr@createliteralmatrix{finderpattern}{8}{% + \qr@black@fixed\qr@black@fixed\qr@black@fixed\qr@black@fixed\qr@black@fixed\qr@black@fixed\qr@black@fixed\qr@white@fixed% + \qr@black@fixed\qr@white@fixed\qr@white@fixed\qr@white@fixed\qr@white@fixed\qr@white@fixed\qr@black@fixed\qr@white@fixed% + \qr@black@fixed\qr@white@fixed\qr@black@fixed\qr@black@fixed\qr@black@fixed\qr@white@fixed\qr@black@fixed\qr@white@fixed% + \qr@black@fixed\qr@white@fixed\qr@black@fixed\qr@black@fixed\qr@black@fixed\qr@white@fixed\qr@black@fixed\qr@white@fixed% + \qr@black@fixed\qr@white@fixed\qr@black@fixed\qr@black@fixed\qr@black@fixed\qr@white@fixed\qr@black@fixed\qr@white@fixed% + \qr@black@fixed\qr@white@fixed\qr@white@fixed\qr@white@fixed\qr@white@fixed\qr@white@fixed\qr@black@fixed\qr@white@fixed% + \qr@black@fixed\qr@black@fixed\qr@black@fixed\qr@black@fixed\qr@black@fixed\qr@black@fixed\qr@black@fixed\qr@white@fixed% + \qr@white@fixed\qr@white@fixed\qr@white@fixed\qr@white@fixed\qr@white@fixed\qr@white@fixed\qr@white@fixed\qr@white@fixed% +}% + +\qr@createliteralmatrix{alignmentpattern}{5}{% + \qr@black@fixed\qr@black@fixed\qr@black@fixed\qr@black@fixed\qr@black@fixed% + \qr@black@fixed\qr@white@fixed\qr@white@fixed\qr@white@fixed\qr@black@fixed% + \qr@black@fixed\qr@white@fixed\qr@black@fixed\qr@white@fixed\qr@black@fixed% + \qr@black@fixed\qr@white@fixed\qr@white@fixed\qr@white@fixed\qr@black@fixed% + \qr@black@fixed\qr@black@fixed\qr@black@fixed\qr@black@fixed\qr@black@fixed% +}% + +\def\qr@copymatrixentry#1#2#3#4#5#6{% + % Copy the (#2,#3) entry of matrix #1 + % to the (#5,#6) position of matrix #4. + \xa\xa\xa\global% + \xa\xa\xa\let\xa\xa\csname #4@#5@#6\endcsname% + \csname #1@#2@#3\endcsname% +}% + +\def\qr@createduplicatematrix#1#2{% + % #1 = name of copy + % #2 = original matrix to be copied + \qr@creatematrix{#1}% + \qr@for \i = 1 to \qr@numberofrowsinmatrix{#2} by 1% + {\qr@for \j = 1 to \qr@numberofcolsinmatrix{#2} by 1% + {\qr@copymatrixentry{#2}{\the\i}{\the\j}{#1}{\the\i}{\the\j}% + }% + }% + \qr@setnumberofrows{#1}{\qr@numberofrowsinmatrix{#2}}% + \qr@setnumberofcols{#1}{\qr@numberofcolsinmatrix{#2}}% +}% + +\def\qr@placefinderpattern@int#1#2#3#4#5{% + % Work on matrix #1. + % Start in position (#2, #3) -- should be a corner + % #4 indicates horizontal direction (1=right, -1=left) + % #5 indicates vertical direction (1=down, -1=up) + % + % In this code, \sourcei and \sourcej are TeX counts working through the finderpattern matrix, + % and i and j are LaTeX counters indicating positions in the big matrix. + \setcounter{qr@i}{#2}% + \qr@for \sourcei=1 to 8 by 1% + {\setcounter{qr@j}{#3}% + \qr@for \sourcej=1 to 8 by 1% + {\qr@copymatrixentry{finderpattern}{\the\sourcei}{\the\sourcej}% + {#1}{\theqr@i}{\theqr@j}% + \addtocounter{qr@j}{#5}% + }% + \addtocounter{qr@i}{#4}% + }% +}% + +\def\qr@placefinderpatterns#1{% + % #1=matrix name + \qr@placefinderpattern@int{#1}{1}{1}{1}{1}% + \qr@placefinderpattern@int{#1}{\qr@numberofrowsinmatrix{#1}}{1}{-1}{1}% + \qr@placefinderpattern@int{#1}{1}{\qr@numberofcolsinmatrix{#1}}{1}{-1}% +}% + +\def\qr@placetimingpatterns#1{% + %Set \qr@endingcol to n-8. + \qr@a=\qr@size\relax% + \advance\qr@a by -8\relax% + \edef\qr@endingcol{\the\qr@a}% + \qr@for \j = 9 to \qr@endingcol by 1% + {\ifodd\j\relax% + \qr@storetomatrix{#1}{7}{\the\j}{\qr@black@fixed}% + \qr@storetomatrix{#1}{\the\j}{7}{\qr@black@fixed}% + \else% + \qr@storetomatrix{#1}{7}{\the\j}{\qr@white@fixed}% + \qr@storetomatrix{#1}{\the\j}{7}{\qr@white@fixed}% + \fi% + }% +}% + +\def\qr@placealignmentpattern@int#1#2#3{% + % Work on matrix #1. + % Write an alignment pattern into the matrix, centered on (#2,#3). + \qr@a=#2\relax% + \advance\qr@a by -2\relax% + \qr@b=#3\relax% + \advance\qr@b by -2\relax% + \setcounter{qr@i}{\the\qr@a}% + \qr@for \i=1 to 5 by 1% + {\setcounter{qr@j}{\the\qr@b}% + \qr@for \j=1 to 5 by 1% + {\qr@copymatrixentry{alignmentpattern}{\the\i}{\the\j}% + {#1}{\theqr@i}{\theqr@j}% + \stepcounter{qr@j}% + }% + \stepcounter{qr@i}% + }% +}% + +\newif\ifqr@incorner% +\def\qr@placealignmentpatterns#1{% + %There are k^2-3 alignment patterns, + %arranged in a (k x k) grid within the matrix. + %They begin in row 7, column 7, + %except that the ones in the NW, NE, and SW corners + %are omitted because of the finder patterns. + %Recall that + % * \qr@k stores k, + % * \qr@alignment@firstskip stores how far between the 1st and 2nd row/col, & + % * \qr@alignment@generalskip stores how far between each subsequent row/col. + \xa\ifnum\qr@k>0\relax + %There will be at least one alignment pattern. + %N.B. k cannot equal 1. + \xa\ifnum\qr@k=2\relax + % 2*2-3 = exactly 1 alignment pattern. + \qr@a=7\relax + \advance\qr@a by \qr@alignment@firstskip\relax + \xdef\qr@target@ii{\the\qr@a}% + \qr@placealignmentpattern@int{#1}{\qr@target@ii}{\qr@target@ii}% + \else + % k is at least 3, so the following loops should be safe. + \xdef\qr@target@ii{7}% + \qr@for \ii = 1 to \qr@k by 1% + {\ifcase\ii\relax% + \relax% \ii should never equal 0. + \or + \xdef\qr@target@ii{7}% If \ii = 1, we start in row 7. + \or + %If \ii = 2, we add the firstskip. + \qr@a=\qr@target@ii\relax% + \advance\qr@a by \qr@alignment@firstskip\relax% + \xdef\qr@target@ii{\the\qr@a}% + \else + %If \ii>2, we add the generalskip. + \qr@a=\qr@target@ii\relax% + \advance\qr@a by \qr@alignment@generalskip\relax% + \xdef\qr@target@ii{\the\qr@a}% + \fi + \qr@for \jj = 1 to \qr@k by 1% + {\ifcase\jj\relax% + \relax% \jj should never equal 0. + \or + \xdef\qr@target@jj{7}% If \jj=1, we start in row 7. + \or + %If \jj=2, we add the firstskip. + \qr@a=\qr@target@jj\relax% + \advance\qr@a by \qr@alignment@firstskip% + \xdef\qr@target@jj{\the\qr@a}% + \else + %If \jj>2, we add the generalskip. + \qr@a=\qr@target@jj\relax% + \advance\qr@a by \qr@alignment@generalskip% + \xdef\qr@target@jj{\the\qr@a}% + \fi + \qr@incornerfalse% + \ifnum\ii=1\relax + \ifnum\jj=1\relax + \qr@incornertrue + \else + \ifnum\qr@k=\jj\relax + \qr@incornertrue + \fi + \fi + \else + \xa\ifnum\qr@k=\ii\relax + \ifnum\jj=1\relax + \qr@incornertrue + \fi + \fi + \fi + \ifqr@incorner + \relax + \else + \qr@placealignmentpattern@int{#1}{\qr@target@ii}{\qr@target@jj}% + \fi + }% ends \qr@for \jj + }% ends \qr@for \ii + \fi + \fi +}% + +\def\qr@placedummyformatpatterns#1{% + \qr@for \j = 1 to 9 by 1% + {\ifnum\j=7\relax% + \else% + \qr@storetomatrix{#1}{9}{\the\j}{\qr@format@square}% + \qr@storetomatrix{#1}{\the\j}{9}{\qr@format@square}% + \fi% + }% + \setcounter{qr@j}{\qr@size}% + \qr@for \j = 1 to 8 by 1% + {\qr@storetomatrix{#1}{9}{\theqr@j}{\qr@format@square}% + \qr@storetomatrix{#1}{\theqr@j}{9}{\qr@format@square}% + \addtocounter{qr@j}{-1}% + }% + %Now go back and change the \qr@format@square in (n-8,9) to \qr@black@fixed. + \addtocounter{qr@j}{1}% + \qr@storetomatrix{#1}{\theqr@j}{9}{\qr@black@fixed}% +}% + +\def\qr@placedummyversionpatterns#1{% + \xa\ifnum\qr@version>6\relax + %Must include version information. + \global\c@qr@i=\qr@size% + \global\advance\c@qr@i by -10\relax% + \qr@for \i = 1 to 3 by 1% + {\qr@for \j = 1 to 6 by 1% + {\qr@storetomatrix{#1}{\theqr@i}{\the\j}{\qr@format@square}% + \qr@storetomatrix{#1}{\the\j}{\theqr@i}{\qr@format@square}% + }% + \stepcounter{qr@i}% + }% + \fi +}% + +\def\qr@writebit(#1#2)#3{% + % #3 = matrix name + % (qr@i,qr@j) = position to write in (LaTeX counters) + % #1 = bit to be written + % #2 = remaining bits plus '\relax' as an end-of-file marker + \edef\qr@datatowrite{#2}% + \ifnum#1=1 + \qr@storetomatrix{#3}{\theqr@i}{\theqr@j}{\qr@black}% + \else + \qr@storetomatrix{#3}{\theqr@i}{\theqr@j}{\qr@white}% + \fi +}% + +\newif\ifqr@rightcol +\newif\ifqr@goingup + +\def\qr@writedata@hex#1#2{% + % #1 = name of a matrix that has been prepared with finder patterns, timing patterns, etc. + % #2 = a string consisting of bytes to write into the matrix, in two-char hex format. + \setcounter{qr@i}{\qr@numberofrowsinmatrix{#1}}% + \setcounter{qr@j}{\qr@numberofcolsinmatrix{#1}}% + \qr@rightcoltrue% + \qr@goinguptrue% + \edef\qr@argument{{#1}(#2\relax\relax\relax)}% + \xa\qr@writedata@hex@recursive\qr@argument% +}% + +\def\qr@writedata@hex@recursive#1(#2#3#4){% + % #1 = name of a matrix that has been prepared with finder patterns, timing patterns, etc. + % (qr@i,qr@j) = position to write in LaTeX counters + % #2#3#4 contains the hex codes of the bytes to be written, plus \relax\relax\relax + % as an end-of-file marker + \edef\qr@testii{#2}% + \ifx\qr@testii\qr@relax% + % #2 is \relax, so there is nothing more to write. + \relax + \let\qr@next=\relax + \else + % #2 is not \relax, so there is another byte to write. + \qr@hextobinary[8]{\bytetowrite}{#2#3}% + \xdef\qr@datatowrite{\bytetowrite\relax}% %Add terminating "\relax" + \qr@writedata@recursive{#1}% %This function actually writes the 8 bits. + \edef\qr@argument{{#1}(#4)}% + \xa\def\xa\qr@next\xa{\xa\qr@writedata@hex@recursive\qr@argument}% %Call self to write the next bit. + \fi + \qr@next +}% + +\def\qr@writedata#1#2{% + % #1 = name of a matrix that has been prepared with finder patterns, timing patterns, etc. + % #2 = a string consisting of 0's and 1's to write into the matrix. + \setcounter{qr@i}{\qr@numberofrowsinmatrix{#1}}% + \setcounter{qr@j}{\qr@numberofcolsinmatrix{#1}}% + \qr@rightcoltrue + \qr@goinguptrue + \edef\qr@datatowrite{#2\relax}% + \qr@writedata@recursive{#1}% +}% + +\def\qr@@blank{\qr@blank}% + +\def\qr@writedata@recursive#1{% + % #1 = matrix name + % (qr@i,qr@j) = position to write in (LaTeX counters) + % \qr@datatowrite contains the bits to be written, plus '\relax' as an end-of-file marker + \xa\let\xa\squarevalue\csname #1@\theqr@i @\theqr@j\endcsname% + \ifx\squarevalue\qr@@blank + %Square is blank, so write data in it. + \xa\qr@writebit\xa(\qr@datatowrite){#1}% + %The \qr@writebit macro not only writes the first bit of \qr@datatowrite into the matrix, + %but also removes the bit from the 'bitstream' of \qr@datatowrite. + \fi + %Now adjust our position in the matrix. + \ifqr@rightcol + %From the right-hand half of the two-bit column, we always move left. Easy peasy. + \addtocounter{qr@j}{-1}% + \qr@rightcolfalse + \else + %If we're in the left-hand column, things are harder. + \ifqr@goingup + %First, suppose we're going upwards. + \ifnum\c@qr@i>1\relax% + %If we're not in the first row, things are easy. + %We move one to the right and one up. + \addtocounter{qr@j}{1}% + \addtocounter{qr@i}{-1}% + \qr@rightcoltrue + \else + %If we are in the first row, then we move to the left, + %and we are now in the right-hand column on a downward pass. + \addtocounter{qr@j}{-1}% + \qr@goingupfalse + \qr@rightcoltrue + \fi + \else + %Now, suppose we're going downwards. + \xa\ifnum\qr@size>\c@qr@i\relax% + %If we're not yet in the bottom row, things are easy. + %We move one to the right and one down. + \addtocounter{qr@j}{1}% + \addtocounter{qr@i}{1}% + \qr@rightcoltrue + \else + %If we are in the bottom row, then we move to the left, + %and we are now in the right-hand column on an upward pass. + \addtocounter{qr@j}{-1}% + \qr@rightcoltrue + \qr@goinguptrue + \fi + \fi + %One problem: what if we just moved into the 7th column? + %Das ist verboten. + %If we just moved (left) into the 7th column, we should move on into the 6th column. + \ifnum\c@qr@j=7\relax% + \setcounter{qr@j}{6}% + \fi + \fi + %Now check whether there are any more bits to write. + \ifx\qr@datatowrite\qr@relax + % \qr@datatowrite is just `\relax', so we're done. + \let\qr@next=\relax + \relax + \else + % Write some more! + \def\qr@next{\qr@writedata@recursive{#1}}% + \fi + \qr@next +}% + +\def\qr@writeremainderbits#1{% + % #1 = name of a matrix that has been prepared and partly filled. + % (qr@i,qr@j) = position to write in LaTeX counters + \xa\ifnum\qr@numremainderbits>0\relax + \def\qr@datatowrite{}% + \qr@for \i = 1 to \qr@numremainderbits by 1% + {\g@addto@macro{\qr@datatowrite}{0}}% + \g@addto@macro{\qr@datatowrite}{\relax}% terminator + \qr@writedata@recursive{#1}% + \fi +}% + +\newif\ifqr@cellinmask + +\def\qr@setmaskingfunction#1{% + % #1 = 1 decimal digit for the mask. (I see no reason to use the 3-bit binary code.) + % The current position is (\themaski,\themaskj), with indexing starting at 0. + \edef\qr@maskselection{#1}% + \xa\ifcase\qr@maskselection\relax + %Case 0: checkerboard + \def\qr@parsemaskingfunction{% + % Compute mod(\themaski+\themaskj,2)% + \qr@a=\c@maski% + \advance\qr@a by \c@maskj% + \qr@b=\qr@a% + \divide\qr@b by 2% + \multiply\qr@b by 2% + \advance\qr@a by -\qr@b% + \edef\qr@maskfunctionresult{\the\qr@a}% + }% + \or + %Case 1: horizontal stripes + \def\qr@parsemaskingfunction{% + % Compute mod(\themaski,2)% + \ifodd\c@maski\relax% + \def\qr@maskfunctionresult{1}% + \else% + \def\qr@maskfunctionresult{0}% + \fi% + }% + \or + %Case 2: vertical stripes + \def\qr@parsemaskingfunction{% + % Compute mod(\themaskj,3)% + \qr@a=\c@maskj% + \divide\qr@a by 3% + \multiply\qr@a by 3% + \advance\qr@a by -\c@maskj% + \edef\qr@maskfunctionresult{\the\qr@a}% + }% + \or + %Case 3: diagonal stripes + \def\qr@parsemaskingfunction{% + % Compute mod(\themaski+\themaskj,3)% + \qr@a=\c@maski% + \advance\qr@a by \c@maskj% + \qr@b=\qr@a% + \divide\qr@b by 3% + \multiply\qr@b by 3% + \advance\qr@b by -\qr@a% + \edef\qr@maskfunctionresult{\the\qr@b}% + }% + \or + %Case 4: wide checkerboard + \def\qr@parsemaskingfunction{% + % Compute mod(floor(\themaski/2) + floor(\themaskj/3),2) % + \qr@a=\c@maski% + \divide\qr@a by 2% + \qr@b=\c@maskj% + \divide\qr@b by 3% + \advance\qr@a by \qr@b% + \qr@b=\qr@a% + \divide\qr@a by 2% + \multiply\qr@a by 2% + \advance\qr@a by -\qr@b% + \edef\qr@maskfunctionresult{\the\qr@a}% + }% + \or + %Case 5: quilt + \def\qr@parsemaskingfunction{% + % Compute mod(\themaski*\themaskj,2) + mod(\themaski*\themaskj,3) % + \qr@a=\c@maski% + \multiply\qr@a by \c@maskj% + \qr@b=\qr@a% + \qr@c=\qr@a% + \divide\qr@a by 2% + \multiply\qr@a by 2% + \advance\qr@a by -\qr@c% (result will be -mod(i*j,2), which is negative.) + \divide\qr@b by 3% + \multiply\qr@b by 3% + \advance\qr@b by -\qr@c% (result will be -mod(i*j,3), which is negative.) + \advance\qr@a by \qr@b% (result is negative of what's in the spec.) + \edef\qr@maskfunctionresult{\the\qr@a}% + }% + \or + %Case 6: arrows + \def\qr@parsemaskingfunction{% + % Compute mod( mod(\themaski*\themaskj,2) + mod(\themaski*\themaskj,3) , 2 ) % + \qr@a=\c@maski% + \multiply\qr@a by \c@maskj% + \qr@b=\qr@a% + \qr@c=\qr@a% + \multiply\qr@c by 2% % \qr@c equals 2*i*j. + \divide\qr@a by 2% + \multiply\qr@a by 2% + \advance\qr@c by -\qr@a% Now \qr@c equals i*j + mod(i*j,2). + \divide\qr@b by 3% + \multiply\qr@b by 3% + \advance\qr@c by -\qr@b% (Now \qr@c equals mod(i*j,2) + mod(i*j,3). + \qr@a=\qr@c% + \divide\qr@a by 2% + \multiply\qr@a by 2% + \advance\qr@c by-\qr@a% + \edef\qr@maskfunctionresult{\the\qr@c}% + }% + \or + %Case 7: shotgun + \def\qr@parsemaskingfunction{% + % Compute mod( mod(\themaski+\themaskj,2) + mod(\themaski*\themaskj,3) , 2 ) % + \qr@a=\c@maski% + \advance\qr@a by \c@maskj% %So \qr@a = i+j + \qr@b=\c@maski% + \multiply\qr@b by \c@maskj% %So \qr@b = i*j + \qr@c=\qr@a% + \advance\qr@c by \qr@b% So \qr@c = i+j+i*j + \divide\qr@a by 2% + \multiply\qr@a by 2% + \advance\qr@c by -\qr@a% So \qr@c = mod(i+j,2) + i*j + \divide\qr@b by 3% + \multiply\qr@b by 3% + \advance\qr@c by -\qr@b% So \qr@c = mod(i+j,2) + mod(i*j,3) + \qr@a=\qr@c% + \divide\qr@c by 2% + \multiply\qr@c by 2% + \advance\qr@a by -\qr@c% + \edef\qr@maskfunctionresult{\the\qr@a}% + }% + \fi +}% + +\def\qr@checkifcellisinmask{% + % The current position is (\i,\j), in TeX counts, + % but the LaTeX counters (maski,maskj) should contain + % the current position with indexing starting at 0. + % That is, maski = \i-1 and maskj = \j-1. + % + % \qr@parsemaskingfunction must have been set by a call to \qr@setmaskingfunction + \qr@parsemaskingfunction + \xa\ifnum\qr@maskfunctionresult=0\relax + \qr@cellinmasktrue + \else + \qr@cellinmaskfalse + \fi +}% + +\newcounter{maski}% +\newcounter{maskj}% + +\def\qr@applymask#1#2#3{% + % #1 = name of a matrix that should be filled out completely + % except for the format and/or version information. + % #2 = name of a new matrix to contain the masked version + % #3 = 1 decimal digit naming the mask + \qr@createduplicatematrix{#2}{#1}% + \qr@setmaskingfunction{#3}% + \setcounter{maski}{-1}% + \qr@for \i = 1 to \qr@size by 1% + {\stepcounter{maski}% + \setcounter{maskj}{-1}% + \qr@for \j = 1 to \qr@size by 1% + {\stepcounter{maskj}% + \qr@checkifcellisinmask + \ifqr@cellinmask + \qr@checkifcurrentcellcontainsdata{#2}% + \ifqr@currentcellcontainsdata + \qr@flipcurrentcell{#2}% + \fi + \fi + }% + }% +}% + +\newif\ifqr@currentcellcontainsdata +\qr@currentcellcontainsdatafalse + +\def\qr@@white{\qr@white}% +\def\qr@@black{\qr@black}% + +\def\qr@checkifcurrentcellcontainsdata#1{% + % #1 = name of matrix + \qr@currentcellcontainsdatafalse + \xa\ifx\csname #1@\the\i @\the\j\endcsname\qr@@white + \qr@currentcellcontainsdatatrue + \fi + \xa\ifx\csname #1@\the\i @\the\j\endcsname\qr@@black + \qr@currentcellcontainsdatatrue + \fi +}% + +\def\qr@flipped@black{\qr@black}% +\def\qr@flipped@white{\qr@white}% + +\def\qr@flipcurrentcell#1{% + % #1 = name of matrix + % (\i, \j) = current position, in TeX counts. + % This assumes the cell contains data, either black or white! + \xa\ifx\csname #1@\the\i @\the\j\endcsname\qr@@white + \qr@storetomatrix{#1}{\the\i}{\the\j}{\qr@flipped@black}% + \else + \qr@storetomatrix{#1}{\the\i}{\the\j}{\qr@flipped@white}% + \fi +}% + +\def\qr@chooseandapplybestmask#1{% + % #1 = name of a matrix that should be filled out completely + % except for the format and/or version information. + % This function applies all eight masks in succession, + % calculates their penalties, and remembers the best. + % The number indicating which mask was used is saved in \qr@mask@selected. + \qr@createduplicatematrix{originalmatrix}{#1}% + \message{^^J}% + \gdef\qr@currentbestmask{0}% + \qr@for \i = 1 to 7 by 1% + {\message{^^J}% + \xa\xa\xa\ifnum\xa\qr@penalty\xa<\qr@currentbestpenalty\relax + %We found a better mask. + \xdef\qr@currentbestmask{\the\i}% + \qr@createduplicatematrix{#1}{currentmasked}% + \xdef\qr@currentbestpenalty{\qr@penalty}% + \fi + }% + \xdef\qr@mask@selected{\qr@currentbestmask}% + \message{^^J}% +}% + +\def\qr@Ni{3}% +\def\qr@Nii{3}% +\def\qr@Niii{40}% +\def\qr@Niv{10}% +\def\qr@fiveones{11111}% +\def\qr@fivezeros{11111}% +\def\qr@twoones{11}% +\def\qr@twozeros{00}% +\def\qr@finderA{00001011101}% +\def\qr@finderB{10111010000}% +\def\qr@finderB@three{1011101000}% +\def\qr@finderB@two{101110100}% +\def\qr@finderB@one{10111010}% +\def\qr@finderB@zero{1011101}% +\newif\ifqr@stringoffive +\def\qr@addpenaltyiii{% + \addtocounter{penaltyiii}{\qr@Niii}% +}% +\newcounter{totalones}% +\newcounter{penaltyi}% +\newcounter{penaltyii}% +\newcounter{penaltyiii}% +\newcounter{penaltyiv}% +\def\qr@evaluatemaskpenalty#1{% + % #1 = name of a matrix that we will test for the penalty + % according to the specs. + \setcounter{penaltyi}{0}% + \setcounter{penaltyii}{0}% + \setcounter{penaltyiii}{0}% + \setcounter{penaltyiv}{0}% + \bgroup%localize the meanings we give to the symbols + \def\qr@black{1}\def\qr@white{0}% + \def\qr@black@fixed{1}\def\qr@white@fixed{0}% + \def\qr@format@square{0}% This is not stated in the specs, but seems + % to be the standard implementation. + \def\qr@blank{0}% These would be any bits at the end. + % + \setcounter{totalones}{0}% + \qr@for \i=1 to \qr@size by 1% + {\def\qr@lastfive{z}% %The z is a dummy, that will be removed before any testing. + \qr@stringoffivefalse + \def\qr@lasttwo@thisrow{z}% %The z is a dummy. + \def\qr@lasttwo@nextrow{z}% %The z is a dummy. + \def\qr@lastnine{z0000}% %The 0000 stands for the white space to the left. The z is a dummy. + \def\qr@ignore@finderB@at{0}% + \qr@for \j=1 to \qr@size by 1% + {\edef\qr@newbit{\qr@matrixentry{#1}{\the\i}{\the\j}}% + % + % LASTFIVE CODE FOR PENALTY 1 + % First, add the new bit to the end. + \xa\g@addto@macro\xa\qr@lastfive\xa{\qr@newbit}% + \ifnum\j<5\relax% + %Not yet on the 5th entry. + %Don't do any testing. + \else + % 5th entry or later. + % Remove the old one, and then test. + \qr@removefirsttoken\qr@lastfive% + \ifx\qr@lastfive\qr@fiveones% + \ifqr@stringoffive% + %This is a continuation of a previous block of five or more 1's. + \stepcounter{penaltyi}% + \else + %This is a new string of five 1's. + \addtocounter{penaltyi}{\qr@Ni}% + \global\qr@stringoffivetrue + \fi + \else + \ifx\qr@lastfive\qr@fivezeros% + \ifqr@stringoffive + %This is a continuation of a previous block of five or more 0's. + \stepcounter{penaltyi}% + \else + %This is a new string of five 0's. + \addtocounter{penaltyi}{\qr@Ni}% + \global\qr@stringoffivetrue + \fi + \else + %This is not a string of five 1's or five 0's. + \global\qr@stringoffivefalse + \fi + \fi + \fi + % + % 2x2 BLOCKS FOR PENALTY 2 + % Every 2x2 block of all 1's counts for \qr@Nii penalty points. + % We do not need to run this test in the last row. + \xa\ifnum\xa\i\xa<\qr@size\relax + \xa\g@addto@macro\xa\qr@lasttwo@thisrow\xa{\qr@newbit}% + %Compute \qr@iplusone + \qr@a=\i\relax% + \advance\qr@a by 1% + \edef\qr@iplusone{\the\qr@a}% + % + \edef\qr@nextrowbit{\qr@matrixentry{#1}{\qr@iplusone}{\the\j}}% + \xa\g@addto@macro\xa\qr@lasttwo@nextrow\xa{\qr@nextrowbit}% + \ifnum\j<2\relax% + %Still in the first column; no check. + \else + %Second column or later. Remove the old bits, and then test. + \qr@removefirsttoken\qr@lasttwo@thisrow + \qr@removefirsttoken\qr@lasttwo@nextrow + \ifx\qr@lasttwo@thisrow\qr@twoones + \ifx\qr@lasttwo@nextrow\qr@twoones + \addtocounter{penaltyii}{\qr@Nii}% + \fi + \else + \ifx\qr@lasttwo@thisrow\qr@twozeros + \ifx\qr@lasttwo@nextrow\qr@twozeros + \addtocounter{penaltyii}{\qr@Nii}% + \fi + \fi + \fi + \fi + \fi + % + % LASTNINE CODE FOR PENALTY 3 + % First, add the new bit to the end. + \xa\g@addto@macro\xa\qr@lastnine\xa{\qr@newbit}% + \ifnum\j<7\relax% + %Not yet on the 7th entry. + %Don't do any testing. + \else + % 7th entry or later. + % Remove the old one, and then test. + \qr@removefirsttoken\qr@lastnine + \xa\ifnum\qr@size=\j\relax% + % Last column. Any of the following should count: + % 1011101 (\qr@finderB@zero) + % 10111010 (\qr@finderB@one) + % 101110100 (\qr@finderB@two) + % 1011101000 (\qr@finderB@three) + % 10111010000 (\qr@finderB) + \ifx\qr@lastnine\qr@finderB + \qr@addpenaltyiii + \else + \qr@removefirsttoken\qr@lastnine + \ifx\qr@lastnine\qr@finderB@three + \qr@addpenaltyiii + \else + \qr@removefirsttoken\qr@lastnine + \ifx\qr@lastnine\qr@finderB@two + \qr@addpenaltyiii + \else + \qr@removefirsttoken\qr@lastnine + \ifx\qr@lastnine\qr@finderB@one + \qr@addpenaltyiii + \else + \qr@removefirsttoken\qr@lastnine + \ifx\qr@lastnine\qr@finderB@zero + \qr@addpenaltyiii + \fi + \fi + \fi + \fi + \fi + \else + \ifx\qr@lastnine\qr@finderA% %Matches 0000 1011101 + \qr@addpenaltyiii + %Also, we record our discovery, so that we can't count this pattern again + %if it shows up four columns later as 1011101 0000. + % + %Set \qr@ignore@finderB@at to \j+4. + \qr@a=\j\relax% + \advance\qr@a by 4% + \xdef\qr@ignore@finderB@at{\the\qr@a}% + \else + \ifx\qr@lastfive\qr@finderB% %Matches 1011101 0000. + \xa\ifnum\qr@ignore@finderB@at=\j\relax + %This pattern was *not* counted already earlier. + \qr@addpenaltyiii + \fi + \fi + \fi + \fi + \fi + % + %COUNT 1's FOR PENALTY 4 + \xa\ifnum\qr@newbit=1\relax% + \stepcounter{totalones}% + \fi + }% end of j-loop + }% end of i-loop + % + %NOW WE ALSO NEED TO RUN DOWN THE COLUMNS TO FINISH CALCULATING PENALTIES 1 AND 3. + \qr@for \j=1 to \qr@size by 1% + {\def\qr@lastfive{z}% %The z is a dummy, that will be removed before any testing. + \qr@stringoffivefalse + \def\qr@lastnine{z0000}% %The 0000 stands for the white space to the left. The z is a dummy. + \def\qr@ignore@finderB@at{0}% + \qr@for \i=1 to \qr@size by 1% + {\edef\qr@newbit{\qr@matrixentry{#1}{\the\i}{\the\j}}% + % + % LASTFIVE CODE FOR PENALTY 1 + % First, add the new bit to the end. + \xa\g@addto@macro\xa\qr@lastfive\xa{\qr@newbit}% + \ifnum\i<5\relax% + %Not yet on the 5th entry. + %Don't do any testing. + \else + % 5th entry or later. + % Remove the old one, and then test. + \qr@removefirsttoken\qr@lastfive% + \ifx\qr@lastfive\qr@fiveones% + \ifqr@stringoffive% + %This is a continuation of a previous block of five or more 1's. + \stepcounter{penaltyi}% + \else + %This is a new string of five 1's. + \addtocounter{penaltyi}{\qr@Ni}% + \global\qr@stringoffivetrue + \fi + \else + \ifx\qr@lastfive\qr@fivezeros% + \ifqr@stringoffive + %This is a continuation of a previous block of five or more 0's. + \stepcounter{penaltyi}% + \else + %This is a new string of five 0's. + \addtocounter{penaltyi}{\qr@Ni}% + \global\qr@stringoffivetrue + \fi + \else + %This is not a string of five 1's or five 0's. + \global\qr@stringoffivefalse + \fi + \fi + \fi + % + % HAPPILY, WE DON'T NEED TO CALCULATE PENALTY 2 AGAIN. + % + % LASTNINE CODE FOR PENALTY 3 + % First, add the new bit to the end. + \xa\g@addto@macro\xa\qr@lastnine\xa{\qr@newbit}% + \ifnum\i<7\relax% + %Not yet on the 7th entry. + %Don't do any testing. + \else + % 7th entry or later. + % Remove the old one, and then test. + \qr@removefirsttoken\qr@lastnine + \xa\ifnum\qr@size=\i\relax% + % Last column. Any of the following should count: + % 1011101 (\qr@finderB@zero) + % 10111010 (\qr@finderB@one) + % 101110100 (\qr@finderB@two) + % 1011101000 (\qr@finderB@three) + % 10111010000 (\qr@finderB) + \ifx\qr@lastnine\qr@finderB + \qr@addpenaltyiii + \else + \qr@removefirsttoken\qr@lastnine + \ifx\qr@lastnine\qr@finderB@three + \qr@addpenaltyiii + \else + \qr@removefirsttoken\qr@lastnine + \ifx\qr@lastnine\qr@finderB@two + \qr@addpenaltyiii + \else + \qr@removefirsttoken\qr@lastnine + \ifx\qr@lastnine\qr@finderB@one + \qr@addpenaltyiii + \else + \qr@removefirsttoken\qr@lastnine + \ifx\qr@lastnine\qr@finderB@zero + \qr@addpenaltyiii + \fi + \fi + \fi + \fi + \fi + \else + \ifx\qr@lastnine\qr@finderA% %Matches 0000 1011101 + \qr@addpenaltyiii + %Also, we record our discovery, so that we can't count this pattern again + %if it shows up four columns later as 1011101 0000. + % + %Set \qr@ignore@finderB@at to \i+4. + \qr@a=\i\relax% + \advance\qr@a by 4% + \xdef\qr@ignore@finderB@at{\the\qr@a}% + \else + \ifx\qr@lastfive\qr@finderB% %Matches 1011101 0000. + \xa\ifnum\qr@ignore@finderB@at=\i\relax + %This pattern was *not* counted already earlier. + \qr@addpenaltyiii + \fi + \fi + \fi + \fi + \fi + % + }% end of i-loop + }% end of j-loop + \egroup% + % + %CALCULATE PENALTY 4 + %According to the spec, penalty #4 is computed as + % floor( |(i/n^2)-0.5|/0.05 ) + % where i is the total number of 1's in the matrix. + % This is equal to abs(20*i-10n^2) div n^2. + % + \qr@a=\c@totalones\relax + \multiply\qr@a by 20\relax + \qr@b=\qr@size\relax + \multiply\qr@b by \qr@size\relax + \qr@c=10\relax + \multiply\qr@c by \qr@b\relax + \advance\qr@a by -\qr@c\relax + \ifnum\qr@a<0\relax + \multiply\qr@a by -1\relax + \fi + \divide\qr@a by \qr@b\relax + \setcounter{penaltyiv}{\the\qr@a}% + % + %CALCULATE TOTAL PENALTY + \qr@a=\thepenaltyi\relax% + \advance\qr@a by \thepenaltyii\relax% + \advance\qr@a by \thepenaltyiii\relax% + \advance\qr@a by \thepenaltyiv\relax% + \edef\qr@penalty{\the\qr@a}% +}% + +\def\qr@removefirsttoken#1{% + %Removes the first token from the macro named in #1. + \edef\qr@argument{(#1)}% + \xa\qr@removefirsttoken@int\qr@argument% + \xdef#1{\qr@removefirsttoken@result}% +}% +\def\qr@removefirsttoken@int(#1#2){% + \def\qr@removefirsttoken@result{#2}% +}% + +\def\qr@writeformatstring#1#2{% + % #1 = matrix name + % #2 = binary string representing the encoded and masked format information + \setcounter{qr@i}{9}% + \setcounter{qr@j}{1}% + \edef\qr@argument{{#1}(#2\relax)}% + \xa\qr@writeformatA@recursive\qr@argument + % + \setcounter{qr@i}{\qr@numberofrowsinmatrix{#1}}% + \setcounter{qr@j}{9}% + \xa\qr@writeformatB@recursive\qr@argument +}% + +\def\qr@writeformatA@recursive#1(#2#3){% + % #1 = matrix name + % #2 = first bit of string + % #3 = rest of bitstream + % (qr@i,qr@j) = current (valid) position to write (in LaTeX counters) + \ifnum#2=1\relax + \qr@storetomatrix{#1}{\theqr@i}{\theqr@j}{\qr@black@format}% + \else + \qr@storetomatrix{#1}{\theqr@i}{\theqr@j}{\qr@white@format}% + \fi + % Now the tricky part--moving \i and \j to their next positions. + \ifnum\c@qr@j<9\relax + %If we're not yet in column 9, move right. + \stepcounter{qr@j}% + \ifnum\c@qr@j=7\relax + %But we skip column 7! + \stepcounter{qr@j}% + \fi + \else + %If we're in column 9, we move up. + \addtocounter{qr@i}{-1}% + \ifnum\c@qr@i=7\relax + %But we skip row 7! + \addtocounter{qr@i}{-1}% + \fi + \fi + %N.B. that at the end of time, this will leave us at invalid position (0,9). + %That makes for an easy test to know when we are done. + \ifnum\c@qr@i<1 + \let\qr@next=\relax + \else + \def\qr@next{\qr@writeformatA@recursive{#1}(#3)}% + \fi + \qr@next +}% + +\def\qr@writeformatB@recursive#1(#2#3){% + % #1 = matrix name + % #2 = first bit of string + % #3 = rest of bitstream + % (qr@i,qr@j) = current (valid) position to write (in LaTeX counters) + \ifnum#2=1\relax + \qr@storetomatrix{#1}{\theqr@i}{\theqr@j}{\qr@black@format}% + \else + \qr@storetomatrix{#1}{\theqr@i}{\theqr@j}{\qr@white@format}% + \fi + % Now the tricky part--moving counters i and j to their next positions. + \qr@a=\qr@size% + \advance\qr@a by -6\relax% + \ifnum\qr@a<\c@qr@i\relax + %If we're not yet in row n-6, move up. + \addtocounter{qr@i}{-1}% + \else + \ifnum\qr@a=\c@qr@i\relax + %If we're actually in row n-6, we jump to position (9,n-7). + \setcounter{qr@i}{9}% + %Set counter j equal to \qr@size-7. + \global\c@qr@j=\qr@size\relax% + \global\advance\c@qr@j by -7\relax% + \else + %Otherwise, we must be in row 9. + %In this case, we move right. + \stepcounter{qr@j}% + \fi + \fi + %N.B. that at the end of time, this will leave us at invalid position (9,n+1). + %That makes for an easy test to know when we are done. + \xa\ifnum\qr@size<\c@qr@j\relax + \let\qr@next=\relax + \else + \def\qr@next{\qr@writeformatB@recursive{#1}(#3)}% + \fi + \qr@next +}% + +\def\qr@writeversionstring#1#2{% + % #1 = matrix name + % #2 = binary string representing the encoded version information + % + % Plot the encoded version string into the matrix. + % This is only done for versions 7 and higher. + \xa\ifnum\qr@version>6\relax + %Move to position (n-8,6). + \setcounter{qr@i}{\qr@size}\relax% + \addtocounter{qr@i}{-8}\relax% + \setcounter{qr@j}{6}% + \edef\qr@argument{{#1}(#2\relax)}% + \xa\qr@writeversion@recursive\qr@argument + \fi +}% + +\def\qr@writeversion@recursive#1(#2#3){% + % #1 = matrix name + % #2 = first bit of string + % #3 = rest of bitstream + % (qr@i,qr@j) = current (valid) position to write (in LaTeX counters) + % + % The version information is stored symmetrically in the matrix + % In two transposed regions, so we can write both at the same time. + % In the comments, we describe what happens in the lower-left region, + % not the upper-right. + % + %Set \qr@topline equal to n-10. + \qr@a=\qr@size\relax% + \advance\qr@a by -10\relax% + \edef\qr@topline{\the\qr@a}% + % + \ifnum#2=1\relax + \qr@storetomatrix{#1}{\theqr@i}{\theqr@j}{\qr@black@format}% + \qr@storetomatrix{#1}{\theqr@j}{\theqr@i}{\qr@black@format}% + \else + \qr@storetomatrix{#1}{\theqr@i}{\theqr@j}{\qr@white@format}% + \qr@storetomatrix{#1}{\theqr@j}{\theqr@i}{\qr@white@format}% + \fi + % Now the tricky part--moving counters i and j to their next positions. + \addtocounter{qr@i}{-1}% + \xa\ifnum\qr@topline>\c@qr@i\relax + %We've overshot the top of the region. + %We need to move left one column and down three. + \addtocounter{qr@j}{-1}% + \addtocounter{qr@i}{3}% + \fi + %N.B. that at the end of time, this will leave us at invalid position (n-8,0). + %That makes for an easy test to know when we are done. + \ifnum\c@qr@j<1\relax + \let\qr@next=\relax + \else + \def\qr@next{\qr@writeversion@recursive{#1}(#3)}% + \fi + \qr@next +}% +\newcounter{qr@hexchars}% + +\def\qr@string@binarytohex#1{% + \qr@binarytohex{\qr@hex@result}{#1}% +}% + +\def\qr@encode@binary#1{% + % #1 = string of ascii characters, to be converted into bitstream + % + % We do this one entirely in hex, rather than binary, because we can. + \edef\qr@plaintext{#1}% + % + %First, the mode indicator. + \def\qr@codetext{4}% %This means `binary' + % + %Next, the character count. + \qr@getstringlength{\qr@plaintext}% + %Set \qr@charactercountlengthinhex to \qr@charactercountbits@byte/4% + \qr@a=\qr@charactercountbits@byte\relax% + \divide \qr@a by 4\relax% + \edef\qr@charactercountlengthinhex{\the\qr@a}% + \qr@decimaltohex[\qr@charactercountlengthinhex]{\qr@charactercount}{\qr@stringlength}% + \xa\g@addto@macro\xa\qr@codetext\xa{\qr@charactercount}% + % + %Now comes the actual data. + \edef\qr@argument{(,\qr@plaintext\relax\relax\relax)}% + \xa\qr@encode@ascii@recursive\qr@argument% + % + %Now the terminator. + \g@addto@macro\qr@codetext{0}% %This is '0000' in binary. + % + %There is no need to pad bits to make a multiple of 8, + %because the data length is already 4 + 8 + 8n + 4. + % + %Now add padding codewords if needed. + \setcounter{qr@hexchars}{0}% + \qr@getstringlength{\qr@codetext}% + \setcounter{qr@hexchars}{\qr@stringlength}% + %Set \qr@numpaddingcodewords equal to \qr@totaldatacodewords - qr@hexchars/2. + \qr@a=-\c@qr@hexchars\relax + \divide\qr@a by 2\relax + \advance\qr@a by \qr@totaldatacodewords\relax + \edef\qr@numpaddingcodewords{\the\qr@a}% + % + \xa\ifnum\qr@numpaddingcodewords<0% + \edef\ds{ERROR: Too much data! Over by \qr@numpaddingcodewords bytes.}\show\ds% + \fi% + \xa\ifnum\qr@numpaddingcodewords>0% + \qr@for \i = 2 to \qr@numpaddingcodewords by 2% + {\g@addto@macro{\qr@codetext}{ec11}}% + \xa\ifodd\qr@numpaddingcodewords\relax% + \g@addto@macro{\qr@codetext}{ec}% + \fi% + \fi% +}% + +\def\qr@encode@ascii@recursive(#1,#2#3){% + % #1 = hex codes translated so far + % #2 = next plaintext character to translate + % #3 = remainder of plaintext + \edef\qr@testii{#2}% + \ifx\qr@testii\qr@relax% + % All done! + \g@addto@macro\qr@codetext{#1}% + \else% + % Another character to translate. + \edef\qr@asciicode{\number`#2}% + \qr@decimaltohex[2]{\qr@newhexcodes}{\qr@asciicode}% + \edef\qr@argument{(#1\qr@newhexcodes,#3)}% + %\show\qr@argument + \xa\qr@encode@ascii@recursive\qr@argument% + \fi% +}% + +\def\qr@splitcodetextintoblocks{% + \setcounter{qr@i}{0}% + \qr@for \j = 1 to \qr@numshortblocks by 1% + {\stepcounter{qr@i}% + \qr@splitoffblock{\qr@codetext}{\theqr@i}{\qr@shortblock@size}% + }% + \xa\ifnum\qr@numlongblocks>0\relax% + \qr@for \j = 1 to \qr@numlongblocks by 1% + {\stepcounter{qr@i}% + \qr@splitoffblock{\qr@codetext}{\theqr@i}{\qr@longblock@size}% + }% + \fi% +}% + +\def\qr@splitoffblock#1#2#3{% + % #1 = current codetext in hexadecimal + % #2 = number to use in csname "\datablock@#2". + % #3 = number of bytes to split off + \message{}% + \xa\gdef\csname datablock@#2\endcsname{}% %This line is important! + \qr@for \i = 1 to #3 by 1% + {\edef\qr@argument{{#2}(#1)}% + \xa\qr@splitoffblock@int\qr@argument% + }% +}% + +\def\qr@splitoffblock@int#1(#2#3#4){% + % #1 = number to use in csname "\datablock@#1". + % #2#3 = next byte to split off + % #4 = remaining text + % + % We add the next byte to "\datablock@#1", + % and we remove it from the codetext. + \xa\xdef\csname datablock@#1\endcsname{\csname datablock@#1\endcsname#2#3}% + \xdef\qr@codetext{#4}% +}% + +\def\qr@createerrorblocks{% + \qr@for \ii = 1 to \qr@numblocks by 1% + {\message{}% + \FX@generate@errorbytes{\csname datablock@\the\ii\endcsname}{\qr@num@eccodewords}% + \xa\xdef\csname errorblock@\the\ii\endcsname{\FX@errorbytes}% + }% +}% + +\def\qr@interleave{% + \setcounter{qr@i}{0}% + \def\qr@interleaved@text{}% + \message{0\relax% + \message{\qr@longblock@size.>}% + \else + \message{.>}% + \fi + \message{}% +}% + +\def\qr@writefromblock#1#2{% + % #1 = either 'datablock' or 'errorblock' + % #2 = block number, in {1,...,\qr@numblocks}% + \edef\qr@argument{(\csname #1@#2\endcsname\relax\relax\relax)}% + \xa\qr@writefromblock@int\qr@argument + \xa\xdef\csname #1@#2\endcsname{\qr@writefromblock@remainder}% +}% + +\def\qr@writefromblock@int(#1#2#3){% + % #1#2 = first byte (in hex) of text, which will be written to \qr@interleaved@text + % #3 = remainder, including \relax\relax\relax terminator. + \g@addto@macro{\qr@interleaved@text}{#1#2}% + \qr@writefromblock@intint(#3)% +}% + +\def\qr@writefromblock@intint(#1\relax\relax\relax){% + \xdef\qr@writefromblock@remainder{#1}% +}% +\let\xa=\expandafter +\makeatletter + +\def\qr@preface@macro#1#2{% + % #1 = macro name + % #2 = text to add to front of macro + \def\qr@tempb{#2}% + \xa\xa\xa\gdef\xa\xa\xa#1\xa\xa\xa{\xa\qr@tempb #1}% +}% + +\newif\ifqr@leadingcoeff +\def\qr@testleadingcoeff(#1#2){% + % Tests whether the leading digit of #1#2 is 1. + \ifnum#1=1\relax + \qr@leadingcoefftrue + \else + \qr@leadingcoefffalse + \fi +}% + +\def\qr@polynomialdivide#1#2{% + \edef\qr@numerator{#1}% + \edef\qr@denominator{#2}% + \qr@divisiondonefalse% + \xa\xa\xa\qr@oneroundofdivision\xa\xa\xa{\xa\qr@numerator\xa}\xa{\qr@denominator}% +}% + +\def\@qr@empty{}% +\def\qr@oneroundofdivision#1#2{% + % #1 = f(x), of degree n + % #2 = g(x), of degree m + % Obtains a new polynomial h(x), congruent to f(x) modulo g(x), + % but of degree at most n-1. + % + % If leading coefficient of f(x) is 1, subtracts off g(x) * x^(n-m). + % If leading coefficient of f(x) is 0, strips off that leading zero. + % + \qr@testleadingcoeff(#1)% + \ifqr@leadingcoeff + \qr@xorbitstrings{#1}{#2}% + \ifqr@xorfailed + %If xor failed, that means our #1 was already the remainder! + \qr@divisiondonetrue + \edef\qr@theremainder{#1}% + \else + %xor succeeded. We need to recurse. + \xa\xa\xa\edef\xa\xa\xa\qr@numerator\xa\xa\xa{\xa\qr@stripleadingzero\xa(\qr@xorresult)}% + \fi + \else + \xa\def\xa\qr@numerator\xa{\qr@stripleadingzero(#1)}% + \ifx\qr@numerator\@qr@empty + \qr@divisiondonetrue + \def\qr@theremainder{0}% + \fi + \fi + \ifqr@divisiondone + \relax + \else + \xa\qr@oneroundofdivision\xa{\qr@numerator}{#2}% + \fi +}% + +\def\qr@stripleadingzero(0#1){#1}%Strips off a leading zero. + +\newif\ifqr@xorfailed% This flag will trigger when #2 is longer than #1. + +\def\qr@xorbitstrings#1#2{% + % #1 = bitstring + % #2 = bitstring no longer than #1 + \qr@xorfailedfalse + \edef\qr@argument{(,#1\relax\relax)(#2\relax\relax)}% + \xa\qr@xorbitstrings@recursive\qr@argument + %\qr@xorbitstrings@recursive(,#1\relax\relax)(#2\relax\relax)% +}% + +\def\qr@xorbitstrings@recursive(#1,#2#3)(#4#5){% + % #1#2#3 is the first bitstring, xor'ed up through #1. + % #4#5 is the remaining portion of the second bitstring. + \def\qr@testii{#2}% + \def\qr@testiv{#4}% + \ifx\qr@testii\qr@relax + % #1 contains the whole string. + % Now if #4 is also \relax, that means the two strings started off with equal lengths. + % If, however, #4 is not \relax, that means the second string was longer than the first, a problem. + \ifx\qr@testiv\qr@relax + %No problem. We are done. + \qr@xorbit@saveresult(#1#2#3)% + \else + %Problem! The second string was longer than the first. + \qr@xorfailedtrue + \def\qr@xorresult{}% + \fi + \else + % There is still a bit to manipulate in #2. + % Check whether #4 contains anything. + \ifx\qr@testiv\qr@relax + % No, #4 is empty. We are done. "#2#3" contains the remainder of the first string, + % which we append untouched and then strip off the two \relax-es. + \qr@xorbit@saveresult(#1#2#3)% + \else + % Yes, #4 still has something to XOR. Do the task. + \ifnum#2=#4\relax + \qr@xorbitstrings@recursive(#1% + 0,#3)(#5)% + \else + \qr@xorbitstrings@recursive(#1% + 1,#3)(#5)% + \fi + \fi + \fi +}% + +\def\qr@xorbit@saveresult(#1\relax\relax){% + %Strips off the extra '\relax'es at the end. + \def\qr@xorresult{#1}% +}% + +\newif\ifqr@divisiondone + +\def\qr@BCHcode#1{% + \edef\qr@formatinfo{#1}% + \def\qr@formatinfopadded{\qr@formatinfo 0000000000}% + \def\qr@divisor{10100110111}% + \qr@divisiondonefalse + \qr@polynomialdivide{\qr@formatinfopadded}{\qr@divisor}% + % + \qr@getstringlength{\qr@theremainder}% + %Run loop from stringlength+1 to 10. + \qr@a=\qr@stringlength\relax% + \advance\qr@a by 1\relax% + \qr@for \i = \qr@a to 10 by 1% + {\qr@preface@macro{\qr@theremainder}{0}% + \xdef\qr@theremainder{\qr@theremainder}% + }% + \edef\qr@BCHresult{\qr@formatinfo\qr@theremainder}% +}% + +\def\qr@formatmask{101010000010010}% + +\def\qr@encodeandmaskformat#1{% + \qr@BCHcode{#1}% + \qr@xorbitstrings{\qr@BCHresult}{\qr@formatmask}% + \edef\qr@format@bitstring{\qr@xorresult}% +}% + +\def\qr@Golaycode#1{% + % #1 = 6-bit version number + \edef\qr@versioninfo{#1}% + \def\qr@versioninfopadded{\qr@versioninfo 000000000000}% %Append 12 zeros. + \def\qr@divisor{1111100100101}% + \qr@divisiondonefalse + \qr@polynomialdivide{\qr@versioninfopadded}{\qr@divisor}% + % + \qr@getstringlength{\qr@theremainder}% + %Run loop from stringlength+1 to 12. + \qr@a=\qr@stringlength\relax% + \advance\qr@a by 1\relax% + \qr@for \i = \qr@a to 12 by 1% + {\qr@preface@macro{\qr@theremainder}{0}% + \xdef\qr@theremainder{\qr@theremainder}% + }% + \edef\qr@Golayresult{\qr@versioninfo\qr@theremainder}% +}% +\def\F@result{}% + +\def\qr@xorbitstring#1#2#3{% + % #1 = new macro to receive result + % #2, #3 = bitstrings to xor. The second can be shorter than the first. + \def\qr@xor@result{}% + \edef\qr@argument{(#2\relax\relax)(#3\relax\relax)}% + \xa\qr@xorbitstring@recursive\qr@argument% + \edef#1{\qr@xor@result}% +}% +\def\qr@xorbitstring@recursive(#1#2)(#3#4){% + \edef\qr@testi{#1}% + \ifx\qr@testi\qr@relax% + %Done. + \let\qr@next=\relax% + \else + \if#1#3\relax + \g@addto@macro{\qr@xor@result}{0}% + \else + \g@addto@macro{\qr@xor@result}{1}% + \fi + \edef\qr@next{\noexpand\qr@xorbitstring@recursive(#2)(#4)}% + \fi + \qr@next +} + +\def\F@addchar@raw#1#2{% + %Add two hexadecimal digits using bitwise xor + \qr@hextobinary[4]{\qr@summandA}{#1}% + \qr@hextobinary[4]{\qr@summandB}{#2}% + \qr@xorbitstring{\F@result}{\qr@summandA}{\qr@summandB}% + \qr@binarytohex[1]{\F@result}{\F@result}% +}% + +\def\qr@canceltwos#1{% + \edef\qr@argument{(#1\relax\relax)}% + \xa\qr@canceltwos@int\qr@argument% +}% + +\def\qr@canceltwos@int(#1#2){% + \xa\qr@canceltwos@recursion(,#1#2)% +}% + +\def\qr@canceltwos@recursion(#1,#2#3){% + \def\qr@testii{#2}% + \ifx\qr@testii\qr@relax + %Cancelling complete. + \qr@striptworelaxes(#1#2#3)% + %Now \F@result contains the answer. + \else + \relax + \ifnum#2=2\relax + \qr@canceltwos@recursion(#10,#3)% + \else + \qr@canceltwos@recursion(#1#2,#3)% + \fi + \fi +}% + +\def\qr@striptworelaxes(#1\relax\relax){% + \gdef\F@result{#1}% +}% + +\qr@for \i = 0 to 15 by 1% + {\qr@decimaltohex[1]{\qr@tempa}{\the\i}% + \qr@for \j = 0 to 15 by 1% + {\qr@decimaltohex[1]{\qr@tempb}{\the\j}% + \F@addchar@raw\qr@tempa\qr@tempb + \xa\xdef\csname F@addchar@\qr@tempa\qr@tempb\endcsname{\F@result}% + }% + }% + +\def\F@addchar#1#2{% + \xa\def\xa\F@result\xa{\csname F@addchar@#1#2\endcsname}% +}% + +\def\F@addstrings#1#2{% + \edef\qr@argument{(,#1\relax\relax)(#2\relax\relax)}% + \xa\F@addstrings@recursion\qr@argument% +}% + +\def\F@addstrings@recursion(#1,#2#3)(#4#5){% + %Adds two hexadecimal strings, bitwise, from left to right. + %The second string is allowed to be shorter than the first. + \def\qr@testii{#2}% + \def\qr@testiv{#4}% + \ifx\qr@testii\qr@relax + %The entire string has been processed. + \gdef\F@result{#1}% + \else + \ifx\qr@testiv\qr@relax + %The second string is over. + \qr@striptworelaxes(#1#2#3)% + %Now \F@result contains the answer. + \else + %We continue to add. + \F@addchar{#2}{#4}% + \edef\qr@argument{(#1\F@result,#3)(#5)}% + \xa\F@addstrings@recursion\qr@argument% + \fi + \fi +}% +\gdef\F@stripleadingzero(0#1){\edef\F@result{#1}}% + +\setcounter{qr@i}{0}% +\def\qr@poweroftwo{1}% +\qr@for \i = 1 to 254 by 1% + {\stepcounter{qr@i}% + \qr@a=\qr@poweroftwo\relax + \multiply\qr@a by 2\relax + \edef\qr@poweroftwo{\the\qr@a}% + %\show\qr@poweroftwo + \qr@decimaltohex[2]{\qr@poweroftwo@hex}{\qr@poweroftwo}% + \xa\ifnum\qr@poweroftwo>255\relax + %We need to bitwise add the polynomial represented by 100011101, i.e. 0x11d. + \F@addstrings{\qr@poweroftwo@hex}{11d}% %Now it should start with 0. + \xa\F@stripleadingzero\xa(\F@result)% %Now it should be two hex digits. + \edef\qr@poweroftwo@hex{\F@result}% %Save the hex version. + \qr@hextodecimal{\qr@poweroftwo}{\F@result}% + \fi + \xdef\qr@poweroftwo{\qr@poweroftwo}% + \xa\xdef\csname F@twotothe@\theqr@i\endcsname{\qr@poweroftwo@hex}% + \xa\xdef\csname F@logtwo@\qr@poweroftwo@hex\endcsname{\theqr@i}% + }% +\xa\xdef\csname F@twotothe@0\endcsname{01}% +\xa\xdef\csname F@logtwo@01\endcsname{0}% + +\def\F@twotothe#1{% + \xa\xdef\xa\F@result\xa{\csname F@twotothe@#1\endcsname}% +}% +\def\F@logtwo#1{% + \xa\xdef\xa\F@result\xa{\csname F@logtwo@#1\endcsname}% +}% + +\def\qr@zerozero{00}% + +\def\F@multiply#1#2{% + % #1 and #2 are two elements of F_256, + % given as two-character hexadecimal strings. + % Multiply them within F_256, and place the answer in \F@result + \edef\qr@argA{#1}% + \edef\qr@argB{#2}% + \ifx\qr@argA\qr@zerozero + \def\F@result{00}% + \else + \ifx\qr@argB\qr@zerozero + \def\F@result{00}% + \else + \xa\F@logtwo\xa{\qr@argA}% + \edef\qr@logA{\F@result}% + \xa\F@logtwo\xa{\qr@argB}% + \edef\qr@logB{\F@result}% + \xa\qr@a\xa=\qr@logA\relax% \qr@a = \qr@logA + \xa\advance\xa\qr@a\qr@logB\relax% \advance \qr@a by \qr@logB + \ifnum\qr@a>254\relax% + \advance\qr@a by -255\relax% + \fi% + \xa\F@twotothe\xa{\the\qr@a}% + % Now \F@result contains the product, as desired. + \fi + \fi +}% + +\def\F@multiply#1#2{% + % #1 and #2 are two elements of F_256, + % given as two-character hexadecimal strings. + % Multiply them within F_256, and place the answer in \F@result + \edef\qr@argA{#1}% + \edef\qr@argB{#2}% + \ifx\qr@argA\qr@zerozero + \def\F@result{00}% + \else + \ifx\qr@argB\qr@zerozero + \def\F@result{00}% + \else + \xa\F@logtwo\xa{\qr@argA}% + \edef\qr@logA{\F@result}% + \xa\F@logtwo\xa{\qr@argB}% + \edef\qr@logB{\F@result}% + \xa\qr@a\xa=\qr@logA\relax% \qr@a = \qr@logA + \xa\advance\xa\qr@a\qr@logB\relax% \advance \qr@a by \qr@logB + \ifnum\qr@a>254\relax% + \advance\qr@a by -255\relax% + \fi% + \xa\F@twotothe\xa{\the\qr@a}% + % Now \F@result contains the product, as desired. + \fi + \fi +}% + +\def\FX@getstringlength#1{% + %Count number of two-character coefficients + \setcounter{qr@i}{0}% + \xdef\qr@argument{(#1\relax\relax\relax)}% + \xa\FX@stringlength@recursive\qr@argument% + \xdef\stringresult{\arabic{qr@i}}% +}% + +\def\FX@stringlength@recursive(#1#2#3){% + \def\qr@testi{#1}% + \ifx\qr@testi\qr@relax + %we are done. + \else + \stepcounter{qr@i}% + %\showthe\c@qr@i + \qr@stringlength@recursive(#3)% + \fi +}% + +\newif\ifFX@leadingcoeff@zero +\def\FX@testleadingcoeff(#1#2#3){% + % Tests whether the leading coefficient of the hex-string #1#2#3 is '00'. + \edef\FX@leadingcoefficient{#1#2}% + \FX@leadingcoeff@zerofalse + \ifx\FX@leadingcoefficient\qr@zerozero + \FX@leadingcoeff@zerotrue + \fi +}% + +\newif\ifFX@divisiondone + +\newcounter{qr@divisionsremaining} %Keep track of how many divisions to go! +\def\FX@polynomialdivide#1#2{% + \edef\FX@numerator{#1}% + \edef\FX@denominator{#2}% + \qr@getstringlength\FX@numerator% + \setcounter{qr@divisionsremaining}{\qr@stringlength}% + \qr@getstringlength\FX@denominator% + \addtocounter{qr@divisionsremaining}{-\qr@stringlength}% + \addtocounter{qr@divisionsremaining}{2}% + \divide\c@qr@divisionsremaining by 2\relax% %2 hex chars per number + \FX@divisiondonefalse% + \xa\xa\xa\FX@polynomialdivide@recursive\xa\xa\xa{\xa\FX@numerator\xa}\xa{\FX@denominator}% +}% + +\def\FX@polynomialdivide@recursive#1#2{% + % #1 = f(x), of degree n + % #2 = g(x), of degree m + % Obtains a new polynomial h(x), congruent to f(x) modulo g(x), + % but of degree at most n-1. + % + % If leading coefficient of f(x) is 0, strips off that leading zero. + % If leading coefficient of f(x) is a, subtracts off a * g(x) * x^(n-m). + % N.B. we assume g is monic. + % + \FX@testleadingcoeff(#1)% + \ifFX@leadingcoeff@zero% + %Leading coefficient is zero, so remove it. + \xa\def\xa\FX@numerator\xa{\FX@stripleadingzero(#1)}% + \else% + %Leading coefficient is nonzero, and contained in \FX@leadingcoefficient + \FX@subtractphase{#1}{#2}{\FX@leadingcoefficient}% + \ifFX@subtract@failed% + %If subtraction failed, that means our #1 was already the remainder! + \FX@divisiondonetrue% + \edef\qr@theremainder{#1}% + \else% + %xor succeeded. We need to recurse. + \xa\xa\xa\edef\xa\xa\xa\FX@numerator\xa\xa\xa{\xa\FX@stripleadingzero\xa(\FX@subtraction@result)}% + \fi% + \fi% + \addtocounter{qr@divisionsremaining}{-1}% + \ifnum\c@qr@divisionsremaining=0\relax + %Division is done! + \FX@divisiondonetrue% + \edef\qr@theremainder{\FX@numerator}% + \relax% + \else% + \xa\FX@polynomialdivide@recursive\xa{\FX@numerator}{#2}% + \fi% +}% + +\def\FX@stripleadingzero(00#1){#1}%Strips off a single leading zero of F_256. + +\newif\ifFX@subtract@failed% This flag will trigger when #2 is longer than #1. + +\def\FX@subtractphase#1#2#3{% + % #1 = bitstring + % #2 = bitstring no longer than #1 + % #3 = leading coefficient + \FX@subtract@failedfalse% + \edef\qr@argument{(,#1\relax\relax\relax)(#2\relax\relax\relax)(#3)}% + \xa\FX@subtract@recursive\qr@argument% +}% + +\def\FX@subtract@recursive(#1,#2#3#4)(#5#6#7)(#8){% + % This is a recursive way to compute f(x) - a*g(x)*x^k. + % #1#2#3#4 is the first bitstring, subtracted up through #1. + % Thus #2#3 constitutes the next two-character coefficient. + % #5#6#7 is the remaining portion of the second bitstring. + % Thus #5#6 constitutes the next two-character coefficient + % #8 is the element a of F_256. It should contain two characters. + \def\qr@testii{#2}% + \def\qr@testv{#5}% + \ifx\qr@testii\qr@relax + % #1 contains the whole string. + % Now if #5 is also \relax, that means the two strings started off with equal lengths. + % If, however, #5 is not \relax, that means the second string was longer than the first, a problem. + \ifx\qr@testv\qr@relax + %No problem. We are done. + \FX@subtract@saveresult(#1#2#3#4)% %We keep the #2#3#4 to be sure we have all three relax-es to strip off. + \else + %Problem! The second string was longer than the first. + %This usually indicates the end of the long division process. + \FX@subtract@failedtrue + \def\FX@subtraction@result{}% + \fi + \else + % There is still a coefficient to manipulate in #2#3. + % Check whether #5 contains anything. + \ifx\qr@testv\qr@relax + % No, #5 is empty. We are done. "#2#3#4" contains the remainder of the first string, + % which we append untouched and then strip off the three \relax-es. + \FX@subtract@saveresult(#1#2#3#4)% + \else + % Yes, #5#6 still has something to XOR. Do the task. + \F@multiply{#5#6}{#8}% Multiply by the factor 'a'. + \F@addstrings{#2#3}{\F@result}% Subtract. (We're in characteristic two, so adding works.) + \edef\qr@argument{(#1\F@result,#4)(#7)(#8)}% + \xa\FX@subtract@recursive\qr@argument% + \fi + \fi +}% + +\def\FX@subtract@saveresult(#1\relax\relax\relax){% + %Strips off the three extra '\relax'es at the end. + \def\FX@subtraction@result{#1}% +}% + +\def\FX@creategeneratorpolynomial#1{% + % #1 = n, the number of error codewords desired. + % We need to create \prod_{j=0}^{n-1} (x-2^j). + \edef\FX@generator@degree{#1}% + \def\FX@generatorpolynomial{01}% Initially, set it equal to 1. + \setcounter{qr@i}{0}% + \FX@creategenerator@recursive% + %The result is now stored in \FX@generatorpolynomial +}% + +\def\FX@creategenerator@recursive{% + % \c@qr@i contains the current value of i. + % \FX@generatorpolynomial contains the current polynomial f(x), + % which should be a degree-i polynomial + % equal to \prod_{j=0}^{i-1} (x-2^j). + % (If i=0, then \FX@generatorpolynomial should be 01.) + % This recursion step should multiply the existing polynomial by (x-2^i), + % increment i by 1, and check whether we're done or not. + \edef\qr@summandA{\FX@generatorpolynomial 00}% This is f(x) * x + \edef\qr@summandB{00\FX@generatorpolynomial}% This is f(x), with a 0x^{i+1} in front. + \F@twotothe{\theqr@i}% + \edef\qr@theconstant{\F@result}% + \FX@subtractphase{\qr@summandA}{\qr@summandB}{\qr@theconstant}% + %This calculates \qr@summandA + \qr@theconstant * \qr@summandB + %and stores the result in \FX@subtraction@result + \edef\FX@generatorpolynomial{\FX@subtraction@result}% + \stepcounter{qr@i}% + \xa\ifnum\FX@generator@degree=\c@qr@i\relax% + %We just multiplied by (x-2^{n-1}), so we're done. + \relax% + \else% + %We need to do this again! + \xa% + \FX@creategenerator@recursive% + \fi% +}% + +\def\FX@generate@errorbytes#1#2{% + % #1 = datastream in hex + % #2 = number of error correction bytes requested + \edef\qr@numerrorbytes{#2}% + \xa\FX@creategeneratorpolynomial\xa{\qr@numerrorbytes}% + \edef\FX@numerator{#1}% + \qr@for \i = 1 to \qr@numerrorbytes by 1% + {\g@addto@macro\FX@numerator{00}}% %One error byte means two hex codes. + \FX@polynomialdivide{\FX@numerator}{\FX@generatorpolynomial}% + \edef\FX@errorbytes{\qr@theremainder}% +}% +\newif\ifqr@versionmodules + +\def\qr@level@char#1{% + \xa\ifcase#1 + M\or L\or H\or Q\fi}% + +\newif\ifqr@versiongoodenough +\def\qr@choose@best@version#1{% + % \qr@desiredversion = user-requested version + % \qr@desiredlevel = user-requested error-correction level + \edef\qr@plaintext{#1}% + \qr@getstringlength{\qr@plaintext}% + % + %Run double loop over levels and versions, looking for + %the smallest version that can contain our data, + %and then choosing the best error-correcting level at that version, + %subject to the level being at least as good as the user desires. + \global\qr@versiongoodenoughfalse% + \gdef\qr@bestversion{0}% + \gdef\qr@bestlevel{0}% + \ifnum\qr@desiredversion=0\relax + \qr@a=1\relax + \else + \qr@a=\qr@desiredversion\relax + \fi + \qr@for \i=\qr@a to 40 by 1 + {\edef\qr@version{\the\i}% + \global\qr@versiongoodenoughfalse + \qr@for \j=0 to 3 by 1% + {%First, we map {0,1,2,3} to {1,0,4,3}, so that we loop through {M,L,H,Q} + %in order of increasing error-correction capabilities. + \qr@a = \j\relax + \divide \qr@a by 2\relax + \multiply \qr@a by 4\relax + \advance \qr@a by 1\relax + \advance \qr@a by -\j\relax + \edef\qr@level{\the\qr@a}% + \ifnum\qr@desiredlevel=\qr@a\relax + \global\qr@versiongoodenoughtrue + \fi + \ifqr@versiongoodenough + \qr@calculate@capacity{\qr@version}{\qr@level}% + \xa\xa\xa\ifnum\xa\qr@truecapacity\xa<\qr@stringlength\relax + %Too short + \relax + \else + %Long enough! + \xdef\qr@bestversion{\qr@version}% + \xdef\qr@bestlevel{\qr@level}% + \global\i=40% + \fi + \fi + }% + }% + \edef\qr@version{\qr@bestversion}% + \edef\qr@level{\qr@bestlevel}% + \xa\ifnum\qr@desiredversion>0\relax + \ifx\qr@bestversion\qr@desiredversion\relax + %No change from desired version. + \else + %Version was increased + \message{^^J}% + \fi + \fi + \ifx\qr@bestlevel\qr@desiredlevel\relax + %No change in level. + \else + \message{^^J}% + \fi +}% + +\def\qr@calculate@capacity#1#2{% + \edef\qr@version{#1}% + \edef\qr@level{#2}% + %Calculate \qr@size, the number of modules per side. + % The formula is 4\qr@version+17. + \qr@a=\qr@version\relax% + \multiply\qr@a by 4\relax% + \advance\qr@a by 17\relax% + \edef\qr@size{\the\qr@a}% + % + % Calculate \qr@k, which governs the number of alignment patterns. + % The alignment patterns lie in a kxk square, except for 3 that are replaced by finding patterns. + % The formula is 2 + floor( \qr@version / 7 ), except that k=0 for version 1. + \xa\ifnum\qr@version=1\relax% + \def\qr@k{0}% + \else% + \qr@a=\qr@version\relax + \divide \qr@a by 7\relax + \advance\qr@a by 2\relax + \edef\qr@k{\the\qr@a}% + \fi% + % + %Calculate number of function pattern modules. + %This consists of the three 8x8 finder patterns, the two timing strips, and the (k^2-3) 5x5 alignment patterns. + %The formula is 160+2n+25(k^2-3)-10(k-2), unless k=0 in which case we just have 160+2n. + \qr@a=\qr@size\relax + \multiply\qr@a by 2\relax + \advance\qr@a by 160\relax + \xa\ifnum\qr@k=0\relax\else + %\qr@k is nonzero, hence at least 2, so we continue to add 25(k^2-3)-10(k-2). + \qr@b=\qr@k\relax + \multiply\qr@b by \qr@k\relax + \advance\qr@b by -3\relax + \multiply\qr@b by 25\relax + \advance\qr@a by \qr@b\relax + \qr@b=\qr@k\relax + \advance\qr@b by -2\relax + \multiply\qr@b by 10\relax + \advance\qr@a by -\qr@b\relax + \fi + \edef\qr@numfunctionpatternmodules{\the\qr@a}% + % + %Calculate the number of version modules, either 36 or 0. + \xa\ifnum\qr@version>6\relax + \qr@versionmodulestrue + \def\qr@numversionmodules{36}% + \else + \qr@versionmodulesfalse + \def\qr@numversionmodules{0}% + \fi + % + %Now calculate the codeword capacity and remainder bits. + %Take n^2 modules, subtract all those dedicated to finder patterns etc., format information, and version information, + %and what's left is the number of bits we can play with. + %The number of complete bytes is \qr@numdatacodewords; + %the leftover bits are \qr@numremainderbits. + \qr@a=\qr@size\relax + \multiply \qr@a by \qr@size\relax + \advance \qr@a by -\qr@numfunctionpatternmodules\relax + \advance \qr@a by -31\relax% % There are 31 format modules. + \advance \qr@a by -\qr@numversionmodules\relax + \qr@b=\qr@a\relax + \divide \qr@a by 8\relax + \edef\qr@numdatacodewords{\the\qr@a}% + \multiply\qr@a by 8\relax + \advance \qr@b by -\qr@a\relax + \edef\qr@numremainderbits{\the\qr@b}% + % + %The size of the character count indicator also varies by version. + %There are only two options, so hardcoding seems easier than expressing these functionally. + \xa\ifnum\qr@version<10\relax + \def\qr@charactercountbytes@byte{1}% + \def\qr@charactercountbits@byte{8}% + \else + \def\qr@charactercountbytes@byte{2}% + \def\qr@charactercountbits@byte{16}% + \fi + % + %Now we call on the table, from the QR specification, + %of how many blocks to divide the message into, and how many error bytes each block gets. + %This affects the true capacity for data, which we store into \qr@totaldatacodewords. + % The following macro sets \qr@numblocks and \qr@num@eccodewords + % based on Table 9 of the QR specification. + \qr@settableix + \qr@a = -\qr@numblocks\relax + \multiply \qr@a by \qr@num@eccodewords\relax + \advance\qr@a by \qr@numdatacodewords\relax + \edef\qr@totaldatacodewords{\the\qr@a}% + \advance\qr@a by -\qr@charactercountbytes@byte\relax%Subtract character count + \advance\qr@a by -1\relax% Subtract 1 byte for the 4-bit mode indicator and the 4-bit terminator at the end. + \edef\qr@truecapacity{\the\qr@a}% +} + +\def\qr@setversion#1#2{% + % #1 = version number, an integer between 1 and 40 inclusive. + % #2 = error-correction level, as an integer between 0 and 3 inclusive. + % 0 = 00 = M + % 1 = 01 = L + % 2 = 10 = H + % 3 = 11 = Q + % This macro calculates and sets a variety of global macros and/or counters + % storing version information that is used later in construction the QR code. + % Thus \qr@setversion should be called every time! + % + \edef\qr@version{#1}% + \edef\qr@level{#2}% + % + \qr@calculate@capacity{\qr@version}{\qr@level}% + %The capacity-check code sets the following: + % * \qr@size + % * \qr@k + % * \ifqr@versionmodules + % * \qr@numversionmodules + % * \qr@numdatacodewords + % * \qr@numremainderbits + % * \qr@charactercountbits@byte + % * \qr@charactercountbytes@byte + % * \qr@numblocks (via \qr@settableix) + % * \qr@num@eccodewords (via \qr@settableix) + % * \qr@totaldatacodewords + % + % The alignment patterns' square is 7 modules in from each edge. + % They are spaced "as evenly as possible" with an even number of modules between each row/column, + % unevenness in division being accommodated by making the first such gap smaller. + % The formula seems to be + % general distance = 2*round((n-13)/(k-1)/2+0.25) + % = 2*floor((n-13)/(k-1)/2+0.75) + % = 2*floor( (2*(n-13)/(k-1)+3) / 4 ) + % = (((2*(n-13)) div (k-1) + 3 ) div 4 ) * 2 + % first distance = leftovers + % The 0.25 is to accommodate version 32, which is the only time we round down. + % Otherwise a simple 2*ceiling((n-13)/(k-1)/2) would have sufficed. + % + \qr@a = \qr@size\relax + \advance\qr@a by -13\relax + \multiply\qr@a by 2\relax + \qr@b = \qr@k\relax + \advance \qr@b by -1\relax + \divide\qr@a by \qr@b\relax + \advance\qr@a by 3\relax + \divide\qr@a by 4\relax + \multiply\qr@a by 2\relax + \edef\qr@alignment@generalskip{\the\qr@a}% + % + %Now set \qr@alignment@firstskip to (\qr@size-13)-(\qr@k-2)*\qr@alignment@generalskip % + \qr@a = \qr@k\relax + \advance\qr@a by -2\relax + \multiply\qr@a by -\qr@alignment@generalskip\relax + \advance\qr@a by \qr@size\relax + \advance\qr@a by -13\relax + \edef\qr@alignment@firstskip{\the\qr@a}% + % + % + % + % Our \qr@totaldatacodewords bytes of data are broken up as evenly as possible + % into \qr@numblocks datablocks; some may be one byte longer than others. + % We set \qr@shortblock@size to floor(\qr@totaldatacodewords / \qr@numblocks) + % and \qr@numlongblocks to mod(\qr@totaldatacodewords , \qr@numblocks). + \qr@a=\qr@totaldatacodewords\relax + \divide\qr@a by \qr@numblocks\relax + \edef\qr@shortblock@size{\the\qr@a}% + \multiply\qr@a by -\qr@numblocks\relax + \advance\qr@a by \qr@totaldatacodewords\relax + \edef\qr@numlongblocks{\the\qr@a}% + % + %Set \qr@longblock@size to \qr@shortblock@size+1. + \qr@a=\qr@shortblock@size\relax + \advance\qr@a by 1\relax + \edef\qr@longblock@size{\the\qr@a}% + % + %Set \qr@numshortblocks to \qr@numblocks - \qr@numlongblocks + \qr@b=\qr@numblocks\relax + \advance\qr@b by -\qr@numlongblocks\relax + \edef\qr@numshortblocks{\the\qr@b}% +}% + +\def\qr@settableix@int(#1,#2){% + \edef\qr@numblocks{#1}% + \edef\qr@num@eccodewords{#2}% +}% + +\def\qr@settableix{% +\xa\ifcase\qr@level\relax + %00: Level 'M', medium error correction + \edef\qr@tempdata{(% + \ifcase\qr@version\relax + \relax %There is no version 0. + \or1,10% + \or1,16% + \or1,26% + \or2,18% + \or2,24% + \or4,16% + \or4,18% + \or4,22% + \or5,22% + \or5,26% + \or5,30% + \or8,22% + \or9,22% + \or9,24% + \or10,24% + \or10,28% + \or11,28% + \or13,26% + \or14,26% + \or16,26% + \or17,26% + \or17,28% + \or18,28% + \or20,28% + \or21,28% + \or23,28% + \or25,28% + \or26,28% + \or28,28% + \or29,28% + \or31,28% + \or33,28% + \or35,28% + \or37,28% + \or38,28% + \or40,28% + \or43,28% + \or45,28% + \or47,28% + \or49,28% + \fi)}% +\or + %01: Level 'L', low error correction + \edef\qr@tempdata{% + (\ifcase\qr@version\relax + \relax %There is no version 0. + \or 1,7% + \or 1,10% + \or 1,15% + \or 1,20% + \or 1,26% + \or 2,18% + \or 2,20% + \or 2,24% + \or 2,30% + \or 4,18% + \or 4,20% + \or 4,24% + \or 4,26% + \or 4,30% + \or 6,22% + \or 6,24% + \or 6,28% + \or 6,30% + \or 7,28% + \or 8,28% + \or 8,28% + \or 9,28% + \or 9,30% + \or 10,30% + \or 12,26% + \or 12,28% + \or 12,30% + \or 13,30% + \or 14,30% + \or 15,30% + \or 16,30% + \or 17,30% + \or 18,30% + \or 19,30% + \or 19,30% + \or 20,30% + \or 21,30% + \or 22,30% + \or 24,30% + \or 25,30% + \fi)}% +\or + %10: Level 'H', high error correction + \edef\qr@tempdata{(% + \ifcase\qr@version\relax + \relax %There is no version 0. + \or1,17% + \or1,28% + \or2,22% + \or4,16% + \or4,22% + \or4,28% + \or5,26% + \or6,26% + \or8,24% + \or8,28% + \or11,24% + \or11,28% + \or16,22% + \or16,24% + \or18,24% + \or16,30% + \or19,28% + \or21,28% + \or25,26% + \or25,28% + \or25,30% + \or34,24% + \or30,30% + \or32,30% + \or35,30% + \or37,30% + \or40,30% + \or42,30% + \or45,30% + \or48,30% + \or51,30% + \or54,30% + \or57,30% + \or60,30% + \or63,30% + \or66,30% + \or70,30% + \or74,30% + \or77,30% + \or81,30% + \fi)}% +\or + %11: Level 'Q', quality error correction + \edef\qr@tempdata{(% + \ifcase\qr@version\relax + \relax %There is no version 0. + \or1,13% + \or1,22% + \or2,18% + \or2,26% + \or4,18% + \or4,24% + \or6,18% + \or6,22% + \or8,20% + \or8,24% + \or8,28% + \or10,26% + \or12,24% + \or16,20% + \or12,30% + \or17,24% + \or16,28% + \or18,28% + \or21,26% + \or20,30% + \or23,28% + \or23,30% + \or25,30% + \or27,30% + \or29,30% + \or34,28% + \or34,30% + \or35,30% + \or38,30% + \or40,30% + \or43,30% + \or45,30% + \or48,30% + \or51,30% + \or53,30% + \or56,30% + \or59,30% + \or62,30% + \or65,30% + \or68,30% + \fi)}% +\fi +\xa\qr@settableix@int\qr@tempdata +}% +\define@key{qr}{version}{\edef\qr@desiredversion{#1}}% +\define@key{qr}{level}{\qr@setlevel{#1}}% +\define@key{qr}{height}{\qr@setheight{#1}}% +\define@boolkey{qr}[qr@]{tight}[true]{}% %This creates \ifqr@tight and initializes it to true. +\define@boolkey{qr}[qr@]{padding}[true]{\ifqr@padding\qr@tightfalse\else\qr@tighttrue\fi}% %Define 'padding' as antonym to 'tight' + +\def\@qr@M{M}\def\@qr@z{0}% +\def\@qr@L{L}\def\@qr@i{1}% +\def\@qr@H{H}\def\@qr@ii{2}% +\def\@qr@Q{Q}\def\@qr@iii{3}% +\def\qr@setlevel#1{% + \edef\qr@level@selected{#1}% + \ifx\qr@level@selected\@qr@M + \edef\qr@desiredlevel{0}% + \fi + \ifx\qr@level@selected\@qr@L + \edef\qr@desiredlevel{1}% + \fi + \ifx\qr@level@selected\@qr@H + \edef\qr@desiredlevel{2}% + \fi + \ifx\qr@level@selected\@qr@Q + \edef\qr@desiredlevel{3}% + \fi + \ifx\qr@level@selected\@qr@z + \edef\qr@desiredlevel{0}% + \fi + \ifx\qr@level@selected\@qr@i + \edef\qr@desiredlevel{1}% + \fi + \ifx\qr@level@selected\@qr@ii + \edef\qr@desiredlevel{2}% + \fi + \ifx\qr@level@selected\@qr@iii + \edef\qr@desiredlevel{3}% + \fi +}% + +\def\qr@setheight#1{% + \setlength{\qr@desiredheight}{#1}% +}% + +\newcommand\qrset[1]{% + \setkeys{qr}{#1}% +} + +\qrset{version=0, level=0, tight} +\newif\ifqr@starinvoked% +\def\qrcode{\@ifstar\qrcode@star\qrcode@nostar}% +\def\qrcode@star{\qr@starinvokedtrue\qrcode@i}% +\def\qrcode@nostar{\qr@starinvokedfalse\qrcode@i}% + +\newcommand\qrcode@i[1][]{% + \begingroup% + \ifqr@starinvoked% + \qr@hyperlinkfalse% + \fi% + \setkeys{qr}{#1}% + \bgroup\qr@verbatimcatcodes\qr@setescapedspecials\qrcode@in}% + +\def\qrcode@in#1{\xdef\qr@texttoencode{#1}\egroup\qrcode@int\endgroup}% + +\def\qrcode@hyperwrapper@hyperref{\href{\qr@texttoencode}}% +\def\qrcode@hyperwrapper@nohyperref{\relax}% + +\AtBeginDocument{% + \@ifpackageloaded{hyperref}% + {\global\let\qrcode@hyperwrapper=\qrcode@hyperwrapper@hyperref}% + {\global\let\qrcode@hyperwrapper=\qrcode@hyperwrapper@nohyperref}% +}% + +\def\qrcode@int{% + \message{^^J^^J^^J}% + %First, choose the version and level. + %Recall that \qr@choose@best@version sets \qr@version and \qr@level. + \xa\qr@choose@best@version\xa{\qr@texttoencode}% + \qr@setversion{\qr@version}{\qr@level}% + % + \ifqr@hyperlink% + \let\qrcode@wrapper=\qrcode@hyperwrapper% + \else% + \let\qrcode@wrapper=\relax% + \fi% + % + %Next, check whether we have already encoded this text at this version + %and level. + \qrcode@wrapper{% + \xa\ifx\csname qr@savedbinarymatrix@\qr@texttoencode @\qr@version @\qr@level\endcsname + \relax% + %This text has not yet been encoded. + \qrcode@int@new% + \else + %This text has already been encoded! + \ifqr@forget@mode + %In 'forget' mode, we deliberately recalculate anyway. + \qrcode@int@new% + \else + \qrcode@int@remember% + \fi + \fi% + }% +}% + +\def\qrcode@int@new{% + \qr@createsquareblankmatrix{newqr}{\qr@size}% + \qr@placefinderpatterns{newqr}% + \qr@placetimingpatterns{newqr}% + \qr@placealignmentpatterns{newqr}% + \qr@placedummyformatpatterns{newqr}% + \qr@placedummyversionpatterns{newqr}% + \ifqr@draft@mode + \message{^^J}% + \relax% Draft mode---don't load any data or do any work. Also don't save! + \def\qr@format@square{\qr@black}% + \def\qr@blank{\qr@white}% + \fboxsep=-\fboxrule% + \fbox{\qr@printmatrix{newqr}}% + \else + \message{^^J}% + \xa\qr@encode@binary\xa{\qr@texttoencode}% + \qr@splitcodetextintoblocks + \qr@createerrorblocks + \qr@interleave + \message{^^J}% + \qr@writeremainderbits{newqr}% + \qr@chooseandapplybestmask{newqr}% + \qr@decimaltobinary[2]{\qr@level@binary}{\qr@level}% + \qr@decimaltobinary[3]{\qr@mask@binary}{\qr@mask@selected}% + \edef\qr@formatstring{\qr@level@binary\qr@mask@binary}% + \message{^^J}% + \message{^^J}% + \message{^^J}% + % + %Also save the binary version into the aux file, for use in later runs. + \message{^^J}% + \message{^^J}% + \fi + \message{^^J}% +}% +\def\qrcode@int@remember{% + %This text has already been encoded, + %so we just copy it from the saved binary string. + \message{^^J}% + \xa\qr@printsavedbinarymatrix\xa{\csname qr@savedbinarymatrix@\qr@texttoencode @\qr@version @\qr@level\endcsname}% + % + % Now this still might need to be written to the aux file. + % + \xa\ifx\csname qr@savedflag@\qr@texttoencode @\qr@version @\qr@level\endcsname\@qr@TRUE + %Okay, this has already been written to aux file. + %Do nothing. + \relax% + \else% + %This has NOT been written to the aux file yet. + %We need to do so now. + \xa\qr@writebinarymatrixtoauxfile\xa{\csname qr@savedbinarymatrix@\qr@texttoencode @\qr@version @\qr@level\endcsname}% + \fi% +}% + +\def\qr@matrixtobinary#1{% + \def\qr@binarymatrix@result{}% + \bgroup + \def\qr@black{1}% + \def\qr@white{0}% + \def\qr@blank{0}% + \def\qr@black@fixed{1}% + \def\qr@white@fixed{0}% + \def\qr@black@format{1}% + \def\qr@white@format{0}% + % + \qr@for \i = 1 to \qr@size by 1% + {\qr@for \j = 1 to \qr@size by 1% + {\edef\qr@theentry{\qr@matrixentry{#1}{\the\i}{\the\j}}% + \xa\g@addto@macro\xa\qr@binarymatrix@result\xa{\qr@theentry}% + }% + }% + \egroup% +}% + +\def\qr@sanitize@output#1{% + %Read through ASCII text '#1' and escape backslashes and braces + \def\qr@sanitized@result{}% + \edef\qr@argument{(#1\relax\relax\relax)}% + \xa\qr@sanitize@output@int\qr@argument% +} + +\def\qr@sanitize@output@int(#1#2){% + % #1 = first character + % #2 = rest of output, including terminator + \edef\qr@testi{#1}% + \ifx\qr@testi\qr@relax + % Done. + \let\qr@next=\relax + \else + \ifx\qr@testi\qr@otherrightbrace + \edef\qr@sanitized@result{\qr@sanitized@result\qr@otherbackslash}% + \else\ifx\qr@testi\qr@otherleftbrace + \edef\qr@sanitized@result{\qr@sanitized@result\qr@otherbackslash}% + \else\ifx\qr@testi\qr@otherbackslash + \edef\qr@sanitized@result{\qr@sanitized@result\qr@otherbackslash}% + \fi + \fi + \fi + \edef\qr@sanitized@result{\qr@sanitized@result#1}% + \def\qr@next{\qr@sanitize@output@int(#2)}% + \fi + \qr@next +} + +\def\@qr@TRUE{TRUE}% +\def\qr@writebinarymatrixtoauxfile#1{% + \qr@sanitize@output{\qr@texttoencode}% + \edef\qr@theargument{{\qr@sanitized@result}{\qr@version}{\qr@level}{#1}}% + \xa\write\xa\@auxout\xa{\xa\string\xa\qr@savematrix\qr@theargument}% + % + % Now set a flag, so we don't write this again. + \xa\gdef\csname qr@savedflag@\qr@texttoencode @\qr@version @\qr@level\endcsname{TRUE}% +}% + +\gdef\qr@dummyqrsavedefinition{}% +\begingroup + \catcode`\#=12\relax + \catcode`\<=1\relax + \catcode`\{=12\relax + \catcode`\>=2\relax + \catcode`\}=12\relax + \catcode`\|=0\relax + \catcode`\\=12|relax + |gdef|qr@dummyqrsavedefinition<% + \ifx\qr@savematrix\@undefined% + \def\qr@savematrix{\begingroup\let\do\@makeother\dospecials\catcode`\{=1\catcode`\}=2\relax + \qr@savematrix@int}% + \def\qr@savematrix@int#1#2#3#4{\endgroup}% + \fi% + > +|endgroup + +\edef\qr@argument{(\qr@dummyqrsavedefinition)}% +\xa\write\xa\@auxout\xa{\qr@dummyqrsavedefinition}% + +\def\qr@savematrix{\bgroup\qr@verbatimcatcodes\qr@setescapedspecials\qr@savematrix@int}% + +\def\qr@savematrix@int#1{\xdef\qr@savedmatrix@name{#1}\egroup\qr@savematrix@int@int}% + +\def\qr@savematrix@int@int#1#2#3{% + % \qr@savedmatrix@name = encoded text + % #1 = version + % #2 = level + % #3 = binary text + \def\ds{^^J}\xa\message\xa{\ds}% + {\let\%=\qr@otherpercent + \xa\gdef\csname qr@savedbinarymatrix@\qr@savedmatrix@name @#1@#2\endcsname{#3}% + }% +}% +\endinput +%% +%% End of file `qrcode.sty'. diff --git a/judoWiki/.gitignore b/judoWiki/.gitignore new file mode 100644 index 0000000..5500895 --- /dev/null +++ b/judoWiki/.gitignore @@ -0,0 +1,2 @@ +Makefile.local + diff --git a/judoWiki/Makefile b/judoWiki/Makefile new file mode 100644 index 0000000..571fb1d --- /dev/null +++ b/judoWiki/Makefile @@ -0,0 +1,19 @@ +include Makefile.cfg +include Makefile.local + +.PHONY: all clean +all: + +.PHONY: +clean: + rm -r tmp + mkdir -p tmp + +.PHONY: updatePmWiki +updatePmWiki: clean + mkdir -p tmp + curl -L -o tmp/.pmwiki-latest.tgz http://pmwiki.org/pub/pmwiki/pmwiki-latest.tgz + tar zxvf tmp/.pmwiki-latest.tgz -C tmp/ + mv -f tmp/pmwiki-* tmp/JudoWiki + lftp -e "set ftp:ssl-allow no; mirror -R --only-newer --parallel ./tmp/JudoWiki /www/; quit" -u $(ftpUser),$(ftpPassword) $(ftpHost) + diff --git a/judoWiki/Makefile.cfg b/judoWiki/Makefile.cfg new file mode 100644 index 0000000..aeb9cc1 --- /dev/null +++ b/judoWiki/Makefile.cfg @@ -0,0 +1 @@ +ftpHost = cwsvjudo.bplaced.net diff --git a/judoWiki/Makefile.local-template b/judoWiki/Makefile.local-template new file mode 100644 index 0000000..c921aa5 --- /dev/null +++ b/judoWiki/Makefile.local-template @@ -0,0 +1,3 @@ +# login for the ftp upload +ftpUser = +ftpPassword = diff --git a/mitglieder/mitglieder.2019/anwesenheitsliste-2019.fods b/mitglieder/mitglieder.2019/anwesenheitsliste-2019.fods index f70b33d..feeec2c 100644 --- a/mitglieder/mitglieder.2019/anwesenheitsliste-2019.fods +++ b/mitglieder/mitglieder.2019/anwesenheitsliste-2019.fods @@ -1,7 +1,7 @@ - 2017-02-26T16:26:55.6448692282017-02-26T16:43:50.5216193632019-11-20T10:50:39.750721270P2DT16H59M56S33LibreOffice/5.2.7.2$Linux_X86_64 LibreOffice_project/20m0$Build-2 + 2017-02-26T16:26:55.6448692282017-02-26T16:43:50.5216193632019-12-15T16:39:04.192211042P2DT17H6M1S34LibreOffice/5.2.7.2$Linux_X86_64 LibreOffice_project/20m0$Build-2 0 @@ -30,8 +30,8 @@ true - 1 - 41 + 2 + 44 0 2 0 @@ -40,15 +40,15 @@ 0 0 0 - 23 + 1 0 120 60 true - 47 - 14 + 0 + 13 0 0 0 @@ -57,7 +57,7 @@ 0 0 0 - 0 + 4 0 120 60 @@ -99,7 +99,7 @@ 2. Halbjahr - 1223 + 1108 0 120 60 @@ -246,6 +246,9 @@ + + + @@ -258,28 +261,22 @@ - - - + + + - + - - - - - - - + @@ -290,6 +287,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -338,701 +376,533 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - + - + - + - + - + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -1077,7 +947,7 @@ ??? (???) - 00.00.0000, 00:00:00 + 00.00.0000, 00:00:00 @@ -1091,3425 +961,3425 @@ - - - - - + + + + + - + 2019 - + Alina - + Arthur - + Azim - + Ben - + Cliff - + Colin - + Dominic - + Elly - + Fabian - + Jan - + Jasmin - + Kurt - + Kyra - + Lea - + Lennox - + Lucas - + MiaSky - + MiaSophie - + Mihail - + Natalia - + Nelly - + Nick - + Nico - + Pascal - + Paul - + Rio - + Rolf - + Romy - + Sebastian - + Sophia - + - + Mi 02.Jan 19 - + X - + - - + X - - + + - - - + + V - + - - + X - - + + X - - + + X - + X - + - - - + + X - + + - + X - + - - - + + - - + X - + - + Fr 04.Jan 19 - + X - + - - + X - - + + - - + E - - + + V - + - - + X - - + + E - - + + X - + X - + - - - + + X - + - - - + + - - + X - + - - + X - + - - + - + Mi 09.Jan 19 - + X - + - - + X - - + + X - + - - - + + V - + X - - + + X - - + + X - + X - + - - - + + X - - + + - - + e - + X - + - + Fr 11.Jan 19 - + - - + X - - + + X - + - - - + + X - + - - + X - - + + X - - + + X - + X - + - - - + + X - + E - - + + X - + E - + X - + - + Mi 16.Jan 19 - + X - + - - + X - - + + X - + - - - + + X - + - - + X - - + + X - - + + X - + X - + - - - + + E - + X - - + + X - + - - + X - + - - + - + Fr 18.Jan 19 - + X - - + + X - + - - - + + X - - + + X - - + + X - + X - + - - - + + K - + X - + E - - + + X - + - - + E - + X - + - + Mi 23.Jan 19 - + X - + - - + X - + E - - + + X - + - - - + + K - + E - + X - - + + X - - + + X - + V - + X - - + + X - - + + - - + E - + X - + - + Fr 25.Jan 19 - + X - + - - + X - - + + X - - + + X - + - - + X - - + + X - - + + X - + X - - + + X - + E - + X - - + + - - + E - + X - + - + Mi 30.Jan 19 - + X - + - - + X - - + + X - + - - - + + X - + - - + X - - + + X - - + + X - + X - - + + X - - + + + - + - - + X - + E - + X - + - + Fr 01.Feb 19 - + X - - + + X - - + + X - + - - + X - - + + X - - + + X - + X - - + + X - + E - - + + X - + - - + X - + - - + - + Mi 06.Feb 19 - + X - + - - + X - - + + - - - + + X - + E - + X - - + + X - - + + X - + X - - + + X - + - - + X - - + + - - + X - + - - + - + Fr 08.Feb 19 - + - - + E - + X - - + + X - + E - - + + X - + - - + E - - + + X - - + + X - + X - + - - - + + E - + K - + X - - + + X - + - + Mi 13.Feb 19 - + - - + E - + X - - + + X - + - - - + + X - + K - - + + X - - + + X - + X - - + + X - + - - + X - - + + - - + X - + - + Fr 15.Feb 19 - + - - + X - - + + X - + E - - + + X - + - - + E - + X - - + + X - - + + X - + X - + - - - + + X - - + + - - + X - + - + Mi 20.Feb 19 - + - - + X - + K - - + + X - + - - - + + X - + - - + X - - + + X - - + + X - + X - + - - - + + X - - + + - - + X - + - + Fr 22.Feb 19 - + X - + - - + X - - + + X - - + + X - + - - + X - - + + X - - + + X - + X - + - - - + + X - + E - + X - + - - - + + X - + K - + X - + - + Mi 27.Feb 19 - + X - + - - + X - - + + X - + - - - + + X - - + + X - - + + X - + X - + - - - + + X - + E - + X - - + + e - + - - + K - + X - + - + Fr 01.Mrz 19 - + X - - + + - - + E - - + + X - + E - + X - - + + X - - + + X - + X - + - - - + + E - + X - - + + E - + X - + K - + E - + X - + - + Mi 06.Mrz 19 - + X - + - - + X - - + + X - + - - - + + X - + - - + X - - + + X - - + + X - + X - + - - - + + X - + E - + X - - + + X - + - - + X - + - + Fr 08.Mrz 19 - + X - - + + X - - + + X - + - - + X - - + + X - - + + X - + X - + - - - + + X - + E - + X - + - - - + + X - + - - + X - + - + Mi 13.Mrz 19 - + X - + - - + X - - + + X - - + + X - - + + X - - + + X - + X - - + + X - + K - - + + X - + - - + X - + - + Fr 15.Mrz 19 - + - - + X - - + + X - - + + X - - + + X - - + + X - + X - - + + X - - + + - - + X - + - + Mi 20.Mrz 19 - + - - + X - - + + X - + - - - + + X - - + + X - - + + X - + X - - + + X - + - - + X - - + + X - + - - + X - + - - + - + Fr 22.Mrz 19 - + - - + X - - + + X - - + + X - + - - + X - - + + X - - + + X - + X - - + + X - + E - - + + X - + - + Mi 27.Mrz 19 - - - - + + + + - + Fr 29.Mrz 19 - + - - + X - - + + - - + E - - + + X - + - - + X - - + + X - - + + X - + X - - + + X - + - - - + + X - + E - + X - + - + Mi 03.Apr 19 - + X - + - - + X - - + + E - + - - - + + X - + - - + X - - + + X - - + + X - + E - + X - - + + X - - + + X - + - - + X - + E - + X - + - + Fr 05.Apr 19 - + X - - + + E - + - - - + + X - + - - + X - - + + X - - + + X - + E - + X - - + + X - + - - - + + X - + E - + - - + - + Mi 10.Apr 19 - + X - + - - + X - - + + X - + - - - + + X - + - - + X - - + + X - - + + X - + X - - + + X - - + + X - + - - + X - + - + Fr 12.Apr 19 - + X - - + + X - + - - - + + X - + - - + X - - + + X - - + + X - + X - - + + X - + - - - + + X - + - - + - + Mi 17.Apr 19 - + X - + - - + X - - + + X - + - - - + + X - + - - + X - - + + X - - + + X - + X - - + + X - + - - + X - - + + - - + X - + - + Fr 19.Apr 19 - + X - + - - + X - - + + - - + E - - + + E - + - - + X - - + + E - - + + X - + - - + E - - + + X - + - - + X - + - - - + + X - + - - + - + Mi 24.Apr 19 - + E - + - - + X - - + + X - + - - - + + X - + - - + X - + E - - + + E - - + + X - + X - - + + X - + - - + X - + - - - + + X - + - - + X - + - + Fr 26.Apr 19 - + E - + X - - + + X - - + + E - + - - + E - - + + E - - + + X - + X - - + + X - + - - - + + X - + E - + X - + - + Mi 01.Mai 19 - + X - + - - + X - - + + X - + - - - + + E - + - - + X - - + + X - - + + X - + X - - + + X - + - - - + + - - + X - + - + Fr 03.Mai 19 - + X - - + + X - + E - - + + E - + - - + X - - + + X - - + + X - + X - - + + X - - + + X - + E - + - - + X - + - - + - + Mi 08.Mai 19 - + X - + - - + K - - + + X - + - - - + + E - + X - + - - + X - - + + X - - + + X - + X - - + + X - - + + - - + X - + - + Fr 10.Mai 19 - + X - + - - + X - - + + X - + E - - + + E - + X - + - - + X - - + + X - - + + X - + X - - + + X - + - - - + + X - + + - + X - + - + Mi 15.Mai 19 - + X - + - - + X - - + + - - - + + X - + - - + X - - + + X - - + + X - + - - + X - - + + X - - + + X - + - - + + - + X - + - + Fr 17.Mai 19 - + X - + - - + X - - + + X - + - - - + + E - + X - + - - + X - - + + E - - + + X - + X - - + + X - + - - - + + X - + + - + X - + - + Mi 22.Mai 19 - + E - + - - + X - - + + X - + - - - + + x - + X - + - - + E - - + + X - - + + X - + X - - + + E - + X - - + + + - + x - + X - + E - + - + Fr 24.Mai 19 - + X - + - - + X - - + + X - + E - - + + x - + X - + - - + X - - + + X - - + + X - + X - - + + X - + E - - + + X - + E - + X - + - + Mi 29.Mai 19 - + X - + - - + X - - + + X - + - - - + + X - + - - + X - - + + X - - + + X - + X - - + + - - + X - + - - - + + - - + X - + - - + - + Fr 31.Mai 19 - + X - - + + X - + E - - + + E - + X - - + + X - - + + X - + K - + X - - + + X - + - - - + + X - + E - + - - + X - + - - + - + Mi 05.Jun 19 - + X - + - - + X - - + + X - + - - - + + E - + X - + - - + X - - + + X - - + + X - + X - - + + X - - + + + - + - - + E - + - - + - + Fr 07.Jun 19 - + E - + X - + - - + X - - + + X - + E - - + + E - + X - + - - + V - - + + X - - + + X - + X - - + + X - + - - - + + - - + X - + - - + X - + - - + - + Mi 12.Jun 19 - + E - + - - + X - - + + X - + - - - + + V - + X - + - - + V - - + + X - - + + X - + X - - + + - - + X - + - - - + + - - + X - + - + Fr 14.Jun 19 - + - - + X - - + + X - + E - - + + X - + - - + V - - + + X - - + + X - + X - - + + - - + X - + - - - + + - - + X - + - - + X - + - - + - + Mi 19.Jun 19 - + X - + - - + X - - + + X - + - - - + + X - + - - + X - - + + X - - + + X - + X - - + + X - - + + X - + - - + X - + - - + - + Fr 21.Jun 19 - + X - + - - + X - - + + E - - + + V - + X - + - - + X - - + + X - - + + X - + E - + X - - + + X - + - - - + + X - + - - + X - + - + Mi 26.Jun 19 - + X - + - - + X - - + + E - + - - - + + V - + - - + X - - + + X - - + + X - + E - + X - - + + E - + + - + X - - + + - - + E - + - - + - + Fr 28.Jun 19 - + X - + - - + X - - + + X - + E - - + + V - + X - + - - + X - - + + X - - + + X - + X - - + + X - + - - - + + X - + + - + X - + - - + - + Mi 03.Jul 19 - + X - + - - + X - - + + X - + - - - + + V - + X - + x - - + + X - - + + X - + X - - + + K - + + - + X - - + + + - + - - + X - + - - + - + Fr 05.Jul 19 - - - - + + + + - + Alina - + Arthur - + Azim - + Ben - + Cliff - + Colin - + Dominic - + Elly - + Fabian - + Jan - + Jasmin - + Kurt - + Kyra - + Lea - + Lennox - - + + MiaSky - + MiaSophie - + Mihail - + Natalia - + Nelly - + Nick - + Nico - + Pascal - + Paul - + Rio - + Rolf - + Romy - + Sebastian - + Sophia - + - + @@ -4527,2226 +4397,2472 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + 2019 - + Alina - + Arthur - + Azim - + Ben - + Cliff - + Colin - + Dominic - + Elly - + Fabian - + Jan - + Jasmin - + Kurt - + Kyra - + Lea - + Lennox - + Lucas - + MiaSky - + MiaSophie - + Mihail - + Natalia - + Nelly - + Nick - + Nico - + Pascal - + Paul - + Rio - + Rolf - + Romy - + Sebastian - + Sophia - + - + - + - + Mi 03.Jul 19 - - - - - - - - + + + + + + + + - + Fr 05.Jul 19 - - - - - - - - + + + + + + + + - + Mi 10.Jul 19 - - - - - - - - + + + + + + + + - + Fr 12.Jul 19 - - - - - - - - + + + + + + + + - + Mi 17.Jul 19 - - - - - - - - + + + + + + + + - + Fr 19.Jul 19 - - - - - - - - + + + + + + + + - + Mi 24.Jul 19 - - - - - - - - + + + + + + + + - + Fr 26.Jul 19 - - - - - - - - + + + + + + + + - + Mi 31.Jul 19 - - - - - - - - + + + + + + + + - + Fr 02.Aug 19 - - - - - - - - - + + + + + + + + + - + Mi 07.Aug 19 - - - - - - - - - + + + + + + + + + - + Fr 09.Aug 19 - - - - - - - - - + + + + + + + + + - + Mi 14.Aug 19 - - - - - - - - - + + + + + + + + + - + Fr 16.Aug 19 - - - - - - - - - + + + + + + + + + - + Mi 21.Aug 19 - + X - + - - + - - + X - + - - + - - + X - + - - + X - + - - + X - + U - + X - + - - + X - + X - + - - + X - - - + + + - + Fr 23.Aug 19 - + X - + - - + - - + X - + - - + - - + X - + - - + X - + - - + X - + U - + X - + - - + X - + X - + X - + - - - - + + + - + Mi 28.Aug 19 - + - - + - - + X - + - - + X - + - - + - - + X - + - - + X - + U - + X - + - - + X - + X - + - - + X - + - - - - + + + - + Fr 30.Aug 19 - + K - + X - + - - + X - + - - + - - + X - + - - + - - + K - + - - + X - + - - + X - + - - + U - + X - + - - + - - + E - + E - + X - + - - - - + + + - + Mi 04.Sep 19 - + X - + X - + - - + X - + - - + X - + - - + - - + X - + - - + X - + E - + X - + E - + X - + U - + X - + - - + X - + x - + - - + - - + X - + - - - + + - + Fr 06.Sep 19 - + X - + X - + - - + X - + - - + - - + X - + - - + X - + U - + E - + - - + X - + X - + - - + X - + - - - + + - + Mi 11.Sep 19 - + X - + - - + X - + - - + - - + X - + - - + - - + X - + - - + X - + - - + X - + - - + U - + X - + - - + X - + - - + X - + - - - + + - + Fr 13.Sep 19 - + X - + - - + X - + - - + - - + X - + - - + - - + X - + - - + X - + - - + X - + - - + X - + U - + X - + - - + X - + E - + X - + - - - + + - + Mi 18.Sep 19 - + X - + - - + X - + - - + - - + X - + - - + - - + V - + - - + X - + E - + X - + - - + - - + X - + - - + X - + - - + - - + X - + - - - + + - + Fr 20.Sep 19 - + - - + - - + X - + - - + X - + E - + - - + V - + - - + X - + - - + - - + X - + - - + X - + X - + X - + - - - + + - + Mi 25.Sep 19 - + - - + - - + X - - + + - - + X - + - - - + + X - + - - + X - + - - + X - + - - + X - - + + X - + - - + E - + X - + - - - + + - + Fr 27.Sep 19 - + X - + - - + X - - + + X - + - - - + + - - + X - + - - + X - - + + X - + - - + X - + X - + - - - + + - + Mi 02.Okt 19 - - + + - - - - + + + - - - + + - - - - - - + + + + + - - - - + + + - + Fr 04.Okt 19 - - + + - - + X - - - + + + - - - + + - - + X - - - - - + + + + + - - - - + + + - + Mi 09.Okt 19 - - + + - - - - + + + - - - + + - - - - - - + + + + + - - - - + + + - + Fr 11.Okt 19 - - + + - - + X - - - + + + - - - + + - - + X - - - - - + + + + + - - - - + + + - + Mi 16.Okt 19 - - + + - - + - - - - + + + - - - + + - - - - - - + + + + + - - - - + + + - + Fr 18.Okt 19 - - + + - - + - - - - + + + - - - + + - - - - - - + + + + + - - - - + + + - + Mi 23.Okt 19 - - + + - - + - - - - + + + - - - + + - - - + + - - - - - - + + + + + - - - - + + + - + Fr 25.Okt 19 - - + + - - + X - - + + - - + X - + - - - + + X - + - - + X - + - - + X - + - - + X - + - - + X - + X - - + + - - + X - + - - + X - + - - - - + + + - + Mi 30.Okt 19 - + - - + - - + X - - + + - - + X - + - - - + + - - + - - + - - + X - + - - + X - - + + - - + X - + - - + - - + X - + - - - - + + + - + Fr 01.Nov 19 - + X - + - - + X - - + + - - + X - + - - - + + - - + X - - + + X - + X - + - - - + + - + Mi 06.Nov 19 - + X - + - - + X - - + + - - + X - + - - - + + X - + - - + X - + - - + X - + - - + X - - + + X - + - - + E - + X - + - - - + + - + Fr 08.Nov 19 - + E - + X - + - - + E - - + + X - + X - + - - - + + - - + E - + - - + E - + X - + - - + E - + X - + E - - + + - - + X - + - - + X - + - - - + + - + Mi 13.Nov 19 - + X - + - - + X - - + + - - + X - + - - - + + X - + - - + X - + - - + X - + - - + X - + K - + X - - + + - - + X - + - - + X - + - - - + + - + Fr 15.Nov 19 - + - - + X - + - - + X - - + + X - + X - + - - - + + X - + - - + X - + K - + X - - + + X - + - - + X - + - - - + + - + Mi 20.Nov 19 - - - - - + + - - - + + + + - - - - + + - - - + + + - + + + + - + + + + + - + + + - + Fr 22.Nov 19 - - - - - + + - - - + + + + - - - - + + - - - + + + - + + + + - + + + + + - + + + - + Mi 27.Nov 19 - - - - - + + - - - + + + + - - - - + + - - - + + + - + + + + - + + + + + - + + + - + Fr 29.Nov 19 - - - - - + + + - - - + + + + - - - - + + - - - + + + - + + + + - + + + + + - + + + - + Mi 04.Dez 19 - - - - - + + - - - + - - - - + + + + - - - - + + + - + + + + - + + + + - + + + + + - + + + + - + Fr 06.Dez 19 - - - - - + + + - - - + + + + - - - - + + - - - - + + + - + + + + - + + + + + - + + + + - + Mi 11.Dez 19 - - - - - + - - - + - - - - + - - - - + + - + + + + - + + + - + + + - + + + + - + + + - + + + X + + + - + + + X + + + V + + + - + + + X + + + - + + + X + + + V + + + + X + + + - + + + - + + + X + + + - + + + + - + Fr 13.Dez 19 - - - - - + - - - + + X + + - - - - + + X + + + + X + + + X + + - - - - + + + - + + + V + + + X + + + - + + + X + + + V + + + X + + + V + + + + - + + + X + + + E + + + X + + + - + + + + - + Mi 18.Dez 19 - - - - - + + + - - - + + + + - - - - + + - - - - + + + - + + + + - + + + + + - + + + + - + Fr 20.Dez 19 - - - - - + + + - - - + + + + - - - - + + - - - - + + + - + + + + - + + + + + - + + + + - + Mi 25.Dez 19 - - - - - + + + - - - + + + + - - - - + + - - - - + + + - + + + + - + + + + + - + + + + - + Fr 27.Dez 19 - - - - - + + + - - - + + + + - - - - + + - - - - + + + - + + + + - + + + + + - + + + + - + Mi 01.Jan 20 - - - - - + + + - - - + + + + - - - - + + - - - + + + - + + + + - + + + + + - + + + - + Fr 03.Jan 20 - - - - - + + + - - - - + + + + - - - - + + - - - + + + - + + + + + - + + + + + - + + + - - + + Alina - + Arthur - + Azim - + Ben - + Cliff - + Colin - + Dominic - + Elly - + Fabian - + Jan - + Jasmin - + Kurt - + Kyra - + Lea - + Lennox - + Lucas - + MiaSky - + MiaSophie - + Mihail - + Natalia - + Nelly - + Nick - + Nico - + Paul - + Paul - + Rio - + Rolf - + Romy - + Sebastian - + Sophia - + - + - + @@ -6770,7 +6886,7 @@ - + @@ -6794,1191 +6910,1246 @@ - - - + + + + + - - + + Alina - + Arthur - + Azim - + Ben - + Cliff - + Colin - + Dominic - + Elly - + Fabian - + Jan - + Jasmin - + Kurt - + Kyra - + Lea - + Lennox - + MiaSky - + MiaSophie - + Mihail - + Natalia - + Nelly - + Nick - + Nico - + Pascal - + Paul - + Rio - + Rolf - + Romy - + Sebastian - + Sophia - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + Anwesend - + 37 - + 18 - + 34 - + 49 - + 0 - + 0 - + 41 - + 8 - + 0 - + 33 - + 23 - + 26 - + 44 - + 0 - + 47 - + 52 - + 44 - + 37 - + 0 - + 42 - + 38 - + 52 - + 26 - + 0 - + 32 - + 21 - + 27 - + 44 - + 33 - + + pünktlich - + 37 - + 18 - + 34 - + 49 - + 0 - + 0 - + 41 - + 8 - + 0 - + 33 - + 23 - + 26 - + 44 - + 0 - + 47 - + 52 - + 44 - + 37 - + 0 - + 42 - + 35 - + 52 - + 26 - + 0 - + 28 - + 21 - + 23 - + 44 - + 33 - + + zu spät - + 0 - + 0 - + 0 - + 0 - + 0 - + 0 - + 0 - + 0 - + 0 - + 0 - + 0 - + 0 - + 0 - + 0 - + 0 - + 0 - + 0 - + 0 - + 0 - + 0 - + 3 - + 0 - + 0 - + 0 - + 4 - + 0 - + 4 - + 0 - + 0 - + + - + nicht Anwesend - + 15 - + 34 - + 18 - + 3 - + 0 - + 0 - + 11 - + 44 - + 0 - + 19 - + 29 - + 26 - + 8 - + 0 - + 5 - + 0 - + 8 - + 15 - + 0 - + 10 - + 14 - + 0 - + 26 - + 0 - + 20 - + 31 - + 25 - + 8 - + 19 - + + krank - + 0 - + 0 - + 0 - + 2 - + 0 - + 0 - + 0 - + 0 - + 0 - + 1 - + 0 - + 0 - + 1 - + 0 - + 0 - + 0 - + 1 - + 0 - + 0 - + 2 - + 1 - + 0 - + 1 - + 0 - + 0 - + 0 - + 3 - + 0 - + 0 - + + verletzt - + 0 - + 0 - + 0 - + 0 - + 0 - + 0 - + 0 - + 0 - + 0 - + 8 - + 0 - + 0 - + 3 - + 0 - + 0 - + 0 - + 1 - + 0 - + 0 - + 0 - + 0 - + 0 - + 0 - + 0 - + 0 - + 0 - + 0 - + 0 - + 0 - + + entschuldigt - + 5 - + 1 - + 1 - + 1 - + 0 - + 0 - + 4 - + 14 - + 0 - + 10 - + 2 - + 4 - + 4 - + 0 - + 5 - + 0 - + 4 - + 1 - + 0 - + 5 - + 6 - + 0 - + 5 - + 0 - + 2 - + 4 - + 6 - + 7 - + 1 - + + ??? - + 10 - + 33 - + 17 - + 0 - + 0 - + 0 - + 7 - + 30 - + 0 - + 0 - + 27 - + 22 - + 0 - + 0 - + 0 - + 0 - + 2 - + 14 - + 0 - + 3 - + 7 - + 0 - + 20 - + 0 - + 18 - + 27 - + 16 - + 1 - + 18 - + Urlaub - + 0 - + 0 - + 0 - + 0 - + 0 - + 0 - + 0 - + 0 - + 0 - + 0 - + 0 - + 0 - + 0 - + 0 - + 0 - + 0 - + 0 - + 0 - + 0 - + 0 - + 0 - + 0 - + 0 - + 0 - + 0 - + 0 - + 0 - + 0 - + 0 - + + - + Kontrolle - + 52 - + 52 - + 52 - + 52 - + 0 - + 0 - + 52 - + 52 - + 0 - + 52 - + 52 - + 52 - + 52 - + 0 - + 52 - + 52 - + 52 - + 52 - + 0 - + 52 - + 52 - + 52 - + 52 - + 0 - + 52 - + 52 - + 52 - + 52 - + 52 - + + - - + + - - - + + + Alina - + Arthur - + Azim - + Ben - + Cliff - + Colin - + Dominic - + Elly - + Fabian - + Jan - + Jasmin - + Kurt - + Kyra - + Lea - + Lennox - + Lucas - + MiaSky - + MiaSophie - + Mihail - + Natalia - + Nelly - - + + Nick + + + Nico + + + Pascal + + + Paul + + + Rio + + + Rolf + + + Romy + + + Sebastian + + + Sophia + + + + + + + + + + + + + + + + + + + + - - + + Anwesend 11 - - 5 + + 6 3 - - 16 + + 17 0 - - 7 + + 8 - - 19 + + 20 0 @@ -7998,47 +8169,83 @@ 13 - - 13 + + 15 10 - - 13 + + 15 14 - - 19 + + 20 - + + 20 + + + 17 + + + 13 + + + 6 + + + 17 + + + 0 + + + 14 + + + 14 + + + 6 + + + 12 + + + 20 + + + 1 + + - + pünktlich 11 - - 5 + + 6 3 - - 16 + + 17 0 - - 7 + + 8 - - 19 + + 20 0 @@ -8058,25 +8265,61 @@ 13 - - 13 + + 15 10 - - 13 + + 15 14 - - 19 + + 20 - + + 20 + + + 17 + + + 13 + + + 6 + + + 17 + + + 0 + + + 14 + + + 14 + + + 6 + + + 12 + + + 20 + + + 1 + + - - + + zu spät @@ -8133,32 +8376,68 @@ 0 - + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + - - + + nicht Anwesend - + + 9 + + + 26 + + + 37 + + 7 - - 21 - - - 23 - - - 6 - 10 - - 12 + + 13 - - 0 + + 1 40 @@ -8166,37 +8445,73 @@ 10 - - 10 - - - 21 - - + 24 - - 6 + + 35 + + + 38 + + + 8 6 - - 10 + + 24 7 - - 5 + + 7 - - 0 + + 1 - + + 1 + + + 4 + + + 8 + + + 15 + + + 16 + + + 10 + + + 7 + + + 7 + + + 15 + + + 9 + + + 1 + + + 39 + + - - + + krank @@ -8253,10 +8568,46 @@ 0 - + + 0 + + + 0 + + + 0 + + + 2 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + - - + + verletzt @@ -8295,8 +8646,8 @@ 0 - - 0 + + 1 0 @@ -8307,16 +8658,52 @@ 0 - - 0 + + 2 0 - + + 0 + + + 0 + + + 0 + + + 0 + + + 2 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + - - + + entschuldigt @@ -8373,70 +8760,142 @@ 0 - + + 1 + + + 0 + + + 1 + + + 0 + + + 2 + + + 0 + + + 0 + + + 0 + + + 2 + + + 4 + + + 0 + + + 0 + + - - + + ??? - - 5 - - - 21 - - - 23 - - - 5 - - - 10 - - - 12 - - - 0 - - - 39 - - - 10 - - - 8 - - - 21 - - - 24 - - - 4 - - - 5 - - - 8 - - + 7 - + + 26 + + + 37 + + + 6 + + + 10 + + + 13 + + + 1 + + + 39 + + + 10 + + + 22 + + + 35 + + + 38 + + + 5 + + + 5 + + + 22 + + + 7 + + 4 - + + 1 + + 0 - + + 4 + + + 7 + + + 5 + + + 12 + + + 10 + + + 7 + + + 7 + + + 13 + + + 5 + + + 1 + + + 39 + + - - + + Urlaub @@ -8493,32 +8952,68 @@ 0 - + + 0 + + + 0 + + + 0 + + + 8 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + - - + + Kontrolle - - 18 + + 20 - - 26 + + 32 - - 26 + + 40 - - 22 + + 24 10 - - 19 + + 21 - - 19 + + 21 40 @@ -8526,308 +9021,344 @@ 10 - - 19 + + 33 - - 26 + + 40 - - 26 + + 40 - - 19 + + 21 - - 19 + + 21 - - 20 + + 34 - - 20 + + 22 - - 19 + + 21 - - 19 + + 21 - + + 21 + + + 21 + + + 21 + + + 21 + + + 33 + + + 10 + + + 21 + + + 21 + + + 21 + + + 21 + + + 21 + + + 40 + + - + - + 2019 - + Alina - + Arthur - + Azim - + Ben - + Cliff - + Colin - + Dominic - + Elly - + Fabian - + Jan - + Jasmin - + Kurt - + Kyra - + Lea - + Lennox - + MiaSky - + MiaSophie - + Mihail - + Natalia - + Nelly - + Nick - + Nico - + Pascal - + Paul - + Rio - + Rolf - + Romy - + Sebastian - + Sophia - + - + - + - + - - + + Mi 03.Jul 19 - - + + + + + + + Fr 05.Jul 19 + + + - - Fr 05.Jul 19 - - - - - - - + Mi 10.Jul 19 - - + + - + - - + + Fr 12.Jul 19 - - + + - + - - + + Mi 17.Jul 19 - - + + - + - - + + Fr 19.Jul 19 - - + + - + - - + + Mi 24.Jul 19 - - + + - + - - + + Fr 26.Jul 19 - - + + - + - - + + Mi 31.Jul 19 - - + + - + - - + + Fr 02.Aug 19 - + - + - - + + Mi 07.Aug 19 - + - + - - + + Fr 09.Aug 19 - + - + - - + + Mi 14.Aug 19 - + - + - - + + Fr 16.Aug 19 - + - + - - + + Mi 21.Aug 19 - + - + - - + + Fr 23.Aug 19 - + - + - - + + Mi 28.Aug 19 - + - + - - + + Fr 30.Aug 19 - + - + - - + + Mi 04.Sep 19 - + - - + + Fr 06.Sep 19 - + @@ -8858,161 +9389,161 @@ - - - - - + + + + + - + 2019 - + Pass (9,00 €) - + JahresMarke (18,00 €) - + KyuMarke (12,00 €) - + Pass zurück erhalten - + Arthur - + Azim - + Ben - + Elly - + Eric - + Jan - + Jasmin - + Kurt - + Kyra - + Lennox - + Mia - + Mia-S - + Nelly - + Nick - + Nico - + Pascal - + Rio - + Rolf - + Romy - + Sebastian - + Sophia - + - - - - + + + + diff --git a/onlineTraining/.gitignore b/onlineTraining/.gitignore new file mode 100644 index 0000000..dc84959 --- /dev/null +++ b/onlineTraining/.gitignore @@ -0,0 +1,2 @@ +build/ + diff --git a/onlineTraining/Makefile b/onlineTraining/Makefile new file mode 100644 index 0000000..1a04c73 --- /dev/null +++ b/onlineTraining/Makefile @@ -0,0 +1,82 @@ +mdFilesTraining := $(wildcard trainings.d/*.md) +pdfFilesTraining := $(patsubst trainings.d/%.md, build/trainings.d/pdf/%.pdf, $(mdFilesTraining)) +revealjsFilesTraining := $(patsubst trainings.d/%.md, build/trainings.d/revealjs/%.html, $(mdFilesTraining)) + +mdFilesIdeen := $(wildcard ideen.d/*.md) +pdfFilesIdeen := $(patsubst ideen.d/%.md, build/ideen.d/pdf/%.pdf, $(mdFilesIdeen)) + +.PHONY: all +all: $(pdfFilesTraining) $(pdfFilesIdeen) $(revealjsFilesTraining) ideenSammlung + +.PHONY: ideenSammlung +ideenSammlung: $(mdFilesIdeen) + pandoc -o build/ideenSammlung.pdf $(mdFilesIdeen) + +.PHONY: pdf +pdf: $(pdfFiles) + +.PHONY: installReveal3 +installReveal3: + wget https://github.com/hakimel/reveal.js/archive/3.9.2.tar.gz + tar -xzvf 3.9.2.tar.gz +# mv reveal.js-3.9.2 reveal.js + +.PHONY: revealjs +revealjs: $(revealjsFiles) + +build/trainings.d/revealjs/%.html: trainings.d/%.md css/cwsvJudo-revealjs.css + mkdir -p build/trainings.d/revealjs + pandoc -t revealjs -s -o $@ $< -V revealjs-url=https://unpkg.com/reveal.js@3.9.2/ --css="css/cwsvJudo-revealjs.css" +# pandoc -t revealjs -s -o $@ $< -V revealjs-url=/ressourcen/reveal.js-3.9.2 --css="css/cwsvJudo-revealjs.css" + +build/ideen.d/pdf/%.pdf: ideen.d/%.md + mkdir -p build/ideen.d/pdf + pandoc -o $@ $< + +.PHONY: get-revealjs3 +get-revealjs3: + wget https://github.com/hakimel/reveal.js/archive/3.9.2.tar.gz + tar -xzvf 3.9.2.tar.gz + mv reveal.js-3.9.2 reveal.js + +.PHONY: echo +echo: + echo $(mdFiles) + echo $(pdfFiles) + echo $(revealjsFiles) + +build/trainings.d/pdf/%.pdf: trainings.d/%.md + mkdir -p build/trainings.d/pdf + pandoc -t beamer -o $@ $< + +build/trainings.d/revealjs/%.html: trainings.d/%.md + mkdir -p build/trainings.d/revealjs + pandoc -t revealjs -s -o $@ $< --css css/cwsvJudo-revealjs.css -V revealjs-url=https://unpkg.com/reveal.js@3.9.2/ + +.PHONY: links +links: + ln -s videos.d build/trainings.d/revealjs/videos.d + ln -s images.d build/trainings.d/revealjs/images.d + +.PHONY: download +download: + make --file=Makefile.d/Makefile.youtube-dl + + +.PHONY: videos +videos: otVideos machsVideos + +# Videos zu den onlineTrainings +.PHONY: otVideos +otVideos: + make --file=Makefile.d/Makefile.clips all + +# Videos zu den AchievementGroups im MAchS +.PHONY: machsVideos +machsVideos: + mkdir --parents build/videos.d/machs/groups + make --file=Makefile.d/Makefile.clips.machs all + +.PHONY: images +images: + make --file=Makefile.d/Makefile.images diff --git a/onlineTraining/Makefile.d/Makefile.clips b/onlineTraining/Makefile.d/Makefile.clips new file mode 100644 index 0000000..91a9059 --- /dev/null +++ b/onlineTraining/Makefile.d/Makefile.clips @@ -0,0 +1,11 @@ +jsonClips := $(wildcard clips.d/*.json) +jsonTaisoClips := $(wildcard clips.d/taiso/*.json) + +webmClips := $(patsubst clips.d/%.json, build/videos.d/%.webm, $(jsonClips)) +webmTaisoClips := $(patsubst clips.d/taiso/%.json, build/videos.d/taiso/%.webm, $(jsonTaisoClips)) + +.PHONY: all +all: $(webmClips) $(webmTaisoClips) + +build/videos.d/%.webm: clips.d/%.json + ./yt-clipper.py $^ diff --git a/onlineTraining/Makefile.d/Makefile.clips.machs b/onlineTraining/Makefile.d/Makefile.clips.machs new file mode 100644 index 0000000..054a5f1 --- /dev/null +++ b/onlineTraining/Makefile.d/Makefile.clips.machs @@ -0,0 +1,13 @@ +jsonGroupsClips := $(wildcard clips.d/machs/groups/*.json) +webmGroupsClips := $(patsubst clips.d/machs/groups/%.json, build/videos.d/machs/groups/%.webm, $(jsonGroupsClips)) + +.PHONY: all +all: $(webmGroupsClips) + +build/videos.d/%.webm: clips.d/%.json + ./yt-clipper.py $^ + +.PHONY: echo +echo: + echo jsonGroupsClips: $(jsonGroupsClips) + echo webmGroupsClips: $(webmGroupsClips) diff --git a/onlineTraining/Makefile.d/Makefile.images b/onlineTraining/Makefile.d/Makefile.images new file mode 100644 index 0000000..cdaa3b6 --- /dev/null +++ b/onlineTraining/Makefile.d/Makefile.images @@ -0,0 +1,23 @@ +jpgImages := $(wildcard images.d/*.jpg) +jpgImagesSeefahrt := $(wildcard images.d/seefahrt.d/*.jpg) +pngImages := $(wildcard images.d/*.png) +pngImagesSeefahrt := $(wildcard images.d/seefahrt.d/*.png) + +processedJpgImages := $(patsubst images.d/%.jpg, build/images.d/%.jpg, $(jpgImages)) +processedJpgImagesSeefahrt := $(patsubst images.d/seefahrt.d/%.jpg, build/images.d/seefahrt.d/%.jpg, $(jpgImagesSeefahrt)) +processedPngImages := $(patsubst images.d/%.png, build/images.d/%.png, $(pngImages)) +processedPngImagesSeefahrt := $(patsubst images.d/seefahrt.d/%.png, build/images.d/seefahrt.d/%.png, $(pngImagesSeefahrt)) + +.PHONY: all +all: $(processedJpgImages) $(processedJpgImagesSeefahrt) $(processedPngImages) $(processedPngImagesSeefahrt) + +build/%.jpg: %.jpg + convert $^ -resize x1024 $@ + +build/%.png: %.png + convert $^ -resize x1024 $@ + +.PHONY: echo +echo: + echo From: $(jpgImagesSeefahrt) + echo To: $(processedJpgImagesSeefahrt) diff --git a/onlineTraining/Makefile.d/Makefile.youtube-dl b/onlineTraining/Makefile.d/Makefile.youtube-dl new file mode 100644 index 0000000..486018b --- /dev/null +++ b/onlineTraining/Makefile.d/Makefile.youtube-dl @@ -0,0 +1,8 @@ +# Downloading youtube videos + +.PHONY: djbVideos +djbVideos: + mkdir -p djbVideos/judoTrainingDeluxe + youtube-dl -o"djbVideos/judoTrainingDeluxe/%(title)s-%(id)s.%(ext)s" https://www.youtube.com/playlist?list=PLZOOND0QXndNXaAuUeDuKrcoQx8efdB50 + mkdir -p djbVideos/judoTrainingLive + youtube-dl -o"djbVideos/judoTrainingDeluxe/%(title)s-%(id)s.%(ext)s" https://www.youtube.com/playlist?list=PLZOOND0QXndMB8sFTwPkWyiXklwuvLlRi diff --git a/onlineTraining/clips.d/anfersen.json b/onlineTraining/clips.d/anfersen.json new file mode 100644 index 0000000..63c1a86 --- /dev/null +++ b/onlineTraining/clips.d/anfersen.json @@ -0,0 +1,7 @@ +[{ + "source": "https://www.youtube.com/embed/6wcWZZw6RGk", + "target": "build/videos.d/anfersen.webm", + "from": "01:40.208", + "to": "01:54.625", + "crop": {"x": 581, "y": 32, "w": 1309, "h": 1018} +}] diff --git a/onlineTraining/clips.d/aufspringen.json b/onlineTraining/clips.d/aufspringen.json new file mode 100644 index 0000000..e992773 --- /dev/null +++ b/onlineTraining/clips.d/aufspringen.json @@ -0,0 +1,7 @@ +[{ + "source": "https://www.youtube.com/watch?v=k2kMAJPyaHs", + "target": "build/videos.d/aufspringen.webm", + "from": "00:04.867", + "to": "00:35.900", + "crop": {"x": 568, "y": 124, "w": 898, "h": 784} +}] diff --git a/onlineTraining/clips.d/griff-aermel-katzentatze-rein-raus-zug.json b/onlineTraining/clips.d/griff-aermel-katzentatze-rein-raus-zug.json new file mode 100644 index 0000000..a893ff4 --- /dev/null +++ b/onlineTraining/clips.d/griff-aermel-katzentatze-rein-raus-zug.json @@ -0,0 +1,7 @@ +[{ + "source": "XQpD6YMSlUg", + "target": "build/videos.d/griff-aermel-katzentatze-rein-raus-zug.webm", + "from": "03:51.933", + "to": "04:02.733", + "crop": {"x": 237, "y": 0, "w": 617, "h": 478} +}] diff --git a/onlineTraining/clips.d/griff-aermel-katzentatze-rein.json b/onlineTraining/clips.d/griff-aermel-katzentatze-rein.json new file mode 100644 index 0000000..6be9075 --- /dev/null +++ b/onlineTraining/clips.d/griff-aermel-katzentatze-rein.json @@ -0,0 +1,7 @@ +[{ + "source": "XQpD6YMSlUg", + "target": "build/videos.d/griff-aermel-katzentatze-rein.webm", + "from": "05:16.300", + "to": "05:24.966", + "crop": {"x": 237, "y": 0, "w": 617, "h": 478} +}] diff --git a/onlineTraining/clips.d/griff-aermel-nach-aussen.json b/onlineTraining/clips.d/griff-aermel-nach-aussen.json new file mode 100644 index 0000000..c3f60d6 --- /dev/null +++ b/onlineTraining/clips.d/griff-aermel-nach-aussen.json @@ -0,0 +1,7 @@ +[{ + "source": "XQpD6YMSlUg", + "target": "build/videos.d/griff-aermel-nach-aussen.webm", + "from": "04:07.833", + "to": "04:18.766", + "crop": {"x": 237, "y": 0, "w": 617, "h": 478} +}] diff --git a/onlineTraining/clips.d/griff-ausgangsstellung.json b/onlineTraining/clips.d/griff-ausgangsstellung.json new file mode 100644 index 0000000..3a07117 --- /dev/null +++ b/onlineTraining/clips.d/griff-ausgangsstellung.json @@ -0,0 +1,7 @@ +[{ + "source": "XQpD6YMSlUg", + "target": "build/videos.d/griff-ausgangsstellung.webm", + "from": "00:37.366", + "to": "00:53.366", + "crop": {"x": 237, "y": 0, "w": 617, "h": 478} +}] diff --git a/onlineTraining/clips.d/griff-kragen-nach-aussen.json b/onlineTraining/clips.d/griff-kragen-nach-aussen.json new file mode 100644 index 0000000..4135f40 --- /dev/null +++ b/onlineTraining/clips.d/griff-kragen-nach-aussen.json @@ -0,0 +1,7 @@ +[{ + "source": "XQpD6YMSlUg", + "target": "build/videos.d/griff-kragen-nach-aussen.webm", + "from": "02:18.900", + "to": "03:02.233", + "crop": {"x": 237, "y": 0, "w": 617, "h": 478} +}] diff --git a/onlineTraining/clips.d/griff-kragen-nach-innen.json b/onlineTraining/clips.d/griff-kragen-nach-innen.json new file mode 100644 index 0000000..279fcc9 --- /dev/null +++ b/onlineTraining/clips.d/griff-kragen-nach-innen.json @@ -0,0 +1,7 @@ +[{ + "source": "XQpD6YMSlUg", + "target": "build/videos.d/griff-kragen-nach-innen.webm", + "from": "01:45.266", + "to": "02:16.833", + "crop": {"x": 237, "y": 0, "w": 617, "h": 478} +}] diff --git a/onlineTraining/clips.d/hampelmann.json b/onlineTraining/clips.d/hampelmann.json new file mode 100644 index 0000000..880c0b7 --- /dev/null +++ b/onlineTraining/clips.d/hampelmann.json @@ -0,0 +1,7 @@ +[{ + "source": "https://www.youtube.com/embed/SdwY3Pd59yE", + "target": "build/videos.d/hampelmann.webm", + "from": "00:39.907", + "to": "00:59.493", + "crop": {"x": 563, "y": 0, "w": 1357, "h": 1080} +}] diff --git a/onlineTraining/clips.d/handtuchzug.json b/onlineTraining/clips.d/handtuchzug.json new file mode 100644 index 0000000..1538988 --- /dev/null +++ b/onlineTraining/clips.d/handtuchzug.json @@ -0,0 +1,6 @@ +[{ + "source": "https://www.youtube.com/embed/HZ7Y41JVoZ8", + "target": "build/videos.d/handtuchzug.webm", + "from": "02:37.880", + "to": "02:54.200" +}] diff --git a/onlineTraining/clips.d/harei-ushiro.json b/onlineTraining/clips.d/harei-ushiro.json new file mode 100644 index 0000000..95d9333 --- /dev/null +++ b/onlineTraining/clips.d/harei-ushiro.json @@ -0,0 +1,7 @@ +[{ + "source": "https://www.youtube.com/watch?v=DsMj71FhToo", + "target": "build/videos.d/harei-ushiro.webm", + "from": "03:31.344", + "to": "04:21.294", + "crop": {"x": 656, "y": 0, "w": 1264, "h": 1018} +}] diff --git a/onlineTraining/clips.d/harei-yoko-tsugiAshi.json b/onlineTraining/clips.d/harei-yoko-tsugiAshi.json new file mode 100644 index 0000000..14ff48d --- /dev/null +++ b/onlineTraining/clips.d/harei-yoko-tsugiAshi.json @@ -0,0 +1,7 @@ +[{ + "source": "https://www.youtube.com/watch?v=DsMj71FhToo", + "target": "build/videos.d/harei-yoko-tsugiAshi.webm", + "from": "02:55.442", + "to": "03:23.803", + "crop": {"x": 656, "y": 0, "w": 1264, "h": 1018} +}] diff --git a/onlineTraining/clips.d/harei-yoko.json b/onlineTraining/clips.d/harei-yoko.json new file mode 100644 index 0000000..f71ff05 --- /dev/null +++ b/onlineTraining/clips.d/harei-yoko.json @@ -0,0 +1,7 @@ +[{ + "source": "https://www.youtube.com/watch?v=DsMj71FhToo", + "target": "build/videos.d/harei-yoko.webm", + "from": "02:29.750", + "to": "02:48.035", + "crop": {"x": 656, "y": 0, "w": 1264, "h": 1018} +}] diff --git a/onlineTraining/clips.d/hopserlauf.json b/onlineTraining/clips.d/hopserlauf.json new file mode 100644 index 0000000..c10d708 --- /dev/null +++ b/onlineTraining/clips.d/hopserlauf.json @@ -0,0 +1,7 @@ +[{ + "source": "https://www.youtube.com/embed/6wcWZZw6RGk", + "target": "build/videos.d/hopserlauf.webm", + "from": "01:09.000", + "to": "01:24.833", + "crop": {"x": 581, "y": 32, "w": 1309, "h": 1018} +}] diff --git a/onlineTraining/clips.d/indianer.json b/onlineTraining/clips.d/indianer.json new file mode 100644 index 0000000..575bdb4 --- /dev/null +++ b/onlineTraining/clips.d/indianer.json @@ -0,0 +1,7 @@ +[{ + "source": "https://www.youtube.com/embed/6wcWZZw6RGk", + "target": "build/videos.d/indianer.webm", + "from": "04:36.917", + "to": "05:05.458", + "crop": {"x": 581, "y": 32, "w": 1309, "h": 1018} +}] diff --git a/onlineTraining/clips.d/kniehebelauf.json b/onlineTraining/clips.d/kniehebelauf.json new file mode 100644 index 0000000..4fb74d3 --- /dev/null +++ b/onlineTraining/clips.d/kniehebelauf.json @@ -0,0 +1,7 @@ +[{ + "source": "https://www.youtube.com/embed/6wcWZZw6RGk", + "target": "build/videos.d/kniehebelauf.webm", + "from": "01:24.917", + "to": "01:39.542", + "crop": {"x": 581, "y": 32, "w": 1309, "h": 1018} +}] diff --git a/onlineTraining/clips.d/kodokanEingang-kniebeuge.json b/onlineTraining/clips.d/kodokanEingang-kniebeuge.json new file mode 100644 index 0000000..af6e645 --- /dev/null +++ b/onlineTraining/clips.d/kodokanEingang-kniebeuge.json @@ -0,0 +1,7 @@ +[{ + "source": "https://www.youtube.com/embed/6wcWZZw6RGk", + "target": "build/videos.d/***REMOVED***Eingang-kniebeuge.webm", + "from": "03:45.250", + "to": "04:05.167", + "crop": {"x": 581, "y": 32, "w": 1309, "h": 1018} +}] diff --git a/onlineTraining/clips.d/kragengriff.json b/onlineTraining/clips.d/kragengriff.json new file mode 100644 index 0000000..5b8be0d --- /dev/null +++ b/onlineTraining/clips.d/kragengriff.json @@ -0,0 +1,7 @@ +[{ + "source": "XQpD6YMSlUg", + "target": "build/videos.d/kragengriff.webm", + "from": "01:45.266", + "to": "02:16.833", + "crop": {"x": 236, "y": 32, "w": 618, "h": 478} +}] diff --git a/onlineTraining/clips.d/loecherlaufen.json b/onlineTraining/clips.d/loecherlaufen.json new file mode 100644 index 0000000..21c4b09 --- /dev/null +++ b/onlineTraining/clips.d/loecherlaufen.json @@ -0,0 +1,6 @@ +[{ + "source": "https://www.youtube.com/embed/jxt1gagi6C4", + "target": "build/videos.d/loecherlaufen.webm", + "from": "05:44.633", + "to": "06:17.949" +}] diff --git a/onlineTraining/clips.d/loecherspringen.json b/onlineTraining/clips.d/loecherspringen.json new file mode 100644 index 0000000..ceecd53 --- /dev/null +++ b/onlineTraining/clips.d/loecherspringen.json @@ -0,0 +1,6 @@ +[{ + "source": "https://www.youtube.com/embed/jxt1gagi6C4", + "target": "build/videos.d/loecherspringen.webm", + "from": "05:01.483", + "to": "05:06.399" +}] diff --git a/onlineTraining/clips.d/machs/groups/aufspringen.json b/onlineTraining/clips.d/machs/groups/aufspringen.json new file mode 100644 index 0000000..f2ea068 --- /dev/null +++ b/onlineTraining/clips.d/machs/groups/aufspringen.json @@ -0,0 +1,8 @@ +[{ + "source": "https://www.youtube.com/watch?v=k2kMAJPyaHs", + "target": "build/videos.d/aufspringen.webm", + "from": "00:04.867", + "to": "00:35.900", + "crop": {"x": 568, "y": 124, "w": 898, "h": 784}, + "scale": {"h": 320} +}] diff --git a/onlineTraining/clips.d/machs/groups/breakdance.json b/onlineTraining/clips.d/machs/groups/breakdance.json new file mode 100644 index 0000000..8f2cd8e --- /dev/null +++ b/onlineTraining/clips.d/machs/groups/breakdance.json @@ -0,0 +1,7 @@ +[{ + "source": "https://www.youtube.com/watch?v=TaZ9WbXTSCU", + "target": "build/videos.d/machs/groups/breakdance.webm", + "from": "00:52.533", + "to": "01:09.383", + "crop": {"x": 592, "y": 224, "w": 750, "h": 558} +}] diff --git a/onlineTraining/clips.d/machs/groups/wechselVierfuesslerKrebs.json b/onlineTraining/clips.d/machs/groups/wechselVierfuesslerKrebs.json new file mode 100644 index 0000000..7be7dfc --- /dev/null +++ b/onlineTraining/clips.d/machs/groups/wechselVierfuesslerKrebs.json @@ -0,0 +1,7 @@ +[{ + "source": "https://www.youtube.com/watch?v=JtTqpFKE8Ow", + "target": "build/videos.d/machs/groups/wechselVierfuesslerKrebs.webm", + "from": "00:05.500", + "to": "00:09.900", + "crop": {"x": 546, "y": 324, "w": 762, "h": 546} +}] diff --git a/onlineTraining/clips.d/sockenkreisel.json b/onlineTraining/clips.d/sockenkreisel.json new file mode 100644 index 0000000..d6523cb --- /dev/null +++ b/onlineTraining/clips.d/sockenkreisel.json @@ -0,0 +1,6 @@ +[{ + "source": "https://www.youtube.com/embed/HZ7Y41JVoZ8", + "target": "build/videos.d/sockenkreisel.webm", + "from": "05:21.240", + "to": "05:34.880" +}] diff --git a/onlineTraining/clips.d/taiso/beingraetche.json b/onlineTraining/clips.d/taiso/beingraetche.json new file mode 100644 index 0000000..286d0fd --- /dev/null +++ b/onlineTraining/clips.d/taiso/beingraetche.json @@ -0,0 +1,6 @@ +[{ + "source": "https://www.youtube.com/watch?v=oFBJH1dddGg", + "target": "build/videos.d/taiso/beingraetche.webm", + "from": "01.368", + "to": "06.774" +}] diff --git a/onlineTraining/clips.d/taiso/bogenschuetze-schritt.json b/onlineTraining/clips.d/taiso/bogenschuetze-schritt.json new file mode 100644 index 0000000..548c6fc --- /dev/null +++ b/onlineTraining/clips.d/taiso/bogenschuetze-schritt.json @@ -0,0 +1,6 @@ +[{ + "source": "https://www.youtube.com/watch?v=aH8qOAOerCA", + "target": "build/videos.d/taiso/bogenschuetze-stand.webm", + "from": "00:32.240", + "to": "00:58.480" +}] diff --git a/onlineTraining/clips.d/taiso/bogenschuetze-stand.json b/onlineTraining/clips.d/taiso/bogenschuetze-stand.json new file mode 100644 index 0000000..de0dab6 --- /dev/null +++ b/onlineTraining/clips.d/taiso/bogenschuetze-stand.json @@ -0,0 +1,6 @@ +[{ + "source": "https://www.youtube.com/watch?v=aH8qOAOerCA", + "target": "build/videos.d/taiso/bogenschuetze-stand.webm", + "from": "00:08.680", + "to": "00:28.320" +}] diff --git a/onlineTraining/clips.d/taiso/schultereindrehen.json b/onlineTraining/clips.d/taiso/schultereindrehen.json new file mode 100644 index 0000000..f394655 --- /dev/null +++ b/onlineTraining/clips.d/taiso/schultereindrehen.json @@ -0,0 +1,6 @@ +[{ + "source": "https://www.youtube.com/watch?v=uOmLFzjECP4", + "target": "build/videos.d/taiso/schultereindrehen.webm", + "from": "02.119", + "to": "17.033" +}] diff --git a/onlineTraining/clips.d/taiso/sumo.json b/onlineTraining/clips.d/taiso/sumo.json new file mode 100644 index 0000000..70638cf --- /dev/null +++ b/onlineTraining/clips.d/taiso/sumo.json @@ -0,0 +1,6 @@ +[{ + "source": "https://www.youtube.com/embed/zDj1Yf4d07I", + "target": "build/videos.d/taiso/sumo.webm", + "from": "03.103", + "to": "20.804" +}] diff --git a/onlineTraining/clips.json b/onlineTraining/clips.json new file mode 100644 index 0000000..bb0416f --- /dev/null +++ b/onlineTraining/clips.json @@ -0,0 +1,79 @@ +[ +{ + "source": "https://www.youtube.com/embed/6wcWZZw6RGk", + "target": "videos.d/hopserlauf.webm", + "from": "01:09.000", + "to": "01:24.833", + "crop": {"x": 581, "y": 32, "w": 1309, "h": 1018} +}, +{ + "source": "https://www.youtube.com/embed/6wcWZZw6RGk", + "target": "videos.d/kniehebelauf.webm", + "from": "01:24.917", + "to": "01:39.542", + "crop": {"x": 581, "y": 32, "w": 1309, "h": 1018} +}, +{ + "source": "https://www.youtube.com/embed/6wcWZZw6RGk", + "target": "videos.d/anfersen.webm", + "from": "01:40.208", + "to": "01:54.625", + "crop": {"x": 581, "y": 32, "w": 1309, "h": 1018} +}, +{ + "source": "https://www.youtube.com/embed/6wcWZZw6RGk", + "target": "videos.d/***REMOVED***Eingang-kniebeuge.webm", + "from": "03:45.250", + "to": "04:05.167", + "crop": {"x": 581, "y": 32, "w": 1309, "h": 1018} +}, +{ + "source": "https://www.youtube.com/embed/6wcWZZw6RGk", + "target": "videos.d/indianer.webm", + "from": "04:36.917", + "to": "05:05.458", + "crop": {"x": 581, "y": 32, "w": 1309, "h": 1018} +}, +{ + "source": "https://www.youtube.com/watch?v=oFBJH1dddGg", + "target": "videos.d/taiso/beingraetche.webm", + "from": "01.368", + "to": "06.774" +}, +{ + "source": "https://www.youtube.com/watch?v=uOmLFzjECP4", + "target": "videos.d/taiso/schultereindrehen.webm", + "from": "02.119", + "to": "17.033" +}, +{ + "source": "https://www.youtube.com/embed/zDj1Yf4d07I", + "target": "videos.d/taiso/sumo.webm", + "from": "03.103", + "to": "20.804" +}, +{ + "source": "https://www.youtube.com/embed/HZ7Y41JVoZ8", + "target": "videos.d/handtuchzug.webm", + "from": "02:37.880", + "to": "02:54.200" +}, +{ + "source": "https://www.youtube.com/embed/HZ7Y41JVoZ8", + "target": "videos.d/sockenkreisel.webm", + "from": "05:21.240", + "to": "05:34.880" +}, +{ + "source": "https://www.youtube.com/embed/jxt1gagi6C4", + "target": "videos.d/loecherspringen.webm", + "from": "05:01.483", + "to": "05:06.399" +}, +{ + "source": "https://www.youtube.com/embed/jxt1gagi6C4", + "target": "videos.d/loecherlaufen.webm", + "from": "05:44.633", + "to": "06:17.949" +} +] diff --git a/onlineTraining/css/cwsvJudo-revealjs.css b/onlineTraining/css/cwsvJudo-revealjs.css new file mode 100644 index 0000000..3a8e270 --- /dev/null +++ b/onlineTraining/css/cwsvJudo-revealjs.css @@ -0,0 +1,5 @@ +.reveal .slides > section{ + background: rgb(60, 60, 60); + background: rgba(60, 60, 60, 0.4); +} + diff --git a/onlineTraining/guertel.md b/onlineTraining/guertel.md new file mode 100644 index 0000000..82ed2db --- /dev/null +++ b/onlineTraining/guertel.md @@ -0,0 +1,16 @@ +- springen über den gürtel + - varianten: + - vor und zurück + - Skifahren + - seitlich hin und her + - seitlich von einem bein aufs andere + - in der Standwaage + - hinweise: + - mit zwischenhopsern ist es ersmmal einfacher +- hockwenden über den Gürtel + - Gürtel zwischen den Händen und mit den Füßen wechselseitig des + Gürtels springen +- superman über den Gürtel + - auf einer Seite des Gürtel den Superman und den Raketen + ausweichen indem man über den Gürtel rollt und so die Seiten + wechselt diff --git a/onlineTraining/ideen.d/bambamRaetsel.md b/onlineTraining/ideen.d/bambamRaetsel.md new file mode 100644 index 0000000..86af3de --- /dev/null +++ b/onlineTraining/ideen.d/bambamRaetsel.md @@ -0,0 +1,72 @@ +# Bam-Bam Rätsel + +Geklaut bei: [https://stopkidsmagazin.de](https://stopkidsmagazin.de) + +Nachdem stopkids Redakteurin Sophia in ihrem Rätsel des Monats für +Februar 2013 einige Bam-Bam Rätsel Aufgaben stellte, kamen wir auf die +Idee doch gleich eine ganze Seite mit solchen Rätseln zu machen. + +Aber was ist ein Bam-Bam Rätsel? + +In einem Satz stehen 2 Bam-Bams, die durch ein und dasselbe Wort +ersetzt werden müssen. Dieses Wort hat gleich zwei unterschiedliche +Bedeutungen. + +Beispiel: + + Heute muss ich noch meinen neuen Kleiderschrank zusammenbauen und + einige Bam-Bam Bam-Bam! + +Das gesuchte Bam-Bam wär hier Schrauben und schrauben. Der Satz würde +also richtig gelöst so aussehen: + + Heute muss ich noch meinen neuen Kleiderschrank zusammenbauen und + einige Schrauben schrauben! + +1. Bevor wir die Bam-Bam Kuchen backen können, müssen wir das Mehl gut +durch Bam-Bam! +2. Nach einem starken Gewitter stellte der Händler fest, dass alles +unter Wasser stand. Sogar die Lagerräume, wo seine Bam-Bam Bam-Bam. +3. Vorhin musste ich sehr lachen, weil es so lustig aussah, wie meine +Katze vor einem Bam-Bam Bam-Bam. +4. Die Hasenmutter sagt mahnend zu ihren kleinen. „Auf dieser Wiese +gibt es viele Bam-Bam in die ihr herein Bam-Bam könnt!“ +5. In einer Durchsage mahnt eine Stewardess die Passagiere, sie sollen +doch auf ihren Bam-Bam Bam-Bam bleiben. +6. Die Mieterin hatte wiederholt ihre Miete nicht bezahlt. Deshalb +forderte der Hausbesitzer sie jetzt auf, dass sie ihre Bam-Bam Bam-Bam. +7. Lorenz kauft sich die Hausnummern für sein neues Haus im Baumarkt, +denn dort muss er weniger für die Bam-Bam Bam-Bam. +8. Wem es unter Palmen zu heiß ist, der sollte seinen nächsten Urlaub +unter Bam-Bam Bam-Bam. +9. Erzählt ein Ranger von seinem letzten Abenteuer: "Es war ganz schön +anstrengend und ich bin durch viele Bam-Bam Bam-Bam!" +10. Luka machte bei einem Reiseunternehmen eine Bustour. Der Service +war schlecht und es gab keine warme Mahlzeit. So konnte er erst wieder +in Bam-Bam Bam-Bam. +11. Lorenz fiel im Fischladen auf, wie streng doch die +Bam-Bam Bam-Bam. +12. Im Gefängnis sagt ein Gefangener zum anderen: "Ich weiß jetzt, wo +wir am besten ausbrechen können. Lass uns einfach zwischen den Bam-Bam +Bam-Bam!" +13. Hubert ist entsetzt. Er sah eine schwarze Masse von 1000 Bam-Bam +auf ihn zu Bam-Bam. +14. Der Dieb wurde an den Bahnschienen festgenommen, weil er dort den +verbauten Bam-Bam Bam-Bam. + +### Lösungen der Bam-Bam Rätsel + +1. Sieben - sieben +2. Waren - waren +3. Floh - floh +4. Fallen - fallen +5. Sitzen - sitzen +6. Räume - räume +7. Zahlen - zahlen +8. Buchen - buchen +9. Gefahren - gefahren +10. Essen - essen +11. Rochen - rochen +12. Türmen - türmen +13. Fliegen - fliegen +14. Stahl - stahl diff --git a/onlineTraining/ideen.d/jaNeinGeschichten.md b/onlineTraining/ideen.d/jaNeinGeschichten.md new file mode 100644 index 0000000..6aa118c --- /dev/null +++ b/onlineTraining/ideen.d/jaNeinGeschichten.md @@ -0,0 +1,394 @@ +Geklaut unter anderem bei: + +- [https://stopkidsmagazin.de](https://stopkidsmagazin.de) + + + +## Ja/Nein-Geschichten (Black Storys - Rätselgeschichten) + +Bei diesen Rätseln geht es um rätselhafte Geschehnisse, wie Morde oder +ähnliches, die nur mit Kriminalistischen Spürsinn gelöst werden können. + +Normalerweise ist es ein Spiel, bei dem eben ein solches Rätsel anderen +Mitspielern gestellt wird. Diese müssen sich dann, Stück für Stück, wie +Detektive mit Fragen an die Lösung heran arbeiten. Dabei darf der +Rätselsteller nur mit JA, NEIN oder UNWICHTIG Antworten! Das geht dann +so lange, bis jemand die Lösung gefunden hat. + +### Teil I + +1. In einem Raum hängt ein Mann tot an einem Seil. Er hat sich erhängt. +Doch die Polizei konnte sich einfach nicht erklären, wie der Mann das +alleine geschafft haben soll. Denn der Raum war völlig leer. Nur auf +dem Boden fanden die Polizisten eine große Wasserpfütze. +2. Eine Frau kauft sich am Morgen in einem Schuhgeschäft neue Schuhe. +Doch schon am Abend muss sie diesen kauf mit ihrem Leben bezahlen! +3. In einem Raum liegen M & M tot in einer großen Wasserlache auf dem +Boden. Um sie herum liegen jede Menge Scherben verteilt. Das einzige +Fenster von dem Raum ist geöffnet und draußen tobt ein heftiger Sturm! +4. Der kleine Lukas hat einen blauen Luftballon. Er bläst ihn auf und +verknotet ihn sorgfältig. Eine kurze Zeit spielt er auch mit dem +Ballon, bevor er mit seiner Mutter die Wohnung verlässt. Als beide nach +2 Stunden wieder kommen, sehen sie erstaunliches. Der Luftballon liegt +nicht mehr auf dem Boden sondern schwebt 5 cm darüber! +5. Ein Mann liegt Tod auf der Straße. Neben ihm liegt ein ungeöffnetes +Paket. +6. Tom lebt nicht mehr. Er starb in dem Augenblick, als er gerade etwas +essen wollte. Auf ihm liegt eine Metallstange! +7. Ein Taucher mit Taucherausrüstung liegt tot in einem abgebrannten +Wald. +8. Ein Mann liegt nackt vor einem großen Berg mit einem abgeknickten +Streichholz in der Hand. +9. Hätte der große Bruder das Eis und nicht den Kuchen genommen, würde +der kleine Bruder jetzt noch leben. +10. Nur weil ein Mann gepinkelt hat ist ein anderer Mann gestorben! + + +#### Lösungen zu Teil I + +1. Der Mann hat sich einen großen Eisblock gekauft, ist auf ihn hinauf +geklettert und hat sich dann die Schlinge um den Hals gelegt. Als der +Eisblock dann geschmolzen war, erhängte sich der Mann und starb! +2. Die Frau arbeitete als Assistentin eines Messer- und Axt Werfers in +einem Zirkus. Der Messerwerfer hatte bei seinen Auftritten immer die +Augen verbunden, da er die Größe seiner Assistentin genau kannte. So +konnte er immer blind seine Messer und Äxte knapp daneben werfen. Doch +leider hatte die Frau sich Schuhe mit sehr hohen Absätzen gekauft und +war so ein ganzes Stück größer als sonst. Deshalb traf der Messerwerfer +sie mit einer Axt tödlich am Kopf! +3. M & M waren zwei Goldfische, die in einem Glas lebten. Dieses stand +auf der Fensterbank. Der starke Sturm drückte das Fenster auf und so +stürzte das Goldfischglas auf dem Boden und zerbrach. Daher die vielen +Scherben und das Wasser auf dem Boden. Und da Fische ohne Wasser nicht +leben können, erstickten sie einfach! +4. Als Mutter und Sohn unterwegs waren, platzte ein Wasserrohr und +überschwemmte so die ganze Wohnung. Das Wasser stand genau 5 cm hoch +und so schwamm der Luftballon auf dem Wasser und lag nicht mehr auf dem +Boden! +5. Der Mann war Fallschirmspringer und ist aus einem Flugzeug raus +gesprungen. Doch sein Fallschirm öffnete sich nicht und so starb er. In +dem ungeöffneten Paket war sein Fallschirm. +6. Tom war eine kleine Maus, die in einer Mausefalle gestorben ist. +Grade als er von dem Käse naschen wollte, schnappte die Falle zu. Die +Metallstange ist ein Teil dieser Falle! +7. Der Taucher schwamm in einem See. Plötzlich kam ein Löschflugzeug +und saugte Wasser aus dem See um damit einen Waldbrand zu löschen. Der +arme Taucher wurde mit eingesaugt und dann über den brennenden Wald +fallen gelassen! (Diese Geschichte soll tatsächlich einmal so passiert +sein) +8. Ein Ballon mit 3 Personen an Bord flog auf einen Berg zu. Doch er +war zu schwer und konnte nicht höher aufsteigen. Um nicht gegen den +Berg zu knallen warfen die Insassen alles an Ballast ab. Sogar noch +ihre Kleidung. (Deshalb war der tote auch Nackt) Aber noch immer stieg +der Ballon nicht höher. In ihrer Not beschlossen sie dann, dass einer +aus dem Ballon springen muss, um die beiden anderen zu retten. Und das +losten sie dann mit Streichhölzern aus. Der mit dem abgeknickten +Streichholz musste leider springen! +9. Der Kuchen stand auf dem Küchentisch und das Eis lag in der +Tiefkühltruhe. Als der kleine Bruder sich ein Eis holen wollte, viel er +in die Tiefkühltruhe und erfror dort. Wenn der große Bruder sich also +auch ein Eis geholt hätte, würde der kleine Bruder noch leben! +10. Der Mann stand auf einen Berg und hat dort hinunter gepinkelt und +dabei einen großen Stein getroffen, der ganz locker an der steilen +Böschung lag. Der Pinkelstrahl brachte den Stein ins Rollen und so +stürzte er schließlich auf den Kopf des anderen Mannes, der gerade +unten vorbei lief. + + +### Teil II (11-20) + +11. Zwei Männer sind mit dem Auto auf einer nur wenig befahrenen +Landstraße unterwegs. Wäre der Nebel nicht so dicht gewesen, hätten +beide jetzt nicht so schlimme Kopfschmerzen. FRAGE: Warum hatten die +Männer solche Kopfschmerzen? +12. Vor einer Telefonzelle liegt ein Toter Mann. Er trägt Gummistiefel +und an beiden Armen befinden sich schwere Schnittverletzungen. Klar ist +nur, dass der Mann verblutet ist. FRAGE: Was genau ist hier passiert? +13. Im London sitzt ein Mann im Highpark und liest in der Zeitung, dass +Frau Schnützelwitz beim Skifahren in der Schweiz Tod im Schnee +aufgefunden worden ist. Der Mann kennt die Frau nicht. Trotzdem ist er +sich aber sicher, dass es ein Mord gewesen war. Er geht zu der nächsten +Polizeistelle und fragt nach. Die Polizei bestätigt ihm, dass Frau +Schnützelwitz absichtlich getötet wurde! FRAGE: Woher wusste der Mann, +dass es ein Mord gewesen war? +14. Und als die Musik aufhörte zu spielen, starb er. FRAGE: Aber warum? +15. Ein Bauer steht auf einem Feld vor einem Turm und weiß, dass er +gleich sterben wird. FRAGE: Warum? +16. Joe kommt nach Hause in seinen Wohnwagen, stellt sich vor dem +Spiegel und erschießt sich. Auf dem Boden liegen Sägespäne herum. Hätte +er sie gesehen wäre er noch am Leben und hätte sich nicht erschossen. +17. Der Wasserkocher ist aus und eine Frau stirbt. FRAGE: Warum? +18. Eine Frau stürzte sich von einem Hochhaus. Doch kurz bevor sie +aufschlug bereute sie diesen Schritt. FRAGE: Aber wieso tat sie das? +19. Eine Frau trifft auf der Beerdigung ihrer Mutter einen Mann, den +sie noch nie zuvor gesehen hat. Einigen Wochen später ermordet sie ihre +Schwester. FRAGE: Aber warum? +20. Eine Frau geht in eine Bar und bestellt ein Glas Wasser. +Der Barkeeper holt ein Gewehr raus und schießt von hinten. FRAGE: Warum +das? + + +### Lösungen zu Teil II + +11. Beide Männer fuhren mit ihren eigenen Autos aufeinander zu. Da der +Nebel so dicht war, streckten beide ihre Köpfe aus dem Fenster um den +Mittelstreifen der Straße besser sehen zu können. Und so kam es, das +sie schließlich mit ihren Köpfen zusammen stießen. Logisch, dass man +davon schlimme Kopfschmerzen bekommen kann! +12. Der Mann war Angler und prahlte in einem Telefongespräch über die +Größe seines gefangenen Fisches. Dabei breitete er spontan beide Arme +aus und durchbrach mit ihnen die Glasscheiben der Telefonzelle. So kam +er zu den Schnittverletzungen, die so schwer waren, dass er schließlich +daran verblutete. +13. Der Mann kennt den Mörder. Es ist der Ehemann der Frau. Mit ihm +arbeitet er in London in einem Reisebüro zusammen. Herr Schnützelwitz +hatte für sich und seine Frau Tickets für eine Reise in die Schweiz +besorgt. Dem Mann kam es aber seltsam vor, dass Herr Schnützelwitz zwei +Tickets für die Hinfahrt, für die Rückfahrt aber nur ein Ticket besorgt +hatte. Deshalb kam der Mann auf die Idee, dass Herr Schnützelwitz der +Mörder gewesen war! +14. Der Mann war Akrobat und lief mit verbundenen Augen auf einem +Hochseil herum. Um die Spannung zu steigern, spielte ein Musiker auf +einer Trommel die passende Musik dazu. Da der Akrobat nicht sehen +konnte, wann er auf der anderen Seite des Seiles ankommt, verließ er +sich ganz auf die Trommel. Denn wenn diese verstummen würde, wäre er +sicher auf der anderen Seite angekommen. Leider wurde der Trommler +während seiner Vorführung etwas abgelenkt, so dass er zu früh mit dem +Trommeln aufhörte. Der Akrobat dachte so, er wäre im Ziel und als er +die Binde abnehmen wollte, stürzte er in die Tiefe und starb! +15. Bauer und der Turm sind Schachfiguren in einem Schachspiel. Der +Turm schlägt den Bauern und so stirbt er! +16. Joe arbeitete im Zirkus, wo er eine Attraktion wegen seiner sehr, +sehr kleinen Größe war. Als er nicht zuhause war, ging jemand in seinen +Wohnwagen, der dringend Holz brauchte. Deshalb sägte der unbekannte +etwas Holz von dem Schrank ab, an dem der Spiegel hing. Als Joe später +in den Spiegel sah, der jetzt viel niedriger hing als sonst, da glaubte +er, dass er gewachsen sei. Aus Angst vor einer möglichen +Arbeitslosigkeit erschoss sich dann. +17. Der Wasserkocher funktioniert nicht, da er kaputt ist. Daraufhin +geht die Frau zum Gasherd und möchte dort ihren Tee kochen, denn sie +hat Schnupfen. Der ganze Raum ist schon voller Gas, da jemand vergas +den Gas Schalter aus zu drehen. Weil sie Schnupfen hat, riecht die Frau +das Gas nicht. Sie zündet ein Streichholz an und die Küche explodiert. +Tod! +18. Die Frau war, so dachte sie die einzige überlebende eines +Atomkriegs. Nach ein paar Jahren beschloss sie sich das Leben zu +nehmen. Als sie sprang und am ersten Stockwerk vorbei flog klingelte +dort ein Telefon. Es gab also außer ihr mindestens noch einen weiteren +Menschen. Deshalb bereute sie ihre Entscheidung! +19. Die Frau hatte sich unsterblich in diesen Mann verliebt. Sie tötete +ihre Schwester in der Hoffnung, diesen Mann auch auf ihrer Beerdigung +wieder zutreffen. +20. Dieses Mal ist es kein Mord und kein schlechtes Ende! Die Frau +hatte Schluckauf und der Mann wollte sie nur erschrecken, damit der +Schluckauf aufhört. + + +### Teil III (21-30) + +21. Ein Mann geht auf eine Party und trinkt einige Gläser Punsch. Weil +er früh aufstehen muss verlässt er als erster die Party wieder. Am Tag +darauf hört er mit Entsetzen, dass alle seine Kollegen an vergiftetem +Punsch gestorben sind. Er selbst aber hatte gar nichts bemerkt und auch +keine Beschwerden gehabt. FRAGE: Wieso ist ihm nichts passiert? +22. Ein Mann mit dunkler Brille und Hut steigt in einen Zug und fährt +von A nach B. Zwei Wochen später tritt er die Rückfahrt an. Als der Zug +durch einen Tunnel fährt, stürzt er sich aus dem Zug. Hätte der Mann in +einem Raucher Abteilung gesessen, wäre er noch am Leben. FRAGE: Was ist +passiert? +23. Ein Mann fuhr spät nachts mit seinem Auto auf der Autobahn. Es war +ein langer Tag und der Mann hatte viel um die Ohren gehabt. Deshalb +ließ er sich leise vom Radio berieseln. Plötzlich, mitten auf der A +utobahn, fährt er auf den Pannenstreifen, nimmt eine Waffe aus dem +Handschuhfach und erschießt sich damit. FRAGE: Was ist geschehen? +24. Ein Berliner ist aus dem 15. Stock eines Hochhauses gefallen und +dann noch am Boden von einem LKW überfahren worden. Trotzdem wurde +dabei kein Mensch verletzt. FRAGE: Wieso? +25. Ein Mann steht morgens in der früh auf, lässt die Fensterläden zu +und stellt das Radio an. Dabei erfährt er von einem schlimmen Unglück, +bei dem 100 Menschen gestorben sind. Er geht ein paar Treppen hoch ins +oberste Stockwerk und sieht dann sofort, dass er allein für das Unglück +verantwortlich ist. FRAGE: Woran erkennt er das? +26. Ein Mann wurde erschossen. Trotzdem wurde der Schütze nicht +bestraft. FRAGE: Warum? +27. Ein Mann kommt in eine Bibliothek und nimmt sich ein Buch aus dem +Regal. Er blättert es durch und findet einen Zehn-Euro-Schein, den er +behält. Aber er freut sich nicht darüber. FRAGE: Warum? +28. Einer Tätlichkeit folgt ein Duell. Der Schütze schießt und trifft +den anderen am Kopf. Trotzdem bleibt der Getroffene unverletzt und +freut sich sogar. FRAGE: Aber warum denn das? +29. Ein Mann bringt seine Frau in der 9. Etage um und geht hinunter in +das Erdgeschoss. Dort merkt er, dass er die Tatwaffe vergessen hat. +Deshalb fährt er mit dem Aufzug in die 3. Etage und geht den Rest zu +Fuß. FRAGE: Aber warum geht der den Rest zu Fuß? +30. Ein Mann geht in einen Laden und kauft etwas. Gleich nach Verlassen +des Ladens wirft er den halben Inhalt weg. Aber warum tut er das? + +#### Lösungen zu Teil III + +21. Das Gift war mit in den Eiswürfeln eingefroren. Da der Mann als +erster ging waren diese noch nicht geschmolzen. Später aber als alles +Eis geschmolzen war wurde das Gift freigesetzt und hat so zu der +Vergiftung der restlichen Party Gäste geführt. +22. Der Mann war blind und ist zu einer Augenoperation gefahren. Man +sagte ihm wenn er die Augenbinde abnimmt, kann er wieder sehen. Doch +der Mann nahm ausgerechnet im Tunnel die Augenbinde herunter. Da um ihn +alles dunkel war konnte er nichts sehen und dachte, die OP war sinnlos +gewesen. In einem Raucher Abteil hätte er das glühen der Zigaretten +gesehen. Doch so sah der Mann nichts und stürzte sich aus Frust aus +dem Zug! +23. Der Mann war Radiomoderator und hatte eigentlich Nachtdienst. +Seine Sendung kam aber diesmal vom Band. Statt zu moderieren fuhr er +nach Hause und ermordete seine Frau. Auf dem Rückweg hörte er seine +eigene aufgezeichnete Sendung im Radio an. Plötzlich aber verstummte +das Radio. Das Band mit der Aufzeichnung war gerissen. Damit war sein +Alibi natürlich geplatzt. In seiner Verzweiflung erschießt er sich. +24. Es war kein Mensch sondern ein "Berliner" zum Essen. +25. Der Mann ist Leuchtturmwärter. Während er geschlafen hat, ist das +Licht erloschen. Ein vorbeikommendes Schiff lief deshalb auf Grund. +26. Der Mann war ein Schauspieler in einem Film. Der Schütze sollte ihn +laut Drehbuch erschießen. Unglücklicherweise war die Pistole +tatsächlich geladen, wovon der Schütze allerdings nichts wusste. +27. Der Mann war der Autor dieses Buches und hat den Schein selbst vor +einem Jahr in das Buch reingelegt. Dass er jetzt immer noch drin liegt, +ist ein Zeichen dafür, dass das Buch während dieser Zeit niemand +gelesen hat. Deshalb war er traurig. +28. Die Tätlichkeit fand beim Fußball im Strafraum statt. Es gibt +Elfmeter. Der Torwart kriegt den Ball an den Kopf, freut sich aber, +dass er den Elfmeter gehalten hat. +29. Der Mann war Kleinwüchsig und konnte deshalb im Aufzug nur den +Knopf zum 3. Stockwerk erreichen. +30. Der arme Mann hat nur noch ein Bein und hat deshalb von dem Paar +Schuhe, das er sich gekauft hat, einen weggeworfen. + +### Teil IV (31-40) + +31. Ein toter Mann liegt in der Nähe eines Haufens Steine. Auf ihm +liegen ein Buch und ein Käfer. Was ist passiert? +32. Der Inspektor beugte sich über die Leiche und wunderte sich. +So etwas Merkwürdiges hatte er noch nie gesehen. Aber was ist passiert? +33. Hätte Karl eine andere Frisur gehabt wäre er noch am Leben. Aber +warum? +34. Ein Vater und ein Sohn gerieten in einen Autounfall. Dabei wurde +der Sohn schwer verletzt. Der Vater bringt den Sohn sofort in eine +Notfallklinik. Der zuständige Chirurg sieht den verletzten Jungen und +sagt: "Ich kann diesen Jungen nicht verarzten. Er ist mein Sohn!" Aber +wie kann das sein? +35. Der eine Mann blutete und war tot, der andere nicht. Es ist ein +Schachspiel zu sehen und ein Revolver. Aber was ist hier geschehen? +36. Ein Mann kauft sich eines Tages Bananen in einer Verpackung. Als er +sie Zuhause öffnet, stirbt er. Aber warum? +37. Ein Mann macht ein Spaziergang in einer Wüste. Nach kurzer Zeit +hört er eine Explosion und stirbt. Frage: Warum ist er gestorben obwohl +er unverletzt war? +38. Ein Mann kommt in eine Bar. Er hat eine Gabel dabei. Als er geht, +muss er für seine Getränke nichts bezahlen und trotzdem ist der +Barbesitzer sehr zufrieden. Wieso denn das? +39. Ein Mann, der sich sein ganzes Leben verständigen konnte, kann auf +einmal nicht mehr sprechen. 8 Wochen später kann er wieder sprechen. +Ein Wunder oder was ist da passiert? +40. Eine Frau und ihr Bruder haben am gleichen Tag Geburtstag. Sie sind +wirkliche Geschwister (nicht adoptiert). Sie sind Zwillinge, aber +sind nicht gleich alt. Wie geht das? + +#### Lösungen zu Teil IV + +31. Der Mann wollte anhand eines Handbuches seinen VW Käfer reparieren. +Deshalb hatte er ihn aufgebockt und auf Steinen gestellt. Leider ist +das Auto von den Steinen runter gerutscht und so wurde er zerquetscht. +32. Der Tote war Raucher. Seine Frau wollte, dass er aufhört und so hat +er es ihr versprochen, heimlich jedoch immer weiter geraucht. Die Frau +kam dahinter und als Rache beklebte sie ihn mit Nikotinpflastern den +ganzen Körper voll. An der Überdosis Nikotin starb der Mann +schließlich. +33. Karl hatte eine Glatze. Beim Bergwandern wurde sein Kopf von einem +Bartgeier für einen Stein gehalten. Der Vogel schmiss seine soeben +gefangene Schildkröte auf den Kopf des Mannes, um an das Fleisch der +Schildkröte heran zu kommen. +34. Es ist die Mutter, die beruflich als Chirurgin tätig ist! +35. Die beiden Männer waren an Bord eines U-Bootes, was gekentert war. +Der Atemvorrat reichte nur noch für einige Stunden. In dem Revolver war +nur noch eine Kugel Munition. So spielten sie darum, wer sich +erschießen durfte, da das Ersticken eines Menschen der qualvollere Tod +war. +36. In der Verpackung war eine australische Bananenspinne drin und als +er sie öffnete kroch sie raus. Später stach die giftige Spinne den Mann +und dieser starb durch das Gift der Spinne. +37. In der Nähe wo der Mann Spazieren ging, war ein Testgelände für +Atomsprengungen. Eine Atombombe wurde in großer Höhe gezündet und +löste einen sogenannten EMP (Elektromagnetischer Impuls) aus. Die +lässt sämtliche Schaltkreise aller elektrischen Geräte durchschmoren. +Der Mann hatte ein Herzschrittmacher, der vom EMP betroffen war und der +Schaltkreis brannte durch. Das Herz hörte auf zu schlagen und so starb +er. +38. Es handelt sich um den Klavierstimmer, der mit seiner Stimmgabel +das Klavier in der Bar stimmte. +39. Der Mann war stumm und konnte sich nur mit Hilfe der +Gebärdensprache verständigen. Bei einem Skiunfall brach er sich aber +beide Arme, so dass er nicht mehr sprechen konnte. Nachdem der Gips +wieder entfernt war, konnte er sich wieder unterhalten. +40. Es ist Zufall, dass sie am gleichen Tag geboren sind. Zwillinge +sind sie nur vom Sternzeichen her. + + +### Teil V (41-50) + +41. Gerade als sich die Einbrecher sicher fühlten kam die Polizei! +Frage: Warum stand die Polizei vor dem Haus? +42. Ein Mann steht vor einem rotem Haus und weint. Warum? +43. Ein Mann wohnt in der 20. Etage. Wenn er nach Hause kommt und es +hat geregnet, fährt er mit dem Fahrstuhl bis zu seiner Wohnung. Schien +jedoch die Sonne, fährt er nur bis zur 17. Etage und nimmt von da ab +die Treppe. Warum? +44. Ein Mann steigt in einen Zug. Gegenüber von ihm sitzt eine Frau, +die gerade ihre Handschuhe auszieht. Eine Stunde später wird der Mann +verhaftet, jedoch muss ihn die Polizei am selben Tag wieder gehen +lassen. Was ist passiert? +45. S und H gingen in ein Lokal und bestellen Flamingo Fleisch. Nachdem +sie den ersten Bissen zu sich genommen hatten, rastet S komplett aus, +lief aus dem Lokal und beging Selbstmord. Frage: Warum hat er das +getan? +46. Eine Familie aß ihre Oma löffelweise auf. Aber warum? +47. Sie war so schön. Er sah sie an und erhängte sich. Aber warum? +48. Ein Mann liegt Tot in dem Garten eines Freundes. Alles was er bei +sich hat ist ein ungeöffnetes Geburtstagsgeschenk. Was ist hier +passiert? +49. Ein Mann liegt auf einer Wiese. Er ist tot. Er trägt schwarze +Kleidung und hält eine verbrannte Karte in der Hand. Was ist hier +passiert? +50. Im 24.Stock eines Hochhauses starben ein Mann (Helmut B.) und eine Frau. (Susanne P.) Beide innerhalb derselben 24 Stunden, jedoch nicht gleichzeitig. Was ist hier passiert? + + +#### Lösungen zu Teil V + +41. Die Nachbarn des Hauses wo gerade eingebrochen wurde riefen die Polizei weil die Besitzer des Hauses immer alle Rollläden unten haben außer einen. Doch den einen haben die Einbrecher auch runter gelassen. Auf diesen Fensterladen stand aber: Hier wird gerade eingebrochen. Bitte alarmieren sie die Polizei! +42. Der Mann steht auf der Schlossallee (Monopoly) und auf der Schlossallee steht ein Hotel. Er muss jetzt teuer bezahlen weil es nicht ihm gehört. +43. Der Mann ist zu klein, um bis zu an den richtigen Etagenknopf zu kommen. Wenn er aber den Schirm dabei hat, ist das kein Problem mehr. +44. Der Mann und die Frau waren früher ein Paar. Vor vielen Jahren hat die Frau ihren eigenen Tod vorgetäuscht, indem sie sich einen Finger abgeschnitten und ihrem Mann den Mord angehängt hat, welcher dafür ins Gefängnis musste. Der Mann erkennt seine Exfrau im Zug, als er ihren fehlenden Finger bemerkt und tötet sie. Wieder freigelassen werden musste er deswegen, weil er seine Strafe für dieselbe Tat ja schon abgesessen hat. +45. S und H waren einst mit einem weiteren Mann, P, auf einer einsamen Insel gestrandet. S und P waren eng befreundet gewesen. Die Nahrung wurde mit der Zeit immer knapper und um nicht zu verhungern, beschloss H, P zu töten, um sein Fleisch zu essen. Er brachte P also um und sagte S, er habe einen Flamingo erlegt. Die beiden aßen von Ps Fleisch und S dachte, es wäre tatsächlich Flamingo Fleisch. Kurz darauf wurden S und H von einem Schiff gerettet. Einige Jahre später trafen sie sich beide in einem Lokal wieder und bestellten Flamingo Fleisch. Doch als S das Fleisch zu sich nahm, merkte er, dass es anders schmeckte als das, was er damals auf der einsamen Insel gegessen hatte. Ihm wurde sofort klar, dass er das Fleisch seines Freundes gegessen hatte. Wegen seiner starken Schuldgefühle beging er dann Selbstmord. +46. Die Familie lebte in einem Kriegsgebiet. Ihre Oma, die ihm Ausland lebte, schickte immer Geschenke, wie Lebensmittel. Einmal kam ein Paket mit Pulver und die Familie dachte, es wäre Vitaminpulver. Leider lag keine Nachricht dem Paket bei und so aßen sie das Pulver einfach auf. Erst eine Woche später kam ein Brief, in der die traurige Mitteilung über den Tot der Oma stand. Da sie eingeäschert worden war, hatte die Familie unwissentlich ihre Asche gegessen, die zuvor mit dem Paket verschickt worden war. Man hatte einfach vergessen den Brief mit in das Paket zulegen. +47. Der Mann missachtete jede Sicherheitsvorkehrung und schaute sich die Sonnenfinsternis mit bloßem Auge an. Er erblindete. Da er dies nicht ertragen konnte, nahm er sich das Leben. +48. Der Mann war ein Amerikaner und der Freund schoss leidenschaftlich gerne. Doch als der Mann durch das Gartentor kam schoss der Freund gerade und erschrak sich, als der Mann Happy Birthday sang. Der Freund schoss auf denn Mann und der war auf der Stelle Tot. +49. Der Mann war Schiedsrichter bei einem Fußballspiel. Als ein Gewitter aufzieht und er eine gelbe Karte zeigt, schlägt ein Blitz ein und weil der Blitz immer an der höchsten Stelle einschlägt, wurde der Schiedsrichter, der gerade den Arm gehoben hatte, vom Blitz getroffen und starb. +50. Susanne P. begeht den Mord an Helmut B. ihrem Ex-Mann. Sie besucht ihn in seiner Wohnung und überrascht ihn mit Sekt. Sie mischt ohne sein Wissen Strychnin hinein. Am nächsten Tag geht sie zur Arbeit aufs Polizei-Revier. Sie und ihr Kollege Peter S. werden mit dem Fall betraut. Susanne P. hüllt sich in Schweigen und da auch niemand weiß, dass sie mit dem Toten verheiratet gewesen war, lief zuerst alles gut. Am Tatort fand Peter S. zwei Sektgläser. Eines mit Lippenstiftabdruck und eines mit weißem Pulver am Boden. Er sah seine Kollegin nachdenklich an, wodurch sie sich ertappt fühlte. Susanne P. geriet in Panik, wollte flüchten, stolperte über einen Hocker der vor dem weit geöffneten Fenster stand und viel in die Tiefe. + + +### Teil VI (51-57) + +51. Ben erstach jemanden, doch starb er an den Folgen. Aber warum? +52. Eine Frau starb weil sie zu lange Telefonierte. Was ist hier passiert? +53. Zwei Frauen trinken in einer Disko immer die gleichen Kirschsäfte mit Eiswürfeln. Die Kirschsäfte sind vergiftet. Die eine Frau trinkt ihren Kirschsaft ganz langsam. In der gleichen Zeit trinkt die andere Frau ganz viele Kirschsäfte. Die langsame Trinkerin stirbt. Die schnelle Trinkerin bleibt gesund. Frage: Wieso stirbt nur die eine Frau? +54. Ein Bär geht in eine feuchte Höhle und wird kurz danach in Stücke gerissen. Frage: Was ist passiert? +55. Ein Mann geht morgens gut gelaunt zur Arbeit. Sein Büro liegt auf der 25. Etage eines Hochhauses. Im Laufe des Tages wird er auf der Straße tot aufgefunden. Frage: Was ist passiert? +56. Ein Mann liegt im Krankenhaus. Einen Tag bevor er entlassen werden soll stirbt er. Frage: Was ist passiert? +57. Eine Frau fällt aus einem 20 stöckigen Gebäude überlebt es aber. Wie hat sie überlebt? + +#### Lösungen zu Teil VI + +51. Ben war eine Biene und wollte sich wehren, doch er starb an dem Verlust des Stachels. +52. Sie hatte ihr Auto zuvor in eine Werkstatt gefahren damit der Mechaniker ihr die Reifen wechselt. Doch dieser vergaß die neuen Reifen wieder richtig fest zuschrauben. Er hatte das Auto auf dem Hof abgestellt. Aber später erinnerte er sich an seinen Fehler. Er versuchte die Frau anzurufen, doch da diese mit ihrer Freundin telefonierte war natürlich ständig besetzt. So stiegt die Frau in ihr Auto und fuhr los. Die Reifen flogen ab und die Frau baute einen Unfall bei der sie starb. +53. Das Gift war in den Eiswürfeln. Bei der langsamen Trinkerin ist das Gift mit dem schmelzen des Eises in den Kirschsaft gekommen. Bei der schnellen Trinkerin nicht! +54. Der Bär war ein Gummibär und ist in eine Mundhöhle gegangen. Dort wurde er von den Zähnen in Stücke gerissen! +55. Der Mann verkauft bruchfeste Fenster für Hochhäuser. Er wollte Kunden zeigen, dass das Glas nicht zerbricht. Er rennt mit viel Kraft gegen das Fenster, was nicht zerbricht. Jedoch bricht der ganze Fensterrahmen raus und der Mann stürzt zu Boden. +56. Es ist das Jahr 2044 und die Medikation wird über ein Computerprogramm gesteuert. Hacker sind in den Serverraum des Krankenhauses gelangt und haben die Dosen an Medizin der verschiedenen Patienten verändert. Deshalb starb der Mann. +57. Sie ist aus dem 1. Stock gefallen. diff --git a/onlineTraining/ideen.d/scherzraetsel.md b/onlineTraining/ideen.d/scherzraetsel.md new file mode 100644 index 0000000..016a69e --- /dev/null +++ b/onlineTraining/ideen.d/scherzraetsel.md @@ -0,0 +1,318 @@ +# Scherz Rätsel + +1. Wer trägt den Pelz sogar im Bett? +2. Mit welchem Ball kann man nicht spielen? +3. Worin besteht der Unterschied zwischen einem Nilpferd und einem Jägerhut? +4. Welche Brille verbessert nicht die Sicht? +5. Was ist das: Loch an Loch und hält doch? +6. Welche Brille schwitzt am meisten? +7. Welcher Mann ist Herzlos? +8. Was hat vier Beine, ohne laufen zu können? +9. Was ist klein, rot und fährt hoch und runter? +10. Wer reist ständig kostenlos um die Welt? + +11. Wer hat Hühneraugen am Kopf? +12. Was ist wärmer als ein Pelz? +13. Wo wird das meiste Heu gemäht? +14. In welche Gläser kann man am besten Wein einschenken? +15. Welcher Hund bekommt nie einen Knochen? +16. Welche Tiere können ihr ganzes Leben lang Geburtstag feiern? +17. Wie vermehren sich Igel? +18. Wodurch unterscheidet sich ein VW von Toilettenpapier? +19. Was für Steine liegen im Rein? +20. Was bekomme ich, wenn ich ein DIN-A4 Blatt in tausend Teile zerreiße? + +21. Warum kann man eine Maus nicht melken? +22. Wer liegt ständig im Bett, ohne zu schlafen? +23. Was haben ein Pferd und eine Pflaume gemeinsam? +24. Weshalb fressen schwarze Schafe weniger als weiße? +25. Wer ist in der Küche der albernste? +26. Welches ist das vernünftigste Tier? +27. Was gehört dir allein, wird jedoch meist von anderen Leuten benutzt? +28. Worin besteht der Unterschied zwischen einem Bäcker und einem Teppich? +29. Was machst du, wenn du einer Schlange begegnest? + +30. Was kann man mit 1000 Nullen machen? +31. Was macht der Storch, wenn er auf einem Bein steht? +32. Was ist das: Es steht auf der Weide, ist Blau und bellt? +33. Was ist gelb und sehr gefährlich? +34. In welchem Getränk klettert ein Tier herum? +35. Welcher Stein raucht häufig? +36. Welche Haare hat ein siebenjähriger, einäugiger und schwerhöriger Schäferhund? +37. Was ist der Unterschied zwischen einem Schaukelstuhl und einem Nadelkissen? +38. Warum haben Motorradfahrer so lange Fingernägel? +39. Seit wann haben Elefanten so lange Rüssel? + +40. Welches Laub wird immer kleiner? +41. Was ist eine Erdbeere? +42. Warum gehen so wenig Elefanten in die Universität? +43. Welcher Zahn beißt nicht? +44. Warum macht der Hahn beim krähen die Augen zu? +45. Wie kommt eine Ameise über den Fluss? +46. Was tut der Elefant wenn es regnet? +47. Wer beherrscht alle Sprachen der Welt? +48. Was fällt, ohne sich zu verletzen? +49. Was fliegt durch die Luft und macht „mus, mus“. + +50. Was rennt gegen die Kellerwand und klirrt? +51. Kannst du höher als ein Kirchturm springen? +52. Was hast du mit einer Stecknadel gemeinsam? +53. Wie feiern die Schotten den 4.Advent? +54. Was machen die Chinesen mit Cola Flaschen? +55. Welche Zeit ist es, wenn die Uhr 13 Mal schlägt? +56. Weiß wirft man es in die Luft, gelb liegt es auf dem Boden? +57. Welcher Hase läuft auf zwei Beinen. +58. Was ist blau und saust mit 10 Stundenkilometern durch die Luft? +59. Womit endet die Ewigkeit? + +60. Was kann eine Familie nicht unter Wasser tun? +61. Warum trinkt die Maus keinen Schnaps? +62. Welche Mausefalle hat fünf Buchstaben? +63. Im welchem Monat pflegt man Heu zu machen? +64. Was geht rot ins Wasser und kommt schwarz wieder raus? +65. Wie viele Elefanten passen in einem roten VW? +66. Woran erkennst du, das vier Elefanten in einem Hochhaus sind? +67. Woran kannst du erkennen, das die Elefanten dort im Kühlschrank waren? +68. Welcher Tiger lacht ständig? +69. Welcher Tiger muss in die Schule gehen? + +70. Welcher Tiger muss eine Brille tragen? +71. Welcher Tiger flieht stets? +72. Welcher Tiger beißt niemanden? +73. Welche Haare hat ein 10jähriger Junge? +74. Was ist das? Es sitzt in der Dachrinne und rasselt. +75. Was ist das? Es ist grün, hängt an der Wand und bellt. +76. Was ist der Unterschied zwischen einem Meerschweinchen und einem Computer? +77. Wie fängt man eine Fliege? +78. Wie heißt der Teufel mit Vornamen? +79. Was ist der Unterschied zwischen dem Tabellenletzten in der Bundesliga und einem Marienkäfer? + +80. Was ist der Unterschied zwischen Kaffee und Tee? +81. Warum spielen Geizkragen nie Skat? +82. Wo findet man eine Schildkröte ohne Beine? +83. Was sitzt auf dem Baum und sagt „AHA“? +84. Kennst du den Unterschied zwischen Klavier und Geige? +85. Was ergibt eine Kreuzung aus Maulwurf und Giraffe? +86. Wie nennt man einen Matrosen, der sich nie wäscht? +87. Was sind die letzten Worte eines Computerfreaks? +88. Wie nennt man einen intelligenten Toilettenbesucher? +89. Was ist der Unterschied zwischen einen Heuwagen und einer Zigarette? +90. Kennst du den Unterschied zwischen einen Bundesligatrainer und einen Elefanten? + +91. Was ist gelb und kann nicht schwimmen? +92. Was ist braun und fetzt durch den Wald? +93. Was ist durchsichtig und rennt durch den Wald? +94. Was ist gelb-schwarz und fliegt durch den Wald? +95. Welche Angst hat ein Luftballon? +96. Was fliegt durch den Wald und ruft: „Gackgack“? +97. Welche Tiere müssen mal geölt werden? +98. Was wünscht sich ein Tausendfüßler zum Geburtstag? +99. Warum sind Hunde in der Wüste so schnell und schlank? +100. Warum ist ein Kanarienvogel klein und gelb? + +101. Welche Worte hört ein Hai am liebsten? +102. Stimmt es, das es Unglück bringt, wenn dir eine schwarze Katze über den Weg läuft? +103. Wie nennen Kannibalen einen Doktor? +104. Welche Sprache spricht man in der Sauna? +105. Was macht ein Baby in der Wüste? +106. Weißt du was eine Raupe ist? +107. Was ist weiß und hüpft von Baum zu Baum? +108. Was ist schwarzweiß und hüpft von Eisscholle zu Eisscholle? +109. Was ist weiß und stört beim Essen? +110. Was ist gelb, groß und kann nicht schwimmen? + +111. In welchen Raum kann man keine Bilder aufhängen? +112. Tagsüber sitzt man drauf, nachts schläft man drin und morgens putzt man sich damit die Zähne? +113. Was ergibt eine Kreuzung aus einer Giraffe und einem Maulwurf? +114. Welches Tier kommt raus, wenn sich ein Uhu im Sand versteckt? +115. Welche Hose ist gefährlich? +116. Wie viele Erbsen passen in ein leeres Glas? +117. Was ist schwerer? Ein Kilo Gold oder ein Kilo Silber? +118. Was ist der Unterschied zwischen einem Fußballspieler und einen Fußgänger? +119. Welcher Wolf hat kein Fell? +120. Was ist beim Elefanten klein und beim Floh groß? + +121. Wer lebt von der Hand in den Mund? +122. Wer hört alles und sagt nichts? +123. Welcher Mann hat kein Gehör? +124. Wer hat Flügel, aber keine Federn? +125. Wann fällt Frauen das Abnehmen am leichtesten? +126. Was ist der Unterschied zwischen einem Beinbruch und einem Einbruch? +127. Was passiert mit einem Engel, wenn er in einen Misthaufen fällt? +128. Wer hat einen Bauch, aber keinen Rücken? +129. Wer hat einen Rücken, aber keinen Bauch? +130. Womit beginnt jede Arbeit? + +131. Welcher Stuhl hat kein einziges Bein? +132. Welches ist das einzige Geheimnis, dass Frauen bewahren können? +133. Was gibt es in einer Frauentasche nicht? +134. Welcher Biss tut nicht weh? +135. Was macht ein Glaser, wenn er kein Glas mehr zur Verfügung hat? +136. Welches Auge kann fliegen? +137. Was ist fertig und wird doch täglich neu gemacht? +138. In welchem Beutel kann man nichts tragen? +139. Welches Gewicht will keiner verlieren? +140. Wer wirft mit Geld um sich? + +141. Welche Vögel legen keine Eier, obwohl sie selbst einem Ei entschlüpft sind? +142. Was sitzt still in einer Ecke und reist doch um die ganze Welt? + +## Scherzrätsel Lösungen + +1. Der Faulpelz. +2. Mit dem Erdball. +3. Ein Nilpferd kann einen Jägerhut tragen, ein Jägerhut kein Nilpferd. +4. Die Klobrille. +5. Eine Kette. +6. Die Schweißerbrille. +7. Der Schneemann. +8. Ein Stuhl. +9. Ein Radieschen im Aufzug. +10. Der Mond. + +11. Hühner natürlich. +12. Zwei Pelze. +13. Nirgends. Man mäht Gras. +14. In Leere. +15. Der Seehund +16. Die Eintagsfliegen. +17. Sehr vorsichtig. +18. Den VW kann man gebraucht kaufen. +19. Nasse Steine. + +20. Konfetti. +21. Weil man keinen Eimer unter sie stellen kann. +22. Das Bettzeug. +23. Das PF. +24. Weil es mehr weiße als schwarze Schafe gibt. +25. Die Kichererbse. +26. Das Huhn, den es legt die Eier und wirft sie nicht. +27. Der Name. +28. Der Bäcker. Er steht um fünf auf, der Teppich darf liegen bleiben. +29. Du stellst dich hinten an. +30. 500 Toiletten. + +31. Er zieht das andere Bein hoch. +32. Eine Kuh im Trainingsanzug, die Fremdsprachen beherrscht. +33. Ein Hai im Senf Glas. +34. Im Kaffee- der Affe. +35. Der Schornstein. +36. Hundehaare. +37. Setz dich mal drauf. +38. Damit sie besser die Kurve kratzen können. +39. Seitdem es Elefanten gibt. +40. Der Urlaub. + +41. Kirsche mit Gänsehaut. +42. Weil sie das Abi nicht schaffen. +43. Der Löwenzahn. +44. Weil er es auswendig kann. +45. Sie nimmt das A weg und fliegt rüber. +46. Er wird nass. +47. Das Echo. +48. Der Regen. +49. Eine Biene im Rückwärtsgang. +50. Eine Maus mit Glasauge. + +51. Selbstverständlich, den ein Kirchturm kann nicht springen. +52. Den Kopf. +53. Sie zünden zwei Kerzen an und stellen sich vor dem Spiegel. +54. Sie trinken sie aus. +55. Zeit für die Reparatur. +56. Das Ei. +57. Der Angsthase. +58. Eine Pflaume mit Außenbordmotor. +59. Mit t. +60. Rund um eine brennende Kerze sitzen. + +61. Sie hat Angst vor dem Kater. +62. Die Katze. +63. Man macht Gras, kein Heu. +64. Glühende Kohle. +65. Vier. Zwei vorne, zwei hinten. +66. An dem Erdnussgeruch im Aufzug, +67. An den Fußspuren in der Butter. +68. Ein Lustiger +69. Ein Schulpflichtiger +70. Ein Kurzsichtiger. + +71. Ein Flüchtiger. +72. Ein Sanftmütiger. +73. Seine eigenen Haare. +74. Ein Spatz mit Schneeketten. +75. Ein Hund im Rucksack. +76. Ein Meerschweinchen wird auch sonntags gefüttert. +77. Du lockst sie auf den Heuboden und nimmst die Leiter weg. +78. Pfui! +79. Der Marienkäfer hat mehr Punkte. +80. Der Kaffee kann sich setzen und der Tee muss ziehen. + +81. Keiner will geben. +82. Da wo man sie hingelegt hat. +83. Ein Uhu mit Sprachfehler. +84. Ein Klavier brennt länger. +85. Einen Bohrturm. +86. Meerschweinchen. +87. Aus die Maus. +88. Klugscheißer. +89. An einen Heuwagen ziehen zwei Ochsen; an der Zigarette einer. +90. Elefanten können nicht fliegen! + +91. Ein Baukran! +92. Ein ferngesteuertes Schnitzel. +93. Ein Rudel Kontaktlinsen! +94. Ein Rudel Senfkörner in Lederjacken! +95. Platzangst! +96. Ein Kuckuck der Fremdsprachen kann! +97. Die Mäuse, weil sie quietschen! +98. Ein Fahrrad mit 1000 Pedalen! +99. Weil die Bäume soweit auseinander stehen! + +100. Wäre er groß und gelb, wäre er ein Postauto! +101. "Mann über Bord!" +102. Nur wenn du eine Maus bist! +103. HOT DOC +104. Schweizerdeutsch! +105. Es sucht das Ende der Sandkiste! +106. Ein gepolsterter Regenwurm! +107. Ein Doktor beim Zecken Impfen! +108. Ein Springuin! +109. Eine Schneelawine! +110. Ein Baukran! + +111. Im Weltraum! +112. Ein Stuhl, ein Bett und eine Zahnbürste! +113. Einen Bohrturm! +114. Der Sauhund! +115. Die Windhose +116. Eine Erbse. Danach ist das Glas nicht mehr leer! +117. Beides ist gleich schwer. +118. Der Fußgänger geht bei grün, der Fußballer bei rot. +119. Der Fleischwolf! +120. Das "F"! + +121. Der Zahnarzt! +122. Das Ohr! +123. Der Schneemann! +124. Das Fenster! +125. Wenn das Telefon klingelt! +126. Nach einem Beinbruch muss man liegen, nach einem Einbruch muss man sitzen! +127. Er bekommt Kotflügel! +128. Die Teekanne! +129. Ein Berg! +130. Ja mit was denn Mit "A" Natürlich! + +131. Der Fahrstuhl! +132. Ihr Alter! +133. Die Ordnung! +134. Der Imbiss! +135. Er trinkt aus der Flasche! +136. Das Pfauenauge! +137. Das Bett! +138. Im Windbeutel! +139. Das Gleichgewicht! +140. Der Scheinwerfer! + +141. Ganz einfach. Männliche Vögel! +142. Die Briefmarke! + diff --git a/onlineTraining/ideen.d/schnizeljagd.md b/onlineTraining/ideen.d/schnizeljagd.md new file mode 100644 index 0000000..27c53a4 --- /dev/null +++ b/onlineTraining/ideen.d/schnizeljagd.md @@ -0,0 +1,18 @@ +# Schnitzeljagd + +Jeder sucht in der Wohnung etwas zu einem Bestimmten Stichwort. Für +jedes Objekt, was man findet, erhält man einen Punkt. Einen extra Punkt +erhält man, wenn man der einzige ist, der die Sache gefunden hat. + +Stichpunkte: + +- etwas blaues +- etwas altes +- etwas durchsichtiges +- etwas scharfes +- etwas weiches +- etwas nasses +- etwas gesundes +- etwas spitzes +- etwas warmes +- etwas großes diff --git a/onlineTraining/images.d/seefahrt.d/Klabautermann_on_ship.jpg b/onlineTraining/images.d/seefahrt.d/Klabautermann_on_ship.jpg new file mode 100644 index 0000000..8598781 Binary files /dev/null and b/onlineTraining/images.d/seefahrt.d/Klabautermann_on_ship.jpg differ diff --git a/onlineTraining/images.d/seefahrt.d/beach-1824855.jpg b/onlineTraining/images.d/seefahrt.d/beach-1824855.jpg new file mode 100755 index 0000000..5cee9f6 Binary files /dev/null and b/onlineTraining/images.d/seefahrt.d/beach-1824855.jpg differ diff --git a/onlineTraining/images.d/seefahrt.d/beach-5960371.jpg b/onlineTraining/images.d/seefahrt.d/beach-5960371.jpg new file mode 100755 index 0000000..5a11605 Binary files /dev/null and b/onlineTraining/images.d/seefahrt.d/beach-5960371.jpg differ diff --git a/onlineTraining/images.d/seefahrt.d/bell-pepper-569070.jpg b/onlineTraining/images.d/seefahrt.d/bell-pepper-569070.jpg new file mode 100644 index 0000000..877c307 Binary files /dev/null and b/onlineTraining/images.d/seefahrt.d/bell-pepper-569070.jpg differ diff --git a/onlineTraining/images.d/seefahrt.d/bread-387842.jpg b/onlineTraining/images.d/seefahrt.d/bread-387842.jpg new file mode 100644 index 0000000..d6a9933 Binary files /dev/null and b/onlineTraining/images.d/seefahrt.d/bread-387842.jpg differ diff --git a/onlineTraining/images.d/seefahrt.d/coast-4587777.jpg b/onlineTraining/images.d/seefahrt.d/coast-4587777.jpg new file mode 100644 index 0000000..216baff Binary files /dev/null and b/onlineTraining/images.d/seefahrt.d/coast-4587777.jpg differ diff --git a/onlineTraining/images.d/seefahrt.d/karlchenKlabauter.png b/onlineTraining/images.d/seefahrt.d/karlchenKlabauter.png new file mode 100644 index 0000000..195c92a Binary files /dev/null and b/onlineTraining/images.d/seefahrt.d/karlchenKlabauter.png differ diff --git a/onlineTraining/images.d/seefahrt.d/lego-568039.jpg b/onlineTraining/images.d/seefahrt.d/lego-568039.jpg new file mode 100644 index 0000000..1048d18 Binary files /dev/null and b/onlineTraining/images.d/seefahrt.d/lego-568039.jpg differ diff --git a/onlineTraining/images.d/seefahrt.d/mast-655257.jpg b/onlineTraining/images.d/seefahrt.d/mast-655257.jpg new file mode 100644 index 0000000..f1a5cc2 Binary files /dev/null and b/onlineTraining/images.d/seefahrt.d/mast-655257.jpg differ diff --git a/onlineTraining/images.d/seefahrt.d/moon-5803873.jpg b/onlineTraining/images.d/seefahrt.d/moon-5803873.jpg new file mode 100644 index 0000000..66387b0 Binary files /dev/null and b/onlineTraining/images.d/seefahrt.d/moon-5803873.jpg differ diff --git a/onlineTraining/images.d/seefahrt.d/pirates-1693519.jpg b/onlineTraining/images.d/seefahrt.d/pirates-1693519.jpg new file mode 100644 index 0000000..cfc30d2 Binary files /dev/null and b/onlineTraining/images.d/seefahrt.d/pirates-1693519.jpg differ diff --git a/onlineTraining/images.d/seefahrt.d/pumuckl-und-der-blaue-klabauter-10-rcm1024x0u.jpg b/onlineTraining/images.d/seefahrt.d/pumuckl-und-der-blaue-klabauter-10-rcm1024x0u.jpg new file mode 100644 index 0000000..db13e76 Binary files /dev/null and b/onlineTraining/images.d/seefahrt.d/pumuckl-und-der-blaue-klabauter-10-rcm1024x0u.jpg differ diff --git a/onlineTraining/images.d/seefahrt.d/pumuckl-und-der-blaue-klabauter_sz-442700.jpg b/onlineTraining/images.d/seefahrt.d/pumuckl-und-der-blaue-klabauter_sz-442700.jpg new file mode 100644 index 0000000..d65a039 Binary files /dev/null and b/onlineTraining/images.d/seefahrt.d/pumuckl-und-der-blaue-klabauter_sz-442700.jpg differ diff --git a/onlineTraining/images.d/seefahrt.d/ship-1632613.jpg b/onlineTraining/images.d/seefahrt.d/ship-1632613.jpg new file mode 100644 index 0000000..7cbf99e Binary files /dev/null and b/onlineTraining/images.d/seefahrt.d/ship-1632613.jpg differ diff --git a/onlineTraining/images.d/seefahrt.d/ship-5822314.jpg b/onlineTraining/images.d/seefahrt.d/ship-5822314.jpg new file mode 100755 index 0000000..fd4e383 Binary files /dev/null and b/onlineTraining/images.d/seefahrt.d/ship-5822314.jpg differ diff --git a/onlineTraining/images.d/seefahrt.d/ship-701079.jpg b/onlineTraining/images.d/seefahrt.d/ship-701079.jpg new file mode 100644 index 0000000..880d9d4 Binary files /dev/null and b/onlineTraining/images.d/seefahrt.d/ship-701079.jpg differ diff --git a/onlineTraining/images.d/seefahrt.d/tortola-116939.jpg b/onlineTraining/images.d/seefahrt.d/tortola-116939.jpg new file mode 100644 index 0000000..6f33113 Binary files /dev/null and b/onlineTraining/images.d/seefahrt.d/tortola-116939.jpg differ diff --git a/onlineTraining/images.d/seefahrt.d/wave-2649217.jpg b/onlineTraining/images.d/seefahrt.d/wave-2649217.jpg new file mode 100644 index 0000000..d967037 Binary files /dev/null and b/onlineTraining/images.d/seefahrt.d/wave-2649217.jpg differ diff --git a/onlineTraining/images.d/seefahrt.d/yacht-4191578.jpg b/onlineTraining/images.d/seefahrt.d/yacht-4191578.jpg new file mode 100644 index 0000000..dfad9bd Binary files /dev/null and b/onlineTraining/images.d/seefahrt.d/yacht-4191578.jpg differ diff --git a/onlineTraining/kodokanKniebeuge.json b/onlineTraining/kodokanKniebeuge.json new file mode 100644 index 0000000..ace566a --- /dev/null +++ b/onlineTraining/kodokanKniebeuge.json @@ -0,0 +1,9 @@ +[ +{ + "source": "https://www.youtube.com/embed/6wcWZZw6RGk", + "target": "videos.d/***REMOVED***Eingang-kniebeuge.webm", + "from": "03:45.250", + "to": "04:05.167", + "crop": {"x": 581, "y": 32, "w": 1309, "h": 1018} +} +] diff --git a/onlineTraining/onlineTraining.css b/onlineTraining/onlineTraining.css new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/onlineTraining/onlineTraining.css @@ -0,0 +1 @@ + diff --git a/onlineTraining/revealTest.md b/onlineTraining/revealTest.md new file mode 100644 index 0000000..adafd30 --- /dev/null +++ b/onlineTraining/revealTest.md @@ -0,0 +1,46 @@ +--- +title: 2021-02-10 OnlineTraining der Judoka des Chemnitzer WSV +--- + +# Eidechse im heißen Wüstensand + +- um die Gliedmaßen abzukühlen: Rückenstrecker + - immer auf einer Seite den Arm und auf der anderen Seiten das Bein + anheben + - und Wechsel + +