Archiv der Kategorie: Technik

Automatisiertes Posten in einem Simple Machines Forum

Seit 2002 betreibe ich die Website der Gesellschaft zur Stärkung der Verben (GSV), seit 2007 nutze ich dafür die von Wikipedia bekannte Wiki-Software MediaWiki. Seit 2003 gibt es parallel dazu ein Forum, auch bulletin board genannt. Dieses läuft mit der Forensoftware Simple Machines Forum (SMF), die aber erst seit 2004 so heißt. Als ich das Forum einrichtete, hieß sie noch YaBB SE. Zu den aktiveren Zeiten der GSV fand die meiste Interaktion zwischen den Mitgliedern im Forum statt. Um die Aktivität im Wiki sichtbarer zu machen, richtete ich ein Skript ein, das regelmäßig den RSS-Feed der letzten Änderungen im Wiki abruft und neue Änderungen als Forenpost formatiert in einen dedizierten Faden im Forum postet. Dieses Skript hatte zunächst die Form eines SMF-Mods. Mods sind softwaretechnisch gesehen abenteuerliche Gebilde. Ähnlich wie Plugins fügen sie der Basissoftware (hier: SMF) neue Funktionalität hinzu. Sie tun dies jedoch nicht notwendigerweise über sauber definierte Schnittstellen. Vielmehr können sie, und so war es in diesem Fall, als eine Art Patch in einem SMF-eigenen XML-Format daherkommen, mit dem der PHP-Code von SMF im laufenden Betrieb modifiziert wird. Es ist sogar SMF selbst, das diese Modifikation an sich vornimmt, über den Paketmanager im Administrationsbereich. Neben dem Patch zur Installation enthalten Mods auch einen Patch zur Deinstallation, der unabhängig von ersterem ist. Z.B. sagt der Installationspatch »Suche in Datei X nach dem String ABC und füge direkt danach den String XYZ ein« und der Deinstallationspatch sagt »Suche in Datei X nach dem String XYZ und entferne ihn.« Man kann sich leicht vorstellen, wie chaotisch es werden kann, wenn eine Mod-Autorin es versäumt, die beiden Patches synchron zu halten, wenn SMF ein Update erhält, durch das der String ABC verändert wird, oder wenn zwei Mods benachbarte Codebereiche modifizieren. Aber für viele Jahre funktionierte mein Setup, basierend auf einer selbst modifizierten Version eines nicht mehr gepflegten Mods namens »RSS Feed Poster«, das eine komplette RSS-Parsing-Bibliothek im Code mit sich führte, gut. Erst kürzlich begann es zu holpern, es kam zu Dopplungen bei den Einträgen. Ich vermute, es hatte etwas mit neuen aggressiven Rate-Limiting-Einstellungen seitens meines Webhosters zu tun, durch die das Skript abbrach, bevor es Gelegenheit bekam, in der Datenbank zu vermerken, welche Feed-Einträge es schon bearbeitet hatte. Das nahm ich zum Anlass, endlich einen softwaretechnisch schöneren Zustand herzustellen, indem ich das Mod aufs Altenteil schickte und durch ein Python-Skript ersetzte, das auf dem Server als Cronjob läuft. Das Auslesen des Feeds der letzten Änderungen aus MediaWiki umzusetzen war easy, Feed-Parsing-Bibliotheken für Python gibt es zuhauf, ich entschied mich für feedparser. Interessanter war die Interaktion mit SMF, das leider über kein API verfügt. Mein Skript muss also so tun, als wäre es eine menschliche Benutzerin, die sich über einen Browser in das Forum einloggt und dort einen Beitrag verfasst. Dazu braucht man einen sog. headless web browser. Als ich aus dieser langen Liste einmal einen ausgewählt hatte, der schön leichtgewichtig ist und ein herzaugenmachend cutes API hat, nämlich mechanicalsoup, war auch das ein Vergnügen. Ah, die Freuden der Systempflege!

Vorlesungsaufzeichnung mit Kamera-Roboter

