Technik, Gothic und Anderes

Technik ist Spiel, Gothic ist ernst und Zeit hat man zuviel

Archiv für 'Coding' Kategorie


Moodle Block Resource-Download

Geschrieben von skaldrom am 22. October 2007

Der Moodle Resource Download Block

Moodle Resource Download Block Auf vielfachen Schülerwunsch hin habe ich einen Block für unser Learning Management System Moodle codiert: Den Resource Download Block. Er erlaubt den Download aller Kursdateien und Verzeichnisse in einem ZIP-Archiv. Dieses Zip-Archiv wird wie im Beitrag Zipdateien on-the-fly erstellen mit PHP dynamisch erstellt, da (in der Theorie) jeder Lernende eine andere Kursansicht haben kann.

Einen Block erstellen ist relativ einfach, wenn man dem Block Howto folgt, aber der Teufel liegt wie immer im Detail.

Configwerte

Jeder Block kann verschiedene Konfigurationswerte erfragen und erhalten. Diese unterscheiden sich aber, ob der Block global (pinned, sticky) ist, in welchem er nur von einem Ort aus konfiguruiert wird oder ob er den individuellen Kursen hinzugefügt wurde, wobei dann jede Instanz ihre eigene Konfiguration hat. Ich habe mich für den zweiten Weg entschieden.

Um die Konfigurationsvariablen mit einem Defaultwert zu versehen, muss man sich in der instance_config_print() Methode darum kümmern:

if (!isset ($this->config)) {
    // ... teacher has not yet configured the block, let's put some default values here to explain things
    $this->config->exclusionregexp= block_downloader_default_exclusionregexp();
    $this->config->compression= block_downloader_default_compression();
    $this->config->maxsize= block_downloader_default_maxsize();
}

Die Datei, die das Zip zusammenstellt ist mehr oder weniger ausserhalb von Moodle, da sie nicht “als Block” erscheinen kann. Um da an die Konfigurationsdaten zu kommen, muss man etwas mehr Aufwand treiben. Sie befinden sich base64 codiert in den Tabellen block_instance respektive blocks_pinned für globale Blocks. courseid und instanceid werden dabei vom Link im Block übergeben.

<?php

/**
 * Create the zip on the fly and push it to the browser.
 */


require_once ('../../config.php');
require_once ($CFG->dirroot . '/blocks/downloader/lib/archive.php');
require_once ($CFG->dirroot . '/blocks/downloader/lib/downloadlib.php');
require_once ($CFG->dirroot . '/lib/filelib.php');
require_once ($CFG->dirroot . '/lib/moodlelib.php');
require_once ($CFG->dirroot . '/blocks/downloader/lib/downloadlib.php');

$courseid= required_param('courseid', PARAM_INT); // Course identification
$instanceid= required_param('instanceid', PARAM_INT); // Instance of the block

// Securitycheck
[SNIP]

// Get Config Data
$where= "pagetype = 'course-view' AND visible = 1 AND id=" . addslashes($instanceid);

// Instance?
$blockarr= get_records_select('block_instance', $where . " AND pageid=" . addslashes($courseid));

// Maybe pinned? In this case we have no courseid
if (!$blockarr) {
    $blockarr= get_records_select('block_pinned', $where);
}

if (!$blockarr) {
    error("cannot find block with: " . $where . " AND pageid=" . addslashes($courseid));
    exit ();
}

// Take the first result
$block= array_pop($blockarr);

$configdata= unserialize(base64_decode($block->configdata));

print_r($configdata);

[...]

Dateien pro Kurs abholen

Das Zusammenstellen aller Pfade für Dateien, die ein Benutzer sieht und auf die er Zugriff hat ist echt mühsam. Ich wünsche mir hier ein Bisschen den Servicegedanken: Beispielsweise würde man viel Zeit sparen, wenn der Entwickler mit dem entsprechenden Wissen Funktionen wie can_read($userid, $resourceid) implementieren würde. Zusätzlich wäre man unabhängig vom verwendeten Absicherungsschema. Ich werde das zukünftig in meinen Programmen berücksichtigen.

Reaktionen

Die Community hat - wie meistens bei Moodle - sehr nett auf die Veröffentlichung reagiert. Zwei Tage nach Version 1.0.0 habe ich schon eine Slovakische Übersetzung und diverse Hinweise auf Bugs erhalten.

Teile und geniesse:
  • Technorati
  • del.icio.us
  • MisterWong
  • Digg
  • StumbleUpon
  • blogmarks
  • Furl
  • Simpy
  • Spurl
  • YahooMyWeb

Eingeordnet in Theorie und Schnipsel, Web | Keine Kommentare »

Zipdateien on-the-fly erstellen mit PHP

Geschrieben von skaldrom am 17. October 2007

Das Problem

