Friday, 12. June 2009

Can't say it any better

Matt Gemmell on new iPhone 3GS

Digital | Kommentare: (0) | Tags:

Saturday, 7. March 2009

ecoDriver

FIS im Audi A3 Eine Woche Stadtverkehr. 140 PS, aufgeladener Selbstzünder mit Partikelfilter. Fünf Türen und gemäßigter Assistenz- und Komfortschnickschnack.

Selbst wenn das Mäusekino schwindelt: Schöne Belohnung für konsequentes Streicheln des Gaspedals. :-)








Analog | Kommentare: (0)

Sunday, 12. October 2008

Preisfrage

Was hatte Arne hier im Sucher seiner Leica M7?

Analog | Kommentare: (2)

Friday, 26. September 2008

History repeating

Denke ich an die 1980er Jahre zurück, erinnere ich mich an endlos erscheinende Sommerferien an der Ostsee, dezente Verwerfungen des Alltags durch Beschaffungsprobleme und eine geduldige Hinnahme von Fahnenappell, Wandzeitung, K. E. von Schnitzler, Klaus Feldmann & Co.

20 Jahre erlebte DDR erscheinen - im Nachhinein betrachtet - ziemlich absurd, aber da das heutige Leben nicht weniger Merkwürdigkeiten bereit hält, verblassen allmählich alle Ecken und Kanten und werden nach und nach durch den Weichzeichner der Altersmilde entschärft. :-)

Eine Erinnerung an meine Kindheit und Jugend ist allerdings nach wie so präsent wie unangenehm: Wenn die Sirene losging, habe ich immer mitgezählt. Ich befand mich in permanenter Erwartung des dritten Weltkrieges. Ein greller Lichtblitz am Horizont erschien mir wesentlich plausibler als das Auftauchen von Mickey-Mouse in unserer Strasse.

Ehrlich gesagt: Diesen Scheiss muß ich nicht noch mal haben.

It’s very important when you consider even national security issues with Russia, as Putin rears his head and comes into the airspace of the United States of America, where do they go? It’s Alaska. It’s just right over the border. It is from Alaska that we send those out to make sure an eye is being kept on this very powerful nation, Russia, because they are right there, right next to our state.

Sarah Palin

Analog | Kommentare: (0)

Tuesday, 9. September 2008

Cappuccino

Vor einiger Zeit habe ich mit Verblüffung von 280slides.com Notiz genommen - seit ein paar Tagen gibt es die technische Grundlage als Cappuccino genanntes Framework zum Download. Seht unter der LGPL und ist...

...Revolution!

Jemand mit unglaublich viel Talent hat nicht weniger gemacht, als

• mit JavaScript das zu machen, was Brad Cox mit C gemacht hat und es Objective-J zu nennen

• und große Teile von Cocoas Haupt-Frameworks AppKit und Foundation (und Teile von CoreAnimation!) nach Objective-J zu portieren.

Damit ist ein Werkzeug entstanden, das es erlaubt, alle wichtigen Metaphern der nativen Applikationsentwicklung unter Mac OS X auch im Browser zu nutzen. Etwaige kleine Unterschiede sind absolut zu vernachlässigen.

Kleines Beispiel gefällig?

So sieht ein AppController für gewöhnlich unter Objective-C und Cocoa aus:

#import "AppController.h"

@implementation AppController
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    // note that instance creation of controls is already done by InterfaceBuilder (IB)
    // same applies to centering & other cosmetics
	
    // set up initial state of the textfield
    [label setStringValue:@"Hello World!"];
    [label setFont:[NSFont boldSystemFontOfSize:20.0]]; 
        
    // init the button by setting its title & wiring its action
    [button setTitle:@"Click me!"];
	
    // just to illustrate, wiring is actually done in IB
    [button setAction:@selector(payload:)]; 
}	

- (IBAction)payload:(id)sender {
    // do something nasty...
    [label setStringValue:@"Thanks for acting like a monkey! :-)"];	
    
    // ...and disable button
    [button setTitle:@"I am done..."];
    [button setEnabled:NO];
}
@end

Unter Objective-J und Cappuccino nahezu kongruent:

import <Foundation/CPObject.j>

