• Zu Fuß im Zug ins Netz

    Screenshot

    Wer hinreichend Geduld und Kompetenz hat, bekommt in den Zügen von Go-Ahead am Ende so eine Seite vom Captive Portal.

    Zu den ärgerlichen Folgen des Irrsinns vom „geistigem Eigentum“ gehören Captive Portals, also Webseiten, auf die mensch in öffentlichen WLANs erstmal umgeleitet wird. Erst, wer Familienpackungen Javascript ausführen lässt und schließlich per Häkchen lügt, er_sie habe die Nutzungsbedingungen gelesen und anerkannt, darf ins Netz. Allein fürs Öffnen dieser Sicherheitslücke („gehen Sie in irgendein unbekanntes Netz und lassen Sie ihren Browser allen Code ausführen, der da rauskommt, und dann ziehen Sie noch megabyteweise Bilder – vielleicht ist ja in einem der Bilder-Decoder auch noch ein Buffer Overflow“) verdient die Geistiges-Eigentum-Mafia Teeren und Federn.

    Na ja, und erstaunlich oft ist der Mist einfach kaputt. Eine besondere Kränkung für die Ingenieursabteilung meines Herzens ist, wenn die ganze aufregende Hi-Tech, mit der mensch in fahrenden Zügen ins Netz kann, prima geht, aber trotzdem kein Bit durch die Leitung zu kriegen ist, weil ein „Web-Programmierer“ im doofen Captive Portal gemurkst hat.

    Kaputt sah das WLAN für mich heute in einem Zug von Go-Ahead aus. Die Geschichte, wie ich mich dennoch ins Netz vorgekämpft habe, finde ich im Hinblick auf manuelles Fummeln an IP-Netzen instruktiv, und so dachte ich mir, ich könnte im nächsten Zug (betrieben von der Bahn und deshalb noch nicht mal mit kaputtem Internet ausgestattet) zusammenschreiben, was ich alles gemacht habe. Das Tooling, das ich dabei verwende, ist etwas, öhm, oldschool. So sollte ich statt ifconfig und route heute wohl lieber ein Programm mit dem schönen Namen ip verwenden. Aber leider finde ich dessen Kommandozeile immer noch ziemlich grässlich, und solange die guten alten Programme aus grauer Vorzeit immer noch auf eigentlich allen Linuxen rumliegen, kann ich mich einfach nicht zur Migration durchringen.

    Am Anfang stand die einfache ifupdown-Konfiguration für das Zug-Netz:

    iface roam inet dhcp
      wireless-essid freeWIFIahead!
    

    in /etc/network/interfaces.d/roam. Damit kann ich sudo ifup wlan0=roam laufen lassen, und der Kram sollte sich verbinden (wenn ihr die Interface-Umbenamsung der systemd-Umgebung nicht wie ich abgeschaltet habt, würde vor dem = einer der kompizierten „vorhersagbaren“ Buchstabensuppen der Art wp4e1 oder so stehen).

    Nur: das Netz kam nicht hoch. Ein Blick nach /var/log/syslog (wie gesagt: etwas altbackenes Tooling; moderner Kram bräuchte hier eine wilde journalctl-Kommandozeile) liefert:

    Jan  2 1████████ victor kernel: wlan0: associate with be:30:7e:07:8e:82 (try 1/3)
    Jan  2 1████████ victor kernel: wlan0: RX AssocResp from be:30:7e:07:8e:82 (capab=0x401 status=0 aid=4)
    Jan  2 1████████ victor kernel: wlan0: associated
    Jan  2 1████████ victor kernel: IPv6: ADDRCONF(NETDEV_CHANGE): wlan0: link becomes ready
    Jan  2 1████████ victor dhclient[18221]: Listening on LPF/wlan0/█████████████████
    Jan  2 1████████ victor dhclient[18221]: Sending on   LPF/wlan0/█████████████████
    Jan  2 1████████ victor dhclient[18221]: Sending on   Socket/fallback
    Jan  2 1████████ victor dhclient[18221]: DHCPDISCOVER on wlan0 to 255.255.255.255 port 67 interval 6
    Jan  2 1████████ victor dhclient[18221]: DHCPDISCOVER on wlan0 to 255.255.255.255 port 67 interval 14
    Jan  2 1████████ victor dhclient[18221]: DHCPDISCOVER on wlan0 to 255.255.255.255 port 67 interval 1
    Jan  2 1████████ victor dhclient[18221]: No DHCPOFFERS received.
    

    Das bedeutet: Das lokale „Router“ (Access Point, AP) hat mich ins Netz gelassen („associated“; das ist quasi das Stecken des Netzkabels), aber dann hat der DHCP-Server, der mir eigentlich eine IP-Adresse hätte zuteilen sollen (mit der ich dann übers lokale Netz hinauskommen könnte), genau das nicht getan: „No DHCPOFFERS received“.

    Wenn das so ist – der Rechner ist Teil von einem Ethernet-Segment, sieht mithin Netzwerkverkehr, bekommt aber keine IP-Adresse und kann also mit niemandem über TCP/IP reden –, lohnt sich ein Blick in die Pakete, die im Netzwerksegment unterwegs sind. Das geht mit fetten Grafikmonstern wie wireshark, aber für einen schnellen Blick tut es tcpdump allemal. Da wir aber noch keine Internet-Verbindung haben, können wir sicher keine IP-Adressen („192.168.1.15“) zu Namen („blog.tfiu.de“) auflösen. Tatsächlich würde der Versuch tcpdump schon zum Stehen bringen. Deshalb habe ich per -n bestellt, Adressen numerisch auszugeben:

    tcpdump -n
    

    Ich sehe dabei einen Haufen ARP-requests, also Versuche, die lokalen Adressen von Ethernet-Karten für IP-Adressen herauszufinden, von denen der Router meint, sie müssten im lokalen Ethernet-Segment sein, etwa:

    12:█████████383626 ARP, Request who-has 10.1.224.139 tell 10.1.0.1, length 28
    

    Aus dieser Zeile allein kann ich schon mal raten, dass das Gateway, also der Router, über den ich ins Internet kommen könnte, wohl die Maschine 10.1.0.1 sein wird. Dabei sind Adressen aus dem 10er-Block leicht magisch, weil sie nicht (öffentlich) geroutet werden und daher (im Gegensatz zu normalen IP-Adressen) im Internet beliebig oft vorkommen können. Sie sind deshalb für relativ abgeschottete Unternetze wie hier im Zug populär (ins richtige Netz gehts dann per Network Address Translation NAT) – und Maschinen mit .1 hinten dran sind konventionell gerne Router.

    Wenn ich mit dem Gateway reden will, brauche ich immer noch selbst eine IP-Adresse. Ohne DHCP-Server bleibt mir wenig übrig als mir selbst eine zu nehmen. Das ist normalerweise ein unfreundlicher Akt, denn wer eine Adresse wiederverwendet, die jemand anders in dem Teilnetz schon hat, macht die Verbindung für den anderen Rechner im Effekt kaputt. Insofern: Wer etwas wie das Folgende tut, sollte erstmal für eine Weile dem tcpdump zusehen und sicherstellen, dass sonst niemand mit der gewählten Adresse unterwegs ist. Wer öfter zu Stunts dieser Art genötigt ist, möge sich arping ansehen – damit kann mensch kontrolliert nachsehen, ob eine Adresse frei ist.

    In meinem Fall war es ruhig im Netz – es hat ja vermutlich auch kaum jemand sonst eine Verbindung bekommen. Ich fühlte mich also hinreichend sicher, irgendwas zu probieren, das der Router wohl als „im eigenen Netz“ akzeptieren würde. Die so geratene Adresse habe ich versuchsweise auf meine Netzwerkschnittstelle geklebt:

    sudo ifconfig wlan0 inet 10.1.0.105 up
    

    Ein guter erster Tipp für diese Zwecke ist eine Adresse, bei der nur das letzte Byte anders ist als in der Router-Adresse (in antikem Jargon: „im selben Klasse C-Netz“). In diesem Fall wäre es denkbar, noch mehr zu ändern, denn im antiken Jargon ist 10.0.0.0 ein A-Netz („die Netzmaske ist 255.0.0.0“), was mit dem Kommando oben (das nicht explizit eine andere Netzmaske gibt) den lokalen Rechner Pakete, die an eine 10.irgendwas-Adresse gehen, an wlan0 schicken lässt. Allerdings macht fast niemand mehr Routen nach diesen Regeln, und so ist es nicht unwahrscheinlich, dass der Router allzu weit entfernte Adressen routen will oder jedenfalls nicht einfach wieder ins lokale Netz-Segment zurückschickt. So in etwa ist die Logik, die mich auf die IP-Adresse oben gebracht hat.

    Wenn meine Vermutungen richtig waren, hätte ich nach dem ifconfig mit dem vermuteten Router bei 10.1.0.1 IP sprechen können. Der Klassiker zur Konnektivitätsprüfung ist ping, und wirklich:

    ping 10.1.0.1
    

    kriegte brav Paket für Paekt zurück. Wow! Immerhin schon IP!

    Ein DHCP-Server konfiguriert als nächstes normalerweise die „Default-Route“, also das, was der Rechner mit Paketen tun soll, für die er nichts anderes weiß. Rechner am Rande des Netzes (und wir ungewaschenen Massen sind eigentlich immer mehr oder weniger am Rande des Netzes) schicken in der Regel alle Pakete, die nicht ins lokale Netz gehen, an einen (und nur einen) Router, nämlich ihr Gateway. Dieses Gateway legt mensch mit meinen alten Werkzeugen so fest:

    sudo route add default gw 10.1.0.1
    

    Damit könnte ich im Netz sein. Ein schnelles ssh auf eine meiner Maschinen im Netz führt aber zu nichts: meine Maschine kann keine Namen auflösen. Ach ja, das ist noch etwas, das normalerweise ein DHCP-Server macht: der lokalen Maschine Adressen geben, an denen sie Namen auflösen kann (die DNS-Server). Über (inzwischen potenziell sehr komplizierte) Umwege enden diese Adressen in gewissem Sinn in der Datei /etc/resolv.conf; dort erwartet sie jedenfalls die C-Bibliothek.

    Nun ist aber der DHCP-Server gerade kaputt. Die Namen von DNS-Servern, die aus einem bestimmten Netz heraus funktionieren, kann mensch jedoch nicht raten. Manchmal – typisch bei privaten Netzen – tut es der Router selbst. Andererseits betreibt Google unter 8.8.8.8 einen DNS-Server, und so ungern ich Google-Dienste empfehle: Die 8.8.8.8 verwende ich in Notsituationen wie dieser. Nur bin ich ja immer noch im Captive Portal, und der Router mag meine Versuche, mit dem Google-DNS zu reden, unterbinden. Viele Captive Portals tun das nicht (aus relativ guten Gründen). Und wirklich:

    ping 8.8.8.8
    

    kommt gut zurück. Andererseits kann mir das Captive Portal natürlich alles vorspielen. Ist da wirklich ein DNS-Server?

    Das Tool der Wahl zum Spielen mit DNS-Servern ist dig [1]. Im einfachsten Fall bekommt dig einen Namen als Parameter, das wird hier zu nichts führen, denn noch hat mein Rechner ja kein DNS. Eine Stufe komplizierter übergibt mensch noch eine Nameserver-Adresse hinter einem @, also:

    dig blog.tfiu.de @8.8.8.8
    

    Und das kommt zurück! Mit der richtigen Information, nicht irgendeinem Mist, den sich das Captive Portal ausdenkt. Damit kann ich für meine temporäre Netzverbindung mein /etc/resolv.conf ändern zu:

    nameserver 8.8.8.8 …
  • Anachronismen

    Wer gestern vom Papst Generalabsolution haben wollte, bekam in der Vatikan-Übertragung folgendes Bild sehen:

    Schweizer Garde mit riesigen Helmen und OP-Mundschutz

    Quelle: Vatikan-Mitschnitt. Rechte beim Vatikan.

    Ich kann gar nicht genau sagen, warum genau mich das als symbolisch für Religion in der Moderne hingerissen hat: die Kombination aus offensichtlich unsinniger Tradition (die Rüstungen) und modernen Einsichten (Viren, Tröpfcheninfektion)? Das Festhalten an unsinnigen Prozeduren (hier: eng stehen, laut brüllen), auch wenn diese mit erkennbaren Risiken verbunden sind, die mensch leicht vermeiden könnte? Oder wars nur, dass die Mundschutze in dieser Situation annäheernd leere Demonstration waren, denn vergleichen mit dem, was dann nachher in den Umkleiden[1] stattfindet, ist das Infektionsrisiko am durchpusteten Petersplatz trotz des zu geringen Abstands fast vernachlässigbar (na gut, jedenfalls, wenn sich die Leute bereitgefunden hätten, aufs Rumbrüllen zu verzichten).

    [1]Oder der Kaserne? Leider geht aus dem Wikipedia-Artikel zur Schweizergarde nicht hervor, ob die Leute kaserniert sind oder nicht. Dafür steht dort zu lesen, dass auch der Papst statt auf ordentliche Schutzengel doch eher auf die Maschinenpistole 5 aus der Todesfabrik von Heckler und Koch in Oberndorf am Neckar setzt. Außerdem im Artikel: Ein Link auf die nachgerade klischeereine Geschichte um den Mord an dem Kommandanten Alois Estermann. Manchmal, so scheint es, stimmt der Bibelspruch doch: Wer das Schwert ergreift, wird durch das Schwert umkommen.
  • Keine Vollendung

    Vor gut 30 Jahren hat der Bundestag beschlossen, mit der Regierung nach Berlin umzuziehen. Es setzte sich damals ein Antrag durch, der von Willy Brandt und Wolfgang Schäuble unterstützt wurde – wie so oft hatte der Patriotismus großzügig weltanschauliche Differenzen zugekleistert.

    Der Titel des siegreichen Antrags von 1991: „Vollendung der inneren Einheit Deutschlands“.

    Diese „Sternstunde des deutschen Bundestags“ (Bundestagsverwaltung) kommentiert das SARS-2-Cornavirus am 23.12.2021 wie folgt:

    Deutschlandkarte mit Inzidenzen: die alten Grenzen sind unschwer sichtbar

    Aus: RKI-Bericht von heute, Rechte beim RKI

    Wer sich nicht mehr erinnert: vgl. Wikipedia.

  • Optimierte Inzidenz

    Mortalitätspunkte und eine Fit-Gerade in einem Logplot

    Abbildung 3 aus dem Paper von Levine et al, auf das ich unten ein wenig eingehe: das Risiko, an SARS-2 zu sterben, geht ziemlich genau exponentiell mit dem Alter (die Ordinate ist logarithmisch aufgeteilt). Diese Beobachtung führt ziemlich direkt zu einem Kult-Paper aus den wilden Jahres des Internet. CC-BY doi:10.1007/s10654-020-00698-1.

    Als das WWW noch jung war und das Internet jedenfalls nicht alt, im Dezember 1999 nämlich, haben Chris Gottbrath, Jeremy Bailin, Casey Meakin, Todd Thompson und J.J. Charfman vom Steward Observatory das bemerkenswerte Paper „The Effects of Moore's Law and Slacking on Large Computations“ auf astro-ph, der Astrophyik-Abteilung des Preprint-Servers arXiv, veröffentlicht. Obwohl das damals nach meiner Erinnerung hohe Wellen geschlagen hat (selbst slashdot, damals eine der wichtigsten Seiten im Netz, berichtete), haben sie es bis heute zu keiner Fachzeitschrift eingereicht. Keine Ahnung, warum nicht, denn ihr Punkt ist trotz ihres eher leichtfüßigen Stils[1] völlig korrekt und jedenfalls nicht ganz offensichtlich.

    Gottbrath und Freunde sagen nämlich, dass, wer eine riesige Rechenaufgabe und ein festes Budget hat, durch Warten schneller fertig werden kann. Das liegt daran, dass mensch nach 18 Monaten (das ist die konventionelle Zeitskala für Moore's Law) fürs gleiche Geld einen Rechner mit doppelt so vielen Transistoren kaufen kann und der wird mit etwas Glück doppelt so schnell sein wie der, den mensch heute kaufen würde. Sie berechnen auch, wie groß eine Rechnung sein muss, damit sich das Warten lohnt: mit dem 18-Monate-Gesetz ist die Grenze bei Aufgaben, die 26 Monate rechnen würden.

    Weil das Paper damals in meiner Blase intensiv herumgereicht worden ist, finde ich überraschend, dass es laut ADS nur sechs Mal zitiert (wenn auch von einer illustren Auswahl von Papern) worden ist und bei den üblichen Suchmaschinen bei Anfragen wie „Moore's Law optimal waiting“ nicht in Sicht kommt.

    Transistoren vs. SARS-2

    Gesucht hatte ich es wiederum, weil ich ja schon länger mit Niedriginzidenzsstrategien hadere. Ganz unabhängig davon, ob wir als Gesellschaft hohe Inzidenzen ohne Schrammen überstehen, dürfte inzwischen niemand mehr ernsthaft bestreiten, dass „am Ende“ alle SARS-2 gehabt haben werden – die Frage ist nur, wann („werden wir im Herbst 2022 wieder einen Lockdown brauchen?“) und auch, wie viele Menschen bis dahin wegen SARS-2 schwer krank geworden oder gar gestorben sein werden.

    An diesem Punkt ist mir das 1999er-Paper eingefallen, denn wir haben bei SARS-2 etwas ganz ähnliches wie Moore's Gesetz: Die Sterblichkeit nach einer Erstinfektion steigt exponentiell mit dem Alter. Das haben im September 2020 (also einige Monate, bevor Impfungen gegen SARS-2 epidemiologisch relevant wurden) Andrew Levin und Kollegen in ihrem Artikel „Assessing the age specificity of infection fatality rates for COVID-19: systematic review, meta-analysis, and public policy implications“ (doi:10.1007/s10654-020-00698-1) recht sorgfältig und beeindruckend gezeigt. Die Abbildung am oben im Post ist aus dieser Arbeit.

    Da hier das Risiko und nicht die Leistung zunimmt, ist jetzt allerdings die Frage nicht, ob mensch lieber etwas warten soll. Nein, je älter Leute werden, desto größer ist ihr Risiko, eine SARS-2-Infektion nicht zu überleben, und dieses Risiko wächst ziemlich steil. Der Gedanke, die Gesamtopferzahl könnte sinken, wenn sich Menschen anstecken, solange sie noch jünger sind und sie also die Infektion mit höherer Wahrscheinlichkeit überleben, liegt also nicht fern. Die zur Prüfung des Gedankens notwendige Mathematik läuft im Wesentlichen analog zu den Überlegungen von Gottbrath und Freunden.

    Ethisch ist es natürlich nicht analog, aber ich wollte dennoch wissen, wie viel das eigentlich ausmachen könnte. Deshalb habe ich mir folgendes Modell ausgedacht:

    1. Die Infection Fatality Rate, also die Wahrscheinlichkeit, an einer (erkannten oder unerkannten) SARS-2-Infektion zu sterben, ist inspiriert von der Abbildung oben

      IFR = exp((t − A1) ⁄ λ) ⁄ 100.

      Dabei ist t das Alter der erkrankten Person, A1 das Alter, in dem 1% der Infizierten versterben (das pro-cent ist auch der Grund für die Division durch Hundert), und λ so etwas wie die Steigung; nennt mensch das Alter, in dem die Todesrate auf 10% gestiegen ist, A10, so lässt sich leicht

      λ = (A10 − A1) ⁄ ln(10)

      ausrechnen.

    2. Eine ultrakompetente Regierung (oder Schwarmintelligenz auf Brillianzniveau cosmic) kriegt es hin, die Inzidenz konstant über viele Jahre auf i zu halten. In meiner Simulation bleibe bei der Interpretation als Wocheninzidenz und simuliere die Infektion von Woche zu Woche. Gegenüber den Inzidenzen in der realen Welt gibt es bei mir außerdem keine Dunkelziffer.

    3. Wer nicht an SARS-2 stribt, stirbt nach Gompertz (cf. Mortalität in der Wikpedia), es stirbt also jedes Jahr ein Anteil („General Fatality Rate”)

      GFR = S30⋅exp(G⋅(t − 30  a)).

      der t-jährigen. Dabei ist S30 die Sterberate für 30-jährige, die ich aus dem Wikipedia-Artikel als ungefähr 40/100000 pro Jahr ablese, und G der Gompertz-Sterbekoeffizient – ich bin nicht sicher, ob ich so eine Größe eigentlich nach mir benannt haben wollte -, den die Wikipedia als 0.08 ⁄  a gibt. Etwas jenseits von Gompertz lasse ich jede Woche 1/52 der fürs jeweilige Wochen-Alter berechneten Menschen sterben; das macht vor allem die Kurven von SARS-2-Opfern über der Zeit glatter.

    4. Wer eine SARS-2-Infektion überlebt hat, stirbt nicht mehr an SARS-2. Das ist sicher eine unrealistische Annahme, aber sie macht das Modell auch deutlich klarer.

    Bliebe noch die Schätzung der Parameter aus der Formel für die IFR. Aus der Abbildung am Artikelanfang lese ich per Auge A1 = 65  a und A10 = 83  a ab (wer von den a irritiert ist: das ist die Einheit, nämlich das Jahr).

    Hier liegt die zweite wesentliche Schwäche meines Modells: Nachdem inzwischen in den dabei mitspielenden Altersgruppen wirklich eine überwältigende Mehrheit geimpft ist, werden diese Zahlen heute garantiert anders aussehen als in der ersten Jahreshälfte 2020, als die Studien gemacht wurden, die Levine et al ausgewertet haben. Andererseits legen die immer noch recht erheblichen Sterbefallzahlen nahe, dass sich die Kurve wohl nur ein wenig nach rechts verschoben haben wird; ich komme gleich nochmal darauf zurück.

    Der Berg des Todes

    Habe ich dieses Modell, kann ich einer Gruppe von Menschen folgen, bis sich (fast) niemand mehr infizieren kann, weil alle entweder tot oder in meinem Sinne immun sind. Ohne es probiert zu haben, glaube ich, dass das Modell einfach genug ist, um es in eine geschlossen lösbare Differentialgleichung umschreiben zu können. Aber wer will denken, wenn es doch Computer gibt?

    Und so habe ich die Modellannahmen von oben einfach in ein paar Zeilen Python gepackt und folge dem Schicksal einer Kohorte von 100000 70-jährigen, bis alle tot oder genesen sind. Und das mache ich für einen Satz von Inzidenzen zwischen 20 und 2000. für Das Ergebnis:

    Eine Kurve mit einem deutlichen Maximum um die 100

    Ich gebe zu, dass ich mit dieser Kurvenform nicht gerechnet hatte. Dass ganz niedrige Inzidenzen die Todeszahlen drücken, ist zwar zunächst klar, denn bei, sagen wir, 20/100000/Woche würde es 100000 ⁄ 20 = 5000 Wochen oder fast 100 Jahre dauern, bis alle mal das Virus hätten haben können, und in der Zeit sind 70-jährige natürlich anderweitig gestorben.

    Das hohe und recht steile Maximum um die 100 herum hatte ich so aber nicht erwartet. Zu ihm tragen vor allem Leute bei, die erst nach einigen Jahren – und dann deutlich gebrechlicher – mit SARS-2 in Kontakt kommen. Bei einer 100er-Inzidenz sieht die Wochensterblichkeit über der Zeit (in Wochen) so aus (cf. make_hist_fig im Skript):

    Kurve mit einem Maximum zwischen 1000 und 1700 Wochen

    Diese Kurve wäre ziemlich zackig, wenn ich strikt nach Gompertz-Formel nur ein Mal im Jahr natürliche Tode hätte, statt die diese geeignet auf die Wochen zu verteilen.

    Die Menschen, die am Anfang der Pandemie 70 sind, sterben in diesem Modell also typischerweise nach 1000 Wochen oder fast 20 Jahren, wenn sie ihn ihren 90ern wären. Das mag etwas fantastisch klingen. Jedoch: Das RKI hat früher immer dienstags die Demographie der Verstorbenen veröffentlicht (z.B. Bericht vom 30.3.2021, siehe S. 12), und tatsächlich sind 20% der Coronatoten in der Altersgruppe 90-99.

    Aber klar: Das ist hypothetisch. Niemand kann die Inzidenzen konstant auf 100 halten, und niemand wird das vernünftigerweise wollen. Vor allem aber mag die Impfung die IFR-Kurve durchaus so weit nach rechts verschieben, dass der Sterblichkeitspeak, der hier noch bei 90-jährigen sitzt, jenseits der 100 rutscht, und dann betrifft das, bei heutigen Lebenswerwartungen, praktisch niemanden mehr.

    Zynische Metriken

    Als Gedankenexperiment jedoch finde ich das Ganze schon bemerkenswert: Wenn wir eine 1000er-Inzidenz aushalten können, würden wir nach diesem, eingestandenermaßen idealisierten, Modell 7% der 70-jährigen den Tod durch SARS-2 ersparen.

    Ein so starker Effekt muss eigentlich schon aufgefallen sein. Wenn das kein Fehler auf meiner Seite ist: steht das schon irgendwo in der epidemiologischen Literatur?

    Allerdings ist die, ach ja, Metrik „Wie viele Leute sterben an SARS-2?“ auch ziemlich nichtssagend. Weit üblicher zur Einschätzung der Frage, wie viel Geld (oder Nerven) mensch für Interventionen gegen Krankheiten ausgeben mag, sind die YLL, Years of Life Lost (cf. nochmal DALY in der Wikipedia). Diese Metrik ist zwar – ganz wie meine Rechnung hier – ein wenig zynisch, aber doch nachvollziebar genug, dass ich mir aus meinem Modell auch nochmal die Gesamtlebensjahre habe ausspucken lassen, die meine 100000er-Kohorte in den Läufen mit den verschiedenen Inzidenzen …

  • El-Cheapo Internationalisation in Pelican and Jinja

    This blog is mainly in German, but in particular computer-related posts I'm writing in (some version of) English, as I expect they might be useful and/or interesting to quite a few people who don't speak German. On the English-language pages, I was always a bit unhappy that the footers (and to a certain degree, menu items) were in German.

    Now, the standard way to “internationalize” programs is gettext, and sure enough, Pelican's template engine Jinja supports i18n with gettext. But my actual use case is mainly to replace large blocks (like the full footer, which has little markup but quite a lot of text), and having gettext-style message catalogues for those seemed unattractive to me.

    Instead, I thought I could somehow work thorugh jinja computed includes, perhaps with something like:

    {% import 'messages-'+article.lang+'.html' as messages %}
    

    For each language I want to support, I'd then have one messages file (messages-en.html, messages-de.html, …), a bit like the message catalogues in gettext, but containing jinja markup.

    The first question to answer was: What jinja markup? After a few experiments, it seems to me that using jinja blocks – which initially had seemed idiomatic to me – to write these messages files is at least tricky. After a while I rather settled for macros, such that the message file could contain something like:

    {% macro basefoot() -%}
     <footer id="main-footer" class="clearfix">
       <ul class="nobull">
       <li><a href="/pages/wer.html">[Wer?/Kontakt]</a>
         | <a href="/archives.html">[Archiv]</a></li>
       ...
    {%- endmacro }
    

    and the application in the template would then be:

    {% block footer %}
      {{ messages.basefoot() }}
    {% endblock footer %}
    

    This works nicely for internationalising large tree fragments and is not a lot worse than gettext for single strings (though I admit message catalogues are a bit nicer to work with when translating).

    The one big problem was how to select the messages. For all the infrastructure pages (archive, tags, categories), I'm happy to use the default language (who looks at them, after all?). Hence,

    {% import 'messages-'+DEFAULT_LANG+'.html' as messages %}
    

    in the base.html template sounded like a good idea and went well enough. Then I thought I could use:

    {% import 'messages-'+article.lang+'.html' as messages %}
    

    in article.html and something similar in page.html. But alas: That won't work, because, as in python, jinja imports only happen once per run and are simply namespace operations when repeated.

    I then tried to put the import statement into a named block, hoping that perhaps block overriding would suppress the default import. I suspect it wouldn't have because block content, I gather, is executed unconditionally, but never mind: it won't work anyway because (at least that's what I gather) blocks have python namespaces of their own, and hence imports in a block are not visible outside of it. Hence, once I put the import statement into a jinja block, my messages object is gone from where I need it.

    So, I ended up with the following hack in base.html:

    {# Yeah, hard-coding the various cases here *is* lame, but
       you can't override an import in a child templates as far
       as I can see, so this seems the least ugly option #}
    {% if article %}
    {% import 'messages-'+article.lang+'.html' as messages %}
    {% elif page %}
    {% import 'messages-'+page.lang+'.html' as messages %}
    {% else %}
    {% import 'messages-'+DEFAULT_LANG+'.html' as messages %}
    {% endif %}
    

    – this is ugly, breaks the encapsulation of the article and page templates, and it generally sucks, but for now it's good enough for me. I suppose the clean way to do this would be through a pelican extension providing a variable main_language (perhaps), computed in much the same way as this.

    Let's see if this hack falls on my feet; for now, I like the way this works out and that most of the stuff on the article pages is now English on English pages and German on German pages.

    Ceterum censeo: the more template languages I use for producing XML (and yes, I'm aware jinja has a much wider scope), the more I'm convinced the low adoption of stan is another instance of IT discarding a clearly superior design. What a pity it is that, for all I can see, all the popular templating engines work against the existing XML markup rather than, as in stan, with it.

  • Müdigkeit zur rechten Zeit

    Ich persönlich bin ja überzeugt, dass Public Health-Studien in einer mindestens ebenso dramatischen Replikationskrise stecken wie Studien in der Psychologie. Die Überzeugung resultiert in erster Linie aus einer Überdosis von Papern zu Broccoli oder Spirulina als „Superfoods“, aber eigentlich glaube ich im Groben gar keiner Studie, die Lebensgestaltung mit Lebenserwartung zusammenbringt, ohne eine wenigstens annähernd plausible mechanistische Begründung zu liefern (im Idealfall natürlich so stringent wie bei der erblichen Hypomagniesiämie).

    Manchmal jedoch sind epidemiologische Befunde einfach zu schön für Skepsis. Der Wille zum Glauben regte sich bei mir beispielsweise bei „Accelerometer-derived sleep onset timing and cardiovascular disease incidence: a UK Biobank cohort study“ von Shahram Nikbakhtian et al (doi:10.1093/ehjdh/ztab088). Politikkompatibel formuliert behauptet die Arbeit, mensch solle zwischen 10 und 11 ins Bett gehen, um möglichst alt zu werden; so in etwa war es auch in Forschung aktuell vom 9.11.2021 zu hören (ab 2:58).

    Piktogramme und Schlagworte

    Aus dem Paper von Nikbakhtian et al: Ein „graphical abstract“. Wer bitte ist auf die Idee gekommen, alberne Piktogramme würden beim Verständnis eines wissenschaftlichen Aufsatzes helfen? CC-BY-NC Nikbakhtian et al.

    Angesichts meiner spontanen Sympathie für das Ergebnis wollte ich ein besser fundiertes Gefühl dafür bekommen, wie sehr ich dieser Arbeit misstrauen sollte – und was sie wirklich sagt. Nun: abgesehen vom „graphical abstract“, das auf meinem crap-o-meter schon nennenswerte Ausschläge verursacht, sieht das eigentlich nicht unvernünftig aus. Die AutorInnen haben um die 100000 Leute eine Woche lang mit Beschleunigungsmessern schlafen lassen, und ich glaube ihnen, dass sie damit ganz gut quantifizieren können, wann da wer eingeschlafen und wieder aufgewacht ist.

    Dann haben sie fünf Jahre gewartet, bis sie in der UK Biobank – einer richtig großen Datenbank mit allerlei Gesundheitsdaten, in die erstaunlich viele BritInnen erstaunlich detaillierte Daten bis hin zu ihren Gensequenzen spenden[1] – nachgesehen haben, was aus ihren ProbandInnen geworden ist.

    Eigentlich nicht schlecht

    Ein Projekt, das sich fünf Jahre Zeit lässt, ist schon mal nicht ganz verkehrt. Weiter haben sie ihre Datenanalyse mit R und Python gemacht (und nicht mit proprietärer klicken-bis-es-signifikant-istware wie SPSS oder SAS, oder gar, <gottheit> bewahre, Excel), was auch kein schlechtes Zeichen ist. Klar, es gibt ein paar kleine technische Schwierigkeiten. So haben sie zum Beispiel notorische SchnarcherInnen („Schlafapnoe“) ausgeschlossen, so dass von ihren gut 100000 ProbandInnen am Schluss zwar gut 50000 Frauen, aber nur knapp 37000 Männer übrig geblieben sind.

    Dann gibt es Dinge, die in der Tabelle 1 (S. 4 im PDF) seltsam wirken, aber wohl plausibel sind. So schätzen sich ein Drittel der TeilnehmerInnen selbst als „more morning type“ ein – wo sind all die Morgentypen in meiner Bekanntschaft? Und warum schätzen sich 27% der Leute, die erst nach Mitternacht einschlafen, als „more morning type“ ein (14% sogar als „morning type“)? Kein Wunder, dass die armen Leute dann allenfalls sechs Stunden Schlaf kriegen, die Nach-Mitternacht-SchläferInnen sogar nur fünfeinhalb. Oh grusel.

    Und die Tabelle gibt her, dass die Diabetesrate bei den Nach-Mitternacht-SchläferInnen erheblich höher ist als bei den Früher-SchläferInnen (fast 9% gegen um die 5.5%) – ist das eine Folge von Chips auf dem Sofa beim Fernsehkonsum? Ganz überraschend fand ich schließlich den niedrigen Anteil von RaucherInnen, der in allen Gruppen deutlich unter 10% lag. Das, denke ich, würde in der BRD auch bei der betrachteten Altersgruppe (meist älter als 50) noch ganz anders aussehen. Aber ich vermute eher, dass RaucherInnen in der (nach meiner Erinnerung auf freiwilliger Rekrutierung basierenden) Biobank stark unterrepräsentiert sind. Das wirft dann natürlich Fragen bezüglich anderer Auswahleffekte in der Testgruppe auf.

    Wie dem auch sei: Das Ergebnis am Schluss war, grafisch zunächst sehr beeindruckend (Abbildung 2 in der Arbeit), dass Leute, die zwischen 10 und 11 einschlafen, deutlich weniger Herz-Kreislauf-Probleme haben als die anderen, ein Ergebnis, das mir gut gefällt, denn ich werde recht zuverlässig gegen 22 Uhr müde und bin dann froh, wenn ich ins Bett kann.

    Aber leider: Wenn mensch z.B. die erhöhte Diabetesrate rausrechnet, bleibt von dem Schlaf-Effekt nicht mehr viel übrig, jedenfalls nicht bei Männern, bei denen nur die Frühschläfer gegenüber Andersschläfern signifikant erhöhte Risiken hatten. Diese ließen sich recht zwanglos erklären, wenn das z.B. Schichtarbeiter gewesen wären, denn die Korrelation zwischen Schichtarbeit und Herzgeschichten ist wohlbekannt.

    Das ist aus meiner Sicht ohnehin die größte Schwierigkeit des Papers: Da Armut und Reichtum in westlichen Gesellschaften der beste Prädiktor für die Lebenserwartung ist[2], hätte ich gerne eine Kontrolle gegen die Klassenzugehörigkeit gesehen. Aber ich vermute, dass die Biobank solchen Einschätzungen aus dem Weg geht.

    Was verständlich ist, denn diese könnten ja den Schwefelgeruch des Klassenkampfs verströmen. Der wäre bei der vorliegenen Studie sicher auch deshalb besonders unwillkommen, weil die AutorInnen alle für den Gesundheitshöker Huma arbeiten, der, wenn ich den Wikipedia-Artikel richtig lese, auch im Geschäft mit Fitnesstrackerei unterwegs ist. In deren Welt jedoch ist jedeR seiner/ihrer Gesundheit Schmied, so dass für Klassenfragen besonders wenig Platz ist.

    Global Burden of Disease

    Eine weitere Entdeckung habe ich beim Reinblättern ins Paper gemacht, weil ich schon den ersten Satz nicht glauben wollte:

    Cardiovascular disease (CVD) continues to be the most significant cause of mortality worldwide, with an estimated 18.6 million deaths each year.

    Das schien mir gewagt, denn unter der (falschen) Annahme eines Gleichgewichts müssten bei rund 8 Milliarden Menschen mit einer Lebenserwartung von 100 Jahren 80 Millionen im Jahr sterben; auf einen Faktor zwei wird das trotz starken Wachstums vor allem in der zweiten Hälfte des 20. Jahrhunderts (senkt die Todesrate, weil ja mehr Menschen relativ jung sind) sowie gegenläufig geringerer Lebenserwartung schon stimmen. Wenn die 80 Millionen hinkämen, würden Herz-Kreislaufgeschichten 20% der Todesursachen ausmachen. Das soll schon die Nummer 1 sein? Tja – ich bin dem Literaturverweis gefolgt.

    Dabei kommt mensch bei den Global Burden of Disease-Daten (GBD) eines Institute for Health Metrics and Evaluation an der University of Washington heraus, einer Übersicht über das, woran die Leute auf der Welt so sterben und wie viele Lebensjahre was kostet. Nur nur, weil da „Metrik“ drinsteht, wäre an der ganzen Anlage der Daten schon viel zu kritisieren – die Wikipedia bespricht z.B. in ihrem Artikel zu DALY einige Punkte. Und natürlich ist das „Tool“, über das mensch die Daten nutzen soll, wieder so eine Javascript Only-Grütze.

    Aber spannend ist das doch, angefangen bei der Ansage von GBD, es stürben derzeit weltweit rund 56.5 Millionen Menschen pro Jahr. Dabei geben die GBD-Leute ein – Vorsicht, unverantwortlicher Natwi-Jargon – 2 σ-Intervall, also 95%-Konfidenzbereich, von 53.7 bis 59.2 Millionen; so große Fehlerbereiche verstärken tatsächlich mein Zutrauen zu diesen Daten, denn wenn ich mir so das globale Meldewesen vorstelle, scheint es sehr nachvollziehbar, dass drei Millionen Tote mehr oder weniger nicht ohne weiteres auffallen. Sie verlören, und dabei wirds allmählich wirtschafts„wissenschaftlich“, dabei 1.7 Milliarden Lebenjahre an Krankheiten und ähnliches.

    Ich muss mich demnächst mal mehr damit beschäftigen. Schade, dass der November schon vorbei ist. Das wäre eine sehr jahreszeitgemäße Tätigkeit gewesen.

    [1]Auch einer meiner Lieblingskollegen tut das. Als wir uns mal drüber unterhalten haben, meinte er etwas wie: Ich dachte mir schon, dass du das komisch findest. Meine Antwort war: Nun, nicht per se, aber doch in einem Staat, der selbst von Kindern DNA-Profile einsammelt, um damit flächendeckend Ladendiebstahl aufzuklären.
    [2]Gut, das ist jetzt etwas provokant, zumal „bester“ ja immer eine Menge braucht, innerhalb derer verglichen wird, und über dieser eine Totalordnung, was für ziemlich viele praktisch relevante Mengen schon mal nicht (eindeutig) gilt. Hier: klar ist der Unterschied der Lebenserwartung für Leute mit und ohne amyotrophe Lateralsklerose noch größer als der zwischen armen und reichen Menschen, so dass „hat ALS” mit einigem Recht als „besserer“ Prädiktor bezeichnet werden könnte. Aber „ist arm“ erlaubt für weit mehr Menschen eine recht starke Aussage. Deshalb kann ich, ohne nur zu provozieren, mit mindestens gleichem Recht von „besser“ reden. Ist halt eine andere Ordnungsrelation. Oder eine andere Menge, in der exotische Prädiktoren gar nicht vorkommen.
  • Die überraschende Macht der Tradition

    Foto: Grabstein

    Nur, damit ich nicht falsch verstanden werde: Ich bin ein großer Fan von Argelander, so groß, dass ich zu seinem Grab in Bonn gepilgert bin.

    Als ich heute morgen bei heise online einen Artikel las, in dem die Entdeckung eines braunen Zwergs (oder meinethalben auch einen besonders großen Riesenplaneten) durch einen Amateurastronomen verkündet wurde, musste ich traurig lächeln, denn das Objekt, um das es ging, hieß dort – und, wie sich rausstellt, sogar in der Originalarbeit (doi:10.3847/1538-4357/ac2499; open access arXiv:2112.04678) – „BD+60 1417b“.

    Was ist daran traurig? Nun, das „BD“ darin bezieht sich auf die Bonner Durchmusterung, ein eingestandenermaßen epochales Werk. Nur eben eines mit dem Äquinoktium B1855.0, was aus dem Astronomesischen übersetzt „echt retro“ heißt. Genau: Die 1855 steht so in etwa für das bürgerliche Jahr 1855; wer genau nachrechnet, kommt auf den 31.12.1854, kurz vor zehn am Abend, aber legt mich jetzt bitte nicht auf die Zeitzone fest. Was Erdkoordinaten angeht, haben manche Leute damals noch mit der Längenzählung in Paris angefangen. „Äquinoktium B1855.0“ ist tatsächlich ein wenig mit sowas vergleichbar, denn es bezeicnet letztlich eine Art, den Himmel in Länge und Bereite aufzuteilen.

    Damit will ich nichts gegen die Arbeit von Friedrich Argelander – der hat das damals in der Hand gehabt – gesagt haben. Im Gegenteil: sie war unglaublich wertvoll, und es ist heute kaum glaublich, dass Menschen (statt Computer) überhaupt 325000 Sterne beobachten und die Beobachtungen reduzieren können. Aber der Kram ist halt Mitte des vorletzten Jahrhunderts beobachtet worden, und die abschließende Publikation war 1903.

    Dass Bezeichner aus Arbeiten vor der Publikation der speziellen Relativitätstheorie noch in einer Arbeit vorkommen, die mit Daten von einem Weltraumteleskop im mittleren Infraroten operiert, ist schon, na ja, zünftig, zumal eine schnelle Simbad-Anfrage reichlich weniger angestaubte Bezeichnungen geliefert hätte; vermutlich hätte ich das Ding aus persönlicher Verbundenheit PPM 18359 genannt, oder dann halt SAO 15880. Die wirklich aktuellen Gaia-Bezeichnungen hingegen („DR2 1579929906250111232“; ich habe gerade nachgesehen: die Nummer bleibt im DR3) – ach ja, die sind vielleicht wirklich nicht so gut für Menschen geeignet. Dabei sind sind die monströsen Ziffernfolgen nur 64 bit… eigentlich sollte es da eine menschenwürdigere Kodierung geben. Hm.

    Aber am Ende: es ist wieder die Macht der Tradition, die ich gerade für die Astronomie schon jüngst beklagt hatte, als es in Fußnote 1 um die in dem Bereich einfach nicht verschwinden wollenden sexagesimalen Koordinaten ging. Unter diesen Umständen würde ich mir vielleicht auch keine allzu große Mühe geben mit lesbaren Kodierungen von 64-bit-Zahlen.

  • Telecon-Gefühl: Das glaub ich jetzt nicht

    Nachdem ich hier schon zwei andere Patzer in Live-Übertragungen diskutiert habe, wird es klar Zeit für ein neues Tag: Live. Ich habe nämlich noch eine schöne und motivierende Reaktion auf technische Probleme in einer Live-Sendung [kommt es nur mir vor, als würde deren Rate zunehmen? Das wäre dann wohl Beleg für Digitalisierung…].

    Wieder sind es vor allem Erinnerungen an eigene Telecons, die mir Volkart Wildermuths Ausbruch in der Forschung aktuell-Sendung vom 19.11.2021 (Kudos an den DLF, dass sie die Panne nicht aus der Archiv-Sendung rausgeschnitten haben) so sympathisch machen:

    —Rechte beim Deutschlandfunk

    Der Seufzer bei Sekunde 27! Ich erkenne mich so wieder. Genau mein Geräusch, wenn der doofe Chromium (wer ist eigentlich auf die hirnrissige Idee gekommen, ausgerechnet in Webbrowsern Telecons zu halten?) wieder genau das Alsa-Audiodevice nicht findet, über das ich sprechen will.

    „Mann! Dann ruft mich an.“ Absolut ich. Bis in den Tonfall.

    „Das glaub ich jetzt nicht.“ Wie oft habe ich das schon gesagt speziell seit Corona, etwa, wenn der fiese closed-source zoom-Client (immerhin kein Web-Browser!) genau das xephyr-Fenster nicht zum Screenshare anbietet, in dem ich den Kram zeigen wollte (stattdessen aber alle Fenster von Dockapps, die er jetzt wirklich anhand ihrer Properties hätte rausfiltern können)? Das ganze Elend mistiger und unfixbarer proprietärer Software, der Horror von Javascript-Salat, zu deren Nutzung mich die Technikfeindlichkeit (im Sinne von: ich nehme halt das Bequemste und Vorgekochteste, was es nur gibt) meiner doch angeblich so digitalisierungslustigen Umwelt so nötigt: „Ach, Mann, das glaub ich jetzt nicht.“

    Abgesehen von der Panne fand ich in der Sendung übrigens speziell das das Segment über Flussblindheit wirklich hörenswert: Ich muss gestehen, dass ich diese komplett vermeidbare Dauerkatastrophe zwischenzeitlich verdrängt hatte. Noch so ein Ding, bei dem in hundert Jahren zurückblickende Menschen den Kopf schütteln werden: Wie konnten die eine so einfach behandelbare Krankheit so viele Opfer fordern lassen? Während sie, um nur ein besonders bizarres Beispiel zu nennen, gleichzeitig mit unfassbarem Aufwand High Frequency Trading gespielt haben?

  • Dickens und die Gründerzeit – Pro und Contra

    Ich bin kein besonderer Freund von Pro/Contra-Formaten wie der Streitkultur am Deutschlandfunk. Warum? Nun, ich denke, die dabei diskutierbaren Fragen lassen sich in drei Gruppen einteilen:

    1. Es gibt keine klare Antwort, und mensch muss sich auch nicht einigen. Beispiel: „Ist die Musik von Richard oder einem der Johann Strauße besser oder die von den Rolling Stones?“ – natürlich braucht das nur unter der Annahme keine Einigung, dass die Beteiligten sich aktustisch aus dem Weg gehen können; aber können sie das nicht, sollte vielleicht das repariert werden.
    2. Es gibt keine klare Antwort, und mensch muss sich irgendwie einigen, z.B. „Wollen wir hier im Flur noch ein Regal aufstellen?“ Das braucht eine Einigung unter der Annahme, dass die Beteiligten sich den Flur teilen, und es ist nicht klar entscheidbar unter der Annahme, dass der Flur auch mit Regal noch grob benutzbar bleibt.
    3. Es gibt eine ethisch oder sachlich klar gebotene Antwort, und es ist allenfalls statthaft, noch nachzusehen, wie viel Bequemlichkeit mensch sich gegen das gebotene Verhalten rausnehmen kann („können wir nicht 22 Grad machen in der Wohnung?“; „kann ich mir eine Flasche Kokos-Ananas-Saft kaufen?“).

    Beim ersten und dritten Typ hat so ein Pro/Contra-Format keinen Sinn; im ersten Fall ist der Streit Zeitverschwendung, weil weder Notwendigkeit noch Möglichkeit einer Einigung besteht. Im dritten Fall hingegen muss mindestens ein Part in der Diskussion entweder ethischen Bankrott oder Realitätsverweigerung erklären, wenn die ganze Veranstaltung nicht eine rhetorische Übung werden soll[1] (was mithin fast notwendig passiert).

    Nur bei Fragen vom Typ 2 hat so ein Format eigentlich Sinn. Es ist aber gar einfach, nichttriviale Beispiele für solche Fragen zu finden. Die in der Streitkultur vom 13.11. debattierte war jedenfalls nicht von diesem Typ: „Brauchen wir ein Einwanderungsrecht nach kanadischem Vorbild?“ Ethisch ist völlig klar, dass es nicht angeht, Menschen nach ihrer Herkunft zu sortieren, und so wäre das kanadische Modell vielleicht schon ein wenig besser als das, was wir jetzt haben, aber immer noch ein Tiefschlag gegen Ethik und Menschenrecht.

    Natürlich wurde das in der Sendung nicht so analysiert. Wie auch, wenn sich ein „Migrationsforscher“ (Dietrich Thränhardt, der immerhin schon seit den 1980er Jahren das „Gastarbeiter“-Narrativ bekämpft hat) mit einem VWL-Prof aus dem FDP-Sumpf (Karl-Heinz Paqué) herumschlagen muss. Dennoch fand ich die Sendung bemerkenswert, und zwar aus drei Gründen.

    Erstens gab es mal wieder so einen Dickens-Moment, also eine Aussage, mit der ganz analog die Reichen in der Zeit von Charles Dickens das katastrophale Elend gleich nebenan wegignorieren konnten. Wer sich fragt, wie Verhältnisse aus Oliver Twist (oder meinethalben dem kleinen Lord; Weihnachten steht ja vor der Tür) und weit Schlimmeres für die Menschen damals ertragbar waren: Nun, wir haben ganz ähnliche Verhältnisse immer noch, nur eben nicht mehr zwischen dem Manor House und der Taglöhnersiedlung, sondern zwischen globalem Norden und Süden. Und Paqué ist völlig klar, dass „wir“ diese schockierende Ungleichheit mit Gewalt aufrechterhalten und vertritt nonchalant, dass die Ausübung dieser Gewalt unser Recht, ja unsere Pflicht ist (ab Minute 9:12):

    Die Freizügigkeit innerhalb Europas kann man nicht mit einer globalen Freizügigkeit vergleichen. Wir haben hier eine gänzlich andere Situation, wie wir übrigens auch bei dem Migrationsstrom im Zusammenhang mit unserem Asylrecht sehen, das man natürlich ganz scharf von einem Zuwanderungspunktesystem unterscheiden muss. [...] Das ist nicht auf die Welt übertragbar. Hier muss man eine Auswahl treffen [... Minute 13:30] Bis wir diesen Punkt erreichen, eines globalen Arbeitsmarkts, den ich mir natürlich auch wünschen würde, als Liberaler, werden noch einige Jahrzehnte vergehen, da brauchen Sie eine Übergangslösung.

    Was ist der Unterschied zwischen Europa und der Welt? Nun, woanders sind die Leute noch schlimmer dran als in Rumänien oder Polen. Das damit verbundene Elend hat Paqué ganz offenbar völlig wegabstrahiert, als einen quasi naturgesetzlich „noch einige Jahrzehnte“ fortbestehenden Sachzwang. Genau so muss das die viktorianische Gentry auch gedacht haben, als sie die Kinder ihrer ArbeiterInnen zu 14-Stunden-Schichten in die Minen einfahren ließen.

    Immerhin, und das ist mein zweiter Punkt, hat Paqué eine realistische Selbsteinschätzung (Minute 14:05).

    Ich wäre als habilitierter Volkswirt völlig ungeeignet, um eine technische Aufgabe in einem Unternehmen zu lösen.

    Wenn das die anderen Volks- und Betriebswirte auch einsehen und aufhören würden, die Leute zu „managen“, die nachher die „technischen Aufgaben“ erledigen: Das wäre ein klarer Fortschritt.

    Und schließlich verriet Paqué, in welcher Zeit er sich sieht:

    Deutschland war zwar immer faktisch zu einem relativ hohen Grad ein Einwanderungsland, auch schon am Ende des letzten Jahrhunderts, im wilhelminischen Boom…

    Der „wilhelminische Boom“ heißt unter Nichtvolkswirten „Gründerzeit“. Beide Bezeichnungen sind etwa gleich dämlich, um so mehr angesichts des oben für die entsprechende Epoche in England diskutierten himmelschreienden Massenelends. Großzügig gerechnet geht es um ein paar Jahre um 1870 herum. Der Boom war, das nur nebenbei, schnell vorbei und mündete in rund zwanzig Jahre Krise.

    Diese Zeit noch im zweiten Jahrzehnt des dritten Jahrtausends als „letztes Jahrhundert“ zu bezeichnen: Nun, das passt gut zu jemand, der erkennbar immer noch Marktwirtschaft pfundig findet und möglicherweise sogar die ökonomischen Rezepte von damals für im Prinzip richtig, aber schlecht umgesetzt hält.

    [1]Damit will ich nicht gesagt haben, eine gemeinsame Klärung der Verhältnisse und Verhältnismäßigkeiten sei nicht sinnvoll. Das wären dann Fragen wie: was müssen wir noch rauskriegen, um eine verlässliche Antwort zu finden? Wie viel subjektiven Gewinn habe ich von einer Verletzung der physisch („Newton war ein Schwätzer: 10 m über dem Boden hört die Gravitation auf”) oder ethisch („Bei den Temperaturen setz ich mich nicht aufs Fahrrad.“) gebotenen Antwort? Aber genau dieser zweifellos sinnvolle Diskurs findet in Pro/Contra-Formaten konzeptionell und in aller Regel auch real nicht statt.
  • Fernseh-Livestreams mit Python und mpv

    Nachtrag (2022-10-11)

    Ich habe das Programm jetzt auf codeberg untergebracht

    Die Unsitte, alles in den Browser zu verlegen, ist ja schon aus einer Freiheitsperspektive zu verurteilen – „die Plattform“ gibt die Benutzerschnittstelle vor, kann die Software jederzeit abschalten und sieht (potenziell) noch den kleinsten Klick der NutzerIn (vgl. WWWorst App Store). Bei Mediatheken und Livestreams kommt noch dazu, dass videoabspielende Browser jedenfalls in der Vergangenheit gerne mal einen Faktor zwei oder drei mehr Strom verbraucht haben als ordentliche Videosoftware, von vermeidbaren Hakeleien aufgrund von schlechter Hardwarenutzung und daraus resultierendem Elektroschrott ganz zu schweigen.

    Es gibt also viele Gründe, speziell im Videobereich den Web-Gefängnissen entkommen zu wollen. Für übliche Videoplattformen gibt es dafür Meisterwerke der EntwicklerInnengeduld wie youtube-dl oder streamlink.

    Für die Live-Ströme der öffentlich-rechtlichen Anstalten hingegen habe ich zumindest nichts Paketiertes gefunden. Vor vielen Jahren hatte ich von einem Freund ein paar screenscrapende Zeilen Python erledigt dazu. In diesen Zeiten müssen allerdings Webseiten alle paar Monate komplett umgeschrieben („jquery ist doch total alt, angular.js hat auch schon bessere Tage gesehen“) und regelauncht werden, und das Skript ging mit einem Relaunch ca. 2015 kaputt. Als ich am Freitag die Tagesschau ansehen wollte, ohne DVB-Hardware zu haben, habe ich mich deshalb nach einer Neufassung des Skripts umgesehen.

    Das Ergebnis war eine uralte Seite mit mpv-Kommandozeilen und ein Verweis auf ein von den MediathekView-Leuten gepflegtes Verzeichnis von Live-Strömen. Da stehen zwar oben alt aussehende Timestamps drin, das Log aber zeigt, dass der Kram durchaus gepflegt wird.

    Aus letzterem habe ich livetv.py (ja, das ist ein Download-Link) gestrickt, ein weiteres meiner Ein-Datei-Programme. Installiert mpv (und Python, klar), macht chmod +x livetv.py und sagt dann ./livetv.py ARD Livestream – fertig. Bequemer ist es natürlich, das Skript einfach irgendwo in den Pfad zu legen.

    Das Argument, das das Programm haben will, kann irgendeine Zeichenfolge sein, die eindeutig einen Sender identifiziert, also nur in einem Sendernamen vorkommt. Welche Sender es gibt, gibt das Programm aus, wenn es ohne Argumente aufgerufen wird:

    $ livetv.py
    3Sat Livestream
    ...
    PHOENIX Livestream
    

    Mit der aktuellen Liste könnt ihr z.B. livetv.py Hamburg sagen, weil „Hamburg“ (auch nach Normalisierung auf Kleinbuchstaben) nur in einer Stationsbezeichnung vorkommt, während „SWR“ auf eine Rückfrage führt:

    $ livetv.py SWR
    SWR BW Livestream? SWR RP Livestream?
    

    „SWR BW“ (mit oder ohne Quotes auf der Kommandozeile) ist dann eindeutig, woraufhin livetv an den mpv übergibt.

    Ich gehe davon aus, dass die Anstalten die URLs ihrer Streams auch weiterhin munter verändern werden. Deshalb kann sich das Programm neue URLs von den MediathekView-Leuten holen, und zwar durch den Aufruf:

    $ livety.py update
    

    Das schreibt, wenn alles gut geht, die Programmdatei neu und funktioniert mithin nur, wenn ihr Schreibrechte auf das Verzeichnis habt, in dem livetv.py liegt – was besser nicht der Fall sein sollte, wenn ihr es z.B. nach /usr/local/bin geschoben habt.

    A propos Sicherheitsüberlegungen: Der update-Teil vertraut gegenwärtig ein wenig den MediathekView-Repo – ich entschärfe zwar die offensichtlichsten Probleme, die durch Kopieren heruntergeladenen Materials in ausführbaren Code entstehen, aber ich verspreche nicht, raffinierteren Angriffen zu widerstehen. Abgesehen vom update-Teil halte ich das Programm für sicherheits-unkritisch. Es redet selbst auch nicht mit dem Netz, sondern überlässt das dem mpv.

    Livetv.py sagt per Voreinstellung dem mpv, es solle einen „vernünftigen“ Stream aussuchen, was sich im Augenblick zu „2 Mbit/s oder weniger“ übersetzt. Wer eine andere Auffassung von „vernünftig“ hat, kann die --max-bitrate-Option verwenden, die einfach an mpvs --hls-bitrate weitergereicht wird. Damit könnt ihr

    $ livetv.py --max-bitrate min arte.de
    

    für etwas sagen, das für die Sender, die ich geprüft habe, auch auf sehr alten Geräten noch geht,

    $ livetv.py --max-bitrate max arte.fr
    

    für HD-Wahnsinn oder

    $ livetv.py --max-bitrate 4000000 dw live
    

    für einen Stream, der nicht mehr als 4 MB/s verbraucht.

    Technics

    Die größte Fummelei war, die Kanalliste geparst zu bekommen, denn aus Gründen, für die meine Fantasie nicht ausreicht (MediathekView-Leute: Ich wäre echt neugierig, warum ihr das so gemacht habt), kommen die Sender in einem JSON-Objekt (statt einer Liste), und jeder Sender hat den gleichen Schlüssel:

    "X" : [ "3Sat", "Livestream", ...
    "X" : [ "ARD", "Livestream", ...
    

    – ein einfaches json.loads liefert also ein Dictionary, in dem nur ein Kanal enthalten ist.

    Auch wenn ich sowas noch nie gesehen habe, ist es offenbar nicht ganz unüblich, denn der json-Parser aus der Python-Standardbibliothek ist darauf vorbereitet. Wer ein JSONDecoder-Objekt konstruiert, kann in object_pairs_hook eine Funktion übergeben, die entscheiden kann, was mit solchen mehrfach besetzen Schlüsseln pasieren soll. Sie bekommt vom Parser eine Sequenz von Schlüssel-Wert-Paaren übergeben.

    Für meine spezielle Anwendung will ich lediglich ein Mapping von Stationstiteln (in Element 3 der Kanaldefinition) zu Stream-URLs (in Element 8) rausziehen und den Rest der Information wegwerfen. Deshalb reicht mir Code wie dieser:

    def load_stations():
      channels = {}
      def collect(args):
        for name, val in args:
          if name=="X":
            channels[val[2]] = val[8]
    
      dec = json.JSONDecoder(object_pairs_hook=collect)
      dec.decode(LIST_CACHE)
    
      return channels
    

    – das channels-Dictionary, das collect nach und nach füllt, ist wegen Pythons Scoping-Regeln das, das load_stations definiert. Die collect-Funktion ist also eine Closure, eine Funktion, die Teile ihres Definitionsumfelds einpackt und mitnehmt. So etwas macht das Leben von AutorInnen von Code sehr oft leichter – aber vielleicht nicht das Leben der späteren LeserInnen. Dass die collect-Funktion als ein Seiteneffekt von dec.decode(...) aufgerufen wird und dadurch channels gefüllt wird, braucht jedenfalls erstmal etwas Überlegung.

    Der andere interessante Aspekt am Code ist, dass ich die Liste der Live-Streams nicht separat irgendwo ablegen wollte. Das Ganze soll ja ein Ein-Datei-Programm sein, das einfach und ohne Installation überall läuft, wo es Python und mpv gibt. Ein Blick ins Commit-Log der Kanalliste verrät, dass sich diese allein im letzten Jahr über ein dutzend Mal geändert hat (herzlichen Dank an dieser Stelle an die Maintainer!). Es braucht also eine Möglichkeit, sie aktuell zu halten, wenn ich die Liste nicht bei jedem Aufruf erneut aus dem Netz holen will. Das aber will ich auf keinen Fall, weniger, um github zu schonen, mehr, weil sonst github sehen kann, wer so alles wann livetv.py verwendet.

    Ich könnte die Liste beim ersten Programmstart holen und irgendwo im Home (oder gar unter /var/tmp) speichern. Aber dann setzt zumindest der erste Aufruf einen Datenpunkt bei github, und zwar für neue NutzerInnen eher überraschend. Das kann ich verhindern, wenn ich die Liste einfach im Programm selbst speichere, also selbstverändernden Code schreibe.

    Das ist in interpretierten Sprachen eigentlich nicht schwierig, da bei ihnen Quellcode und ausgeführtes Programm identisch sind. Zu den großartigen Ideen in Unix gehört weiter, dass (das Äquivalent von) sys.argv[0] den Pfad zur gerade ausgeführten Datei enthält. Und so dachte ich mir, ich ziehe mir einfach den eigenen Programmcode und ersetze die Zuweisung des LIST_CACHE (das json-Literal von github) per Holzhammer, also regulärem Ausdruck. In Code:

    self_path = sys.argv[0]
    with open(self_path, "rb") as f:
      src = f.read()
    
    src = re.sub(b'(?s)LIST_CACHE = """.*?"""',
      b'LIST_CACHE = """%s"""'%(in_bytes.replace(b'"', b'\\"')),
      src)
    
    with open(self_path, "wb") as f:
      f.write(src)
    

    Dass das Schreiben ein eigener, fast atomarer Schritt ist, ist Vorsicht: Wenn beim Ersetzen etwas schief geht und das Programm eine Exception wirft, ist das open(... "wb") noch nicht gelaufen. Es leert ja die Programmdatei, und solange es das nicht getan hat, hat mensch eine zweite Chance. Ähnlich übrigens meine Überlegung, das alles in Binärstrings zu bearbeiten: beim Enkodieren kann es immer mal Probleme geben, die am Ende zu teilgeschriebenen Dateien führen können. Vermeide ich Umkodierungen, kann zumindest die Sorte von Fehler nicht auftreten.

    Wie dem auch sei: Dieser Code funktioniert nicht. Und zwar in recht typischer Weise innerhalb der Familie von Quines und anderen Selbstanwendungsproblemen: das re.sub erwischt auch seine beiden ersten Argumente, denn beide passen auf das Muster LIST_CACHE = """.*?""". Deshalb würden von livetv.py update auch diese beiden durch das json-Literal mit den Senderdefinitionen ersetzt. Das so geänderte Programm hat zwei Syntaxfehler, weil das json natürlich nicht in die String-Literale passt, und selbst wenn es das täte, gingen keine weiteren Updates mehr, da die Such- und Ersatzpatterns wegersetzt wären.

    Eine Lösung in diesem Fall ist geradezu billig: in Python kann mensch ein Leerzeichen auch als '\x20' schreiben (das ASCII-Zeichen Nummer 0x20 oder 32), und schon matcht der reguläre Ausdruck nicht mehr sich selbst:

    re.sub(b'(?s)LIST_CACHE\x20= """.*?"""',
      b'LIST_CACHE\x20= """%s"""'...
    

    Sicherheitsfragen

    Ein Programm, das Daten aus dem Netz in sich selbst einbaut, muss eigentlich eine Ecke vorsichtiger vorgehen als dieses hier. Stellt euch vor, irgendwer bekommt etwas wie:

    { "Filmliste": [....,
      "X": ["...
      "Igore": ['"""; os.system("rm -r ~"); """']
    }
    

    in das MediathekView-Repo committet; das würde für die MediathekView immer noch prima funktionieren, das Objekt mit dem Schlüssel Ignore würde fast sicher tatsächlich einfach ignoriert.

    Wer dann allerdings livetv.py update laufen lässt, bekommt den ganzen Kram in Python-Quelltext gepackt, und der Inhalt des Ignore-Schlüssels wird vom Python-Parser gelesen. Der sieht, wie der lange String mit den drei Anführungszeichen geschlossen wird. Danach kommt eine normale Python-Anweisung. Die hier das Home-Verzeichnis der NutzerIn löscht. Python wird die treu ausführen. Bumm.

    So funktioniert das in Wirklichkeit zum Glück nicht, denn ich escape im realen Code Anführungszeichen (das .replace(b'"', b'\\"')). Damit …

  • Antisprache: Chancengleichheit

    Foto: Schriftzug

    Freiheit, Gleichheit, Brüderlichkeit am Rathaus des fünften Pariser Arrondissements. Ok, die „Brüderlichkeit“ sollte heute besser „Solidarität“ sein. Klar ist aber: Mit „Chancengleichheit“ in der Losung wäre das 1789 nichts geworden.

    Ein Klassiker der Antisprache – Wörtern, die von normalen Wörtern übertragene Information zerstrahlen wie Antimaterie normale Materie – ist „Chancengleichheit”. Seit meinem Schurken und Engel-Post, der eine reale Chancengleichheit modelliert hat, hatte ich immer mal diskutieren wollen, warum das eine sehr unrealistische Annahme war. Jetzt ist ein guter Anlass dafür da – siehe unten.

    Zunächst aber will ich meine Fantasie loswerden, wie zwei gewissenlose Werbefuzzis die Chancengleichheit ausgekocht haben:

    A: „Die Leute finden es irgendwie doof, dass ein Vorstand so viel kostet wie 1000 Leute, die die Arbeit machen [ok: Als dieses Gespräch stattgefunden haben könnte, war der Faktor vielleicht 100]. Wir müssen was tun.“

    B: „Da springen wirklich ein paar Knallköpfe rum, die finden, alle sollten gleich viel verdienen. Haha. Wo kämen wir denn da hin? Also: Erstmal müssen wir denen klarmachen, dass Gleichheit totaler und fieser Quatsch ist.”

    A: „Das ist einfach: Lass uns von Mao-Einheitskleidung erzählen. Das wird unser claim: Gleichheit ist eintönig!“

    B: „Genau! Und nicht die Gewalt, die die krassen Eigentumsunterschiede aufrechterhält, ist Zwang, nein, es wäre total fieser Zwang, wenn die Reichen nicht mehr die anderen für sich arbeiten lassen dürften. Gleichmacherei! Das wäre die üble Bevormundung, das ist mal klar.“

    A: „Aber… die Leute werden es immer noch doof finden, dass der Vorstand hässliche Protzbauten bauen lässt und endlos in der Welt rumjettet, während die Zeitungsausträger noch nicht mal Mindestlohn [ups: den hat es in der Geburtsstunde der Chancengleichheit in der BRD noch nicht gegeben] kriegen.“

    B: „Ah bah. Denen müssen nur eben bescheidstoßen, dass sie selbst schuld sind. Wäre der Zeitungsausträger halt auch Vorstand geworden. Er hätte ja die Chance gehabt. Vor allem die Chance, sich andere Eltern auszusuchen.“

    A: „Chance… Chance… Ich habs: Wir sagen »Chancengleichheit«. Damit ist ein bisschen von der Gleichheit drin, die die Leute ja immer irgendwie gerecht finden, aber noch der letzte Hirni versteht, dass es ihm nur deshalb dreckig geht, weil er seine Chancen verplempert hat.“

    B: „Brilliant. Mit ein bisschen Glück glauben sie sogar so arg dran, dass sie versuchen, ihren Kindern die Chancen, haha, wirklich zu geben, und wir können noch einen 1a Bildungsmarkt aufmachen. Heia Bruttosozialprodukt!“

    Also gut, ich kann jetzt nicht versprechen, dass das Gespräch genau so stattgefunden hat, vielleicht irgendwann in den 70ern. Ich finde das aber ziemlich plausibel. „Chancengleichheit“ ist jedenfalls ein zutiefst reaktionäres Konzept, das einerseits Ungleichheit legitimiert und andererseits Armen die Schuld an ihrer Situation zuschiebt.

    Ein Moment der Überlegung entlarvt diesen Begriff sofort: Niemand kann sich irgendwelche Verhältnisse vorstellen, in denen die Tochter eines armen, strukturell analphabetischen Paars auch nur irgendwie vergleichbare „Chancen“ hat wie der Sohn des Klischee-Paares aus Prof und Anwältin. Nicht auf Bildung, nicht auf ordentlich bezahlte oder gar halbwegs befriedigende Jobs, nicht auf eine Machtposition und auch nicht auf einen Sitzplatz in der Oper. Und selbst wenn sie die Chance hätte: würde das die dramatischen Unterschiede bei Existenzsicherheit, Lebenserwartung, Stinkigkeit der Jobs rechtfertigen, die wir in unserer Gesellschaft haben?

    Für mich ganz zweifellos: Würde es nicht. Die Ungleichheit ist das Problem, nicht irgendwelche Gemeinheiten, die ein paar Privilegierten ein Abo auf die Sonnenseiten (für irgendwelche vielleicht seltsamen Begriffe von Sonne) geben. Die zentrale Antisprachlichkeit von Chancengleichheit besteht im Versuch, das Gleichheitsgebot zu diskreditieren und zu demontieren. Demgegenüber fast schon verzeihlich wäre der innere Widerspruch, dass eine Gleichheit von Chancen überhaupt nur bei halbwegs gleicher gesellschaftlicher Teilhabe, also mindestens sozialer Gleichheit, vorstellbar ist. Etwas gedrechselt: die Chancengleichheit hat paradoxerweise die Gleichheit, deren Fehlen sie legitimieren würde, zur Voraussetzung.

    Natürlich bin ich nicht der erste, dem das auffällt, und so ist übers letzte Jahrzehnt oder so die „Chancengerechtigkeit“ populär geworden, vermutlich zunächst aus dem Gedanken heraus, Arme müssten gerechtigkeitshalber halt mehr Chancen bekommen als Reiche, damit es am Schluss „gerecht“ zugeht, ein wenig im Stil der affirmative action.

    Leider hilft das fast nichts. Auch die Chancengerechtigkeit legitimiert jede Ungleichheit („du hattest deine gerechte Chance und hast sie nicht genutzt“) und schiebt die Schuld für individuelles Elend nur noch mehr den Armen zu („wir haben dich ja sogar extra gefördert, aber dann hast du nur handygedaddelt und RTL 2 geschaut“).

    Nein: die richtige Forderung ist die nach Gleichheit, und erfreulicherweise hat die GEW im Gastkommentar der Erziehung und Wissenschaft 11/2021 Christian Baron das auf den Punkt bringen lassen:

    Die Formel muss also lauten: Erst die Umverteilung, dann die Bildung. Oder anders gesagt: Ein Goethe-Gedicht kann Wunder bewirken. Essen kann man es aber nicht. Anstatt Bildung als Weg aus der Armut zu verkaufen und ihr damit einen rein nutzenmaximierenden Ballast aufzuladen, sollte die Politik lieber dafür sorgen, dass kein Mensch mehr in Armut leben muss.

    Nur wäre die GEW nicht die GEW, wenn nicht in der gleichen Ausgabe das kritisierte Konzept im Titel eines Artikels auftauchen würde: „20 Jahre PISA: Schlusslicht in Sachen Chancengleichheit“. Nee: Nur, weil ein Hochamt der Metrik- und Marktreligion wie PISA für eine Weile mal Argumente für eigenen Interessen liefert (oder zu liefern scheint), ist das noch lang kein Grund, den Mist zu verwenden. Oder gar, die damit transportierte Antisprache gegen die eigenen LeserInnen einzusetzen.

  • Fortschritt statt Demokratie

    Demo-Szene: Die Polizei kickt Leute weg

    Meine bisher engste Begegnung mit Olaf Scholz: Ich bin der Mensch in Gelb mit dem Knüppel im Rücken. Die Herren mit den Helmen hat Olaf Scholz geschickt. Bildrechte: ARD.

    Der Vertrag, über den die künftigen Koalitionsparteien derzeit befinden, verballhornt das (ohnehin mit Glaubwürdigkeitsproblemen behaftete) Brandt-Motto „Mehr Demokratie wagen“ zu „Mehr Fortschritt wagen“ – das ist ohne großen Zwang zusammenziehbar zu „Fortschritt statt Demokratie“ als Motto der künftigen Scholz-Regierung.

    Das finde ich angesichts meiner bisherigen Erfahrung mit Scholz sehr naheliegend. Der körperlich eindrücklichste, quasi tuchfühlendste Teil dieser Erfahrungen ist im Bild oben zu sehen. Wir sind im Juli 2017, Hamburg wird von Olaf Scholz regiert. Im Wesentlichen die ganze Stadt ist gegen den von Scholz eingefädelten Gipfel der G20. Mag sein, dass er in dieser Situation keine andere Wahl hatte, als die willkürlichen und teilweise erschreckend gewalttätigen Einsätze der Polizei unter seinem Innensenator Andy Grote[1] bedingungslos zu unterstützen. Aber wahrscheinlich fand er sie gut. Bis heute jedenfalls war von ihm keine Distanzierung oder gar Entschuldigung zu hören.

    Bevor ich wie auf dem Bild oben Bekanntschaft mit einigen Scholz'schen Knüppeln machte, hatte die Polizei ein Protestcamp in Entenwerder geräumt, und zwar trotz eines diese Räumung untersagenden Gerichtsurteils. Gegen diesen dicken Stinkefinger in Richtung der G20-GegenerInnen ebenso in Richtung dessen, was sonntags als Rechtsstaat gelobt wird, hatten sich vielleicht tausend Leute auf einer Wiese versammelt, darunter ich und auch ein paar der aus Entenwerder Vertriebenen mitsamt ihren Zelten.

    Dann kam Polizei. Viel Polizei. Und prügelte die Leute vom Platz, ohne jeden erkennbaren Grund, sieht mensch davon ab, dass Scholz und Grote schlicht keine Störung ihrer Machtdemonstration dulden wollten. Und was als eine Machtdemonstration soll so ein Gipfel gleich neben einer, ach ja, Herzkammer des Linksradikalismus in der BRD – der Austragungsort Messehallen liegt gleich neben dem Karo-, und das wiederum gleich neben dem Schanzenviertel – denn wohl sein?

    So ging es weiter: Die Eröffnungsdemo („Welcome to Hell“) hat die Polizei von vorne in einer Straßenschlucht angegriffen – mit dem spätestens nach über anderthalb Jahren Maskenpflicht bei Versammlungen schier unfassbar dämlichen Vorwand, ein paar der TeilnehmerInnen hätten sich vermummt. Dass die zwischen drei Meter hohen Mauern und dem Rest der Demo eingeklemmten Menschen nicht angefangen haben, im Love-Parade-Stil panisch zu fliehen, finde ich bis heute bemerkenswert. Die Besonnenheit der Demonstrierenden hat, rückblickend betrachtet, die Köpfe von Scholz und Grote gerettet, denn Dutzende Zertrampelte wären nach dieser katastrophalen Polizeitaktik dann noch nicht durchgegangen.

    Diese Rettung dankten sie, indem sie am Folgetag am Rondenbarg nicht nur einen Demozug mit wirklich bemerkenswert brutaler Gewalt plattmachen ließen, sondern die Opfer des Einsatzes auch noch unter haarsträubenden Vorwürfen verfolgten und verfolgen – inklusive der Schikane, die auf viele Termine angelegten Verfahren selbst für Minderjährige in Hamburg laufen zu lassen, so dass Leute, die gerade noch in die Schule gegangen wären, mehrmals wöchentlich etwa auch aus Baden-Württemberg dorthin hätten fahren müssen. Immerhin ist aus der Schikane nicht viel geworden, wenn auch vor allem, weil die Justiz mit Corona nicht gut zurecht gekommen ist. Sollten die Rondenbarg-Prozesse nun doch wieder aufgenommen werden, dürften wohl auch die jüngsten Angeklagten mit der Schule fertig sein. Immerhin.

    Und damit sind wir zurück in der Gegenwart. In der ein Soldat den Corona-Krisenstab führen soll. Das hat, nach dem eben erzählten, aus meiner Sicht dem jede Menge innerer Logik. Der Menschenrechts-Record der kommenden Regierung wird jedenfalls absehbar kaum besser werden als der der Schröder-Administration.

    [1]Ja, genau der Grote, der neulich auch Menschen willkürlichen Hausdurchsuchungen unterworfen hat, ganz offenbar nur, um sein Mütchen zu kühlen („Pimmelgate“).
  • Trifft die Menschen hart

    Viele Kurven mit Lebenserwartungen

    Die SARS-2-Pandemie ist historisch: relative Änderungen der Lebenserwartungen nach Jahren für Männer, soweit doi:10.1016/S2214-109X(21)00386-7 brauchbare Daten hatte. In Blau ist die Veränderung 2020 (also vor allem durch SARS-2) markiert. Es lohnt sich, die Abbildung detailliert in einem eigenen Browserfenster anzusehen: Von den demographischen Folgen des Zusammenbruchs der alten Ordnung in vielen Ex-Ostblockstaaten über die Spanische Grippe und die verschiedenen Kriege bis hin zum Rauschen der kleinen Zahlen in Island ist viel zu entdecken. CC-BY Aburto et al.

    In den Informationen am Morgen im Deutschlandfunk hat der Moderator Rainer Brandes heute berichtet, dass die deutsche Regierung nun Einreisesperren für Menschen aus dem südlichen Afrika verhängt hat und fuhr fort mit dem Satz: „Das trifft die Menschen dort natürlich hart“.

    Wenn das ein Versuch von Empathie war, ist der ziemlich misslungen. Einerseits, weil „die Menschen“ in der Region im Schnitt sicher nicht gerade jetzt (es ist eiskalt!) dringend in die BRD wollen. Tatsächlich wäre ich überrascht, wenn das Land als Reise- oder Fluchtdestination überhaupt schon in vielen Köpfen aufgetaucht wäre, schon aus Sprachgründen.

    Weiter geht aus der Übersicht zur Visumspflicht des Auswärtigen Amts hervor, dass die BewohnerInnen aller Staaten des südlichen Afrikas (Südafrika/Azania, Eswatini, Lesotho, Simbabwe, Botsuana, Angola, Mosambik und sogar die unseres alten Schlachtfeldes Namibia) ohne Visum nicht reinkommen. Wie groß sind wohl die Chancen eines Durchschnittsmenschen aus, sagen wir, Namibia ohne bereits bestehende Kontakte hierher, so ein Visum zu bekommen?

    Der wirklich wesentliche Punkt in Sachen Empathie ist aber: Für fast die gesamte EinwohnerInnenschaft des südlichen Afrika stellt sich die Visafrage nicht, und auch nicht die coronabedingter Reisebeschränkungen: Die Leute sind schlicht zu arm, und bevor sie darüber nachdenken, wo sie nächste Woche hinfliegen könnten[1], müssen sie erstmal klarkriegen, was sie morgen zu beißen haben.

    Angesichts der oft wirklich schreienden Armut in der weiteren Region (und auch unserer eigenen Visapolitiken) ausgerechnet die coronabedinge Einreisesperre in die BRD als „hart“ zu bezeichnen – nun, das ist entweder verwegen oder ignorant.

    Etwas Ähnliches ist mir neulich beim Hören eines Interviews mit Arne Kroidl vom Tropeninstitut der GSU LMU München zu einer Corona-Seroprävalenzstudie in Äthiopien durch den Kopf gegangen. Hintergrund ist das Paper doi:10.1016/S2214-109X(21)00386-7, in dem berichtet wird, dass es zwischen August 2020 und und Februar 2021 im eher ländlich geprägten Jimma Inzidenzen im Bereich von im Schnitt 1600/100000/Woche gegeben haben muss, in Addis Abeba sogar über 4500; was das für Inzidenzen während der tatsächlichen Ausbrüche bedeutet, ist unschwer vorstellbar.

    Das ist dort offenbar nicht besonders aufgefallen, es hat ein Forschungsprojekt gebraucht, um es zu merken. In einer im Wesentlichen völlig ungeimpften Bevölkerung.

    Das ist kein Argument dafür, dass SARS-2 doch harmlos ist. Es ist ein Symptom der Nonchalance, mit der „wir“ Verhältnisse hinnehmen, in denen Menschen an einem Fleck recht normal finden, was woanders (zu recht) als wirklich ganz schlimme Gesundheitskrise empfunden würde. Bei aller Reserviertheit gegenüber Metriken und Zweifeln am Meldewesen: Laut CIA World Factbook ist die Lebenserwartung in Äthiopien 68 Jahre. Die Vergleichszahl für die BRD sind 81 Jahre.

    Aburto et al, doi:10.1093/ije/dyab207, schätzen, dass Corona, wo es wirklich schlimm durchgelaufen ist (Spanien, Belgien), etwa anderthalb Jahre Lebenserwartung gekostet hat (in der BRD: ca. 6 Monate). Wie viel schlimmer das ohne Lockdown geworden wäre, ist natürlich Spekulation, aber da es gerade die besonders verwundbaren Bevölkerungsgruppen ohnehin besonders schlimm erwischt hat, dürfte ein Faktor fünf zwischen dem realen Verlauf und dem schlimmsten Szenario eine sehr plausible Obergrenze geben, oder etwa eine um acht Jahre reduzierte Lebenserwartung. Auch damit wäre die BRD immer noch fünf Jahre über den offiziösen Zehlen in Äthiopien.

    Was in dieser Metrik[2] hier im Land ein unvorstellbares Gemetzel ist (denn fünf Mal Belgien wäre hier bundesweit Bergamo), ist dort Normalzustand, und zwar zu guten Stücken aus völlig vermeidbaren Gründen, wie beispielsweise unserer Völlerei; vgl. dazu How food and water are driving a 21st-century African land grab aus dem Guardian von 2010. Oder den IWF-Strukturanpassungsmaßnahmen, die, wo immer sie zuschlugen, das öffentliche Gesundheitswesen ruinierten und die Menschen Evangelikalen und anderen Hexendoktoren in die Arme trieben. Am Beispiel Peru illustriert zwangen „wir“ mit unseren marktradikalen Zivilreligion zwischen 1981 und 1990 die dortige Regierung zur Senkung der Gesundheitsausgaben um 75%.

    Verglichen mit solchen Totalabrissen sind unsere Gesundheitsreformen kaum mehr als das Niederlegen einer Hälfte der Doppelgarage vor der Villa. Dass „wir“ bei sowas dezent in die andere Richtung schauen, das ist ein noch größeres Empathieversagen als das vom Anfang dieses Posts.

    Nachtrag (2022-03-28)

    Der Hintergrund Politik vom 11. März wirft weitere Blicke auf die SARS-2-Situation in Afrika. In der Sendung berichtet Kondwani Jambo beispielsweise, dass BlutspenderInnen in Malawi im Februar 2022 bereits zu 80% SARS-2-positiv waren; auch in einem Land mit einem – laut Angaben der Sendung – Durchschnittsalter von knapp 18 hätte eine derart hohe Welle eigentlich stark auffallen müssen. Die Vermutung, Kreuzimmunitäten mit lokal verbreiteten anderen Coronavieren könnten geholfen haben, findet Jambo nicht bestätigt. Seine in der Sendung unverbindlich angebotene Erklärung über „schnellere“ Monozyten in Malawi gegenüber einer britischen Vergleichsgruppe finde ich allerdings spontan auch nicht allzu überzeugend.

    [1]Wie der BUND nicht ganz unplausibel behauptet: 90 Prozent der Weltbevölkerung haben noch nie ein Flugzeug von innen gesehen.
    [2]Wie immer sollte die Metrik nicht überbewertet werden; metriktheoretisch lesenswert ist in diesem Zusammenhang das Methoden-Kapitel der Aburto-Arbeit. Mensch sollte insbesondere klar haben, dass sich ein Tod weniger junger Menschen in der Lebenserwartung bei Geburt nicht von einem Tod vieler alter Menschen (wie bei SARS-2, wo der Verlust von Lebenserwartung bei Männern bei Aburto et al fast überall durch Tode in der Altersgruppe 60-79 dominiert ist) unterscheiden lässt. Mensch muss nicht Boris Palmer sein, um zwischen diesen Situationen unterscheiden zu wollen. Aber schon meine Erfahrungen mit Notaufnahmen in den USA (näher bin ich, eingestandenermaßen, Krankenhäusern im globalen Süden nie gekommen) sagen mir, dass die Lebenserwartungs-Zahlen eben doch oft sehr konkrete Not beim Zugang zu medizinischer Versorgung spiegeln.
  • Wasch mir den Pelz

    In der Forschung aktuell-Sendung vom 3.11. am Deutschlandfunk liefen zwei ziemlich bemerkenswerte Beiträge, die sich beide ein wenig im Umfeld von XKCD 1301 bewegen:

    Fake-Balkengrafik

    Nun: Ich würde XLS deutlich weniger trauen als der Autor dieser Grafik, Randall Munroe. Argumente dafür folgen unten. CC-BY-NC XKCD.

    Erstens gab es ein Interview mit Regina Riphan von der Uni Erlangen (nun: sie ist an deren WISO-Fakultät, sitzt also in Wirklichkeit in Nürnberg), in dem sie zur Nutzung wissenschaftlicher Erkenntnisse durch die Politik ab Minute 2:20 berichtet,

    dass die wissenschaftlichen Analysen am häufigsten verwendet werden, wenn sie thematisch und redaktionell aufbereitet sind

    und dann weiter ab 3:35:

    damit die Nutzung von wissenschaftlichen Erkenntnissen steigen kann, müssen die Texte gut verständlich sein und kurz zusammengefasst sein.

    Übersetzt: Wissenschaft bitte nur in Powerpoint. Eine Implikation dieser Erwartung zeigt der XKCD oben.

    Allein: Wenn etwas eindeutig ist, leicht konsumierbar runtergekocht und kurz zusammengefasst werden kann, ist es im besten Fall Lehrbuchwissen, aber jedenfalls nicht mehr Wissenschaft.

    Wissenschaft im Sinne von „was wir gerade erforschen” hat immer Voraussetzungen, Fehlerbetrachtungen und Einschränkungen, ohne die die Aussage nicht sinnvoll eingeordnet werden kann. Natürlich können auch wissenschaftliche Aussagen schon mal auf einen Satz zusammenschnurren („Cygnus X-3 enthält ein schwarzes Loch von 17 Sonnenmassen.”), aber der ist fast immer zu ergänzen mit einem „…wenn A, B und C so stimmen“. Ohne solche Einschränkungen wird es meist mehr oder weniger falsch („…aber wenn das so wäre, könnten wir das nicht im Röntgen sehen, und deshalb kann es gut sein, dass da stattdessen nicht mal ein weniger exotisches schwarzes Loch ist.“).

    Wer sich fragt, warum auch weit über den Umgang mit SARS-2 hinaus politisches Handeln oft ziemlich plemplem wirkt, könnte hier die Antwort finden. Wer Entscheidungen auf wissenschaftlicher Evidenz basieren will, muss sich auf Wisschenschaft einlassen, und das bedeutet in aller Regel, Papers zu lesen. Das dauert auch mit fachkundiger Erläuterung zumindest im Bereich der Naturwissenschaften Stunden. Für ein erstes Verständnis. Wer das nicht will, sollte vielleicht lieber nicht so viel entscheiden. Oder jedenfalls nicht sagen, seine/ihre Politik sei irgendwie anders als durch soziale Zwänge, Interessen, Fast Talk, Loyalität und Bauchgefühl geleitet.

    Dabei bleibt einzuräumen, dass ein großer Teil von Wissenschaft am Ende schlicht gar nicht hinhaut – wenn es einfach wäre, bräuchte es keine Forschung. Und gelegentlich ist Kram auch nicht nur falsch, weil er sackschwierig ist. Eine erstaunlich irre Geschichte in dieser Abteilung wird in einem zweiten Beitrag der Sendung erzählt: Da nutzen Leute ernsthaft Excel für Wissenschaft, etwas, das mir selbst in der Astronomie immer wieder mit fatalen Ergebnissen begegnet[1]. Wo Leute über Genetik reden, hat das besonders lachhafte Folgen:

    Der Name des Gens Septin 4, abgekürzt Sept4, wird automatisch in den vierten September umgewandelt.

    Das ist auch Mark Ziemann und KollegInnen von der Deakin University in Melbourne aufgefallen, die daraufhin nachgesehen haben, wie groß das Problem wohl in publizierten Arbeiten sein mag (PLOS Comput. Biol. 17(7), e1008984, doi:10.1371/journal.pcbi.1008984). Im DLF-Beitrag:

    [Ziemann:] „Die Ergebnisse waren kurz gesagt viel schlechter als bei unserer ersten Analyse 2016.“ [...] In fast jeder dritten Studie war ein Gen-Name in ein Datum gewandelt worden. [... Ziemann:] „Zunächst sollte Genomik nicht in eine Tabellenkalkulation aufgenommen werden. Es ist viel besser, Software zu nehmen, die für umfangreiche Datenanalysen geeignet ist.“

    Dem Appell am Ende des Zitats kann ich mal mit ganzem Herzen zustimmen, und zwar wie gesagt weit über das Feld der Genetik hinaus. Eine so klare und offensichtlich wahre Aussage verlässt das Feld der Wissenschaft. Ich kanonisiere sie hiermit zu Lehrbuchwissen.

    [1]Richtig schräg wird es, wenn Leute in Tabellenkalkulationen mit vorzeichenbehafteten sexagesimalen Koordinaten wie -80° 14' 27" rechnen. Klar, das sollten sie auch ohne Excel nicht tun, aber Leute, die immer noch Excel verwenden, haben offensichtlich besonders große Schwierigkeiten, sich von problematischen Traditionen zu lösen.
  • Wieder falsch vorhergesagt

    Also gut. Ich sehe es ein. Und gebe es auf. Vor neun Tagen hatte ich vorhergesagt, heute müssten so in etwa 4700 Intensivbetten mit SARS-2-PatientInnen belegt sein. In Wahrheit liegt die DIVI-Zahl im RKI-Bericht von heute bei 3987, also gut 15% darunter. Das wäre bei meinen sonstigen Handwerks-Abschätzungen kein Drama. Hier aber sagt es klar: Meine Methode taugt (erstmal) nicht (mehr).

    Hintergrund war mein Artikel von vor 18 Tagen, in dem ich (für Verhältnisse dieses Blogs sorgfältig) die Verzögerung zwischen steigenden Inzidenzen und in der Folge steigender Intensivbelegung abgeschätzt habe. Das Ergebnis für die vierte Welle waren neun Tage. Doch schon die daraus folgende Abschätzung der Intensivbelegung vor neun Tagen lag weit daneben.

    Und nun liege ich eine weitere Verzögerungsperiode später wieder falsch. Das ist also ganz offenbar alles Quatsch. Während ich mich bei der letzten falschen Vorhersage noch mit einer Fehlanwendung des heuristischen Modells herausreden konnte, ist das bei zwei falschen Vorhersagen nicht mehr drin. Nein. Die Prämisse ist falsch. Die Instensivbelegung folgt nicht mehr, wie noch in den zweiten und dritten Wellen, ganz brauchbar der Inzidenz. Die beiden Kurven haben sich inzwischen sehr deutlich entkoppelt:

    Graph: Entkoppelte Entwicklungen

    Meldezahlen des RKI vs. DIVI-Zahlen (Quellen vgl. Halbwegs gute Nachrichten). Auf der Zeitachse Sekunden seit 1.1.2020; 5⋅107 entspricht dabei dem 1.8.2021. Die Intensivbelegung ist um neun Tage nach vorne gezogen, um den wahrscheinlichsten Verzug auszugleichen und die Kurven übereinanderzubringen. Die y-Achse ist wie immer bei solchen Wachstumsplots von mir logarithmisch (also: exponentielles Wachstum ist eine Gerade). Die Skalierung der Intensivbelegung ist frei Auge, aber egal, wie mensch das macht: die Kurven passen nicht übereinander.

    Ganz offensichtlich reagiert die Intensivbelegung „weicher“ als die Inzidenz, und zwar nicht nur, wie aufgrund längerer Liegezeiten zu erwarten, nach unten, sondern auch nach oben. Es ist eben derzeit nicht so, dass aus einer gegebenen Zahl von Infizierten eine leicht vorhersehbare Zahl von IntensivpatientInnen wird. Daher ist vorläufig jede Vorhersage, die von einem konstanten Verhältnis von Intensivbelegung zu Inzidenz ausgeht, eine schlechte und ziemlich sicher falsche Vorhersage.

    Das richtige Vorgehen wäre jetzt, nachzusehen, was eigentlich diese Annahme kaputt macht (wobei: wie ich im September herausgefunden habe, war sie so ganz richtig ohnehin nie). Leider gibt es eine große Zahl möglicher Gründe, allen voran ist das natürlich die Demographie. Solange sie nicht ihre Eltern und Großeltern anstecken, können sich sehr viele Kinder mit SARS-2 infizieren, bevor das irgendwo in Intensivstatistiken sichtbar wird, während umgekehrt ein einziger Ausbruch in einem Pflegeheim mit gebrechlichen Menschen einige dutzend Intensivbetten belegen mag, was auch bundesweit schon eine Veränderung im einstelligen Prozentbereich ausmachen würde.

    Dazu kommen dann regional und nach Altersgruppen recht deutlich schwankende Impfquoten: Rasant steigende Inzidenzen in Bremen mit einer relativ stark durchimpften Bevölkerung geben ziemlich sicher ein deutlich schwächeres Signal auf Intensiv als eine rollende Welle in Sachsen, wo immer noch viele Menschen im mittleren Altersbereich ungeimpft sind und damit weit eher langwierige und kritische Verläufe nehmen werden

    Nachtrag (2021-11-25)

    Zum Thema Sachsen ist in der taz vom 25.11. zu lesen, von den dortigen 14000 PolizistInnen seien derzeit 519 SARS-2-positiv. Das ist eine 100000er-Wocheninzidenz zwischen 1500 und 4000, je nach dem, wie die zählen, und damit selbst für sächsische Verhältnisse (RKI-Inzidenz heute 1075) ziemlich sportlich.

    Mein int/inc-Maß (IntensivpatientInnen pro Inzidenzpunkt) ist aber auch empfindlich für Auswahleffekte. So wird es immer dann stark sinken, wenn systematisch getestet wird: Wenn die Dunkelziffer unerkannt Infizierter runtergeht, geht die Inzidenz im Hellfeld und damit mein Nenner hoch, ohne dass sich an der im Zähler reflektierten Realität etwas ändert. Besonders verzerrend werden sich solche Effekte auswirken, wenn systematische Tests nur demographisch oder impfstatistisch sehr auffällige Teile der Bevölkerung erreichen (sagen wir: SchülerInnen).

    In Summe: Wer derzeit aus der Inzidenzkurve Vorhersagen über die Intensivbelegung machen will, musss Impfquoten und Demographie, und damit auch die geographische Verteilung der Inzidenz, berücksichtigen, wenn das irgendwie hinkommen soll. Und das mutiert zu mehr Arbeit als ich in der Kategorie handwerk tun will.

    Bestimmt macht das irgendwer auch richtig. Aber dann: die Zahlenspielereien ändern nichts daran, dass wir Inzidenzen um 5000 haben müssten, wenn wir im nächsten Frühling durch sein wollen (100000/(5000 pro Woche) entspricht 20 Wochen oder einem knappen halben Jahr, mit Dunkelziffer also vielleicht einem Vierteljahr oder so), und auch nicht daran, dass das mit unseren augenblicklichen Techniken und Politiken ein furchtbares Gemetzel werden würde. Seufz.

  • Kohlendioxid auf dem Balkon

    Nicht offensichtlich korrelierte Kurven von CO_2, Windgeschwindigkeit und Temperatur

    CO2-Konzentrationen auf meinem Straßenbalkon, zusammen mit Windgeschwindigkeiten und Temperaturen. Das ist ein SVG, es lohnt sich also durchaus, in einem separaten Browserfenster in den Plot zu zoomen.

    Ich habe neulich eine längere Zeitreihe mit CO2-Konzentrationen auf meinem „vorderen” Balkon genommen. Zur Einordnung: Das Messgerät steht so etwa 10 Meter über und 15 Meter neben einer halbwegs viel befahrenen Straße. Ob das wohl etwas mit den wilden Schwankungen zu tun hat, die in der Kurve oben vor allem um den 9.11. herum zu sehen sind? Muss ich meine Einschätzung von neulich, einzelne Autos seien selbst im mittleren Nahbereich im CO2 kaum nachzuweisen (nun: an der frischen Luft, natürlich), revidieren?

    Verheizt jemand 100000 Tonnen Kohlenstoff am Tag?

    Wer die Kurven von Windgeschwindigkeit[1] und CO2-Konzentration vergleicht, könnte schon glauben wollen, ohne externe Frischluftzufuhr (also bei niedrigen Windgeschwindigkeiten) gehe das CO2 lokal merklich nach oben. Wirklich überzeugen kann mich aber keine Korrelation zwischen den verschiedenen geplotteten Größen.

    Darum gehe ich die Frage zunächst deduktiv an: woher könnten die enormen Schwankungen der CO2-Konzentration wohl kommen? Wir reden hier von einer Spanne zwischen 260 ppm und über 400 ppm, wobei es vorkommen kann, dass ich innerhalb von wenigen Stunden 100 ppm mehr CO2 sehe. Der langfristig ansteigende Trend macht mir übrigens weniger Sorgen: Wenn die Photosyntheserate Richtung Winter dramatisch sinkt, die Emission aber z.B. wegen Heizung eher zunimmt, ist das angesichts der beschränkten globalen Durchmischung der Atmosphäre auf der Erde zu erwarten[2], auch wenn das vielleicht nicht gerade innerhalb von zwei Wochen vonstatten gehen sollte.

    Mit den Werkzeugen aus dem Artikel zu meiner Heizleistung von neulich kann mensch abschätzen, was so eine Konzentrationsschwankung in einer lokal gut durchmischten Atmosphäre in, sagen wir, verbranntem Kohlenstoff bedeuten würde.

    Dafür muss ich erst überlegen, wie viele CO2-Teilchen ΔNCO2, oder der Bequemlichkeit halber eher welche CO2-Stoffmenge ΔnCO2 = NCO2 ⁄ A („in mol”) es braucht, um die Konzentration (in ppm, also CO2-Molekülen pro Million Teilchen insgesamt) innerhalb eines angenommenen Volumens V um das Δcppm zu erhöhen, das ich aus dem Plot ablese. Gemäß meinen Rezepten von neulich ist das:

    ΔnCO2 = (V)/(Vm)⋅Δcppm⋅106, 

    wobei Vm wieder das Normvolumen ist (22.4 Liter pro mol); das A von oben war die Avogadro-Konstante. Um herauszukriegen, wie viel Kohlenstoff (sagen wir, in Kilogramm) ich verbrennen muss, um diese Änderung quasi durch „frisches“ CO2 hinzukriegen, muss ich das nur noch mit dem Atomgewicht von Kohlenstoff uC multiplizieren.

    Das Atomgewicht ist, weil Kohlenstoffkerne meist 6 Protonoen und 6 Neutronen enthalten, mit 12 g/mol gut abgeschätzt (ganz genau ist das nicht, vor allem weil in der Atmosphäre auch etwas C-13 und sogar ein wenig C-14 herumschwebt). In dieser Kopfzahl steht das Gramm aus historischen Gründen. Das Mol wurde so definiert, dass die Zahl der Nukleonen im Kern so in etwa das Atomgewicht liefert, als in der Wissenschaft das cgs-System (aus Zentimeter, Gramm und Sekunde) seine große Zeit hatte. Würde mensch das Mol in den heutigen SI-Zeiten (na gut: die meisten AstronomInnen bleiben dem cgs verhaftet und reden zum Beispiel über Energien in erg) definieren, wäre die Avogadro-Konstante um einen Faktor 1000 (nämlich den Faktor zur SI-Einheit Kilogramm) größer.

    Wie auch immer: Wenn ich mir mal vorstelle, dass das, was ich da auf meinem Balkon messe, repräsentativ für den Umkreis von 10 km und bis in eine Höhe von 2 km wäre (mensch ahnt schon: Ich eröffne hier eine Reductio ad absurdum), komme ich auf ein Volumen von

    V = 2⋅π⋅(10  km)2⋅(2  km) ≈ 1.3⋅1012  m3

    was mit Vm ≈ 0.02 m3 ⁄  mol, einer Änderung von 100 ppm, die mensch als Sprung am 9. und 10.11. sehen kann, sowie der Formel oben auf

    ΔmC  = uC(V)/(Vm)⋅Δcppm⋅106  ≈ 0.012 kg ⁄ mol(1.3⋅1012  m3)/(0.02 m3 ⁄  mol)⋅100⋅10 − 6  ≈ 8⋅107  kg

    oder achzigtausend Tonnen verbrannten Kohlenstoff führt. Das klingt nach richtig viel und ist es auch. Aber das Volumen, das ich hier betrachte, sind eben auch 1200 Kubikkilometer, und wer sich erinnert, dass ein Kubikmeter eines normalen Gase bei Normalbedingungen um die 1 kg wiegt, kann leicht ausrechnen, dass die Luft in diesem Volumen 1.2⋅1012  kg (oder 1.2 Milliarden Tonnen – Luft in großen Mengen ist überhaupt nicht leicht) wiegen wird. Dieser ganze Kohlenstoff macht also ungefähr 0.07 Promille (oder 70 Milionstel) der Masse der Atmosphäre aus, was ganz gut mit den 100 ppm in Teilchen zusammengeht, die wir in die ganze Rechnung reingesteckt haben.

    Andersrum gerechnet

    Tatsächlich kann mensch die Kohlenstoffmasse, die eine Erhöhung der Teilchenkonzentration in einem Gasvolumen bewirkt, auch so herum abschätzen. Der Umrechnungsfaktor von Teilchen- zu Massenkonzentration ist der Faktor zwischen den Dichten von CO2 und Luft. Das Verhältnis dieser Dichten ist wiederum das der jeweiligen Atommassen, solange jedes Teilchen das gleiche Volumen einnimmt; das schließlich folgt aus der Annahme, dass die Gase ideal sind, was wiederum für unsere Abschätzungen überallhin gut genug ist.

    Für CO2 ist das mit den überwiegend vorkommenden Isotopen von Sauerstoff und Kohlenstoff 16 + 16 + 12 = 44, für Luft, wenn wir nur auf den Stickstoff N2 schauen, 14 + 14 = 28. Demnach macht 1 ppm in der Teilchenzahl von CO2 44 ⁄ 28 ≈ 1.6 ppm in der Masse aus, solange die CO2-Konzentration so gering ist, dass tatsächlich N2 die Dichte dominiert.

    Andererseits macht Kohlenstoff nur 12 ⁄ 44 ≈ 0.3 an der Masse im CO2 aus, die Zunahme an Kohlenstoff ist demnach nur ein Drittel von dem gerade berechneten 1.6, also etwas wie 0.5. Folglich werden aus 100 ppm Änderung in der Teilchenzahl etwas wie 100⋅0.5 = 50  ppm Änderung in der Masse; wer das genauer rechnet, bekommt auf diese Weise natürlich das gleiche Resultat wie oben raus.

    Wie herum mensch das auch rechnet, es ist klar, dass niemand in der kurzen Zeit so viel Kohlenstoff verbrennt. Ein schneller Reality Check: Meine Kohlendioxid-Kopfzahl war, dass die BRD 2/3 Gigatonnen im Jahr emittiert, was mit dem C/CO2-Verhältnis von 0.3 von oben ungefähr 200 Megatonnen Kohlenstoff entspricht, oder irgendwas wie gut 500000 Tonnen am Tag. Damit wäre die Zunahme, die ich hier sehe, rund ein Sechstel des gesamten Kohlenstoffbudgets der BRD, und mehr, wenn der Anstieg schneller als in einem Tag vonstatten geht: Das ist (fast) natürlich Quatsch.

    Aber was ist es dann? Noch immer gefällt mir die These ganz lokaler Schwankungen nicht. Wenn hier wirklich nur das CO2 von Autos und Heizungen nicht mehr weggepustet würde, müsste die Korrelation zwischen CO2 und Wind viel deutlicher sein.

    Ist es eine die Abgasfahne des GKM?

    Nächster Versuch: Rund 12 km westlich von meiner Wohnung läuft das Großkraftwerk Mannheim („GKM“). Wenn das Volllast fährt und meine Wohnung in seine Abgasfahne kommt, könnte das so ein Signal geben?

    Nun, so ein Kraftwerk liefert ungefähr 1 Gigawatt elektrische Leistung (wie mir der Wikipedia-Artikel dazu gerade verrät: darunter 15% des deutschen Bahnstroms), was bei einem Wirkungsgrad von 1/3 (ok, bei modernen Kohlekraftwerken ist das noch ein wenig mehr, aber als Kopfzahl taugt es) auf 3 Gigawatt thermische Leistung führt (tatsächlich nennt die Wikpedia eine Bruttoleistung von 2146 MW für das GKM).

    Aus den 394 kJ/mol, die bei der Verbrennung von Kohlenstoff frei werden (vgl. den Artikel zu meiner thermischen Leistung) könnte mensch jetzt die CO2-Emission aus der Bruttoleistung ableiten, aber ich bin mal faul und sehe beim WWF nach, der für Kraftwerke dieser Größenordnung ansagt, für eine Kilowattstunde Strom (wir sind dann also wieder bei der Nutzleistung) werde rund ein Kilogramm CO2 emittiert.

    Wenn das Kraftwerk also Volldampf (rund ein GW netto) macht, wird es etwa

    109  W⋅0.001 kg ⁄ Wh = 106 kg ⁄ h

    CO2 emittieren, also etwa 1000 Tonnen, was wiederum mit unserem 0.3-Faktor zwischen Kohlenstoff und CO2 zu einem Kohleverbrauch von 300 Tonnen pro Stunde führt.

    Damit leert das Kraftwerk unter Vollast ein Großes Rheinschiff in zehn Stunden – das scheint mir zwar schon sehr schnell zu gehen, ist aber auch nicht gänzlich unplausibel. Gegenrechnung: Das WWF-Dokument von oben nennt 7.7⋅109  kg ⁄ a als CO2-Emission des GKM im Jahr 2006. Mit der Ur-Kopfzahl π ⋅ 1e7 Sekunden pro Jahr übersetzt sich das in eine mittlere Emission von etwa 200 kg pro Sekunde oder gut 1000 Tonnen pro Stunde. Das passt fast zu gut, denn als jemand, der das Kraftwerk von seiner Leseecke aus sehen kann, kann ich zuverlässig sagen, dass das Ding keineswegs durchläuft. Andererseits hatte das Kraftwerk 2006 auch noch einen Block weniger, und überhaupt ist in der Rechnung genug Luft für Stillstandszeiten.

    Nehmen wir …

  • Sicherheit, die wirklich niemand will

    Ich habe nie viel von dem Gerede von der „Balance von Sicherheit und Freiheit“ gehalten – so würde ich etwa behaupten, dass ohne eine gewisse soziale Sicherheit Freiheit ein recht hohler Begriff wird. Wer, sagen wir, unter permanenter Drohung durch die Hartz IV-Kautelen lebt, hat zumindest nicht mehr die Freiheit, sinnlose und miese Arbeit (Call Center, Lieferdienste, Burgerflippen) abzulehnen. Wenn nun die Gesellschaft auf absehbare Zeit nicht vom Arbeitszwang wegkommt, sind vermutlich nicht viele Zwänge (ja: Einschränkungen von Freiheit) demütigender als eine Lohnarbeit tun zu müssen, ohne einen Sinn in ihr zu sehen oder wenigestens Spaß an ihr zu haben.

    Aber gut: Die Leute, die gerne vom Widerspruch zwischen Freiheit und Sicherheit reden, haben sicher keine Freiheit zur Faulheit im Sinn, sondern eher die Freiheit, sich anderer Menschen zur eigenen Bereicherung zu bedienen. Auch ihre Sicherheit ist eine ganz andere als die von Existenz und Obdach. Ihre Sicherheit ist ziemlich genau das, das von Polizei, Militär und Überwachungstechnologie hergestellt, genauer: erzwungen werden kann. Erst bei diesem Erzwingen wird der Widerspruch von Freiheit und Sicherheit unausweichlich; er hängt damit aber klar an einem genz spezifischen Begriff von Sicherheit, den, wird er explizit gemacht, wohl nicht viele Menschen teilen werden.

    Ein gutes Beispiel, dass häufig gerade die „Geschützten“ diese Sorte Sicherheit gar nicht haben wollen, gab es am 24. Oktober im Hintergrund Politik des DLF: Jedenfalls offiziell zum „Schutz“ der auf Samos gestrandeten Geflüchteten findet im dort neu errichteten Lager eine strikte Eingangskontrolle statt. Die ist aber nur bis 20 Uhr besetzt. Das Lager ist außerdem am Ende der Welt, so dass Stadtausflüge am Nachmittag riskant werden. Ein Geflüchteter berichtet in der Sendung:

    Ich brauche [für den Weg zurück aus der Stadt] eine Stunde und 20 Minuten. Aber wenn du es nicht rechtzeitig zurückschaffst, lassen sie dich nicht mehr rein. Das ist mir schon passiert. Ich musste die ganze Nacht draußen verbringen. Im alten Camp haben wir zwar im Zelt gelebt, aber wir hatten unsere Freiheit.

    Grob in den Bereich passt etwas, auf das ich seit Wochen linken wollte, weil es wirklich lesenswert ist, nämlich die Stellungnahme von Amnesty International zum neuen Versammlungsgesetz in NRW. Ich glaube zwar nicht, dass irgendwer ernsthaft versucht, diesen Gesetzentwurf mit „Sicherheit” zu begründen. Es geht recht offensichtlich durchweg nur um autoritären Durchgriff („öffentliche Ordnung“). Dafür ist der Abbau von Grundrechten, die die Voraussetung von „Freiheit“ in jedem nicht völlig verdrehtem Sinn sind, hier aber auch besonders greifbar.

    Das sage nicht nur ich aus meiner linksradikalen Ecke. Selbst die sonst ja eher zurückhaltenden Leute von ai reden Klartext:

    Mit der Distanzierung von der Brokdorf-Entscheidung distanziert sich der Gesetzentwurf daher nicht nur von der Rechtsprechung des Bundesverfassungsgerichts, sondern auch von international verbindlichen Menschenrechtsstandards.

    Wie gesagt: Lohnende Lektüre für alle, die noch gerne einen Unterschied hätten zwischen den viel geschmähten „autokratischen Regimes“ und ihren eigenen Regierungen. Oder, sagen wir, den Verhältnissen in Spanien. Oder denen in Hessen.

  • Keine guten Nachrichten

    Und wieder muss ich meinen Hut essen im Zusammenhang mit meinen Corona-Zahlenspielen. Ich hatte nämlich vor neun Tagen zuversichtlich vorhergesagt, so etwa jetzt sollten knapp 3500 Intensivbetten in der BRD mit SARS-2-PatientInnen belegt sein, mit dem Argument, dass sich die entsprechenden Zahlen derzeit neun Tage hinter der Inzidenz herbewegen. Da (und das war, wie unten diskutiert, ein Fehlschluss) die Inzidenz in den neun Tagen vor dem 6.11. um 44% gestiegen war, sah ich die Intensivbelegung heute bei 2332⋅1.44 ≈ 3350. Tatsächlich aber berichtet das RKI heute von nur 3034 SARS-2 IntensivpatientInnen, also um die 10% weniger als meine Vorhersage – oder 30% weniger Anstieg, um die Fehleinschätzung mal deutlicher zu machen.

    Ein Metafehler und einige Nicht-Fehler

    Es war schon ein paar Tage abzusehen, dass ich falsch liegen würde, und ich habe mir bereits letzte Woche ein paar lose Gedanken gemacht, wo wohl mein Fehler liegen könnte. Nicht angreifen konnte ich meine Argumentation aus dem Artikel, nach der die Leute, die in den vergangenen neun Tagen intensivpflichtig geworden sind, damals bereits krank waren und in diesem Sinn nicht mehr viel zu ändern sein würde.

    Ich hatte dann kurz überlegt, ob vielleicht bei der Normalisierung der Ableitungen (das incs /= sum(abs(incs)) irgendwas schief gegangen sein kann. Aber nein, eine Angabe wie „44%“ ist natürlich selbst normalisiert („pro hundert“). Der Verdacht jedoch führte schon mal in die richtige Richtung: Nachdenken über die Ableiterei und was dabei so passiert.

    Bevor ich da weiterknoble, zunächst die eigenliche Selbstbezichtung, denn was ich vor neun Tagen zumindest hätte tun sollen, wäre eine simple Validierung an den bestehenden Daten, nämlich am unmittelbar vorhergehenden 9-Tage-Intervall. Am 27.10. war die Intensivbelegung bei 1707, in den neun Tagen vor dem 6.11. war die Intensivbelegung also um 37% gestiegen. Es wäre ganz leicht gewesen, gleich nachzusehen, ob auch die Meldezahlen des RKI in den neun Tagen davor um etwas wie 37% gestiegen sind. Ich hätte festgestellt, dass sie das nicht sind – am 27.10. lag die RKI-Meldeinzidenz bei 118, am 18.10. bei 74, ein Anstieg also um satte 59% –, und das hätte mir gesagt, dass ich einen Fehler gemacht habe.

    Auch dann hätte ich vermutlich, wie heute auch, den nächsten Verdacht auf die heftige Kontamination der tageweisen Inzidenzschätzungen des RKI durch Wochenenden und Co gelenkt – schon in meinem allerersten Corona-Post hatte ich die bejammert. Vielleicht ist es ja das? Im Programm von neulich glätte ich deshalb vor der Ableitung. Die geglättete Kurve kommt am 18.10. auf 75, am 27.10. auf 120, und für den 6.11. habe ich noch keine geglätteten Daten, weil da noch zu viele Randeffekte dabei sind. Das ist sehr nah an den ungeglätteten Daten. Also, nein: Das macht repariert meine Fehlvorhersage nicht.

    Der wirkliche Fehler

    Das tatsächliche Problem liegt in der Methode, und zwar nicht in dem komplizierten Teil. Die Berechnung des Verzuges mit all dem Glätten und Ableiten ist völlig in Ordnung. Das Problem ist vielmehr, und ein wenig Nachdenken über Schulmathematik hätte mich darauf bringen können, in der Natur der Ableitung. Bei der gehen Konstanten nämlich verloren: (d)/(dx)(f(x) + C) = (d)/(dx)f(x). Ein hoher Sockel von Langzeit-IntensivpatientInnen wird bei meiner Verzögerungsrechnung einfach wegdifferenziert. Das ist ja sogar der Sinn der Differenziererei.

    Nur: Wenn ich am Schluss blind „44% mehr“ rechne, wird der Sockel (das C) mitmultipliziert, und genau da wird es falsch. Die richtige Rechnung wäre gewesen, die Differenz der Inzidenzen über die neun Tage vor dem 27.10. (von 74 auf 118) zu vergleichen mit der Differenz der Intensivbelegung der neun Tage vor dem 6.11 (von 1707 auf 2332) – dabei geht der Verzug ein, irgendwelche konstanzen Sockel spielen aber keine Rolle.

    Dieser Vergleich ergibt einen, sagen wir, 9-Tage-Übersetzungfaktor von 625 ⁄ 44 ≈ 14. In diesem stecken die Demographie der Erkrankten, die Eigenschaften des Virus, das Verhalten der Bevölkerung, und alles andere, was die mittlere Wahrscheinlichkeit bestimmt, mit einer SARS-2-Infektion intensivpflichtig zu werden. Unter der Annahme jedoch, dass der Übersetzungsfaktor über kurze Zeiten in etwa kontant ist, kann mensch jetzt die Entwicklung korrekt vorhersagen. Und zwar übersetzt sich demnach die Inzidenzentwicklung zwischen 27.10. und 6.11. (von 118 auf 164) 14-fach in die Intensivbelegung der jetzt gerade vergangenen neun Tage (das ist letztlich etwas wie ein Momentanwert von meiner int/inc-Metrik aus dem September).

    Ich hätte damit am 6.11. vorhergesagt, die Intensivbelegung würde um 46⋅16 = 644 zunehmen oder eben auf 2332 + 644 = 2976, in guter Übereinstimmung mit dem berichteten Wert von 3034.

    Blöd, dass ich nach meinen Zahlen- und Interpolationsspielen beim Zusammenbau der Vorhersage nicht aufgepasst habe. Aber es zeigt mal wieder, dass Mathe voll ist mit Fallen und ein Moment der Unaufmerksamkeit ziemlich unausweichlich zu zwanghaftem Vertilgen von Hüten führt. Und dabei hätte ich mir durch einfache Versuche, die Zukunft der Verangenheit vorherzusagen – ein sehr probates Mittel, wann immer mensch Zeitreihen analysiert – diese wenig erfreuliche Mahlzeit sparen können. Rülps.

    Aus eine physikalischen Betrachtung heraus ist diese Methode auch nicht so arg befriedigend, denn natürlich gibts bei den Meldezahlen keinen Sockel. Die sind ja selbst schon Ableitungen[1], nämlich die der Gesamtzahl der Infizierten. Die Intensivbelegung ist von der Genese her noch komplexer, da dort Zu- wie Abgänge eingehen. Insofern ist die Sache mit dem Übersetzungsfaktor zutiefst phänomenologisch und kann also aus vielen Gründen brechen.

    Schauen wir also mal, wie es in neun Tagen, am 24.11., aussieht. Meine Vorhersage wäre 3034 + (303 − 184)⋅14 = 4700. Das ist auch von der Dynamik her nicht mehr weit weg von der Höchstbelegung am 3.1.2021 (5762), und ohne ziemlich deutliche „Maßnahmen” werden wir wohl recht bald an der vorbeirauschen.

    [1]Wobei: Solange die Entwicklung exponentiell ist, ist das mit der Ableitung in diesem Kontext quasi wurst, denn die Exponentialfunktion ex ist ihre eigene Ableitung. Reale Wachstumsfunktionen über der Zeit t sehen aus wie N(1 + r)t = Neln(1 + r)⋅t, wobei r die Wachstumsrate ist (mit RKI-Zahlen R-Wert minus 1). Die Ableitung solcher Funktionen sind sie selbst mal einem konstanten Faktor, und der würde bequem in unserem Übersetzungfaktor 14 aufgehen. Wie gesagt: alles erstmal phänomenologisch.
  • Fixing "No sandbox user" the Right Way

    I'm setting up an ancient machine – a Pentium M box with a meme 256 MB of RAM – with current Debian bullseye, and I'm impressed that that still works: this machine is almost 20 years old. Hats off to the Debian folks.

    But that's not really my story. Instead, this is about fixing what's behind the message:

    No sandbox user '_apt' on the system, can not drop privileges
    

    from apt. As you probably have just done, my first reaction was to feed that message to a search engine.

    Quite a few pages were returned, and all I looked at suggested to simply create the user using one of the many ways a Debian box has for that. That is not totally unreasonable, but it does not really address the underlying cause, and hence I thought I should do better.

    The immediately underlying cause is that for whatever deeper reason a maintainer script – shell scripts that Debian packages run after installing packages or before removing them – has not properly run; that is usually the place where packages create users and do similar housekeeping. Just creating the user may or may not be enough, depending on what else the maintainer script would have done.

    Hence, the better way to fix things is to re-run the maintainer script, as that would either run the full routine or at least give an error message that lets you figure out the deeper cause of the problem. Dpkg runs the maintainer script(s) automatically when you re-install the package in question.

    But what is that “package in question” that should have created the user? You could guess, and in this particular case your guess would quite likely be right, but a more generally applicable technique is to simply see what script should have created the user. That's not hard to do once you know that the maintainer scripts are kept (next to other package metadata) in /var/lib/dpkg/info/; so, with GNU grep's -r (recursive) option, you can run:

    grep -lr "_apt" /var/lib/dpkg/info/
    

    which gives the names of all files containing _apt in files below that directory. On my box, that is:

    /var/lib/dpkg/info/python3-apt.md5sums
    /var/lib/dpkg/info/libperl5.32:i386.symbols
    /var/lib/dpkg/info/apt.postinst
    /var/lib/dpkg/info/python3-apt.list
    

    Ah-ha! The string is mentioned in the post-installation script of the apt package. Peeking inside this file, you see:

    if [ "$1" = 'configure' ]; then
            # add unprivileged user for the apt methods
            adduser --force-badname --system --home /nonexistent  \
                --no-create-home --quiet _apt || true
    fi
    

    So: this really tries to create the user when the package is being configured, but it ignores any errors that may occur in the process (the || true). That explains why the system installation went fine and I got the warnings later (rather than a hard error during the installation).

    Just re-configuring the apt package would therefore be enough to either fix things or at least see an error message. But really, unless it's a huge package I tend to save on brain cycles and just run apt reinstall, which in this particular case leads to the somewhat funky command line:

    apt reinstall apt
    

    For me, this fixed the problem – and I've not bothered to fathom why the user creation failed during initial system setup. If you've seen the same problem and still have a record of the installation, perhaps you could investigate and file a bug if necessary?

  • Stemming for the Search Engine

    First off, here is a quick reference for the search syntax on this site (the search form links here):

    • Phrase searches ("this is a phrase")
    • Exclusions (-dontmatch)
    • Matches only when two words appear within 10 tokens of each other (matches NEAR appear)
    • Trailing wildcard as in file patterns (trail*)
    • Searches don't use stemming by default, but stem for German when introduced with l:de and for English when introduced with l:en
    • See also the Xapian syntax.

    If you only came here for the search syntax, that's it, and you can stop reading here.

    Otherwise, if you have read the previous post on my little search engine, you will remember I was a bit unhappy that I completely ignored the language of the posts and had wanted to support stemming so that you can find, ideally, documents containing any of "search", "searches", "searching", and "searched" when searching for any of these. Being able to do that (without completely ruining precision) is obviously language-dependent, which means the first step to make it happen is to properly declare the languague of your posts.

    As discussed in the previous post, my blogsearch script only looks at elements with the CSS class indexable, and so I decided to have the language declaration there, too. In my templates, I hence now use:

    <div class="indexable" lang="{{ article.lang }}">
    

    or:

    <div class="indexable" lang="{{ page.lang }}">
    

    as appropriate.

    This is interpreted by the indexer rather straightforwardly by pulling the value out of the attribute and asking xapian for a stemmer for the named language. That works for at least most European two-letter country codes, because those happen to coincide with what's legal in HTML's lang universal attribute. It does not work for the more complex BCP 47 language tags like de-AT (where no actually existing stemmer would give results different from plain de anyway) or even sr-Latn-RS (for which, I think, no stemmer exists).

    On searching, I was worried that enabling stemming would blow unstemmed searches, but xapian's indexes are clever enough that that's not a problem. But I still cannot stem queries by default, because it is hard to guess their language from just a word or two. Hence, I have defined a query syntax extension: If you prefix your query with l:whatever, blogsearch will try to construct a xapian stemmer from whatever. If that fails, you'll get an error, if it succeeds, it will stem the query in that language.

    As an aside, I considered for a moment whether it is a terribly good idea to hand through essentially unfiltered user input to a C++ API like xapian's. I eventually settled for just making it a bit harder to craft buffer overflows by saying:

    lang = parts[0][2:30]
    

    – that is, I'm only allowing through up to 28 characters of language code. Not that I expect that anything in between my code and xapian's core has an overflow problem, but this is a cheap defensive measure that would also limit the amount of code someone could smuggle in in case some vulnerability did sneak in. Since it's essentially free, I'd say that's reasonable defensive programming.

    In closing, I do not think stemmed searches will be used a lot, and as usual with these very simple stemmers, they leave a lot to be desired from a linguistic point of view. Compare, for instance, a simple search for going with the result l:en going to see where this is supposed to go (and compare with the result when stemming as German). And then compare with l:en went, which should return the same as l:en going in an ideal world but of course doesn't: Not with the simple snowball stemmer that xapian employs.

    I'm still happy the feature's there, and I'm sure I'll need it one of these days.

    And again, if you need a CGI that can index and query your static HTML collection with low deployment effort: you're welcome.

  • Ad hominem 2

    Panorama des Stuttgarter Schlosses

    Einst die Residenz des Herrn Schmid, der nun die Ukraine[1] als Zwischenlager ihm unwillkommener Menschen nutzen möchte: Das Stuttgarter Schloss (CC-BY-SA Grossmummrich).

    Wie ich neulich schon betonte, ist mir selbstverständlich klar, dass im politischen Diskurs Attacken auf fragwürdige charakterliche oder physische Eigenschaften von MachthaberInnen sowie Menschen, die es werden wollen, als unfein gelten.

    Andererseits gehen die guten Sitten™ offensichtlich auch ohne mich vor die Hunde. Aktuelles Beispiel: Der „SPD-Außenpolitiker“ (Deutschlandfunk) Nils Schmidt hat gestern im DLF gefordert, die Menschen, die gerade über Belarus in die EU fliehen, sollten doch in der Ukraine quasi zwischengelagert (eingestanden: das ist nicht Schmids Wort, aber doch nach Bedeutung und Stil das, was er sagt) werden, und zwar im Wesentlichen aus Gründen des Prinzips.

    Er hat sich so nicht nur an dem furchtbaren Diskurs beteiligt, die Fliehenden seien irgendwie eine Waffe oder eine Bedrohung, sondern macht auch die Ansage, er halte die Ukraine – ganz wie die russische Regierung übrigens – für so eine Art Kolonie der EU, über die diese nach ihrem Belieben verfügen kann. Und so fühle ich mich aufgerufen, an eine Geschichte zu erinnern, bei der Schmid vor seiner Zeit als „Außenpolitiker“ in meiner weiteren Umgebung unangenehm aufgefallen ist.

    Bevor er nämlich „Außenpolitiker“ wurde, war er Finanzminister der ersten Grün-Roten Regierung hier in Baden-Württemberg. Als solcher residierte er im Stuttgarter Schloss. Wenn ihr dem Wikipedia-Link folgt, lest ihr dort:

    Seit dem Auszug des Ministeriums für Kultus, Jugend und Sport Anfang 2012 ist es heute noch Sitz des Finanzministeriums [...]

    Der Auszug des Kultusministeriums hat mit Schmid zu tun – seine Amtszeit als Finanzminister begann 2011. Zumindest im Umfeld der Verdrängten ging damals die Geschichte um, das Schloss sei zu CDU-Zeiten zwar groß genug für zwei Ministerien gewesen, für Schmid, sein Ego und das Kultusministerium reiche es aber nicht. Da die CDU-Ära Kultusministerinnen wie Dr. Annette Schavan und Finanzminister wie Gerhard Mayer-Vorfelder – beide gewiss keine Kinder der Bescheidenheit – kannte, fällt es nicht leicht, das zu glauben, aber es ist zweifellos plausibel, dass Schmid nach seiner Wahlniederlage gegen die Grünen einiges zu kompensieren hatte und sich das ganze Schloss sozusagen zum Trost gönnte.

    Ja, das ist alles etwas ad hominem, aber wer im Namen von „Recht und Ordnung“ austeilt wie Schmid in dem DLF-Interview, sollte auf Rückfragen zur eigenen Charakterfestigkeit zumindest vorbereitet sein.

    Bei alldem gestehe ich gerne, dass mich der Furor des Herrn Schmid besonders befremdet, weil er gerade jetzt kommt. Lukaschenko ist sicher neben vielem anderen vorzuwerfen, dass er viele Jahre lang in das schmutzige Grenzregime der EU verstrickt war; im 2019er-Bericht zu Abschiebungen aus der EU heißt es etwa zu Weißrussland:

    A total of 18 Member States reported having approached the authorities of Belarus for readmission matters [das ist hier Schurkensprache für „Abschiebung“] related to its nationals in 2019.

    All of them assessed the overall cooperation with Belarus in the identification procedure as good or very good (except one which rated it as average).

    This is reflected in 13 Member States having a functioning established routine [für Abschiebungen] with Belarus diplomatic missions, with only one informing that it is not effective.

    Gut: die da abgeschoben wurden, waren Menschen mit belarusischen Pässen, aber auch die sollte mensch wohl nicht in ein Land abschieben, das im öffentlichen Diskurs recht konsistent als „letzte Diktatur Europas“ gehandelt wurde (if only it were true). Jedenfalls nicht, wenn mensch anschließend irgendwelche menschenrechtlichen Standards an andere anlegen will.

    Angesichts dieser Geschichte der Kollusion beim Grenzregime Lukaschenko ausgerechnet dann Verfehlungen vorzuwerfen, wenn er sein Land erstmal nicht mehr als extrabreite Grenzmauer der EU zur Verfügung stellt, das lässt tief blicken im Hinblick auf die Umsetzung eines Ziels, das in der DLF-Presseschau vom 10.12. mit wirklich schockierender Ehrlichkeit aus der Nordwest-Zeitung zitiert wurde:

    Viertens ist auf EU-Ebene eine kollektive Einwanderungspolitik, die sich ausschließlich an den Interessen Europas ausrichtet, noch immer überfällig.

    Raubt nur mir den Atem, wie komplett der Kommentator hier vergessen hat, was das Wort „Asylrecht“ bedeutet[2]? Dass es darum ging, Menschen, die vor Krieg und Verfolgung fliehen müssen, eine Möglichkeit dazu zu geben?

    Wer so etwas schreibt, ist sich offensichtlich sehr sicher, niemals fliehen zu müssen. Diese Sicherheit sei solchen Leuten gegönnt, und wer mit so viel Patriotismus und Staatsraison gesegnet ist, mag mit der Zuversicht auch richtig liegen. Daraus aber zu schließen, dass auch alle anderen nicht fliehen dürfen, das ist, ich kann es nicht anders sagen, ein klares Merkmal von Schurken.

    Doch ich will versöhnlich enden, denn die Presseschau am nächsten Tag schloss mit folgender Einsicht aus dem Freitag (den natürlich wieder niemand liest):

    Was bei aller Lukaschenko-Verteufelung in vielen Zeitungen vergessen wird: Das ist nicht der Grund, warum diese Leute aus dem Nahen Osten kommen. Sie fliehen vor Kriegen und kriegerischen Folgeschäden aus dem Irak, Syrien oder Afghanistan. Die zugrunde liegenden Konflikte, die ihre Heimat destabilisierten, fanden ohne Beteiligung von Belarus, sehr wohl aber unter maßgeblichem Mitmischen des Westens, darunter EU-Mitgliedern, statt.

    Das hätte ich nicht schöner sagen können.

    [1]Das gerade, während in der Ukraine Corona durch schwindelerregend schnell durch eine offenbar nicht gut immunisierte Bevölkerung läuft: der z-Score (in etwa: Wie viele Standardabweichungen liegt die derzeitige Sterblichkeit über dem langjährigen Mittel?) war dort laut Euromomo vor drei Wochen bei fast 23, in Worten „extraordinarily high“. Aktuellere Zahlen sind wohl wegen Meldeverzug noch sehr unzuverlässig.
    [2]Na gut: Das ist, was Asylrecht bedeutet hat, bevor der Bundestag am schicksalsschweren 26.5.1993 mit dem Artikel 16a Grundgesetz das Asylrecht in der BRD in eine hohle, winddurchpfeifte Ruine verwandelt hat. Zur Erinnerung: Damit wurde die „Drittstaatenregelung“ eingeführt, die, auf EU-Ebene skaliert (u.a. „Dublin II“), letztlich der rechtliche Hintergrund der gespenstischen Vorgänge an der Grenze zwischen Belarus und Polen ist. Aber das ist nochmal eine ganz andere Geschichte.
  • Moving Clipboard Content Between Displays and Machines with Xclip

    Since Corona started, I've had to occasionally run zoom and other questionable telecon software. I don't want that proprietary junk on my main machine, partly because I'm a raving Free software lunatic, partly because binary packages from commercial vendors outside of the Debian main repository have a way of blowing up things years after one has put them on a box. I take some pride in never having re-installed my primary machine since 1996, so there would have been lots of opportunity for binary junk to accumulate.

    Hence I took a spare box I had sitting around idly, quickly put a simple Debian on its disk and then dumped all the questionable proprietary code next to its systemd and pulseaudio, reckoning that shredding that file system once the zoom pandemic is over will give me a lot of satisfaction.

    But now the various links, room ids and whatnot come in on the proper machine. Until a few days ago, I used to move them over to the zoom machine by having a screen open there, ssh-ing in from my main box, running screen -x to attach the screen that is already running in the ssh session, and then pasting the link into that shared screen. It works, but it feels clunky.

    The other day, I finally realised there's a better way using a nifty thing called xclip. I had already used xclip for ages whenever I have two displays running on a single box and I need to copy and paste between the two displaye; that happens when I'm at work. Then, I use the following key bindings (in this case for sawfish) on both ends:

    (bind-keys global-keymap "M-C-v"
            '(system "xclip -in < ~/.current-clipboard"))
    (bind-keys global-keymap "M-C-c"
            '(system "xclip -out > ~/.current-clipboard"))
    

    This lets me hit Alt-Ctrl-C on the first display and Alt-Ctrl-V on the second, and I'll then have what was in the primary selection on the first in the primary selection on the second.

    When later webkit on gtk3 started to copy links into the X11 clipboard rather than the primary selection and I wanted a quick way to get them to where I can middle-mouse them in again, I added another xclip binding to my sawfshrc:

    (bind-keys global-keymap "M-RET"
      '(system "xclip -out -selection clipboard | xclip -in"))
    

    – that's Meta-Return copying the content of the clipoard to the primary selection, and I've come to use that one quite extensively after initially piling quite a bit of abuse on the gtk3 policy of using the clipboard.

    What I noticed the other day was that xclip also lets me conveniently transport the telecon links. I've created an alias for that:

    alias zoomclip='xclip -o | ssh zoom "DISPLAY=:0 xclip -r -l 1 -i"'
    

    (zoom here is the name of the target machine). My new workflow is: select the string to transmit, run zoomclip in a terminal, hit the middle mouse button on the target machine to paste what I selected on the source machine. I'm not sure if it saves a lot of time over the old screen-based method, but it sure feels niftier, and I'd say that's reason enough for that alias.

    Note that the DISPLAY=:0 in the remote command is necessary because xclip of course is a normal X client and needs to know what display to talk to; and you want the local display on the target machine, not the display on the source machine. The -l 1, on the other hand, makes the xclip on the remote machine exit once you have pasted the content. Leave the option out if you expect to need to paste the thing multiple times. But without the -l 1, due to the way the selections are built on X11 (i.e, the system doesn't store selection content, you're always directly sending stuff between clients), xclip runs (and hence the ssh connection is being maintained) until some other client takes over the selection.

  • Der hundertste Post

    Vor 10 Monaten habe ich den ersten Artikel für dieses Blog geschrieben, und siehe da: Mit diesem sind es jetzt 100 Posts geworden.

    Das wäre ein guter Vorwand für ein paar Statistiken, aber da ich ja generell ein Feind von Metriken bin, die mensch ohne konkrete Fragestellung sammelt (das ist ein wenig wie beim statistischen Testen: Wenn du nicht von vorneherein weißt, worauf du testest, machst du es falsch), bestätige ich mir nur, dass meine Posts viel länger sind als ich das eigentlich will. Insgesamt nämlich habe ich nach Zählung von wc -l auf den Quelldateien fast 93000 Wörter in diesen Artikeln. Zur Fehlerabschätzung: xapian (vgl. unten) zählt nur 89000.

    Die Länge der Artikel ist nach wc-Wörtern so verteilt:

    Histogramm mit einem Klumpen zwischen 200 und 1000 und einem Outlier bei 3000

    Ich weiß auch nicht recht, warum ich mich nicht kürzer fassen kann. Oder will. Der überlange Post mit 3244 Wörtern ist übrigens der über die Konfiguration eines Mailservers – und das ist wieder ein gutes Beispiel für die Fragwürdigkeit von Metriken, denn erstens hat Englisch fast keine Komposita und ist von daher im Nachteil beim Wörterzählen und zweitens ist in dem Artikel ziemlich viel Material, das in Wirklichkeit Rechner lesen, und das sollte wirklich anders zählen als natürlichsprachiger Text.

    Na gut, und einem Weiteren kann ich nicht widerstehen: Wie viele verschiedene Wörter („Paradigmata“) kommen da eigentlich vor? Das ist natürlich auch Mumpitz, denn die Definition, wann zwei Wörter verschieden sind („die Token verschiedenen Paradigmata angehören“), ist alles andere als tivial. So würde ich beispielsweise behaupten, dass die Wörter Worte und Wörter praktisch nichts miteinander zu tun haben, während im Deuschen z.B. auf, schaute und aufschauen besser alle zusammen ein einziges Paradigma bilden sollten (zusammen mit allerlei anderem).

    Aber ist ja egal, sind ja nur Metriken, ist also eh Quatsch. Und es gibt die Daten auch schon, was für die Nutzung von und die Liebe zu Kennzahlen immer ein Vorteil ist. Ich habe nämlich den xapian-Index über dem Blog, und mit dem kann ich einfach ein paar Zeilen Python schreiben:

    import xapian
    db = xapian.Database("output/.xapian_db")
    print(sum(1 for w in db.allterms()))
    

    (Beachtet die elegante Längenbestimmung mit konstantem Speicherbedarf – db.allterms() ist nämlich ein Iterator).

    Damit bekomme ich – ich stemme nach wie vor nicht – 16540 raus. Klar, diese 16540 für die Zahl der verschiedenen Wörter ist selbst nach den lockeren Maßstäben von Metriken ganz besonders sinnlos, weil es ja eine wilde Mischung von Deutsch und Englisch ist.

    Um so mehr Spaß macht es, das mit den 100'000 Wörtern zu vergleichen, die schließlich mal im Goethe-Wörterbuch sein sollen, wenn es fertig ist. Eine schnelle Webrecherche hat leider nichts zur Frage ergeben, wie entsprechende Schätzungen für Thomas Mann aussehen. Einmal, wenn ich gerne Kennzahlen vergleichen würde…

  • Tatort und Menschenrechte

    Ich bekenne, regelmäßiger Tatort-Konsument zu sein und rechtfertige das gerne mit einem Interesse an der Öffentlichkeitsarbeit der Polizei, auch wenn die Danksagungen an diverse Polizeien in den Abspannen seltener geworden sind (oder jedenfalls scheint mir das so). Aber lasst mir mal die Annahme, dass bei den Drehbüchern polizeiliche PressesprecherInnen dann und wann mitreden.

    Mit dieser Annahme verblüfft mich, in welchem Maße die Filme zu einer Demo für Überwachungstechnologie verkommen sind. Seht euch mal im Vergleich irgendeinen alten Derrick an, oder wegen mir auch einen Felmy-Tatort aus den 70ern: Nicht, dass die plausibler oder näher an der damaligen Realität gewesen sein werden, aber das äußerste, was dort an Technik aufscheint, ist vielleicht ein mal ein Fingerabdruck, und wenns ganz scary werden soll, ein Nachschlagen in einer Straftäterdatei über ein grün flimmerndes Terminal. Ansonsten: Verhöre, Zeugengespräche, ernst guckende Beamte in braunen Anzügen.

    Filmszene: ein eine gelbe Spur auf einem Stadtplan

    Aus dem Tatort „Dreams“ vom letzten Sonntag: die Ermittler diskutieren ein in der Erzählung retrograd (nämlich etwas wie drei Tage nach der mutmaßlichen Tat) abgerufenes „Bewegungsprofil“ einer Verdächtigen. Wie sich Tatort-AutorInnen das halt so vorstellen. Und vielleicht auch die Münchner Polizei? (Bildrechte bei der ARD)

    Natürlich ist in der Zwischenzeit auch der reale Polizeialltag deutlich techniklastiger geworden, und das muss ein Fernsehkrimi nicht unbedingt ignorieren. Aber: Im Wesentlichen jeden Fall um DNA-Abgleiche oder -Analysen, Telefon-Verbindungs- und Standortdaten, haufenweise Videodaten (übrigens: im Hinblick auf private Kameras hat das erst seit 2017 überhaupt eine Rechtsgrundlage in der StPO), mehr oder weniger legale Zugriffe auf allerlei weiteren Computerkram (den nächsten Tatort, in dem die Kommissäre scharfsinnig Passwörter raten, schalte ich ab) und etliche weitere forensische Methoden aus der dystopischen Zukunft herumzustricken, das reflektiert sicher keine Realität. Das kann ich schon allein in Kenntnis aktueller Klageschriften und den in (wenn auch vor allem politischen) Verfahren tatsächlich verwendeten Beweismitteln zuversichtlich sagen.

    Vor allem verblüfft dabei, was für völlig bürgerrechtsfeindliche Vorstellungen der durchschnittliche Tatort inzwischen transportiert. Da hängen überall aufzeichnende Kameras rum, die auch noch fröhlich öffentliche Räume abbilden[1] , da reicht ein Blick in den Computer für eine halbwegs vollständige Biographe offenbar beliebiger Personen, und dann gibts den ganzen Mythos rund um das, worum es bei der Vorratsdatenspeicherung wirklich geht.

    Der Screenshot oben aus dem Tatort vom Sonntag ist ein besonderes absurdes Beispiel. Da haben die Ermittler ein „Bewegungsprofil“ bestellt – wo genau, bleibt unklar – und bekommen dann tatsächlich etwas, das die Qualität eines GPS-Tracks hat. Das ist glücklicherweise Unfug. Noch nicht mal bei einem Live-Abruf von Standortdaten nach §100i StPO kämen Geodaten dieser Sorte heraus; im GSM-Netz schon gar nicht, und selbst mit LTE und 5G sind Zellen mindestens einige Hektar groß und eine Triangulation – so sie überhaupt gemacht wird – ist in der Stadt Glückssache. Klar, mit einem GPS-Tracker (für den gibt es, im Gegensatz zum Zugriff auf die GPS-Daten des Mobiltelefons außerhalb der „Online-Durchsuchung“, eine Rechtsgrundlage) ginge das, aber den gab es am Auto der Verdächtigen in dieser Geschichte nicht.

    Im Nachhinein, also wie in diesem Fall sagen wir nach drei Tagen, kann die Polizei allenfalls auf Verkehrsdaten nach §96 TKG hoffen. Da sind zwar auch Standortdaten dabei, aber eben nur zu „Beginn und […] Ende der jeweiligen Verbindung“ – die Herstellung einer solchen Verbindung war Zweck der „Ortungspulse“ der stillen SMS. Nun ist das mit der „Verbindung“ im Zeitalter von paketvermittelten Diensten ein etwas schwieriger Begriff, und ich gestehe, auch nicht aus erster Hand zu wissen, wie das in der Praxis interpretiert wird. Klar ist aber, dass nicht alle paar Sekunden so ein §96 TKG-Record entsteht, um so mehr, als die der Norm zugrundeliegende Vorratsdatenspeicherung ja ausgesetzt ist[2].

    Also: Warum erfinden die Tatort-AutorInnen eine Aluhut-Welt und warum rät ihnen die Polizei nicht davon ab, rechnend, dass die ZuschauerInnen es gruselig finden könnten, wenn die Polizei auf Knopfdruck noch nach Wochen ihre Wege so genau nachvollziehen könnte? Und wie ist das mit den ZuschauerInnen selbst? Haben die inzwischen so viel Angst, dass sie in der Breite so eine dystopische Vision als „na ja, wenns der Sicherheit dient“ gerne ansehen?

    Sachdienliche Hinweise werden bei der Kontaktadresse dankbar angenommen.

    [1]In jedem zweiten Fall wird das Videomaterial dann auch noch hochgezoomt, als wäre es die slippy map auf osm.org. Ich glaube, diese Albernheit hat sich inzwischen zu einem Meme entwickelt. Läuft das unter dem Label „Navy CIS”?
    [2]Die Frage von oben, „wo genau“ die Polizei das „Bewegungsprofil“ her hat, könnte hier interessant werden, denn es ist vorstellbar, dass Google bei hinreichend unvorsichtig konfigurierten Telefonen Daten dieser Genauigkeit vorhält. Wenn das so ist, wäre es wirklich spannend, Statistiken über den staatlichen Zugriff auf diese Bestände zu bekommen. Ich sollte dazu mal sorgfältig https://lumendatabase.org (so heißen die chilling effects von einst inzwischen) lesen.

« Seite 13 / 18 »

Letzte Ergänzungen