ek

Beiträge zum Thema JS, HTML, CSS & anderem Kram

(English version of this article @Codepen.)

Neulich hatte ich ein interessantes Problem: Ich musste ein <iframe>-Element in eine responsive Website einbetten, dessen Inhalt wiederum nicht responsiv war. Man kann sich leicht vorstellen, wo hier der Fallstrick liegt. Wird der Bildschirm kleiner, passt sich die umgebende Website zwar problemlos an, der Inhalt des iFrames jedoch bleibt starr in seinen Dimensionen. Zusätzlich erscheinen unschöne, horizontale Scroll-Balken am iFrame.

Glücklicherweise gibt es in modernen Browsern einen Weg, mit diesem Problem umzugehen. Mithilfe von CSS-Transforms kann der iFrame inklusive seines Inhalts runter skaliert werden wie ein Bild. Der folgende Codepen zeigt, wie das aussehen kann.

(Link zur Demo-Seite)

Um dieses Verhalten zu implementieren, benötigen wir als erstes einen Breakpoint, ab dem die Skalierung wirksam wird. Den Breakpoint kann man sehr leicht ermitteln, indem man das Browser-Fenster verkleinert. Sobald am iFrame ein horizontaler Scroll-Balken auftaucht, hat man den Breakpoint erreicht.

JavaScript

var BREAKPOINT = 1060; // (Willkuerlich gewaehlter Wert!)

Der Breakpoint dient außerdem als Referenz-Breite des iFrames: 100% entsprechen 1060px. Nun benötigen wir den Skalierungs-Faktor. In der Theorie ist das der Quotient aus gegenwärtiger Bildschirm-Breite und iFrame-Referenz-Breite. In der Praxis hat sich dieser Wert für mich jedoch ab einem bestimmten Punkt als zu groß erwiesen. Daher verringere ich den Wert geringfügig mithilfe der Math.pow-Methode und einem Exponenten von 1.2.

JavaScript

var scale = Math.pow(window.innerWidth / BREAKPOINT, 1.2);

Eigentlich habe wir damit auch schon alles, was wir benötigen: einen Breakpoint, ab dem das Skalieren einsetzt, und einen Skalierungs-Faktor. Setzten wir nun jedoch den CSS-Transforms-Wert mit dem jeweiligen Skalierungs-Faktor am iFrame-Element an, passiert etwas merkwürdiges: der Inhalt des iFrames skaliert unmerklich, wobei das iFrame-Element selbst rapide an Größe verliert und buchstäblich in sich zusammen fällt. Das ist leider nicht das gewünschte Resultat.

Glücklicherweise gibt es einen Weg, dieses Verhalten zu unterbinden. Die Lösung ist, die Dimensionen des iFrames in dem Maße zu erhöhen, in dem es skaliert wird. Die Auswirkungen der CSS-Transforms auf die Abmessungen werden somit vollständig kompensiert und der iFrame verhält sich wieder wie ein normales, responsives Element. Lediglich der Inhalt des iFrames schrumpft wie gewünscht.

JavaScript

var scale = 0.8; // (Willkürlich gewählt!)
var width = 100 / scale; // Breite in Prozent
var height = INITIAL_IFRAME_HEIGHT / scale; // Hoehe in Pixeln

Die Breite des iFrames in Prozent ist die Inverse des gegenwärtigen Skalierungs-Faktors multipliziert mit 100. Die angepasste Höhe in Pixel ist der Quotient aus initialer Höhe und Skalierungs-Faktor. Die initiale Höhe des iFrames muss dabei ganz zu Beginn einmal ermittelt und gespeichert werden.

Jetzt gibt es nur noch ein potenzielles Problem: ist das iFrame-Element mithilfe von margin: * auto; mittig auf der Seite positioniert, muss die transform-origin ebenfalls durch "center top" auf Zentrierung eingestellt werden.

Dies hat jedoch zur Folge, dass der iFrame während des Skalierens rechts aus dem Bild "läuft", da sich seine Breite sukzessive erhöht. Um dieses Verhalten zu kompensieren, muss der iFrame um die Hälfte seines Wachstums in der Breite nach links verschoben werden.

JavaScript

var width = 100 / scale; // Breite in Prozent
var offsetLeft = (width - 100) / -2; // Versatz nach links in Prozent