Eine Studentin kann wegen einer Überschneidung meine Vorlesung nicht besuchen und fragt, ob eine Videoaufnahme gemacht werden könne. Mir gefällt die Idee. Wenn die Vorlesung aufgezeichnet wird und von den Kursteilnehmer/inne/n zeit- und ortsunabhängig gesehen und gehört werden kann, lohnt sich der im Vergleich zum Ertrag dieses eher veralteten Wissensvermittlungsformats doch recht hohe Vorbereitungs- und Energieaufwand sicher etwas mehr.

Ich also in den Hörsaal, um zu gucken, ob da eine fest installierte Kamera ist. Das ist der Fall. Aber wie benutzt man sie? Ich frage in der Portiersloge, die schickt mich zum AV-Dienst, der schickt mich zum Büro für studentische Angelegenheiten, das schickt mich zur Abteilung Stundenpläne. Dort wird die Vorlesung im zentralen Stundenplansystem als aufzunehmen markiert, mir wird aber nahegelegt, wegen der Kurzfristigkeit dem AV-Dienst nochmal Bescheid zu sagen, damit die den anscheinend erforderlichen analogen Zwischenschritt noch vornehmen können. Das tue ich per E-Mail, die Bestätigung kommt alsbald und ich kann im webbasierten Kursportal meinem Kurs eine Sektion hinzufügen, in der dann die Videos aller Vorlesungswochen nach und nach automatisch auftauchen sollen.

Von da an geht anscheinend tatsächlich fast alles von selbst. Vor der ersten Vorlesungssitzung hole ich in der Portiersloge ein Funkmikrofon ab. Pünktlich um 13:00 Uhr geht im Hörsaal die Kamera an und dreht sich automatisch, wenn ich auf und ab schreite. Die ersten zehn Minuten lang zeichnet sie ohne Ton die Versuche von mir und der studentischen Hilfskraft auf, PC und Beamer zum Laufen zu kriegen. Alles wird zentral über ein Touchscreen-Gerät bedient, das sich aber anscheinend gerne mal aufhängt, und der Neustart beinhaltet einen kompletten Abkühl- und Wiederaufwärm-Zyklus des Beamers. Nicht alle Technik ist so benutzerfreundlich wie der freundliche Kamera-Roboter.

Am Anfang und Ende des Vortrags und aller Pausen gelingt es mir jeweils, den Mute-Schalter im richtigen Moment in die richtige Stellung zu bringen. Minuten nach der Vorlesung ist im Kursportal ein Vorschaubild zu sehen, nach ein paar Stunden ist das Video dann transkodiert und kann angesehen werden – schön mit dem separat aufgezeichneten Output des Beamers daneben, wie man das mag. Gerne wieder.

Your diff viewer is right

I stumbled upon the most ridiculous article tonight. The author claims diff viewers are wrong for displaying deletions in red and additions in green. Why? Because, he says, that is tantamount to passing a value judgment, red being associated with evil and danger, and green with good, and all:

Our diff viewer, then, tells us that deletions are bad, dangerous, and possibly an error, while insertions are good, safe, and successful. More code good. Less code bad.

At this point we know the article is utterly flawed, because of course it is not the deletions that are colored red by diff viewers such as GitHub’s. It is the old code. The author acknowledges this objection:

Edit: multiple people have suggested a different interpretation: old code bad, new code good.

But he still tries to save his argument:

However, since that would be a similarly invalid value judgment, the argument below is still valid.

Invalid value judgment? Why, of course the old code is bad, or at least worse than whatever replaced it – hopefully! Otherwise, why would we have deleted it? Perhaps what the author is thinking about is that we may have made a mistake and don’t know whether we really improved the program:

In reality, insertion/deletion is orthogonal to good/bad. There are good insertions, good deletions, bad insertions, bad deletions. Only we humans get to judge which changes are good and which are bad, but during code review, the diff viewer is constantly subtly trying to influence our judgment.

But he got it all backwards. A human already made the decision that the old code is bad, and the diff viewer had better be doing its job and reflect that judgment! Software cannot spot the programmer’s mistakes – it should make her intent clear so she or others will hopefully notice.

As far-fetched as the author’s complaints about diff viewers trying to influence our judgment is his theory of why red came to accompany deletions and green, additions:

