The most awesome colorscheme for vim
vom 9. June 2010Ich meckere ja gerne über die hässlichen Farbschemas für vim. Ich hab schon ettliche ausprobiert und ein paar davon hatten mir sogar gefallen. Leider gab es für mich noch nicht "das perfekte" Farbschema, das überall gut aussah. Aus diesem Grund hab ich beschlossen, selbst eines anzufertigen.
![]()
Das Farbschema ist noch nicht ganz fertig, und an einigen Stellen muss noch einmal nachgebesert werden, doch ist es -- in meinen Augen -- das brauchbarste, das es in der vim.org Scripts Grabbelkiste gibt. Ich habe mich bemüht, eine dezente und dennoch klare Farbpalette zu erstellen. Verbesserungen kommen bestimmt in den nächsten Wochen, wenn ich mit anderen Programmiersprachen gearbeitet habe.
Download von vim.org (Screenshot 1, Screenshot 2)
Edit (10.06.2010): Danke für die Beiträge! Habe eben eine neue Version mit den Änderungen hochgeladen.
RSS Feed update
vom 17. December 2009Falls sich jemand wundert, warum sein Feedreader alte Posts nun plötzlich als brandneue Posts markiert: Das liegt daran, dass ich einen kleinen Fehler im RSS Feed repariert habe (das Preface der Artikel werden jetzt auch angezeigt, danke an Bea und Benjamin für den Bug-Report!) und sich die Titel aller Posts geändert haben. Also keine Panik, der einzige neue Artikel ist dieser hier :)
Kommentar schreiben,
del.icio.us,
Adventskalender 2009
vom 2. December 2009Dieses Jahr haben Florian und ich uns einen besonderen Adventskalender ausgedacht. Wir werden uns jeden Tag abwechseln, wobei Florian jeden zweiten Tag ein Kommandozeilentool vorstellen wird und ich euch im gleichen Rhythmus mit einem kleinen 2D-Spiel in die Open Source Scene einführen werde.
Wir freuen uns natürlich auf regelmäßige Besuche und auch rege Teilnahme. Florians Teile werden jeweils in sich abgeschlossen sein, mein Teil dagegen ist zusammenhängend und bezieht jeden der mitmachen will mit ein.
Viel Spaß und eine schöne Vorweihnachtszeit!
Kommentar schreiben,
del.icio.us,
Auflösung des zweiten Programmierwettbewerbs
vom 8. March 2009Zuerst einmal möchte ich mich in aller Form dafür entschuldigen, dass ich so lange nichts von mir hören lassen habe und - noch schlimmer - den Programmierwettbewerb noch nicht aufgelöst habe. Seit knapp zwei Monaten liegen nun schon die Abgaben auf meinem Desktop und ich habe mir geschworen, erst die Auswertung zu machen, bevor ich irgend etwas anderes schreibe. Ich tat mich so schwer dabei, weil die Einsendungen mich so überrascht haben und so vielseitig waren, dass ich mir lange Zeit Gedanken gemacht habe, wie ich diese tollen Arbeiten entsprechend würdigen und bewerten könnte.
Das Problem war, dass die Einsendungen so grundlegend verschieden waren, dass man sie fast nicht miteinander vergleichen konnte. In allen abgegebenen Projekten steckt zudem so viel Arbeit, Mühe und Detailverliebtheit, dass ich es kaum geschafft habe, einen zum Sieger zu erklären und die anderen leer ausgehen zu lassen. Aus diesem Grunde erhalten alle Teilnehmer für ihre tolle Abgabe ein Buch und der Sieger ein zusätzliches Dankeschön.