Setzt man diesen Versatz mithilfe von transform: translateX(…);, bleibt der iFrame in der Mitte der Seite.

Das ist auch schon alles. Solltest du Fragen dazu haben, schreib einen Kommentar oder frag mich via Twitter: @Herschel_R.

GitHub Random Favorite

»GH Random Favorite« im Google Chrome Store

»GH Random Favorite« auf GitHub

Interessante GitHub-Repos zu favorisieren ist fast schon ein Reflex. Ich denke, niemand spart dabei mit Sternen. Allerdings gilt für die meisten favorisierten Repos wohl der Leitspruch: aus den Augen, aus dem Sinn.

Das ist schade und oftmals ärgerlich. Wie oft sucht man nach einer Lösung (aka Library, PlugIn, Framework, …) für ein bestimmtes Problem und stellt dann — nachdem man auf GitHub etwas gefunden hat — fest, dass man das Repo vor einem halben Jahr schon einmal favorisiert hat.

Um dieser Form der digitalen Demenz entgegen zu treten, habe ich eine Chrome-Extension — »GH Random Favorite« — geschrieben, die auf der GitHub-Startseite ein zufällig gewähltes Repo aus der Favoritenliste anzeigt. Dabei treten wahre Schätze wieder zutage.

Probierts mal aus!

Sollte es Probleme geben, kann im zugehörigen GitHub-Repo ein Ticket angelegt werden.

PS: Das ganze läuft über die stark reglementierte Public API von GitHub. Es können also nur 30 zufällige Favoriten pro Stunden angezeigt werden (es braucht zwei Requests pro zufälligem Favorit). Sollte sich herausstellen, dass das zu wenig ist, könnte man über die Integration von OAuth nachdenken. Das spielt für mich momentan jedoch noch keine Rolle.

Stupa

Im Oktober/November diesen Jahres hat es mich nach Nepal verschlagen, wo ich mit einem Freund 13 Tage lang den berühmten Annapurna Trek abwanderte. Die Reise führte uns dabei von Besi Shahar über den Thorong-La-Pass bis nach Tatopani. Die Fotos der Reise gibt es bei Flickr:

Foto-Set "Annapurna Trek 2013 (Nepal)"

Das nenne ich mal eine veritable Ungleichverteilung!

Da die Menschen im Gros immer der Meinung sind, sie seien schlauer als ihre Vorgänger-Generationen, wird kaum jemand ernsthaft in Erwägung ziehen, dass eine derartige Einkommensverteilung bzw. noch extremere Ungleichverteilungen zu gewaltsamen Auseinandersetzungen führen könnten. Nicht im zivilisierten 21. Jahrhundert!

Dabei ist das IMHO blütenreines Konfliktpotenzial. Und je eher man da entgegensteuert, desto besser. In einer Arbeitswelt, die immer mehr durch den Einsatz von Computern und Automatisierung gekennzeichnet ist, und immer höhere Erträge von immer weniger Akteuren erwirtschaftet werden, greifen die althergebrachten Entlohnungsstrukturen nicht mehr. Das sind aber auch old News.

Wir müssen auch gar nicht groß über den Atlantik glotzen. Das gleiche Problem (in weniger extremer Form) haben wir auch bei uns. Und die klassische Ignoranz gegenüber historischen Erfahrungen ist auf dieser Welt so gleichverteilt, wie es Geld selbst im Muster-Sozialismus nicht sein könnte. Von daher ist eine Besserung in nächster Zeit nicht zu erwarten. Um des Friedens Willen wäre es jedoch wünschenswert.

Link: www.utrend.tv/v/9-out-of-10-americans-are-completely-wrong-about-this-mind-blowing-fact/

(via @anked)

This is a rather unusual post as it is written in english. So don't be irritated by the fact that everything around here on this blog is in german. I switched the language for this post because I wanted to write a response to an article on Smashing Magazine about Full-stack JavaScript. Normally I would have just written a comment over at Smashing Magazine's, but this comment would have gotten way too long.

Also I want to shortly clarify my relationship to JavaScript. I'm working as a frontend developer for an agency in Hanover and I actually love writing JavaScript. In fact I have to love writing JavaScript as it is my main programming-/scripting-language. I'm quite familiar with PHP too and I wrote a little Python some time ago, but most of the time I'm writing JavaScript. And therefor I would get in real trouble if I started to hate writing it.

