Tag Archives: Programmierung

Hierarchische Package-Darstellung in Eclipse

Nachdem mir heute wieder ein “Wie machst Du das eigentlich?” begegnet ist, bringe ich als Abwechslung zu ewig langen Text-Einträgen mal ein kurzes Bunte-Bildchen-Howto:

Viele Eclipse-Nutzer sehen in der Java-Perspektive ihre Package-Struktur so:

Package-Explorer - flache Darstellung

Der Nachteil dieser Darstellung ist, dass sich die Baumstruktur der Packages nur schwer nachvollziehen lässt. Die Darstellung ist flach und genauso heisst sie auch: Flat Package Presentation.

Viel günstiger ist aber meist die Hierarchical Package Presentation, bei der Packets wieder in einer Baumstruktur dargestellt werden:

Package Explorer - hierarchische Darstellung

Erreicht wird dies, indem man in der rechten oberen Ecke des Package Explorers das Menü öffnet und die Option Package Presentation von Flat auf Hierarchical umstellt:

Package Explorer - Menü

Dort befinden sich auch einige andere nützliche – oder vielleicht auch nervige – Optionen der Package-Darstellung, die sich je nach Belieben aktivieren oder deaktivieren lassen.

Flexibles Issue Tracking mit roundup

Fuer den Einsatz in der Firma suche ich derzeit ein Bug- und Issue-Tracking-System. Nicht ausschliesslich fuer unsere Engineeringabteilung, sondern auch fuer die Jungs vom Service, die die Hilfeschreie entgegennehmen, wenn der Kunde (fliegendes Personal, und damit extrem ungeduldig) ausnahmsweise mal nicht von der Runway wegkommt.

Eins ist klar: Es muss Open-Source sein. Zum einen will ich nicht erst eine ellenlange Begruendung fuer die Finanzbuchhaltung schreiben, warum sie bitte schoen n+1 Euro fuer eine Software ausgeben sollen, deren Nutzen fuer die Firma sie ohnehin (wieder mal) nicht korrekt quantifizieren koennen. Zum anderen will ich nicht erst mit m+1 Vertrieblern von irgendwelchen Softwarebuden quatschen, die mir ihre “Marktfuehrer”-Loesung aufschwatzen wollen. Aber noch viel wichtiger: Ich will schnell mal eben was aendern koennen, wenn das Tagesgeschaeft es notwendig macht!

Also dann, Wikipedia ist mein Freund, und auf in die taktische Aufklaerung auf dem Softwarefeld: http://en.wikipedia.org/wiki/Comparison_of_issue_tracking_systems listet einen ganzen Wald von Optionen auf. Neben dem eierlegenden Wollmilchborstenviehmoloch “Bugzilla” existieren viele nette kleinere Systeme, die zwar nicht so dick auftragen, die dafuer aber umso schneller und wartbarer sind und fuer deren man Evaluierung man nicht erst im RDBMS herumfuhrwerken muss (bravo!). Web- und Email-Frontends sind anscheinend per stiller Konvention ohnehin ueberall dabei (wobei ich das Email-Frontend derzeit ueberhaupt nicht brauch’).

Besonderen Gefallen habe ich an Roundup gefunden, der ist nicht nur sehr flink, sondern vor allem sehr vielseitig. Eine der Uebersetzungen von Roundup aus dem Englischen ist “Razzia”, und dem Namen macht das kleine Softwarepaket alle Ehre: Neben PostgreSQL und MySQL kann Roundup auch mit sqlite umgehen, das macht das Testen sehr bequem; es bringt seinen eigenen Webserver mit, fuehlt sich aber im mod_python-erweiterten Apache2 genauso daheim; es laesst sich als Bugtracker, Trouble-Ticket-System, ToDo-Liste, persoenliche Zeiterfassung und sogar als Kaffeemaschine konfigurieren. Okay, die Kaffeemaschine ist jetzt gelogen, aber ich wette, lange dauert’s nicht mehr, dann gibt’s auch das! Nettes Feature: Pro Eintrag in die Issue Liste wird eine kleine Mailingliste angelegt, so dass alle Beteiligten/Interessenten ohne viel Aufwand verfolgen koennen, wie sich ein Problem seiner Loesung naehert.

