AeroFS

Neulich hatte ich überlegt, wie ich meine computerübergreifende Dokumentenablage am besten organisieren könnte. Eine Idee dazu war dann ein verteiltes Peer-to-Peer-Dateisystem. In den Kommentaren hatte ich dazu schon einiges gefunden.

Und eine Lösung kommt dem, was ich will, ziemlich nahe: AeroFS, entwickelt von einem Start-Up in Kalifornien. Dafür, dass das noch eine early beta ist, funktioniert es erstaunlich gut. Ich habe es jetzt auf drei Computern im Einsatz, und der Sync funktioniert letztendlich auch, wenn immer nur zwei davon gleichzeitig im Einsatz sind.

Meine Hauptkritikpunkte:

  • Es kann keine Symlinks, auch nicht innerhalb einer Bibliothek. Wie man das unter Windows umsetzt, ist mir letztlich egal, aber es sollte zumindest zwischen Linux-Systemen funktionieren.
  • Im Statusfenster sind ständig irgendwelche Metadatentransfers zu sehen, auch wenn sich nichts ändert. Das ist etwas verwirrend.
  • Man bekommt keine sinnvolle Rückmeldung über den Status der automatischen Synchronisierung. Das macht die Entscheidung, ob man den mobilen Computer jetzt abschalten und mitnehmen kann, etwas schwierig.
  • Synchronisierungsprobleme (beispielsweise Konflikte oder auf einer Plattform nicht zulässige Dateinamen) werden zwar angezeigt, diese Meldungen sind aber sehr versteckt.

Insgesamt erscheint mir der Ansatz aber vielversprechend. Hoffen wir, dass die weiterhin handwerklich saubere Arbeit abliefern, dann wird das schon.

Dokumentenablage

Ich denke gerade darüber nach, wie ich meine Dokumentenablage vernünftig organisiere. Zuerst einmal betrifft das die Ablage beispielsweise von Schreiben. Bisher habe ich dafür einen Ordner “korrespondenz”, aber nur auf meinem PC zu Hause. Nun hätte ich sowas aber auch gerne synchronisiert. Ich könnte es mit rsync, unison oder Ähnlichem probieren. Aber dafür muss man dann ja die zu synchronisierenden Rechner manuell abgleichen. Oder gibt es da auch etwas, was das automatisch anstößt, sobald die sich sehen können? Und klappt das auch mit mehr als zwei Rechnern zuverlässig? Das nächste, woran ich dann gedacht habe, ist ein Versionsverwaltungssystem. Allerdings frage ich mich zum Einen, ob das nicht Overkill ist. Und ich müsste dann mal vom altmodischen SVN weg und am Besten Git ausprobieren. Benutzt das jemand für solche Zwecke? Und eine History ist ja praktisch – allerdings könnte sie bei großen Binärdateien eher hinderlich sein. In der Uni ist mir sowas relativ egal, aber wenn ich den Speicherplatz selbst bereitstellen und bezahlen muss … Benutzt jemand SVN oder Git für so einen Zweck? Irgendwelche Idee, was man mit Binärdateien oder generierten Dateien am besten macht? Jedes Mal ein neues PDF einchecken, wenn man ein Komma ergänzt hat, ist ja auch nicht das Wahre … Ebenso bei Formaten wie ODT oder ODS …

Oder wären vielleicht verteilte Dateisysteme eine Alternative? Gibt es da mittlerweile etwas Ordentliches? Als ich vor Jahren mal geschaut hatte, sah das alles ziemlich kompliziert zu konfigurieren aus … Ideal wäre da eine Lösung, die automatisch ein Overlaynetzwerk aufbaut und darüber verschlüsselt kommuniziert.

Und die Sache ist halt, dass für manche Dateien Versionierung nützlich wäre, für andere aber Overkill. Das zu kombinieren, stelle ich mir irgendwie schwierig vor …

Und was damit noch gar nicht gelöst ist, ist die Metadatenverwaltung (Beispiel: Wann wurde ein Brief abgeschickt, worauf ist er eine Antwort, etc.) und Verwaltungsfunktionen wie Wiedervorlage etc.

Ich freue mich über sämtliche Ideen zu diesem Thema …

Pseudomedizin bei der Techniker Krankenkasse

Dass die Krankenkassen in gewissem Umfang Hokuspokus wie Homöopathie bezahlen, war mir ja durchaus bekannt. Aber was dann in Ausgabe 1/2012 von TK aktuell stand, hat mich dann doch erstaunt.

Im Artikel “TK baut Leistungen weiter aus” heißt es auf Seite 6/7:

Der TK-Verwaltungsrat hat eine neue Leistung zu den alternativen Heilmethoden beschlossen. So übernimmt die TK als erste Krankenkasse ab 2012 die Kosten für nicht verschreibungspflichtige aber apothekenpflichtige Arzneimittel der besonderen Therapierichtungen Antroposophie, Homöopathie und Phytotherapie (Pflanzenheilkunde).

Danach werden noch bestimmte Ausschlüsse genannt sowie die Erstattung (bis 100 € pro Jahr und Versichertem) erläutert.

Auf Seite 24 (“Wissen”) heißt es in einem Kasten “Alternative Heilmethoden” mit einem Vermerk “NEU”:

Homöopathie Immer mehr Menschen setzen auf Homöopathie. Weil sie möglichst schonend und angepasst an ihre besondere Konstitution behandelt werden möchten. Bei der TK ist diese Leistung inklusive. Bundesweit übernimmt die TK die Kosten für homöopathische Beratung bei besonders qualifizierten Ärzten. Dabei wird, basierend auf der individuellen Krankengeschichte und einer ungefähr 60 Minuten dauernden Erstanamnese, ein umfassender Therapieplan entwickelt. Auch Folgegespräche gehören dazu. Neu: Auch die Kosten für homöopathische Medikamente werden ab 2012 bis zu einem bestimmten Betrag im Jahr von der TK übernommen (siehe auch S. 6/7).

Daran stören mich einige Sachen:

  • Normale Menschen müssen nicht verschreibungspflichtige Medikamente selbst bezahlen. Eine Ausnahme gibt es jetzt für abergläubische Menschen, die gerne unwirksame Medikamente nehmen: Nur solche werden auch bezahlt, wenn sie nicht verschreibungspflichtig sind.
  • Die wirre Lehre Rudolf Steiners (bekannt auch durch Waldorfschulen und Demeter-Biohöfe) wird geadelt, indem man sie als “Therapierichtung” anerkennt.
  • Offenbar verblödet die Mitgliederschaft der TK immer mehr, wenn immer mehr davon auf Homöopathie setzen. Ich setze lieber auf Medizin. Wenn die nicht nötig ist, liegt kein Fall für die Solidargemeinschaft vor.
  • Es wird suggeriert (nicht behauptet, wohlgemerkt!), Homöopathie sei “möglichst schonend und angepasst an ihre [=der Patienten] besondere Konstitution”. Solchen Unsinn, verlautbart von meiner Krankenkasse, möchte ich nicht mit meinen Beiträgen finanzieren. Eigentlich finanzieren das übrigens nicht nur die Mitglieder der TK, sondern alle Mitglieder der GKV über den Gesundheitsfonds!
  • Es ist ja schön, wenn Ärzte die Möglichkeit bekommen, sich intensiv mit den Patienten zu befassen. Aber warum wird das nur bezahlt, wenn der fragliche Arzt ein besonders qualifizierter esoterischer Spinner ist?

Ich frage mich ernsthaft, ob solche Regelungen von Rechts wegen Bestand haben können. Hier ein paar einschlägige Vorschriften:

§ 12 Abs. 1 SGB V, Wirtschaftlichkeitsgebot:

(1) Die Leistungen müssen ausreichend, zweckmäßig und wirtschaftlich sein; sie dürfen das Maß des Notwendigen nicht überschreiten. Leistungen, die nicht notwendig oder unwirtschaftlich sind, können Versicherte nicht beanspruchen, dürfen die Leistungserbringer nicht bewirken und die Krankenkassen nicht bewilligen.

§31 Abs. 1 S. 1 SGB V, Arznei- und Verbandmittel:

Versicherte haben Anspruch auf Versorgung mit apothekenpflichtigen Arzneimitteln, soweit die Arzneimittel nicht nach § 34 oder durch Richtlinien nach § 92 Abs. 1 Satz 2 Nr. 6 ausgeschlossen sind [...].

§ 34 SGB V Abs. 1 S. 1, Ausgeschlossene Arznei-, Heil- und Hilfsmittel

Nicht verschreibungspflichtige Arzneimittel sind von der Versorgung nach § 31 ausgeschlossen.

Da frage ich mich schon sehr, wie die TK auf die Idee kommt, diese Arzneimittel bezahlen zu dürfen. Das reißt auch der sehr allgemein gehaltene § 2 Abs. 1 SGB V wieder raus:

Die Krankenkassen stellen den Versicherten die im Dritten Kapitel genannten Leistungen unter Beachtung des Wirtschaftlichkeitsgebots (§ 12) zur Verfügung, soweit diese Leistungen nicht der Eigenverantwortung der Versicherten zugerechnet werden. Behandlungsmethoden, Arznei- und Heilmittel der besonderen Therapierichtungen sind nicht ausgeschlossen. Qualität und Wirksamkeit der Leistungen haben dem allgemein anerkannten Stand der medizinischen Erkenntnisse zu entsprechen und den medizinischen Fortschritt zu berücksichtigen.

Dass die Qualität und Wirksamkeit von Homöopathie und Steiner-Esoterik nicht dem allgemein anerkannten Stand der medizinischen Erkenntnisse entspricht ist eh klar. Geschenkt, das sieht man vermutlich nicht so eng. Aber ich sehe nirgendwo, dass diese Arzneimittel von dem Ausschluss der Erstattung nicht verschreibungspflichtiger Arzneimittel ausgenommen sind.

Ich werde jetzt bei der TK nachfragen und dann ggf. die Aufsichtsbehörde informieren.

Kalender synchronisieren mit freier Software

Nachdem ich mir jetzt einen virtuellen Server gemietet habe, dachte ich, es wäre doch eine gute Idee, der Abhängigkeit von Google zu entfliehen und meinen Kalender selbst zu hosten.

DAViCal läuft inzwischen auch (mit SSL und CACert-Zertifikat, auf einem name-based virtual host, was dank client name indication auch mit SSL geht, und vom DNS abgesehen auch unabhängig von diesem seltsamen Plesk Power Panel). Auch einen iCalendar-Export meines Google-Kalenders habe ich schon erfolgreich importieren können.

Vor dem Umstieg frage ich mich jetzt allerdings noch, wie da die Synchronisation mit verschiedenen Endgeräten aussieht. Ein paar Erwägungen:

  • Meinen privaten Kalender selbst zwischen Lightning-Instanzen zu synchronisieren, ist wohl problemlos.
  • Im Gegensatz zum Google-Kalender dürfte jetzt auch erstmals die Synchronisation von Tasks funktionieren.
  • Aber wie sieht es mit der Android-Synchronisation aus? Muss man dafür tatsächlich irgendwelche Fremdapps installieren, die dann vermutlich weniger reibungslos funktionieren als die eingebaute Synchronisation mit Google?
  • Bisher konnte ich ICS-Feeds im Google-Kalender (im Web) hinzufügen. In Lightning sind die dann leider nicht automatisch aufgetaucht, aber auf dem Android-Smartphone. Gibt es eine Möglichkeit, solche “Kalender-Abos” interoperabel und standardbasiert zu synchronisieren?

Scheduling wäre ein weiterer Punkt, den ich mal ausprobieren müsste …

Schneeschuhwanderung

Auf dem Neujahrstreff des Lauftreff Karlsruhe Mitte Januar wurde ich das erste Mal auf eine Schneeschuhwanderung aufmerksam, die Petra Guntau für den LT zum Freundschaftspreis angeboten hat. Interessant hörte sich das schon an, aber zu dem Zeitpunkt war das Wetter ja noch nicht wirklich abzusehen. Statt mich also gleich in die Liste einzutragen, habe ich erstmal gewartet, bis die entsprechenden Infos über den Verteiler kamen – das war dann Anfang der Woche der Fall. Da war es ja schon klirrend kalt, und ich hatte gerade richtig Lust auf Winter – also habe ich mich angemeldet.

Zum Glück hatte ich schon ausreichend wintertaugliche Klamotten für eine letztendlich ausgefallene Yushan-Tour vor knapp zwei Jahren angeschafft. An den Beinen waren die entsprechenden zwei Lagen (recht dünne lange Thermo-Unterhose und ebenfalls recht dünne Wanderhose) ausreichend, aber die vier Lagen am Oberkörper (ein Lauf-Funktionsunterhemd, ein Thermounterhemd, eine Winter-Laufjacke, und eine Winterregenjacke mit Fleece-Einsatz für 21,75 € von C&A) waren gerade so ausreichend. Schon interessant, ich hatte für die Beine noch eine lange Laufhose eingepackt, falls es zu kalt wird, und war eher davon ausgegangen, dass es am Oberkörper deutlich zu warm wird.