So what's wrong with this article on Full-stack JavaScript? Actually it's overall a good post and provides a wide overview on the topic. But beside the fact, that I disagree with the author when he states that asynchronous, callback-based code is easier to read and understand than synchronous (linearly written) code (e.g. PHP), I don't like the announcement of the "Full-stack-JacaScript-developer-dude/-dudess" he implicitly makes.

It's correct that it is easily possible to to have an application (client and server) fully running on JavaScript. But in my perception Alejandro Hernandez negates the fact that there still exist two different environments, though they both run the same language. And these environments provide different requirements to the developer. On the client-side it's about creating a user experience, dealing with user interaction and device deficiencies. Sure, with client-side-rendering and -routing formerly unusual tasks arrived on the client-side, but IMHO that doesn't equate client- and server-side programming.

On the server-side again there are tasks that could easily be located on the client-side (e. g. SQLite is implemented on both sides of the wire), but that's only a small part of the tasks a common server-side progammer is confronted with. There are way more things to do with data than fetching it from/writing it to a database. This is the kind of computer-sience-stuff a frontend developer has few to nothing to do with with when she's juggling HTML, CSS and JavaScript in the presence of various browser quirks.

That's why I think it's risky to suggest that there could prospectively be one kind of developer that is writing the full stack in JavaScript. And I think Alejandro Hernandez is exactly doing this in his article.

TL;DR

Though client and server are nowadays able to run the same programming language, I think there won't arise a new species of full-stack developer that addresses all the requirements issued by these two environments. Though there is an overlap in tasks and some people out there have a really broad understanding of various JavaScript-driven environments, the common case will be a specialized developer that does reliable work either on either the client- or the server-side.

Anarchy

Photo by Kim Yokota (CC)

Da ich mich gerade auf einem beliebten und nicht unumstrittenen Social Network über den SpOn-Artikel “NSA-Spähprogramm: Friedrich fordert Deutsche zu mehr Datenschutz auf” aufgeregt habe und das zu einem relativ umfangreichen Kommentar geführt hat, möchte ich die Gelegenheit nutzen, mich auch noch einmal öffentlich zu echauffieren.

Unser werter Bundesminister des Inneren, HP Friedrich, hängt nämlich der Meinung nach, die Lösung gegen Totalüberwachung à la NSA wären größere Bemühungen seitens der Bürger, sich selbst zu schützen. Nun bin ich sicherlich kein Anhänger des paternalistischen Staates. Ich erfreue mich meiner Mündigkeit und bin gerne bereit, die damit einhergehende Verantwortung für mich und mein Handeln zu tragen.

Doch alles hat Grenzen. Ich besitze beispielsweise keinen prall gefüllten Waffenschrank. Zwar besteht die hypothetische Möglichkeit von vorsätzlichen Eingriffen in meine körperliche Unversehrtheit durch Dritte, doch hat hier der Staat die Hoheit über die Sicherung meiner Gesundheit. Das ist auch in Ordnung. So genannte “Wild-West-Zustände” halte ich für wenig konstruktiv.

Wenn man sich dagegen die gebetsmühlenartig vorgetragene Beteuerung, das Internet sei kein rechtsfreier Raum, und die teilweise recht strenge “Hacker-Gesetzgebung” anschaut, verwundert es jedoch stark, dass es bei der Überwachung durch (ausländische) Geheimdienste auf einmal anders sein soll. Dass hier nicht mehr der Staat die Wahrung der Grundrechte seiner Bürgerinnen und Bürger übernimmt, sondern dass diese sich selbst helfen müssen.

Herr Friedrich scheint der Meinung zu sein, dass man übernommene Verantwortung mal eben ablegen kann, wenn es opportun erscheint. So viel mangelnde Souveränität und Integrität ist erschreckend!

Sizzle & Angular

Wie weithin bekannt ist, benutzt Angular für DOM-Angelegenheiten intern eine abgespeckte jQuery-Variante namens jqLite, auf die über angular.element zugegriffen werden kann. Diese bietet ein paar Methoden aus dem Bereich DOM-Manipulation und -Traversing, hat jedoch keine Selektor-Engine. Bindet man parallel zu Angular die jQuery-Library ein, wird jqLite durch jQuery ersetzt.