Am besten gefaellt mir bei der Arbeit mit Roundup die Dokumentation, die mit Beispielen nicht geizt, wie man unkompliziert Erweiterungen am Datenbankschema und an den Eingabemasken und Ansichten vornehmen kann: http://roundup.sourceforge.net/doc-1.0/customizing.html. Die Beispiele wirken allesamt wie direkt aus der Praxis entnommen und geben selbst einem Python-Laien wie mir in kuerzester Zeit das Gefuehl, die Dinge wirklich in der Hand zu haben. Innerhalb eines Tages ist es mir gelungen, einen Protoypen zu basteln, in den wir exemplarisch mal ein paar der Bugs der letzten Wochen eingetragen haben. Der Tag Arbeit schliesst eine Customization der CSS-Stylesheets auf unsere Firmen-CI genauso mit ein, wie das Erstellen von automatisierten Reports ueber den Lebenszyklus von Kundenanfragen und Fehlermeldungen fuer die Geschaeftsleitung. Und demnaechst wird auch die Serviceabteilung angebunden, kann ja nicht laenger als einen Tag dauern. ;-)

Fazit: Ich frage mich, warum ich mir ueberhaupt andere Systeme angeschaut und nicht stattdessen gleich Roundup genommen habe. Hier finde ich alles, was ich brauche, um meinen Job zu erledigen, ohne viel Zeit von den Hauptaufgaben abzuzwacken. Ich wuenschte, es waer immer so einfach! Und ich komme von meinem Vorurteilen ueber Python weg, der Produktivitaetsgewinn macht die infantile Syntax locker wieder wett. ;-)

Smilies für Foren auf eigenem Webspace

Internetforen gibt es wie Sand am Meer und es gibt ebenso viele Seiten, wo man Smilies finden kann, die man über die Forencodes oder HTML einbinden kann. Diese Seiten tauchen auf und verschwinden wieder, einige fordern sogar direkt dazu auf, die Smilies runterzuladen und auf den eigenen Webspace zu packen. Das ist nicht weiter schlimm, aber da liegen sie nun in den Untiefen in irgendeinem Unterordner der eigenen Domain. Will man einen Smiley verwenden, wühlt man sich lange durch Verzeichnisse und schreibt die URL des Bildchens zusammen mit den Forencodes mühsam von Hand zusammen.

Genauso ging es mir und daher hab ich mir ein Skript in PHP gebastelt, das mir nicht nur alle Smilies, die ich gesammelt habe, übersichtlich anzeigt, sondern auch gleich noch den Forencode mit der passenden URL dazu. Der brauch nur noch kopiert werden und schon hat man den eigenen besonders witzigen Smiley im Internetforum seiner Wahl eingefügt. Folgendes habe ich in ein Grundgerüst einer HTML-Seite eingefügt. Ich hab das einfach mal ein wenig getrennt hier, damit es sich leichter kommentieren lässt, später einfach wieder zusammenfügen…

<?php
$extcounter = 0;
function fileextension($filename)
{
    $pospunkt = strrpos($filename,".");
    return substr($filename, $pospunkt+1,
        strlen($filename) - $pospunkt);
}

function isimagefile($filename) {
    $extension = fileextension($filename);
    if( ($extension == "gif") OR
        ($extension == "jpg") OR
        ($extension == "jpeg") OR
        ($extension == "png") ) {
        return true;
    }
    else {
        return false;
    }
}

In den beiden Funktionen passiert erstmal nichts spannendes. Die erste gibt von einem Dateinamen die Erweiterung, also den Teil nach dem letzten Punkt zurück. Die zweite Funktion bekommt so ein Ergebnis vorgesetzt und gibt wahr oder falsch zurück, je nachdem ob es die Erweiterung einer Bilddatei ist oder nicht.