On-The-Fly An unserer Schule wird Moodle als LMS (Learning Management System) verwendet. Es eignet sich sehr gut um Unterrichtsunterlagen wie Skripts, Aufträge und Präsentationen zu publizieren und den Lernenden auf eine angenehme Art und Weise zur Verfügung zu stellen. In einigen Kursen gibt es sehr viele dieser Ressourcen (Dateien und Verzeichnisse) zum Download und alleine schon das Anklicken und Speichern nimmt einen grossen Teil des zur Verfügung stehenden Zeitbudgets ein.

Einzelne Ressourcen können von der Lehrperson unsichtbar gemacht werden und nicht alle Dateien eines Kurses stehen zum Download bereit. Die Ansicht ist also sehr individuell und kann sich schnell ändern. Die Dateien werden über eine Versionsverwaltung in das System eingespiesen und können sich so ausserhalb des Systems verändern. Leider verunmöglicht dies die offensichtliche Lösung, einfach ein statisches Zip-Archiv zum Download zur Verfügung zu stellen.

Screenshot Moodle

Die Lösung

Das Zip muss also dynamisch (im Speicher) generiert werden bei einem Aufruf. Fündig wurde ich bei der Klasse archive bei phpclasses.org. Neben Zip-Archiven kann sie auch tar’s, gzip’s und bzip2’s erzeugen. Ich habe einige, kleine Erweiterungen vorgenommen, die noch beschrieben werden.

Die Handhabung ist sehr einfach:

// Archivklasse einbinden:
require_once ('lib/archive.php');

// Objekt erzeugen. Das Argument bezeichnet den Dateinamen
$zipfile= new zip_file('Meine Zipdatei.zip');

// Die Optionen
$zipfile->set_options(array (
        'basedir' => "/home/me/toZip/", // Das Basisverzeichnis. Sonst wird der ganze Pfad von / an im Zip gespeichert.
        'followlinks' => 1, // Symlinks sollen berücksichtigt werden
        'inmemory' => 1, // Die Datei nur im Speicher erstellen
        'level' => 6, // Level 1 = schnell, Level 9 = gut
        'recurse' => 1, // In Unterverzeichnisse wechseln
        // Wenn zu grosse dateien verarbeitet werden, kannes zu einem php memory error kommen
        // Man sollte nicht über das halbe memory_limit (php.ini) hinausgehen
        'maxsize' => 12*1024*1024 // Nur Dateien die <= 12 MB gross sind zippen
));

// Alle Dateien im Verzeichnis /home/me/toZip/Stuff hinzufügen
// Alle ".doc" Dateien und alle Ordner im Verzeichnis /home/me/toZip/Letters hinzufügen
$zipfile->add_files(array("Stuff", "Letters/*.doc"));

// Alle ".tmp" dateien in Stuff ausschliessen
$zipfile->exclude_files("htdocs/*.tmp");

// Alle Dateien in ".svn" und "CVS" Verzeichnissen ausschliessen (Regular Expressions)
$zipfile->exclude_regexp_files('.*/CVS|.*/CVS/.*|.*/\.svn|.*/\.svn.*');

// Archiv erstellen
$zipfile->create_archive();

// Archiv zum Download anbieten
$zipfile->download_file();

Änderungen

Ich habe folgende Dinge gegenüber der original archive.php geändert:

  • Mittels exclude_regexp_files() können Dateien auf Grund von Regular Expressions ausgeschlossen werden.
  • Die maxsize Option erlaubt das Ausschliessen von Dateien die grösser sind als die angegebene Zahl in Byte.
  • Verzeichnisse unter Linux werden als Verzeichnisse behandelt (Bug?)
  • exclude_file() prüft, ob eine Datei ausgeschlossen würde

Meine Version kann natürlich auch frei heruntergeladen werden.

Teile und geniesse:
  • Technorati
  • del.icio.us
  • MisterWong
  • Digg
  • StumbleUpon
  • blogmarks
  • Furl
  • Simpy
  • Spurl
  • YahooMyWeb

Eingeordnet in Theorie und Schnipsel | 9 Komentare »

Lehrstellenanbieter und Lehrstellensuchende mit Lehrstellenboerse.ch zusammenbringen

Geschrieben von skaldrom am 8. October 2007

Dies ist ein von trigami vermittelter, bezahlter Eintrag Hinweis: Dies ist ein von trigami vermittelter, bezahlter Eintrag.

Das Web als Plattform

EmployeesDas Web eignet sich ja für vieles… Besonders gut hat es sich in meinen Augen unter Anderem als Plattform um Angebot und Nachfrage zusammenzubringen bewährt. Im Folgenden geht es um die Website http://www.lehrstellenboerse.ch. Dieser Beitrag ist mir sehr wichtig, da meine Lehrzeit unglaublich gut war und in einer sehr labilen Zeit (Pubertät und so…) wahrscheinlich so manch Übel in meinem Leben verhindert und mir viel Gutes ermöglicht hat. Als Berufsschullehrer wünsche ich allen jungen Menschen, die dies möchten, eine Lehrstelle nach ihrem Geschmack und Fähigkeiten und begrüsse jede nur erdenkliche Aktion um ihnen dies zu ermöglichen.