@implementation AppController : CPObject
{
    // meet the actors...
    var theWindow;      // the window    
    var label;          // a textfield
    var button;         // and a button    
}

- (void)applicationDidFinishLaunching:(CPNotification)aNotification
{
    
    // create a window instance
    theWindow = [[CPWindow alloc] initWithContentRect:CGRectMakeZero() styleMask:CPBorderlessBridgeWindowMask], contentView = [theWindow contentView];
    
    // create a textfield instance
    label = [[CPTextField alloc] initWithFrame:CGRectMakeZero()];
    
    // create a button instance
    button = [[CPButton alloc] initWithFrame:CPRectMake(0.0,0.0,200,18)];   
        
    // set up initial state of the textfield
    [label setStringValue:@"Hello World!"];
    [label setFont:[CPFont boldSystemFontOfSize:20.0]];    
    [label sizeToFit];
    
    // init the button by setting its title & wiring its action
    [button setTitle:@"Click me!"];
    [button setAction:@selector(payload:)];
    
    // center the controls
    [label setAutoresizingMask:CPViewMinXMargin | CPViewMaxXMargin | CPViewMinYMargin | CPViewMaxYMargin];
    [label setFrameOrigin:CGPointMake((CGRectGetWidth([contentView bounds]) - CGRectGetWidth([label frame])) / 2.0, (CGRectGetHeight([contentView bounds]) - CGRectGetHeight([label frame])) / 2.0)];
    [button setAutoresizingMask:CPViewMinXMargin | CPViewMaxXMargin | CPViewMinYMargin | CPViewMaxYMargin];
    [button setFrameOrigin:CGPointMake((CGRectGetWidth([contentView bounds]) - CGRectGetWidth([button frame])) / 2.0, (CGRectGetHeight([contentView bounds]) - CGRectGetHeight([button frame])) / 1.7)];
    
    // ... and add them to the window
    [contentView addSubview:label];
    [contentView addSubview:button];
    
    // set window to focus 
    [theWindow orderFront:self];
}

- (void)payload: (id)sender
{
    // do something nasty
    [label setStringValue:@"Thanks for acting like a monkey! :-)"];
    
    // cosmetics (centering and stuff)
    [label sizeToFit];
    [label setAutoresizingMask:CPViewMinXMargin | CPViewMaxXMargin | CPViewMinYMargin | CPViewMaxYMargin];
    [label setFrameOrigin:CGPointMake((CGRectGetWidth([contentView bounds]) - CGRectGetWidth([label frame])) / 2.0, (CGRectGetHeight([contentView bounds]) - CGRectGetHeight([label frame])) / 2.0)];
    
    // disable button
    [button setTitle:@"I am done..."];
    [button setEnabled:NO];      
}
@end

Man beachte die gleiche Syntax und - viel wichtiger - die komplette Adaption des Lebenszyklus der Applikation. Unterschiede bestehen lediglich im "Namensraum" (CPTextField statt NSTextField) und in der Art und Weise der Instanziierung und Anordnung der Controls. Im "Original" werden derlei Dinge für gewöhnlich im InterfaceBuilder erledigt, unter Cappuccino muß das (noch?, NIB-Support geplant) programmatisch erledigt werden. Gleichwohl erlaubt auch Cocoa den programmatischen Weg. Im Prinzip gleicht der momentane Stand von Cappuccino dem der ersten iPhone-SDK-Releases, wo auch noch alles per Hand geschrieben werden musste.

Ausprobieren?

CPHelloWorld.zip, 744kB und NSHelloWorld.zip, 88 kB.

Was bleibt unterm Strich?

Jeder kennt noch die ersten Web-Applikationen: Serverseitig wurde eine HTML-Seite zusammengebaut, die Interaktion mit dem Nutzer erfolgte über das Request/Response zwischen Client und Server. Jedes Mal ein kompletter Roundtrip.

Dann kam AJAX. Teilaufgaben wurden in einzelne (gern asynchrone) Requests ausgelagert, Ergebnisse in Teilbereichen der Seite per DOM-Scripting aktualisiert. Auch in der Iteration unter Verwendung von Frameworks schwer zu debuggen (was sagt der Server, was der Client?) und auch mit Template-Engines immer noch ein schöner Verhau aus HTML, CSS, JavaScript und serverseitigem Code.

