Archiv der Kategorie: Programmierung

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.

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.

MathML mit WordPress

Im Artikel über Matrix-Generierung habe ich zum ersten Mal MathML benutzt. Um zu einer korrekten Darstellung in WordPress zu kommen, musste ich etwas Tricksen. Was genau zu tun ist, beschreibe ich hier.

Das Layout von nerdpause ist bereits in HTML5 geschrieben (erkennbar am als erster Zeile der Ausgabe), so dass Math ML ohne weitere Probleme benutzt werden kann. Sollte das Layout noch in XHTML 1.1 verfasst sein, muss der DocType um die Angabe zu MathML erweitert werden, sie lautet dann .

Wie man MathML-Code schreibt, ist in vielen Artikeln und Blogs beschrieben, zum Beispiel hier von Danijel Gorupec, aber auch der (englische) Wikipedia-Artikel bietet für den Einstieg einige Beispiele. Der Deutsche taugt natürlich mal wieder nichts und verdient im aktuellen Zustand keinen Link.

Die wesentliche Struktur von MathML-Code ist eher langatmig. Der Formel aus dem Satz von Pythagoras,

a2 + b2 = c2, wobei a,b,c

, sieht etwa so aus:

<math>
  <msup>
    <mi>a</mi>
    <mn>2</mn>
  </msup>
  <mo>+</mo>
  <msup>
    <mi>b</mi>
    <mn>2</mn>
  </msup>
  <mo>=</mo>
  <msup>
    <mi>c</mi>
    <mn>2</mn>
  </msup>
  <mtext>, wobei&nbsp;</mtext>
  <mi>a</mi>
  <mo>,</mo>
  <mi>b</mi>
  <mo>,</mo>
  <mi>c</mi>
  <mo>&#x02208;</mo>
  <mi>&#x0211D;</mi>
</math>

Dabei ist vor allem zu beachten, dass der Mathematik-Bereich von <math> umschlossen wird. Das Element math kann entweder inline oder als Block dargestellt werden, was über CSS geregelt werden kann (analog z.B. zu span oder div).

Im Standardverhalten von WordPress ist das Ergebnis jedoch grauenhaft. Es werden zahllose Leerzeilen eingefügt, ein Blick in den Code der übertragenen Seite zeigt viele zusätzliche <p> und <br>-Tags. Das ist ein bekannter Bug, der jedoch schon seit 4 Jahren nicht gefixt wird. Angeblich weil das Einflüsse auf Rückwärtskompatibilität hätte. Dass man bei Verwendung der Auto-Format-Funktion von WordPress auf MathML in der selbst geschriebenen Variante komplett verzichten muss wird dabei nicht berücksichtig.

Wie behebt man das ganze nun? Ganz einfach!

In WordPress gibt es die Funktion wpautop, die bestimmte Formatierungen automatisch durchführt. Eigentlich ganz praktisch, damit kann man Absätze erzeugen, indem man einfach leere Zeilen einfügt, ähnlich wie bei LaTeX. Die Methode fügt die Absätze noch an weiteren Stellen ein, unter anderem auch nach math-Umgebungen. Um das Verhalten zu ändern, muss man einfach die datei wp-includes/formatting.php öffnen und eine Zeile wie folgende suchen:

// Space things out a little
$allblocks = '(?:table|thead|tfoot|caption|col|colgroup|tbody|tr|td|th|div|dl|dd|dt|ul|ol|li|pre|select|option|form|map|area|blockquote|address|style|p|h[1-6]|hr|fieldset|noscript|legend|section|article|aside|hgroup|header|footer|nav|figure|figcaption|details|menu|summary)';

In der Variable allblocks sind alle Bereiche definiert, die als Block dargestellt werden sollen. Man muss dort einfach den Teil |math| löschen, und die Darstellung von MathML klappt problemlos!

Geschrieben von Kap. Zuletzt geändert am 7. Februar 2014.

Zufällige Matrizen generieren

Zum Testen einer Methode zur Matrix-Multiplikation wollte ich gern Matrizen haben, dass das Ergebnis einer Matrixmultiplikation eine ganzzahlige Matrix mit „schönem“ Aussehen ist, so dass die Korrektheit der Implementation leicht überprüft werden kann. Sämtliche Matrizen sollten nach möglichkeit ganzzahlig sein. Um das Ziel zu erreichen habe ich einen Matrix-Generator geschrieben, mit dem ich das vorgestellte Verfahren erleutere. Der Generator benutzt meine simple Implementation einer Matrix-Klasse, die die wichtigsten Methoden bereitstellt.