Background

LehrstellenboerseDie Website ist aus einem Projekt von HSG Studenten hervorgegangen und wird heute von einem gemeinnützige Verein betreut. Ausser einer bezahlten 100% Stelle für den Geschäftsführer wird der Verein ehrenamtlich geführt und die Website mit Hilfe von Sponsoren unterhalten.

Die Lehrstellen werden nicht nur auf dem Web publiziert, sondern auch in Printmedien wie dem St. Galler Tagblatt, der Jungfrau Zeitung und dem Taxi-Magazin abgedruckt.

Das Angebot

Für Lehrstellen- und Praktikasuchende

Momentan werden 4228 Lehrstellen aus den verschiedensten Bereichen und Kantonen sowie 14 Praktikas (unter Anderem ein Bloggerpraktikum :-) ) angeboten. Es gibt zwei Wege um eine passende Lehrstelle zu finden:

  • Über die Suche (Branche, Beruf, Kanton, Region, etc)
  • Einen Assistenten, der Schritt für Schritt zur Lehrstelle oder zum Praktikum führt.

Noch nicht implementiert, aber in Planung, ist die Filterfunktion, die ein Mail versendet wenn ein Angebot aufgenommen wird, das zum entsprechenden, registrierten Benutzer passt.

Die meisten Lehrstellen sind sehr detailliert beschrieben und ein Link zur Anbieterfirma erleichtert das Informieren.

Für Lehrstellenanbieter

Laut Geschäftsbericht wurden Firmen mit Auszubildenden direkt angeschrieben. Die Lehrstellenverantwortlichen erhalten einen Login der ihnen erlaubt, die Lehrstellen selbst zu verwalten.

Mit einem Onlinebewerbungstool das den Firmen zur Verfügung gestellt wird, können Interessenten sich sofort bewerben und den Firmen wird eine gewisse Vorselektion erleichtert.

Bemerkungen

Technisches

Die Website ist für meinen Geschmack auf den ersten Blick etwas unübersichtlich. Es dauert aber nicht lange bis man das Konzept geblickt hat und dann geht die Suche sehr schnell von der Hand.

Lehrstellenboerse

Sobald die erwähnte Filterfunktion zum Erhalt von Emails implementiert ist, kann sich der interessierte Suchende sehr einfach und komfortabel auf dem Laufenden halten. Ein RSS-Feed wäre vielleicht auch noch nett und nicht allzu aufwändig zu implementieren.

Ebenfalls ist geplant, dass Lehrstellensuchende ihr Profil erfassen und so direkt von Lehrfirmen angeschrieben werden können.

Nicht technisches

Dass die Lehrlingsverantwortlichen die Stellen selbst unterhalten ist eine gute Idee. In der Praxis zeigt sich jedoch, dass dies vielbeschäftigte Leute sind und so gibt es einige Lehrstellen, die schon länger nicht mehr aktuell sind. Das ist etwas schade und trübt den Blick auf die über 4000 Angebote. Vielleicht könnte man hier technisch ein automatisches Ausblenddatum zur Verfügung stellen.

Das Huhn-Ei Problem des Webs wurde elegant gelöst *bravo*. Wenn es nicht genug Angebot hat gibt es nicht genügend Interessenten und umgekehrt und so kommen viele gute Ideen nicht in Schwung. Hier wurden die Lehrfirmen aktiv aquiriert und damit steht ein grosses Angebot zur Verfügung. Vielleicht könnte einiges an Aufwand und Doppelspurigkeiten eingespart werden, wenn die Anstrengungen kanalisiert und eventuell die Datenbestände zentralisiert würden. So verfolgt zum Beispiel we-are-ready in Etwa die gleichen Ziele.

Fazit

Schöne und sinnvolle Sache im öffentlichen Interessen! Bitte unterstützen..!

Teile und geniesse:
  • Technorati
  • del.icio.us
  • MisterWong
  • Digg
  • StumbleUpon
  • blogmarks
  • Furl
  • Simpy
  • Spurl
  • YahooMyWeb

Eingeordnet in Webapplikationen | 1 Kommentar »

Gutscheine per Internet: Nützliches im Doppelpack

Geschrieben von skaldrom am 1. October 2007

Dies ist ein von trigami vermittelter, bezahlter Eintrag Hinweis: Dies ist ein von trigami vermittelter, bezahlter Eintrag.

Die Idee…