Wer bequemer zu desktop-ähnlichen Applikationen kommen wollte, musste sich einer proprietären Laufzeitumgebung (Java, Flash, Flex, Air, Silverlight) unterwerfen.

Mit Cappuccino haben sich die Spielregeln geändert. (Mac-zentrierte) Desktop-Entwickler können mit relativ wenig Aufwand und unter Beibehaltung bekannter Metaphern fürs Web programmieren (oder ihren Desktop-Code schneller prototypen). Exakter: Die momentan besten Paradigmen für Applikationsentwicklung gibt es jetzt auch für den Browser. Ohne Plugin. Clientseitig wird lediglich ein moderner Browser mit halbwegs aktueller CSS-Implementierung und schnellem JavaScript-Interpreter (WebKit SquirrelFish? Google Chrome V8?) vorausgesetzt.

Wie gesagt: Revolution!

Digital | Kommentare: (0) | Tags:

Monday, 14. July 2008

Self service

Früher immer geulkt, dass man sich im Krankheitsfalle bald so genannter Expertensysteme im Internet bedienen wird. Nach dem Beantworten eines Dialogsystems (multiple choice) steht am Ende der Download des Therapie-Vorschlages; bei dentalen Problemen gern auch unter Einbeziehung des häuslichen Werkzeugkastens.

Was eigentlich als satirische Aufheiterung am Stammtisch gedacht war, scheint nun endlich Realität zu werden - die "IKEAisierung" schreitet munter voran...

Analog | Kommentare: (2)

Friday, 4. July 2008

Meet "CardCleaner"

Der Wunsch

Eine Secure Digital Memory Card (SD Card) wird am Mac mit MP3-Dateien befüllt und soll danach ein Autoradio, das über einen entsprechenden Kartenslot verfügt, mit Musik versorgen.

Das Problem

Die relative stumpfe Software des Autoradios verlangt nach einem FAT-formatierten Medium und ist lediglich in der Lage, alles unterhalb des Wurzelverzeichnisses der Karte rekursiv zu iterieren und abzuspielen. Dabei verstolpert sie sich an den unsichtbaren Dateien, die der Mac auf der Karte hinterläßt.

Lösung I

Man kopiert die Ordnerstruktur mit den MP3-Dateien und begibt sich auf die Konsole (Terminal.app). Dort folgt ein

find /Volumes/NAME_DER_KARTE/ -name '.*' -exec rm -rf {} \;

Lösung II

Man lädt dieses kleine Programm (ab Mac OS X 10.5, UB), packt es aus, und läßt es im Dock wohnen. Danach zieht man die mit den MP3-Dateien beschriebene Karte auf das Icon des Programms.

Was passiert dabei?

Beide Methoden löschen rückstandsfrei und rekursiv alle Objekte (Dateien und Verzeichnisse), die mit einem "." beginnen.

Welche Dateien und Verzeichnisse sind betroffen?

Habe ich doch gesagt: Alle, die mit einem "." beginnen! :-)

OK, aber warum legt der Mac überhaupt Dateien an, die man offensichtlich nicht braucht?

Ummm, gute Frage. Zwei Antworten:

Zum einen verwendet der Mac seit Unzeiten ein "zweidimensionales" Dateisystem namens HFS. Eigentliche Daten (data-fork) werden von sogenannten Resources (resource-fork) getrennt gespeichert.

Beispiel: Man verpasst einer - auf der lokalen Festplatte gespeicherten - MP3-Datei (test.mp3) im Finder ein Etikett. Die Informationen über die Etikett-Farbe würde für die entsprechende Datei in der resource-fork gespeichert werden.

Solange sich alles auf einem HFS-formatierten Volume abspielt, braucht man sich darum nicht zu kümmern. Problematisch wird es erst, wenn die "gefärbte" Datei auf ein Non-HFS-Volume kopiert wird. Da der Finder dort nur ein "eindimensionales" Dateisystem vorfindet, aber gern die Etikett-Farbe erhalten möchte, greift er zu einem Trick: Er legt Daten- und Ressource-Zweig in ZWEI GETRENNTEN Dateien ab. Aus "test.mp3" wird "test.mp3" UND "._test.mp3", wobei letztere Datei die resource-fork enthält. Solange dieses Non-HFS-Volume am Mac per Finder beackert wird, sieht man (per default) nix davon, da das Mac OS X diesen Trick (zumindest auf dem GUI) maskiert.