Zuerst wollte ich eine Einheitsmatrix erzeugen, ich suchte also zwei Matrizen

A

und

B

mit

A×B=E

. Dies würde jede invertierbare Matrix erfüllen. Zusätzlich sollten nun aber

A

und

B

noch ganzzahlig sein. Allgemein ist für eine ganzzahlige Matrix

A

die Inverse

A1

zwar rational, aber nicht ganzzahlig.

Meine Kenntnisse der linearen Algebra waren etwas eingerostet, aber nach kurzer Suche fand ich einen Artikel von Nathan Brixius, der ebenfalls über die Erzeugung spezieller Matrizen schrieb und mir bei der Erinnerung half. Für die Determinanten von Matrizen gilt

det(A) · det(B)=det(AB)

und die Determinante der Einheitsmatrix ist natürlich 1. Außerdem kann man die Determinante von Matrizen in oberer oder unterer Dreiecksform als Produkt der Diagonalen leicht bestimmen.

Wir erzeugen zunächst eine Matrix in unterer Dreiecksform:

double[][] values = new double[dimension][dimension];
for( int i = 0; i < dimension; ++i )
	values[i][i] = 1;
for( int i = 1; i < dimension; ++i )
	for( int j = 0; j < i; ++j )
		values[i][j] = getValue(i, j);
Matrix lowerTriangular = new Matrix( values );

Es wird ein 2-dimensionales Array erzeugt, das die Werte enthält. Die Diagonale wird mit

1

gefüllt und die untere Hälfte mit Werten, die in der Methode getValue erzeugt werden (z.B. zufällig).

Genauso wird eine Matrix in oberer Dreiecksform benötigt:

values = new double[dimension][dimension];
for( int i = 0; i < dimension; ++i )
	values[i][i] = 1;
for( int i = 0; i < dimension-1; ++i )
	for( int j = i+1; j < dimension; ++j )
		values[i][j] = getValue(i, j);
Matrix upperTriangular = new Matrix( values );

Das Prinzip entspricht dem der LU-Zerlegung einer Matrix: Es werden zwei Matrizen L und U in unterer beziehungsweise oberer Dreiecksform erzeugt, so dass die Determinante 1 ist (d.h. die Diagonale ist 1). Die Matrix

M:=L×U

ist ganzzahlig und invertierbar und nach der Bestimmung der Inversen über die Determinante ist die inverse Matrix

A1

ebenfalls ganzzahlig.

Matrix matrix = lowerTriangular.mult( upperTriangular );
Matrix inverse = matrix.invert();

Mögliche Matrizen als Testinstanzen sind damit also

M

und

A1

. Um Abwechslung zu erzeugen kann man nun beliebige Matrizen

F

an

M

von links anmultiplizieren (oder an

A1

von rechts) und erhält als Ergebnis nicht mehr die Einheitsmatrix, sondern

F

:

F×M×M1=F×E=F

.

Als Beispiel erzeugen wir eine Matrix, die natürliche Zahlen von 1 aufsteigend enthält:

values = new double[dimension][dimension];
int c = 1;
for( int i = 0; i < dimension; ++i )
	for( int j = 0; j < dimension; ++j )
		values[i][j] = c++;
Matrix F = new Matrix( values );

Damit kann die Ausgabematrix erstellt werden:

Matrix result = matrix.mult( inverse );

Die beiden Testinstanzen sind dann result und inverse, das Ergebnis der Multiplikation ist

F

. Natürlich kann

F

auch rationale Zahlen enthalten, dann ist natürlich die Eingabematrix auch nicht mehr ganzzahlig.

Geschrieben von Kap. Zuletzt geändert am 11. Januar 2014.

OMG, they have a time machine!

Heute wollte ich euch Vim Habits 2.0 vorstellen, ein Tech Talk, den Bram Moolenaar vor einigen Jahren gegeben hat. Er präsentiert dort einige Tricks, die das Leben mit Vim einfacher machen. Das wichtigste dabei ist, dass man neue Tricks regelmäßig Anwenden muss, damit man wirklich effektiver wird, daher auch der Titel.