Gift …ist genial und genial einfach! Gutscheine für die verschiedensten Dinge werden über das Web angeboten. Das Einkaufen als solches ist durch das Web schon sehr viel schuhsohlensparender geworden, da die physikalische Bewegung der Körpermasse von Ladenlokal zu Ladenlokal nicht mehr notwendig ist. Bei vouchernet.ch findet man nun über 70 Anbieter bei welchen Gutscheine käuflich erworben werden können auf einer Seite vereint.
Will man Gutscheine verschenken, so sollte dies wohlüberlegt sein: Zum Einen sollte es nicht als fehlenden Einsatz oder mangelnde Fantasie interpretiert werden können (auch wenn genau das der Grund für ein Gutscheinkauf war :-) ) und zum Anderen muss man sich bewusst sein, dass der monetäre Wert des Geschenks von der/dem Beschenkten direkt abgelesen werden kann. Andererseits gibt es Dinge wie ein Kinoeintritt oder ein Essen in einem schönen Restaurant die nur sehr schwer, mit viel Papier und eventuell unter Einwirkung von Zwang eingepackt werden können.

Das Angebot

Auswahl

Die Anbieter der Gutscheine sind sehr breit gestreut: Regionale Unternehmen wie zum Beispiel eine Waschanlage in Wohlen oder ein Chocolatier aus Cham/Zug, aber auch national bekannte und verbreitete Betriebe wie McDonalds oder der WWF, das Alpamare, das Technorama oder das Verkehrshaus bieten Gutscheine feil. Interessante Ideen wie ein schweizerischer Museumspass oder eine Minimal Techno/Minimal House DJane können den eher unkreativen Schenker inspirieren. Sollte man mal nicht beim Umziehen helfen wollen, so kann man immerhin Umzugskisten von Homegate verschenken…
Über 70 Unternehmen sind eine solide Basis, können aber regional natürlich nicht alles abdecken.

Gutscheinarten

Die meisten Gutscheine werden über die Website bestellt und finden den Weg per herkömmlicher Schneckenpost zu einer beliebigen Adresse. Der Versendezeitpunkt kann frei ausgewählt werden und streicht somit schon wieder eine Pendenz von der Liste des Schenkers.
Vouchernet.ch preist sich als e-mässigen-Last-Minute-Geschenke-Retter an. So richtig ist das aber noch nicht möglich, da nur 8 Anbieter Gutscheine per Email anbieten.
Einige Gutscheincodes können bei den Webshops der Anbieter verwendet werden, was natürlich extrem e-mässig-web2.0ig rüberkommt. Die überwiegende Mehrheit wird aber im entsprechenden Ladenlokal gegen weltlich Gut getauscht. Das macht sicher bei vielen Dingen auch Sinn, da ein BigMac per Post und ein Haarschnitt im Paket einfach nicht dasselbe sind wie wenn sie frisch vom Produzenten kommen…

Die Website

vouchernet.ch Screenshot

Navigation und Usability

Der ganze Webauftritt ist klar und strukturiert aufgebaut. Ein grosses *bravo* für den Verzicht auf unnötige Schnörkel und die klare Navigation. Das ganze Design vermittelt Seriosität und Klarheit. Auch der ungeübte Webeinkäufer wird sich bis zum Kauf des Gutscheines durchschlagen können. Eine schenkerfreundliche Suchfunktion (für wen, Kanton, Preisrahmen) ist eine grosse Hilfe für den noch nicht festgelegten Schenker. Einzig die Gutscheinsvoransicht beim Hoovern über den Gutscheintitel ist zwar schön und illustrativ, aber etwas versteckt, wenn auch in der Hilfe beschrieben (liest die jemand?).

Was mir dann eher schwer gefallen ist, ist die Registrierung. Man könne bei einem Wettbewerb mitmachen und erhalte Exklusivangebote. Wollen wir doch! Die Site will dann aber plötzlich frech viele Privatdaten von mir. Adresse, Geburtsdatum und woher man Vouchernet kennt sind Pflichtfelder. Sicher interessant für das Marketing, aber herauspressen aus dem Anwender wirkt eher unsympathisch (im Gegensatz zum Rest der Site und den Texten, die sehr sympathisch rüberkommen!). Dann akzeptierte er auch noch meine .info Emailadresse nicht. Hey, .info gibts schon seit 2001!.
Als ich endlich alle meine Reichtümer und einen Gegenwert für meine Informationspreisgabe (jaa, meine Info ist was wert, ich will was dafür!) einsammeln wollte, wurde mir eine Seite “Eigene Daten ändern” präsentiert. Darauf sind zwei voreingestellte Passworteingabefelder mit ihrem Inhalt hinter den bekannten Sternchen versteckt. Allerdings waren die beiden Passwörter nicht gleich lang. Häh? Mit Click und Clack auch diese Hürde gemeistert und dann kommt heraus, dass der Wettbewerb abgeschlossen ist (obwohl mir noch viel Glück gewünscht wurde) und die Exklusivangebote “in Kürze” aufgeschaltet werden. Naja, hmm, tja, nett ist das nicht.

Technisches