Ganz herzlich bedanken möchte ich mich natürlich bei allen, die mitgemacht haben. Das wären Andreas Maier, Florian Eitel, Ruben Müller und Uwe Klawitter. Ich hoffe, ihr habt jetzt nicht die Lust verloren, weil es so lange gedauert hat. Ich verspreche hiermit feierlich, dass die nächste Auswertung eines kommenden Programmierwettbewerbs schneller geht.
So, nun zu den Einsendungen: Ich habe versucht, die relevanten Punkte herauszuschreiben und den Code und die gesamte Anwendung nach den vier zuvor angegebenen Gesichtspunkten Features, Codedesign, Nutzung der Sprachfeatures und Usability zu bewerten. Wenn ich bei einem Punkt komplett falsch liege, würde ich mich sehr über einen Kommentar an der Seite freuen.
Ruben Müller
Sprache: ActionScript
Features: 1/5
Codedesign: 3/5
Nutzung der Sprachfeatures: 3/5
Usability: 4/5
(Download)
Features
Dadurch, dass der Chat-Client in ActionScript und Flash programmiert ist, läuft er auf jedem Rechner, der Flash installiert hat.
Positiv
Exzessive Nutzung vom Delegate-Pattern, um beim Datenempfang und beim Verbinden vom Socket auf die entsprachenden Methoden zu delegieren. Hier wurde strikt zwischen Darstellung und Logik getrennt.
Farbliche Markierung von Systemnachrichten, Benutzernamen und normalen Nachrichten.
Der Name: "Macc: Most awesome chat client" :-)
Negativ
Wenig Dokumentation
Das Einfärben der Nachrichten funktioniert in manchen Fällen nicht richtig, wenn im Benutzernamen ein "*" vorkommt oder wenn die geschickte Nachricht in einem "falschen" Zeichensatz Nachrichten schickt.
Umlaute werden nur unter OSX dargestellt. Unter Linux gibt es Darstellungsprobleme. Unter Windows hab ich es nicht getestet.
Das Senden und Empfangen von Nachrichten findet in unterschiedlichen Klassen statt, hier hätte man die beiden Funktionalitäten unter einen Hut bringen können.
Geilste Stelle im Code
if (success) {
Debug.trace( "macc.as :: Connection succeeded, yay for the cheeseburgers! :D", 3 );
}
Andreas Maier
Sprache: F#, WPS(XAML), C#
Features: 5/5
Codedesign: 5/5
Nutzung der Sprachfeatures: 5/5
Usability: 4/5
(Download)
Features
GUI und Kommunikationslogik sind hier komplett voneinander getrennt. Und nicht nur das, sie wurden auch in unterschiedlichen Programmiersprachen realisiert. Die GUI ist ein WPF-Anwendung mit C# und die restliche Logik wurde in F# geschrieben. Eine sehr interessante Kombination. Auch hier wurde die Trennung von GUI und Logik strikt eingehalten; Interfaces und Factories sorgten hier für die lose Kopplung.
Die GUI bietet alles, was man aus dem Server rausholen hätte können. Ein Chatfenster zeigt den Chat an, Nachrichten vom Server sind speziell markiert. Rechts befindet sich eine Userliste, die immer die aktuell im Chat befindlichen User anzeigt. Den Nicknamen kann man auch bequem über die GUI ändern.
Positiv
Verwendung meherer Sprachen in einem "Projekt". Die Wahl der Sprache F# war äußerst mutig und hat sicher viel Zeit in Anspruch genommen. Dies hat sich aber ausgezahlt, der Code ist sehr schlank und auch wenn man F# nicht komplett verstanden hat, versteht man, was passiert.
Eine Schicke GUI mit tollen Extrafeatures
Es lag noch eine Dokumentation bei, die den Code und das Vorgehen beschreibt. Das hat mir sehr geholfen zu verstehen, wie was zusammenwirkt.
Negativ
Ich habe alles Mögliche versucht, das Programm zum Laufen zu bringen, doch ich bin kläglich gescheitert. Selbst im Windows-Pool konnte ich das Programm nicht compillieren bzw. ausführen. Vermutlich fehlten mir einfach die Kenntnisse zu Visual Studio und Windows. Da in der Aufgabenbeschreibung stand, dass das Programm Plattformunabhängig sein soll, muss ich hier bei der Usability einen Punkt abziehen.
Geilste Stelle im Code
fun dataEvArgs ->
let dat = dataEvArgs.Data;
if x.IsGetUsersMessage(dat) then
(x.usersAvailableFunc.Invoke(dat.Split([|'\n'|])
// The pipeline operator rocks :-)!!
|> Seq.filter (fun element -> element <> null
&& element.Trim().Length >= 2)
|> Seq.map (fun element ->
(let mutable nickName = element.Trim().Substring(1, element.Trim().Length-1).Trim()
while nickName.StartsWith("*") do
nickName <- nickName.Substring(1, nickName.Length-1).Trim()
new User(nickName)))
|> List.of_seq))
else
())
Florian Eitel
Sprache: Ruby, Bash
Features: 3/5
Codedesign: 5/5
Nutzung der Sprachfeatures: 5/5
Usability: 3/5
(Download)
Features
Florian ging einen komplett anderen Weg. Er reduzierte sein Programm auf das mindeste Minimum, in dem er Features des Linux-Systems nutzte. Inspiriert durch suckless.org kommuniziert der Client mit Named Pipes. Das Chat-Programm kontrolliert nur die Named Pipes "in" und "out", die dann mit anderen Programmen oder einem simplen "echo" und "tail" beschrieben und ausgelesen werden können. Über Hooks kann dann auf Events reagiert werden.
Um die Kommunikation mit dem Server zu vereinfachen, lag ein kleines Shell-Skript bei, das alle Eingaben in die "in"-Pipe schreibt. Für die farbige Ausgabe wurde das Ruby gem "term/ansicolor" verwendet. Zudem konnte das System mit dmenu (aus dem dwm Windowmanager) betrieben werden.
Positiv
Die Einfachheit des Programms hat mich begeistert. Dadurch, dass simple Named Pipes verwendet wurden, wurde hier ebenfalls die Logik von der Darstellung getrennt.
Eine README beschrieb das komplette System und deren Aufbau, was sehr hilfreich war.
Negativ
Es gab keinerlei Möglichkeit, sich eine Benutzerliste anzuzeigen, was allerdings etwas umständlich gewesen wäre, dies auch mit Named Pipes zu lösen.
Die Benutzung des Programms erfordert einiges an Linux-Kenntnis, um es "zum Laufen zu bringen".
Geilste Stelle im Code
def def_hook name, *aliases
# Workaround da define_method vor ruby 1.9 keine Blocks als Parameter unterstützt
eval_methods name, "
def #{name}(&block)
( @#{name} ||= Array.new ) << block if block_given?
return @#{name}
end", aliases
end
Uwe Klawitter
Sprache: Java
Features: 1/5
Codedesign: 4/5
Nutzung der Sprachfeatures: 5/5
Usability: 4/5
(Download)
Features
Uwe ging den "traditionellen" Weg über Java. Trotz Java hat er es geschafft mit relativ wenig und übersichtlichem Code die Kernaufgaben zu erfüllen. Selbst der Code zur Swing-GUI ist anschaulich und übersichtlich. Im Code selbst wurden die Features von Java voll ausgeschöpft; eine Queue-Objekt sammelt alle Nachrichten zur weiterverarbeitung und der komplette Code kommt ohne Telnet-Wrapper o.ä. aus. Alles in allem macht der Code einen sehr stabilen Eindruck.
Positiv
"java -jar AChat.jar" und läuft :)
Übersichtlicher Code trotz Java.
Negativ
Leider biete die GUI nicht all zu viel Möglichkeiten. Hier hätte man noch einiges rausholen können. Beispielsweise eine Userliste oder einen Button zum Ändern des Benutzernamens. Deshalb hier auch ein Punkt Abzug bei Usability.
Geilste Stelle im Code
package cowabunga;
Aaron Müller
Sprache: Ruby, (XML)
(Download)
Ich habe natürlich auch eine "Referenzimplementierung" in Ruby gemacht :-) Verwendet habe ich dazu libgnome2 und glade für die GUI.
Der Server
Der Server selbst - gegen den ihr alle programmiert habt - ist in Ruby geschrieben und nutzt den "gserver" (GenericServer) von Ruby. Wer ihn sich mal anschauen möchte, kann ihn hier herunterladen.
Bewertung
Wie schon anfangs geschrieben, ist es mir sehr schwer gefallen, einen Gewinner zu ermitteln, weil ich alle Einsendungen toll fand und sich die einzelnen Einsendungen sehr schwer direkt vergleichen lassen. Ich habe mich dazu entschlossen, euch zu entscheiden, wer den Hauptpreis bekommen soll. Gebt einfach am linken Rand eure Stimme ab (am Besten noch mit einer kurzen Begründung). Natürlich bekommen alle, die mitgemacht haben ein Buch von mir. Schickt mir einfach eure Adresse per E-Mail.
Noch einmal vielen Dank fürs Mitmachen! Ich hoffe, es gibt wieder solch tolle Einsendungen bei kommenden Programmierwettbewerben. Mir hat es sehr viel Spaß gemacht, ich hoffe euch auch.
Programmierwettbewerb, Runde 2
vom 1. January 2009Da der erste Programmierwettbewerb so großen Andrang hatte und ich schon mehrfach angesprochen wurde, ob es denn nicht einen zweiten Teil geben wird, habe ich mir wieder eine kleine Programmieraufgabe ausgedacht. Ideal also, um die neuen Vorsätze fürs neue Jahr auf die Probe zu stellen und das Wochenende "sinnvoll" zu nutzen :-)
Die Aufgabe (ca. 2-4 Stunden Aufwand)
Es gilt, einen Chat-Client zu programmieren, der mit einem von mir gestellten Chat-Server kommunizieren kann. Die Programmiersprache ist frei wählbar, solange sie unter Linux, OSX und Windows interpretiert oder compiliert werden kann. Es dürfen alle eingebauten Features der gewählten Programmiersprache verwendet werden, jedoch keine externen "fertigen Lösungen". Eine Socket-Lib, GUI-Toolkit o.ä. ist natürlich erlaubt.
Der Chat-Client sollte eine Eingabemöglichkeit haben, um Befehle und Chatnachrichten an den Server zu schicken. Zudem sollte er einen Textbereich o.ä. besitzen, um Statusnachrichten und Chat-Nachrichten darzustellen. Eine sich aktualisierende Liste mit den aktuellen im Chat befindlichen Usern ist nicht notwendig, macht aber mehr her :-)
Bewertet werden: Features, Codedesign, Nutzung der Sprachfeatures und Usability.
Der Server
Der Chat-Server ist unter dem Host "aaron-mueller.de" mit dem Port "2009" erreichbar. Der Server kann mit Befehlen - ähnlich wie ein IRC-Server - gesteuert werden. Sendet der Client bspw. den Befehl "/quit" an den Server, trennt dieser die Verbindung zum Client. Weitere Befehle sind "/nick NeuerBenutzername" um den Benutzernamen zu ändern und "/users" um alle im Chat befindlichen User auszugeben. Alle Statusnachrichten, die vom Server kommen, haben einen *(Stern) am Anfang. Die Kommunikation läuft über PlainText-Nachrichten.
Am besten ist es, wenn man sich mit dem Server zuerst mit Telnet oder einem anderen Tool vertraut macht, und dann an die Programmierung geht.
Ziel
Jeder der am Sonntag den 11.01.2009 um 19:00 Uhr mit seinem eigenen Chat-Client in den Chat kommt und seinen Code per E-Mail an mail@aaron-mueller.de abgibt, hat die Aufgabe gemeistert. (Wer an dem Sonntag nicht kann, macht natürlich trotzdem mit :-) Der Gewinner erhält von mir eine Überraschung!
Ich freue mich über jeden Beitrag! Viel Erfolg!
Nachtrag: Ich habe noch ein paar kleinere Bugs im Server korrigiert. Danke an Marc und Florian fürs Testen und Bugs finden.
Neue Features
vom 20. February 2008Ich hab die letzten Tage etwas an meiner Seite rumgespielt und ein Feature eingebaut, das ich schon sehr lange geplant hatte. Mein Ziel war es, meinen Content (sprich Blogeinträge, Artikel, Tutorials usw.) nicht nur wie üblich am Ende des Textes zu kommentieren, sondern auch Anmerkungen an einzelne Paragraphen zu kleben. Das Ganze hat mich ca. 200 Zeilen JavaScript (ohne Prototype wären es sicher doppelt so viel geworden), ein paar neue Methoden im ApplicationController und eine Menge Index-Schupserei gekostet.
Die Funktionsweise ist einfach: Jeder Absatz der eine gewisse Länge hat, erhält links einen grauen Balken, den man anklicken kann. Klickt man auf einen erscheint darunter die schon abgegebenen Anmerkungen (wenn es schon welche gibt) und ein Kommentarfeld. Jeder Absatz der Anmerkungen enthält wird durch ein kleines "Lesezeichen" markiert. Die Zahl steht für die Anzahl der Anmerkungen in diesem Absatz.
Genutzt werden kann dieses Feature für die unterschiedlichsten Dinge: Wenn ich Unsinn schreibe kann man mich direkt verbessern, falls jemand weitere Informationen zu einem Absatz kennt (eine URL, ein Zitat, eine Erweiterung, ...) kann man dies direkt an Ort und Stelle einfügen und natürlich lassen sich so auch Lobpreisung und Tadel im Text verankern.
Markus hat schon bemängelt, das das System keine Notifications für neue Anmerkungen vorsieht. Realisierungsvorschläge hierzu werden gerne angenommen. Mich würde jetzt interessieren, wie ihr diese neue Kommentartechnik findet. Ich habe versucht es so einfach wie möglich zu gestalten, so dass es einfacher ist als einen "normalen" Kommentar zu schreiben.
Ich freue mich auf Feedback.
Kommentar schreiben,
del.icio.us,
Spaß am Gerät
vom 3. December 2007
Durch Martin bin ich vor Kurzem ziemlich günstig an einen 1HE Server gekommen. Heute hab ich endlich Gelegenheit gefunden mir das Baby etwas näher anzuschauen. Da das integrierte CD-Rom Laufwerk nicht so recht wollte, hab ich Ubuntu übers Netzwerk (PXE-Boot/TFTPd) installiert, was zu meinem Erstaunen verdammt gut funktionierte.
Da der Server einen Höllenkrach macht, kann ich ihn nicht im Wohnzimmer stehen lassen. Aus diesem Grund suche ich gerade nach einem passenden Zuhause. Da ich momentan die Serverkapazität nicht brauche, würde ich diese gerne einem OpenSource-Projekt zukommen lassen, also wer da was nützliches kennt das viel CPU-Power braucht (nein Seti@home kommt nicht drauf), solle sich bitte in den Kommentaren melden.
Ein kleines Script hätte ich da schon (hab ich geschrieben während die Installation durchlief :):
#!/usr/bin/env ruby
require 'date'
require 'open-uri'
host = "http://entwickler-press.de"
url = host+"/ep/xmas_calendar.php?day="+Date.today.day.to_s
name = open(url).read.scan(/href="(.+.pdf)"/).to_s.gsub(/ /, "%20").gsub(/#/, "%23")
local_name = name.scan(/ebooks/(.+)_[a-z0-9]+.pdf/).to_s.gsub(/%[0-9]{2}/, "_")+".pdf"
open(local_name, "w").write(open(host+name).read)
Das Script zieht das täglich verfügbare kostenlose eBook vom Adventskalender von entwickler-press. Da kommt Weihnachtsstimmung auf :)
Lively BestOf, Volume #1
vom 30. November 2007Im Rahmen der Vorlesung MSWA mussten wir den Code vom Lively Kernel (ein Research-Projekt von Sun) analysieren und einen Teilaspekt bis ins kleinste Detail untersuchen und verstehen. Florian und ich nahmen uns Morph als Spezielgebiet, was sich im Nachhinein ziemlich in Arbeit ausartete. Um die heutige Abgabe zu zelebrieren, beendeten wir dieses Projekt mit einem Bierchen (thx Andreas).
Bei der Analyse des Codes (>10k Zeilen Javascript) sind uns ein paar lustige und/oder merkwürdige Stellen aufgefallen, die ich euch nicht vorenthalten möchte :) Hier also die BestOf Codezeilen von Lively.
Da alle Javascript-Objekte auch wie eine Hashmap angesprochen werden können, ist es z.B. möglich die Superklasse des Objekts zu löschen oder aber dieses tolle Konstrukt (ähnliches geht übrigens auch in PHP):
addVariable: function(varName, initialValue) {
// functional programming is fun!
this[varName] = initialValue;
this[getter(varName)] = function(name) {
return function() { return this[name]; }
}(varName); // let name = varName ()
this[setter(varName)] = function(name) {
return function(newValue, v) {
this[name] = newValue;
this.changed(getter(name), v);
}
}(varName);
},
Auch ziemlich cool fand ich folgende Funktion:
// my kingdom for a Smalltalk block!
applyFunctionToShape: function() {
var args = $A(arguments);
var func = args.shift();
func.apply(this.shape, args);
if (this.clipPath) {
console.log('clipped to new shape ' + this.shape);
this.clipToShape();
}
this.adjustForNewBounds();
}.wrap(Morph.onLayoutChange('shape')),
Der Funktion wird ein Funktionsblock und eine beliebige Anzahl Parameter übergeben (Funktionsparameter zu definieren oder zummindest in einem Kommentar zu hinterlassen was denn evtl. in die Funktion reinkommt ist was für Weicheier). Der Funktionsblock wird mit einem zusätzlichen Parameter und den restlichen Argumenten aufgerufen ($A() ist übrigends eine Prototype-Funktion die alle Argumente in ein Array schiebt) und am Ende noch mit der Funktion wrap() noch mit dem Aspekt von onLayoutChange() ausgeführt.
Allerdings war nicht alles so genial wie es jetzt den Anschein hat.
for (var i = 1; i <= vertices.length; i++) {
var p2 = vertices[i % vertices.length];
if (p.y > Math.min(p1.y, p2.y)) {
if (p.y <= Math.max(p1.y, p2.y)) {
if (p.x <= Math.max(p1.x, p2.x)) {
if (p1.y != p2.y) {
var xinters = (p.y-p1.y)*(p2.x-p1.x)/(p2.y-p1.y)+p1.x;
if (p1.x == p2.x || p.x <= xinters)
counter ++;
}
}
}
}
p1 = p2;
}
Oder das hier:
/* ca. 5 Seiten von diesen Zuweisungen */ this.images[1][0] = this.images[0][0]; this.images[1][1] = this.images[0][1]; this.images[1][2] = this.images[0][2]; this.images[1][3] = this.images[0][3]; this.images[1][4] = this.images[0][4]; //images[2] = images[1]; // DO NOT DO THIS, -> javascript nice copy-features //images[1] = images[0];
Manche Dinge waren aber auch total sinnlos:
setToggle: function(flag) {
this.setAttributeNS(Namespace.LIVELY, "toggle", !!flag);
},
Nachtrag: Wie sich heute in MSWA herausgestellt hat, ist die doppelte Negation doch nicht so sinnlos wie es offensichtlich scheint. Sie sorgt in diesem Fall für eine Typkonvertierung. Damit die Funktion setAttributeNS() auf jeden Fall einen Boolean als dritten Parameter bekommt, wird der Wert zuerst negiert (also zu einem echten boolschen False gemacht) und anschließend zu einem echten True. (Hintergrund: In dynamisch typisierten Sprachen wird alles was kein False ist automatisch als True interpretiert.)
Erst nach dem fünften Durchsehen des Codes wurde mir klar das das hier eine Art Interfacedefinition sein muss:
recordChange: function(fieldName/*:String*/) {
// Update sever or change log or something
return;
},
Auch eine "Ellegante" Art Copy&Paste zu betreiben - einfach von einer anderen Prototype-Klasse klauen:
// poorman's traits :) bounds: PolygonShape.prototype.bounds, vertices: PolygonShape.prototype.vertices, inspect: PolygonShape.prototype.inspect, setVertices: PolygonShape.prototype.setVertices, reshape: PolygonShape.prototype.reshape, /* ... */
... oder einfach mal bei jedem Schleifendurchgang das Array neu definieren und die i-te Position rausziehen:
for (var i = 0; i < 12; i++) {
... ['XII','I','II','III','IV','V','VI','VII','VIII','IX','X','XI'][i];
/* ... */
}
Bei manchen Funktionen waren sich die Programmierer auch nicht so ganz sicher was sie da gemacht haben.
compositionWidth: function() {
if (this.wrap === WrapStyle.NORMAL) return this.shape.bounds().width - (2*this.inset.x);
else return 9999; // Huh??
},
Function.prototype.inspect = function() {
return this.toString().substring(8, 88);
};
// yes yes.. so its a little laggy to add the current line and delete it...
parent.setIMText("");
... und kleine Zankereien unter den Entwicklern ist auch zu finden:
// KP: note layoutChanged will be called on addition to the tree // DI: ... and yet this seems necessary! this.layoutChanged();
// this code is all copied -- should be factored or, better, removed
Das leidige Thema Browserkompatibilität ...
if (newShape.pathSegList.numberOfItems != this.pathSegList.numberOfItems) {
// ARGH, Safari doesn't clone lists properly???
for (var i = 0; i < this.pathSegList.numberOfItems; i++) {
// How annoying, no way of cloning path segments
var seg = this.pathSegList.getItem(i);
// KP: add the top morph to the world first, to make firefox happy WorldMorph.current().addMorphAt(WindowMorph(engine, 'A Lively Engine'), pt(250, 5)); engine.openAllToDnD(); // have a little fun...
Performance ist auch so ein Thema für sich. An einer ziemlich zentralen Stelle:
// TODO: there MUST be a better way to do this // there "might" be some performance issues with this :)
while (sin < 0) sin += 360; // Can be slow...
Und wer genau hinschaut findet sogar ein Easteregg :)
// uncomment for extra icon fun
/*
sign = NodeFactory.create("use").withHref("#GearIcon");
sign.setAttributeNS(null, 'transform', 'translate(-10, -10) scale(0.040)');
menuButton.addChildElement(sign);
*/
In diesem Sinne:
this.state = "shutdown"; // no one will ever know...
1