Angesichts der Tatsache, dass Angular eigene Services für AJAX und Animationen (Version >= 1.1.3 in Verbindung mit CSS3) bietet, ist der Einsatz von jQuery jedoch stark übertrieben. Zum Glück gibt es die von jQuery verwandte und von John Resig geschriebene Selektor-Engine Sizzle auch als Stand-alone-Version. Diese kann man alternativ einbinden. Man muss angular.element dann nur noch beibringen, sie auch zu verwenden.

Das wiederum ist schnell erledigt.

JavaScript

// Anlegen einer Referenz auf die eigentliche angular.element-Methode
angular._element = angular.element;

// Ueberschreiben der angular.element-Methode
angular.element = function (selector) {
    // ist das uebergebene Argument bereits eine
    // Instanz von angular._element, wird es ohne
    // Umschweife zurueck gegeben.
    if ( selector instanceof angular._element ) {
        return selector;
    }

    // Andernfalls wird eine Sizzle-Instanz erstellt
    // und an die angular._element-Methode uebergeben.
    return angular._element(Sizzle(selector));
};

Fertig ist die Laube!

Das ganze gibt es auch als Angular-Modul "Angular-Sizzle" auf Github.

Zum Schluss noch der Hinweis, dass der Einsatz von Angular-Sizzle gut überlegt sein will. Das Konzept von Angular sieht vor, dass tiefgreifendere Arbeiten am DOM über Direktiven erledigt werden. Diese bieten abstrahierte Element-, Klassen- und Attribut-Selektoren. Innerhalb der Direktiven gibt es automatisch eine jqLite-Instanz der relevanten DOM-Elemente, mit der man arbeiten kann.

Der Einsatz einer ausgewachsenen Selektor-Engine könnte also übertrieben sein. Das hängt jedoch davon ab, was man vor hat.

Burp.js - Screenshot

Seit kurzer Zeit gibt es ein JavaScript-API, mit welchem man Vibrationen von mobilen Geräten im Browser steuern kann. Um den Umgang mit dem API intuitiver zu gestalten, habe ich einen Navigator.Vibrate-Wrapper namens Burp.js geschrieben. Dieser funktioniert folgendermaßen:

JavaScript

Burp('*·*·*·**-**', 200);

Die Burp-Funktion nimmt zwei Parameter entgegen: Einen String, welcher den Rhythmus der Vibration steuert. Sternchen bilden dabei Vibrationen, Punkte (Middle Dot) sind kurze Unterbrechungen und Bindestriche Pausen, welche die gleiche Länge wie die Vibrationen haben. Mehrere Vibrationen bzw. Pausen hintereinander werden addiert.

Der zweite, optionale Parameter gibt in Millisekunden an, wie lang die Vibrationen und Pausen sein sollen. Der Default-Wert ist 300ms.

Hier gibt es eine Demo dazu …

Das ganze wird theoretisch vom mobilen Firefox, dem Android-Browser und dem mobilen Chrome unterstützt. Praktisch zum Laufen bekommen habe ich es jedoch nur im Mobile Firefox. Man wird sehen, wie es sich entwickelt. Für mehr Informationen empfehle ich den Beitrag auf MDN dazu.

Responsive Webdesign (kurz: RWD) kann man getrost als old News bezeichnen und mittlerweile weiß jeder, worum es beim Responsive Webdesign geht. Sollte man meinen.

Meine Recherche nach einem Drupal-Template am gestrigen Abend hat mich jedoch ziemlich ernüchtert und mich an eine BarCamp-Session erinnert, wo der Vortragende über Responsive Webdesign erzählen wollte, jedoch nur eine kleine Einführung in Media Queries gab und sich anschließend im Glauben wähnte, das Thema angemessen erschlagen zu haben. Doch beschränkt sich der RWD-Ansatz mitnichten nur auf den Einsatz von Media Queries.

Aber zurück zu meiner Recherche: Wie es heutzutage beim intensiven Betrachten einer Website Gang und Gäbe ist, habe ich mir jeweils mit dem Cursor den linken Browser-Rand geschnappt und das Fenster horizontal auf und zu gezogen. Das hat sich in den letzten Jahren zu einer regelrechten Neurose in Webdesigner-Kreisen entwickelt. Doch liegt der Nutzen auf der Hand: Man kriegt eine Demonstration darüber, wie sich die Seite ungefähr auf kleineren Bildschirmen verhält.