function echodir($path = ".")
{
    $counter = 1;
    global $extcounter;
    $dir = dir($path);
    while(false !== ($file = $dir->read())) {
        if(("." == $file) OR (".." == $file))
            continue;
        if(is_dir($path."/".$file)) {
            echo "<h2>$file</h2>n";
            echo "<p>n";
            echo "<table>n";
            echodir($path."/".$file);
            echo "</table>n";
            echo "</p>n";
        }
        else {
            if(isimagefile($file)) {
                if($counter%2) {
                    echo "<tr>n";
                }
                echo "<td><img src="".$path."/".$file.""/></td>";
                echo "<td>[img]http://www.lespocky.de/smilies/" .
                    substr($path,2,strlen($path)-2) .
                    "/".$file."[/img]</td>n";
                if(($counter+1)%2) {
                    echo "</tr>n";
                }
                $counter++;
                $extcounter++;
            }
        }
    }
    $dir->close();
}

Hier passiert das spannende. Vorweg sei gesagt, wie die Dateien organisiert sind. In dem Ordner, wo das Skript liegt, befinden sich keine Grafikdateien, sondern nur Ordner. In diesen Ordnern liegen dann direkt die Smilies. Tiefere Ordnerebenen gibt es nicht.

echodir() ist eine rekursiv aufgerufene Funktion. Wird kein Argument übergeben, so ist das aktuelle Verzeichnis zu durchsuchen. Da wird dann in der while-Schleife jeder Eintrag durchgegangen. Bei “.” und “..” passiert nix weiter, es geht zum nächsten Schleifendurchlauf. Dann passiert eine Unterscheidung, ob der Eintrag eine Datei oder ein weiteres Verzeichnis ist. Bei einem Verzeichnis wird eine neue Überschrift geschrieben und eine Tabelle begonnen. Die Smilies sollen in zwei Spalten angezeigt werden, damit nicht so viel Platz verschwendet wird. Nach Beginn der Tabelle, wird echodir selbst rekursiv aufgerufen.

In diesem Aufruf wird die Funktion wegen der oben erwähnten Organisation der Dateien, dann auch Dateien finden und diese dann zweispaltig eintragen. Um die Spalten zu erkennen und an den korrekten Stellen die tr-Tags zu öffnen und zu schließen, werden die Smilies in $counter mitgezählt und über den Modulo-Operator jeweils in linke oder rechte Spalte geschrieben. Ausgegeben wird nicht nur der Smilie selbst zum Angucken, sondern auch das fertige Foren-Tag zum Markieren und Kopieren.

Irgendwann gibt es dann keine Verzeichnisse und Dateien mehr zum lesen, alles Smilies sind ausgegeben und … ach ja, die Funktion ist ja erst definiert und erklärt, aufgerufen muss sie noch werden:

echodir();

echo "<hr /><p>Das waren ".$extcounter." Smilies..</p>n";

?>

Die letzte Zeile ist noch ein bisschen Spielerei als Abschluss. Da die ganze Auflistung von dem PHP-Skript übernommen werden, brauchen neue Smilies nur auf den Webspace kopiert werden, fertig.

happy

Kleiner Passwortgenerator in Perl

Aus der Reihe »Schnelles Kamel-Gehacktes« heute der Beitrag, wie man quick’n’dirty einen Passwortgenerator in Perl schreibt. Anforderungen vorher: 8 Zeichen, weil viele Linuxe sowieso dahinter abhacken; nur Zeichen, die in den ersten 7 Bit der ASCII-Tabelle stehen und dann auch nur welche, die man direkt oder mit Umschalttaste (Shift) eingeben kann, nichts wozu man AltGr oder ähnliches bräuchte. Dazu braucht man eine ASCII-Tabelle und dann geht’s los:

#!/usr/bin/perl -w
# $Id: gen_passwd.pl 111 2008-02-06 13:45:24Z alex $
use strict;

my @allowed_chars;
# ASCII von 0x21 bis 0x3f
# das sind die meisten Sonderzeichen und die Ziffern
for (my $i=0x21; $i<=0x3f; $i++) {
	push @allowed_chars, chr($i);
}

# ASCII von A bis Z
for (my $i=0x41; $i<=0x5a; $i++) {
	push @allowed_chars, chr($i);
}

# ASCII von a bis z
for (my $i=0x61; $i<=0x7a; $i++) {
	push @allowed_chars, chr($i);
}

push @allowed_chars, chr(0x5f); # '_'

my $char_count = scalar @allowed_chars;

