• Wes Brot ich ess…

    Ein schrumpeliger Apfel

    Würdest du diesen Apfel in einem Supermarkt kaufen? Geht nicht mehr. Ich habe ihn vorhin gegessen. Also: Das, was Wurm und Balkonlagerung davon übrig gelassen haben. Auf der anderen Seite dürfte das Ding einen Behandlungsindex um die Null gehabt haben – siehe unten.

    Neulich hat die Parteistiftung der Grünen, die Böll-Stiftung, einen Pestizidatlas herausgegeben, eine Sammlung von Infografiken und Karten über den Einsatz von Giften aller Art in der Landwirtschaft. Wie üblich bei diesen Atlanten, haben sie das dankenswerterweise unter CC-BY publiziert, und besser noch: Die Sachen sind auch ohne Javascript leicht zugänglich[1].

    Ich hatte mir davon einige Kopfzahlen erhofft, denn ich habe wirklich kein gutes Gefühl dafür, was so an Giften auf den Feldern (und Weinbergen!) in meiner Umgebung landet und was das bedeutet. In der Hinsicht hatte ich kein Glück. Im Atlas gibts zwar haufenweise Zahlen, aber wirklich überzeugen konnten mich nur wenige, oft genug, weil sie letztlich Metriken ohne Bedeutung sind. Ein gutes Beispiel für diese Kategorie ist die Masse der Agrochemikalen (verwendet z.B. auf S. 11, S. 15, S. 44), die wohl als Proxy für „Umfang des Gifteinsatzes“ stehen soll.

    Das halte ich für profund fehlerhaft. Neonikotinoide, Glyphosat und DDT (um mal ein paar Pole aufzumachen) sind in spezifischer Giftigkeit, Wirkprofilen, Umweltauswirkungen, Kinetik und eigentlich jeder anderen Hinsicht fast völlig verschieden voneinander. „Eine Tonne Pestizid“ sagt daher so gut wie nichts aus. Obendrauf kommt noch ein kleiner Faktor Unsicherheit, ob sich die Masse auf Wirkstoffe, fertige Rezepturen oder irgendwas dazwischen bezieht, aber das wird wohl in diesem Geschäft kaum mehr als einen kleinen Faktor ausmachen – verglichen mit dem Grundproblem (in dem wir vermutlich über Faktoren von einigen tausend sprechen) wohl vernachlässigbar.

    Ähnlich schwerwiegende Einwände hätte ich zur breiten Mehrheit der Zahlen in dem Atlas: Vage beeindruckend, aber immer ein gutes Stück unterhalb der Schwelle von Wohlfundiertheit und allgemeinen Anwendbarkeit, die ein paar Ziffern zu einer Orientierung gebenden Kopfzahl machen könnten.

    Es gibt jedoch auch ohne schlagende Zahlen von werkübergreifender Bedeutung einige Einsichten, die wertvoll sind, so etwa auf S. 33 die Bankrotterklärung der Idee, durch grüne Gentechnik den Pestizideinsatz zu reduzieren. In Brasilien, wo transgene Pflanzen die Landwirschaft vollständig dominieren, sind 2019 47% mehr Pestizide ausgebracht worden als 2009. Gut: Soja (darauf schaut der Rest der Grafik, und das wird wohl auch den Pestizidverbrauch dominieren) ist in diesem Zusammenhang ein schlechtes Beispiel, denn das populäre transgene Soja („Roundup ready“) ist ja gerade designt, um große Mengen Herbizide zu überleben. Dazu sind wieder blind Massen angegeben, und die angesichts galloppierender Rodungen in Brasilien vermutlich rasch wachsende Anbaufläche wäre eigentlich auch noch einzurechnen, wenn die Zahlen einen analytischen Blick erlauben wollten.

    Aussagekräftiger wären für die behandelte Frage Zahlen für Mais gewesen (nämlich den mit der Bt-Abwehr gegen den Maiszünsler) und folglich auch Insektizide beim Mais. Aber seis drum: Die Grafik zeigt auch ohne methodische Strenge, dass es so nicht weiter gehen kann.

    A propos Mais: Dass der mit recht wenig Chemie auskommt, hat mich schon verblüfft:

    Mit "Schlechte Nachrichten für Apfel-Fans" überschriebene Grafik

    Grafik von Seite 14 des Pestizidatlasses. Die Caption im Atlas deutet an, dass der „Behandlungsindex“ etwas wie die mittlere Anzahl von Anwendungen von Pflanzenschutzmitteln ist; ob das wirklich so ist: Wer weiß? CC-BY Pestizidatlas

    Dass Wein heftig pflanzengeschützt wird, ist hier in der Gegend unübersehbar. Bei Hopfen und Äpfeln überrascht es mich aber, denn hiesige Apfelbäume in Streulagen, um die sich im Wesentlichen niemand kümmert, liefern durchaus sehr essbare Äpfel; hinreichend viele und große, um mir den ganzen Winter über die Basis für mein Frühstücksmüsli zu liefern (das Foto oben zeigt den von heute).

    Klar haben fast alle Hautdefekte, und in vielen wohnte auch mal ein Wurm – aber das tut ihrer Essbarkeit wirklich keinen Abbruch. Aus dieser Erfahrung heraus hätte ich erwartet, dass schon mit recht moderaten Interventionen supermarktkompatible Äpfel erreichbar wären. Das stimmt offenbar so nicht. Die letzten 50% zum makellosen Produkt – und wahrscheinlich auch die Spalierzucht in Monokultur – scheinen Äpfel von einer ganz einfachen zu einer ganz heikelen Kultur zu verwandeln.

    Meine Lieblingsgrafik ist schließich auf Seite 39:

    Eine Kopfzahl gibt auch das nicht her. Als Beleg für das alte Motto „Wes Brot ich ess, des Lied ich sing“ kann das aber durchaus durchgehen. Und als Illustration dafür, wie problematisch es ist, Wissenschaft – wie wir das in unserer Drittmittelkultur nun mal tun – über Geld zu regulieren.

    [1]Na ja, blöderweise ist ohne Javascript so ein doofes animiertes GIF neben jedem Ding, das runtergeladen werden kann. Tipp an die WebseitenmacherInnen: Wenn ihr diese Sorte Gimmick schon braucht, stattet ihn doch wenigstens mit einem display: none im CSS aus. Per Javascript könnt ihr das display-Attribut dann nach Bedarf konfigurieren. Nettoeffekt: UAs ohne JS (aber mit elementarem CSS) sehen keine blinkenden Trümmer.
  • PSA: Grobe Schnitzer beim Trauern

    Gestern um halb eins ist in Heidelberg ein Mann in einen Uni-Hörsaal gelaufen und hat mit einem Gewehr eine Frau erschossen, ist danach wieder rausgegangen und sich irgendwie selbst mit seiner Waffe umgebracht So ein Geschehen in einem Hörsaal, in dem ich vor vielen Jahren auch mal „Mathematische Methoden der Physik“ gehört habe, überhaupt, Leute mit Gewehren im botanischen Garten, in dem ich auch regelmäßig rumlaufe: Das lässt mich natürlich nicht kalt.

    Den bundesweiten Aufschrei, der folgte, finde ich allerdings angesichts der Wurstigkeit, wenn etwa Menschen überfahren werden, sich ohne Ballerei umbringen oder auf der Straße an genereller Verwahrlosung sterben, ziemlich unangemessen. Ich will mich jedenfalls nicht hinstellen und entscheiden, welcher Tod „überflüssiger“ oder „entsetzlicher“ war.

    Zum Glück muss ich das nicht. Ich könnte dazu den Mund halten. Der Rektor der Uni Heidelberg, das will ich gerne zugestehen, kann sich diesen Luxus nicht erlauben. Und so hat er rund fünf Stunden nach dem Ereignis eine Art Trauermail über den uniweiten Verteiler verschicken lassen. Es ist diese, die mich zu diesem Public Service Advisory bringt, denn der Rektor hat zwei Dinge getan, die in solchen Trauermails wirklich niemand haben will:

    1. Die Thoughts-And-Prayers-Phrase verwendet („Das Rektorat ist in Sorge um die Opfer und in Gedanken bei ihnen, ihren Freunden und Angehörigen”). Mal ehrlich: alle wissen, dass die Gedanken eines Rektorats, in dessen Uni gerade ein riesiger Polizei- und Presseauflauf stattfindet, überall sein werden, aber fast sicher nicht bei Freunden und Angehörigen von Opfern. Das ist wahrscheinlich noch nicht mal schlimm, denn die Betreffenden hätten auch dann nichts von diesen Gedanken (zum Glück hat das Rektorat auf „Gebete“ verzichtet), wenn sie bei ihnen wären. Klar ist ein wenig Lügen zum Trost erlaubt, aber bitte nicht mit einer Phrase, die so abgedroschen ist, dass sie sogar für Memes verbrannt ist.
    2. Die Mail von der Adresse kum@uni-heidelberg.de abgeschickt (ok, ich kann nicht genau sagen, ob das der Absender war, denn die Liste hat die Header weitgehend umgeschrieben, aber das Reply-to ist kum@). Kum wie „Kommunikation und Marketing“. Die Nachricht ist: Das ist ein Problem für unser Marketing, und da müssen wir mit Kommunikation Schaden begrenzen. Niemand erwartet, dass der Rektor Mail an rektor@ oder vielleicht eitel@ selbst liest – aber es würde die ganze Nachricht doch ein wenig authentischer wirken lassen, hätte er einen dieser Absender verwendet.

    Nun: Was mensch zum ersten Mal macht, vermurkst mensch. Hoffen wir, dass das Rektorat keine Übung in dieser Sorte Prosa bekommen muss.

  • Geschichte: Carl Benz bei Wilhelm I

    Schlechte Fotomontage: Ein Benz-Portrait in einer Versailles-Spiegelsaal-Variante

    Die Audienz des Herrn Benz (in weißer Uniform) wurde auch im Bild festgehalten.

    Bei Recherchen im Deutschen Nationalarchiv bin ich auf eine Mitschrift einer Art Ansprache – heute würde das wohl sales pitch genannt werden – gestoßen, die Dr. Carl Benz, Mannheim, Eigentümer der dortigen Fabrik für Maschinen zur Blechbearbeitung, gelegentlich einer Audienz bei Kaiser Wilhelm I am 23. Mai 1880 gehalten haben soll. Ich habe sie abgetippt und orthographisch aktualisiert:

    Hochgeehrte kaiserliche Majestät, allerdurchlauchtigste, großmächtigste, allergnädiste Hohheit etc pp,

    Erlaubt mir, Carl Friedrich Michael Benz, Absolvent der polytechnischen Hochschule zu Karlsruhe, Euch untertänigst einen Vorschlag zu unterbreiten, welcher einen ebenso ernsten wie drängenden Missstand aus der Welt zu schaffen verspricht. Namentlich sind nicht nur die Straßen der Hauptstadt Ihro Reiches verunziert von den Hinterlassenschaften zahlloser Rösser. Nein, diese sind in allen Städten wie Dörfern in Ihro Obhut ein beständiges Ärgernis, zu schweigen von den Gefahren, die von ihnen für das öffentliche Wohlbefinden ausgehen. So vergeht wohl kein Tag, ohne dass sich ein tapferer Offizier seine tadellose Uniform durch einen unbedachten Schritt, gar ein unwürdiges Ausrutschen, besudelt mit dem kreatürlichen Schmutz.

    Es wird Zeit, dieses Ärgernis aus der Welt zu schaffen. Ich bin dazu in der Lage, und zwar mittels meines patentierten pferdelosen Wagens, kurz, meines Motorwagens. Er vermag Menschen mit großer Geschwindigkeit zu bewegen, ohne dass dazu Pferde oder anderweitig die Straßen verunreinigende Tiere benötigt würden. Wird es erst genug von meinen Wagen geben, wird unser gütiger Herrscher Seine Städte nicht mehr wiedererkennen.

    Um diesen großen Schritt zur höheren Kultivierung des deutschen Volkes, ja, ich will der Hoffnung Ausdruck geben, der Völker des ganzen Erdenkreises, zu tun, werden nur einige kleine Erweise von Gunst und Gnade nötig sein, abgesehen von einer unbedeutenden Zuwendung aus der Privatschatulle Eurer Majestät. Zuvorderst müssten Majestät einige Aufwendungen für den Ausbau des Straßennetzes veranlassen.

    Natürlich werden meine Wagen gewisse gesetzliche Privilegien benötigen. Ihnen ist die Hälfte des Straßenraums für ihre Bewegung zu reservieren. Der Aufenthalt von Personen muss dort verboten werden. Vielleicht kann ihnen an einzelnen Stellen per Lichtzeichen das gelegentliche Betreten der Straßen Ihro Majestät kurzfristig gestattet werden. Ein weiteres Drittel der Wege und Plätze werden Ihro Untertanen nicht mehr betreten können, da ja die Motorwagen zu akkomodieren sind, während sie nicht fahren. Ich erwarte zuversichtlich, dass dem Gesinde auch nach diesen Anpassungen von Gesetz und Gebrauch hinreichend Raum verbleiben wird und es den kaiserlichen Privilegien für meine Motorwagen freudig und ohne Murren folgen wird.

    Ich erwähne beläufig, dass Jahr um Jahr einige tausend Flaneure und auch Insassen der Motorwagen bei allfälligen Kollisionen sterben werden. Unter den Überlebenden wird es fraglos zahlreiche Beschädigte geben, die, so steht zu befürchten, dem Ruhm des Vaterlandes nicht mehr im gewohnten Maße werden dienen können. Ich habe weiter überschlagen, dass einige weitere Zehntausende an feinem Staub und anderen Miasmen der Motorwagen zugrunde gehen werden, und noch einmal so viele an Lärm und dergleichen. Nun: Auch Pferde töten Menschen. Und fraglos sind dies sehr überschaubare Opfer im Vergleich zum reichlichen Nutzen und Gewinn, da unsere wunderbaren Städte von den dampfenden Hinterlassenschaften der Pferde befreit werden.

    Ohne die Errungenschaft unnötig profanisieren zu wollen, darf ich in aller Kürze anmerken, dass meine Erfindung auch den Geldfluss in Ihro Gnaden Imperium beflügeln wird, da das fleißige Volk ein rundes Siebtel mehr wird arbeiten müssen für die Freude und Gnade, einen Motorwagen besitzen und bewegen zu dürfen. Ich kann indes bereits jetzt versprechen, dass sie das gerne tun werden, dass sie im Gegenteil heftig ringen werden dafür, mehr arbeiten zu müssen. Genauso werden sie ganz aus eigenem Willen ihre Kinder nicht mehr auf der Straße spielen lassen. Dies wird nicht nur das Unwesen der sprichwörtlichen Straßenjungen zu einem Ende bringen, es werden so auch weniger junge, vielleicht hoffnungsvolle Talente unter den Rädern meiner Motorwagen zermalmt.

    Um diese kleinen Preise können Ihro Untertanen dann täglich eine oder zwei Stunden in ihren Blechkäfigen verbringen und mit großer Anspannung durch Glasscheiben auf andere Untertanen blicken, die zumeist ebenfalls in Blechkäfigen dahinrasen. Es wird viel Ärger und Hader sein zwischen den Männern in ihren Käfigen, was gewiss überaus förderlich sein wird zur Ertüchtigung des Volkes im Wettstreit der Nationen und zur Vertiefung der Liebe des Volkes zu Ihro Majestät. Manchmal werden sie auch gar nicht dahinrasen, sondern in ihren Käfigen hintereinander stehen, ohne zu wissen warum. Auch das werden das willig hinnehmen, denn sie werden wissen: Der große Kaiser hat uns erlöst vom Pferdemist.

    Es könnte sein, dass dieses Dokument nicht ganz authentisch ist, denn Forschungs- und Industrieförderung im heutigen Sinn hat es damals noch nicht gegeben. Außerdem hat Benz wahrscheinlich nicht genau kommen sehen, was seine Erfindung in der Welt anrichten würde. Denn auch wenn er wohl kein sehr netter Mensch war, er hätte es andernfalls hoffentlich gelassen.

    In Wahrheit wird es wie so oft gewesen sein: Die allerabsurdesten Dinge haben sich in langen Entscheidungsketten entwickelt, in denen jede einzelne Entscheidung zumindest nachvollziehbar ist. Es hat ja niemand ahnen können, dass am Schluss etwas rauskommt wie unsere Autogesellschaft.

  • Explaining Tags in Pelican

    Right after I had celebrated the first anniversary of this blog with the post on my Pelican setup, I decided to write another plugin I've been planning to write for a while: taginfo.py.

    Nachtrag (2022-10-07)

    Don't take it from here; rather, see https://codeberg.org/AnselmF/pelican-ext

    This is for:

    Blog screenshot

    that is, including explanations in on pages for tags, telling people what the tag is supposed to mean.

    To use taginfo, put the file into your plugins folder, add taginfo to the PLUGINS list in your pelicanconf.py, and then create a folder taginfo next to your content folder. In there, for each tag you want to comment, create a file <tagname>.rstx (or just rst). Such a file has to contain reStructuredText, where pelican's extensions (e.g., {filename} links) do not work (yet). I suppose it wouldn't be hard to support them; if you're interested in this plugin, feel free to poke me in case you'd like to see the extra pelican markup.

    To make the descriptions visible, you need to change your tag.html template (typically in theme/templates/tag.html) in order to arrange for tag.make_description() to be callsed when rendering the document. Me, I'm doing it like this:

    {% block content_title %}
    <h1>Tag <em>{{ tag }}</em></h1>
    <div id="taginfo">
            {{ tag.make_description() }}
    </div>
    {% endblock %}
    

    (And I still find jinja templates exceptionally ugly).

  • How I'm Using Pelican

    I started this blog on January 14th last year. To celebrate the anniversary, I thought I could show how I'm using pelican (the blog engine I'm using); perhaps it'll help other people using it or some other static blog generator.

    Posting and Writing

    First, I structure my content subdirectory (for now) such that each article has the ISO-formatted date as its name, which makes that source name rather predictable (for linking using pelican's {filename} replacement), short, and gives the natural sort order sensible semantics.

    Also, I want to start each post from a template, and so among the first things I did was write a little script to automate name generation and template instantiation. Over the past year, that script has evolved into post.py3.

    Nachtrag (2022-03-15)

    I've changed a few things in the meantime; in particular, I am now opening a web browser because I got tired of hunting for the URI when it was scrolled off the screen before I first had something to open, and to make that work smoothly, I'm building the new post right after creating its source.

    It sits next to pelican's Makefile and is in the blog's version control. With this, starting this post looked like this:

    $ ./post.py3 "How I'm Using Pelican"
    http://blog/how-i-m-using-pelican.html
    remake.sh output/how-i-m-using-pelican.html
    

    Nachtrag (2022-05-26)

    The output is now a bit different, and now I do open the browser window – see below.

    What the thing printed is the URL the article will be seen under (I've considered using the webbrowser module to automatically open it, but for me just pasting the URL into my “permanent” blog browser window works better). The second line gives a command to build the document for review. This remake.sh script has seen a bit of experimentation while I tried to make the specification of what to remake more flexible. I've stopped that, and now it's just:

    #!/bin/bash
    pelican --write-selected "$1"
    

    When you add:

    CACHE_CONTENT = True
    LOAD_CONTENT_CACHE = True
    CONTENT_CACHING_LAYER = 'generator'
    

    to your pelicanconf.py, rebuilding just the current article should be relatively quick (about 1 s on my box). Since I like to proofread on the formatted document, that's rather important to me.

    Nachtrag (2022-05-26)

    N…no. This part I'm now doing very differently. See Quick RST Previews.

    If you look at post.py3's code, you will see that it also fixes the article's slug, i.e., the path part of the URL. I left this to Pelican for a while, but it annoyed me that even minor changes to a blog title would change the article's URI (and hence also the remake statment). I was frankly tempted to not bother having elements of the title in the slug at all, as I consider this practice SEO, and I am a fanatical enemy of SEO. But then I figured producing shorter URIs isn't worth that much, in particular when I'd like them to be unique and easy to pronounce. In the end I kept the title-based slugs.

    The script also picks the local file name as per the above consideration with some disambiguation if there's multiple posts on one day (which has only happened once in the past year). Finally, the script arranges for adding the new post to the version control system. Frankly, from where I stand now, I'd say I had overestimated the utility of git for blogging. But then, a git init is cheap, and who knows when that history may become useful.

    I'm not using pelican's draft feature. I experimented with it for a while, but I found it's a complication that's not worth anything given I'm always finishing a post before starting the next. That means that what otherwise would be the transition from draft to published for me is the make install. The big advantage of starting with status:published is that under normal circumstances, an article never changes its URI.

    Local Server Config and Media

    Another pelican feature I'm not using is attaching static files. I have experimented with that initially, but when the first larger binary files came in, I realised they really shouldn't be under version control. Also, I never managed to work out a smooth and non-confusing way to have pelican copy these files predictably anyway.

    What I ended up doing is have an unversioned, web-published directory that contains all non-article (“media”) files. On my local box, that's in /var/www/blog-media, and to keep a bit of order in there, the files sit in per-year subdirectories (you'll spot that in the link to the script above). The blog directory with the sources and the built documents, on the other hand, is within my home. To assemble all this, I have an /etc/apache2/sites-enabled/007-blog.conf containing:

    <VirtualHost *:80>
      ServerName blog
      DocumentRoot /home/anselm/blog/output
    
      Alias /media /var/www/blog-media
    
      ProxyPass /bin/ http://localhost:6070/
    
      <Directory "/home/anselm/blog/output">
        AllowOverride None
        Options Indexes FollowSymLinks
        Require all granted
      </Directory>
    
      <Directory ~ "/\.git">
        Require all denied
      </Directory>
    </VirtualHost>
    

    which needs something like:

    127.0.0.1 localhost blog
    

    in your /etc/hosts so the system knows what the ServerName means. The ProxyPass statement in there is for CGIs, which of course apache could do itself; more on this in some future post. And I'm blocking the access to git histories for now (which do exist in my media directory) because I consider them fairly personal data.

    Deployment

    Nachtrag (2022-07-10)

    I'm now doing this quite a bit differently because I have decided the procedure described here is a waste of bandwidth (which matters when all you have is GPRS). See Maintaining Static Blogs Using git push.

    When I'm happy with a post, I remake the whole site and push it to the publishing box (called sosa here). I have added an install target to pelican's Makefile for that:

    install: publish
      rsync --exclude .xapian_db -av output/ sosa:/var/blog/generated/
      rsync -av /var/www/blog-media/ sosa:/var/blog/media/
      ssh sosa "BLOG_DIR=/var/blog/generated/ /var/blog/media/cgi/blogsearch"
    

    As you can see, on the target machine there's a directory /var/blog belonging to me, and I'm putting the text content into the generated and the media files into the media subdirectory. The exclude option to the rsync and the call to blogsearch is related to my local search: I don't want the local index on the published site so I don't have to worry about keeping it current locally, and the call to blogsearch updates the index after the upload.

    The publication site uses nginx rather than apache. Its configuration (/etc/nginx/sites-enabled/blog.conf) looks like this (TLS config removed):

    server {
      include snippets/acme.conf;
      listen 80;
      server_name blog.tfiu.de;
    
      location / {
        root /var/blog/generated/;
      }
    
      location /media/ {
        alias /var/blog/media/;
      }
    
      location /bin/ {
        proxy_pass http://localhost:6070;
        proxy_set_header Host $host;
      }
    
      location ~ \.git/ {
        deny all;
      }
    }
    

    – again, the clause for /bin is related to local search and other scripting.

    Extensions

    Nachtrag (2022-10-07)

    Don't take the code from here; rather, see https://codeberg.org/AnselmF/pelican-ext

    In addition to my local search engine discussed elsewhere, I have also written two pelican plugins. I have not yet tried to get them into pelican's plugin collection because… well, because of the usual mixture of doubts. Words of encouragement will certainly help to overcome them.

    For one, again related to searching, it's articlemtime.py. This is just a few lines making sure the time stamps on the formatted articles match those of their input files. That is very desirable to limit re-indexing to just the changed articles. It might also have advantages for, for instance, external search engines or havesters working with the HTTP if-modified-since header; but then these won't see changes in the non-article material on the respective pages (e.g., the tag cloud). Whether or not that is an advantage I can't tell.

    Links to blog posts

    The citedby plugin in action: These are the articles that cite this post right now.

    The other custom extension I wrote when working on something like the third post in total, planning to revisit it later since it has obvious shortcomings. However, it has been good enough so far, and rather than doing it properly and then writing a post of it own, I'm now mentioning it here. It's citedby.py, and it adds links to later articles citing an article. I think this was known as a pingback in the Great Days of Blogs, though this is just within the site; whatever the name, I consider this kind of thing eminently useful when reading an old post, as figuring out how whatever was discussed unfolded later is half of your average story.

    The way I'm currently doing it is admittedly not ideal. Essentially, I'm keeping a litte sqlite database with the cited-citing pairs. This is populated when writing the articles (and pulls the information from the rendered HTML, which perhaps is a bit insane, too). This means, however, that a newly-made link will only …

  • Variable Inflation

    Relativ parallel verlaufende Kurven

    Dieser Artikel hat nach langen Windungen leider keine Pointe. Und zwar im Wesentlichen wegen dieser Grafik, generiert vom Rechner für die persönliche Inflationsrate des statistischen Bundesamts. Siehe unten.

    Ich fletsche hier ja regelmäßig die Zähne in Richtung von allerlei Metriken, also Zahlen, die (meist) Unmessbares messen sollen und damit in aller Regel Politiken rechtfertigen, die schlecht sind für die, bei denen diese ankommen.

    Der ganz große Klassiker im Metrik-Geschäft ist das Bruttosozial- oder -inlandsprodukt (BSP bzw. BIP), dessen Wachstum im allgemeinen Bewusstsein als Synonym für wachsenden Wohlstand gilt, zumal in seiner Form als BIP pro Kopf. In Wirklichkeit versucht die Metrik zu messen, wie viele „Waren und Dienstleistungen“ (womit es schon losgeht: was ist das?) „hergestellt“ (realistisch: verkauft) werden, und zwar von StaatsbürgerInnen (BSP) oder innerhalb der Staatsgrenzen (BIP).

    Das Bruttosozialprodukt und der Krieg

    Dass das BIP wesentlich mit Wohlstand korreliert sei, ist offensichtlich falsch – selbst die Produktion von Wohlstandsvernichtern wie Autos und anderen Waffen erhöht das BIP –, und das wurde auch schon breit kritisiert. Der entsprechende Abschnitt in der Wikipedia ist nach Maßstäben diese Genres eher zahm.

    Diese Klarstellung im Hinblick auf Wohlstand ist wichtig, aber etwas unfair, denn, a propos Waffen: Historisch sollte das BSP das mit dem Wohlstand gar nicht machen. Besonders aufschlussreich in der Hinsicht fand ich einen Artikel in der taz vom 2.5.2015, der daran erinnerte, dass sich das BSP in seiner heutigen Form vom Gottseibeiuns der Marktradikalen, John Maynard Keynes, in einem Artikel mit dem sprechenden Namen How to Pay for the War ersonnen wurde und sich letztlich als Metrik der wirtschaftlichen Kriegsfähigkeit durchgesetzt hat. Die taz-Autorin Ulrike Herrmann implizierte 2015, dass das BSP dafür offenbar taugte, denn es hat ja die Keynes-Seite gewonnen – mehr kann mensch von einer Metrik nicht erwarten.

    Ich selbst glaube zwar nicht, dass BSP-Rechnungen auf Seiten der Nazis irgendwas am Kriegsverlauf geändert hätten, aber für meinen nächsten Gedanken will ich trotzdem mal annehmen, das BSP sei im zweiten Weltkrieg eine kriegsnützliche Metrik gewesen. Von dort aus möchte ich behaupten, dass es unter Bedingungen weitgehender reproduktiver Selbstbestimmung allenfalls noch sehr kurzfristig für die Bewertung der Kriegsfähigkeit taugt. Solange sich nämlich in Kriegen immer noch in erster Linie junge Leute (statt, sagen wir, Roboter) erschießen, braucht es für deren Führung hinreichend Nachwuchs. Den immer noch dominierenden Modus der Reproduktion, unbezahlte Arbeit von Müttern an ihren Kindern, erfasst das BIP jedoch nicht.

    Als das Konzept entstand, war die Vorstellung klarerweise, dass Frauen ganz von selbst Kinder kriegen und aufziehen. Das stimmt nicht mehr, und daher wäre mein Rat an die BIP-MacherInnen: Wenn euer BIP weiter wie gehabt funktionieren soll, müsst ihr auch die Herstellung von Kindern verrechnen.

    Tatsächlich wäre es überhaupt kein Stilbruch, sowas irgendwie ins BIP reinzufummeln. Denn natürlich weiß niemand, wie viel wirklich verkauft oder gar hergestellt (denkt an all die handgestrickten Babysachen, von denen keine Statistikbehörde je erfahren wird) wird, und die Grenze zwischen Ware und Nicht-Ware ist ziemlich beliebig. Gewiss, das Steueraufkommen ist ein brauchbarer Indikator, aber mehr eben nicht. Viele Variablen liegen zwischen dem und irgendwelchen Gesamtproduktions- oder Einkommensziffern. Auch auf der legalen Seite der Demarkationslinie zur Schwarzarbeit passiert viel Austausch, ohne dass davon irgendwer etwas mitbekommt.

    Mit solchen Gedanken im Kopf habe ich vor einiger Zeit GDP: A Brief but Affectionate History von Diane Coyle (Princeton 2014; gibts bei der Imperial Library of Trantor) mit viel Interesse gelesen. Darin geht es zum Beispiel um die Beliebigkeiten in den BIP-Berechnungen (englisch Gross Domestic Product oder GDP) – der Klappentext erwähnt Ausschläge von 60% über Nacht für Ghana –, ebenso wie über die historischen Diskussionen, was alles zum „Volkseinkommen“ gehören soll: Kriegsausgaben? Staatsausgaben überhaupt? Gesundheitsausgaben? Oder in dem Bereich vielleicht nur Pillen, nicht aber die Arbeit von ÄrztInnen? „Dienstleistungen“ (was immer das ist) an sich, und wenn ja, wie bewertet?

    Dennoch: Kopfzahlen

    Die tatsächlichen Regeln für die Berechnung von BIP-artigen Metriken sind also im Gegensatz zur munteren Betrachtung in der Wikipedia in weiten Bereichen biegsam. Zwar mag eine genaue und ehrliche Zweckbestimmung helfen, die eben aufgeworfenen Fragen, sagen wir, intersubjektiv zu beantworten, aber letztlich ist das Konvention, und selbst für das BIP in der Keynes-Definition ist da viel zu vereinbaren. Die international offenbar populärste Konvention stellt Coyle vor, namentlich das System of National Accounts, das sich in den vergangenen siebzig Jahren von fünfzig auf 722 Seiten aufgebläht hat.

    Das allerdings schafft schon wieder Beliebigkeit. Aus meiner Erfahrung mit 50-seitigen Standards, für die nach einer Weile Validator-Programme verfügbar wurden (und zeigten, dass notdürftig funktionsfähig aussehende Dienste voll mit Fehlern waren), kann ich zuversichtlich sagen: Solange es keinen rechnergestützten Validator gibt (und das ist hier bis zur Erfindung starker KI eigentlich undenkbar), sind 722 Seiten voll Regeln so gut wie überhaupt keine Regeln: Das System ist fast sicher in sich höchst widersprüchlich, und auch mit dem besten Willen (der nur bei wenigen Statistikbehörden und Ministerien vorausgesetzt werden darf) werden Menschen ständig Fehler machen.

    Wie auch immer: Als Kopfzahl ist es ja vielleicht trotzdem ganz nützlich zu wissen, dass das BIP der BRD laut IWF 2019 knapp 4 Billionen Dollar betrug, das der USA etwas über 20 Billionen Dollar und das eines ordentlichen und großen Trikontstaats wie z.B. Nigeria 500 Milliarden Dollar. Sicher sind diese verschiedenen Dollars nicht annähernd vergleichbar, aber die Zahlen taugen doch für schnelle Überschlagsrechnungen, wenn verkündet wird, der Börsenwert von Apple sei jetzt, was, zwei Billionen Dollar (etwa: die AktionärInnen von Apple könnten für ein halbes Jahr die BRD leerkaufen und Nigeria für vier Jahre), oder wenn die Frage ist, wie viel der Bund mit einem Bundeshaushalt von (außerhalb von Corona) 350 Milliarden Euro an „den Märkten“ reißen kann – natürlich immer mit der Maßgabe, dass über Messfehler, Umrechnungen, Inflationsanpassung und so fort da schnell ein Faktor zwei dabei ist.

    Persönliche Inflation

    Der größte Unsicherheitsfaktor innerhalb der Serie einer Behörde wird wahrscheinlich die Inflationsanpassung sein, angefangen dabei, ob sie vorgenommen wurde oder nicht. Erstens ist sie ein exponentieller Effekt. Nehmen wir mal an, dass die Inflationsrate im Schnitt bei den 2% pro Jahr liegt, die diverse Zentralbanken gerne hätten, und dass sie tatsächlich ein Maß ist, wie viel mensch so kaufen kann. Nach der Königsformel „Verdoppelungszeit ist 75 Zeiteinheiten[1] durch prozentuale Rate“, liegen inflationsbereinigte und rohe BIPs schon nach 37 Jahren um einen Faktor zwei auseinander.

    Nun liefert aber auch eine Bereinigung um Inflation und Währungseffekte kaum Zahlen, die mit Erfahrungen von Konsummöglichkeiten korrelieren. Seht etwa die nach PPP bereinigten historischen Vergleichswerte zum BIP an: Es ist abwegig, dass sich irgendeine Sorte von „gefühltem“ Konsum für der BRD zwischen 1990 und 2019 von 1437 auf 4672 Milliarden Äquivalent-Euro verdreifacht haben soll. Wer damals schon gelebt hat, wird sich erinnern, dass sich – abgesehen davon, dass es noch keine SUVs und nur wenig Mobiltelefone gab – das allgemeine Konsumniveau hier im Land nicht wesentlich geändert hat.

    Zweitens also ist die Inflation selbst eine wacklige Größe, womit ich endlich zum Link komme, der mich zur vorliegenden Diatribe inspiriert hat, weil ich ihn verkopfzahlen wollte: Labournet berichtet, dass rund die Hälfte der 8.4 Millionen MieterInnen in deutschen Großstädten mehr als 30% ihres Einkommens für Miete augeben müssen. Das fand ich schon für sich relevant, ich wollte aber vor allem den Punkt machen, dass solche Leute bei explodierenden Mietpreisen eine weit höhere Inflation haben werden als Menschen, die keine Miete zahlen müssen.

    Da VermieterInnen in der Regel eher reich und MieterInnen in der Regel eher arm sind, bedeuten Mieten, die stärker steigen als die Inflation, eine Art kalte Umverteilung von unten nach oben bei gegebenem BIP (ob pro Kopf oder anders). Die Inflationsschätzung basiert ja auf einem Warenkorb, den das statistische Bundesamt (Destatis) zusammenstellt, und wenn Leute viel mehr für Miete ausgeben als im Warenkorb repräsentiert und die Mieten viel stärker steigen als die Preise im Rest des Warenkorbs, ist ihre „persönliche Inflation“ viel höher als die Zahl aus den Nachrichten. Die BIP-pro-Kopf-Metrik nicht nur wegen ungleicher Einkommensverteilung zweifelhaft, sondern auch, weil sie obendrauf noch eine innere Kaufkraftkorrektur bräuchte.

    Das hatte ich nun auf der Basis der rasant steigenden Mieten illustrieren wollen und habe auf den Seiten des Statistischen Bundesamts herumgestöbert, um mein Gefühl zu erhärten, dass Mieten weit über der Inflation steigen. Das Gefühl hat seine Grundlage in meinem persönlichen WG-Zimmer-Index für Heidelberg. Ausweislich durchschnittlicher Aushänge würde ich für 1990 den mittleren Kurs etwa bei 150 Euro sehen, inzwischen eher bei 500 Euro (unter Annahme der DM-Euro-Konversion von 2001). Die Mieten hätten sich also in dreißig Jahren also gut verdreifacht, was einer Verdopplungszeit von 18 Jahren oder einer jährlichen Inflation von 75/18, also 4% entspricht; die berichtete Inflation lag in der Zeit von kurzen Phasen abgesehen jedoch deutlich unter 2 Prozent.

    Nun, es stellt sich raus: Das Konzept der je nach sozialer Schicht verschiedenen Inflationsrate illustriert das Amt selbst recht schön und bietet sogar einen Rechner für die persönliche Inflationsrate an – Kompliment an dieser Stelle dafür, dass da ein SVG-Download angeboten wird (wie überhaupt die Webseite den Eindruck hinterlässt, dass hier Leuten mit Verstand und Spaß bei der Sache relativ freie Hand gelassen …

  • Joe Hills Asche und die bessere Zukunft

    „I dreamed I saw Joe Hill last night, alive as you and me“ – so fängt ein Klassiker des Arbeiterlieds an, der mich spätestens bei „And smiling with his eyes,/ says Joe, what they could never kill/ went on to organize“ immer sehr ergriffen hat, auch in seinen Aktualisierungen wie etwa I dreamed I saw Judi Bari last night von David Rovics.

    Was ich nicht wusste: In das Bewusstsein der (halbwegs) modernen Linken hat das Lied Joan Baez gebracht, als sie es beim Woodstock Festival aufführte. Trivia? Klar. Noch viel mehr davon habe ich gestern gehört, als der Deutschlandfunk-Freistil vom 12.12.2021 („Die Asche von Joe Hill”) in meinem asynchronen Radio drankam.

    Diese Sendung hätte ich offen gestanden als außerhalb der Grenzen des öffentlich-rechtlichen Rundfunks liegend eingeschätzt. Einerseits, weil es um grenzwertig kannibalistische Praktiken geht – allerdings stark grotesk-gutgelaunte (lest zumindest mal die Zusammenfassung). Das ist nicht anders zu erwarten, da Abbie Hoffman im Spiel ist, der schon mal als Angeklagter in Richterroben auflief, sich mit dem Stinkefinger vereidigen ließ und wesentlichen Anteil hatte, dass um ein Haar ein Schwein US-Präsidentschaftskandidat (statt des heute zu Recht vergessenen Hubert Humphrey) geworden wäre.

    Andererseits finde ich die Sendung doch recht DLF-mutig, weil sie am Ende schon nachgerade revolutionär wird. Schon die Beschreibung der blutigen Repression gegen die Wobblies in den USA bereitet auf klare Worte vor:

    Mit dem Eintritt der USA in den ersten Weltkrieg erlebten die Wobblies eine brutale Verfolgung. Sie wurden als unpatriotisch gebrandmarkt [ich hoffe doch: zu Recht!], viele wurden verhaftet, einige gelyncht, manche verließen das Land.

    Dies ist natürlich auch eine Erinnerung daran, dass es schlicht keine größere Katastrophe gibt als Kriege und es wirklich Zeit wird, auch im Interesse des liberalen Rechtsstaats endlich Schluss zu machen mit all dem Militärquatsch.

    Vor allem aber schließt der Film mit der Sorte revolutionärem Optimismus, der mir in der derzeitigen radikalen Linken eigentlich fast überall fehlt. Ich mache ja die generelle Miesepetrigkeit, Coolness und Belehrsucht in unseren Kreisen schon etwas mitverantwortlich dafür, dass „konservative“ bis faschistische Gedanken in erstaunlich vielen Studihirnen (und, schlimmer noch, unter weniger Privilegierten) Raum greifen.

    Wie viel hoffnungsvoller klingt, womit Otis Gibbs die HörerInnen aus der Sendung entlässt (Übersetzung des DLF; das Original, wo ich es hören kann, scheint mir noch eine Spur ergreifender):

    Ich habe ein sehr gutes Gefühl, was die Zukunft angeht, und ich denke, es ist nur eine Frage der Zeit, bis sehr gute Sachen in Amerika passieren. Jetzt lastet noch eine Dunkelheit auf uns allen, und ich spüre sie wie jedeR andere auch. Aber ich treffe auch Menschen, die einem Mut machen, und sie sind alle jung. Sie sind Idealisten. Wir müssen nur diese schreckliche Zeit, in der wir leben, überleben, bis die jungen Leute das Ruder übernehmen und die Welt zu einem viel besseren Ort machen.

    So ganz von selbst wird das wohl nicht gehen, aber es ist jedenfalls der viel bessere Ansatz als… na ja, wie ich gerade damit zu hadern, dass unser schnarchiger DGB beängstigend nahe dran ist an der One Big Union, die Joe Hill und die Wobblies mal im Sinn hatten. Jaja, ich hadere ja schon nicht mehr.

  • Replacing root-tail when there is a compositor

    Since there hasn't been real snow around here this year until right this morning, I've been running xsnow off and on recently[1]. And that made me feel the lack of a compositor on my everyday desktop. Certainly, drop shadows and fading windows aren't all that necessary, but I've been using a compositor on the big screen at work for about a decade now, and there are times when the extra visual cues are nice. More importantly, the indispensable xcowsay only has peudo-transparency when there's no compositor ever since it moved to gtk-3 (i.e., in Debian bullseye).

    Well: enough is enough. So, I'm now running picom in my normal desktop sessions (which are managed by sawfish).

    Another near-indispensable part of my desktop is that the syslog is shown in a part of the root window (a.k.a. desktop background), somewhat like this:

    Windows, and a green syslog in the background

    This was enabled by the nice program root-tail for ages, but alas, it does not play well with compositors. It claims its --windowed flag does provide a workaround, but at least for me that failed in rather crazy ways (e.g., ghosts of windows were left behind). I figured that might be hard to fix and thought about an alternative. Given compositors are great for making things transparent: well, perhaps I can replace root-tail with a heavily customised terminal?

    The answer: essentially, yes.

    My terminal program is unicode-rxvt. In the presence of a compositor, you can configure it for a transparent background by telling it to not use its pseudo-transparency (+tr), telling it to use an X visual with an alpha channel (-depth 32) and then using a background colour with the desired opacity prefixed in square brackets. For a completely transparent terminal, that is:

    urxvt -depth 32 +tr -bg "[0]#000000"
    

    This still has the scrollbar sticking out, which for my tail -f-like application I don't want; a +sb turns it off. Also, I'm having black characters in my terminals by default, which really doesn't work with a transparent background. Making them green looks techy, and it even becomes readable when I'm making the background 33% opaque black:

    urxvt -depth 32 +tr +sb -bg "[33]#000000" -fg green
    

    To replace root-tail, I have to execute my tail -f, put the window into the corner and choose a somewhat funky font. To simply let me reference the whole package from startup files, I'm putting all that into a shell script, and to avoid having the shell linger around, all that this script does is call an exec (yes, for interactive use this probably would be an alias):

    #!/bin/sh
    exec /usr/bin/urxvt -title "syslog-on-root" +sb \
            +tr -depth 32 -bg "[33]#000000" -g 83x25-0-0 \
            -fg green -fn "xft:monofur-11:weight=black" \
            -e tail -f /var/log/syslog
    

    This already looks pretty much as it should, except that it's a normal window with frames and all, and worse, when alt-tabbing through the windows, it will come up, and it will also pollute my window list.

    All that needs to be fixed by the window manager, which is why I gave the window a (hopefully unique) title and then configured sawfish (sawfish-config, “Window Rules”) to make windows with that name depth 16, fixed-position, fixed-size, sticky, never-focus, cycle-skip, window-list-skip, task-list-skip, ignore-stacking-requests. I think one could effect about the same with a judicious use of wmctrl – if you rig that up, be sure to let me know, as I give you it would be nice to make that part a bit more independent of the window manager.

    There's one thing where this falls short of root-tail: Clicks into this are not clicks into the root window. That hurts me because I have root menus, and it might hurt other people because they have desktop icons. On the other hand, I can now mouse-select from the syslog, which is kind of nice, too. Let's see.

    [1]Well, really: Mainly because I'm silly.
  • Ach, Bahn, Teil 2: Maustracking ist Quatsch

    Screenshot: Blockiertes Javascript auf bahn.de

    F12 in den üblichen Browsern führt auf verschiedene Sorten von „Web-Inspektoren“. In deren „Network“-Tabs könnt ihr die Flügel'sche Metrik bestimmen: Wie viele Dateien von wie vielen Hosts zieht so eine Seite? Die Bahn-Seite schneidet dabei nicht gut ab, nicht zuletzt aufgrund des nutzerInnenfeindlichen Javascripts, das der Screenshot zeigt.

    Wieder mal habe ich auf bahn.de eine Fahrkarte gekauft, und wieder hakte es an vielen Ecken. Immer noch hat der Server darauf bestanden, ich sei eingeloggt (und hat mir nicht die Möglichkeit gegeben, mich einzuloggen), hat mir aber nicht meine Buchungs-Voreinstellungen („eine Person mit Bahncard 50“) angeboten, hat wieder ganze Seiten mit je nur einer einzelnen Frage ausgeliefert, hat kaputte Zahlungsoptionen angeboten, quittierte einen Browser-Reload mit hartem Ausloggen („fang einfach nochmal an“) und verlangte von mir ein Login beim Kartenkauf, obwohl es mich ja die ganze Zeit schon als eingeloggt geführt hat. Immerhin – niemand soll sagen, ich würde nur motzen – war das Captcha vom letzten Herbst endlich weg (eine Reaktion auf meine diesbezüglichen Mails aus dem Herbst-Blogpost habe ich natürlich nie bekommen).

    Jedenfalls reichen eigentlich ein, zwei Transaktionen auf bahn.de locker, um einige (modulo Ökonomie) leicht zu behebende Usability-Schwächen zu finden. Aber gut: Gerade bei Webseiten bin ich ja schon froh, wenn sie wenigestens ihre Quirks behalten und nicht alle paar Wochen wieder was anders (zumeist: anders kaputt) ist. Ich erwähne das alles überhaupt nur, weil bahn.de in meinem Browser mal wieder so hakelig war, dass ich nachgesehen habe, wessen Javascript mir die Bahn neben ihrem eigenen (das dürfen sie ausführen) noch andrehen will. Unter den geblockten Quellen befand sich ein Laden namens m-pathy.com. Dessen Homepage (kleines Lob am Rande: das geht, ohne Code von m-pathy.com auf der lokalen Maschine laufen zu lassen) radebrecht mit Deppen-Leerzeichen:

    m-pathy UX Insight G4 macht sichtbar, was Ihre Kunden erleben.

    Unsere Analyse Lösung ermöglicht die Auswertung tausender feingranularer Interaktionsdaten aus Mausspuren, Touch-Gesten, Klicks und Formularinteraktionen.

    Das Ergebnis sind belegbare und priorisierbare Handlungsempfehlungen für die Optimierung Ihrer klassischen oder mobilen Webseite.

    Also: Die Bahn sammelt und verarbeitet Daten über meine Mausbewegungen (na ja, natürlich nicht über meine, weil das Javascript dieser Leute bei mir nicht läuft, aber von fast allen anderen ihrer KundInnen), um so zu tun, als würde sie ihre Webseite „optimieren“.

    Da die Usability der Webseite zumindest in meinem „Erleben“ spürbar abgenommen hat – vor allem wohl wegen der Förderung von „Partnerangeboten“ und anderen Marktingkrams, aber seis drum –, würde ich schließen, dass „m-pathy UX Insight G4“ schlicht nicht funktioniert. Ok: Kann sein, dass die hautnahe Bespitzelung der NutzerInnen durch die Bahn funktioniert und sich eben nur niemand um „belegbare und priorisierbare Handlungsempfehlungen“ kümmert. Dann könnte die Bespitzelung aber auch unterbleiben, oder? Oder sind die Zwecke der Bahn ganz andere als die bei m-pathy angegebenen? Allein, mir würden da nicht viele einfallen. Was bitte soll aus meinen Mausbewegungen über der Bahn-Webseite für die Bahn schon folgen?

    Einfach mal offen (also: ohne Fragebogen) mit 10 oder 50 NutzerInnen der Webseite reden und ihnen zuhören wäre ganz klar gigantisch viel datensparsamer und, so bin ich sicher, auch erheblich wirksamer, wenn die Bahn die Seite wirklich verbessern wollte.

    Liebe Bahn, darf ich euch noch einen Neujahrsvorsatz vorschlagen? Es wäre: Buchen ohne Javascript, vielleicht sogar mit einem lokalen, Debian-paketierbaren Programm, das auf einer wohldokumentierten API aufsetzt.

  • 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.

« Seite 12 / 17 »

Letzte Ergänzungen