I believe the reason for this strange color scheme is the lack of a revision control system. Back in the dark ages of programming, we didn’t use them. We edited files on disk, and that was that. In that environment, a deletion is dangerous. (…) But we don’t live in a world without revision control. It is peculiarly ironic that the ‘deletion is dangerous’ sermon is being delivered by our version control systems. That same revision control system which tells us that ‘it’s okay to delete things, because it’s all still there in the history.’

Far from it – there are still very good reasons to associate deletions with danger, and therefore, the color that stands out the most (red). Philosophically appealing though the author’s God-like perspective on revision histories may be – there is no time, all is one, deletions and additions are just the same thing seen from two sides – in reality, software development still happens from past to future.

This firstly means that deleted lines are, though not lost, quickly forgotten – and hopefully for a good reason. Highlighting them in a color that warns us to check our deletions carefully helps avoid relegating important stuff to history and later not being able or bothered to retrieve it.

Secondly, the function of a diff – at least the type that the author shows us, which is not side-by-side – is not to show us an impartial view between two versions of equal status. What we are typically interested in is the new version and how it compares to the previous one. And the new version is right there: it consists of the white and green lines. The green ones are marked for being new, but other than that are not really different from the white ones. In addition, there are red lines showing us what was deleted. Mistaking a red line for part of the new version would be dangerously misleading – hence, again, the signal color.

Der Vorteil von zoomenden Präsentationsprogrammen

Über Vortragsfolien hatte ich alles gesagt, bis ich Prezi entdeckte. Richtig eingesetzt, halte ich Prezi und andere zoomende Präsentationsprogramme für eine ausgesprochen gute Idee. Eine häufige Hauptschwierigkeit beim Gestalten von Vorträgen ist ja, dass man beim Publikum gleichzeitig das Verständnis für Details wecken und das Verständnis für das große Ganze am Leben halten muss, das „big picture“, das Thema des gesamten Vortrags oder der Vortragsreihe. Mit dem Zoomeffekt kann man das Verhältnis von beidem sehr schön veranschaulichen, indem man zum Beispiel ein großes Diagramm macht und im Laufe des Vortrags zwischen diesem und dem jeweils nächsten Detailframe hin- und herzoomt. Ich habe das erstmalig in meinem LREC-Vortrag vom letzten Jahr ausprobiert, in dem es um die Pipeline ging, mit der die Groningen Meaning Bank erstellt wird:

Wenn man das groß genug ausdruckt (sagen wir, auf A3), hat man auch ein schönes Handout, und wenn man es noch größer ausdruckt, hat man ein Poster. Ich kann mir auch vorstellen, dass man auf ähnliche Weise mit visueller Strukturierung und Zoomen mit Gewinn den Stoff für ein ganzes Seminar in eine Präsentation packen kann, etwa mit Hilfe der freien Prezi-Alternative Sozi. Das will ausprobiert werden.

Bloß als knalligen Übergangseffekt sollte man das Zoomen, Drehen und Fahren natürlich nicht verwenden.

Musikfolgen

Heute sinniere ich darüber, wie Medienabspielgeräte nach dem Abspielen eines Tracks entscheiden, welchen Track sie als nächsten abspielen.

Bei Tonbändern und Schallplatten war das einfach: die physische Anordnung der Tracks auf dem Medium legte die Reihenfolge fest. Das Abspielgerät hatte nichts zu entscheiden. Es wusste noch nicht einmal, wenn ein Track zu Ende war.

CD-Player behielten normalerweise die Konvention bei, Tracks ihrer physischen Reihenfolge entsprechend abzuspielen. Aber sie fügten mit der Program-Funktion die Möglichkeit hinzu, die Menge der abzuspielenden Tracks auf eine frei zu bestimmende Untermenge der auf der CD enthaltenen Tracks zu reduzieren, und das ging mit einer frei bestimmbaren Reihenfolge einher. Sie kannten also das Konzept der Playliste. Ebenso kannten sie die Shuffle-Funktion, bei der der nächste abzuspielende Track nicht durch seine Position auf der CD bzw. auf der Playliste, sondern zufällig ausgewählt wird, wobei aber in der Regel jeder nicht manuell unterbrochene Abspielvorgang jeden Track auf der CD bzw. der Playliste genau einmal beinhaltet.