Brams Webseite ist übrigens der Wahnsinn. Die ist sowas von 90er! Der totale Web-Flashback… es gibt sogar einen Webring. (Man beachte, dass Webringe, quasi zeitgleich mit dem Internet geboren, seit der Übernahme durch Yahoo! gestorben sind und nur noch eine Existenz als Zombi führen.)

Auf Brams Webseite gibt es auch eine DivX-Version des Videos zum runterladen.

Geschrieben von Kap. Zuletzt geändert am 17. Juni 2013.

Buck – Das neue Build-Tool von Facebook

Facebook hat sein Build-Tool Buck als Open Source veröffentlicht. Das Tool hat gewisse Ähnlichkeiten mit dem bei Google verwendeten Cloud-Basierten Buildsystem. Während es bei Buck keine Cloud mit verteiltem Dateisesystem gibt, sind die ähnlichkeiten doch groß. Die Konfigurationsdateien heißen bei Google BUILD, während sie bei Facebook BUCK heißen, die Syntax ist aber identisch. Auch bei den Features sind die Tools ähnlich, nur dass Buck halt auf meinem kleinen Rechner zu Hause laufen kann.

Ich habe das Tool mal ausprobiert und beschreibe hier meine Erlebnisse. Ausgehend von einem neuen Benutzer auf GitHub, auf einem System auf dem ich kein Root-Zugang habe und der Java-Compiler veraltet ist, sind einige Härtefälle enthalten ;)

Auf der Installationsseite von Facebook sind die drei Schritte, die benötigt werden, angegeben:

git clone git@github.com:facebook/buck.git
cd buck
ant
sudo ln-s ${PWD}/bin/buck /usr/bin/buck$

Wenn ihr Root-Zugang zu eurem System habt und die benötigte Software auf dem neuesten Stand ist, müsst ihr erstmal nicht weiterlesen ;)

GitHub-Account erstellen

weiter zum Installieren

Zunächst benötigt man einen GitHub-Account und ssh-Schlüssel, wie hier beschrieben.

Falls schon ein ssh-Schlüssel erstellt worden ist, liegt er in ~/.ssh/id_rsa.pub. Falls die datei nicht vorhanden ist, muss ein Schlüssel erstellt werden:

ssh-keygen -t rsa -C "mail@gmail.com"

Wenn man einfach Enter drückt, landet der Schlüssel im obigen Verzeichnis, man kann das hier aber ändern. Zum entschlüsseln des ssh-Schlüssels wird ein Passwort benötigt. Es gelten wie immer die gleichen Sicherheitsregeln.

Anschließend wird der Speicherort des Schlüssels und der Fingerprint angezeigt.

Den exakten Inhalt der Datei ~/.ssh/id_rsa.pub, die den öffentlichen Schlüssel enthält muss gleich bei GitHub eingegeben werden.

Erstellt einen (kostenlosen) Account bei GitHub und loggt euch ein. Wenn ihr einen Gravatar-Account habt, ist euer Avatar auch bereits eingestellt ;)

Klickt nun auf Account Settings (oben rechts, neben dem Ausgang) und dann im Menü links auf SSH Keys. Klickt auf Add SSH Key und gebt den Inhalt der Datei mit dem öffentlichen Schlüssel ein. Am Besten per Copy & Paste ^^

Zurück an der Kommandozeile könnt ihr testen, ob alles soweit gefunzt hat:

ssh -T git@github.com

Der Schlüssel von GitHub ist noch unbekannt, ihr müsst ihn nun verifizieren. Der Fingerprint ist 16:27:ac:a5:76:28:2d:36:63:1b:56:4d:eb:df:a6:48. Falls ihr keine Lust auf den Test habt, kommt die Abfrage des Keys gleich beim Holen der Buck-Daten aus dem Repository.

Buck installieren

weiter zum Einbinden