Dabei war das Resultat in den meisten Fällen das gleiche: Der Inhalt schreckte angsterfüllt zurück sobald der Fensterrand näher kam und kauerte sich nahezu klaustrophobisch in die Seitenmitte. Nur, um nach kurzer Zeit abermals zusammen zu zucken und in neuerliche, geschrumpfte Hab-Acht-Stellung zu verfallen. Da ich einen "Auftrag" hatte und keine Lust, mich mit diesen "Schmuddelkindern" des RWDs intensiver auseinander zu setzen, habe ich die Breakpoints in den Media Queries nicht näher untersucht.

Ich würde jedoch Geld darauf wetten, dass da einfach anhand der Auflösung aktueller iPhones und iPads die Breakpoints gesetzt und das Layout neu-definiert wurde. Das ist auch akzeptabel für Besucher mit "Referenz"-Geräten. Wer jedoch das Pech hat, bspw. mit einem Tablet auf die Seite zu kommen, das eine geringfügig kleinere Auflösung als das iPad hat, bekommt das iPhone-Layout angezeigt: ein Klopapier-breiter Inhaltsstreifen in Gesellschaft zweiter dicker Whitespace-Bereiche links und rechts.

Hier lässt sich der Effekt gut beobachten (der Name des Templates grenzt an Hohn).

Schön und gut, denkt sich da vielleicht der/die geneigte Leser/in. Toll ist das nicht, aber wie soll man es denn dann machen?

"Nichts leichter wie dies!", um es mit den Worten Helge Schneiders zu sagen. Man schmeißt die lästigen Pixel-Angaben aus seinem Stylesheet und macht Breiten-Angaben sowie horizontale Abstände in Prozent-Angaben. Zusätzlich gibt man eine Maximal-Breite der Seite an, damit diese bspw. nicht auf 24-Zoll-Bildschirmen den kompletten horizontalen Raum einnimmt. In den Media Queries ergänzt man anschließend noch Angaben zur Anpassung des Layouts der Elemente. Das Resultat ist ein Design, dass sich geschmeidig wie eine junge Katze dem Browser-Fenster anpasst, egal, wie breit es ist.

Hier lässt sich das ganze praktisch erfahren (kurioserweise ist das Professional Theme unter RWD-Gesichtspunkten besser als das Best Responsive Theme …)

Dem Design ist es nun egal, mit welchem Gerät man die Seite besucht. Die Breakpoints wurden auch nicht nach Lieblingshersteller gesetzt, sondern anhand des Inhalts. Unterstützt werden nicht eine handvoll Auflösungen, sondern ein stufenloser Bereich zwischen einer Minimal- und einer Maximalauflösung.

Und warum habe ich diesen Artikel geschrieben? Ganz einfach, um Missverständnisse aus der Welt zu räumen. Für diejenigen, die nicht selbst HTML/CSS schreiben, jedoch auf fertige Themes/Templates zurückgreifen und da etwas responsives suchen, der Hinweis, genau zu prüfen, was einem da als "responsive" angeboten wird. Euren Besuchern auf Mobile Devices zuliebe solltet ihr auf pseudo-responsive, fixe Layouts verzichten und richtige, responsive Fluid-Layouts wählen. So wird euer Inhalt immer anständig dargestellt, nicht nur auf drei Geräten. Den Unterschied sieht man im sogenannten Browser-Fenster-Auf-und-Zuzieh-Test.

Und für diejenigen, die selbst entwickeln und beim Thema Responsive Webdesign bisher als erste Assoziation Media Queries hatten, die Bitte, sich des Themas umfassender anzunehmen. RWD ist ein neuer Ansatz abseits fixer Layouts. Media Queries sind dabei nur ein Teilaspekt. Folgende zwei Bücher sind ein großartiger Einstieg in das Thema:

  1. Responsive Webdesign: Reaktionsfähige Websites gestalten und umsetzen | neu, umfassend und auf deutsch
  2. Responsive Web Design | der Klassiker von Ethan Marcotte

So, das musste ich einfach mal loswerden. Fragen, Anregungen, Ergänzungen sind hoch willkommen. Scheib einfach einen Kommentar.

Das Wochenende um den 19./20. Januar 2013 hatten die Kollegen von Doctape zum Hackathon geladen. Anlass der Veranstaltung – falls es zum Hacken einen Anlass braucht – war der Launch des Doctape-API, welche von den anwesenden Codern auf Herz und Nieren getestet werden sollte. Als Veranstaltungsort wurde das Co-Working-Space EDELSTALL gewählt, da es zum einen die nötige Infrastruktur für den Anlass bot und zum anderen die Doctape-Büros beherbergt.