In Software implementierte Medienabspielgeräte zeichnen sich gegenüber den CD-Playern wiederum durch die Vielzahl der gleichzeitig verfügbaren Playlisten aus, z.B.: die gesamte MP3-Sammlung, manuell gepflegte Playlisten, automatisch gepflegte Playlisten je nach Künstlerin, Album, Genre usw., sowie Suchergebnislisten. Dabei kann jeder Track Element beliebig vieler Playlisten sein. Wählt die Benutzerin einen Track zum Abspielen aus, merkt sich die Abspielsoftware in der Regel nicht nur, welchen Track sie ausgewählt hat, sondern auch, aus welcher Liste (d.h. über das GUI-Element, das diese Liste repräsentiert) sie den Track ausgewählt hat. Diese Liste wird zur „aktuellen“ Playliste und damit für die Auswahl des nächstabzuspielenden Tracks maßgeblich. Wie gehabt wird dabei der auf der Playliste dem aktuellen Track nachfolgende bzw. ein zufälliger Track von der Playliste ausgewählt, je nach dem, ob der Shuffle-Modus an ist.

Auch spontanen Launen der Hörerin zu genügen, dazu ist die Warteschlange da. Hierbei handelt es sich um eine spezielle, von der Hörerin jederzeit frei bearbeitbare, flüchtige Playliste, die, falls sie nicht leer ist, beim Auswählen des nächsten Tracks der aktuellen Playliste vorgezogen wird, wobei dann der ausgewählte Track automatisch aus der Warteschlange gelöscht wird. So kann die Hörerin spontane Hörwünsche schnell erfüllen, ohne die aktuelle Playliste zu verlassen und somit ohne sich um die Fortdauer der Berieselung sorgen zu müssen. In einer besonders geistesgesunden Variante dieses Sytems ist die Shuffle-Funktion bei der Auswahl eines Tracks von der Warteschlange unerheblich; die Warteschlange wird dann immer ihrer Reihenfolge entsprechend abgearbeitet. So jedenfalls ist es z.B. in Rhythmbox designt und implementiert.

Und so ist es möglich, sich inmitten eines ernsthaften Albumdurchhörens oder inmitten einer zufallsgeleiteten Kreuzfahrt durch die gesammte Musiksammlung im laufenden Betrieb und ohne einen Klick oder einen Gedanken mehr als nötig kleine Pausen einzurichten, die ganz bestimmte, spontane Musikjieper befriedigen.

Und dann gibt es Google Play Music. Google Play Music versucht ohne das Konzept der „aktuellen Playliste“ auszukommen und bürdet deren Aufgabe der Warteschlange mit auf. Bei Anwahl eines Tracks werden alle Tracks auf der Playliste, aus der heraus er angewählt wird (z.B. die gesamte Musiksammlung oder ein Album), automatisch der Warteschlange hinzugefügt.

Dies geschieht entweder in der Playlisten-Reihenfolge oder durcheinandergewürfelt, je nach dem, ob im Moment des Anwählens der Shuffle-Modus aktiviert ist. Es ist nicht möglich, geshuffelte Tracks auf der Warteschlange nachträglich wieder in die ursprüngliche Reihenfolge zu bringen, außer manuell. Das Einschalten des Shuffle-Modus bewirkt außerdem jedes Mal das Shuffeln der Warteschlange. Der Shuffle-Knopf hat also einen etwas seltsamen Zwittercharakter als Aktionsknopf und Modusschalter.

Es ist natürlich auch möglich, Tracks der Warteschlange explizit hinzuzufügen, wie gehabt. Dadurch, dass „aktive Playliste“ und Warteschlange quasi eins sind, hat man mehr Flexibilität als bei der Rhythmbox-Lösung und kann die „spontanen Tracks“ beliebig mit der „aktiven Playliste“ mischen. Auch könnte man Google dazu gratulieren, die Dinge vereinfacht zu haben, indem die „aktive Playliste“ nicht mehr explizit existiert, sondern durch das automatische Hinzufügen zur Warteschlange simuliert wird.