Nun können wir nochmal versuchen, den Buck-Quellcode runterzuladen. Wir können das in einem Verzeichnis unserer Wahl machen (ich wähle das Verzeichnis /local/programs als Basis:

cd /local/programs
git clone git@github.com:facebook/buck.git
cd buck
ant

Zumindest die ersten drei Schritte sollten nun ohne Probleme funktionieren.

Falls eure Java-Installation up-to-date ist, klappt alles, ansonsten gibt ant eine Fehlermeldung aus.

Es kann verschiedene Fehlermeldungen geben, je nach aktueller Java-Version. Eine Möglichkeit ist Unrecognized option: -Werror, die von einem veralteten javac ausgegeben wird.

Java 1.5 genügt nicht, ich hab das Oracle JDK 1.7 genutzt. Wie es mit 1.6 aussieht, weiß ich nicht. Das JDK müsst ihr irgendwo installieren und den Pfad in der Umgebungsvariable JAVA_HOME setzen, dann wird die neue Version automatisch von ant benutzt:

export JAVA_HOME=/local/programs/jdk/

Ein neuer Versuch, buck zu kompilieren sollte nun erfolgreich sein.

Buck im System einbinden

Wenn man Root-Zugriff hat, kann man nun einfach einen symbolischen Link auf buck anlegen:

sudo ln -s /local/programs/buck/bin/buck /usr/bin/buck

Ohne Root-Zugriff kann man zum Beispiel den Pfad erweitern:

export PATH=$PATH:/local/programs/buck/bin

Die Zeile kann man bei Bedarf in die .bashrc einfügen, so dass buck bei jedem Systemstart verfügbar ist.

Nun sollte Buck erfolgreich eingerichtet sein und funktionieren :) Ein erstes Beispiel (zur Android-Programmierung) gibts bei Facebook. Sobald ich es für Java ausprobiert habe, werde ich hier einen weiteren Beitrag dazu schreiben.

Geschrieben von Kap. Zuletzt geändert am 6. Mai 2013.

Lustiger Android

Heute habe ich angefangen, mich mit CSS3 zu beschäftigen und dabei gerlernt, wie man einen kleinen Android designt. Er scheint recht gut drauf zu sein und man kann ihn sogar kitzeln ;)

Sollte in allen aktuellen Versionen der verbreiteten Browser funktionieren.

Selber ausprobieren

Im Folgenden beschreibe ich, wie ihr selbst einen Android bauen könnt. Es ist nicht sehr schwer :)

Bevor wir anfangen, müssen wir aber erst noch die Android-Farbe raussuchen: #A4C739

Zunächst wollen wir einen Android bauen, der nicht animiert ist. Wir nehmen dazu an, dass der Android in einem festgelegten Bereich mit absoluten Koordinaten positioniert wird.

Als Basis dient uns das Folgende:

.droid {
  position: absolute;
  bottom: 30px;
  right: 60px;
  height: 60px;
  width: 65px;
}

Nun folgt der Android:

.droid .torso {
  position: absolute;
  background:  #A4C739;
  width: 65px;
  height: 60px;
  border-radius: 0px 0px 10px 10px;
}
 
.droid .head {
  position: absolute;
  top: -32px;
  background:  #A4C739;
  width: 65px;
  height: 30px;
  border-radius: 65px 65px 0% 0%;
}
 
.droid .head .eye {
  height: 5px;
  width: 5px;
  border-radius: 5px;
  background: #333;
  position: absolute;
  top: 12px;
}
 
.droid .head .eye:nth-child(1) {
  left: 20px;
}
 
.droid .head .eye:nth-child(2) {
  right: 20px;
}
 
.droid .head .ear {
  height: 15px;
  width: 3px;
  border-radius: 15px;
  background: #A5C63B;
  position: absolute;
  top: -10px;
}
 
.droid .head .ear:nth-child(3) {
  left: 15px;
  transform: rotate(-30deg);
  -webkit-transform: rotate(-30deg);
  -moz-transform: rotate(-30deg);
  -o-transform: rotate(-30deg);
}
 
.droid .head .ear:nth-child(4) {
  right: 15px;
  transform: rotate(30deg);
  -moz-transform: rotate(30deg);
  -webkit-transform: rotate(30deg);
  -o-transform: rotate(30deg);
}
 
.droid .leg {
  position: absolute;
  bottom: -27px;
  background:  #A5C63B;
  width: 15px;
  height: 27px;
  border-radius: 0px 0px 30px 30px;
}
 
.droid .leg:nth-child(3) {
  left: 12px;
}
 
.droid .leg:nth-child(4) {
  right: 12px;
}
 
.droid .arm1,
.droid .arm2 {
  left:68px;
  top:-3px;
  width: 15px;
  height: 40px;
  background: #A5C63B;
  position: absolute;
  border-radius: 25px;
}
 
.droid .arm1 {
  left:-18px;
  transform-origin: 54% 18%;
  -webkit-transform-origin: 54% 18%;
  -moz-transform-origin: 54% 18%;
  -o-transform-origin: 54% 18%;
}
Geschrieben von Kap. Zuletzt geändert am 20. November 2013.