for (my $i=0; $i<8; $i++) {
	print $allowed_chars[int rand $char_count];
}

print "\n";

Diese Passwörter eignen sich gut als initiale Passwörter für neue Nutzer. Die Nutzer sollten sodann aufgefordert werden, sich mit passwd ein neues zu setzen. Da so ein zufälliges Passwort mit Zahlen und Sonderzeichen sehr schwer zu merken ist, werden sie dieser Aufforderung sicher nachkommen.

Binary H(e)art

binary heart Heute schrieb die ettercat einen Link auf nebenstehenden Comic von xkcd.com ins IRC. Die Seite hat mich schon des öfteren mit wirklich lustigen Comics begeistert, zumal einige nur mit entsprechendem Geek-Hintergrundwissen wirklich lustig sind. Nummer 99 – »binary heart« – trifft vom Untertitel der Seite (»A webcomic of romance,
sarcasm, math, and language.«) klar den romantischen Teil. Aber ganz ehrlich, seid Ihr nicht auch total neugierig, ob sich hinter den Nullen und Einsen im Bild nicht noch eine zusätzliche Botschaft verbirgt? Ich war es jedenfalls und da nur selbst dekodieren schlau macht, hab ich frei nach dem Perl-Motto »Es gibt mehr als einen Weg, etwas zu tun« die Zeichen einzeln abgetippt und ein kleines Skript geschrieben.

Hart (siehe Titel ;-)) war da dran einerseits das Abtippen vom Comic – man verrutscht schon sehr leicht in Zeile und Spalte – und andererseits um Mitternacht die eingerosteten Perl-Kenntnisse zu reaktivieren. Wer sich gern selbst an einem Progrämmchen in beliebiger Sprache probieren will, kann sich die binär codierte Nachricht runterladen, die Textdatei, wo ich mal die Einsen und Nullen abgetippt habe.

Ach und für die ganz Neugierigen oder zur Kontrolle des eigenen Programms hier noch die Auflösung:

iloveyOuilOveyouiloveyOuilOveyOuiloveyouilOveyouilOveyOuilOv

Fangen und Werfen

Als heute im Büro zwischenzeitlich der Subversion-Server nicht erreichbar war, so dass ich meinen Commit nicht machen konnte, unternahm ich einen Spaziergang im Haus zum verantwortlichen Admin. Der war zwar nicht da, aber im gleichen Büro unterhielt ich mich dann mit einem großen Fan von Python. Ich habe dann mal bei Wikipedia nachgelesen und bin über folgenden Satz gestolpert:

Python unterstützt (und nutzt ausgiebig) die Ausnahmebehandlung (engl. exception handling) als ein Mittel, um Fehlerbedingungen zu testen. Dies ist so weit in Python integriert, dass es sogar möglich ist, Syntaxfehler abzufangen und zur Laufzeit zu behandeln.

Das fand ich schon ziemlich krass. Das Programm kann also stellenweise syntaktisch fehlerhaft geschrieben sein, der Compiler meckert nicht und ich kann das selbst abfangen – coole Sache. Weil ich das ganze sowieso noch für die Arbeit mit .NET und C# brauche und mich das auch für den Perl-Parser für IMPULS interessiert, habe ich mich dann mal ganz allgemein mit Exceptions beschäftigt. Richtig schmunzeln musste ich als alter Handballer über die verwendeten Begriffe. Die Exception wird geworfen und irgendwo sitzt ein Catch-Block, der die irgendwann auffängt. Bildlich vorgestellt kann ich da beim Schreiben dieses Satzes gerade immernoch lachen. happy

Meine Glaskoogle hat mir dann für Exceptionhandling mit Perl die Seite Object Oriented Exception Handling in Perl ausgespuckt, wo das alles schön erklärt ist. Jetzt ratet doch mal, was bei der Ausführung des folgenden leicht abgewandelten Beispiels von jener Seite passiert:

#/usr/bin/perl -w
use Error qw(:try);
try {
	some code;
	code that might throw an exception;
	more code;
	return;
}
catch Error with {
	my $ex = shift;	# Get hold of the exception object
	print "handle the exception\n";
}
finally {
	print "do some more cleanup\n";
};	# < -- Remember the semicolon