Übergibt man ein derart beschriebenes Volume allerdings an die Welt, die etwas mehr "simple minded" ist, sind wir beim ganz oben erwähnten Problem.

Der zweite Teil der Antwort betrifft den generellen Umgang mit gemounteten Volumes am Mac.

Neben den im Finder (per default) sichtbaren Dateien und Verzeichnissen, legt er noch einiges mehr an. Ein Beispiel:

mb.hq.happytoys.de:boot martin$ ls -la /Volumes/NO\ NAME/
total 52
drwxrwxrwx  1 martin  staff  16384  4 Jul 14:22 .
drwxrwxrwt@ 4 root    admin    136  4 Jul 14:22 ..
drwxrwxrwx  1 martin  staff   2048  4 Jul 14:22 .Spotlight-V100
drwxrwxrwx@ 1 martin  staff   2048  4 Jul 14:22 .Trashes
-rwxrwxrwx  1 martin  staff   4096  4 Jul 14:22 ._.Trashes
drwxrwxrwx  1 martin  staff   2048  4 Jul 14:22 .fseventsd
mb.hq.happytoys.de:boot martin$

So sieht eine frisch am Mac (FAT16-) formatierte und vermeinlich leere SmartMedia-Karte bei mir aus.

Unterhalb von .Spotlight-V100 liegt der Index, den Spotlight zum schnellen Durchsuchen des Datenträgers verwendet. .Trashes ist das Verzeichnis für den Papierkorb der Karte, ._.Trashes die dazugehörige resource-fork. Und unter .fseventsd legt der gleichnamige daemon Informationen über Änderungen an diesem Dateisystem ab. Davon profitieren der Spotlight-Indizierer mds und - ich glaube - auch der Backup-Mechanismus "TimeMachine".

Alle diese "unsichtbaren" Daten sind also für den Mac irgendwie wichtig, verwirren aber unter Umständen das Zielsystem, das eigentlich nur eine Verzeichnisstruktur mit Nutzdaten erwartet.

Gut. Was macht "CardCleaner" genau?

CardCleaner ist für alle Objekte mit dem UTI public.volume registriert, man kann also alle Objekte dieses Typs auf das Icon des Programms ziehen. Passiert dieses, testet "CardCleaner", ob dieses Volume FAT-formatiert ist. Dies geschieht, um unvorsichtige Nutzer vor dem Löschen wichtiger Daten auf einem HFS-Volumes oder Netzwerk-Share zu bewahren...

struct statfs buffer;
NSString *fileSystemType;
if (statfs( [filename fileSystemRepresentation], &buffer)) {
   fileSystemType = [NSString stringWithCString:buffer.f_fstypename];
   NSLog(@"FSType: %@", fileSystemType);
}

Ist diese Bedingung erfüllt, löscht es (rekursiv) alle Objekte im Dateisystem, die mit einem "." beginnen. Dazu benutzt es den NSFileManger. Schlussendlich bietet es an, das Medium auszuwerfen.

Und was ist mit den ".DS_Store"-Dateien?

Das ist eine andere Baustelle. Diese Artefakte werden erst relevant, wenn das (lokal gemountete) Medium als Share exportiert wird, also im Netzwerk freigegeben wird. Sie werden per se gelöscht, beginnen ja auch mit einem ".". Etwaige Probleme beim Löschen und Auswerfen (Rechte, offene handles) mal vernachlässigt.

Was kann schief gehen?

Natürlich eine ganze Menge. Erdbeben, der Strom kann ausfallen, "war could be declared", ... :-)

Für den eingangs erwähnten Nutzungsansatz (Medienkarte, MP3, Autoradio) kann nicht viel schief gehen. Unter Umständen kann die Karte nach dem Putz-Vorgang nicht ausgeworfen werden. Dann nämlich, wenn der Nutzer noch Dateien auf der Karte offen hat (eine offene Shell, die gerade in dem Verzeichnis unterhalb von /Volumes/KARTENNAME ist, genügt) oder wenn der mds gerade die Karte unter seiner Fuchtel hat.