Technisch hat mich die Seite eher verwundert. Sie funktioniert einwandfrei, aber einige kleine Dinge sind etwas im Argen. Die Unternehmer sind in der Promotingphase für die Website und möchten eine grössere Bekanntheit erlangen. Dafür müssten sie aber auch etwas SEO (Suchmaschinenoptimierung) betreiben, damit sie der verzweifelte Möchtegernschenker auf dem allmächtgen Google auch findet. Fehlerhaftes HTML, nur zwei Keywords (eines davon noch falsch geschrieben), kein Favicon, keine robots.txt, etc sorgen halt nicht für Spitzenplätze. Bin sehr gespannt ob dieser Eintrag für das Wort “Gutschein” noch vor vouchernet.ch in den Suchresultaten erscheint ;-) . Auf der positiven Seite ist ein Inserat bei Google mit den richtigen Keywords und ein del.icio.us Engagement zu verzeichnen. Auch der RSS-News-Stream funktioniert gut.

Für den Benutzer zeigen sich auch einige Probleme: Die Trennstrich in den Beschreibungstexten müssten entfernt werden, sonst erge- ben sich fremd- artige Gebilde bei einer and- eren Browser- breiten.

Kleinere Details wie ein “Click to activate and use this control” (vom Flash) wenn man im MSIE über dem Logo verweilt, sind dann eher unwichtig (dochdoch, man kann Flash so einbetten dass dieser Hinweis nicht kommt). Interessant ist, dass Microsoft diese Meldung auf Grund eines verlorenen Rechtsstreites einfügen musste…

Ohne Hinweis:


Mit Hinweis (nur MSIE grösser gleich 6.0):

Testkauf

Der Testkauf war eigentlich direkt und einfach, bis ich gesehen habe, dass die Versandkosten für einen Gutschein für einen Kindereintritt ins Technorama (12 Franken) satte 4 Franken betragen. Hui, 4 Hämmer (??!!) das tut weh. Ist da noch der Druck dabei? Seit wann kostet eine A-Post-Marke 4 Franken? Nö, ich bezahle keine 33% Aufpreis.

Dafür wäre das Bezahlen einfach: Rechnung oder Postcard. Kreditkarte ist vorgesehen und wird bald integriert werden.

Wenn die Gutscheine wirklich so aussehen wie auf dem Preview, dann machen sie echt was her.
Gutschein fürs Technoarama

Bei einigen Gutscheinen sind allerdings die Texte etwas irritierend.
Beispielsweie:

Mit diesem Gutschein schenken Sie Vergnügen pur.

oder

Dieses Geschenk passt immer. Noch dazu hat es Format: praktisch, ultradünn, modern.

implizieren nicht gerade Bescheidenheit des Schenkers. Der Gutschein ist ja für den Beschenkten, und der schenkt nicht und soll selbst beurteilen, ob es immer passt.

Für Anbieter

Anbieter können zwischen drei Modellen wählen: vouchernet.ch bietet auf Wunsch Druck der Gutscheine und Inkasso an. Der Preis bewegt sich um 1 sFr. pro Tag plus 1,75% Umsatzbeteiligung wenn für ein Jahr gebucht wird und eine Preisstaffelung für längerfristige Buchungen. Interessant ist auch die Verkaufsgarantie, die greift, wenn nicht mindestens ein Gutschein pro Monat verkauft wird. In diesem Falle gibt es eine Gratis-Verlängerung.

Fazit

Eine geniale Idee, seriös umgesetzt. Kleinere technische Unfeinheiten halten einem nicht vom Einkauf ab, höchstens vielleicht die happigen Versandkosten.
Firmen könnten bei vouchernet.ch Gutscheine kaufen und den Mitarbeitern mit Jubiläen kalkulierbar, richtig getimed etwas schenken, dass sie wahrscheinlich auch brauchen können. Göttis und Gotten finden nützliche Dinge, auch wenn sie sich in der Welt der Pubertierenden nicht mehr unbedingt auskennen und inspirierend ist es allemal. Ich werde die Site für kommende Weihnachten in sicher in meinen e-Bummel mitaufnehmen.

Teile und geniesse:
  • Technorati
  • del.icio.us
  • MisterWong
  • Digg
  • StumbleUpon
  • blogmarks
  • Furl
  • Simpy
  • Spurl
  • YahooMyWeb

Eingeordnet in Webapplikationen | Keine Kommentare »

Schere, Stein, Papier: Bewertungen im Kreis

Geschrieben von skaldrom am 27. September 2007

Round n RoundDie Regeln von Schere, Stein, Papier sind weitherum bekannt. Zwei Mitspieler zeigen gleichzeitig ein Symbol, danach wird ausgewertet: Schere wird von Stein geschlagen → Stein wird von Papier geschlagen → Papier wird von Schere geschlagen. Die Gewinne sind im Kreis herum (zirkulär wie der geneigte Klugscheisser sagen würde). Diese Kreisbewertung gibt es oft, auch wenn mir jetzt überhaupt kein Beispiel dazu einfällt :-D .

