About
Accounts
Friends
-
Loading…gpunktschmitz 10 days ago -
Loading…TheoRettich 4 days ago -
Loading…awezone 9 minutes ago -
Loading…this-looks-shopped 18 minutes ago -
Loading…updates about 1 month ago -
Loading…fyi about 6 hours ago -
Loading…ohmygodthebritish about 5 hours ago -
Loading…pokemon about 18 hours ago -
Loading…antiprodukt 3 days ago -
Loading…science about 4 hours ago - +65
Click here to check if anything new just came in.
January 08 2012
GNU Parallel
Vom GNU Parallel Projekt habe ich vor einiger Zeit in der Arbeit so am Rande etwas mitbekommen. Nachdem ich mir die gute Dokumentation etwas angeschaut habe, hab ich Lust bekommen das mal selbst auszuprobieren.
Ich dachte es wäre eine gute Idee einfach ein paar md5 Summen zu bilden.
$ time seq 1 10000 | parallel 'echo {}| md5sum &> /dev/null '
real 0m20.102s
user 0m35.082s
sys 0m24.918s
Nun. Ich bilde nicht so oft 10.000 md5 Summen. War das jetzt viel? Oder wenig? Um einen Vergleichswert zu haben sollte ich wohl auch mal nachsehen, wie das ohne Parallel so aussieht.
$ time for x in $(seq 1 10000); do echo $x | md5sum &> /dev/null; done
real 0m13.504s
user 0m2.368s
sys 0m3.948s
Ziemlich seltsam. Obwohl ich 10.000 md5 Summen gebildet habe war die sequenzielle Methode schneller als die Parallele. Zumindest dachte ich zu dem Punkt noch das es seltsam ist. Aber an was lag das. Ich hab mir dann überlegt ob ich nicht vielleicht doch noch eine andere Aufgabe als md5 Summenbildung abbilden sollte. Ich entschied mich dazu 1000 mal eine 100.000 Zeichen lange Zeichenkette durch gzip zu schubsen.
$ time seq 1 1000 | parallel 'cat /dev/urandom | head -c 100000 | gzip &> /dev/null'
real 0m7.845s
user 0m4.064s
sys 0m20.485s
7 Sekunden. Sieht eigentlich ganz nett aus. Und in der Schleife sequenziell?
$ time for x in $(seq 1 1000); do cat /dev/urandom | head -c 100000 | gzip &> /dev/null; done
real 0m31.869s
user 0m8.301s
sys 0m33.658s
Okay. Jetzt weiss ich, das GNU Parallel eher was für (rechen-)intensivere Aufgaben ist als für viele kleine Prozesse. Anscheinend braucht das Parsing des zusätzlichen Binaries doch etwas zu lange um einen Prozess zu ordnen der sowieso nach sehr kurzer Zeit wieder beendet ist. Alles in allem gefällt mir GNU Parallel aber sehr gut wenn man weiss für was man es einsetzen muss :)
December 21 2011
Arduino | Ich bau mir einen Synthesizer
Vor ca. 2 Wochen habe ich auf der Suppe vom K4CG ein Video über einen auf Arduino basierten Synthesizer. Die “Firmware” die darauf läuft nennt sich “Auduino”.
Auf deren Projektseite habe ich mich dann etwas schlau gelesen und wie auch schon bei dem Megabitmeter über tinkersoup.de meine Teile bestellt. Auf der Projektseite ist die Konstruktion des ganzen finde ich zwar nicht sonderlich gut beschrieben, aber man kommt mit ein bisschen Googeln und Reverse Engineering schon weiter.
Habe dabei aber einen Arduino Nano benutzt, weil mir die Anschlüsse bzw “Architektur” besser gefällt und ich nicht erst ein Breakout Board von Seriell auf USB nachkaufen musste. Entgegen aller Erwartungen musste ich die Firmware dafür nichtmal modifizieren, da auch bei diesem Board ein ATMega328 verbaut ist.
Ich habe mir wegen der einfacheren Anbringung am Nano so eine Art Halterung/Breadboard mitbestellt, in dem ich die Adern mit Schrauben einfacher verbauen konnte.
Die Potenziometer (wieder was, das ich gelernt habe) sind in Reihe an den Ground und den 5V Pin geschlossen. Der jeweils mittlere Pin der Drehschalter kommt an die Analog Pins 0 bis 4.
Danach kam der (für mich) kniffligere Teil. Der Audio Jack (bzw. Klinke Buchse) hat von Haus aus 5 Pins. Auf der Projekte Seite von Auduino nur Input und Ground. Nach bisschen schlaulesen in Wikis und Foren scheint es, als würden die verschiedenen Revisionen von Klinke andere Features mit sich bringen. für den Mini Synthesizer hätte vollkommen Klinke Mono ausgereicht. Diverse Zusatzfunktionskanäle sind da eigentlich überflüssig aber im Audio Jack bei TinkerSoup integriert.
Nach etwas Trial and Error Verfahren den weg für Doofe gewählt. Ich hab ehrlichgesagt einfach ein altes Klinke Stecker auf Buchse Kabel aufgeschnitten und mir die Belegung auf der Steckerseite angesehen.
Bei 3poligen Klinken Steckern sind die vorderen beiden Kontakte fürs Signal (Links, Rechts) und hinten für Ground. Habe dann die beiden Signaladern auf der Buchsenseite verdrillt und wie vorgesehen in den Digitalen Pin 3 geklemmt. Ground natürlich an seine Stelle.
Im Endeffekt wars dann schon fertig. Firmware mit dem Arduino IDE auf den Chip geladen und hat auch schon funktioniert. Aber weil ich dann ständig die Potenziometer durcheinander gebracht habe, hab ich noch eine alte Plastikbox aus dem Baumarkt meiner Wahl benutzt, die entsprechenden Löcher gebohrt dort das ganze eingebaut.
Etwas smoother ;) Noch ein paar kleine Kostproben von einem wirklich unbegabten Synthesizer-Bediener. Beim hören etwas aufpassen, ab und zu ist mir da ein Ton entglitten.
December 11 2011
fbcmd | Nie wieder Geburtstage vergessen via Shell.
Die nachfolgende Beschreibung eines technischen Vorgangs würde die Mehrheit der Gesellschaft wahrscheinlich als soziologisch fragwürdig abstempeln. Jedoch beschreibe ich den Hergang trotzdem und gerade deswegen.
Ich weiß gar nicht mehr wie genau ich auf fbcmd gekommen bin. Im Zweifel über einen XML basierten Medienkanal. Jedenfalls ist fbcmd ein äußerst schönes Tool um die gängigen Informationen zum eigenen Facebook Account auf der Kommandozeile abzufragen. Dazu bietet es wahnsinnig trickreiche Queries und “Vergruppungen” der Facebook Bekanntschaften. Alles dazu hier und besonders hier.
Somit lässt sich wunderbar ein automatisches “Alles Gute zum Geburtstag!” bauen. Vorraussetzung ist hierfür eine funktionierende Installation von fbcmd.
Der von fbcmd vorgeschlagene Query um eine Geburstagsnachricht an die Pinnwand von jenen zu senden, deren Geburtstag sich heute jährt lautet:
fbcmd WALLPOST =bday 'Alles Gute zum Geburstag!'
Das lässt sich natürlich wunderbar in einen Cronjob verbauen, der einmal täglich um 15:00 eben diesen Query ausführt:
0 15 * * * fbcmd WALLPOST =bday 'Alles Gute zum Geburstag!' > /dev/null
Weil ich aber wissen möchte, wem mein Rechner alles in meinem Namen zum Geburtstag graturliert hab ich das noch leicht modifiziert und lasse mich via Mail darüber benachrichtigen:
0 15 * * * fbcmd WALLPOST =bday 'Alles Gute zum Geburstag!' | grep -v "^No Friends With Birthday Matches$" | mail -s "fbcmd Gratulation" user@domain.de
Eigentlich ist der Titel des Posts gar nicht richtig. Man vergisst Sie trotzdem. Aber ein Device erledigt die Arbeit für einen :)
November 26 2011
October 22 2011
Taskwarrior | The better-task-shell
Eigentlich wollte ich das Projekt task-shell-ng nennen. Aber so gut ist es dann doch nicht geworden. Stattdessen hat es sich aber den Prefix better verdient ;)
Als ich vor ca. einem Monat Taskwarrior für mich entdeckt habe, war eigentlich alles gut. Ich hab mich über den integrierten interactive Mode wirklich gefreut. Anfangs. Mit der Zeit habe ich aber festgestellt, dass mich dieses “Ding” fast in den Wahnsinn treibt. Mir persönlich fehlen einfach elementare Features wie einfaches Cursor bewegen nach vorne und zurück. Überhaupt eine History zu haben wäre schon ein enormer Vorteil.
Ich hab mir dann kurzer Hand selber eine Taskwarrior Shell Variante gebaut, die im großen und ganzen auf einer Bash basiert.
Features:
- History vorwärts und rückwärts via Pfeiltasten
- Cursorbewegung vorwärts und rückwerts in der aktuellen Zeile
- Alle Kommandos nativ benutzbar ( $ add pri:H pro:Living Miete zahlen )
- ID’s direkt nutzbar ( $ 34 edit oder $ 12 pri:H )
- separate Logging Funktion in $HOME/.better-task-shell_history
- OS Befehle weiterhin nutzbar! ( $ vim /home/user/foobar.txt )
- Automatische Erkennung von doppelten Aliases
- Automatische Alias Generierung fuer os-binaries ( $ ls = task ls ; os-ls = /bin/ls )
- Auto-Komplettierung aller Taskwarrior Befehle und definierte Aliase
Known Bugs:
- Neu angelegt tasks können derzeit noch nicht via ID aufgerufen werden.
$ add Uberweisung einwerfen
Created Task 45
$ 45 pri:H
bash: 45: Kommando nicht gefunden
Für beim Start bestehende Einträge funktioniert dies allerdings problemlos. - Mode -v ist bis jetzt noch nicht benutzbar aber bereits implementiert.
Das ganze gibts jetzt unter http://github.com/noqqe/better-task-shell
Usage:
git clone git@github.com:noqqe/better-task-shell.git
$ cd better-task-shell
$ ./better-task-shell
October 15 2011
Git and the Unix philosophy
Mein Feedreader hat heute einen Post von Julius ausgespuckt, den ich so gut fand, dass ich ihn hier rezitieren möchte.
Git follows Linux’s philosophy of refusing to protect you from yourself. Much like Linux, Git will sit back and watch you fuck your shit right up, and then laugh at you as you try to get your world back to a state where up is up and down is down. As far as source control goes, not a lot of people are used to this kind of free love.
Ich rezitierte also Julius Zitat. Blogpost-Inception?
October 04 2011
October 02 2011
Statistiken | Einfache Graphen mit R und MySQL Anbindung
Immer mal wieder reizt mich die Programmiersprache für Statistiken R. Um diesen Reiz dann auszuleben hab ich vor ein paar Monaten angefangen kleine Graphen für den zufallsbasierten Simulator ZRE zu bauen. Das Spiel “läuft” einfach 24/7 und schreibt für jedes geschehene Event Einträge in die Datenbank. Diese Einträge werte ich dann mit Hilfe von R aus.
Dazu gibt es ein Skript. Nämlich zre.R (Ob das die Konvention bei R-Skriptnamen ist, kann ich nicht sagen ;) )
#!/usr/bin/env Rscript
### General R-Script
# MySQL
library(RMySQL)
con <- dbConnect(MySQL(), user="", password="", host="", client.flag=CLIENT_MULTI_RESULTS)
# Style
zre_colors <- colors()[grep("green",colors())]
zre_mint <- colors()[c(48,86,50)]
Im Klartext wird aus dem CRAN Library Verzeichnis die Library RMySQL includiert und die Verbindung in der Variable con abgelegt. Ähnlich wie bei PHP. Für alle Debian / Ubuntu Benutzer empfiehlt sich aber, die Library einfach über das Paketsystem nachzuinstallieren.
$ aptitude install r-cran-rmysql
Standardmäßig sehen Graphen die mit R erstellt werden ziemlich mau aus. Die weiteren Variablen unter Style habe ich gewählt um mir die Colorierung der Graphen etwas zu erleichtern. Diese werden später einfach als Attribute in den Plots/Barplots gesetzt und ausgewertet. Ich fange einfach mal der Reihe nach an:
Die Abfolge ist immer ziemlich ähnlich. Zu aller Erst wird der Query für die Datenbank an die Variable sql übergeben. Diese Variable wiederrum wird zusammen mit der Connection an die Funktion dbGetQuery übergeben und das Ergebnis dessen schliesslich in zre_wins gespeichert. Anschliessend ein paar kleine Informationen an das Dateiformat übergeben und den Graphen bauen.
Die Funktion par lässt sich erstmal als eine Art Environment Funktion für Graphen verstehen. Hier werden Eigenschaften wie Schriftfarbe, Hintergrund, Axenfarbe, und Liniendicke definiert. Danach kommt (wie ich finde) der schwierigste Teil. Bauen des Graphen. Je nach Art des Graphen (Balken, Linien, Torte u.ä.) werden logischerweise verschiedene Parameter erwartet. Die Daten werden hierbei jetzt als Matrix an ein Balkendiagram übergeben. Weitere Informationen wie die Überschrift (main) und die Beschreibung der Balken (names.arg) werden einfach angefügt.
# Graph: Wins
sql <- paste("SELECT COUNT(id) AS sum, side FROM zombies.zre_wins GROUP BY side;")
zre_wins <- dbGetQuery(con, sql)
png(file="wins.png", width=400, height=400)
par(col="white", bg="transparent", col.axis="white", col.lab="white", col.main="white", lwd=2)
barplot(as.matrix(zre_wins$sum), main="Game Summary", names.arg=c(zre_wins$side), beside=TRUE, col=zre_mint)
Selbes Spiel wieder, nur mit mehr Balken und anderem Use-Case. Diesmal werden die 25 Konflikte mit den meisten Opfern visualisiert.
# Graph: Highest Kills
sql <- paste("SELECT id, kills FROM zombies.zre_kills ORDER BY kills DESC LIMIT 25;")
zre_matches_highest <- dbGetQuery(con,sql)
png(file="highestkills.png", width = 400, height = 400, bg="transparent")
par(col="white", bg="transparent", col.axis="white", col.lab="white", col.main="white", lwd=4)
barplot(zre_matches_highest$kills, zre_matches_highest$id, main="25 Highest Kills", beside = TRUE, ylab="Kills", col=zre_colors)
Aber da Balkendiagramme auch irgendwann Langweilig werden geht das natürlich auch anders. Die 25 letzten Konflikte werden im “Opferverlauf” wie folgt dargestellt:
# Graph: Kills
sql <- paste("SELECT kills FROM zombies.zre_kills ORDER BY id DESC limit 25;")
zre_kills <- dbGetQuery(con,sql)
yrange <- range(zre_kills$kills)
xrange <- length(zre_kills$kills)
png(file="kills.png", width=400, height=400, bg="transparent")
par(col="white", bg="transparent", col.axis="white", col.lab="white", col.main="white", lwd=4)
plot(zre_kills$kills, xlab="Games", type="b", ylab="Kills", main="Kills from last 25 Attacks", col=zre_mint)
Damit es nicht immer nur um Tote geht, auch mal was erfreuliches. Die Geburtenrate in ZRE steigt! :)
# Graph: BirthRate
sql <- paste("SELECT Month(date) AS month, count(id) AS born FROM (SELECT *, Month(date) AS M FROM zombies.zre_born) t Group by M; ")
zre_birthrate <- dbGetQuery(con,sql)
png(file="birthrate.png", width=400, height=400)
par(col="white", bg="transparent", col.axis="white", col.lab="white", col.main="white", lwd=3)
barplot(zre_birthrate$born, xlab="Month", ylab="Born Humans/Zombies", names.arg=c(zre_birthrate$month),main="BirthRate per Month", col=zre_colors)
Und auch das Wetter soll bei der ganzen Sache nicht zu kurz kommen. Hierbei bitte besonderes Augenmerk auf die Legende rechts oben. Eine direkte Zuordnung der Werte und Farben ist nicht nötig, da die Farben in der selben Reihenfolge von zre_colors befüllt werden wie die Balken. Die erschreckend hohe Zahl an Naturkatastrophen erklärt das aber trotzdem nicht :)
# Graph: Weather
sql <- paste("SELECT COUNT(id) AS count, weather FROM zombies.zre_weather GROUP BY weather ORDER BY count DESC;")
zre_weather <- dbGetQuery(con,sql)
png(file="weather.png", width=400, height=400)
par(col="white", bg="transparent", col.axis="white", col.lab="white", col.main="white", lwd=2)
barplot(zre_weather[,1], main="Weather in ZRE", beside = TRUE, col=zre_colors)
legend( 5, 40000, zre_weather$weather, cex=0.9, fill=zre_colors, col="white")
Das volle zre.R Skript befindet sich wie das meiste auf Github: https://gist.github.com/1031260
October 01 2011
Flattr | Man kann seine Meinung auch mal ändern.
Als dieses Micro-Payment System Flattr vor mehr als einem Jahr raus kam habe ich hier im Blog über Sinn und Unsinn des Dienstes sinniert. Ich konnte mich damals nicht wirklich entscheiden, ob mir das System gefällt oder nicht. In der Tat ist es eigentlich eher so, dass mir das Projekt Kulturwertmark vom CCC viel eher zusagt.
Im Moment ist es abe so, dass es keinen anderen verbreiteten Weg gibt Content bzw. Software von Privat-Menschen zu belohnen, weil er/sie mir geholfen hat. Deshalb (und auch weil mich die Oberfläche interessiert hat) habe ich mich dort angemeldet und verteile seit 2 Monaten etwas Geld hier und da. Vorwiegend an Podcasts, Taskwarrior und Blogs von Leuten die ich kenne. Ich habe initial 8 Euro überwiesen mit denen ich jetzt erstmal 4 Monate rumflattern werde. Das das nicht die Welt ist, ist mir klar.
Und da ich jetzt sowieso schon einen Account dort habe, habe ich auch meinen Flattr-Button im Blog (links) eingebunden. Es wird erstmal keinen individuell Button für einzelne Posts geben und es braucht sich auch niemand verpflichtet fühlen da drauf zu drücken.
September 25 2011
Taskwarrior | Migration von MyTinyTodo
Im Programm der Ubucon habe ich einen Vortrag von Dirk über Taskwarrior gefunden. Aus Gründen hat mich das Tool interessiert. Ich habe zwar bereits eine Todo-Verwaltung (nämlich MyTinytodo) aber trotzdem.
Nach zwei Tagen herumspielen und einem wirklich hervorragendem How-To hat mir Taskwarrior allerdings so gefallen, dass ich mich entschlossen habe MyTinyTodo aufzugeben und zu Taskwarrior zu wechseln. Da ich meine TodoListe aber auch gerne als eine Art “Log” verwende musste ich die Aufgaben erst aus MyTinyTodo migrieren.
Realisiert habe ich das über ein kleines Bash-Script, welches die Daten aus der MyTinyTodo MySQL Datenbank ausliesst und daraus automatisch Taskwarrior Statements formuliert. Allerdings: Ich habe absichtlich nur abgeschlossene Tasks über die “LOG”-Funktion von Taskwarrior einfuegt.
Aus dem Datenbank Eintrag:
mysql> select d_completed, mtt_lists.name as liste, title from mtt_todolist, mtt_lists where mtt_lists.id = mtt_todolist.list_id order by d_completed desc limit 1;
+-------------+-------+--------------+
| d_completed | liste | title |
+-------------+-------+--------------+
| 1307714692 | Home | Miete zahlen |
+-------------+-------+--------------+
1 row in set (0.00 sec)
formuliert das Skript beispielsweise folgendes Kommando für Taskwarrior:
task log due:20110610 pro:IMPORT-Home Miete zahlen
Das passiert eben für jede Eintrag in der Todo-Datenbank, damit ich dort nachschlagen kann wann was passiert ist.
August 27 2011
Arduino | Ich baute ein Megabitmeter
Vor einiger Zeit hab ich über den Podcast von Tim Pritlove (NSFW) von dem Projekt MegabitMeter erfahren. Es hat mich ehrlichgesagt fasziniert. Der eigentliche (im Namen implimzierte) Zweck zwar weniger, aber gernerell einfach Werte über ein USB Device darstellen zu können. Genaue Anwendungsfälle gibts weiter unten.
Zunächstmal hab ich mich ausgiebig mit dem HowTo beschäftigt welches ich (bis auf ein paar Stellen) sehr gut finde. Die letzten Paar Unstimmigkeiten habe ich dann mit dem wirklich netten und zuvorkommenden Betreibern des Projekts via Mail abstimmen dürfen :) Das lag aber auch an meinen fehlenden elektrotechnischen Kenntnissen.
Ich muss dazu sagen, dass ich in der glücklichen Situation war und jemanden kannte, der in einer Firma tätig ist, die solche Messgeräte anfertigt wodurch ich keinen Kit kaufen musste. Das ist auch der Grund warum das Messgerät etwas anders aussieht.
Ich denke auch das der Sinn des Projekts eher das “do-it-yourself” ist und der wirtschaftliche Erfolg nur eine positiver Nebeneffekt der Betreiber ist… (Zumindest hoffe ich, dass ich das nicht falsch interpretiert habe). Außerdem schwierig war, dass der Kit 2 (incl. dem Arduino) nicht verfügbar war, da laut Twitter gerade keine Arduinio Nano in rauen Mengen billig einzukaufen sind. Den Arduino Prozessor habe ich deswegen von TinkerSoup.de geordert.
Wenn alles fertig gebastelt ist, kann man dem Gerät einfach via echo Werte übergeben.
$ echo "200" > /dev/ttyUSB0
Ein paar Anwendungsbeispeile:
Zufällige Zahlen auf das Gerät projezieren
while true; do RND=$(($RANDOM % 99 * 10)); printf "$RND\n" > /dev/ttyUSB0 ;echo $RND; sleep 2 ; done
Zombie Kill Meter (In Verbindung zu zombies.n0q.org)
while true ; do mysql -u user -ppw -e \"SELECT kills from zombies.zre_kills ORDER BY id DESC LIMIT 1;\" | grep -v ^kills ; sleep 3; done" > /dev/ttyUSB0
Port 80 Verbindungen des Webservers
ssh user@host "while true; do echo \$(( $(netstat -tapn | grep -c -e ':80\s*') * 100 )) ; sleep 2; done" > /dev/ttyUSB0
An weiteren Snippets bastle ich im Moment noch. Werden eventuell nachgereicht wenn Sie spruchreif sind. Am Ende noch ein riesen Danke für die Software und die Projektidee sowie das wunderbare HowTo an das Team von <a href=”megabitmeter.de”>megabitmeter.de</a>
August 23 2011
PostgreSQL | 1000 und 1 Query
Zur Zeit spiele und bastle ich nebenher mit PostgreSQL rum. Überlege ob ich mal eine alternative DB für das Zombie-Revolution-Environment an den Start bringe…
Für meinen Use-Case scheint das allerdings nur begrenzt von Nutzen zu sein. Ich mache vielleicht etwas falsch, aber wenn ich 1000 Queries in MySQL kippe, dauert nur einen Bruchteil so lange wie in postgreSQL. Um das zu veranschaulichen:
$ time for x in $(seq 1 1000) ; do mysql -u root -ppw -e "insert into foobar.foo values ($x, now());" ; done
real 0m7.349s
user 0m0.060s
sys 0m0.380s
$ time for x in $(seq 1 1000) ; do psql --quiet -d foobar -c "insert into foobar values ($x, now());" ; done
real 1m28.363s
user 0m37.450s
sys 0m13.020s
Kann mir jemand sagen woran das liegt? Ich kann mir nur schwer vorstellen das PostgreSQL so hinterher hinkt.
July 24 2011
Abschlussprüfung | Zentrales Versionskontrollsystem mit git und etckeeper
Nachdem ich letzten Donnerstag erfolgreich meine Ausbildung zum Fachinformatiker abgeschlossen habe, kann ich die dazugehörige Dokumentation / Präsentation hier veröffentlichen.
Zu danken habe ich dabei hauptsächlich all den wunderbaren OpenSource Tools, die mir zur Erstellung und Umsetzung gedient haben. Um einige zu nennen:
July 04 2011
Minecraft + Git + Bash =
Seit mittlerweile erstaunlich langer Zeit spiele ich Minecraft. Minecraft hält seine Daten in ~/.minecraft vor. Also Levels, Statistiken, Items. Das Minecraft Home Directory unter Versionskontolle zu stellen hat unter Umständen mehrere Vorteile, die ich hier kurz erläutern möchte :)
Initiales Setup
Als erstes muss das Verzeichnis initial eingerichtet werden. Initialisierung, hinzufügen aller Dateien und ersten Commit erstellen.
$ cd $HOME/.minecraft
$ git init
$ git add .
$ git commit -a -m "Initialer Commit"
Spielstände manuell Laden und Verwalten (Commits)
Einer der gravierendsten Vorteile. Wer wie ich oft an Klippen hinunter stürzt oder an einem (oder auch mehreren :P ) Creeper(n) scheitert wird das bestätigen können. Einmal gefallen/gestorben gibt es kein zurück mehr. Bis jetzt.
Die hypothetische “Herausforderung” scheint sich gerade aufzutun. Ob jetzt Creeper, Berg oder sonst was ist erstmal egal. Könnte auf jeden Fall kritisch für meinen Minecraft Character enden.
$ git commit -a -m "Ob man den Sprung ueberlebt?"
Nach einem kurzen Tab in die Konsole, sollte das Spiel erstmal gesichert sein und ich kann den Sprung wagen.
Anscheinend überlebt man nicht, aber genau das war auch der kritische Punkt. Genau jetzt bin ich in der Lage meinen alten Spielstand wiederherzustellen. Mit nachfolgendem Kommando verwerfe ich alle seit dem letzten Commit entstandenen Änderungen an meinem Spielstand. Vorher dringend aufs Minecraft Titelmenü zurückkehren!
$ git stash
Dieses Szenario lässt sich nicht nur auf gerade geschehene Ereignisse abbilden sondern auch zwischen Commits die längere Zeit her sind. Wenn nach einer halben Stunde/einem Monat klar wird, das der Minecraft Char gerade nur Müll verzapft hat, kann auch zwischen mehrere Commits hin und her gesprungen werden. Mit welchen git Kommandos das bewerkstelligt wird, bleibt jedem selbst überlassen.
git-revert macht den letzten Commit rückgängig, erstellt dabei einen neuen in dem die Änderungen enthalten sind. Das ist in soweit gefährlich, dass zwischenliegende Commits unberührt bleiben und eventuell in einen großen Haufen Datenmüll zerfallen(!). Eher Anwendung für den “Warp” an einen früheren Zeitpunkt X findet daher git-reset.
$ git reset 66a2594
# oder
$ git reset HEAD^
Das Working Directory wird damit auf einen Stand gebracht, wie es zum Zeitpunkt des angegebenen Commits aussah. Dieser kann somit auch weiter in der Vergangenheit liegen.
Automatische Speicherung (Bash-Einzeiler)
Allerdings muss ich zugeben, dass diese Praxis relativ schnell aufwendig wird. Immer zwischen Fenstern hin und her zappen ist ja auf Dauer auch eher zermürbend. Daher habe ich mir diese “Arbeit” von einer kleinen Bash Zeile abnehmen lassen.
$ SEKUNDEN=10 ; while true ; do git add . ; git commit -a -m "AutoSave $(date)" ; sleep $SEKUNDEN ; done
Ich denke es ist Geschmacksache wie oft bzw. in welcher Frequenz die Commits abgesetzt werden können. Bis jetzt bin ich mit ca 300 Sekunden (5 Minuten) am besten Gefahren. Die Commits rieseln vor sich hin und beeinträchtigen so in keinster Weise den Spielfluss.
[master bf9dd85] AutoSave Mo 4. Jul 19:56:17 CEST 2011
4 files changed, 15 insertions(+), 12 deletions(-)
rewrite saves/0pen_Running/level.dat (100%)
rewrite saves/0pen_Running/level.dat_old (100%)
[master 5ddedc8] AutoSave Mo 4. Jul 19:56:27 CEST 2011
4 files changed, 17 insertions(+), 19 deletions(-)
rewrite saves/0pen_Running/level.dat (100%)
rewrite saves/0pen_Running/level.dat_old (100%)
[master 2d33023] AutoSave Mo 4. Jul 19:56:37 CEST 2011
4 files changed, 10 insertions(+), 11 deletions(-)
rewrite saves/0pen_Running/level.dat (100%)
rewrite saves/0pen_Running/level.dat_old (100%)
Parallele Welten (Branches)
Um einfach mal ein Anwendungsbeispiel zu nennen: Wer in seinem virtuellen Minecraft-Keller mal raue Mengen an TNT gebunkert hat, möchte es nach Möglichkeit auch mal benutzen, right? Aber danach das ganze Dorf wieder aufbauen? Nee… Branching!
Das ist der Punkt an dem die Geschichte der lokalen Minecraft Map sich in zwei Teile spaltet. In einer wird das eigene Bauwerk Sorum und Gumorra mäßig untergehen und in der anderen weiterhin existierenden Welt tollen sich Pigs und Sheeps in Minecarts herum. Die Abzweigung lässt sich wie folgt bewerkstelligen.
$ git branch blowup
$ git checkout blowup
Jetzt kann man in aller Seelen Ruhe TNT verteilen und auch mal Destroyer statt Builder spielen. Tipp: Commit vor der Sprengung setzen :P Explosion immer und immer wieder von vorne genießen ;) Bemerkenswert sind außerdem die unterschiedlichen Abläufe von ein und der selben Explosion, aber dazu vielleicht wann anders ein Blogpost. Irgendwann wird aber auch das dann zur Routine und man wechselt via
$ git checkout master
wieder zu den Schäfchen. Der Branch “blowup” bleibt aber bestehen und lässt sich auch nach weiteren Spielständen immer wieder herbeirufen. Ich habe mittlerweile eine Art Branchset meiner “Lieblingssituationen” im Game, die ich immer wieder durchspielen kann, wie es mir gerade gefällt. Und nein es sind nicht immer nur Explosionen :)
Networking, Baby! (Remotes)
Mein Minecraft Setup mit allen Einstellungen und Spielständen zentral an einem Ort zu haben war ehrlich gesagt meine erste Motivation git einzusetzen. Ich spiele Minecraft auf 3 verschiedenen Maschinen (Ubuntu, Debian und sogar Mac OSX) und wollte keine 3 unterschiedlichen Maps pflegen müssen. Deshalb fing ich an auf meinem Server zwischen zu lagern. Ein eigens laufender git-Server ist hier aber Vorraussetzung! Freies Hosting bei beispielsweise Github fällt wegen der großen Datenmengen (ca. 300MB bei mir derzeit) und der fehlenden Privatsphäre flach. Remote-Server hinterlegen und aktuellen Stand pushen:
$ git remote add origin git@gitserver.com:minecraft
$ git push origin master
Remote-Server auf anderen hosts klonen:
# Ubuntu/Debian
$ git clone git@gitserver.com:minecraft $HOME/.minecraft
# Mac OSX
$ git clone git@gitserver.com:minecraft $HOME/Library/Application\ Support/minecraft
At least
Ich möchte nicht sagen, dass dies hier der ultimative Weg zum heiligen Gral in Minecraft ist. Manchmal weckt eben diese erzeugte “Sicherheit” durch den Reset eine gewisse “Wayne…” Einstellung in einem, die dem Spielspaß ein Kleinwenig den kitzel raubt. Gerade am Anfang hat es mir aber extrem geholfen, nicht bei jedem Wipe alle Items zu verlieren oder sich nach einem Ausflug in den Wald wieder “zurück warpen” zu können.
Auf weitere Ideen im Umgang mit Minecraft und Git freue ich mich natürlich wie immer :)
June 12 2011
BitCoin | Debian Daemon Script für poclbm-mod
Man muss Dinge über Hirnschäden von Menschen lesen die Nachts guten Gewissens neben einem 4 Grafikarten im SLI-Verbund schlafen und zugleich die Bedenken von sinnierenden Typen die an den Limitierungen von 21 Billionen maximal möglichen BitCoins zweifeln. Umweltverschmutzung ist natürlich auch ein Thema. Klar. Gerechtfertigter Weise.
Wenn Ihr mich fragt, schiesst die BitCoin Mining Gesellschaft am Ziel vorbei. Separate Rechner betreiben schiesst am Ziel vorbei. Hunderte von Euros für neue Grafikkarten ausgeben um 5 MegaHashes/s mehr rechnen zu können schiesst am Ziel vorbei. Euro’s für BitCoins bezahlen schiesst sowieso am Ziel vorbei. Man kann BitCoins meines Erachtens auch benutzen ohne Kopfstände zu machen. Immer wenn der Rechner sowieso gerade läuft, mit der Hardware die man zur Verfügung hat.
Aus diesem Grund habe ich ein kleines Skript gebastelt. Einen Start-Stop-Daemon für /etc/init.d/. Es startet automatisch wenn mein Rechner hochfährt und hört auf wenn ich Ihn herunterfahre. Ganz einfach
$ wget -O /etc/init.d/bitcoin https://gist.github.com/raw/1007794/bitcoin.sh
$ chmod +x /etc/init.d/bitcoin
$ update-rc.d bitcoin defaults
https://gist.github.com/1007794
Ich möchte aber dazu sagen, dass ich dies Funktionstüchtigkeit des Skripts nicht auf anderen Rechnern/Betriebssystemen getestet habe. Vor Benutzung also bitte lesen, verstehen ggf. anpassen. Außerdem wird ein Account bei einem Mining Pool benötigt und der Mining Client an sich (poclbm-mod). Während ich diesen Post geschrieben habe, hat mein BitCoin Mining Client entspannt auf meiner Geforce 8600 GS mit nahezu niedlichen 950 KiloHashes/s vor sich hin gemined.
May 03 2011
April 29 2011
RT | RequestTracker-Stats
Ich habe es bereits öfters angesprochen und trotzdem noch nicht die Zeit gefunden einen kleinen Blogpost darüber zu verfassen. Vor kurzem habe ich mir das Balkendiagramm-Shellskript statistical gebastelt. Nachdem es so gut funktionierte hatte, hatte ich mir überlegt, was ich damit jetzt anfangen könnte. Ich brauchte einen großem Umfang an Datenmengen, den ich visualisieren konnte (abgesehen von zufällig erzeugten Daten). Am Besten noch etwas, dass Sinn macht :)
At Work war “Ticket-Squashing” immer wieder ein gutes Stichwort in unserem Ticketsystem. Wir benutzen den RequestTracker von BestPractical und ich hatte mir überlegt ein kleines Skript zu basteln, welches die Anzahl der erledigten Tickets pro User aus der MySQL Datenbank ausliesst und dann im Key:Value Format an statistical übergibt. Das hat auch ganz gut funktioniert.
Resolved ticket statistic for this month (April)
---------------------------------------------------
Tracy |##################### (22)
Amelie |##################### (22)
Kiri |############ (13)
Tersina |########## (11)
Birgitta |######### (10)
Justine |######### (10)
Frank |######## (9)
Betteann |####### (8)
Cyndy |# (2)
Kaleena |# (2)
Kiah |# (2)
Roxy | (1)
Estella | (1)
Marj | (1)
Allerdings haben sich dann im Laufe des Tages immer mehr (ich nenne es mal statistische-) Anwendungsmöglichkeiten ergeben. Zum Beispiel die Anzahl der erstellten Tickets pro Benutzer:
Most active creators for this month (April)
---------------------------------------------------
Christel@company.com |############ (13)
Sydelle@company.com |########### (12)
Birgitta@company.com |######### (10)
Ainsley@company.com |######## (9)
Halette@company.com |##### (6)
Martguerita@comp |##### (6)
Tracy@company.com |#### (5)
care@company.com |#### (5)
fooo@company.com |### (4)
Christyna@company.com |## (3)
Ethel@company.com |## (3)
[...]
Oder die Anzahl der Tickets pro Kategorie:
Queues for this month (April)
---------------------------------------------------
General |##################### (22)
Web |##################### (22)
Management |#################### (21)
WebContent |################### (20)
IT-Interal |################ (17)
Categ |############### (16)
Access |############### (16)
E-Mail-Service |############## (15)
SWAN |########### (12)
Domain-Service |########## (11)
Junk |########## (11)
DSL |## (3)
Other |# (2)
Hotspot-Service |# (2)
Buchhaltung | (1)
Um nur ein paar Beispiele zu nennen. Leider waren es zu diesem Zeitpunkt noch etliche separate Skripte, was mir eigentlich nicht gefiel. Darum habe ich es in ein modular aufgebautes Statistik Umgebungstool umgewandelt. Module sind (de-)aktivierbar und lassen sich leicht in das Rahmenprogramm einfügen. Letztendlich gibt es jetzt einen ganzen Satz von Modulen der unter Github zur Verfügung steht.
git clone git://github.com/noqqe/RequestTracker-Stats.git
Sollte außer uns noch jemand RequestTracker Stats verwenden und Interesse daran haben, ist er herzlich eingeladen die Stats Umgebung zu benutzen ggf. auch Module hinzuzufügen oder zu verbessern :) Eine (ich hoffe doch) ausreichende Anleitung zur Benutzung befindet sich im README des Github Repos.
Shell-Zauberei | Namensliste in MySQL Datenbank einspeisen
Code
for x in $(mysql --batch -u root --password=passw0rd -e "USE rtdb; SELECT DISTINCT id FROM Users;" | grep -v ^id); do mysql -u root --password=passw0rd -e "USE rtdb; UPDATE Users SET Name=\"$(sed -n $(($RANDOM % $(cat Names | wc -l) +1 ))p Names)\" WHERE id=\"$x\" ;" ; done
Hintergrund
Wie auch schon beim letzten mal dreht es sich wieder um die Anonymisierung der RequestTracker Datenbank für die ich zur Zeit an einem Statistik Tool arbeite. Diesmal will ich aber nicht die EmailAdressen ändern, sondern die Namen der Benutzer. Da ich diese nicht so einfach generieren lassen kann, habe ich mir aus dem Interweb eine Liste mit Namen besorgt und mit diesen Namen die eingetragenen überschrieben. Jetzt kann ich endlich den Post über das Statistik Tool schreiben und mit Beispielen versehen :)
Funktion
Das Ganze läuft wie folgt ab: Für jede ID die ich mittels Datenbank-Verbindung in die For-Schleife einbette, setze ich einen UPDATE Befehl ab, der die Tabelle “Users” und das Feld “Name” aktualisiert. Der Aktualisierungsvorgang passiert aber generisch. Das heisst ich setze den Namen des Users auf einen zufällig ausgewählten neuen Namen aus der Datei “Names”. Das habe ich mit sed -n p FILE gelöst, was sicher auch schöner geht, aber für meine Zwecke hat es ausgereicht.
April 20 2011
Commandline Tools | PDFs zusammenführen
Aufgrund meiner aktuell vorherrschenden Bewerbungsphase wollte ich ein paar PDF Dateien (hauptsächlich Zertifikate und Zeugnisse) in eine PDF Datei zusammenführen. Auf der Suche nach einem derartigen Programm liefen mir natürlich allerlei (dem anschein nach) hübsche Windows Tools für diese Aufgabe über den Weg. Wie schon oft, fand ich dann aber im Unixboard meine Antwort.
Das Commandline Tool pdftk. Wunderbar für Debian und Ubuntu paketiert.
$ sudo aptitude install pdftk
Ich muss trotzdem zugeben, dass die Syntax mir etwas ungewöhnlich erschien, aber nicht unbezwingbar ist
Nach ein paar Blicken in die Manpage, kam ich auch da an wo ich wollte.
$ pdftk novell-cert.pdf ripe.pdf lpic-1.pdf cisco-ccna1.pdf cat output Zertifikate.pdf
\___/ \________________________________________________/ \_/ \____________________/
| | | |
| | | \- Ausgabe an
| | | Zertifikate.pdf
| | |
| | \- Ausgabe der PDFs
| |
| \- Angabe aller zu kombinierenden PDFs
|
\- Programmaufruf
April 16 2011
statistical | It’s about internal functions.
Als ich statistical auf GitHub hochgepushed habe, fing ich an mir Gedanken über die Leistungsfähigkeit des Scripts zu machen. Ich meine es verhielt sich in Anbetracht der Daten (in meinen Augen) wunderbar. Die Key Länge wird bis zu 4 Tab-Längen mit skaliert, genauso wie die Values, in Form der Bars. Aber wie verhält sich es mit größeren Datenmengen?
Diesbezüglich wollte ich eine kleine For-Schleife benutzen um mehrere zufällige Werte zu generieren und in statistical zu pipen.
time for x in $(seq 1 6000); do echo "$x:$RANDOM" ; done | statistical > /dev/null
Das Ergebnis war mit 6000 Datensätzen und guten 7 Minuten relativ ernüchternd. Vor kurzem hat mich dann auch noch Vain via GitHub auf die Geschwindigkeit von statistical hingewiesen. In seinem Fork, hat er alle extern spawnenden Befehle gegen Bash interne Funktionen ausgetauscht. Siehe da:
real 0m7.788s
user 0m7.610s
sys 0m0.250s
Wahnsinn oder? Durch den Austausch von awk und grep durch interne Bash Funktionen wird das ganze ernsthaft 23x mal schneller. Vielen Dank an Vain an dieser Stelle!
Maybe Soup is currently being updated? I'll try again automatically in a few seconds...
