Für den unwahrscheinlichen Fall dramatischer Konsequenzen durch nicht berücksichtigte Seiteneffekte oder Fehlfunktionen des Programms bin ich natürlich nicht verantwortlich. Der Einsatz von "CardCleaner" geschieht auf eigene Gefahr!

Kann ich helfen?

Klar, "CardCleaner" ist zwar nur ein programmiertechnischer Fliegenschiss und ich bin kein Programmierer, würde mich aber über Anmerkungen und Verbesserungsvorschäge freuen. Im Impressum steht meine e-Mail-Adresse. Dank gebührt allen Helfern.

Für den Fall der Erlangung spirituellen Gleichgewichts nach der Benutzung des Programms sei noch darauf hingewiesen, dass diese e-mail-Adresse mit einem PayPal-Konto (wink, wink) assoziert ist... :-)

Update

Inzwischen hat "CardCleaner" schon einigen Menschen geholfen. Der generische Ansatz, alle FAT-formatierten Medien zu beackern, schliesst auch festplattenbasierte Player nicht aus. Erstes Geld ist eingetroffen! :-) Und es gibt ein Update: "Minor changes to improve reliability". "Bugfixes to address rare circumstances", wie es so schön heißt...

Der absolute Knaller aber: Die englische Lokalisierung ist von Cabel Sasser überarbeitet worden!

Digital | Kommentare: (0) | Tags:

Tuesday, 27. May 2008

MobTrack

Hier findet sich ein kleines MIDlet für GPS-fähige Mobiltelefone. Es zeichnet in einem wählbaren Intervall die aktuelle Position des Telefons auf und kann diese in einem zweiten, parameterisierbaren Intervall direkt an den Server von digital-seas.com senden. Account erforderlich. Dort wird das ganze hübsch gegen die üblichen verdächtigen APIs mit Hilfe von Flash visualisiert.

Zusätzlich können die gesammelten Daten nach GPX und KML exportiert werden.

Erfordert ein Telefon, dass JSR-179 unterstützt. Entwickelt auf dem BlackBerry 8800 (internes GPS und BT-Empfänger von TomTom). Getestet auf dem Nokia E90.

Auf der Roadmap ist der Support für JSR-82-Telefone ohne direkte GPS-Unterstützung.

Digital | Kommentare: (0) | Tags:

Thursday, 20. March 2008

New gear in town

frankenstein.hq.happytoys.de Frisch dem Labor entwichen, und momentan der Schnellste im Büro: frankenstein.hq.happytoys.de.


























Digital | Kommentare: (2) | Tags:

 
It's all about: adidas apache apple applescript aspartam autoaufkleber automator backup bad music blackberry blackberry 8800 blogging blojsom book boot camp brain slug brigadetagebuch cappuccino captcha cocoa comic cover css deppen-apostroph diy dsl e-plus exif exiftool extract text exzess fat finder firefox firmware flash flex freiheit ftp fururama fuzzy g8 gigaset golf gps gpx hardlink hfs hibernate hidden files hirnfurz html httpd hyena iPhoto ichat ikimagebrowserview imagemagick inside interkosmos 10 internet explorer iphone itunes jabber james tiberius kirk java java me javascript jsr-179 jsr179 keyboard kindernamen kino klingel kombinat 100 koppelin launchd lbs leopard little miss sunshine mac os x macbook macpro mail mallorca marketing mecklenburg-vorpommern microsoft midlet midp mobile music mysql newsletter subscription nokia e90 objective-c objective-j ostsee-zeitung paprika pdf pelewin perl photo picture gallery podcast polizei-beratung powerbook primer regex reiseführer rim rosetta rostock rss safari scode segeln segway siemens sms snapmania soundex spam sponge bob spring subversion svn t-shirt telekom text to speech thumbnails time machine tomcat track transmit tv unix urlaub bornholm urlaub ski snowboard utf-8 vienna vogelhaus volkswagen webdev webkit widget windows wittenburg wlan world of warcraft xml xml-rpc