Push to Publish

Seit Anfang August wird dieses Blog nicht mehr von einem Raspberry aus den eigenen vier Wänden ausgeliefert, sondern von GitHub pages. Da die Quellen dieses Blogs bereits auf GitHub sind, ist dies ein konsequenter Schritt.

Hosting auf GitHub Pages GitHub Logo

GitHub bietet hosting von statischen Seiten an, was perfekt zu diesem Pelican Blog passt. Die Verwaltung ist denkbar einfach: Für jedes Repository ist der Branch gh-pages unter [username].github.io/[reponame], hier z.B. surt91.github.io/blog, erreichbar.

Will man unter einer eigenen Domain erreichbar sein, reicht es aus, im DNS für die Domain einen CNAME Eintrag auf [username].github.io anzulegen und im root des gh-pages Branches eine Datei CNAME mit der eigenen Domain anzulegen, hier z.B.

echo blog.schawe.me > CNAME

Primär dient GitHub pages dazu Jekyll Seiten zu erstellen und auszuliefern, was zu Konflikten führen kann, wenn man einfach nur statische Seiten im gh-pages Branch vorhält. Dies lässt sich einfach vermeiden, indem man eine Datei .nojekyll im root anlegt.

Automatische Erstellung durch Travis CI Travis CI Logo

Natürlich könnte man das statische HTML auf einem lokalen Computer erstellen und per Hand in den gh-pages Branch pushen. Aber man kann das auch einem Dienst wie Travis CI überlassen.

Die Idee ist, dass jedes Mal wenn man die Quellen seiner Seite ändert — im Fall von Pelican werden die Blogeinträge in Markdown geschrieben und dann in HTML konvertiert — ein Server die Seite erstellt und das Ergebnis in den gh-pages Branch pusht. Dadurch wird ein Update der Website auf ein einfaches git push reduziert.

Die Konfiguration von Travis CI wird durch eine denkbar einfache YAML Datei definiert. Eine (vereinfachte) Konfiguration für dieses Blog sieht beispielsweise so aus:

# pelican is a python program
language: python
python:
  - "3.5"

# install pelican and some more packages
install: "pip install -r requirements.txt"

# generate static html through pelican's makefile
script:
  - make publish

# deploy to github pages
deploy:
  provider: pages
  skip_cleanup: true
  github_token: $GITHUB_TOKEN
  local_dir: output
  on:
    branch: master

Falls Fehler beim Erstellen auftreten, schickt Travis eine Email und bricht die Veröffentlichung ab. Wenn keine Fehler auftreten, wird wenige Sekunden später die neue Version von GitHub ausgeliefert.

SSL verschlüsselt von Cloudflare®

Die github.io Domains werden zwar verschlüsselt ausgeliefert, aber natürlich kann GitHub keine SSL Zertifikate für die eigene Domain ausstellen lassen. [Update: Mittlerweile kann GitHub das.] Man kann auch kein eigenes Zertifikat hochladen. Aber die Situation ist nicht so aussichtslos wie sie scheint. Cloudflare ermöglicht es, allerdings müssen ein paar Bedingungen erfüllt sein.

Cloudflare muss

  • als DNS Service für die gewünschte Domain genutzt werden und
  • als Proxy vor der Seite benutzt werden.

Als Bonus können wir Cloudflares CDN nutzen.

Sobald sich Cloudflare um das DNS der Domain kümmert, kann über das Dashboard SSL aktiviert werden — und wenn man schon dabei ist, sollte man auch die Always use HTTPS und HSTS Optionen aktivieren.

Vicsek

Das Vicsek-Modell wurde 1995 vorgeschlagen, um das Schwarmverhalten von Vögeln oder Fischen zu modellieren. Die Idee ist, dass jedes Individuum seine Bewegungsrichtung an der seiner Nachbarn anpasst. Wenn jedes Individuum genügend Nachbarn hat und die Störeinflüsse nicht zu groß sind, bilden sich Schwärme. Videos von solchen Schwärmen werden auf allen größeren Konferenzen der Statistischen Physik gezeigt — und jetzt auch hier.

Auf GitHub findet sich das Programm, das ich für obiges Video geschrieben habe. Es ist in Rust geschrieben und zeigt die Simulation per Piston auf dem Bildschirm.