Die Wanderung führte vom Skihang in Unterstmatt hoch zum Hornisgrinde-Plateau und nach kurzer Rast auf geringfügig anderem Weg wieder herunter. Der Schnee war zwar nicht von allerbester Qualität, aber trotzdem genug, um Schneeschuhe zumindest mal auszuprobieren. Und es war richtig schön kalt. Die Mütze ist mir dank Brille immer wieder verrutscht, aber mit Kapuze war es dann halbwegs auszuhalten. Wichtig ist es jedenfalls, in Bewegung zu bleiben. Wenn wir irgendwo angehalten haben, wurde es recht schnell ziemlich kalt.

Insgesamt eine wunderschöne Tour mit traumhaftem sonnigen Wetter bei ca. -15 °C … Am Abend war ich ersteinmal hundemüde, und jetzt habe ich ordentlich Muskelkater am vorderen Schienbeinmuskel. Die Schneeschuhtouren bei Petra kann ich nur empfehlen. Zum Einstieg wohl am besten erstmal eine kurze Tour, aber es gibt auch mehrtägige Touren.

Hier erstmal ein “Symbolfoto”, sobald ich ein Foto mit mir selbst bekomme, ergänze ich es.

Leckere Speck-Champignon-Sahne-Sauce

Bei der Bayern-Aktionswoche von Lidl hatte ich auch eine Packung Semmelknödel (gekühlt, also schon mit Flüssigkeit, nicht im Kochbeutel oder so) gekauft. Darauf war ein ganz nett aussehendes Rezept für eine Speck-Champignon-Sahne-Sauce:

125 Gramm Bacon, eine gewürfelte Zwiebel und 200 g geschnittene Champignons anbraten (zweckmäßigerweise wohl so lange, bis die Champignons deutlich an Volumen verloren haben und insgesamt die Flüssigkeit weitgehend weg ist). Das Ganze dann mit 50 ml Weißwein ablöschen und wieder einkochen lassen. Darauf dann 250 ml Sahne (was ist das eigentlich für eine Unsitte, in Rezepten Sahne mit der Mengenangabe “ml” aufzuführen? Und 250 davon begegnen einem auch immer wieder – die übliche Packungsgröße sind aber 200 Gramm) und fünf Minuten köcheln lassen.

Parallel dazu zogen die Knödel 10 Minuten lang in heißer Fleischbrühe. Die Sauce war ziemlich lecker – bloß die Knödel waren nicht allzu toll (ziemlich hart und klunschig). Ich werde es bei Gelegenheit nochmal mit solchen aus dem Kochbeutel ausprobieren. Spätzle könnten auch ganz gut passen.

Die Absurdität des Parkraummarktes

Ein großes Thema in der Stadtplanung etc. ist ja der angebliche Parkraummangel in den Städten, insbesondere den innenstadtnahen Bezirken. Das hat zu zweifachem Gegensteuern geführt:

  • Die Gemeinden können für Neubauten Stellplatznachweise verlangen und tun das in der Regel auch. Die Anforderung ist wohl in der Regel, jedenfalls im Geschosswohnungsbau, dass ein Stellplatz pro Wohneinheit vorhanden ist. Alternativ sind manchmal auch Ausgleichszahlungen des Bauherrn an die Gemeinde möglich.
  • Bauträger gegen wegen des vermeintlichen Parkraummangels davon aus, dass Wohnungen ohne zugehörigen Stellplatz sich nicht vernünftig absetzen lassen. Ebenso gehen Käufer, die die Wohnung hauptsächlich als Geldanlage sehen, davon aus, dass sie sich ohne Verfügbarkeit eines Stellplatzes schlechter vermieten bzw. ggf. irgendwann in der Zukunft schlechter verkaufen lässt.

All diese Leute nutzen aber weder die Wohnung noch den zugehörigen Stellplatz. Und das führt dann dazu, dass die Erwägungen tatsächlich auf dem skizzierten, abstrakten Niveau bleiben. Das führt dann zu folgendem:

  • Der Gemeinde ist es vollkommen egal, wie der Stellplatz aussieht. Jedenfalls macht sie keine weiteren Vorgaben.
  • Dem Bauträger ist es ebenfalls egal, wie der Stellplatz aussieht. Er will aber möglichst viel daran verdienen.
  • Der Käufer der Wohnung interessiert sich ebenfalls nicht sonderlich dafür. Er muss aber eh einen Stellplatz abnehmen, und möchte nicht allzu viel dafür ausgeben.

Das Ergebnis ist dann eine Tiefgarage, bei denen es ein paar “Luxus”parkplätze gibt, die überwiegende Mehrzahl aber die gesetzlich und nach irgendwelchen Normen vorgesehenen Mindestmaße hat. Besonders hervorzuheben sind sog. Doppelparker, zum beispielweise der hier.

Sowas haben wir auch hier in der Tiefgarage, und ich war gezwungen, einen entsprechenden Stellplatz mitzumieten. Am Anfang konnte ich den untervermieten, jetzt zahle ich seit über einem halben Jahr 30 € im Monat für einen Stellplatz, den ich nicht nutze. Nun will ich mir ein Auto anschaffen (günstig von einem Verwandten …) – und muss feststellen, dass es in diesen Doppelparker nicht reinpasst. Ich werde also 30 € im Monat für einen Stellplatz, den ich nicht nutze, bezahlen müssen, außerdem 30 € im Jahr für eine Bewohnerparkerlaubnis, und obendrein ist das Auto dann dem Wetter ausgesetzt, mit dem Ergebnis eines erhöhten Verschleißes. Dem Augenschein nach sind übrigens deutlich über die Hälfte der Stellplätze in den Doppelparkern nicht benutzt. Interessant wäre es, mal zu beobachten, wie viele dauerhaft nicht benutzt werden.

Im Ergebnis ist jedenfalls festzuhalten: Es wird für viel Geld eine Tiefgarage gebaut. Statt dort komfortabel nutzbare Parkplätze einzurichten, werden aufgrund regulatorischer Zwänge und einem irrationalen Verhalten der relevanten Marktteilnehmer doppelt so viele Parkplätze eingerichtet, die dafür gar nicht mehr nutzbar sind. Also eine Investitionsruine.

Bloß: Wie kommt es dazu eigentlich?

  • Wurde die Nachfrage an Stellplätzen überschätzt?
  • War es vielleicht vor 10 Jahren wirklich noch nicht absehbar, dass viele Autos gar nicht in die damals installierten Parksysteme passen?
  • Haben die Beteiligten vielleicht einfach versucht, ihren Gewinn zu maximieren, ohne ausreichend nachzudenken?

Oder was könnten sonst die Gründe sein, die zu so einem absurden Ergebnis führen? Und wie kann man da gegensteuern?

Patch-Queue – wie organisieren?

