Ich wollte nur [...] und dann ist das Universum explodiert.

Projects
Books
Archive
About









    Permalink
  1. MySQL | Table Migration zu InnoDB

    Ich durfte letztens einer schönen Schulung zum Thema MySQL lauschen. Dabei kam viel herrum. Ein Teil davon hat sich mit verschiedenen Storage Engines beschäftigt.

    Ich habe mich entschieden den Großteil meiner Datenbanken zu InnoDB umzuwandeln. Welche Vor- und Nachteile das hatt sollte sich jeder vorher klarmachen. Stichwort: ACID und Fulltext-Search. Natürlich könnte man einfach mit ALTER arbeiten. Aber ich wollte nicht umbedingt die alten MyISAM Tables noch im FS liegen haben. Also alle Datenbanken droppen und den geänderten Dump wieder einspielen, sodass die Tables neu (mit InnoDB) angelegt werden.

    Zuersteinmal eine Liste mit den generieren mit den Datenbanken die man Bearbeiten möchte. Es ist zu beachten, dass man den mysql Table selbst nicht auf InnoDB umstellen möchte.

    mysql -u root -p -e "show databases;" -N --batch | grep -v ^information_schema$ | grep -v ^mysql$

    Die Liste der Datenbanken wird nachher noch hilfreich sein. Danach will man wahrscheinlich erstmal alle Dienste beenden, die auf dem MySQL zugreifen (Apache, Tomcat, whatever). In der my.cnf habe ich dann folgende Optionen für die InnoDB spezifiziert.

    defaulot-storage-engine = InnoDB
    innodb_buffer_pool_size = 16M
    innodb_additional_mem_pool_size = 2M
    innodb_log_file_size = 5M
    innodb_log_buffer_size = 8M
    innodb_flush_log_at_trx_commit = 1
    innodb_lock_wait_timeout = 50

    Anschliessend den Dump erstellen und alle ENGINE=MyISAM durch InnoDB ersetzen:

    mysqldump -u root -p > all-databases.sql
    sed -i -e 's#ENGINE=MyISAM#ENGINE=InnoDB#g' all-databases.sql

    Vorsicht. Hier ist mysql als Datenbank mit gedumped! Mir ist dabei keine wirklich einfache Zeile eingefallen die mit Suche/Ersetze Spielchen mysql ausschliesst. Es gibt bei mysqldump die Option “–ignore-table=” aber auch hier hätte ich jeden mysql Table einzeln nennen müssen. Ich hab die Datenbank dann einfach per hand aus dem Dump herausgelöscht.

    Außerdem sollte man seinen Datenbank Dump nach FULLTEXT durchsuchen, da dieser von InnoDB nicht unterstützt wird. In meinem Fall hat es nur ein altes Forum das niemand mehr benutzt betroffen, weshalb ich die Zeile einfach löschen konnte.

    grep "FULLTEXT" all-databases.sql

    Um jetzt alle Datenbanken zu droppen hab ich mir folgende Line gebastelt:

    for x in $(mysql -u root -phierstehteinpasswort -e "show databases;" -N --batch | grep -v ^information_schema | grep -v ^mysql$) ; do mysql -u root -phierstehteinpasswort -e "drop database $x ; " --batch ; done

    Nach der Bearbeitung kann man den Dump mit der neuen Engine für die Tables wieder einspielen:

    mysql -u root -p < all-databases.sql


  2. Permalink
  3. 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 :)


  4. Permalink
  5. 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.

    Auduino Sample Mp4
    Auduino Sample WAV 16 bit 22 Kkhz


  6. Permalink
  7. 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 :)


  8. Permalink
  9. Loading | Eine Bash-Progress-Bar

    Für ein kleines Projekt, an dem ich so nebenher immer etwas schreibe habe ich eine Art Ladebalken gebraucht. Habe ein paar wirklich coole Lösungsansätze gefunden, aber es läuft meistens auf Depencies raus (pv z.B.) oder nicht wirklich mein Anwendungsfall.

    Ich hab mir dann kurzerhand was selber gebastelt. Ich gebe zu ich hätte es auch so gestaltet können das es einfach nur für meinen Use-Case gereicht hätte, aber das erschien mir unsinnig. Wenn ich mich schon einen halben Abend hinsetze, dann können ja evtl. auch mehr Menschen was davon haben. So entstand dann die bash-progress-bar.

    Zu allererst besteht der Ladebalken aus einer while true Schleife. Sollte die Bar in ein Skript einbaut werden wäre die Bedingung dem Skript anzupassen. Ob das jetzt ein test -e auf ein File ist das getouched wird oder eine Art Counter bleibt jedem selbst überlassen.

    $ git clone git://github.com/noqqe/bash-progress-bar.git
    $ cd /bash-progress-bar/
    $ ./loading.sh
    > [            #####       ]

    Alle Parameter sind natürlich anpassbar. Ich habe versucht so gut wie alles anpassbar zu halten. Ich hoffe das ist mir gelungen ;)
    ./loading.sh Groesse Geschwindigkeit Rahmen-Anfang Füllcharacter Rahmen-Ende
    ./loading.sh 50 0.02 [ "######" ]

    Ohne irgendwie ein GIF-File zu erstellen kann ich das jetzt leider schlecht im Blog demonstrieren. Deshalb: ausprobieren :) Mehr Infos auf der Github Page.

    Fragen, Anregungen, Kritik erwünscht!


  10. Permalink
  11. 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


  12. Permalink
  13. 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?


  14. Permalink
  15. DeadDrop | Sharing mit Alice and Bob in Baiersdorf

    Als ich durch den Park in Baiersdorf lief und diese alte Mauer einer (vermutlich) verlassenen Werkstatt sah, konnte ich dann doch nicht anders.

    Wie es begann:

    Vorbereitung:

    Abschluss:

    Ende:

    http://www.deaddrops.com/db/?page=view&id=804


  16. Permalink
  17. 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


  18. Permalink
  19. 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.

    UPDATE:
    Ich hab Flattr “Things” bis eben missverstanden. Bis jetzt war im Blog der Flattr Button zu meiner Person eingebunden. Scheint aber als wäre das nicht der Use-Case. Ich habe jetzt für meinen Blog selbst noch ein “Thing” eingereicht und dieses mit der richtigen URL eingebunden. Vielen dank an die beiden die bereits den Flattr Knopf gedrückt haben! Leider ist das jetzt nicht mehr sichtbar hier.


Older »