UMS als systemd Service

Der Universal Media Server ist praktisch um Musik oder Filme und Serien zum Beispiel über eine Playstation abspielen zu können. Besonders wenn man einen kleinen Server laufen hat. In dem Fall soll der UMS natürlich beim Systemstart ebenfalls starten. Leider hat der UMS manchmal aber auch seine macken, insbesondere leidet er an gelegentlichen Exceptions und lässt den Speicher voll laufen.

Installation als Service

Neuere Systeme, z. B. CentOS 7 oder die aktuelle LTS Ubuntu-Variante Yakkety Yak nutzen systemd anstelle von init.d zum Starten von Systemdiensten. Es gibt einige Ressentiments dagegen und viele Diskussionen. Es spielen sogar irgendwie Nazis rein :D

[…] he’s your typical German that’s into efficiency and control, and that’s the philosophy the software is built around. Doing everything as efficiently as possible with whatever is available. This doesn’t mesh too well with the (arguably very American) Linux philosophy of modularity and freedom of choice. [1]

Gemeint ist hier wohl Entwickler Lennart Poettering und sein Beitrag zur Klärung. Ein weiter deutscher Entwickler ist Kay Sievers, der durch seine Art scheinbar Stress mit Linus Torvalds hat, der mal wieder einen seiner epischen Rants abgelassen hat

Wie dem auch sei, man kann den UMS auch mit systemd starten.

Zur Konfiguration des Media Servers als Service wird in der Datei

/etc/systemd/system/ums.service

die Konfiguration hinterlegt. UMS kommt bereits mit einem Startscript namens UMS.sh, was als Startkommando ExecStart hinterlegt wird. Wie es sich gehört, sollte der Media Server auch mit seinen eigenen Benutzerrechten laufen, in diesem Fall als Nutzer ums.

Im bereich [Install] wird angegeben, wann der Service gestartet werden soll, in diesem Fall also beim Systemstart vom Ziel multi-user.

[Unit]
Description=Universal Media Server
 
[Service]
Type=simple
User=ums
Group=ums
ExecStart=/opt/UMS/UMS.sh
 
[Install]
WantedBy=multi-user.target

Nun muss der Service noch aktiviert werden.

systemctl enable ums.service
systemctl start ums.service

Neustart des Service

Eigentlich könnte es das schon gewesen sein. Leider stürzt der Server manchmal ab oder belegt zu viele Resourcen. Eine Möglichkeit das zu umgehen ist ein regelmäßiger Neustart.

Das kann man mit systemd auch automatisieren, es ist ein cron ähnlicher Scheduler enthalten (siehe feature creep ;) ) Die Umsetzung ist aber etwas umständlich. Zunächst benötigt man einen eigenen Service

/etc/systemd/system/umsRestart.service

dessen Aufgabe darin besteht, den gerade definierten UMS Service neu zu starten. Er soll danach direkt beendet werden, und nicht wieterlaufen. Es ist daher eigentlich kein Service im eigentlichen Sinne. Dazu wird der Type als oneshot definiert. Um einen systemd-Service neu zu starten kann der Befehl try-restart genutzt werden.

[Unit]
Description=Universal Media Server Restart Service
 
[Service]
Type=oneshot
ExecStart=/bin/systemctl try-restart ums.service

Nun fehlt noch der Timer. Dazu wird ein dritter systemd-Service benötigt, der diesmal ein anderer Typ ist und daher in der Datei

/etc/systemd/system/umsRestart.timer

mit der Endung .timer spezifiziert wird. Die genaue Uhrzeit kann als Parameter OnCalendar im 24-Stunden-Format angegeben werden, zum Beispiel nachts wenn normalerweise nichts läuft. Die verschiedenen Timer werden vom Target timer verwaltet.

[Unit]
Description=Universal Media Server Restart Timer
 
[Timer]
OnCalendar=4:45
Persistent=true
 
[Install]
WantedBy=timer.target

Damit nun alles läuft, muss die neuen Services noch gestartet werden:

systemctl daemon-reload
systemctl start umsRestart.service

Testen

Eine Liste der aktuell laufenden Timer kann mit

systemctl list-timers

angezeigt werden. Wenn alles funktioniert hat ist der UMS Restart Service in der Liste enthalten:

NEXT                         LEFT          LAST                         PASSED               UNIT                
Di 2017-04-11 00:04:01 CEST  42min left    Mo 2017-04-10 13:07:02 CEST  10h ago              apt-daily.timer     
Di 2017-04-11 02:21:04 CEST  2h 59min left Mo 2017-04-10 19:32:02 CEST  3h 49min ago         snapd.refresh.timer 
Di 2017-04-11 04:45:00 CEST  5h 23min left Mo 2017-04-10 04:45:02 CEST  18h ago              umsRestart.timer    
Di 2017-04-11 22:33:35 CEST  23h left      Mo 2017-04-10 22:33:35 CEST  47min ago            systemd-tmpfiles-clean.timer