Ich habe in letzter Zeit angefangen, Patches für ein Open-Source-Projekt (Boost, konkret die Graph Library) zu erstellen. Da ich selbst dort keine Commit-Rechte habe, bin ich darauf angewiesen, dass Entwickler mit solchen Rechten meine Änderungen für mich einchecken. Und da die auch nicht 24h verfügbar sind, dauert es eine Weile, bis die Sachen eingecheckt sind. Ich will aber ggf. mit Folgeänderungen weitermachen, die die vom ersten Patch geänderten Stellen nochmals ändern. Und da geht dann schnell das Chaos los :-(

Bevor jetzt gleich tolle Tipps kommen, dass das mit diesem oder jenem Versionsverwaltungssystem ja alles ganz einfach geht: Das Chaos dürfte zuallererstmal dadurch verursacht sein, dass ich gar nicht so recht weiß, was ich von einer Lösung erwarte. Der erste Schritt ist also eine saubere Anforderungsanalyse:

  • Diff gegen noch nicht eingecheckte Patches: Ich möchte sehen, welche Änderungen sich in meiner working copy befinden, die über die bereits erzeugten (aber noch nicht eingecheckten) Patches hinausgehen. Die Differenz zum Trunk reicht also nicht.
  • Status von Patches: Ich muss Patches als erledigt markieren können, wenn sie eingecheckt sind.
  • Zusammenfassen von Patches: Wenn ich Patches noch nicht eingesendet habe (oder ggf. auch dann noch), will ich mehrere Patches zu einem großen zusammenfassen können.
  • Selektives Anwenden von Patches: Ich will leicht meine/eine Working Copy auf einen Stand bringen können, der den Trunk (oder eine bestimmte Revision) und nur bestimmte Patches enthält. Das ist beispielsweise nötig, um zu prüfen, dass die voneinander unabhängig sind.
  • Unterstützung bei der Erstellung von Patches: Optimal (aber auch optional und eher nice-to-have) wäre, aus den lokalen Änderungen in der lokalen working copy gegenüber dem Trunk (ggf. zuzüglich einer Auswahl von Patches) einen Patch erstellen zu können – aber nicht mit sämtlichen Änderungen, sondern Auswahlmöglichkeiten bezüglich der Dateien und der einzelnen Änderungen darin. Das geht aber zur Not auch manuell, ggf. mit Nachbearbeiten.

Hat jemand eine Idee, wie man diese Funktionalität am besten umsetzt? Gibt es für so etwas fertige Tools? Ist es vielleicht mit bestimmten Versionsverwaltungssystemen besonders einfach? Git wird ja ständig für alles Mögliche in höchsten Tönen gelobt. Nutzt es vielleicht auch hier? Wenn ja, wie lassen sich obige Anforderungen auf die Begrifflichkeiten von Git (oder einem anderen System) abbilden?

Boost, LEDA und meine wiederhergestellte Ehre

Neulich, als ich gerade Urlaub hatte, standen bei mir im Büro zwei Studenten, die einen Fehler in meiner Boost-Implementierung entdeckt haben wollten (wie mir danach mein Büromitbewohner berichtete). Zumindest habe ich mich gefreut, dass den Code jemand benutzen wollte. Allerdings haben die beiden sich dann nicht mehr gemeldet. Über Umwege erfuhr ich dann am Wochenende, was der Fehler ist: Es fehlt in leda_graph.hpp eine spitze Klammer:

  template <class vtype, class etype, class PropertyTag, class Key>
  inline
  typename boost::property_traits<
    typename boost::property_map<leda::GRAPH<vtype, etype>,PropertyTag>::const_type
::value_type
  get(PropertyTag p, const leda::GRAPH<vtype, etype>& g, const Key& key) {
    return get(get(p, g), key);
  }

Es hat also nicht nur jemand diese Templates auf bisher ungetestete Art und Weise verwendet – das hier knallt schon, wenn man leda_graph.hpp nur einbindet … Dass ich diesen Fehler verursacht haben sollte, erschien mir etwas unplausibel – denn ich habe den Header ja damals benutzt, und mein Programm kompilierte. Also habe ich mir die SVN-Historie angeschaut.

------------------------------------------------------------------------
r36836 | dgregor | 2007-01-29 20:29:06 +0100 (Mo, 29. Jan 2007) | 2 Zeilen

Improvements to LEDA adaptors, from Jens Mueller
@@ -528,11 +884,11 @@
   inline
   typename boost::property_traits<
     typename boost::property_map<leda::GRAPH<vtype, etype>,PropertyTag>::const_type
-  >::value_type
+::value_type
   get(PropertyTag p, const leda::GRAPH<vtype, etype>& g, const Key& key) {
     return get(get(p, g), key);
   }

Die ersten Indizien sprachen aber gegen mich: In dem Checkin meines Patches von Douglas Gregor wurde auch das > entfernt. Trotzdem: Irgendwie konnte das doch nicht sein. Also habe ich die Mail herausgesucht, mit der ich den Patch eingereicht habe. Anscheinend habe ich damals den Programmcode im Body der Mail verschickt, statt als Anhang. Klar, mit der Policy von Boost, die Zeilen auf lesbare Länge zu begrenzen, hat das ja auch wunderbar funktioniert. Allerdings wurde dabei offenbar ein > als gequoteter Text interpretiert. Douglas hat dann einfach den Text in eine Datei kopiert und das fehlende > nicht bemerkt. Jens nix schuld, meine Ehre ist wiederhergestellt. Und da es keine automatisierten Tests für die LEDA-Bindings gibt (dafür bräuchte man ja eine LEDA-Installation, und die gab es damals nur gegen Geld), ist das niemandem aufgefallen. Viel irritierender finde ich aber, dass den Fehler vier Jahre lang niemand bemerkt hat :-(

Naja, jedenfalls wurde mir damals angeboten, Maintainer der LEDA-Bindings zu werden. Inzwischen gibt es eine kostenlose Version der LEDA-Bibliothek. Insofern eine gute Gelegenheit, auf das Angebot zurückzukommen. Anscheinend hat sich auch niemand um die Datei gekümmert, und sogar Verbesserungsvorschläge mit fertigen Patches wurden nicht bearbeitet. Vielleicht würde es sich ja lohnen, die wieder hervorzukramen …

TV-Out mit Nvidia unter Linux?

Ich würde gerne mal TV-Out so einrichten, dass es komfortabel benutzbar ist. Die Anleitungen, die man dazu im Netz so findet, haben mich bisher nicht weiter gebracht.

Im Moment benutze ich den Binär-Treiber von Nvidia nebst passendem Kernel-Modul. Damit ist es offenbar nicht möglich, Bildschirme zur Laufzeit dynamisch hinzuzufügen. Wenn ich mit nvidia-settings den Monitor am HDMI-Ausgang erkennen lasse und hinzufüge, schreibt der das in die xorg.conf, und ich muss den X-Server neu starten, bevor die Änderung aktiv ist. Der TV-Bildschirm ist dann virtuell gesehen rechts vom Hauptbildschirm, der Mauszeiger erscheint also auf dem TV, wenn ich ihn über den rechten Bildschirmrand bewege. Ein X-Neustart ist auch erforderlich, wenn ich den zweiten Monitor entfernen will. Und den aktiviert zu lassen, ist durchaus ungünstig: Dann verschwindet der Mauszeiger nämlich plötzlich, wenn man ihn an den rechten Rand bewegt.

Eigentlich ist dieser Modus mit der erweiterten Arbeitsfläche auch nur sinnvoll, wenn man zwei (gleich hohe) Bildschirme nebeneinander stehen hat. Ich kann mir jedenfalls kein sinnvolles Szenario vorstellen, in dem ich eine solche kombinierte Arbeitsfläche aus normalem Computerbildschirm und TV benutzen würde. Mit meinem Windows-Notebook benutze ich sowas auch nur ganz selten: Wenn ich auf dem Beamer mit meinem Notebook irgendetwas statisches zeigen muss und gleichzeitig Sachen nachschauen muss, die nicht für alle sichtbar auf dem Beamer erscheinen sollen. Aber für Präsentationen benutze ich entweder getrennte Displays (wenn das entsprechende Programm einen Präsentationsmodus hat, in dem es auf dem zweiten Display eine Vollbilddarstellung ausgibt), oder ansonsten halt auf dem zweiten Display eine Kopie des ersten Displays (wobei in dem Fall aber auch die Auflösung des Primärbildschirms an das entsprechende Seitenverhältnis angepasst wird). Unter Windows funktioniert das jedenfalls auf dem Notebook wunderbar mit einer extra markierten Taste (Fn-F7 müsste es sein). Bei TV-Out sind die Usecases ähnlich, nur dass es nicht um Präsentationen, sondern um Videos geht. Übrigens funktioniert seit Ubuntu 11.04 Audioausgabe über HDMI endlich ohne Gefrickel (will sagen, man kann diesen Ausgang im Mixer auswählen, bei Pulseaudio auch für jede Anwendung einzeln).

Was ich mir jetzt wünschen würde, ist:

  • Der Fernseher ist als gesonderter Bildschirm verfügbar. Am besten wäre es natürlich noch, wenn man das auf einfache Weise ein- und ausschalten könnte.
  • Ich kann Programme wie mplayer oder vlc unkompliziert so starten, dass sie das Bild als Vollbild aufs TV schieben, und auch den Ton über TV ausgeben.
  • Ich kann den Firefox Videos im Vollbildmodus (ob nun nativ über HTML5 oder mit dem Flashplugin) auf dem TV ausgeben lassen, nebst zugehörigem Ton.

Ist das möglich, bzw. wenn ja, wie? Ein paar runtergebrochene Fragen fallen mir schon ein:

  • Die RandR-Erweiterung ist ja dafür da, Displays dynamisch zu konfigurieren. Funktioniert die mit dem Binärtreiber von Nvidia? Die Antwort nach dem Lesen eines Eintrags im Ubuntu-Wiki scheint mir vielleicht zu sein.
  • Alternativ dazu: Läuft Nouveau inzwischen stabil? Unterstützt der RandR? Und wenn ja: wie stelle ich unter Ubuntu um von nvidia auf nouveau?
  • Welchen Support haben Desktop-Umgebungen und gebräuchliche Anwendungen für den Umgang mit sekundären Displays und Audio-Ausgängen?

Vielleicht komme ich ja jetzt mit dem Problem endlich mal weiter. Als nächstes wären dann noch einige weitere Sachen zu lösen … Beispielsweise: Ist mein Kabelanschluss defekt, oder liegt der schlechte Digitalempfang der Privatsender nur an einem minderwertigen Kabel? Wie steuere ich einen Videoplayer geeignet fern?

Tipps bei der Anschaffung eines Kleiderschranks

Nachdem ich an meinem Kleiderschrank einiges umgestalten und umräumen möchte, weil ich mit dem aktuellen Zustand nicht komplett zufrieden bin, und ich mich auch mit einem Kollegen, der vor einem Umzug und der Anschaffung eines neuen Schrankes steht, über das Thema gesprochen habe, möchte ich hier einige methodische Tipps für Anschaffung und Einrichtung eines Kleiderschranks zusammenstellen. Ich selbst habe von IKEA den PAX mit UGGDAL-Schiebetüren. Daher werde ich im Folgenden öfter mal auf meine (auch negativen) Erfahrungen damit eingehen.

Größe: Wenn nicht gerade der Platz in der Wohnung äußerst knapp ist, spricht meines Erachtens nichts dagegen, den Schrank großzügig zu dimensionieren. Zwei Meter Breite sind meines Erachtens auch für eine Person nicht übertrieben. Von der Höhe sollte der Schrank bis knapp unter die Decke gehen. 237 cm ist beispielsweise das, was IKEA im Sortiment hat. Der einzige vernünftige Grund, warum man einen Schrank nicht zur Decke reichen sollte, ist, dass man noch etwas drauflegen möchte. Das (beispielsweise Bettwäsche, einen Schlafsack, oder ähnliche Sachen, an die man selten ran muss), kann man dann aber auch in den Schrank nach ganz oben legen. Dort sieht es weniger plünnig aus und staubt nicht zu.

Türen: Prinzipiell gibt es hier die Wahl zwischen normalen Klapptüren und Schiebetüren. Sicher gibt es auch noch exotischere Varianten, aber auf die werde ich hier nicht eingehen. Schiebetüren haben den Vorteil, dass sie weniger Platz verbrauchen und einfach “cool” sind. Bei IKEA gibt es verschiedene Glasschiebetüren, die halbwegs spiegeln (wenn man sie regelmäßig putzt). Was mir erst später aufgefallen ist, ist, wie sehr auch bei der recht dunklen UGGDAL der Schrankinhalt durchscheint. Bei beiden Türarten sollte man wohl das Öffnungs- und Schließverhalten genau prüfen. Bei Klapptüren kommen ggf. Druckluftdämpfer in Frage. Schiebetüren haben den Nachteil, dass man sie beim Öffnen manuell anstoßen und bremsen muss – oder gibt es (zumindest für das zielgenaue Bremsen) auch schon praktisches Zubehör? Ein weiterer Nachteil bei Schiebetüren ist, dass man nur eine Seite des Schrankes gleichzeitig öffnen kann (was die Aufteilung des Schrankinhaltes noch wichtiger macht, dazu unten mehr). Und wenn man Schubladen hat, muss man die Schiebetür komplett öffnen (siehe oben …), um die Schublade herausziehen zu können. Fazit: Schiebetüren sind zwar nett und erscheinen auf den ersten Blick als Nonplusultra. Aber sie haben einige nicht ganz offensichtliche unpraktische Seiten. Ein Tipp von einer Bekannten war übrigens noch, komplett verspiegelte Türen zu nehmen – damit spart man sich einen gesonderten Spiegel.

Horizontale Aufteilung: Bei der horizontalen Aufteilung sollte man darauf achten, dass man bei üblichen Abläufen nicht ständig zwischen beiden Schrankteilen hin- und herwechseln muss (insbesondere bei Schiebetüren, siehe oben). Beispielsweise wird man wohl nicht jeden Morgen eine frische Hose oder einen frischen Pullover anziehen. Aber Unterwäsche, Socken und T-Shirts sollten sich schon im selben Schrankteil befinden. Ähnliches gilt beispielsweise für Sportsachen – Handtücher, Bademantel und Badehose sollten im gleichen Teil sein.

Vertikale Aufteilung: Auf einer Seite braucht es eine Stange, an die man Kleiderbügel hängen kann. Die sollte in eine Höhe, in der man (gerade noch) bequem rankommt. Wenn es mehrere Nutzer gibt, sollten die natürlich alle noch rankommen. Darüber kommt dann einfach ein Brett. Das ist die Höhe, wo man ohne Stuhl, Leiter o.ä. nicht mehr rankommt. Es ergibt sich also ein Fach, dass ideal für selten genutzte Gegenstände geeignet ist, beispielsweise zusätzliche Bettwäsche, Schlafsack o.ä. (je nach Verfügbarkeit von sonstigem Stauraum also durchaus für Sachen, die jetzt nicht typisch für einen Kleiderschrank sind). Aus Symmetriegründen macht man das Gleiche dann einfach auch auf der anderen Schrankseite. Unter Kleiderstange sollte ausreichend Platz zum Aufhängen auch längerer Kleidungsstücke (beispielsweise eines Bademantels oder auch eines Abendkleides sein). Und wenn man sich entscheidet, beispielsweise einen Bademantel unten doch aufliegen zu lassen, sollte dort zumindest eine horizontale Abtrennung zum nächsten “Fach” hin. Aktuell hängt mein Bademantel in eine Schublade hinein, das nervt tierisch. Dafür verbraucht man vertikal schon ziemlich viel Platz – im Grunde bleibt auf der Seite dann nur unten ein Fach, für das man sich schon ziemlich bücken muss und das damit auch eher für selten genutzte Gegenstände taugt. Auf der anderen Seite wird die Aufteilung dann zwingend etwas kleinteiliger …

Kleinräumigere Aufteilung: Natürlich kann nicht jedes Kleidungsstück ein eigenes Fach bekommen. Aber die Aufteilung sollte schon so kleinräumig sein, dass nur so viele Sachen reinpassen, dass man nicht den Überblick verliert. Eine Schublade in kompletter Schrankhälftenbreite ist da schon eher zu groß. Und ohne Unterteilung geraten die Sachen zwangsläufig durcheinander. Ich habe beispielsweise eine Schublade mit “Sportsachen”. Dort sind dann hauptsächlich die verschiedensten Laufklamotten (Socken, Unterwäsche, Shirts, Hosen, Oberteile …), die natürlich vollkommen durcheinander sind. Hier muss ich dringend nachbessern. Insgesamt unterschätzt man jedenfalls leicht, wieviele verschiedene Kleidungsstücke man hat. Und eine wichtige Erkenntnis ist, dass es nicht nur auf die Liegefläche (also einfache Bretter) ankommt – die muss vielmehr ausreichend unterteilt sein, außerdem muss man sie einsehen können. Bretter im 10cm-Abstand sind also beispielsweise ziemlich ungünstig – da bildet sich “hinten” zwangsläufig Chaos.

Ich hoffe, dass diese Tipps anderen helfen, ein paar Fehler zu vermeiden, die ich gemacht habe :-) Viel Spaß beim Wohnen!

Equalismus auf der Openmind – mehr Gelassenheit, bitte

Auf der #om11 wurden zu Beginn (nach der Keynote) Themen für Gesprächsrunden gesammelt (ich habe nach der Lektüredem Überfliegen des Wikipedia-Artikels gerade so meine Zweifel, ob es sich dabei tatsächlich um ein Barcamp handelte …).

Ein Vorschlag kam von Julia ‘laprintemps’ Schramm und betraf mal wieder das Genderthema (oder, wie Julia es etwas flapsig ausdrückte, “genderpopender” …) – allerdings unter dem Schlagwort “Equalismus”, um die Abneigungen zu vermeiden, die der Begriff “Feminismus” oft provoziert. Oder, wie es das Pad (missing link intended) dazu formuliert:

Equalismus. Also die Emanzipation und Entdiskriminierung des Einzelnen bei Beibehaltung aller individuellen Merkmale, die sich Mensch selber zuschreiben möchte.

Ehrlich gesagt verstehe ich das immer noch nur so ansatzweise – mir ist noch nicht wirklich klar, wovon sich der Einzelne emanzipieren soll, bzw. Diskriminierung aufgrund welcher Merkmale (oder zugeschriebenen Merkmale) abgebaut werden soll. Dass tradierte Geschlechterrollen dazugehören, ist sowas klar, aber was noch?

Jedenfalls hat mich an diesem Thema angesprochen, dass die Vorbehalte gegen das Thema “Feminismus” ernstgenommen wurden und ein ernsthafter Anlauf unternommen wurde, auf die Kritiker zuzugehen. Also hab ich bei dem Thema mein +1 gemacht und bin dann auch hingegangen. Der Raum war ziemlich voll, und hat auch zusätzliche Stühle bekommen. Im folgenden vermische ich Zusammenfassungen von Inhalten, die laut Mitschrift im Pad Teil der Diskussion waren, mit meiner persönlichen Stellungnahme dazu. Es soll eigentlich ein MP3 geben, aber wo das ist, weiß ich nicht. Insofern von meiner Seite keine Gewähr dafür, dass der Diskussionsverlauf richtig gewichtet oder auch nur richtig wiedergegeben ist.

Einig waren sich die Anwesenden, dass es in der Piratenpartei ein Problem in Bezug auf das Thema Gender gibt. Eins der Probleme mit Feminismus ist, dass der als ungerechtfertigter Vorwurf empfunden wird, Frauen zu diskriminieren und schlecht zu behandeln.

Die Diskussion drehte sich dann dahin, dass Diskriminierung nicht nur aufgrund des Geschlechts stattfindet. Eine Beobachtung war, dass “während man darüber spricht, dass Menschen über Sprachverhalten ausgeschlossen werden, man Menschen über Sprachverhalten auschließt”. Folgerung: Wir müssen allgemein am innerparteilichen Umgang arbeiten und auch Leuten Beteiligungsmöglichkeiten bieten, die bei diesen Strukturen nicht mithalten können (meine Formulierung).

Bis hierhin habe ich einiges mitnehmen und nachvollziehen können. Danke!

Heute las ich dann den Beitrag “Wir sind das Problem (#Genderdebatte)” im Blog “Wider die Windmühlen”. Darin wird begrüßt, dass die Runde zwar viele Teilnehmer hatte, aber kritisiert, dass es zu keinen konkreten Ergebnissen kam. Weiter wird kritisiert, dass die Diskussion von ein paar wenigen Leuten dominiert wurde. Festgestellt wird, dass Ausschlussmechanismen wirken, und dass jeder einzelne an diesem Problem beteiligt ist. Darauf folgt dann die Kritik, dass es “am Eingeständnis der eigenen persönlichen Mitverantwortung mangelt” und keiner die Frage “Was kann ich tun?” stellt. Immerhin wird in einer Randnotiz angemerkt “Es gab allerdings Ausnahmen, die auf der Session z.B. ihr Redeverhalten auf Veranstaltungen kritisch reflektierten”. Damit ändert dieser Beitrag auch schon. Und ich finde diese Folgerungen zu vorschnell. Was ist denn hier die Erwartungshaltung? Dass sich Leute, die sich mit diesen Themen nie vorher bewusst beschäftigt haben, ihre “eigene persönliche Mitverantwortung” sowohl zunächst erkennen als auch dann auch noch eingestehen (Mea culpa, mea maxima culpa!, oder wie?) und am besten noch die Frage “Was kann ich tun?” nicht nur stellen, sondern auch noch beantworten. So eine Erwartung wäre überzogen, zumal für eine nur gut einstündige Gesprächsrunde. Eine realistische Erwartung ist, dass ein guter Teil der Teilnehmer Denkanstöße mitgenommen hat, und zumindest in Bezug auf mich war das auch der Fall. Geduld ist wichtig, und ein wenig Gelassenheit.

Kundenorientierung beim Zahnarzt

Am Montag habe ich mir beim Zahnarzt eine Füllung einsetzen lassen. Handwerklich habe ich bisher nichts zu bemängeln, das dürfte soweit alles passen. Aber die Beratung war recht dürftig …

Das ging schon mit der Routineuntersuchung vor einigen Wochen los, bei der diese behandlungsbedürftige Karies-Stelle entdeckt wurde. Da die vor ca. 5 Jahren schon im Ansatz auf einem Röntgenbild zu sehen war, wusste ich immerhin, dass jetzt wohl wirklich Bohren nötig war (und nicht nur die Zahnärztin gerne etwas verdienen wollte).

Aber schon mit der Wahl der Behandlungsmethode ging es los: Amalgam würde man grundsätzlich nicht mehr verarbeiten. Die Kasse würde ansonsten nur einfache Zementfüllungen bezahlen, bei einer Komposit-Füllung müsste ich ca. 80 € zuzahlen. Ich würde eigentlich gerne mit der für die konkrete Situation am besten passendsten (und gleichzeitig noch wirtschaftlichen) Methode behandelt werden, und nicht von vornherein eine ausschließen, weil der behandelnde Arzt die grundsätzlich nicht mehr anwendet. Und Zementfüllungen sind reine Behelfsfüllungen und nicht als Dauerlösung gedacht. Sowas allen Ernstes vorzuschlagen, grenzt schon an Unseriösität. Amalgam ist durchaus noch eine gebräuchliche Anwendungsmethode. Die Quecksilberbelastung tritt beim Anbringen der Füllung auf und bewegt sich in der Größenordnung, die man eh über die Nahrung zu sich nimmt. Was aus der fertigen Legierung (falls überhaupt …) noch austritt, dürfte Größenordnungen darunter liegen … Eine positive Eigenschaft von Amalgam ist, dass es sich beim Abbinden der Legierung ausdehnt und damit fest sitzt, wohingegen sich Kunststofffüllungen bei der Polymerisation zusammenziehen (was das Anbringen handwerklich aufwendiger macht). Es soll zwar auch Fälle geben, bei denen man die Ausdehnung von Amalgam vermeiden möchte, weil die den Zahn sprengen kann, aber das dürften wohl seltene Ausnahmen sein. Jedenfalls ein schönes Beispiel, wie sinnvolle Werkstoffe und Behandlungsmethoden verteufelt werden und daher nicht mehr in Frage kommen … Ich frage mich ja, ob ein Zahnarzt mit Kassenzulassung die Behandlung mit Amalgam (eine Kassenleistung!) überhaupt grundsätzlich verweigern darf. Wenn das tatsächlich unter “Therapiefreiheit” fällt, gerät das Sachleistungsprinzip zur Farce …

Bei der Behandlung selbst gab es dann erstmal Computerprobleme beim Aufrufen des Röntgenbildes. Das lag wohl auf einem Server, der noch nicht hochgefahren war, lol … Los ging es mit einer örtlichen Betäubung. Spätestens an der Stelle hätte ich mir ja schon eine genauere Information über den Behandlungsablauf gewünscht. Und ist so eine Betäubungsspritze eigentlich komplett risikolos? Ich hab, bevor ich lauter Zeugs in den Mund gestopft bekam, zumindest noch gefragt, wie lange das eigentliche Bohren dauert – “wenige Minuten” war die Antwort. Zuerst wurde an meinen Zähnen rumpoliert, eine Metallklammer und ein Keil angebracht, und weiter poliert. Gemerkt habe ich kaum was, erst als wirklich gebohrt wurde, hab ich (am Geräusch) gemerkt, dass das vorher ja noch nicht das Bohren war … Das Bohren selbst ging auch fix – aber danach wäre auch eine Information, dass jetzt “nur noch” die Füllung reinkommt, toll gewesen … Das hat nämlich (mit mehreren Schichten Kunststoff, die jeweils einzeln gehärtet wurden), auch noch mal eine Weile gedauert. Was mich auch noch interessiert hätte, wie groß diese Füllung eigentlich ist. Gehört IMO zwingend zur Aufklärung über die Behandlung, denn es macht ja schon einen Unterschied, ob das Loch einen mm groß ist oder der halbe Zahn entfernt wird …

Fazit: Ihr Handwerk dürften die meisten Ärzte ja durchaus verstehen. Aber darin, den Patienten angemessen zu informieren und “mitzunehmen”, besteht erheblicher Nachholbedarf …

Zum Konzept für die politische Meinungsbildung

Schon vor einigen Monaten (“um 15:49″ – vermutlich am 13. Juni 2011) hat unsere politische Geschäftsführerin einen Entwurf eines Konzeptes für die politische Meinungsbildung zur Diskussion gestellt. Sie selbst betont, dass alles zur Diskussion steht und einige wichtige Fragen noch offen sind. Also versuche ich mich mal an einer Stellungnahme.

Zunächst zur Einleitung: Das Ziel des Konzeptes finde ich etwas unstrukturiert dargestellt. Etwas versteckt ist ein Punkt, der mir besonders wichtig erscheint: Jeder “soll die Möglichkeit haben, eine ganzheitliche Meinung darzustellen” (Hervorhebung hinzugefügt). Dieser Punkt kommt auch bei der Unterscheidung zwischen Diskussion und Debatte wieder vor: Als Diskussion bezeichnet Marina, wenn sich die Teilnehmer “gegenseitig ihre Argumente zerlegen”, während die Debatte “anze Meinungen in Betracht” zieht. Das halte ich auch für wesentlich, damit die Meinungsbildung vorankommt. Aber natürlich ist es anstrengender, ganzheitlich andere Meinungen zu kritisieren und seine eigene Meinung darzustellen, als nur einzelne Argumente als Strohmann anzugreifen, und selbst nur einzelne Argumente zu bringen, wie es halt gerade am besten passt. Allerdings erfordert das eine ehrliche Argumentationstechnik und Darstellung der eigenen Argumentation. Wenn das nicht vorliegt, erkennt man es nicht unbedingt gleich – IMO funktioniert das daher am besten mit nicht-synchroner Kommunikation. Denn wer differenziert argumentiert, wird dabei immer langsamer sein als der, der seine Meinung apodiktischer darstellt.

Das Konzept beginnt in Schritt 1 mit dem Ist-Zustand: Diskussionen und Meinungsäußerungen erfolgen über unterschiedlichste Medien, die einzelnen Meinungen ähneln sich, sind aber jeweils leicht unterschiedlich. Hier fehlt mir die deutlich unterschiedliche Qualität bzw. Differenziertheit (und damit Länge) von Meinungsäußerungen. Vielleicht sollten die Buchstaben auch noch unterschiedliche Größe haben (wobei die kleineren Buchstaben in der Regel auch schnörkelloser sein werden …).

Die Überschrift von Schritt 2 lautet “Wiki”, die daneben befindliche Abbildung legt nahe, dass Kongresse, Mumble, AGs und Stammtische ähnliche Meinungen (Meinungsäußerungen?) bündeln. Der Zusammenhang zwischen Überschrift und Abbildung erschließt sich mir nicht auf Anhieb. Ich hoffe, er wird im Abschnitt klarer …

Grundlage dieses Schrittes ist das Debattenportal, dass Meinungen “etwa” in dafür, dagegen, neutral “oder ähnlich” einteilt, oder in inhaltliche Kategorien (“Meinung A, Meinung B und Meinung C”) einteilt. Marina stellt dazu fest: “Dieser Schritt 2 funktioniert auch, wenn der Rest überhaupt nicht funktioniert.” Hier kann ich wiederum nicht zustimmen. Ich halte diese Einteilung für höchst subjektiv. Das gilt schon bei der Einteilung in dafür, dagegen, neutral, die ja auch Marina nur als eine Möglichkeit (“etwa”, “oder ähnlich”) darstellt. Aber auch, wenn wir diese drei Möglichkeiten mal als gegeben ansehen: Eine differenzierte Position wird der Autor vielleicht als neutral ansehen, der, der die Einteilung macht, wird sie aber mit seiner eigenen Position vergleichen und als negativ oder positiv einordnen. Noch schwieriger wird es bei den inhaltlichen Kategorien: Was sind hier überhaupt sinnvolle Kategorien? Wie formuliert man die Zusammenfassungen neutral? Welche Granularität sollen die Kategorien haben? Das sind sehr subjektive und inhaltliche Fragen, keine reine Verwaltungsarbeit. Um es mit Marinas eigenen Worten zu sagen: “‎Die Überführung zweier politischer Standpunkte in einen einzigen politischen Standpunkt ist eine politische und keine sozialpädagogische Aufgabe.” (für eine autorisierte Version dieses Zitats wäre ich dankbar). Vollkommen zustimmen (siehe auch oben) kann ich dagegen der Aussage, dass jeder die Gelegenheit haben muss, “eine Meinung mit allen Prämissen und Konsequenzen darzustellen, bevor jemand widersprechen darf”.

Das hier eine offene Frage ist, erkennt Marina aber auch selbst: “Eine der offenen Fragen ist, wie die Zusammenfassungen ablaufen sollen.” Wie dargelegt, bin ich aber der Aufassung, dass es schon eine offene Frage ist, wie die Einteilung gemacht wird. Sie schlägt vor, dass man hier gründlich nachdenken muss, um Akzeptanz zu schaffen. Ich frage: Warum? Können wir hier nicht auch konkurrierende Zusammenfassungen (und Einteilungen, siehe oben) haben? Hier sehe ich auch einen Bezug zu dem Titelbild dieses Abschnitts, der im Text nicht aufgegriffen wurde: Dort tauchen (neben anderen Foren) Stammtische auf, die Positionen zusammenführen sollen. Aber es gibt ja nicht nur einen Stammtisch, also ist diese Konkurrenzsituation hier immanent.

Aber ich nehme jetzt einfach mal als gegeben an, dass wir irgendwie zu halbwegs trennscharfen Positionen kommen, denn das ist die Voraussetzung für den nächsten Schritt. Dass es hier offene Fragen gibt, er kennt ja auch Marina an.

Als Schritt 3 sieht Marina Liquid Feedback: “Einen in sich relativ konsistenten Antrag verfeinern, verbessern und mehrheitsfähig machen, das kann es super.” Dieser Abschnitt ist recht knapp gehalten und wäre sicher eine vertiefte Darstellung wert. So kaufe ich das jedenfalls nicht – ich habe LQFB leider bisher nur ziemlich unkonstruktiv erlebt … In Schritt 4 werden dann gut ausgearbeitete und konkurrierende Anträge auf einem Parteitag zur Abstimmung gestellt. So weit, so gut und folgerichtig.

Am Ende geht der Artikel dann noch auf Kritikpunkte ein. Einige davon sind für mich persönlich nicht relevant, andere greifen oben schon behandelte offene Fragen (“Wer darf sortieren? Was gilt als Debattenbeitrag?”) auf.

Mein Fazit: Das Konzept bietet eine erste Struktur für den Ablauf der politischen Meinungsbildung. Allerdings habe ich insbesondere bei Schritt 2 Zweifel, ob er — unter Erfüllung der definierten Ziele — operationalisierbar ist. Ich vermute aber, dass es dafür (unter dem Stichwort “peer production” schon einiges an Forschungsansätzen gibt … Aber vielleicht ist Ausprobieren wirklich eine gute Idee. Bis jetzt gibt es das Debattenportal allerdings offenbar noch nicht.

IKEA-Bilderrätsel: FAKTUM-Wandschränke (Korpus)

Regelmäßig ärgere ich mich über die Bilderrätsel von IKEA. Die enthalten zwar in der Tat die meisten Sachen, auf die man achten muss. Bloß worauf man hätte achten müssen, und woran das im Bild zu erkennen gewesen wäre, merkt man meist erst, wenn man etwas falsch gemacht hat.

Wie heißt es doch so schön: 1000 Worte sagen mehr als ein Dutzend Bilder. Insbesondere ist Sprache insbesondere dann direkter verständlich, wenn es darum geht, auf verschiedenen Abstraktionsniveaus wichtige Fakten zu vermitteln. Bei Bildern führt das in der Regel zu regelrechten “Bildersprachen” – bloß dass bei IKEA die Leseanleitung fehlt (anders als beispielsweise bei Bebauungsplänen, wo es die Planzeichenverordnung gibt. Da hat man wenigstens verstanden, dass solche Pläne ab einer gewissen Faktendichte alles andere als intuitiv sind).

Und ich bin mir ziemlich sicher, dass es auch bei IKEA einen Text bzw. eine Liste von Punkten gibt, worauf man achten muss. Der Ingenieur, der das weiß, ist ja vermutlich nicht derjenige, der die Bilder malt – also muss er das diesem irgendwie anders mitteilen. Zweckmäßigerweise also als Text, der damit schonmal in einer Sprache vorliegt. Und an der Stelle bricht dann der grenzenlose Geiz von IKEA durch. Die wenigen Euro (IMO vierstellig pro Anleitung), die eine kundengerechte Aufbereitung dieser Texte und eine Übersetzung kosten würde, will man sich natürlich sparen. Ebenso die wenigen Cent zusätzliche Druckkosten, wobei mir eine Anleitung im Internet vollends ausreichen würde.

Damit genug der Vorrede und des Lamentierens. Damit möchte ich es nämlich nicht belassen, sondern verschiedene IKEA-Anleitungen in normale Sprache übersetzen und dabei zugleich meine Erfahrung einfließen lassen.

Heute geht es los mit dem FAKTUM-Küchensystem, und zwar den Wandschränken, bzw. noch genauer deren Korpus (Türen, Scharniere und Griffe kommen erst noch …). Wie die meisten IKEA-Montageanleitungen gibt es auch diese Anleitung als PDF (959 kB).

Zuerst einige generelle Anmerkungen:

  • Die Anleitung gilt anscheinend für alle FAKTUM-Wandschränke. Jedenfalls war sie bei meinen Schränken in 40×92 cm, 60×70 cm und 80×92 cm jeweils identisch. Das führt dann natürlich auch dazu, dass die Abbildungen in der Regel nicht maßstabsgetreu sind, und auch die Zahl der Löcher für Einlegeböden etc. nicht unbedingt mit der Realität übereinstimmt.
  • Wie üblich, werden die Schränke mit Beschlägen, aber ohne Befestigungsmaterial geliefert. Es gilt der Rat: “Erkundigen Sie sich ggf. im Eisenwarenhandel.”, was ich auch gemacht habe. Die Anleitung weist jedenfalls darauf hin, dass der Kopf der Schrauben flach und nicht spitz zulaufend sein muss. Mir wurden 8/48-Universaldurchsteckdübel von Stabilit sowie 6,0×60-Spanplattenschrauben mit gelbem Kopf empfohlen, die auch gut funktioniert haben. Für Altbau gibt es ggf. noch bessere Dübel sowie Schrauben, die mehr Drehmoment vertragen, die man also fester ziehen kann.
  • Die Anleitung listet als Werkzeug einen Flachschlitzschraubenzieher, einen Kreuzschlitzschraubenzieher, einen Hammer, eine Schraubzwinge und eine Bohrmaschine auf. Der Flachschlitzschraubenzieher sollte recht breit sein – er dient für die runden Einsätze, mit denen die horizontalen Wände an den Seitenwänden festgezogen werden. Der Kreuzschlitzschraubenzieher sollte ganz normal groß sein, besonders viel Drehmoment braucht man da auch nicht. Als Hammer tut es auch irgendeiner – damit schlägt man die Holzstifte fest, außerdem die kleinen Nägel der Rückwand. Schraubzwinge und Bohrmaschine braucht man nur, wenn man zwei Schränke aneinander schrauben will.

Nun zu den einzelnen Schritten der Anleitung:

  1. Auf Seite 6 kommt zunächst eine Fallunterscheidung. Die ist deshalb nötig, weil man für die komplette Serie die gleiche Anleitung nimmt. Offebar gibt es Schränke, bei denen die Rückwand nicht den ganzen Schrank verschließt. Meine drei verschiedenen Modelle gehören aber offenbar nicht dazu, also geht es auf Seite 7 weiter. Zunächst richtet man die beiden Seitenwände am besten nebeneinander aus. Nach innen kommt die Seite mit der Einkerbung. Oben/unten sind die Wände übrigens symmetrisch. Innen liegt dann die Seite, die nachher hinten ist. Dort verläuft jeweils eine Reihe von Löchern für Einlegeböden. Jeweils an den oberen beiden Löchern (warum auch immer da noch ein weiteres Paar Löcher ist …) werden dann die Eckbeschläge montiert, und zwar mit den äußeren Löchern. Mit der Ecke liegen sie dann genau auf der Kante des Holzes auf.
  2. Dann werden 8 Schrauben montiert: Auf jedem Boden oben und unten sowie innen und außen – aber jeweils in das kleinere der beiden Löcher, das ist das, welches weiter innen liegt.
  3. In die anderen Löcher der linken Wand jetzt die Holzstifte einsetzen und mit dem Hammer leicht festschlagen. Dann die beiden anderen Böden (im fertigen Schrank oben und unten) auf die Holstifte und Schrauben setzen, und zwar mit den Löchern nach außen. Oben die restlichen Holzstifte in die größeren Löcher stecken und leicht festhämmern.
  4. Jetzt die rechte Seitenwand umdrehen und auf die Konstruktion aus linker Seitenwand und Böden legen. Leicht festklopfen. Die flachen “Schrauben” in die runden Löcher einsetzen, und zwar jeweils mit der Öffnung zu den dort herausstehenden Schrauben hin – unten also nach unten, oben nach oben. Mit dem Flachschlitzschraubenzieher festziehen (ca. eine halbe Umdrehung).
  5. Jetzt den Schrank nach links kippen, so dass die Beschläge (also die Rückseite des Schranks) nach oben zeigen. Die Rückwand einsetzen, und zwar mit der braunen Seite nach oben (also außen). Damit zeigt die weiße Seite nach innen.
    Die Rückwand zunächst nach oben rechts schieben und mit einem Nagel fixieren. Dabei darauf achten, dass der Nagel weit genug im inneren der Spanplatte sitzt und gerade eingeschlagen wird – sonst kommt er auf der Innen- oder Außenseite wieder raus, was extrem unschön aussieht. Mir wurde übrigens empfohlen, dass man auch kleine Schrauben (von ähnlicher Größe wie die Nägel) nehmen könne – im Gegensatz zur Befestigung mit Nägeln wäre das recht einfach reversibel.
  6. Jetzt die Rückwand nach unten rechts schieben und wieder mit einem Nagel fixieren.
  7. Dann nach unten schieben und unten links mit einem Nagel fixieren.
  8. Jetzt rundherum Nägel einschlagen. Eine Vorgabe für die Abstände gibt es nicht, 5-10 cm sollten passen. Die Zahl der Nägel in der Packung ist dafür auch kein Indikator – die ist bei kleinen und großen Schränken gleich …
  9. Ab diesem Schritt braucht man wirklich zwei Personen – es geht an die Wandmontage der Schränke. Zunächst das Anzeichnen. Eine Person hält den Schrank an die Wand, die andere stellt sich auf eine Leiter und zeichnet an. Wenn es um die absolute Höhe geht: Der Schrank rutscht bei der Montage eher noch runter, so dass die Schraube am oberen Rand des Loches des Beschlags liegt – das sollte man beim Anzeichnen bedenken (also eher oberhalb der Mitte anzeichnen bzw. bohren). Jetzt bohren (gemäß Anleitung der Dübel), Dübel einsetzen und die Schrauben bis auf ca. 1 cm festziehen. Dann den Schrank wieder an die Wand. Man kann ihn gleich “einhängen”, braucht ihn also während des Festziehens der Schrauben nicht unbedingt mit voller Kraft zu halten. Jetzt die kleinen Metallbeschläge aufsetzen, feinjustieren und festschrauben. Dabei darauf achten, dass sich die Beschläge nicht verdrehen. Danach kann man die weißen Abdeckkappen aufstecken. Schließlich könnte man benachbarte Schränke aneinander befestigen. Zwingend ist das aber nicht, und hat sich bei mir auch nicht ergeben.

Nun hat man also leere Schränke ohne Türen an der Wand hängen. Diesen Schritt beschreibe ich, sobald ich damit selbst durch bin.

Bilder mit GPS-Koordinaten versehen

Leider haben Consumer-Kameras ja noch kein GPS (meine Dezember 2009 gekaufte jedenfalls nicht). Aber wenn man ein Outdoor-GPS-Gerät sein eigen nennt, kann man das ja zum Glück recht einfach anderweitig erledigen. So ein Gerät (ich habe ein eTrex Vista HCx von Garmin) läuft mit 2 AA-Batterien ca. 20 Stunden, und man kann es einfach im Rucksack oder der Jackentasche mit sich rumtragen. Dabei zeichnet es jede Sekunde die Position in einer GPX-Datei (eine Datei pro Tag) auf Speicherkarte auf.

Prinzipiell täte es auch ein einfacher GPS-Logger (der dann deutlich kompakter ausfallen könnte), aber das Display ist ganz praktisch. Die Zeit auf der Kamera muss man ja in der Regel manuell einstellen — eine automatische Synchronisation mit GPS oder einer anderen Zeitnormalquelle haben die Dinger nicht. Das könnte man tun, man kann es aber genauso gut lassen. Denn so eine Uhr hat ja auch ein wenig Gangabweichung, beim nächsten Urlaub stimmt es dann schon wieder nicht. Eine Minute Abweichung ist jedenfalls (mir) zuviel, um mich für die GPS-Korrelation darauf zu verlassen.

An dieser Stelle kommt das Display des GPS-Empfängers ins Spiel: Man macht ab und zu (am Anfang und am Ende des Urlaubs beispielsweise …) Fotos von einer als zuverlässig bekannten Uhrzeitanzeige – dafür bietet sich die des GPS-Empfängers an (Beispiele hier und hier). Dann hat man die Kamerazeit (über EXIF-Daten) und die echte Zeit in einem Foto und kann somit die Differenz ermitteln.

Beispiel: Ich hatte zwei Fotos vom GPS-Empfänger gemacht:

  • Auf dem ersten Foto zeigte der GPS-Empfänger 12:04:40 Uhr am 30. Juli 2011 (Europe/Berlin, also MESZ). Nach Ortszeit (in diesem Fall Island, also erfreulicherweise gleichzeitig UTC – es entfällt also die schwierige Entscheidung, welche von beiden ich nehmen soll) ist das 10:04:40 Uhr. Die Zeit der Kamera war 11:06:09 (also vermutlich MEZ, ohne S) am 30. Juli 2010 (sic!). Um von der Kamerazeit auf die richtige Zeit zu kommen, muss man also ein Jahr hinzuzählen, 1 Stunde abziehen, 2 Minuten abziehen und 31 Sekunden hinzuziehen (bzw: 1:29 Minuten abziehen).
  • Auf dem zweiten Foto zeigte der GPS-Empfänger 13:13:10 Uhr am 2. August 2011 (MESZ). Nach Ortszeit/UTC ist das 11:13:10 Uhr. Die Zeit der Kamera war 12:14:38 (MEZ) am 2. August 2010 (sic!). Um von der Kamerazeit auf die richtige Zeit zu kommen, muss man also ein Jahr hinzuzählen, 1 Stunde abziehen, 2 Minuten abziehen und 28 Sekunden hinzuziehen (also 1:28 Minuten, und damit nur eine Sekunde Abweichung zum ersten Foto, die auch Rundungsfehlern geschuldet sein können).

Nachdem wir nun also wissen, wie wir die EXIF-Zeit justieren müssen, können wir diese Änderung umsetzen. Als Tool dafür benutze ich exiv2. Die relevanten Stellen der man-Page lauten:

Benutzung: exiv2 [ Optionen ] [ Aktionen ] Datei ...

Ändert die Exif-Metadaten von Bildern.

Aktionen:
ad | adjust ändert die Exif-Zeitstempel um eine gegebene Zeit. Diese
Aktion benötigt mindestens eine der Optionen -a, -Y, -O oder -D.
[...]

-a time Zeitjustierung im Format [-]HH[:MM[:SS]]. Diese Option wird
nur in Zusammenhang mit der Aktion 'Justieren' benutzt.
-Y yrs Justierung von Jahren in der Aktion "justieren".
-O mon Justierung der Monate in der Aktion 'justieren'.
-D day Jusitierung von tagen in der Aktion "Justierung".

In unserem Fall ergibt das:

exiv2 -Y 1 -a -01:01:28

In diesem Fall ist es herzlich egal, ob man nun -01:01:28 oder -01:01:29 schreibt. Bei größerem Drift sind natürlich ggf. andere Maßnahmen erforderlich. Interpolieren dürfte manuell leider etwas aufwendig werden.

Dieser Befehl muss natürlich auf alle Fotos angewendet werden. Bei mir haben diese die Endung .JPG (nicht .jpg!). Es ergibt sich folgender Befehl:

for i in *.JPG; do exiv2 -Y 1 -a -01:01:28 $i; done

Als nächstes kopiere ich die GPX-Tracks für die entsprechenden Tage ins selbe Verzeichnis wie die Bilder und rufe gpscorrelate-gui auf. Dort füge ich zunächst alle Fotos hinzu. Dort muss man nun leider jede GPX-Datei einzeln auswählen. “Interpolate”, ggf. “Between Segments” ankreuzen, “Correlate Photos” klicken – fertig.

Jetzt haben die Fotos GPS-Koordinaten in ihrem EXIF-Block. Bei Flickr und ähnlichen Diensten erscheinen sie dann in einer Karte (Achtung: Bei Flickr muss man das aus Datenschutzgründen in den Account-Einstellungen vor dem Hochladen aktivieren!).

3G in Island

Wenn ich im Ausland bin, vor allem, wenn es länger als nur ein paar Tage sind, habe ich gerne mobiles Internet via 3G/UMTS. Zum einen ist es sehr praktisch, unterwegs Karten zu haben und Infos über den Ort abrufen zu können, an dem man gerade ist. Und mit Status-Updates auf Google+ kann man auf die Schnelle die Daheimgebliebenen neidisch machen – dank Kamera und GPS im Smartphone. Auch bei eigentlich stationärem Einsatz ist das hilfreich – Internetzugang im Hotel ist oft kostenpflichtig, nur in bestimmten Bereichen (Lobby) verfügbar, oder es sind verschiedene Ports blockiert.

Also habe ich mich für Island nach einem entsprechenden Angebot umgeschaut und bin dabei auf Síminn gestoßen. Der Tarif ist recht preisgünstig, die Netzabdeckung soll gut sein (in dem Zusammenhang: Was ist eigentlich 3G Long Distance? Damit kriegt man wohl auch in der Pampa schnelle Verbindungen, jedenfalls, wenn kein Berg im Weg ist). Verkaufsstellen gibt es durchaus in jedem Ort, allerdings muss man es dorthin dann auch zu Öffnungszeiten schaffen. Rundreise durch die „Wildnis“, ein Feiertag, und recht eingeschränkte Öffnungszeiten (samstags erst ab 10 Uhr, beispielsweise) können einem da schonmal einen Strich durch die Rechnung machen.

Schließlich habe ich es zwei Tage vor Abreise doch noch geschafft, eine entsprechende SIM-Karte zu erwerben. Diese kostet 490 ISK und ist mit einem Startguthaben versehen, das für ca. 500 MB reicht. Im Prinzip ja ausreichend für den Einsatz im Urlaub – wenn nicht dummerweise der Thunderbird auf meinem Notebook auf die Idee gekommen wäre, einen IMAP-Ordner ausgerechnet jetzt zu synchronisieren. Damit war das Inklusivkontingent dann nach einem Tag aufgebraucht. Wie in der Anleitung erläutert wurde ich auch tatsächlich auf eine Seite weitergeleitet, wo ich per Kreditkarte ein 4GB- oder 8GB-Paket für 1990 bzw. 3990 ISK hätte kaufen können. Hätte – wenn die Seite denn eine meiner drei Kreditkarten akzeptiert hätte. Woran es lag, dass das nicht ging, weiß ich nicht. Jedenfalls habe ich hinterher vom Kundendienst noch folgende Auskunft bekommen:

You need to contact our customer support at 8007000. They will help you refill your credits via credit card.

- Leider erst, als ich das Land schon wieder verlassen hatte. Falls jemand ebenfalls Probleme mit der Kreditkartenzahlung hat, kann er das ja mal ausprobieren, und ggf. hier berichten, ob es geklappt hat.

Thunderbird-Addons: Optionen

Heute schauen wir uns, wieder am Beispiel von Quicker Filer 0.5.1, an, wie man in einem Thunderbird-Addon Einstellungen benutzt, die als Preferences persistiert werden.

In der install.rdf heißt es:

<em:optionsURL>chrome://quickerfiler/content/options.xul</em:optionsURL>

Damit wird ein Einstellungsdialog definiert. Standardmäßig wird dieser als Dialogfenster geöffnet. Über die Definition des Content Packages in der chrome.manifest (vgl. dieses Posting) ergibt sich also, dass der Dialog in content/options.xul definiert ist.

Gehen wir das also der Reihe nach durch.

<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>

Hier wird ein Stylesheet eingebunden, und zwar ein recht generisches.

<prefwindow id="quickerfilerPrefWindow" title="Quicker Filer - Options" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
  buttons="accept,cancel" height="550">

Das Fenster ist ein prefwindow, also speziell für Einstellungsdialoge vorgesehen. Es gibt weiterführende Dokumentation, die aber bis auf ein Beispiel und einen Hinweis, wie man so ein Fenster aufruft, keine wesentlichen Infos enthält. Also gehen wir weiter unsere Datei im Detail durch.

Zwei der Attribute sind selbsterklärend: title definiert den Fenstertitel und height setzt die bevorzugte Höhe des Fensters in Pixeln. buttons definiert, welche Schaltflächen angezeigt werden, hier also OK und Abbrechen. Das dürfte üblicherweise eine gute Wahl sein.

  <script type="application/x-javascript" src="chrome://quickerfiler/content/options.js"/>

Hier wird ein Script eingebunden. Es definiert einigige Funktionen, die dann in Event-Handlern aufgerufen werden – dazu also unten mehr.

  <prefpane id="quickerfilerOptions.general.prefpane" label="General" selected="true">

Eine prefpane ist ein Panel, also wohl eine Seite, mit Einstellungen. Der Inhalt kann entweder aus einer gesonderten .xul-Datei geladen oder – wie hier – inline definiert werden.

label definiert eine Beschriftung. Ob es tatsächlich vorgesehen ist, selected direkt zu setzen, bezweifle ich gerade ein wenig …

    <preferences>
      <preference id="extensions.quickerfiler.defaultfolder.text"        name="extensions.quickerfiler.defaultfolder.text"        type="string"/>
      <preference id="extensions.quickerfiler.search.root"               name="extensions.quickerfiler.search.root"               type="string"/>
      <preference id="extensions.quickerfiler.search.root.account"       name="extensions.quickerfiler.search.root.account"       type="string"/>
      <preference id="extensions.quickerfiler.search.root.folder.text"   name="extensions.quickerfiler.search.root.folder.text"   type="string"/>
      <preference id="extensions.quickerfiler.mkdir.enable"              name="extensions.quickerfiler.mkdir.enable"              type="bool"/>
      <preference id="extensions.quickerfiler.debug.enable"              name="extensions.quickerfiler.debug.enable"              type="bool"/>
      <preference id="extensions.quickerfiler.suggestlastfolder.enable"  name="extensions.quickerfiler.suggestlastfolder.enable"  type="bool"/>
      <preference id="extensions.quickerfiler.copysentmessage.enable"    name="extensions.quickerfiler.copysentmessage.enable"    type="bool"/>
    </preferences>

Dieser Block beschreibt die Einstellungen, die in der prefpane geändert werden. Er besteht aus einzelnen preference-Elementen.

Die Attribute sind wieder recht selbsterklärend. name setzt den Namen der zu ändernden Einstellung (hier zweckmäßigerweise identisch zur ID des jeweiligen Elements), type legt fest, von welchem Typ der Wert ist.

    <vbox>

Die vbox dient der Gliederung bzw. Layout-Zwecken.

      <groupbox>
        <caption label="Default folder"/>
        <description>Default folder for instant copy/move</description>
        <textbox id="quickerfiler.defaultfolder.textbox"
          preference="extensions.quickerfiler.defaultfolder.text"
          type="autocomplete"
          autocompletesearch="quickerfiler-autocomplete"
          tabScrolling="true"
          autoFill="true"
          forceComplete="true"
          showcommentcolumn="false" />
      </groupbox>

Die groupbox dient der Gruppierung von Elementen und wird in der Regel mit Umriss gezeichnet. Die caption wird in diesem Umnriss gezeichnet. Die description ist ein Textblock, der einfach angezeigt wird.

Die textbox kann Auto-Vervollständigung und entspricht der im letzten Artikel schon genauer erklärten. Genaueres also dort, und die Erläuterung, wie Auto-Vervollständigung im Hintergrund funktioniert, schieben wir immer noch nach hinten.

      <groupbox>
        <caption label="Search Root"/>
        <description>Determines the scope of the folder list</description>
        <radiogroup id="quickerfiler.search.root.radiogroup"
          preference="extensions.quickerfiler.search.root">

Es folgt eine weitere groupbox mit caption und description. radiogroup definiert eine Gruppe von Radio-Buttons. Es ist die zugehörige preference angegeben. Wohlgemerkt verweist der Wert auf die ID des entsprechenden preference-Elements!

          <radio id="quickerfiler.search.root.allfolders.radio"
            label="All folders"
            value="msgaccounts:/"/>

Hier wird ein einzelner Radio-Button definiert. Die Dokumentation weiß anscheinend nicht so recht, dass das value-Attribut im Zusammenhang mit Preferences eine feste Bedeutung hat. Vermutlich sollte man das mal explizit dokumentieren. label definiert die Beschriftung des Radio-Buttons.

          <hbox>
            <radio id="quickerfiler.search.root.account.radio"
              label="This account"
              value="-- account --"/>

            <hbox flex="1" pack="end">

Hier wird es layouttechnisch interessant. Der Radio-Button wird zusammen mit der menulist in eine hbox gesteckt. Die menulist wird nochmal in eine eigene hbox gesteckt, bei der zwei Attribute gesetzt sind. flex="1" sorgt dafür, dass sie sämtlichen freien Platz verbraucht. pack="end" lässt die menulist nach rechts rutschen. Was mir hier nicht klar ist:

  • Warum ist pack="end" noch nötig, wenn flex="1" angegeben ist? Wie kann in dem Fall noch Platz übrig sein?
  • Warum ist die menulist nochmal in eine hbox verpackt? Man könnte diese Attribute auch auf der menulist spezifizieren. Erzielt das ggf. auch den gewünscht Effekt? Wenn nein, warum nicht? Wenn ja, warum sollte man es so wie hier machen?
              <menulist id="quickerfiler.search.root.account.menulist"
                preference="extensions.quickerfiler.search.root.account"
                sortResource="http://home.netscape.com/NC-rdf#Name"
                sortDirection="ascending"
                datasources="rdf:msgaccountmanager rdf:mailnewsfolders"
                containment="http://home.netscape.com/NC-rdf#child"
                ref="msgaccounts:/" flex="1">

menulist definiert eine Dropdown-Auswahlliste. preference legt wieder fest, welche Einstellung gesetzt wird. flex="1" (nochmal!) sorgt dafür, dass die menulist die komplette Breite ausfüllt.

Die restlichen Attribute (sortResource, sortDirection, datasources, containment, ref) beziehen sich darauf, wie man den Inhalt der Liste dynamisch aus einer RDF-Datenquelle zusammenstellen lässt.

Dazu dient auch das darauffolgende template:

                <template xmlns:nc="http://home.netscape.com/NC-rdf#">
                  <rule nc:ServerType="nntp"/>
                  <rule nc:IsDeferred="true"/>
                  <rule nc:IsServer="true">
                    <menupopup>
                      <menuitem uri="..."
                        value="..."
                        label="rdf:http://home.netscape.com/NC-rdf#Name"/>
                    </menupopup>
                  </rule>
                </template>

Dafür gibt es eine eigene Anleitung, und jemanden, der das alles für großen Schrott hält.

Insofern verschieben wir das lieber auf später – bis ich rausgefunden habe, ob das überhaupt etwas taugt. Jedenfalls erstellt das Template wohl ein menupopup mit vielen menuitems – aber ich verstehe schon nicht, warum/ob da nur ein menupopup, aber mehrere menuitems rauskommen …

Danach wird es zum Glück erstmal unspannend – daran merkt man, dass etwas hängen bleibt … Es werden einige noch offene Elemente geschlossen, und dann kommt eine weitere Radiobox, verbunden mit der Möglichkeit, einen Ordner auszuwählen . Hier kommt wieder die altbekannte Textbox mit Autovervollständigen zum Einsatz. So weit unproblematisch, aber da ist eine Sache, der ich noch auf den Grund gehen muss: In den Einstellungen wird definiert, was die Wurzel für die Suche nach Ordnern ist – es wäre aber unschön, wenn diese Einstellung auch bei der Festlegung der Wurzel zum Tragen kommt. Ich muss dementsprechend mal ergründen, warum sie es nicht tut – bzw., ob sie es vielleicht doch tut – das wäre dann wohl ein Bug.

Danach geht es auch relativ unspannend weiter:

      <groupbox>
        <caption label="Suggest last folder"/>
        <description>Search box fill be filled with the last transfer folder used</description>
        <checkbox label="Suggest last folder" preference="extensions.quickerfiler.suggestlastfolder.enable"/>
      </groupbox>

Hier kommt zum ersten Mal eine checkbox vor. Die hat ein label und ist an eine bestimmte preference gebunden – alles easy. Danach kommen noch weitere checkboxes, die ich wiederum überspringe. Interessant ist in dem Zusammenhang nur die Entdeckung der Einstellung quickerfiler.debug.enable. Unter Linux habe ich nämlich Probleme – vielleicht hilft das ja beim Debuggen.

Jedenfalls ist damit:

  </prefpane>

die erste Seite der Einstellungen fertig. Es folgt die zur Festlegung der Tastenkombinationen.

  <prefpane id="quickerfilerOptions.shortcuts.prefpane"
            label="Keyboard Shortcut"
            onpaneload="sQuickerFilerOptions.onPaneLoad();">
    <preferences>
      <preference id="extensions.quickerfiler.shortcuts.copy.key"
                  name="extensions.quickerfiler.shortcuts.copy.key"
                  type="string"/>

       <!-- ... -->     

      <preference id="extensions.quickerfiler.shortcuts.selfolder.modifiers"
                  name="extensions.quickerfiler.shortcuts.selfolder.modifiers"
                  type="string"/>
    </preferences>

Zu Beginn wird wieder definiert, welche Einstellungen auf dieser Seite geändert werden können. Für diverse Aktionen (copy, move, inscopy, insmove, selfolder) wird jeweils eine Einstellung key und eine Einstellung modifiers. Aus Gründen ist das etwas gekürzt.

onpaneload definiert, dass beim Laden der Seite folgende Funktion ausgeführt wird:

onPaneLoad: function onPaneLoad()
{
  this.updateTreeView();
},

Die Funktion updateTreeView() füllt anscheinend einen Treeview anhand der Einstellungen mit den bis jetzt definierten Tastenkürzeln. Die genaue Funktionsweise schaue ich mir an, sobald ich die UI-Elemente selbst angeschaut habe.

In einer vbox folgt dann folgende groupbox:

      <groupbox>
        <caption label="Available shortcuts"/>

        <tree id="quickerfilerOptions.shortcuts.availableShortcutsTree"
          onselect="sQuickerFilerOptions.onAvailableShortcutsTreeSelect();"
          rows="5" hidecolumnpicker="true" seltype="single">

          <treecols>
            <treecol id="nameColumn" label="Name" flex="1"/>
            <treecol id="shortcutColumn" label="Shortcut" flex="2"/>
          </treecols>

Bis hierhin wurde ersteinmal die Struktur des Baums definiert. Das Hauptelement ist ein tree. onselect wird ausgeführt, wenn eine Zeile im Baum ausgewählt wird. Hier werden wohl die Controls für die Auswahl der Tastenkombination für die entsprechende Aktion gesetzt. Genaueres dann unten, wenn wir uns anschauen, wie der Inhalt aufgebaut ist und initialisiert wird. rows gibt an, wieviele Zeilen gleichzeitig angezeigt werden. Das ist hier gerade die Anzahl der insgesamt existierenden Zeilen. seltype="single" bedeutet, dass es nicht möglich ist, mehrere Zeilen auf einmal auszuwählen. hidecolumnpicker="true" schließlich blendet das “Menü” zum Anzeigen und Verstecken einzelner Spalten aus. treecols enthält einzelne treecol-Elemente. Deren label-Attribut legt die Spaltenüberschrift fest.

trees sind im übrigen keine triviale Angelegenheit, weshalb es dazu auch ein Tutorial gibt. Im allgemeinen Fall können sie aus beliebigen Datenquellen mit großen Datenmengen dynamisch befüllt werden – beispielsweise die Nachrichten in einer Newsgroup. Diese Datenquellen heißen tree views. Netterweise gibt es auch einen vordefinierten treeview, bei dem die Daten aus XUL-Elementen kommen. Das nennt sich dann content tree. Was man dabei beachten muss: Dadurch, dass die Daten durch einen tree view geschleift werden, ist man nicht sehr flexibel, was man hier angeben kann. Es können wirklich nur für jede Tabellenzelle ein Text und ein Icon angegeben werden. Wie es das Tutorial ausdrückt:

Having said that the data to be displayed in a tree comes from a view and not from XUL tags, there happens to be a built-in tree view which gets its data from XUL tags.

Der Rest ist dann unspektakulär:

          <treechildren>
            <treeitem>
              <treerow>
                <treecell label="Copy" value="copy"/>
                <treecell label="disabled"/>
              </treerow>
            </treeitem>
            <!-- vier weitere <treeitem>-Elemente für die anderen Aktionen -->
          </treechildren>
        </tree>
      </groupbox>

Das Hauptelement ist treechildren. Dazu sagt die Doku:

This element is the body of the tree. For content trees, the content will be placed inside this element. This element is also used to define container rows in the tree.

Zum Glück haben wir einen content tree. Wie der Inhalt sonst definiert wird, oder was container rows sein sollen, steht da nämlich leider nicht.

Darin sind dann fünf treeitems, die jeweils eine treerow enthalten. Darin wiederum ist dann jeweils eine treecell pro Spalte. Dabei ist jeweils das Attribut label gesetzt, und in der linken Spalte noch value, offenbar zum Wiederfinden aus Scripts.

Und mit den oben noch zurückgestellten Scripts machen wir jetzt auch weiter. Zuerst die Funktion updateTreeView(), die (unter anderem) beim Laden der Pane ausgeführt wird:

  updateTreeView: function updateTreeView()
  {
    var tree = document.getElementById('quickerfilerOptions.shortcuts.availableShortcutsTree');
    var rowCount = tree.view.rowCount;

    for(var i = 0; i<rowCount; i++)
    {
      var shortcut = tree.view.getCellValue(i, tree.columns[0]);
      var key = document.getElementById('extensions.quickerfiler.shortcuts.'+shortcut+'.key').value;
      var modifiers = document.getElementById('extensions.quickerfiler.shortcuts.'+shortcut+'.modifiers').value;

      if(key != undefined && key != '')
      {
        var text = "";
        if(modifiers)
          text = modifiers.toUpperCase().split(' ').sort().join(' + ');
        if(text)
          text += ' + ';
        text += key.toUpperCase();

        tree.view.setCellText(i, tree.columns[1], text);
      }
      else
      {
        tree.view.setCellText(i, tree.columns[1], 'disabled');
      }
    }
  }

Diese Funktion holt sich zunächst das
-Element und geht alle Tabellenzeilen durch: Die Variable shortcut wird auf den value der Tabellenzelle in der ersten Spalte gesetzt. Dieses Attribut dient also, wie oben vermutet, nur dem “Wiedererkennen”. key und modifiers werden auf den Wert der entsprechenden Preferences gesetzt (ausgelesen aus den jeweiligen preference-Elementen). Falls diese Werte sinnvoll sind, wird daraus ein String zusammengebastelt, der dann in der zweiten Tabellenspalte angezeigt wird.

Interessant dürften noch die aufgerufenen Methoden (und benutzten Eigenschaften) des tree view (tree.view) sein, die im Interface nsITreeView definiert sind:

Ebenfalls bereits bemerkt hatten wir die Funktion onAvailableShortcutsTreeSelect. Die stellen wir auch weiterhin zurück, da sie Elemente bearbeitet, die wir noch nicht angeschaut haben.

In options.xul kommt nun eine weitere groupbox:

<groupbox id="quickerfilerOptions.shortcuts.settingsGroupbox" hidden="true">
  <caption label="Shortcut Settings"/>
  <description>These settings apply to the selected shortcut above</description>

  <hbox>
    <vbox>
      <groupbox>
        <caption label="Key"/>

        <menulist id="quickerfilerOptions.shortcuts.shortcutKey"
          oncommand="sQuickerFilerOptions.onShortcutKeyMenulistCommand();">
          <menupopup>
            <menuitem value="" label="disabled"/>

            <menuitem value="A" label="A"/>
             <!-- ... -->
            <menuitem value="Z" label="Z"/>

            <menuitem value="/" label="/"/>
             <!-- ... -->
            <menuitem value="]" label="]"/>
          </menupopup>
        </menulist>
      </groupbox>
    </vbox>

    <groupbox flex="1">
      <caption label="Modifiers"/>

      <checkbox id="quickerfilerOptions.shortcuts.shortcutModifier.accel"
        label="Accel"
        value="accel"
        oncommand="sQuickerFilerOptions.onShortcutModifierCommand();"/>
      <!-- und dasselbe für alt, control, meta und shift -->
    </groupbox>
  </hbox>
</groupbox>

Zu beachten ist, dass diese groupbox anfangs versteckt ist (hidden="true")! Sichtbar gemacht wird sie per Script (siehe unten), sobald im Treeview ein Befehl ausgewählt wird. Die eigentlichen Controls sind dann eine Dropdown-Liste (menulist), die alle möglichen Tasten enthält, und checkboxes für die verschiedenen Modifier. Das ist jetzt hinreichend langweilig, dass es der geneigte Leser gerne eigenständig in der Dokumentation nachlesen darf. Für Veränderungen sind Event-Listener definiert, auf die ich später noch eingehe. Damit ist die Beschreibung des Fensters dann auch schon zu Ende.

Jetzt also die Funktion, die ausgeführt wird, wenn man ein Kommando auswählt, um dafür ein Tastenkürzel zu vergeben:

onAvailableShortcutsTreeSelect: function onAvailableShortcutsTreeSelect()
  {
    var tree = document.getElementById('quickerfilerOptions.shortcuts.availableShortcutsTree');
    var shortcut = tree.view.getCellValue(tree.currentIndex, tree.columns[0]);

    var keyEl = document.getElementById('extensions.quickerfiler.shortcuts.'+shortcut+'.key');
    var key = "";
    var modifiers = "";
    if(keyEl!=null)
    {
      key = keyEl.value;
      if(key==null)
        key = "";
      else
        modifiers = document.getElementById('extensions.quickerfiler.shortcuts.'+shortcut+'.modifiers').value;
    }

    document.getElementById('quickerfilerOptions.shortcuts.settingsGroupbox').hidden = false;
    document.getElementById('quickerfilerOptions.shortcuts.shortcutKey').value = key.toUpperCase();

    for(var i in this.mModifiers)
    {
      document.getElementById('quickerfilerOptions.shortcuts.shortcutModifier.'+this.mModifiers[i]).checked = (modifiers.indexOf(this.mModifiers[i])>-1)
    }

      this.updateTreeView();
  }

Zunächst wird die aktuell ausgewählte Zeile der treelist bestimmt (tree.currentIndex). Diese Eigenschaft funktioniert nur bei seltype="single", aber das ist hier ja gesetzt. keyEl wird dann auf das preference-Element gesetzt. Ggf. werden aus diesem und dem für die Modifiers die entsprechenden Werte ausgelesen. Dann wird die groupbox angezeigt (hidden wird auf false gesetzt), der passende Eintrag der menulist wird selektiert, und die Chechboxes der entsprechenden Modifiers ggf. angekreuzt.

Bleiben noch die zwei Event-Listener, die auf Veränderungen an diesen Elementen reagieren:

  onShortcutKeyMenulistCommand: function onShortcutKeyMenulistCommand()
  {
    // User selected another shortcut key from the pop up menu,
    // set this as new shortcut key for the current selected command:
    var tree = document.getElementById('quickerfilerOptions.shortcuts.availableShortcutsTree')
    var shortcut = tree.view.getCellValue(tree.currentIndex, tree.columns[0]);

    document.getElementById('extensions.quickerfiler.shortcuts.' + shortcut + '.key').value =
      document.getElementById('quickerfilerOptions.shortcuts.shortcutKey').value;

    this.updateTreeView();
  }

Eigentlich recht selbsterklärend: Wenn eine andere Taste ausgewählt wurde, wird die entsprechende preference gesetzt. updateTreeView() setzt dann für alle Zeilen des treeview die Werte neu (was im Grunde Overkill ist – aber immerhin bleiben die Zeilen an sich erhalten – sonst ginge bestimmt auch der Fokus verloren).

  onShortcutModifierCommand: function onShortcutModifierCommand()
  {
    var tree = document.getElementById('quickerfilerOptions.shortcuts.availableShortcutsTree');
    var shortcut = tree.view.getCellValue(tree.currentIndex, tree.columns[0]);

    var modifiers = [];
    for(var i in this.mModifiers)
    {
      if(document.getElementById('quickerfilerOptions.shortcuts.shortcutModifier.'+this.mModifiers[i]).checked)
        modifiers.push(this.mModifiers[i]);
    }

    document.getElementById('extensions.quickerfiler.shortcuts.'+shortcut+'.modifiers').value = modifiers.join(' ');

    this.updateTreeView();
  }

Auch das ist wieder selbsterklärend: Wenn sich ein Modifier geändert hat, wird die komplette Liste wieder erstellt und in der Preference gespeichert, danach werden die Werte des treelist neu gesetzt.

Damit wären wir auch am Ende dieses Teils unseres kleinen Kurses. Zum Lernen ist dieses Beispiel ja ganz nett – aber um einfach nur eine Tastenkombination zu setzen, ist das doch ziemlich viel Aufwand. Schöner wäre ein eigenes XUL-Control, bei dem man die Tastenkombination einfach eintippen kann. Daher habe ich das in Bug 673669 vorgeschlagen.

Und wieder der obligatorische Hinweis: Code-Schnipsel stammen aus Quicker Filer 0.5.1, sind Copyright (C) 2010 Eivind Rovik und stehen unter GPL (Version 3 oder jede spätere Version).

Properties in Tomcat

Wenn man danach sucht, wie man Properties in Webapps bzw. Servlets lädt, findet man viel Unsinn, bzw. nicht richtig durchdachte oder unvollständige Lösungen. Das hier ist daher ein Versuch, für mich selbst mal einen funktionierenden Ansatz zusammenzuschreiben.

Ausgangspunkt war dieser Blog-Eintrag. Zum Zugriff auf eine Properties-Datei wird dort folgender Code verwendet:

InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("myApp.properties");
Properties properties = new Properties();
properties.load(inputStream);

So weit, so gut. OK, das Laden von Konfiguration über einen Classloader erscheint auf den ersten Blick merkwürdig. Aber sei es drum …

Bloß: Wo lege ich die Konfigurationsdatei jetzt ab, so dass sie auch gefunden wird? Im WAR/AAR jedenfalls nicht – ich will diese Archive ja nicht neu packen, bloß weil sich (Deployment-spezifische) Einstellungen ändern. Ein anderes Blog brachte dann eine Lösung, jedenfalls für Tomcat: Man soll den shared class loader benutzen. Also habe ich meine Datei in $CATALINA_HOME/shared/classes angelegt. Schnell noch die Property shared.loader in conf/catalina.properties angepasst … Doch halt: Die ist schon da und ist leer, was laut Kommentar heißt, dass in $CATALINA_HOME/shared gesucht wird. Für mein Empfinden ist das etwas anderes als $CATALINA_HOME/shared/classes. Naja, egal. Ich hatte keine Lust auf weiteres Ausprobieren und habe die Property einfach neu gesetzt:

shared.loader=${catalina.home}/shared/classes

Das tut jetzt sowohl für Webapps/Servlets als auch für Axis2-Webservices. Prima.

Thunderbird-Addons: Chrome-Manifest, XUL-Overlays

Und weiter geht es da, wo der letzte Teil aufgehört hat: Was steht eigentlich in diesem Chrome Registration Manifest so drin? Beispiel ist wieder Quicker Filer 0.5.1. Die chrome.manifest sieht dort so aus:

content     quickerfiler    content/

overlay chrome://messenger/content/messenger.xul chrome://quickerfiler/content/messengeroverlay.xul
overlay chrome://messenger/content/messengercompose/messengercompose.xul chrome://quickerfiler/content/messengercomposeoverlay.xul

component {1C28D908-9DD7-11E0-B67F-DCD94724019B} components/quickerfilerautocomplete.js
contract @mozilla.org/autocomplete/search;1?name=quickerfiler-autocomplete {1C28D908-9DD7-11E0-B67F-DCD94724019B}

Der Reihe nach:

  • Die erste Zeile ist ein sog. content package.
    Das erste content ist ein Schlüsselwort. quickerfiler ist der Name des Packages. content/ ist ein URI, der auf den Inhalt des Packages zeigt – in diesem Fall ein relativer Pfad. Diese Registrierung sorgt dafür, dass Chrome-URIs der Form chrome://quickerfiler/content/... (man beachte, dass auch hier content auftaucht!) aufgelöst werden können, also die entsprechenden Dateien gefunden werden.
  • Die zweite und dritte Zeile definieren XUL-Overlays, also Erweiterungen von bestehenden Sichten der Benutzeroberfläche. Vorliegend werden das Hauptfenster (3-pane window) und das Fenster zum Verfassen neuer Mails erweitert – dazu aber später mehr.
  • Schließlich folgen noch die Definition einer Komponente und eines sog. Contracts (also einer Schnittstelle mit einer Implementierung). Mehr über Komponenten im allgemeinen und diese spezielle später.

Kommen wir also zu den XUL-Overlays. content/messengeroverlay.xul sieht wie folgt aus:

<?xml version="1.0"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
  <script type="application/x-javascript" src="chrome://quickerfiler/content/messengeroverlay.js"/>
  <keyset>
    <key id="quickerfiler_key_move"    oncommand="sQuickerFilerMessengerOverlay.openDialog('move');" modifiers="alt" key="q" />
    <key id="quickerfiler_key_copy"    oncommand="sQuickerFilerMessengerOverlay.openDialog('copy');" />
    <key id="quickerfiler_key_insmove" oncommand="sQuickerFilerMessengerOverlay.openDialog('insmove');" />
    <key id="quickerfiler_key_inscopy" oncommand="sQuickerFilerMessengerOverlay.openDialog('inscopy');" />
    <key id="quickerfiler_key_selfolder" oncommand="sQuickerFilerMessengerOverlay.openDialog('selfolder');"  modifiers="alt" key="r" />
  </keyset>
</window>

Das Ganze ist, wie schon erwähnt, ein Overlay für messenger.xul, das Hauptfenster von Thunderbird. Dieses Hauptfenster ist ziemlich kompliziert und importiert noch diverse andere XUL-Dokumente. Aber zum Glück kommt es darauf nicht wirklich an – das Overlay definiert einfach Aktionen, die mit Tastenkombinationen ausgelöst werden können und legt fest, welche Javascript-Kommandos in dem Fall ausgeführt werden. Die Ergänzung von Kontextmenüs o.ä. wäre vermutlich sehr viel komplizierter …

Die Bedeutung des script-Elements ist ziemlich offensichtlich, genau wie die von keyset und key. Außerdem gibt es noch ein Tutorial zu dem ganzen Thema. Was vielleicht noch interessant ist, dass nur zwei der key-Elemente auch tatsächlich schon eine Tastenkombination festlegen. Das geschieht zur Laufzeit: content/messengeroverlay.js registriert folgenden Event-Handler:

window.addEventListener('load', function () { sQuickerFilerMessengerOverlay.onLoad(); }, false);

Dieser Listener wird zum Fenster hinzugefügt also ausgeführt, wenn das Fenster (in diesem Fall also das Hauptfenster von Thunderbird geladen ist. sQuickerFilerMessengerOverlay.onLoad() lädt die Tastenkombinationen aus den Preferences und setzt die entsprechenden Eigenschaften der key-Elemente.

Das andere Overlay ist content/messengercomposeoverlay.xul:

<?xml version="1.0"?>

<overlay id="sample" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">

  <script type="application/x-javascript" src="chrome://quickerfiler/content/common.js"/>
  <script type="application/x-javascript" src="chrome://quickerfiler/content/messengercomposeoverlay.js"/>

  <vbox id="addresses-box">
    <toolbox id="quickerfiler.CopyToFolderToolbox">
      <hbox align="center">
        <label value="Copy message to:" />
        <textbox id="quickerfiler.CopyToFolder" flex="1" class="toolbar" disableonsend="true"
          type="autocomplete"
          autocompletesearch="quickerfiler-autocomplete"
          maxrows="14"
          tabscrolling="true"
          autoFill="true"
          forcecomplete="true"
          showcommentcolumn="false" />
      </hbox>
    </toolbox>
  </vbox>

</overlay>

Dieses Overlay erweitert messengercompose.xul.

Die script-Elemente sind wieder selbsterklärend. Allerdings fällt auf, dass weiter unten keine Javascript-Befehle enthalten sind. Warum wird also überhaupt Code aufgerufen? Nun, content/messengercompose.js enthält folgende Befehle (die beim Laden des Skripts ausgeführt werden):

window.addEventListener('load', function () { sQuickerFilerMessengerComposeOverlay.onOpen(); }, false);
window.addEventListener('compose-window-reopen', function () { sQuickerFilerMessengerComposeOverlay.onOpen(); }, true);
window.addEventListener("compose-send-message", function(aEvent) { sQuickerFilerMessengerComposeOverlay.sendEventHandler(aEvent); }, true);

Zur genauen Bedeutung der Events später mehr, wenn ich mir den Code anschaue.

Die taucht bereits im Dokument auf. Das heißt also, das dieses Element vom Overlay erweitert wird – in diesem Fall wird eine toolbox hinzugefügt (unter der Empfängerliste und der Betreffzeile. Warum ausgerechnet eine toolbox, ist mir übrigens nicht klar. Laut Dokumentation dienen diese als Container für toolbars – eine solche taucht hier aber nicht auf (ah, halt: Die Textbox unten hat class="toolbar" – vielleicht hat das ja etwas zu bedeuten). Darin ist dann eine hbox, ein einfacher Container, der der Gruppierung dient. Das label ist ebenfalls uninteressant (außer vielleicht für die Frage, wie das Ganze layouttechnisch funktioniert – dazu vielleicht ein anderes Mal mehr).

Das Spannende ist dagegen die textbox. Gehen wir einfach die Attribute einzeln durch:

  • flex: Dieses Attribut legt fest, wie freier Platz zwischen Elementen verschoben wird. In diesem Fall geht also sämtlicher freier Platz an diese Textbox.
  • class: Dieses Element wird in Stylesheets benutzt. Das deutet darauf hin, dass die Verwendung des toolbox-Elements auch nur layouttechnische Gründe hat.
  • disableonsend: Hier fehlt auf MDN Dokumentation, siehe Mozilla-Bug 670512.
  • type: Gibt den Typ der textbox an, wenn es nicht nur ein simples Textfeld sein soll. In diesem Fall, autocomplete, ist die Sache so kompliziert, dass es gesonderte Dokumentation dazu gibt. Die folgenden Attribute sind alle spezifisch für autocomplete. Im Zusammenhang ist das wohl Thema für einen eigenen Artikel …
  • autocompletesearch: Gibt an, wo die Vorschläge für die Autocompletion herkommen, in diesem Fall von einer speziellen Komponente statt von einer der vordefinierten
  • maxrows: Wie viele Vorschläge werden auf einmal angezeigt, also wie hoch ist das “Menü” höchstens?
  • tabscrolling: In diesem Fall iteriert man mit Tab durch die Vorschläge, anstatt zum nächsten Element zu gehen.
  • autoFill: Es findet automatische Vervollständigung während des Tippens statt.
  • forcecomplete: Wenn man zu einem anderen Element geht, wird die Eingabe zwangsweise zu einem Vorschlag vervollständigt. Das heißt aber offenbar nicht, dass es nicht möglich ist, auch anderen Text einzugeben als einen der Vorschläge.
  • showcommentcolumn: Es werden zu den Vorschlägen keine weiteren Kommentare angezeigt.

Außerdem gibt es noch zwei eigenständige XUL-Dialoge, options.xul und quickerfilerdialog.xul. Auf die werde ich eingehen, wenn ich alles andere durchhabe und dort noch interessante neue Dinge finde. Als nächstes sind erstmal der Javascript-Code der bisher vorgestellten Funktionalität sowie die Komponente für die Autovervollständigung dran. Es wird also unter anderem um XPCOM gehen.

Wieder der obligatorische Hinweis: Code-Schnipsel stammen aus Quicker Filer 0.5.1, sind Copyright (C) 2010 Eivind Rovik und stehen unter GPL (Version 3 oder jede spätere Version).