Nehmen wir an, wir müssten die Auswertung programmieren und bestimmen, wer gewonnen hat. Die Symbole seien Konstanten und auf Ziffern gemappt:

define("SCHERE", 0);
define("STEIN", 1);
define("PAPIER", 2);

Insgesamt gibt es 9 Fälle (ich kann 3 Symbole zeigen, mein Mitspieler kann auf jedes mit 3 anderen Symbolen reagieren: 3 mal 3 macht 9). Der Programmierer, der nach SLOCs bezahlt wird würde also 9 ifs schreiben.

Mein Ziel ist es aber, nur 3 ifs zu benötigen für die 3 Resultate: Spieler 0 gewinnt, Spieler 1 gewinnt und unentschieden.

Die erste Reduktion ist trivial: Wenn beide dasselbe Symbol zeigen, dann ist unentschieden. Damit sind wir auf 7 ifs.

Weiter hilft eine Faustregel des alten Informatikers: Wenn etwas im Kreis herum geht, ist fast immer ein Modulo beteiligt.

Die Grundüberlegung: Wenn der Spieler 0 um 1 darunter liegt (beispielsweise STEIN=1 unter PAPIER=2) dann hat Spieler 1 gewonnen. Und nun muss das ganze halt noch im Kreis herum: PAPIER liegt 1 unter SCHERE.

Wenn nicht unentschieden ist, und auch Spieler 1 nicht gewonnen hat, ja dann, hmm, hat wohl Spieler 0 gewonnen!

Code!

define("SCHERE", 0);
define("STEIN", 1);
define("PAPIER", 2);

[...]
    if($symbolFromPlayer0==$symbolFromPlayer1) {
        // Unentschieden:
    } elseif( ($symbolFromPlayer0+1)%3 == $symbolFromPlayer1) {
        // Player1 hat gewonnen
    } else {
        // Player0 hat gewonnen
    }
[...]

Jou, juhu, hat geklappt! Wir haben unsere 3 ifs…

Teile und geniesse:
  • Technorati
  • del.icio.us
  • MisterWong
  • Digg
  • StumbleUpon
  • blogmarks
  • Furl
  • Simpy
  • Spurl
  • YahooMyWeb

Eingeordnet in Theorie und Schnipsel | Keine Kommentare »

ClickHeat: Klick, zeig Dich, Du bist umzingelt!

Geschrieben von skaldrom am 16. September 2007

Heatmaps

Spannende Methode zur Analyse des Benutzerverhaltens von Websites sind sogenannte Heatmaps. Sie speichern die Koordinaten aller Klicks auf eine Website und stellen sie mit “Hitzepunkten” dar:
Beispiel Heatmap

Crazy Egg

CrazyEgg in ActionEine “kommerzielle” Möglichkeit zum Erstellen solcher Heatmaps ist CrazyEgg. Die Basisvariante ist gratis und reicht eigentlich aus für kleine Websites. Viel Web 2.0-Ajax und eine einfache Bedienungsführung machen es zu einem angenehmen Tool. Es ist möglich verschiedene “Tests” zu fahren mit unterschliedlichem Aufbau der Website und diese Durchgänge dann zu vergleichen.
CrazyEgg hat es voll im Griff die Klicks den richtigen Links zuzuordnen. Keine leichte Aufgabe wenn man bedenkt, dass jeder Besucher mit einer anderen Auflösung ankommt. Zur Auswertung stehen folgende Darstellungen zur Verfügung:

Overlay (Siehe Bild)
Zeigt die Attraktivität der Links in absoluten und relativen Zahlen
List
Eine Liste aller Links mit ihrer Popularität
HeatMap
Eine schöne Heatmap halt…
Confetti
Klicks anzeigen an Hand des Referrers (der Website von welcher die Besucher gekommen sind)

ClickHeat