lol2

MinusPiPiTransform

Da wird sich doch der eine oder andere fragen, was diese seltsame Überschrift zu bedeuten hat. *gg* Also heute in diesem Kino nicht etwa das Wasserlassen von Kleinkindern sondern:
Wie transformiere ich Winkel in das Intervall [−π, π]?

Das Problem stellte sich mir vor einigen Wochen im Rahmen meiner Studienarbeit das erste mal. Ich hatte zunächst einen Algorithmus entwickelt, der sich in einer Schleife so lange dem Zielintervall näherte, bis der Winkel transformiert war. Das ist zuverlässig, leicht zu durchschauen und langweilig. Meine Idee für eine elegante einzeilige Lösung war ein wenig mit der Signum-Funktion rumzuspielen und durch geschicktes Anwenden von Runden und aller vier Grundrechenarten die Geschichte mit der Schleife zu umgehen.

Im Prinzip gehe ich dabei ähnlich vor wie im Schleifenalgorithmus: ich addiere oder subtrahiere solange Vielfache von 2π bis ich im Zielintervall bin. Will ich das in einer Zeile tun, muss ich das notwendige Vielfache rausbekommen und das Vorzeichen.

Stellt man sich den allseits beliebten Zahlenstrahl vor – vorstellen mit Zettel und Stift ist leichter ;-) – erkennt man die Zuordnung:

  • [−5π, −3π] : 2
  • [−3π, −π] : 1
  • [−π, π] : 0
  • [π, 3π] : −1
  • [3π, 5π] : −2

Das Intervall [−π, π] um 0 rum stört. Das erste was ich deshalb tue: ich addiere sign(inAngle)*π zu meinem Einganswinkel inAngel. Dadurch schaffe ich mir zwar einen toten Bereich um 0 rum, aber die neuen Abschnitte haben ihre Grenzen bei vollen Vielfachen von 2π, so dass ich nun durch 2π teilen kann. Das Ergebnis runde ich derart, dass ich auf die nächste volle Zahl in Richtung 0 runde, d.h. ich runde bei positiven Zahlen ab und bei negativen auf oder kurz gesagt: ich schneide einfach die Nachkommastellen des Divisionsergebnisses ab. ;-) Damit habe ich schon die gesuchten Koeffizienten mit richtigem Vorzeichen. Die multipliziere ich dann wieder mit 2π und das Ergebnis ziehe ich vom Eingangswinkel ab, fertig. In Simulink sieht das dann aus wie auf dem folgenden Bild (zum Vergrößern anklicken):

Transformation von minus PI bis PI in Simulink

In Matlab liest sich das wie folgt:

function outAngle = MinusPiPiTransform(inAngle)
    outAngle = inAngle - ...
        fix( (inAngle + sign(inAngle)*pi) / (2*pi) ) * ...
        2*pi;
end%function

Diese Lösung hatte ich wie gesagt vor ein paar Wochen entwickelt. Heute brauchte ich das ganze wieder, allerdings in C# – kein Problem. Einfach den Teil aus dem Matlab-Skript in C# übersetzt und dann sieht das ganze so aus:

public double MinusPiPiTransform(double inAngle) {
    return inAngle -
        Math.Truncate((inAngle + Math.Sign(inAngle) * Math.PI) / (2 * Math.PI)) *
        2 * Math.PI;
}

PIM-Synchronisation: Es könnte so einfach sein…

Für ein Projekt, über das ich später umfangreicher berichten werde, habe ich die Standards für das Speichern und Austauschen von Kalender- und Adressbuchinformationen recherchiert.

Dabei habe ich ohne viel Mühe Standards für folgende Aufgabenstellungen gefunden:

  • Ablegen beliebiger Objekte in zentralen Speichern, z.B. IMAP und LDAP
  • Darstellen von Visitenkarten (vCard)
  • Darstellen von Kalendereinträgen, TODOs, Journals und Austausch von Verfügbarkeitsinformationen (iCalendar)
  • Austausch von Kalenderinformationen (iTIP, iMIP)

Außerdem ein RFC, das sich mit dem Zusammenspiel dieser Protokolle beschäftigt.