doctape-Hackathon | Hannover 2013

© Photo by Nicolas Hafele

Los ging es Freitag abend mit einer Präsentation des Unternehmens und der Veranstaltung, sowie einer Vorstellungsrunde der Teilnehmenden. Einige hatten auch direkt schon eine Idee, was sie bauen wollten, andere waren noch in der Findungsphase. Ungeachtet dessen machte sich eigentlich jeder sofort daran, einen ersten Zugang zum API per oAuth2 zu bekommen. Fürs leibliche Wohl wurde eine ansehnliche Pizza-Bestellung abgeschickt.

Ich selbst ließ es am Freitag bei der erfolgreichen Authentifizierung bewenden und trat um 00:30 Uhr den Heimweg an. Einige waren jedoch schon im Flow und blieben teilweise bis 04:00 Uhr morgens.

Doctape-Hackathon | Hannover 2013

© Photo by Nicolas Hafele

Am Samstag ging es um 10:00 Uhr ganz entspannt weiter. Ein gemeinsames Frühstück verschaffte die nötige Stärkung für einen langen Tag des Codens. Nach und nach trudelten auch die Nachtaktiven ein, so dass man ab dem frühen Nachmittag wieder vollzählig an den Rechnern saß und das API strapazierte. Ich hatte nun auch die Muße, mich meiner geplanten App zu widmen. Fürs leibliche Wohl traf mittags ein dicker Topf feinsten Chili con Carnes ein. Standesgemäß und vom Chili beflügelt wurde auch Samstags wieder bis tief in die Nacht hinein gehackt.

Der Sonntag begann wie der Samstag gemütlich mit einem gemeinsamen Frühstück. Anschließend gab es noch ein paar Stunden Zeit, das eigene Projekt fertig zu machen. Um 15:30 Uhr war dann Präsentation der Ergebnisse angesagt. Folgende, beachtliche Resultate sind zu vermelden:

Couchtape

Couchtape ist eine pfiffige, auf Node.js und WebSockets basierende Anwendung, die eine zentral zugängliche Playlist anzeigt und sukzessive abarbeitet. Die Songs kommen von einem Doctape-Account. Die Playlist wiederum kann von Anwesenden befüllt werden, indem diese mit ihrem Smartphone (per Browser) auf das Couchtape-System gehen und dort die verfügbaren Songs auswählen und auf die Liste setzen. Durch die Verwendung von WebSockets ist gewährleistet, dass die zentrale Playlist und alle anwesenden Clients immer in Sync sind.

Das Projekt wird weiter entwickelt und freut sich über Contributors!

TapeBooth

TapeBooth ist eine iOS-App, die es ermöglicht, Bilder zu machen, diese mit Filtern zu versehen und anschließend zu teilen. Nebenbei findet automatisch eine Synchronisierung mit dem eigenen Doctape-Account statt, so dass die Fotos automatisch in Doctape verwaltet werden können. Instagram for Doctapers könnte man – etwas einfallslos – sagen.

Doctape-Gallery

Der Name ist Programm. Doctape-Gallery ist mit Node.js realisiert, zieht alle Fotos über das API und stellt sie in einer schicken Galerie dar. Per Tagging können Bilder in unterschiedliche Galerien eingeordnet werden.

MIDI-Delight

Mein Beitrag zur Veranstaltung: MIDI-Delight zieht alle MIDI-Dateien, die man in seinem Doctape abgelegt hat, und bietet die Möglichkeit, sie im Browser anzuhören. Das ganze baut auf der bei Midi.js gleisteten Arbeit auf und funktioniert leider nur in modernen Desktop-Browsern, auch wenn das Layout der App etwas anderes suggeriert.

Das war es, was ich in Erinnerung behalten habe. Die Liste ist unvollständig. Wer seinen Beitrag zum Doctape-Hackathon hier nicht wiederfindet und das gerne ändern möchte, teilt es mir am besten über einen Kommentar mit. Ich passe die Liste dann an.

Ansonsten bleibt festzuhalten, dass die Veranstaltung gelungen und ein großer Spaß war. Vielen Dank an Doctape und auf ein nächstes mal!