-
Objektorientierte Programmierung in Javascript
erstellt am 29.11.10
Javascript hat ja im Allgemeinen den Ruf nur zum Hacking zu gebrauchen zu sein und sonst nicht viel zu taugen,
dabei ist es eigentlich besser als sein Ruf. Ich denke das Problem ist, dass Javascript in den meisten Projekten zunächst nur
in kleinen Snippets benutzt wird, um Webseiten um bestimmte Effekte anzureichern. Diese Snippets wachsen immer weiter und enden
irgendwann in einem großen unstrukturierten Codebrei. Es geht jedoch auch anders!Ich habe mich intensiv damit ausseinader gesetzt, wie man in Javascript nicht nur Mini-Funktionen implementieren kann, sondern in einem objektorientierten Ansatz auch größere Strukturen darin umsetzen kann. Ich versuche mal mein Wissen in diesem Artikel komprimiert zusammenzufassen.
Erstellung und Benutzung
Die grundsätzliche Frage: wie ist überhaupt die Syntax um Klassen in Javascript zu definieren und wie lassen sich unterschiedliche Sichtbarkeiten erreichen?
Das folgende Trivialbeispiel sollte dafür bereits einen gutes erstes Verständnis vermitteln.
function OOPExampleClass(parameter) { var privateVar = null; this.publicVar = null; function privateMethod() { return 'bla'; } this.publicMethod = function() { return 'blubb'; } } var uut = new OOPExampleClass('some parameter'); uut.publicMethod();"Von aussen" ist der Zugriff damit geklärt, leider muss man beim Zugriff innerhalb der Klasse etwas aufpassen, denn es muss zwischen dem Zugriff auf public und private Variablen und Methoden unterschieden werden. Private Variablen und Methoden lassen einfach durch Angabe des Namens verwenden, public Variablen und Methoden benötigen den Bezug zu this.
function aclass { ... function amethod() { privateVar = 'abc'; this.publicVar = 'abc'; privateMethod(); this.publicMethod() } ... }Eine Alternative ist es die Klasse in Javascript Object Notation (JSON) zu definieren. Man gewinnt dadurch eine bessere Lesbarkeit, kann jedoch keine unterschiedlichen Sichtbarkeiten darin spezifizieren.
var jsonObj = { anArr : [ 'a', 'b', 'c' ], otherObj : { i : 'bla' }, name : 'blubb', getName : function() { return this.name; } } jsonObj.anArr.length; // -> 3) jsonObj.otherObj.i; // -> bla jsonObj.getName(); // -> blubbZwar lässt sich dieser Ansatz auch mit der hier vorgestellen Syntax kombinieren, das Resultat ist dann jedoch das komplette Durcheinander, weshalb man sich für eine Variante entscheiden sollte. Einzig die Kurzfassungen für die Instanzierung von Arrays (var anArr = [];) und Objekten (var obj = {};) sollten auf jeden Fall verwendet werden, egal für welche Option man sich entscheidet.
Konstruktor
Um das Verhalten eines Konstruktors zu erhalten kann innerhalb der Klassendefinition prinzipiell an jeder Stelle zusätzlicher Code eingefügt werden. Im folgenden Beispiel ist exemplarisch an mehreren Stellen ein Log-Befehl eingefügt, die beim Instanzieren ausgeführt werden.
Um nicht im kompletten Chaos zu versinken bevorzuge ich jedoch einen expiziten "Konstruktor-Block", den ich auch in Klammern absetze und einrücke. Da auf öffentliche Variablen und Methoden nur zugegriffen werden kann, wenn sie vor dem Konstruktor stehen, sollte man ihn erst am Ende einfügen.
Man beachte im Beispiel den Zugriff auf die Variable parameter innerhalb des Konstruktors, die als Parameter beim Instanzieren übergeben wird.
function OOPExampleClass(parameter) { // code here ... console.log('foo'); var privateVar = null; this.publicVar = null; function privateMethod() { ... } // ... or here console.log('bar'); this.publicMethod = function() { ... } // "constructor" { privateVar = parameter; this.publicVar = parameter; this.publicMethod(); privateMethod(); } }Anonyme Funktionen
Kompliziert wird es erst beim Zugriff innerhalb der Klasse. Für den Zugriff auf public Variablen und Methoden muss man immer ein this hinzufügen, in anonymen Funktionen zeigt dies jedoch auf etwas anderes. Damit der Zugriff dennnoch funktioniert, gibt es einen kleinen Hack: es wird eine neue Variable that als Synonym für this deklariert und dann über diese Variable zugegriffen.
... var that = this; var bla = null; this.blubb = function() { bla = function() { this.foo(); // -> error that.foo(); // -> works } bla(); } this.foo = function() { console.log('it works!'); } ...Vererbung
Ein wichtiges Werkzeug für das objektorientierte
Programmieren ist die Vererbung. Um beispielhaft zu erläutern, wie dies in Javascript realisiert werden kann, setze ich eine einfache
Hierarchie von Items in Javascript um. Jedes Item soll die Methode getColor()
implementieren, im Bild stellen die Pfeile extends Beziehungen dar.Die Umsetzung dieser Hierarchie ist recht einfach möglich, wie der folgende Code-Abschnitt zeigt. Wichtig ist hierbei, dass der prototyp der Objekte immer auf den Parent-Typ gesetzt wird. Unschönerweise geschieht dies leider ausserhalb der Klassendefinition.
function Item() { this.getColor = function() { return 'no color'; } } function RedItem() { this.getColor = function() { return 'red'; } } RedItem.prototype = new Item(); function GreenItem() { this.getColor = function() { return 'green'; } } GreenItem.prototype = new Item(); function MintItem() { this.getColor = function() { return 'mint'; } } MintItem.prototype = new GreenItem();Statische Methoden
Um die einzelnen Items ausseinanderzuhalten gibt es den instanceof Operator, mit der der Typ einer Variable überprüft werden kann. Für das Beispiel wird eine Klasse mit einer statischen Methode implementiert, die Items mit einem Grünton erkennt.
function Colorizer() {} Colorizer.isShadeOfGreen = function(item) { if(item instanceof Item) { if(item instanceof GreenItem) { return 'green: '+item.getColor(); } else return 'no green: '+item.getColor(); } else return 'no item'; } Colorizer.isShadeOfGreen(new Array()); // -> no item Colorizer.isShadeOfGreen(new RedItem()); // -> no green Colorizer.isShadeOfGreen(new GreenItem()); // -> green: green Colorizer.isShadeOfGreen(new MintItem()); // -> green: mintÜberladen von Methoden
Leider ist es nicht möglich, die Typhierarchie zu nutzen um Methoden zu überladen, da Javascript nur schwach typisiert ist. Immerhin lässt sich durch einen kleinen Workaround dieser Mechanismus emulieren.
function Overloader() { this.dispatch = function(obj) { if(obj instanceof RedItem) return dispatchRed(obj); else return dispatchElse(obj); } function dispatchRed(aRed) { return "dispatchRed"; } function dispatchElse(aElse) { return "dispatchElse"; } } (new Overloader()).dispatch(new RedItem()); // -> dispatchRed (new Overloader()).dispatch(new GreenItem()); // -> dispatchElseDiese Technik lässt sich auch nutzen um eine variable Anzahl von Parametern zu unterstützen.
function ParameterCount() { this.count = function() { switch(arguments.length) { case 0: return count0(); case 1: return count1(); default: return countElse(); } } function count0() { return 0; } function count1() { return 1; } function countElse() { return -1; } } (new ParameterCount()).count(0); // -> 0 (new ParameterCount()).count('a'); // -> 1 (new ParameterCount()).count('a', 'b'); // -> -1Abstrakte Methoden
Für public Methoden ist es sehr einfach abstrakte Methoden zu verwenden. Im folgenden Beispiel wird eine Template Method deklariert, die von einer anderen Methode verwendet wird und für jede erbende Klasse implementiert werden muss.
function AbstractClass() { this.callPublicAbstract = function() { return this.publicAbstract(); } this.publicAbstract = function() { throw new Error('you have to implement "publicAbstract"'); } } function ConcreteClass { this.publicAbstract = function() { return 'pubAbst'; } } ConcreteClass.prototype = new AbstractClass(); var bla = new ConcreteClass(); bla.callPublicAbstract(); // -> pubAbstLeider habe ich noch keine Möglichkeit gefunden, dies auch für private Methoden zu ermöglichen, da hier das Überschreiben in den Kindklassen nicht möglich ist. Um das Überschreiben zu erzwingen, wird standardmässig ein Fehler geworfen.
Fehlerbehandlung
Ähnlich wie in anderen Programmiersprachen, ist es auch in Javascript möglich Fehler über Exceptions (bzw. bei Javascript über Errors) zu behandeln. Es bietet sich an, eigene Fehlerklassen von der Elternklasse Error erben zu lassen. Zur Behandlung können in einem catch jedoch nur alle auf einmal gefangen werden, sodass innerhalb des catchs eine Typunterscheidung getroffen werden muss.
Fehler, die nicht behandelt werden sollen, können einfach wieder geworfen werden.
function MyError() {} MyError.prototype = new Error(); function OOPExceptions() { this.throwError = function() { throw new MyError(); } this.execAndCatch = function(fkt) { try { // execute some code, that might throw an error this.throwError(); } catch (e) { if(e instanceof MyError) { return 'error:mine' else throw e; } } }Gibt es dazu noch mehr zu sagen? :)
Fazit
Ich habe versucht in diesem Artikel einen grundlegenden Eindruck zu vermitteln, wie in Javascript objektorientiert programmiert werden kann. Auch wenn die Möglichkeiten des Programmierers im Vergleich zu anderen Programmiersprachen stark eingeschränkt sind, denke ich, dass der objektorientierte Ansatz zu wesentlich besserem Javascript-Code führt, der insbesondere auch deutlich wartbarer ist.
Ich bin mir sicher, dass dieser Artikel der Thematik nicht ansatzweise gerecht wird, aber ich hoffe einfach, dass ich damit einige Vorurteile gegenüber Javascript abbauen und andere Webentwicker ermutigen konnte, sich die Möglichkeiten einmal näher zu betrachten.
-
And the oscar goes to… Jabber!
erstellt am 17.11.10
Die Erreichbarkeit per Instant Messaging
ist ja eine Bürde der heutigen Zeit. Die Anbieter häufen sich (ICQ/AIM, Skype, Yahoo!, ...) und jeder behauptet
der einzig wahre und wirklich beste Messenger zu sein.Egal, wie die Vorteile des einzelnen Produkts aussehen mögen, eins haben alle kommerziellen Produkte gemein: man kann nur mit Leuten dieses Netzwerks sprechen. Nun werden einige sagen, dass das kein Problem ist, da ein Multi-Protokoll-Client doch alle Protokolle unterstützt, ich halte das jedoch für eine Lösung an der falschen Stelle.
Besonders Skype stellt hier ein zusätzliches Hindernis dar, da keine offene Implementierung des Protokolls existiert und man daher auf den originalen Skype-Client angewiesen ist. Der lässt sich dann immerhin in viele andere Clients integrieren, aber bitte, warum sollte ich mir denn zwei IM-Clients installieren?
Dummerweise habe ich auch eigene Anforderungen an meinen IM-Client. Ich nutze mehrere Computer parallel und noch dazu die unterschiedlichsten Betriebssysteme. Desweiteren will ich die IM-Logs auch im Nachhinein noch lesen können, um sie als Nachschlagequelle nutzen zu können. Aus diesen Anforderungen ergeben sich leider einige Probleme.
- Config Die Config der einzelnen Dienste muss auf allen Rechnern parallel gepflegt werden.
- Log Man kann das IM-Log nicht auf einfache Weise zwischen den Computern syncen.
- Client-Software Ich muss einen Client wählen, der alle nötigen Protokolle unterstützt.
- Interoperabilität Die unterschiedlichen Lösungen für alle Betriebssysteme müssen es erlauben ein gemeinsames Log zu pflegen.
Die Anforderungsliste mag für jeden Benutzer anders aussehen und daher existieren diese Probleme nicht für jeden. Für mich waren sie allerdings so dringlich, dass ich mir weitergehende Gedanken dazu gemacht habe.
Meine Wahl
Ich stelle nun mal die Frage nach den Aufgaben eines IM-Clients. Ich sehe hier in erster Linie das Autauschen von Textnachrichten. Video-/Voicechats wären nett, aber nicht notwendig, dafür gibt es andere gute Lösungen. Auch für den Dateiaustausch gibt es bessere Alternativen. Ein Benutzermagnet kommerziellen Anbieter besteht aus kleinen Minispielchen, die sie dem Nutzer kostenfrei anbieten, hierauf kann ich allerdings komplett verzichten.
Durch die Beschränkung auf diese minimalen Anforderungen an ein IM-Protokoll habe ich die größte Auswahlmöglichkeit. Ich habe mich für XMPP (formals Jabber) entschieden, da es ein offenes Protokoll ist, durch sog. Transports aber auch um die Unterstützung für andere Protokolle erweitert werden kann. Ich bin somit nicht an einen Hersteller gebunden und habe noch dazu die freie Wahl bei den verwendeten Clients, da diese nur Jabber unterstützen müssen.
Da Jabber ein dezentrales Protokoll ist, kann man sich ohne weiteres einen eigenen Server dafür aufsetzen. Ich habe mich dafür entschieden, da ich für meine "Logging-Problematik" gerne das Logging der Gespräche auf dem Server durchführen würde. Ein weiterer Schritt, um den Client zu entlasten.
Im Prinzip kann ich so einen zentralen Multi-Protokoll-Server bereitstellen, den ich sehr einfach von überall ansprechen kann. Im Vergleich zu dem Multi-Protokoll-Client erhalte ich mir sehr hohe Freiheiten bei der Wahl des Clients, und auch die Config wird vereinfacht, da ich nur einen einzelnen Jabber-Account konfigurieren muss.
Der Server
Es gibt einige offene XMPP-Server Implementierungen, ich habe mich für mein Projekt für Openfire
entschieden. Der Server ist in Java implementiert und es gibt etliche Erweiterungen aus der Community.Für den Betrieb benötigt man eine Java JRE und eine Datenbank. In meinem Fall habe ich die JRE von IcedTea benutzt und eine MySQL Datenbank eingesetzt. Die Installation ist absolut straight forward, in der Config Datei trägt man die Zugangsdaten ein, alles weitere lässt sich über ein Webfrontend konfigurieren. Viel mehr gibts hierzu wirklich nicht zu sagen.
Für den ICQ Transport benutze ich das Kraken IM Gateway Plugin. Hier muss ICQ aktiviert werden und die Login-Details der einzelnen Nutzer eingetragen werden. Danach kann man alle ICQ Kontakte als Jabber-Kontakte der Form <icq-nummer>@icq.<server> hinzufügen. Die ICQ-Kontakte werden nach wie vor auf dem ICQ-Server gepflegt und tauchen nicht im Roster des eigenen Servers auf.
Praktischerweise kann Openfire bereits von Haus aus alle Gespräche mitschreiben, wenn man es in der Server-Config aktiviert. Ich musste mir nur noch ein kleines Frontend in PHP zusammenhacken, um auf die gespeicherten Gespräche zugreifen zu können. Ich habe hierfür in der Datenbank noch eine separate Tabelle angelegt, in der ich Kontakte zusammenführen kann, die ich über unterschiedliche Adressen (z.B. ICQ und Jabber) erreichen kann, sodass beide Unterhaltungen zusammengeführt werden und diese nur einmal in der Liste auftauchen.
Das grundsätzliche Problem besteht weiterhin, dass ich nur IM-Protokolle sprechen kann, die von Openfire durch Plugins unterstützt werden. Dies sind jedoch eine ganze Menge und eigentlich alle wichtigen Protokolle, deren Format halbwegs offen ist, werden unterstützt. Andere proprietäre Protokolle werden von mir einfach boykottiert. Wenn Skype meint, die Benutzer fest an den eigenen Client zu binden, sollen sie das tun, aber ohne mich.
Es gibt ja offensichtlich genug Leute, die sich an sowas nicht stören, mit denen kann ich dann halt nicht chatten...
-
Tipps und Tricks für Subversion
erstellt am 12.10.10
Obwohl ich in der letzten Zeit sehr viel Kontakt zu alternativen
Versionskontrollsystemen habe, setze ich bei eigenen Projekten immernoch
Subversion ein und bin auch sehr zufrieden damit. Nach etlichen Jahren lerne
ich allerdings noch Neues.Es ist offensichtlich, dass man über das Webfrontend direkt im Repository browsen kann und dort Zugriff auf die abgelegten Dateien erhält.
https://<host>/<svn>/
Es ist ebenso möglich gezielt auf einzelne Tags zuzugreifen.
https://<host>/<svn>/tags/<tag>/
Nicht direkt offensichtlich ist, dass man über das Webfrontend auch gezielt auf unterschiedliche Revisionen zugreifen kann.
https://<host>/<svn>/!svn/bc/<revision>/
Sicher sind dies nicht die absoluten Neuigkeiten und mit ein bisschen googlen gelangt wohl jeder an diese Information. Ich musste nun aber schon einige Male von Unterwegs gezielt auf etwas zugreifen und musste jedesmal neu nach dem Format der URLs suchen, daher lege ich sie nun ein für alle Mal in meinem Blog ab.
-
Postfix statt sSMTP
erstellt am 26.09.10
Mein vServer läuft nun bereits ein paar Tage (bzw. Monate..) und ich habe mich
bisher erfolgreich davor gedrückt das Mailsystem in Betrieb zu nehmen. Da ich gerade dabei bin,
eine kleine Applikation zu programmieren, die auch Mails schicken soll, konnte ich mich so langsam
nicht mehr davor drücken.Das problematischste Teil dabei basierte auf meinem (DNS-)Setup, denn ich nutze den vServer explizit nur als Webserver, da ich für meine Mails lieber bezahlten IMAP-Space verwende. Für den DNS bedeutet dies, dass bei meinen Domains die MX-Einträge auf die Mailserver des Mailhosters zeigen, die A-Einträge aber auf meinen eigenen vServer.
Mein Plan ist, dass der vServer keinerlei Mails lokal ausliefert (und erst Recht keine von aussen annimmt), sondern einfach alles an eine explizite Email-Adresse weiterleitet. Ich hatte erst versucht, dies mit sSMTP umzusetzen, dem Standard-MTA unter Gentoo, dieser scheint aber die MX-Einträge nicht auszuwerten, folglich liefe es nicht so, wie ich mir das vorgestellt hatte. Da ich schon ein mittelgroßes Mailsystem mit Postfix betreut hatte, war ich nicht weiter Kontaktscheu und habe einfach den MTA gewechselt.
Auch wenn die Konfiguration bei Postfix deutlich umfangreicher ist, war es nicht kompliziert dieses Szenario umzusetzen. Der folgende Config-Ausschnitt zeigt die elementaren Einstellungen, die nötig waren, es fehlen einige Pfadangaben bzw. einige systemspezifische Optionen, diese lassen sich aber der entsprechenden Default-Config entnehmen.
# /etc/postfix/main.cf myhostname = <hostname> mydomain = $myhostname inet_interfaces = localhost mynetworks_style = host unknown_local_recipient_reject_code = 550 alias_database = hash:/etc/mail/aliases virtual_alias_maps = hash:/etc/postfix/maps/virtual relayhost = <mailhostname> smtp_use_tls = yes smtp_tls_security_level = encrypt smtp_tls_CApath = /etc/ssl/certs/ smtp_sasl_auth_enable = yes smtp_sasl_password_maps = hash:/etc/postfix/maps/smtp_auth smtp_sasl_security_options = noanonymous
Hierzu kommen noch drei Maps, in denen verchiedene Informationen abgelegt werden. Die /etc/mail/aliases ist unabhängig von Postfix und ist dafür verantwortlich, dass systemweit verschiedene Mailadressen auf "root" gemappt werden. In /etc/postfix/maps/virtual habe ich den eigentlichen Forward für root angelegt.
# /etc/postfix/maps/virtual root <mailaddress>
In der /etc/postfix/maps/smtp_auth werden die Zugangsdaten für meinen Mailhoster eingetragen.
# /etc/postfix/maps/smtp_auth <mailhostname> user:password
Wenn man am Ende noch dran denkt, alle Maps mit einem postmap <file> neu zu hashen, sollte bereits alles funktionieren. Alles in allem weniger Arbeit als das Schreiben dieses Blog-Eintrags.
-
Hello World! (of Warcraft) in LUA
erstellt am 06.07.10
Um meinem Trial-Account noch etwas Gutes abgewinnen zu können, habe ich mich an mein erstes eigenes Addon für World of Warcraft gemacht. Mein erster Schritt dabei war es, in dem frei verfügbaren Onlinebuch Programming in LUA zu stöbern und einen Eindruck von der Sprache LUA zu bekommen, bevor ich mich mit der verstümmelten Version beschäftige, die mir die World of Warcraft API bereitstellt.Für einen einfachen Start habe ich mein Addon direkt auf das Ace Framework aufgesetzt. Damit werden zwar etliche Details erstmal verborgen, die man als Addon-Entwickler trotzdem kennen sollte, allerdings gab es hierfür einfach das beste Getting-Started Tutorial. Für meine Zwecke hat das auf jeden Fall völlig ausgereicht :D
Hilfreich waren auch noch etliche Posts aus Foren, die man so nebenbei aufschnappt. Es hilft hier der gleiche Tipp, wie sonst auch beim Programmieren: Such nach Beispielen und schau, wie es die anderen machen.
Die WoW API bietet etliche Funktionen an, mit denen nahezu das komplette Spiel gesteuert werden kann. Um auf die Umwelt zu reagieren, kann man sich als Addon auf bestimmte Events registrieren. Nachdem ich das obligatorische "Hello World!" Programm geschrieben hatte, dass sich beim Start im Chat verewigt, habe ich mein bescheidenes Addon durch viel Trial&Error so erweitert, dass es beim Zonenwechsel im Chat den Namen des neuen Bereichs schreibt.
Da ich die letzten Tage viel GUI Programmierung in Java hinter mir habe, hat es mich interessiert, wie man in der LUA WoW API Oberflächen gestalten kann. Auch hierfür bietet Ace eine Lösung: es besitzt ein Widget-System, das im Prinzip keine Wünsche offen lässt, noch dazu gibt es auch hierzu ein gutes Tutorial in deren Dokumentationsbereich. Mein ohnehin schon sinnfreies Addon wurde somit auch noch um eine komplett überflüssige Konfigurationsoberfläche erweitert, die aus mehreren Knöpfen, Feldern und Checkboxen besteht :D Durch ein Callback-System lassen sich Aktionen triggern, die dann mit den Formularinhalten irgendwelche Dinge machen.
Sehr hilfreich bei der Entwicklung ist das Addon BugSack mit seiner integrierten Oberfläche "!BugGrabber", denn ohne Toolsupport verschluckt WoW Fehler in der Ausführung von LUA Skripten. Dieses Addon ermöglicht es im Fehlerfall die Stacktraces auszulesen und die Fehlermeldungen anzuzeigen. Ohne diese Hinweise ist es nahezu unmöglich ein Addon zu entwickeln, weil man nie weiss, was überhaupt schiefläuft, wenn etwas nicht funktioniert.
-
Der Gamer von heute lässt spielen
erstellt am 01.07.10
Ich habe ja vor geraumer Zeit bereits einschlägige Erfahrungen in dem MMO World of Warcraft sammeln können. Ich war dabei auch immer ein braver Zocker, der nie geschummelt hat und sämtliches Gefarme selbst absolviert hat, das einem von Blizzard so aufgebürdet wurde.Obwohl ich inzwischen nicht mehr spiele, verfolge ich doch noch mehr oder weniger aktiv die Neuigkeiten, die sich so um die nächste große Erweiterung "Cataclysm" ranken. Hierbei ist mir die Neuigkeit ins Auge gestossen, dass mit Patch 3.3.5 die Anti-Cheat Software "Warden" aktualisiert wurde und ab sofort Schummler noch einfacher gefunden werden können.
Ich war Neugierig, weil ich von Freunden bereits erstaunliche Dinge über die verfügbaren Hacks und Bots gehört habe und dachte mir "Bevor das Ding rauskommt, probierste es mal aus!". Gesagt getan, ein schicker Bot war schnell gefunden. Da ich einen Mac zum Zocken verwende (ja, eigentlich ein Widerspruch in sich :D), hat sich der "Pocket Gnome" angeboten. Da ich keine Lust habe meinen "Main-Acccount" zu verlieren, habe ich noch fix nen 10 Tage Trial Account erstellt, dann konnte es losgehen.
Beim ersten Start ist man von der Komplexität von "Pocket Gnome" schier überwältigt, da hilft es erstmal in dessen Forum zu stöbern. Ganz einfach erklärt besteht die Konfiguration des Bots aus drei Teilen: einer "Behaviour, einer "Route" und einem "Profile". Für den Anfang finden sich im Forum etliche Beispiele, die man in den Startgebieten einsetzen kann. Wenn der Bot erstmal läuft, versteht man nach und nach, wie man ihn besser machen kann.
In einer Route kann man verschiedene Wegpunkte eintragen, die der Bot dann nacheinander abläuft, dies lässt sich im Falle des Todes auch mit einem "Corpse Run" verbinden, in dem sich der Bot selbstständig die Leiche wiedersucht. Im Profile kann man verschiedene Einstellungen festlegen, z.B. ob Gegner geplündert werden sollen, etc. In einer Behaviour kann man sehr detailierte Regeln aufstellen, was der Bot vor, im und nach dem Kampf tun soll.
Ich war zuerst skeptisch, wie gut das funktioniert, aber nachdem ich die Startschwierigkeiten überwunden hatte und verstanden hatte, wie man das Tool bedient, war ich begeistert. Ich hab den Bot an vier Stellen farmen lassen, jedesmal eine eigene Route erzeugt und nach und nach die Behaviour verbessert. Nach einem Tag war ich bereits Level 20 und damit am Maximum des Trial-Accounts angelangt.
Im Endeffekt war es rein wissenschaftliches Interesse, mal zu schauen "wie das so geht". Ich kann verstehen, dass viele Leute Bots einsetzen um sich dem Dauergefarme von Blizzard entgegenzustellen. Aber auch wenn Gold und Ruf sicherlich reizvoll sind, geht durch das "Botten" eine Menge Spielspass verloren. Ich hoffe, dass Blizzard mit dem neuen Warden nachlegt und Bots in Zukunft möglichst komplett unterbinden kann.
-
Task Liste für PHP Projekte in Eclipse
erstellt am 26.04.10
Ich nutze zum Arbeiten hauptsächlich Eclipse als Editor, sowohl für Java, insbesondere aber auch für PHP Projekte. Bei Java arbeite ich viel mit TODO Kommentaren, die ja praktischerweise in einer Task List zusammengefasst werden. Genau das wollte ich nun auch in meinen PHP Projekten nutzen...Ich benutze das PDT und war etwas verwundert, dass die TODO Kommentare zwar in Javascript-, HTML- und CSS-Dateien funktionieren, aber ebensolche in PHP -Dateien ignoriert wurden. Meine Suche im Internet führte zwar zu einigen andern Posts, die dieses Problem schilderten, aber im Endeffekt ergab die Suche nicht sonderlich viel Fruchtbares... aus der Erfahrung heraus ist die meist ein Zeichen, dass man selbst etwas falsch macht. Hilft einem halt trotzdem nicht weiter... Laut PDT FAQ sollte das auch einfach funktionieren, es gibt in den Settings auch nicht sonderlich viel, was man da falsch einstellen kann. Ich hatte erst die Task Tags in Verdacht und danach die Content Types, bei denen PHP nämlich fehlt, beides war jedoch ein Holzweg und kostete nur Zeit.
Richtig erstaunt war ich, als ich mal testweise ein neues PHP Projekt angelegt habe... da hat das alles direkt out-of-the-box funktioniert. Nach etwas Analyse konnte ich das Problem darauf zurückführen, das meinen Projekte schlichtweg die PHPNature fehlt, die in der .project nachgetragen werden muss. Dies liegt offensichtlich an meinem bisherigen Workflow, da ich neue Projekte immer erst im SVN anlege, um sie dann initial in den Workspace auszuchecken. Mal schauen was mehr Arbeit ist: das ab sofort immer andersrum zu machen oder jedes Mal händisch die Nature nachzutragen...
-
Caching Probleme des Apache unter VirtualBox
erstellt am 23.04.10
Ich habe zum Entwickeln eine Linux-VM laufen, auf der die ganzen Standard Webserver laufen, insbesondere auch den Apache HTTP Server. Um meine Entwicklungsdaten mit Timemachine (Hail to OSX!) sichern zu können, liegen die Datenverzeichnisse der Datenbanken und auch das Document Root des HTTP Servers in meinem OSX Dateisystem und werden per Shared Folder in das Linuxsystem eingebunden. Soweit sogut.Nun bin ich vor kurzem von VMWare zu VirtualBox gewechselt und habe seitdem derbe Probleme gehabt, weil der Apache Änderungen an Dateien nicht wirklich mitbekommen hat, besonders CSS und Javascript Dateien waren ganz schlimm. Trotz Änderungen an den Dateien hat sich beim Herunterladen die Dateilänge nicht geändert, egal ob man etwas hinzugefügt oder entfernt hat. Konsequenz daraus war dann, dass die Datei entweder abgeschnitten war, oder am Ende zufällige Daten standen, die nicht mehr zur Datei gehört haben. Beide Varianten führten zu andauernden Fehlen beim Entwickeln und führten mich kurz vor den Wahnsinn.
Ich hatte zuerst meine Softwareinstallation im Verdacht und um dem Problem Herr zu werden, habe ich das komplette System geupdated, einen neuen Kernel gebaut und etliches an der Konfiguration geändert. Alles ohne Erfolg. Kurz vor der absoluten Verzweiflung bin ich dann zufällig auf einen Hinweis gestoßen, dass dies ein Bug im Zusammenspiel zwischen den Shared Folders VirtualBox und der Apache Sendfile Optimierung ist. Ein einfaches "EnableSendfile Off", irgendwo in der Apache Config zu platzieren, hat dem Spuk dann ein plötzliches Ende bereitet. Jetzt macht auch Entwickeln wieder richtig Spaß.
-
Ein weiterer Blogger ist geboren
erstellt am 22.04.10
Nach reiflicher Überlegung habe ich mich entschlossen, mich auch einmal an dem Thema "Blogging" zu versuchen. In Anbetracht der Tatsache, dass ich doch recht viel Zeit am PC verbringe und dort auch recht interessante Dinge tue, ist es sicher sinnvoll, die ein oder andere Erkenntnis hier nocheinmal zusammengefasst darzustellen. Zum Einen kann ich meine Webseite dann selbst als Nachschlagewerk nutzen, zum anderen stolpert vielleicht auch mal zufällig irgendwer anderes per Suchmaschine über meine Seite und findet eine Lösung für sein Problem.
Mein erster Versuch mich diesem Thema über ein Wiki zu nähern ist leider gescheitert. Zwar fand ich die Möglichkeiten der zwanglosen Informationsablage sehr spannend, leider hab ichs irgendwie nicht hinbekommen, genug Inhalt zu schreiben um auch nur im Ansatz den Verwaltungsaufwand eines Wikis zu rechtfertigen. Ausserdem ist es mir nicht gelungen eine Struktur zu etablieren, um die Daten sinnvoll abzulegen.
Ich bin in der letzten Zeit häufiger am Twittern und bin ziemlich begeistert davon, wie einfach man einen formlosen Inhalt ins Internet stellen kann. Leider sind die 140 Zeichen nicht ausreichend, wenn man mal wirklich etwas zu sagen hat, daher versuche ich nun beides zu verbinden. Diese minimale Webseite besteht nur aus wenigen Zeilen Quellcode, die eigentliche Datenablage ist über normale Textdateien realisiert, in die ich einfaches HTML schreiben kann.
Es bleibt nur abzuwarten, wie regelmässig ich von dieser Möglichkeit gebrauch machen werde, das wird die Zukunft zeigen. Auf mein neues Blogger-Dasein!