4 timers listed.

Wichtig ist, dass der Universal Media Service tatsächlich läuft. Ansonsten kann er nämlich nicht neu gestartet werden. Das kann man testen, indem der Restart-Service direkt ausgeführt wird. Es erscheint dann eine zugegebenermaßen nicht sehr verständliche Fehlermeldung:

$ systemctl status umsRestart.service
● umsRestart.service - Universal Media Server Restart Service
   Loaded: loaded (/etc/systemd/system/umsRestart.service; static; vendor preset: enabled)
   Active: failed (Result: exit-code) since Mo 2017-04-10 04:45:02 CEST; 18h ago
 Main PID: 28192 (code=exited, status=203/EXEC)
 
Apr 10 04:45:02 k systemd[1]: Starting Universal Media Server Restart Service...
Apr 10 04:45:02 k systemd[1]: umsRestart.service: Main process exited, code=exited, status=203/EXEC
Apr 10 04:45:02 k systemd[1]: Failed to start Universal Media Server Restart Service.
Apr 10 04:45:02 k systemd[1]: umsRestart.service: Unit entered failed state.
Apr 10 04:45:02 k systemd[1]: umsRestart.service: Failed with result 'exit-code'.
Geschrieben von Kap. Zuletzt geändert am 22. April 2017.

Alkohol aus den USA liefern

Amerikaner haben ein Problem mit Drogen. Soweit bekannt. Das gilt jedoch auch für Alkohol, also verschicken sie das Zeug nicht nach Europa (too near to the dragons!?). Es gibt Services, die Pakete weiterleiten. Auch mit Alkohol, wie ich bereits berichtet habe. Hier nun der Follow Up, wie man mit der Weiterleitung nun an den guten Alk kommt.

Shopsuche

Nun sollte der leichtere Teil kommen. Einfach einen Vodka 360 Double Donut bestellen, bisschen warten und genießen.

Ich so: „Yeah, eine Adresse in den USA, dann bestelle ich da gleich mal ne Flasche Vodka hin“. Die Wirklichkeit: „Yeah, schade. Wir liefern gar nicht nach Florida! Und wir wissen, dass an der Adresse ein Weiterleitungsservice sitzt. Du bist bestimmt so ein Dreckseuropäer und wir wollen unseren Booze für uns behalten! Har, har har!

Also, suchen bis ein Shop auftaucht, der dahin liefert. Am einfachsten ist ein Shop, der in Florida liegt. Die verschicken auf jeden Fall nach Florida. Beim Suchen muss man aber aufpassen, viele Shops haben zwar ne Webseite, aber man muss das Zeug selbst abholen. Und die wollen den Kapitalismus perfektioniert haben :O ? Dafür gibts auch nette Services wie eine Übersicht zahlloser Alkoholshops, die man nur der Reihe durchgehen muss. Letztendlich hab ich ihn bei ABC Fine Wine & Spirits gefunden und bestellt. Der Laden ist so zuvorkommend, dass er einen Link verdient.

Bezahlen

Dass die Sache mit den Kreditkarten in deren Herkunftsland gar nicht so einfach ist, habe ich bei der Anmeldung bei MyUS.com schon festgestellt. Bei ABC Fine Wine & Spirits wird ein bisher unerreichtes Level erreicht.

Selbst die Informationen der Issuing Bank und Issuing Bank Phone Number haben nicht gereicht, man braucht ein weiteres Qualitätsmerkmal, AVS. Dabei wird überprüft, ob die Adresse der Kreditkarte der Rechnungsadresse bei der Bestellung übereinstimmt. Was natürlich naheliegenderweise Probleme mit dem ß erzeugt. Ein tatsächlich viel größeres Problem ist, dass in Deutschland ausgegebene Kreditkarten normalerweise keine Adressinformationen enthalten :facepalm:

Aber auch für dieses Problem gibt es eine Lösung, die Internet sei Dank, leicht umzusetzen ist. Die in Malta ansässige Firma EntroPay bietet virtuelle Kreditkarten an, die zwar kein AVS unterstützen, aber trotzdem nutzbar sind. Man muss nur als Rechnungsadresse die Adresse der Bank angeben. Die virtuelle Kreditkarte muss mit einem Mindestbetrag aufgeladen werden, das heißt die Differenz ist dann im Zweifel weg ;)

Liefern