So einfach liegen die Dinge dann aber doch nicht. Der Warteschlange automatisch hinzugefügte Tracks haben nicht denselben Status wie explizit hinzugefügte, auch wenn nichts sie sichtbar unterscheidet. Automatisch hinzugefügte Tracks müssen unter der Haube irgendwie als „flüchtig“ markiert sein, denn bei der nächsten Anwahl und damit dem nächsten automatischen Hinzufügen zur Warteschlange werden sie automatisch gelöscht, wohl um ein Springen von Playliste zu Playliste möglich zu machen, ohne dabei die Warteschlange immer weiter zu füllen und um ein Stoppen der Wiedergabe nach der aktuellen Playliste zu gewährleisten, sofern nichts explizit zur Warteschlange hinzugefügt wurde. Explizit hinzugefügte Tracks werden übrigens nie automatisch gelöscht – wer wieder eine leere Warteschlange will, muss sie auch explizit leeren.

Ob dieses Warteschlangenkonzept nun der Weisheit letzter Schluss oder auch nur ein Fortschritt gegenüber dem Rhythmbox-Konzept ist, weiß ich noch nicht so recht.

Neben dem seltsamen oder gewöhnungsbedürftigen Verhalten des Shuffle-Knopfes und der visuellen Ununterschiedenheit flüchtiger und permanenter Warteschlangenelemente stört mich vor allem dies: Mein oben fettgedruckter Use Case wird nicht gut unterstützt. Zwar gibt es zwei Wege des expliziten Hinzufügens zur Warteschlange, nämlich „Zur Warteschlange hinzufügen“ und „Nächster Titel“. Doch keine von beiden zeigt dasselbe Verhalten wie Rhythmboxs „Add to Queue“. Füge ich eine Reihe von Tracks nacheinander als „Nächster Titel“ hinzu, werden sie in der umgekehrten Reihenfolge abgespielt werden, denn immer der zuletzt so hinzugefügte Track ist der nächste. Benutze ich hingegen die Funktion „Zur Warteschlange hinzufügen“, werden sie zwar in der beabsichtigten Reihenfolge abgespielt, aber erst nachdem alles andere, einschließlich automatisch hinzugefügter Tracks, also der „aktuellen Playliste“, abgespielt wurde. So war das nicht gedacht.

Palindrome

I’m beginning to teach myself Haskell, because we all have to. I started doing the 99 Haskell problems and came across a beautifully cunning solution to problem 6, “Find out whether a list is a palindrome.” Let’s first look at the classic solution, which is maximally declarative. I use Prolog here to formulate it:

palindrome(X) :-
  reverse(X,X).

It reverses the list, then checks if the result is the same as the original (that’s the definition of a palindrome). It checks that by going through both lists and comparing elements at corresponding positions.

What’s ugly about this is that this is at least twice as many comparisons as needed. Since we know one list is the reverse of the other, it suffices to compare the first half of one to the last half of the other. (In lists of odd length, the center element does not need to be compared at all, since it is always identical to itself.)

Alternatively, we could just traverse the list to check, carrying along a reversed version of what we have traversed so far, stop in the middle and then compare the reversed first half to the remainder (i.e. to the last half). The problem is: where to stop? We don’t know the length of the list until we have traversed the whole of it, hence we also don’t know what half its length is.

Enter the intriguing solution that was given on the Haskell Wiki, humbly titled “Here’s one that does half as many compares”, and that gave me a very nice lightbulb moment when I had gotten my head around it. Here’s my Prolog translation:

palindrome(List) :-
palindrome(List,[],List).

palindrome([First|Rest],Rev,[_,_|Rest2]) :-
  palindrome(Rest,[First|Rev],Rest2).
palindrome([_|Rev],Rev,[_]).
palindrome(Rev,Rev,[]).

The trick is to carry along a second copy of the original list, popping two elements from it every time we pop one from the main copy. This way, when we reach the end of the second copy, we know we have reached the center of the first. There’s two recursion-ending clauses, one for odd-length and one for even-length lists. Ingenious!