SVN-Revisionen mit NetBeans automatisch einfügen

Insbesondere in OpenSource-Projekten, bei denen Benutzer verschiedene Versionen der Software haben können, kann es zu Debugging-Zwecken sehr interessant sein, die SVN-Version einfach lesbasr zu machen.

Ich beschreibe hier eine Variante unter Windows mit TortoiseSVN und NetBeans.

SVN bietet die Möglichkeit, bestimmte Strings durch die Versionsnummer einer einzelnen Datei ersetzen zu lassen. Schreibt man in eine Datei den String $Rev:$, wird von SVN der Text automatisch durch die aktuelle Revision der Datei ersetzt, also zum Beispiel zu $Rev: 2658 $. Man muss dazu für die ausgewählte Datei ein Schlüsselwort aktualisieren. Bei Tortoise muss im Kontextmenü der Datei der Menüeintrag „TortoiseSVN | Properties“ ausgewählt werden und im sich öffnenden Fenster „New | Keywords“. Von den möglichen Keywords muss „Revision“ ausgewählt werden.

Durch diese Einstellung kann für jede Datei die Version der Datei gespeichert werden. Nun mag es aber auch interessant sein, die aktuellste Version zu haben. Tortoise bietet dazu das Tool subwcrev an. Es kann eine Template-Datei lesen und in dieser Datei sämtliche Vorkommen von $WCREV$ durch die maximale SVN-Revision aller Dateien im Repository zu ersetzen. Bei einer standardmäßigen Installation ist das Tool im Windows-Pfad enthalten und kann direkt aufgerufen werden. Ansonsten ist es unter /bin im Tortoise-Verzeichnis zu finden.

Wir gehen davon aus, dass wir eine Datei version.tmpl haben, in der nur $WCREV$ steht. Wir wollen eine Datei version.txt erstellen, in der die Versionsnummer steht. Der der Aufruf auf Befehlszeile lautet subwcrev . version.tmpl version.txt. Die Ausgabe enthält noch weitere Informationen und sieht zum Beispiel so aus
SubWCRev: 'D:DokumenteProgrammeTool'
Last committed at revision 2657
Mixed revision range 2655:2657
Local modifications found

Damit dieser Befehl nicht jedes mal manuell aufgerufen werden muss, kann man ihn in das NetBeans-Build-Script eingefügt werden. Dazu wird die Datei build.xml bearbeitet. Direkt nach <import file="nbproject/build-impl.xml"/>

fügen wir das Folgende hinzu:

<target name="-pre-compile">
<exec executable="subwcrev" output="svn-revision.log">
<arg line=" . version.tmpl version.txt">
<exec>
<target>

Damit teilen wir der Entwicklungsumgebung mit, dass vor dem Kompilieren das subwcrev-Tool ausgeführt werden soll, welche Parameter übergeben werden wollen und dass die Ausgabe in der datei svn-revision.log gespeichert werden soll. Falls etwas falsch angegeben worden ist, werden die Fehlermeldungen ebenfalls in diese Datei geschrieben.

Nun noch ein Beispiel, wie im Programm auf die Versionsinfos zugegriffen werden kann. Ich habe einen doppelten Ansatz gewählt: es wird versucht, den Text der Datei version.txt einzulesen. Falls dabei etwas schiefgeht, wird die lokale SVN-Revsionsnummer genommen.

/** SVN version */
public final static String revision = getVersion();
 
/**
* Reads the svn revision from a file with name 'version.txt'. If an exception
* occurs, the revision of this source code file is returned. WARNING: no error
* checks are performed!
*/
private static String getVersion() {
  try {
    return new String( Files.readAllBytes( Paths.get( "./version.txt" ) ) );
  } catch( IOException ex ) {
    return "> $Rev: 2658 $"; // return emergency value
  }
}

Das war’s auch schon. Nun kann man im Programm auf die aktuelle Revisionsnummer zugreifen. Die Textdatei wird bei jeder Ausführung von Clean & Build ausgefüht.

Alternativ kann man natürlich auch eine Java-Klasse als Template erzeugen und somit auf das Einlesen verzichten. In dem Fall bietet es sich an, eine eigene Klasse nur für den Versionstext zu entwickeln, da sonst immer das Template verändert werden muss, nicht die „richtige“ Quelldatei.

Geschrieben von Kap. Zuletzt geändert am 18. März 2013.