Ich habe sehr großen Gefallen an Rust gefunden — gerade für ein Projekt wie dieses scheint es ideal geeignet. Es ist so schnell wie C, aber man muss sich keinerlei Gedanken um den Speicher machen und einige andere Fehlerklassen, die der Compiler direkt verhindert. Rayon macht Parallelisierung so einfach wie OpenMP — mit dem Vorteil, dass der Compiler einen Fehler ausgibt, falls es eine Variable gibt, aus der parallel gelesen und geschrieben wird.

Als Beispiel, warum ich Rust als sehr leserlich und elegant empfinde, möchte ich folgendes (unvollständige) Beispiel ansehen.

pub enum Proximity {
    Neighbors(usize),
    Radius(f64)
}

pub struct Vicsek {
    proximity: Proximity,
}

impl Vicsek {
    fn update(bird: &mut Bird) {
        match self.proximity {
            Proximity::Neighbors(n) => self.update_direction_neighbors(bird, n, noise),
            Proximity::Radius(r) => self.update_direction_disk(bird, r, noise),
        }
    }
}

Die Methode update() passt die Richtung an, in die ihr Argument im nächsten Zeitschritt fliegen soll. In meiner Simulation gibt es zwei Möglichkeiten: entweder orientiert man sich an seinen n nächsten Nachbarn oder an allen Vögeln innerhalb eines Radius von r. Der Datentyp Proximity kann eines von beiden beinhalten — welches vorhanden ist, kann elegant per Pattern-Matching ermittelt werden.

Brauche ich länger, um Rust zu schreiben als C oder C++? Vermutlich, aber ich verbringe weniger Zeit mit dem Debuggen. Netto also mehr Spaß.

A Graph a Day

Vor einiger Zeit habe ich @randomGraphs geschrieben: Ein Twitterbot, der einen Zufallsgraphen pro Tag tweetet.

Die meisten Graphtypen, die er darstellen kann stammen aus der NetworkX Bibliothek oder sind reale Netzwerke. Ein paar Proximity Graphs habe ich selbst geschrieben. Die Darstellung und gegebenenfalls das Layout übernimmt Cytoscape oder graph-tool (dessen Autor diesem Bot folgt).

Bei diesem Projekt habe ich exzessiv Gebrauch von Pythons Decorator und Introspection gemacht, sodass man, um einen neuen Graphtyp einzuführen nur eine Methode schreiben muss, die eine Graph-Datenstruktur zurück gibt. Einstellungen, welche Darstellungen erlaubt sind, werden per decorator getätigt und alle Methoden werden per Introspection automatisch zum Pool hinzugefügt, aus dem der Zufallsgenerator zieht.

Eine typische Methode sieht etwa so aus.

@synonym("Barabasi Albert")
@synonym("preferential attachment")
@style(styles_all)
@layout(["kamada-kawai", "force-directed", "sfdp", "fruchterman_reingold", "arf", "radial_tree"])
def generateBarabasiAlbert(self, N=None, m=None, **kwargs):
    if N is None: N = random.randint(4, 400)
    if m is None: m = random.randint(1, 5)

    G = gen.barabasi_albert_graph(N, m)  # gen is networkx Generator
    details = dict(name="Barabási-Albert Graph", N=N, m=m, seed=self.seed,
                   template="{name}, N = {N}, m = {m}")

    return G, details

Und liefert für $N=226, m=1$ und das radial_tree Layout beispielsweise diesen Graph. Die Größe der Knoten wird hier von der Betweenness Centrality bestimmt.

Graph

Die @synonym Decorators ermöglichen die zweite Funktion des Bots, denn er tweetet nicht nur einmal am Tag einen zufälligen Graphen, sondern reagiert auch auf Mentions. Falls in der Mention der Name der Methode oder eines der per @synonym registrierten Worte auftaucht, antwortet er mit einem Bild des entsprechenden Graphen. Dank fuzzywuzzy ist es sogar resistent gegen Tippfehler.

Twitter unterstützt leider keine Vektorgrafiken und wandelt Bilder gerne in stark komprimierte .jpg, was gerade bei diesen Graphen zu störenden Artefakten führt. Dagegen hilft es, wenn ich einen Rand aus transparenten Pixeln dem Bild hinzufüge. Das führt dazu, dass Twitter .jpg nicht als geeignetes Format ansieht und die Bilder im verlustfreien .png ausliefert.

convert -alpha on -channel RGBA -bordercolor "rgba(0,0,0,0)" -border "1x1" input.png output.png

Graph

Der komplette Quellcode ist auf Github.