So, Bestellung abgeschickt, nun heißt es erstmal befriedigt zurücklehnen und warten. Nach ein paar Tagen kommt eine Benachrichtigung von MyUS, dass eine Lieferung angekommen ist und auf „Compliance“ geprüft wird. Man kann da z. B. zur Unterstützung den Link zum Shop schicken, dann geht das angeblich schneller. Nach der überstandenen Überprüfung darf man sich einloggen, eine Zieladresse angeben und nach der Bezahlung gehts direkt los. Nun dauert es etwas länger, muss ja erst der Atlantik überquert werden.

Abschluss

Nach ein paar Tagen kommt das Paket mit dem Vodka an die eigene Haustür und es heißt genießen. Und noch viel später kommt die Rechnung vom Zoll.

Und ein kleines Fazit: Der Aufwand lohnt sich wirklich nur, wenn man etwas unbedingt haben möchte. Dafür ist nachdem die Accounts einmal angelegt sind, beim zweiten mal alles etwas leichter. Und zumindestens beim Alkohol muss man zusätzliche Kosten tragen. Ein zusätzlicher Versand, in meinem Fall etwa 10€ und den Zoll bzw. die Alkoholsteuer. Insgesamt habe ich also für eine 13$-Flasche zirka 30€ bezahlt. Wobei, je teurer der Artikel, desto weniger fällt es auf.

Geschrieben von Kap. Zuletzt geändert am 18. Dezember 2018.

ProLiant MicroServer Gen 8 ruhig stellen

Mein kleiner Miniserver der Reihe ProLiant von HP tut bisher was er soll, hat mich jedoch in letzter Zeit durch schrille Töne etwas gestört. Er steht auch direkt auf dem Schreibtisch, da er ja auch sehr ansehnlich ist :)

Nachdem eine Reinigung der üblichen Verdächtigen (vulgo: des Prozessorlüfters) keine Verbesserung ergab, musste ich feststellen, dass das Netzteil in einer unangenehmen Tonlage Geräusche von sich gab. Zum Glück ist es möglich das Standardnetzteil durch ein lüfterloses Modell auszutauschen. Für Leute, die schonmal einen Rechner mit dem Schraubenzieher traktiert haben, ist es ganz einfach. Alle anderen gehen so vor, wie im Folgenden beschrieben.

Was braucht man?

Um das Netzteil im MicroServer Gen 8 auszutauschen braucht man nicht einfach ein „Silent Gen 8 Power Supply“ sondern mehrere einzelne Teile:

Lüfterloses Netzteil:

Die wichtigste Komponente ist selbstverständlich die leise Stromversorgung, zum Beispiel das PicoPSU-160-XT 160W ATX Netzteil. Das kleine Netzteil passt direkt auf den ATX-Stecker der Hauptplatine. Das Netzteil kann 160 Watt mit kurzzeitigen Spitzen bis zu 200 Watt liefern.
Das PicoPSU 160-XT Netzteil für den MicroServer Gen 8 passt in den ATX-Stecker und hat einige SATA- und Molex-Anschlüsse.

Das PicoPSU 160-XT Netzteil für den MicroServer Gen 8 passt in den ATX-Stecker und hat einige SATA- und Molex-Anschlüsse.

Adapter:

Wie jedes Netzteil braucht auch die kleine Variante Strom, im Unterschied zu handelsüblichen Steckern passt jedoch nicht direkt ein Schukostecker an das PicoPSU. Eine Möglichkeit für die Stromversorgung ist ein Standard-AC/DC Adapter. Der Adapter ist natürlich viel Größer als das alte Netzteil und wird wie ein Laptop-Netzadapter hinter dem Server auf dem Boden liegen (oder sonstwo versteckt.)
Adapter für den PicoPSU 160-XT

Adapter für den PicoPSU 160-XT

Anschlusskabel:

Das PicoPSU hat für den MicroServer Gen 8 einen Anschluss zu wenig. Einige Geräte sind über einen Berg-Stecker (ein herkömmlicher, eigentlich aus der Mode gekommener Disketten-Anschluss) verbunden. Um diesen Anschluss weiterhin zu ermöglichen. Das ist die Gelegenheit den lange vergessenen Molex-Y-Adapter (für alte Stromanschlüsse von Festplatten) aus der alten Kiste mit Kabeln zu suchen. Zumindestens, wenn man so eine Kiste im Keller stehen hat. Ansonsten gibts den auch noch zu kaufen.
Standard Molex-Y-Adapter mit Berg-Anschluss.

Standard Molex-Y-Adapter mit Berg-Anschluss.

Ausbau des alten Netzteils