Meine Fragen:

  • Warum ist es trotzdem nicht möglich, die PIM-Daten auf Handy, PDA und PC miteinander abzugleichen, einfach mal einen Termin zu verschicken oder die Aushandlung eines Termins meiner Kalenderapplikation zu überlassen?
  • Warum gibt es proprietäre Formate zum Austausch dieser Informationen?
  • Ist die Welt nicht schon kompliziert genug?

Wer Antworten hat, ist herzlich eingeladen, einen Kommentar abzugeben.

Subversion Keywords und Doxygen

Gestern habe ich den Arbeitstag damit verbracht, mir selbst Doxygen näher zu bringen und mein Projekt mit den entsprechenden Kommentaren zu versehen. Laut interner Konvention gehört hier an den Anfang jeder Datei ein für Doxygen formatierter Kommentarblock mit Standardinformationen, wo unter anderem auch spezielle Tags drin stehen, die Subversion beim Commit/Update automatisch aktualisiert. Der dafür relevante Teil sieht jetzt (fast) so aus:

/**
 * \$Revision: 19 $\n
 * \$LastChangedBy: dahl $\n
 * \$LastChangedDate: 2007-08-16 11:04:15 +0200 (Thu, 16 Aug 2007) $\n
 */

Der Grund für diesen Blog-Eintrag ist die Tatsache, dass man das erste Dollarzeichen escapen muss, um in der von Doxygen erzeugten Doku auch tatsächlich diese Tags wiederzufinden. Der Grund dafür wiederum liegt darin, dass Doxygen normalerweise Umgebungsvariablen, die mit dem Dollarzeichen beginnen, expandiert. Das kann man mit gutem Willen aus der Doku zu Doxygen raus lesen. Am Ende der Zeile hab ich dann noch jeweils einen Umbruch gesetzt, damit nicht alle Tags in einer Zeile der Doku landen.

Ein kleiner Schönheitsfehler besteht dabei noch: die Einträge landen genau so, nämlich mit Dollarzeichen und Bezeichner in der Doku. Das Problem hat man bei anderen Projekten auch, die was mit den Tags von Subversion anfangen. Um das noch schicker zu machen, müsste man noch einen Filter für Doxygen schreiben. Wenn da jemand was passendes kennt, bitte mal bei mir melden! ;-)

Update: Mit doxygen 1.6.2 unter WindowsXP und C-Quellcode tritt das Problem nicht mehr auf. Man muss hier nicht mehr die Dollar-Zeichen escapen und doxygen filtert das selbst sauber raus und zeigt es schick formatiert an.

Einmal Tester? Immer Tester!

Wie der eine oder andere vielleicht schon mitbekommen hat, läuft auf meinem Heimserver Eisfair. Angefangen hat das ganze irgendwann 2003 als ich auch noch Fli4l benutzt und plötzlich genug Teile für einen zusätzlichen Rechner übrig hatte. Mit der Zeit stellte sich heraus, dass mir gewisse Software fehlten und ich begann 2004 eigene Pakete für Eisfair zu basteln. Da ich auch in den entsprechenden Newsgroups regelmäßig schreibe, wurde ich 2005 gefragt, ob ich dem Testteam beitreten möchte. Dort werden in einem kleinen Kreis Pakete vorab getestet, bevor sie auf die Öffentlichkeit losgelassen werden. Mit der Zeit bekommt man einen Blick dafür, worauf man beim Testen achten muss. Soweit zur Vorgeschichte.

Gestern hatte ich aus einem anderen Grund mein Entwicklungs- und Testsystem angeworfen und »mal eben schnell« noch die neuesten (offiziellen) Versionen einiger Pakete installiert. Dabei sind mir vier Sachen ins Auge gesprungen. »Ufff,« dachte ich »ich hab doch gar keine Zeit für ausführliche Bugreports…«

  • Stand der zum Thema ausgetauschten (empfangenen) E-Mails heute 12:35 Uhr: sechs
  • Stand der dafür verwendeten Zeit: schätzungsweise eine Stunde
  • Stand der für den Blog-Eintrag verwendeten Zeit: nochmal 15 Minuten

Fazit: wenn man wichtige Arbeit hat, durch nichts anderes ablenken lassen! ;-)