ClickHeat ist eine freie Implementierung für Heatmaps. Sie kann auf dem eigenen Server betrieben werden und ist somit sehr geeignet für Kontrollfanatiker wie ich einer bin. Die Installation ist denkbar einfach:

  1. Downloaden der Applikation.
  2. Alles an einen Ort auf dem Server entpacken
  3. Im Browser dieses Verzeichnis aufrufen (Beispielsweise http://www.yoursite.com/clickheat/index.php)
  4. Alles korrekt einstellem
  5. Den Javascriptcode im Footer der Webseiten einbinden
  6. Abwarten, Tee trinken, Sackhüpfen und danach wieder das ClickHeat Verzeichnis aufrufen
  7. Sich freuen!

Einige Tips noch dazu:

  • Man kann und sollte die eigenen Klicks ausblenden (erster Menüpunkt im Hauptmenü).
  • Beim Generieren vom Javascript kann angegeben werden, wie die Linkdaten unterschieden werden:
    • Mit Keyword. Hier muss aber auf jeder Seite der Javascriptcode angepasst werden! Hben alle Seiten denselben Footer, werden wild alle Klicks gesammelt, auch wenn jede Seite anders aufgebaut ist.
    • Nach Titel oder Pfad: Damit kann schön nach einzelnen Seiten unterschieden werden.
  • Um zu checken, ob die Datensammlung funktioniert, die Seite mit dem Parameter ?debugclickheat aufrufen. Also beispielsweise http://www.yoursite.com/index.php?debugclickheat. Dies zeigt ein nettes Overlay mit vielen Informationen.
  • Unbedingt das Layout der Site konfigurieren (beim Icon Icon zur Layoutangabe), da er ansonsten die Klickpositionen ein Bisschen durcheinander bringt. Dieses Blog beispielsweise ist Fixed left and right menus, liquid content.

Resultate

Was habe ich für dieses Blog für Erkenntnisse gewonnen?

  1. Die Suche wird benutzt und hat somit ihren prominenten Platz oben rechts verdient.
  2. Es wird ziemlich oft auf das “lead-in” Bild geklickt. Hmmm, was dies zu bedeuten hat muss ich mir noch überlegen. Was erwarten die Besucher wenn sie draufklicken?
  3. Es wird auch auf den kleinen Link skaldrom oberhalb der Beiträge geklickt. Ich habe den Link darum weg von der Homepage (was wohl eher verwirrend war) auf die Schreiberling-Seite umgebogen.
  4. Die Ads scheinen in einem guten Bereich mit vielen Clicks rundherum zu sein.

Weiteres

t-error (error terror?) hat auch über ClickHeat geschrieben. Inspirierend war auch wieder einmal der ProBlogger Beitrag.

Teile und geniesse:
  • Technorati
  • del.icio.us
  • MisterWong
  • Digg
  • StumbleUpon
  • blogmarks
  • Furl
  • Simpy
  • Spurl
  • YahooMyWeb

Eingeordnet in Blogging, Web, Webapplikationen | Keine Kommentare »

Observer Pattern in PHP mit der SPL

Geschrieben von skaldrom am 12. September 2007

Das Observer Pattern

Observed!Normalerweise läuft es mir kalt den Rücken runter wenn ich das Wort Pattern höre. Ich will keine Fassaden, Dekoratöre und Factories in meinen Applikationen (ausser für Anwendungen in der entsprechenden Problemdomäne). An Patterns lastet der Geruch von CRC-Karten, Pair-Programming, millionenzeiliger, selbstgeschriebener Frameworks die Dinge vereinfachen sollen die man nicht begriffen hat und anderen Dingen an, die ich nicht so mag :-) .
Eine Ausnahme ist das Observer-Pattern (was hat es wohl angestellt, dass es auch Pattern geschimpft wird?). Grundsätzlich geht es darum, dass eine Klasse für Daten oder Ereignisse zuständig ist (das Subject). Andere Klassen können sich als Beobachter (Observer) anmelden und werden bei Statusänderungen informiert. MVC (Model-View-Controller) macht rege davon Gebrauch, indem das Model die Daten verwaltet (Subject) und Views (Observer) die Daten darstellen. Eine View könnte beispielsweise für eine Baumansicht verantwortlich sein, während sich eine andere View um eine listenartige Ansicht kümmert. Ändern sich nun die Daten, so werden beide benachrichtigt und können ihre Ausgaben anpassen. So ist es einfach, neue Klassen hinzuzufügen die auf Statusänderungen reagieren können müssen.

Das Observerpattern mit SPL

SPL ist die Standard PHP Library die ab PHP 5.0 dabei ist, stetig weiterentwickelt wird und ohne zusätzlichen Aufwand/Code verwendet werden kann. Sie erlaubt ein paar ganz nette Gags, aber das soll hier nicht Thema sein.

Ohne SplObjectStorage

Leider sind Beispiele für die PHP Implementierung etwas knapp gesät. Das PHP-Wiki ist offline und auch sonst gibt es neben PHP Avancado nur wenig Code. Die offizielle SPL-Seite hat zwar viel Doku aber leider auch keine Beispielimplementierung.

Darum hier etwas Code. Die Klasse Ticker generiert jede Sekunde einen Tick. Einige Observer beobachten sie und reagieren darauf.

Die erste Version arbeitet ohne SplObjectStorage, damit das Prinzip klar wird. Man muss sich somit selber um die Speicherung der Observer kümmern.

<?php
/**
 * Observer pattern without SplObjectStorage
 *
 * Little example because there are not much of them on the net.
 * It implements a Model-View relationship.
 * Taken from <a href="http://blog.oncode.info">Technik, Gothic und Anderes</a>.
 * Needs at least PHP 5.1
 * 
 * @see http://www.php.net/~helly/php/ext/spl/interfaceSplObserver.html
 * @see http://phpavancado.net/comment/reply/410
 * @see http://wiki.cc/php/?title=SplObserver
 * @author Skaldrom Y. Sarg
 */