Bevor die Arbeiten beginnen sollte natürlich das Stromkabel vom alten Netzteil abgezogen werden. Dann kann der ATX-Pfostenstecker von der Hauptplatine abgezogen werden. Das Netzteil des Gen 8 hat noch einige weitere Anschlüsse. Die Festplatten sind über einen Molex-Adapter angeschlossen, der sich unter dem optischen Laufwerk verbirgt. Nachdem das Laufwerk gelöst und rausgeschoben worden ist, wird der Anschluss unter dem Gehäuse sichtbar. Es ist nicht notwendig, das CD-Laufwerk komplett auszubauen. Man kommt nicht direkt an den Molex-Stecker heran, sondern muss durch zwei kleine Öffnungen hindurch. Ich habe einen Schraubenzieher und den Inbusschlüssel, der sich vorne hinter der Klappe befindet, genommen um den Stecker auseinander zu ziehen.

Der zum Netzteil gehörende Stecker muss durch einen Adapter ersetzt werden.

Der zum Netzteil gehörende Stecker muss durch einen Adapter ersetzt werden.

Unter dem optischen Laufwerk befindet sich eine Molex-Steckverbindung, die gelöst werden muss.

Unter dem optischen Laufwerk befindet sich eine Molex-Steckverbindung, die gelöst werden muss.

Ein weiteres Anschlusskabel mit Berg-Stecker verläuft direkt oben auf dem Gehäuse. Das Gegenstück zum Stecker ist ziemlich fest verbaut, es lässt sich aber gut lösen wenn ein spitzer Gegenstand zum Anheben der Klemme benutzt wird.

Der Berg-Stecker, der das optische Laufwerk mit Strom versorgt.

Der Berg-Stecker, der das optische Laufwerk mit Strom versorgt.

Zum Lösen des Steckers muss etwas spitzes unter die Klemme geschoben werden.

Zum Lösen des Steckers muss etwas spitzes unter die Klemme geschoben werden.

Das Netzteil selbst ist innen und außen mit jeweils drei Schrauben fixiert, die mit dem Inbusschlüssel an der Vorderseite gelöst werden können. Anschließend kann das alte Netzteil leicht herausgenommen werden.

Drei Schrauben müssen innen entfernt werden um die Halterung zu lösen.

Drei Schrauben müssen innen entfernt werden um die Halterung zu lösen.

Drei Schrauben müssen auf der Rückseite entfernt werden um das Netzteil vom Gehäuse zu lösen.

Drei Schrauben müssen auf der Rückseite entfernt werden um das Netzteil vom Gehäuse zu lösen.

Einbau des neuen Netzteils

Das PicoPSU besteht im wesentlichen nur aus dem Pfostenstecker und kann einfach auf das Motherboard aufgesteckt werden. Das Y-Kabel wird zwischen den Molex-Anschluss des PicoPSU und den unter dem Gehäuse liegenden schwer zu erreichenden Anschluss der Festplatten geklemmt. Hier ist wieder etwas Fingerspitzengefühl oder der geschickte Einsatz eines Schraubenziehers als fester Gegenpol hilfreich.

Das PicoPSU ist sehr klein und sitzt direkt auf dem ATX-Connector der Hauptplatine.

Das PicoPSU ist sehr klein und sitzt direkt auf dem ATX-Connector der Hauptplatine.

Der Y-Adapter wird zwischen das PicoPSU und den Anschluss unter dem optischen Laufwerk eingefügt.

Der Y-Adapter wird zwischen das PicoPSU und den Anschluss unter dem optischen Laufwerk eingefügt.

Der Berg-Connector des Y-Adapters wird nach oben gezogen und einfach in das entsprechende Gegenstück eingesteckt. Zuletzt muss noch das 4-polige Anschlusskabel des Netzteils nach hinten an die Stelle des alten Netzteils gelegt werden, so dass der Netzadapter angeschlossen werden kann. Es bleibt noch ein Loch hinten in der Rückwand des Servers, der als Staubschutz noch mit einem geeigneten Stück Altmetall verschlossen werden kann. Man denke nur an oben erwähnte Kiste ;)

Der Berg-Anschluss des Y-Kabels wird mit dem oben liegenden Gegenstück verbunden.

Der Berg-Anschluss des Y-Kabels wird mit dem oben liegenden Gegenstück verbunden.

Das vierpolige Anschlusskabel für den Stromadapter wird nach hinten gezogen und durch die Lücke des alten Netzteils nach außen geleitet.

Das vierpolige Anschlusskabel für den Stromadapter wird nach hinten gezogen und durch die Lücke des alten Netzteils nach außen geleitet.

Das war’s schon, und jetzt viel Spaß mit eurem neuen, leisen Server :)

Geschrieben von Kap. Zuletzt geändert am 10. März 2017.

Mehrere Rückgabewerte eines HTTP-Requests

Manchmal ist es notwendig, dass ein Webservice mehrere Ergebnisse nacheinander zurückliefert. Zum Beispiel, wenn ein Request abgesetzt wird, der zunächst validiert werden muss, bevor tatsächlich eine Prozessierung beginnt und die Validierung selbst eine längere Zeit dauert. Dann soll der Server nach Möglichkeit den Request direkt beenden und die Validierung im Hintergrund ablaufen. Andernfalls ist die Webseite nicht responsiv, was den Nutzer verunsichern könnte und keine gute User Experience ist. In einem Spring Boot basierten Webservice kann das zum Beispiel mit asynchroner Ausführung und long polling zusammen mit einem Deferred Result erreicht werden, wie im folgenden beschrieben.

Das Szenario

Im folgenden soll ein kleiner Webservice in Spring Boot implementiert werden, der eine Anfrage auslöst, die zwei Stadien durchläuft. Direkt bei der Anfrage wird in einen Zustand INITIALIZING gewechselt, bis nach einigen Sekunden der Zustand PHASE1 erreicht wird. Den Abschluss markiert der Zustand DONE. Die zugehörige Webseite soll jeweils den aktuellen Status anzeigen und bei einem Statuswechsel automatisch aktualisiert werden.

Eine Beispielimplementation des Webservers habe ich auf GitHub hochgeladen. Es kann nach dem Auschecken mit mvn spring-boot:run gestartet werden, der Webservice ist unter http://localhost:8080 erreichbar.

Beispiel-Service für asynchrone Ausführung und Long-Polling

Beispiel-Service für asynchrone Ausführung und Long-Polling

Bei einem Klick auf die Schaltfläche geht es los.

Die serverseitige Implementierung

Zu Beginn wird ein POST-Request über an /request geschickt. Die Methode soll sofort ein Ergebnis zurückliefern, auch wenn die auszuführende Aktion länger dauert. Dazu wird nicht der tatsächliche Ergebnistyp zurückgeliefert sondern ein DeferredResult. Die Webseite kann daraufhin direkt aktualisiert werden, da die Anfrage schnell bearbeitet wird, das tatsächliche Ergebnis ist im Ergebnis erst vorhanden, sobald setResult aufgerufen wird.

@RequestMapping(name = "/request", method = RequestMethod.POST)
@ResponseBody
public DeferredResult request() {
    // Prepare already for the first state change
    DeferredResult result = service.getStatus();
 
    // Actually let the asynchronous service do something
    service.doSomething();
 
    // Return the deferred result that will be set in the above asynchronous call
    return result;
}

Die Anfrage wurde abgesetzt.

Die Anfrage wurde abgesetzt.

Beim Long Polling kann der Webserver verspätet antworten. Typischerweise wird ein Timeout gesetzt, so dass bei einem Verbindungsabbruch eine neue Anfrage gestartet werden kann. Da unklar ist, wie lange die Antwort tatsächlich dauert, sollte mit dem Verbindungsabbruch gerechnet werden. Die Statusabfrage für das Long Polling wird über den Endpunkt /poll durchgeführt. Das Ergebnis wird vom ausführenden Service geholt und zurückgeliefert. Das zurückgelieferte Object vom Typ DeferredResult wird automatisch so lange zurückgehalten, bis der Service über einen Aufruf von setStatus() ein Ergebnis bereitstellt.

@RequestMapping(name = "/poll", method = RequestMethod.GET)
@ResponseBody
public DeferredResult requestStatus() {
    // Simply forward the request to the service
    return service.getStatus();
}

Asynchrone Ausführung der Anfrage

Damit der ganze Prozess funktioniert, muss die Arbeit des Services (service.doSomething() im Beispiel oben) asynchron ablaufen. Das heißt, nach dem Aufruf von doSomething kann direkt etwas zurückgeliefert werden. Spring Boot ermöglicht durch die Annotation @Async, dass eine Methode eines Services automatisch in einem anderen Thread asynchron ausgeführt wird. Die folgende Methode simuliert, dass der Status zunächst auf INITIALIZING gesetzt wird, anschließend eine längere Zeit gearbeitet wird und zuletzt beendet wird sobald der Status auf DONE steht.

@Async
void doSomething() {
    // Initialize the current status and notify any listener that is already present
    currentStatus = LongRequestStatus.INITIALIZING;
    publishStatus(currentStatus);
 
    // Perform some work until the final state is reached.
    do {
        currentStatus = doNecessaryWork(currentStatus);
        publishStatus(currentStatus);
    } while (currentStatus != LongRequestStatus.DONE);
}

Die Methode wird bei einem POST-Request an /request aufgerufen. Den Status der parallel ausgeführten Methode wird mit publishStatus gesetzt. Falls es in der Zwischenzeit eine eventuell vorhandene Long Polling-Anfrage (mit einem Status als DeferredResult) gab, wird der Status gesetzt.

private synchronized void publishStatus(LongRequestStatus nextToReturn) {
    if (waitingResponse != null) {
        waitingResponse.setResult(nextToReturn.toString());
    }
    waitingResponse = null;
}

Die Anfrage wird gerade Bearbeitet.