/**
 * The Class we are observing
 *
 * This class generates a tick every second.
 */

class Ticker implements SplSubject {
    protected $numTicks= 0; // Stores the ticks
    protected $observers= array (); // Stores all observers

    /**
     * Needed to register observers
     *
     * Note the typehinting here.
     */

    public function attach(SplObserver $observer) {
        $this->observers[]= $observer;
    }

    /**
     * Needed to unregister observers
     *
     * Note the typehinting here.
     */

    public function detach(SplObserver $observer) {
        // Not implemented here
    }

    /**
     * Notify all Observers that we have changed
     */

    public function notify() {
        foreach ($this->observers as $obj) {
            $obj->update($this);
        }
    }

    /**
      * Get the number of ticks
      */

    public function getNumTicks() {
        return $this->numTicks;
    }

    /**
     * The ticker itslef
     */

    public function doTicks() {
        while ($this->numTicks < 10) {
            sleep(1); // Sleep for one second
            $this->numTicks++;
            echo "\nTicker: Added a Tick (" . $this->numTicks . ")\n";
            $this->notify(); // Tell all observers we have changed     
        }
    }
}

/**
 * Observer that counts the ticks
 */

class Observer1 implements SplObserver {
    public function update(SplSubject $subject) {
        echo "Observer 1: Wow, a Tick!!! We are at tick number " . $subject->getNumTicks() . "\n";
    }
}

/**
 * Observer that calculates the number of ticks until 10
 */

class Observer2 implements SplObserver {
    public function update(SplSubject $subject) {
        echo "Observer 2: TickTick, there are " . (10 - $subject->getNumTicks()) . " ticks left until 10\n";
    }
}

$ticker= new Ticker(); // The subject to be observed

$observer1_1= new Observer1(); // First observer of type 1
$ticker->attach($observer1_1);

$observer1_2= new Observer1(); // Another observer of type 1
$ticker->attach($observer1_2);

$observer2= new Observer2(); // Observer of type 2
$ticker->attach($observer2);

// Start the run
$ticker->doTicks();
?>

Und die Ausgabe (im Sekundentakt):

Ticker: Added a Tick (1)
Observer 1: Wow, a Tick!!! We are at tick number 1
Observer 1: Wow, a Tick!!! We are at tick number 1
Observer 2: TickTick, there are 9 ticks left until 10

Ticker: Added a Tick (2)
Observer 1: Wow, a Tick!!! We are at tick number 2
Observer 1: Wow, a Tick!!! We are at tick number 2
Observer 2: TickTick, there are 8 ticks left until 10
[...]

SplObjectStorage

SplObjectStorage nimmt uns einiges ab. Er implementiert aber das Interface SplSubject nicht. SplObjectStorage hat eine Implementierung von attach() und detach() und SplSubject auch, aber eine andere :-( . Nun muss man halt zusammenleimen, sonst wärs noch kürzer…

<?php
/**
 * Observer pattern with SplObjectStorage
 *
 * Little example because there are not much of them on the net.
 * It implements a Model-View relationship with the help of the SPL object storage class.
 * Taken from <a href="http://blog.oncode.info">Technik, Gothic und Anderes</a>.
 * Needs at least PHP 5.1
 * 
 * @see http://www.php.net/~helly/php/ext/spl/classSplObjectStorage.html
 * @see http://wiki.cc/php/?title=SplObjectStorage
 * @author Skaldrom Y. Sarg
 */


/**
 * The Class we are observing
 *
 * This class generates a tick every second.
 */

class Ticker extends SplObjectStorage implements SplSubject {
    protected $numTicks= 0; // Stores the ticks

    /**
     * Needed to register observers
     *   
     * This method glues plObjectStorage::attach() and SplSubject::attach(). Otherwise you will get something like:
     *  "Fatal error: Declaration of SplObjectStorage::attach() must be compatible with that of SplSubject::attach()"
     */

    public function attach(SplObserver $observer) {
        // Duplicate-Checking is done in SplObjectStorage::attach()
        parent :: attach($observer);
    }

    /**
     * Needed to unregister observers
     *   
     * This method glues plObjectStorage::detach() and SplSubject::detach(). Otherwise you will get something like:
     *  "Fatal error: Declaration of SplObjectStorage::detach() must be compatible with that of SplSubject::dettach()"
     */

    public function detach(SplObserver $observer) {
        // Duplicate-Checking is done in SplObjectStorage::attach()
        parent :: detach($observer);
    }

    /**
     * Notify all our observers
     *
     * The observers are stored in the SplObjectStorage and this class implements an iterator.
     */

    public function notify() {
        foreach ($this as $observers) {
            $observers->update($this);
        }
    }

    /**
      * Get the number of ticks
      */

    public function getNumTicks() {
        return $this->numTicks;
    }

    /**
     * The ticker itslef
     */

    public function doTicks() {
        while ($this->numTicks < 10) {
            sleep