Die Anfrage wird gerade Bearbeitet.

Eine Polling-Anfrage ruft ausgehend vom Controller die Methode getStatus auf. Diese erzeugt das DeferredResult waitingResponse, das direkt beantwortet wird, wenn bereits Informationen da sind. Andernfalls wird die Anfrage gespeichert und das Ergebnis gegebenenfalls in obiger Methode publishStatus gesetzt.

public synchronized DeferredResult getStatus() {
    waitingResponse = new DeferredResult<>();
 
    // If the request completed, immediately return the status because it will never change
    if (currentStatus == LongRequestStatus.DONE) {
        waitingResponse.setResult(currentStatus.toString());
    }
 
return waitingResponse;

Die Webseite

Auf der Clientseite wird das Statusupdate mit JavaScript durchgeführt. Bei einem Click auf die Schaltfläche wird zunächst wird die Anfrage ausgeführt und bei Erfolg die Long Polling-Abfrage gestartet.

function request() {
    var xhr = new XMLHttpRequest();
    xhr.open("POST", "/request", true);
    xhr.onreadystatechange = function() {
        if(xhr.readyState === 4 && xhr.status === 200) {
            // Do something with the response
            console.log(xhr.responseText);
 
            // Start long polling and get the next status
            poll();
        }
    }
    xhr.send();
}

Die Methode poll sendet die Anfrage an den Server um den aktuellen Status abzuholen. Die Anfrage wird solange erneut ausgeführt, bis das Endergebnis DONE zurückgeliefert wird. Als Timeout ist eine Sekunde gesetzt, was relativ kurz ist und dafür sorgt, dass jede Sekunde erneut beim Server nachgefragt wird.

function poll() {
    var xhr = new XMLHttpRequest();
 
    xhr.open("GET", "/poll", true);
 
    xhr.onreadystatechange = function() {
        if(xhr.readyState == 4 && xhr.status == 200) {
            if (xhr.responseText !== "DONE") {
                // Start the next polling request
                setTimeout(poll, 1000);
            } else {
                // Stop polling
            }
        }
    }
    xhr.send();
}

Die Anfrage wurde komplett bearbeitet.

Die Anfrage wurde komplett bearbeitet.

Was fehlt?

Das Grundgerüst für mehrere konsekutive Ergebnisse, die auf eine Anfrage zurückgegeben werden sollen steht damit. Es schließen sich nun einige Möglichkeiten der Erweiterung an.

Da Server normalerweise mehrere Nutzer haben, sollte es natürlich möglich sein, dass mehrere Anfragen parallel ablaufen. Dazu müssen für alle diese Anfragen die Stati gespeichert werden. Der erste Request kann dann ein Token (zum Beispiel eine UUID) zurückgeben, mit der anschließend beim Polling der Status der passenden Anfrage abgefragt werden kann. Gegebenenfalls muss hier natürlich noch mit Authentifizierung gearbeitet werden, so dass jeder Nutzer nur seine eigenen Requests anfragen kann.

Geschrieben von Kap. Zuletzt geändert am 16. Februar 2019.

Von Videokodierung und Bitraten

Ich bin nun in den „Genuss“ gekommen einige Filme zu kompriemieren und als DVD zu brennen. Bei einigen der Filme gab es verschiedene Probleme…

Typische Programme wie DVD-Flick oder DeVeDe machen das mit wenigen klicks. DeVeDe nutzt jedoch den verfügbaren Platz weniger als zur Hälfte aus und die Version von ffmpeg DVD-Flick kam mit dem (neuen) Inputformat nicht klar.

So habe ich habe kurzerhand beschlossen, selbst die passende Ziel-Bitrate zu berechnen. Eigentlich eine einfache Aufgabe, die Größe einer DVD ist fest, es sollte eine Tonspur enthalten sein und die Filmdaten nach möglichkeit den ganzen Rest ausfüllen.

Überraschenderweise war jedoch die endgültige Version größer als die DVD und auch größer als die Video- und die Audiodaten zusammen. Das konnte ich natürlich leicht durch ein erneutes Kodieren der Videodaten korrigieren. Den Grund für den zusätzlichen Speicherverbrauch konnte ich jedoch nicht rausfinden.

Ein Blick in den Sourcecode von DVD-Flick 2 (ein Fork des nicht weiter verfolgten Ursprungsprojektes) zeigt jedoch, dass willkürlich 4% zusätzlicher Platz für das Muxen eingeplant wird. Ist zwar in der aktuellen Version auskommentiert, funktioniert aber in der Praxis gut. Damit kommen wohl auch die sehr genauen Videogrößen von DVD-Flick zustande, mit denen etwa 20-30 MiB auf dem Medium freibleiben.

  ' Room for muxing overhead is 4% (which is a lot for a 4.3 Gb DVD)
  discSize = 0.96 * discSize

Die Zielbitrate (inklusive wählbarem Mux-Overhead) kann mit folgendem Skript leicht bestimmt werden:

Bei Unterschieden (wie DVD+R und DVD-R) wird die kleine Größe gewählt.
Angenommen, codierung von 5.1 Sound als AAC mit 448 kbit/s
Zusätzlich eingeplanter Platz für das Muxen.
Falls die Abspielgeschwindigkeit von Quell- und Zielmedium unterschiedlich ist, z. B. 23,976 bei BluRay-Quellen und 25 bei PAL DVDs
Aktualisiert die unten angegebenen Werte basierend auf den Eingaben.

Berechnet unter der Anname von Tonspuren kodiert als AC3 mit 448 Kb/s:

Benötigter Platz für Tonspuren: 555,23 MiB
Verfügbarer Platz für Video: 3748,09 MiB
Maximale Bitrate für Video: 5906,72 Kb/s

Unberücksichtigt bleibt, dass für DVDs die maximale Bitrate 9000 ist.

Geschrieben von Kap. Zuletzt geändert am 19. November 2016.

MySports in Linux

Leider gibt es erstmal keinen Port von MySports auf Linux. Es gibt zwar einen Open-Source-Tool zum Auslesen der Daten, aber zur Benutzung der offiziellen Software bleibt man auf eine Lösung mit VirtualBox (die vermutlich einzige brauchbare Software von Oracle) und Windows angewiesen. Die folgenden Schritte beziehen sich alle auf Ubuntu, sollten jedoch ähnlich auf allen gängigen Distributionen funktionieren.

Um die Uhr über USB anzuschließen und in VirtualBox verfügbar zu machen sind einige Schritte notwendig. Automatisch tut sich da nichts, von wegen universelles Plug & Play und so ;-) Zunächst mal zeigt KDE kein angeschlossenes Gerät beim einstecken an. Es lässt sich aber leicht überprüfen, ob ein gerät eingesteckt ist:

$ lsusb
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 001 Device 002: ID 0424:2514 Standard Microsystems Corp. USB 2.0 Hub
Bus 001 Device 003: ID 1390:7474 TOMTOM B.V. GPS Sport Watch [Runner, Multi-Sport]

Es sieht also schonmal so aus, dass die Uhr vorhanden ist. In VirtualBox kann man in den Eigenschaften einer virtuellen Maschine festlegen, welche der im Host-System vorhandenen Geräte im Gastsystem verfügbar sein sollen. Das Symbol mit dem USB-Stecker und dem grünen + zeigt (eigentlich) die vorhandenen Geräte an. Zunächstmal ist die Liste jedoch leer. Über die Kommandozeile kann man das natürlich auch machen:

$ VBoxManage list usbhost
Host USB Devices:
 
  <no devices>

Diesen Konflikt zwischen den beiden Ausgaben gibt es, weil USB standardmäßig nicht unterstützt wird. Zunächst mal muss das Oracle VM Extension Pack installiert sein, und zwar in der gleichen Version wie VirtualBox. Dies kann man so überprüfen:

$ VBoxManage --version
5.1.2r108956
 
$ VBoxManage list extpacks
Extension Packs: 1
Pack no. 0:   Oracle VM VirtualBox Extension Pack
Version:      5.1.2
Revision:     108956
Edition:      
Description:  USB 2.0 and USB 3.0 Host Controller, Host Webcam, VirtualBox RDP, PXE ROM, Disk Encryption.
VRDE Module:  VBoxVRDP
Usable:       true 
Why unusable:

Die Version (5.1.2) stimmt schonmal überein und USB ist generell verfügbar. Damit die Geräte von VirtualBox erkannt sein, muss der Benutzer jedoch auch Mitglied der Gruppe vboxusers sein:

sudo usermod -a -G vboxusers <useruame>

Damit die Änderungen übernommen werden, muss man sich einmal aus- und wieder einloggen. Nun sind auch die USB-Geräte verfügbar:

$ VBoxManage list usbhost
Host USB Devices:
 
UUID:               05f7f0e1-8d84-4cf7-bd2c-7f11753a02a8
VendorId:           0x1390 (1390)
ProductId:          0x7474 (7474)
Revision:           2.0 (0200)
Port:               1
USB version/speed:  2/Full
Manufacturer:       TomTom
Product:            TomTom GPS Watch
SerialNumber:       HE4045G02754
Address:            sysfs:/sys/devices/pci0000:00/0000:00:1a.7/usb1/1-3/1-3.2//device:/dev/vboxusb/001/004
Current State:      Busy

Bei einem Update der distribution, zum Beispiel von Wily Werewolf auf Xenial Xerus, kann es passieren dass man das Ganze nochmal machen muss oO

Geschrieben von Kap. Zuletzt geändert am 2. August 2016.

Solarisiere dein Leben!

Nein, ich meine keinen neuen digitalen Filter, der die neuesten Instagram-Hipster for Freude jauchzen lässt. Auch nicht die (nicht minder nerdigen, da retro) echte Solarisation, mit der schöne Effekte erzielt werden können.

The Black Sun (1939)

The Black Sun (1939) von Ansel Adams, aus dem Buch Examples: The Making of 40 Photographs. Original in der Sammlung der Yale Art Gallery.

Weitere schöne Beispiele, für den echten Effekt auch in der Serie 1h von Hans-Christian Schink.

Stattdessen geht es um mein aktuelles Lieblings-Farbschema für Programmierung, Solarized von Ethan Schoonover, das vom deutschen KDE-Team passend übersetzt wird ;)

Solarized für Bash

Für die Nutzung in Vim wird pathogen benötigt. Wenn es noch nicht installiert ist, die Schnellanleitung geht wie folgt:

# Verzeichnisse anlegen
mkdir -p ~/.vim/autoload ~/.vim/bundle
# Herunterladen und installieren
curl -LSso ~/.vim/autoload/pathogen.vim https://tpo.pe/pathogen.vim

Um pathogen nutzen zu können, muss es in der ~/.vimrc aktiviert werden:

" Pathogen
execute pathogen#infect()
syntax on
filetype plugin indent on

Nun können neue vim-Pakete einfach in das Verzeichnis geladen werden. Für Solarized geht das wie folgt:

# Wechseln in das (spätestens soeben erzeugte) Verzeichnis
cd ~/.vim/bundle
# Installieren über git-clone
git clone git://github.com/altercation/vim-colors-solarized.git

Modifikation in der .vimrc:

" Solarized
syntax enable
set background=dark
colorscheme solarized

Solarized für NetBeans
Die benötigten Dateien für NetBeans liegen ebenfalls in einem Git-Repository.

mkdir tmp
cd tmp
curl -sOL https://github.com/fentie/netbeans-colors-solarized/archive/master.zip
unzip master.zip
pushd netbeans-colors-solarized-master/
zip -r ../config-nb.zip config/
popd

Das Farbschema kann nun in NetBeans importiert werden. Dazu muss unter Extras | Optionen die Schaltfläche Import... in der unteren linken Ecke gewählt werden. Nachdem die gerade erstellte Datei config-nb.zip kann importiert werden und NetBeans verlangt von selbst einen Neustart.

Das Profil ist automatisch aktiviert, man kann wechseln unter Extras | Optionen | Schriften und Farben als Profil.

Die heruntergeladenen Dateien und das Verzeichnis kann gelöscht werden.

Netbeans mit Solarized-Farbschema

Netbeans mit Solarized-Farbschema

Geschrieben von Kap. Zuletzt geändert am 10. März 2017.

arXiv Terror eingrenzen

Der Upload eines Drafts bei arXiv verursacht einige Schmerzen. Abgesehen davon, dass das System relativ langsam ist, gibt es zwei Hauptprobleme.

  1. Die genutzen Paketversionen sind teilweise sehr alt
  2. Man kann nur Dateien in einem Verzeichnis hochladen und Dateien nur einzeln auswählen.

Darüberhinaus werden automatisch die tex-Sourcen veröffentlicht. Das finde ich sogar gut, aber es erzeugt zumindest bei mir einiges Unwohlsein, weil dadurch auch Kommentare veröffentlicht werden. Und oftmals stehen in Veröffentlichungen noch einige %TODOs oder auskommentierte alte Beweisversuche drin, die man ungern veröffentlichen möchte.

Zur Lösung zumindestens des zweiten Problems habe ich ein kleines Python-Script geschrieben, was das Veröffentlichen einfacher macht. Es löst folgende Aufgaben:

  • Bei angabe eines Wurzeldokumentes werden alle eingebundenen Dokumente in eine Ausgabedatei geschrieben.
  • Jeder Kommentar wird entfernt.

Ausgabe ist dann eine einzelne Datei, die das gesamte Dokument enthält. Zusätzlich mag es natürlich noch weitere Dateien, wie zum Beispiel die Literaturangaben oder das Farbschema für den Ausdruck, geben. Zumindestens die Struktur des Inhalts muss man für die Veröffentlichung nicht mehr bearbeiten, was eine deutliche Erleichterung ist. Selbst bei kurzen Papern kommen leicht einige Dateien zusammen wenn Bilder und Tabellen ausgelagert werden. Bei vernünftiger Sturkturierung landen diese dann auch in entsprechenden Unterverzeichnissen.

Das Tool arxify ist auf GitHub verfügbar.

Geschrieben von Kap. Zuletzt geändert am 30. Juni 2016.