Dockerimage für GHC7.8 und GHC7.6

Ich habe heute ein Dockerfile für GHC7.8 bzw. GHC7.6 mit Cabal 1.20.0.1 auf Ubuntu 14.04 (LTS) geschrieben. Die Dockerfiles selbst liegen auf Github und die Images werden per „trusted builds“ automatisch ins Docker Index hochgeladen (GHC7.8, GHC7.6).

Aufbauend auf diesem Image kann man nun zum Beispiel Dockerfiles für seine eigenen Haskell-Projekte schreiben. Ich zeige das kurz an einem Beispiel, dem funblog.

FROM agrafix/ghc7.6
MAINTAINER mail@agrafix.net
RUN git clone https://github.com/agrafix/funblog.git
RUN cd funblog && cabal install --only-dependencies
RUN cd funblog && cabal build
RUN rm -rf /funblog/blog.cfg
ADD blogConfiguration.cfg /funblog/blog.cfg

EXPOSE 8080
CMD ["/funblog/dist/build/funblog/funblog"]

Das Image kann man dann mit

docker build -t 'agrafix/funblog' .

bauen, wobei man eine Datei blogConfiguration.cfg im gleichen Verzeichnis benötigt. (Vorlage dafür ist auf github) Danach kann man den Blog mit

docker run -p 8080:8080 -d agrafix/funblog

starten und unter

http://localhost:8080

aufrufen.

 

Linux: Einfaches Backup-Script

Heute möchte ich mein einfaches „Backup-Script“ für Linux-Rechner vorstellen. In meinem Szenario muss ich eine MySQL-Datenbank und ein paar Verzeichnisse sichern. Die Sicherungskopie möchte ich dann verschlüsseln und auf einen anderen Rechner laden.

Zunächst logge ich mich auf dem Rechner ein, auf dem ich Daten sichern will. Wenn ich noch keinen öffentlichen SSH-Schlüssel habe, lege ich einen neuen an (kein Passwort für den Schlüssel vergeben!):
ssh-keygen -t rsa

Diesen kopiere ich dann auf den Rechner, der die Sicherungskopien speichern soll:
ssh-copy-id benutzer@backup.agrafix.net

Nun lege ich eine neue Datei an, die den Verschlüsselungsschlüssel enthält:
openssl rand -base64 512 > key.txt

Jetzt zum eigentlichen Script:

#!/bin/bash

today=$(date +"%Y_%m_%d")

# CONFIG
mail="mail@agrafix.net"
keyFile="$HOME/key.txt"
backtarget="benutzer@backup.agrafix.net:a01/${today}.tar.gz"
backup=( "$HOME" "/var/www" )
mysqlUser="mysqluser"
mysqlPass="mysqlpass"
mysqlDb=( "mysqldb" )
# END CONFIG

dir=`mktemp -d`
target="/tmp/${today}_back.tar.gz"

for db in "${mysqlDb[@]}"
do
    echo "Backing up mysql to ${dir}/${db}.sql to ${db}.sql"
    mysqldump -u $mysqlUser -p"$mysqlPass" $db > "${dir}/${db}.sql"
done

for d in "${backup[@]}"
do
    backupName=${d////_}
    echo "Backing up ${d} to ${backupName}.tar.gz"
    tar --ignore-failed-read -f "${dir}/${backupName}.tar.gz" -cz $d
done

echo "Compressing everything to ${target}"
tar cfz - $dir | openssl enc -aes-256-cbc -kfile $keyFile -e > $target

echo "Done. Now uploading ${target} to backup machine ${backtarget}"
scp "${target}" "${backuptarget}"

echo "Deleting local backup"
rm -f $target
rm -rf $dir

echo "Sending email"
echo "Backup complete! ${today}" | mail -s 'Backup completed' $mail

echo "Okay! :-)"

Um ein Backup wieder einzuspielen, muss die entsprechende .tar.gz Datei zurück kopiert werden, und kann dann mit

openssl enc -in $1 -kfile key.txt -aes-256-cbc -d | tar -zxvf -

entpackt werden.

 

Zippyshare Downloads automatisieren

Zur Zeit arbeite ich an einem Downloadmanager, der alle gängigen Download-Seiten unterstützen soll. Neulich hat zippyshare.com etwas eingebaut um genau diesen „automatischen“ Downloads einen Riegel vorzuschieben: Der Download-Link wird jetzt per JavaScript „verschlüsselt“. Ich werde jetzt hier keinen Beispiel-Zippyshare-Downloadlink posten, das findet man mit etwas googlen schnell selbst 😉

Nun möchte ich erläutern, wie ich den Download-Link automatisch auslese:
Zuerst entnehme ich der Seite per Regulärem Ausdruck die benötigten JavaScript Variablen:
xHTML-Code der Stelle

var zipdata = eval(eval(eval(((function() {var parzDiXdet= (((function() {var hutByDojpZ= eval(379);var BvLCmMYDEQB= ((function() {var qefrKDjxbJ= eval(51);var DKbCbnceoJN= ((((18+(3*3)))+((function() {var kzCDpmQUwq= eval(eval(43));var UoRHKeZvyaH= 23;return (kzCDpmQUwq+UoRHKeZvyaH)})())));return (qefrKDjxbJ+DKbCbnceoJN)})());return (hutByDojpZ+BvLCmMYDEQB)})())*eval((19*eval(29)+((eval((eval(3)*3))+(((function() {var fhYCresaSD= 0;var XRIVTZgfbzF= eval(2);return (fhYCresaSD+XRIVTZgfbzF)})())*eval(3)+1)))))+468);var MpIWcCCkdZo= (((function() {var ciqbBKFBYW= eval(80);var aAZRNKwkocE= 242;return (ciqbBKFBYW+aAZRNKwkocE)})())*(3*(8*eval(32)+(1*((function() {var yMgeUqevwX= ((function() {var CIechCiWBN= 0;var GoKsZmkLAMw= ((function() {var JYpKjwyxxu= 0;var YfDpdwhpscp= 2;return (JYpKjwyxxu+YfDpdwhpscp)})());return (CIechCiWBN+GoKsZmkLAMw)})());var FklyvoQTPho= eval(eval(2));return (yMgeUqevwX+FklyvoQTPho)})())))+eval(eval((1*((0+eval(2)))))))+261);return (parzDiXdet+MpIWcCCkdZo)})()))));
var fulllink = 'http://www123.zippyshare.com/d/123456789/'+zipdata+'/Alarmclock.mp3';
document.getElementById('dlbutton').href = fulllink;

Regexp zum auslesen

$aFind = StringRegExp($ZippySrc, "s*(var zipdata = .*;)s*var fulllink = '(.*)';s*document", 1)

Nun muss die Variable „zipdata“ evaluiert werden. Dies mache ich wie folgt:

;
;
; Evaluate zippyshare.com JavaScript
;
; Coded by www.agrafix.net
;
;
Func _JSParse_Parse($sJavaScript)
	For $_x = 0 To 50

		If StringRegExp($sJavaScript, "var zipdata = ([0-9]*);") Then
			ExitLoop
		EndIf

		$sJavaScript = _JSParse_NumericVariableDeclarations($sJavaScript)
		$sJavaScript = _JSParse_EvaluateEasyMath($sJavaScript)
		$sJavaScript = _JSParse_SimpleEvals($sJavaScript)
		$sJavaScript = _JSParse_SimpleFunctions($sJavaScript)
	Next

	$m = StringRegExp($sJavaScript, "var zipdata = ([0-9]*);", 1)

	Return $m[0]

EndFunc

Func _JSParse_SourceReplace($aArray, $sJavaScript)
	For $i = 0 To UBound($aArray) - 1 Step 2
		$sJavaScript = StringReplace($sJavaScript, $aArray[$i], $aArray[$i+1])
	Next

	Return $sJavaScript
EndFunc

Func _JSParse_NumericVariableDeclarations($sJavaScript)
	$aNumDeclarations = StringRegExp($sJavaScript, "var ([a-zA-Z0-9_-]*) ?= ([0-9]*);", 3)

	$sJavaScript = StringRegExpReplace($sJavaScript, "var ([a-zA-Z0-9_-]*) ?= ([0-9]*);", "")

	$sJavaScript = _JSParse_SourceReplace($aNumDeclarations, $sJavaScript)

	Return $sJavaScript
EndFunc

Func _JSParse_EvaluateEasyMath($sJavaScript)

	While StringRegExp($sJavaScript, "(([0-9]*?[+-*/]?[0-9]*[+-*/][0-9]*))")

		$aMatches = StringRegExp($sJavaScript, "(([0-9]*?[+-*/]?[0-9]*[+-*/][0-9]*))", 3)

		For $i = 0 To UBound($aMatches) - 1
			$Result = Execute($aMatches[$i])

			$sJavaScript = StringReplace($sJavaScript, "(" & $aMatches[$i] & ")", $Result)
		Next

	WEnd

	Return $sJavaScript

EndFunc

Func _JSParse_SimpleEvals($sJavaScript)

	While StringRegExp($sJavaScript, "eval(([0-9]*))")

		$aMatches = StringRegExp($sJavaScript, "eval(([0-9]*))", 3)

		For $i = 0 To UBound($aMatches) - 1
			$sJavaScript = StringReplace($sJavaScript, "eval(" & $aMatches[$i] & ")", $aMatches[$i])
		Next

	WEnd

	$sJavaScript = StringRegExpReplace($sJavaScript, "(([0-9]{1,11}))", "$1")

	Return $sJavaScript
EndFunc

Func _JSParse_SimpleFunctions($sJavaScript)

	$sJavaScript = StringRegExpReplace($sJavaScript, "(function() {return ([0-9]*)})()", "$1")

	Return $sJavaScript
EndFunc

Nun muss ich die Funktion nur noch mit den obigen Werten aus meiner RegExp aufrufen, die JavaScript Variable „fulllink“ anpassen und aufrufen:

$url = StringReplace($aFind[1], "'+zipdata+'", _JSParse_Parse($aFind[0]))
INetGet($url, "Alarm.mp3")

Das war’s auch schon. Alle Source-Codes sind in AutoIT. Natürlich ist _JSParse kein funktionierender JavaScript Parser, sondern einfach nur eine Funktionssammlung die eben diesen Zippyshare-JavaScript-Haufen evaluieren kann 😉

Der obige Source-Code darf natürlich verwendet, verändert und verteilt werden, ich bitte legendlich um einen kleinen Hinweis auf den Ursprung (http://www.agrafix.net).

 

Agrafix.net in neuem Design

Lange hat sich www.agrafix.net in gleichem Design präsentiert, deshalb war jetzt Zeit für etwas neues. Im Grunde habe ich ein neues Design für die Seite erstellt, die Referenz-Icons vereinheitlicht und auf der Startseite werden nun die letzten 3 Blogbeiträge angezeigt. Wie gefällt euch das neue Design?

Besuche www.agrafix.net

Wärend der „Umstellung“ bin ich natürlich auf ein paar interessante Dinge gestroßen:

1) Die SQL, die es ermöglicht die letzten Blogbeiträge aus einem WordPress auszulesen:

SELECT post_title, post_content, guid, post_author FROM [PREFIX]_posts WHERE post_status = 'publish' AND post_type = 'post' ORDER BY post_date DESC LIMIT 3

2) Außerdem noch ein Tipp für alle xHTML+CSS-Designer: Um ein komplettes DIV zu verlinken habe ich folgenden Code genutzt:

CSS:

div.nelement {
	float:left;
	margin-left:10px;
}

div.nelement a {
	display:block;
	width:100%;
	height:100%;
}

div.nelement a:hover {
	text-decoration:none;	
}

xHTML:

Das war’s auch schon 😉

 

Facebook: Like

Seit kurzem ist es dank neuen Facebook-Schnittstellen möglich auch Webseiten, Beiträge und Ähnliches zu „Liken“ („Gefällt mir“). Auch als Blogger sollte man von diesem profitieren, da man dadurch anderen die Möglichkeit gibt für eure Beiträge Werbung zumachen, denn wenn ein Leser bei eurem Beitrag auf „gefällt mir“/“like“ klickt, wird auf seinem Profil angezeigt „Mister XYZ gefällt ‚Facebook: Like'“.

Für die „faule“ WordPress Gemeinde gibt’s da ein wunderbares Plugin, welches sich Facebook Like nennt. Dieses muss man sich einfach Installieren und dann konfigurieren. Viel Spaß damit!

 

Crawler – eine „Gefahr“?

Letztes Jahr im Herbst ging „SchülerVZ“ durch die Presse – persönliche private (?) Daten wurden von Crawlern „geklaut“. Und jetzt ist es wieder passiert (siehe hier), wieder sind Millionen von Daten geklaut worden. Das ganze ging eigentlich relativ problemlos – ein Crawler bewappnet mit der entsprechenden RegEx krabbelte durch die Seiten von 1,6 Millionen Nutzern. Gehindert werden sollte der Crawler von einer „Klicksperre“, die ein maximum von Klicks pro Zeiteinheit erlaubt. Doch dies umging der Crawler ganz ohne Probleme – der Programmierer legte einfach 800 SchülerVZ-Accounts an, die parallel benutzt werden konnten. SchülerVZ hatte zuvor die Captchas wieder ausgebaut und hatte somit mehr oder weniger alle Tore zu ihren Daten offen – abgesehen von den Daten jener, die sie nur für den Freundeskreis einsehbar gemacht hatten.

Nun kann man sich Fragen ob Crawler eine Gefahr für die eigene Privatsphäre sind oder einfach nur harmlos Daten sammeln. Denn Crawler durchforsten nicht nur „normale“ Seiten, sondern das ganze Internet und dessen Soziale Netzwerke. Die Daten werden dann abgespeichert und auf irgendwelchen Archiv-Servern gespeichert. Google zum Beispiel nimmt riesige Mengen an Daten in seinen Cache auf – das heißt selbst wenn diese vom ursprünglichen Server gelöscht wurden kann man sie noch einsehen. Andere Crawler erstellen jeden Monat einen „Schnappschuss“ von einer Webseite und archivieren ihn dann. Daten die einmal im Internet sind, bleiben dort wohl for eine (wenn auch) begrenzte „Ewigkeit“.

Es gibt dank verschiedensten Crawlern schon Suchmaschienen, die nach Informationen über Personen suchen. Und wenn in dessen Datenbanken jetzt noch Daten aus Sozialen Netzwerken wie etwa Bilder, Vorlieben oder Lebensweise kommen, dann kann jeder (!) im Internet alles über eine wildfremde Person erfahren. Bei einem Bewerbungsgespräch würde es dann nicht mehr „Hallo Herr Crawlerman, erzählen Sie von sich“ sondern „Hallo Herr Crawlerman, ich habe gehört sie trinken viel Alkohol, sind sehr freizügig und ihre Freundin hat sie wohl grade verlassen?“ heißen. Ist das wirklich wünschenswert?

In dieser Hinsicht denke ich sind Crawler eine Gefahr für die Privatsphäre des Einzelnden, allerdings sehr nützlich um andere Daten zu erfassen und zu durchsuchen. Man müsste eine Lösung finden, Crawler effektiv aus der „Cyber-Privatsphäre“ herauszuhalten, und man muss die Betreiber von sozialen Netzwerken dazu zwingen schärfere Maßnahmen in Hinsicht auf Privatsphäre zu ergreifen.

 

Das iPad Board

Liebe Leser,

jeder der von euch uns im Twitter (@agrafix / @agrafixblog) verfolgt weiß vielleicht von unserem neuem Projekt „iPad Board“ – das iPad Forum für die deutsche Fan-Community. Zu finden ist dies unter www.ipad-board.net. Da das iPad leider noch nicht auf dem Markt ist, denkt ihr euch vielleicht: Warum soll ich mich dann in einem iPad Forum anmelden? Deshalb möchte ich kurz erläutern worum es momentan im iPad Board geht – später soll man sich dann natürlich über Erfahrungen und Tipps mit dem iPad und rund ums iPad austauschen. Im Moment diskutieren wir zum Beispiel darüber welches iPad man sich kaufen sollte oder welche iPhone Apps auf dem großem iPad Display noch viel hilfreicher sind oder mehr Spaß machen. Außerdem ist zum Beispiel eine kleine Debatte über den Preis des iPads in Deutschland entstanden, da der Preis ja bekanntlich erst in den USA bzw. in US-Dollar feststeht. Zuletzt möchte ich noch erwähnen das auch technische (bereits bekannte) Aspekte diskutiert werden und gehofft wird das das iPad noch eine iSight Kamera bekommt 😉 Insgesamt ist bei uns also für jeden Apple Fan was zu finden!

Schaut bei uns vorbei, diskutiert mit unter www.ipad-board.net!

Ich freue mich über euren Besuch,
Agrafix

 

Google Wave – ein Flop?

Manche meinen es wäre eine Ehre Google Wave testen zu dürfen, andere wunderen sich was „daran so toll sein soll“. Wir (Buster und Ich) gehören zu der zweiten Gruppe, der Gruppe von Leuten die sich über die Google-Wave-Euphorie wundert. Wir haben Google Wave nun mehr oder weniger ausgiebig getestet und kamen zu dem Ergebniss, dass alle dort enthaltenen Funktionen durch andere Software/Dienste bereits in deutlich besserer Ausführung vorhanden sind.

Zur Kommunikation oder dem Austausch von Neuigkeiten sind die aktuellen Social-Networks wie beispielsweise Facebook, twitter, oder die VZ-Netzwerke deutlich besser geeignet und viel einfacher zu bedienen. Facebook oder Twitter bedürfen eigentlich auch keine kurzen Einleitungsvideos, was man als GoogleWave eher schon benötigt. Ein weiteres Manko im Aspekt „Kommunikation“ ist, dass GoogleWave nicht sehr bekannt ist und momentan nur von sehr wenigen Leuten genutzt wird. Auch zum Werbung machen für einen Blogbeitrag oder zum Mitteilen von Updates, etc. ist Wave nicht wirklich geeignet. Wave wirbt zum Beispiel damit durch eine integrierte Translator-Application sich international in seiner Sprache ausdrücken zu können, was jedoch auch nicht sehr gut funktioniert, da die Übersetzungen auf die GoogleSprachtools basiert, und man merkt selbst, dass dieser Dienst nur mangelhaft übersetzt.

Auch das integrieren von anderen Applications wie zB Schach läuft nicht wirklich flüssig und macht auf die Dauer keinen Spaß. Desweiteren soll Wave ja auch noch zum Diskutieren gut sein, bis man jedoch die passende Wave für ein bestimmes Thema gefunden hat kann das eine Weile dauern. Auch hier bevorzuge ich Foren.

Was mit Wave jedoch wirklich prima funktioniert ist das Organisieren von Veranstaltungen, da zB jeder Veranstalter seinen „Senf“ dazu geben kann was noch mit rein muss und was nicht. Außerdem kann live gleichzeitig an einem Dokument arbeiten und Kommentare dazu abgeben. Funktioniere in unserem Test auch nicht super flüssig und überzeugend. Aber auch hierzu gibt es wesentlich bessere Live-MultiUser-Edit Programme wie zum Beispiel Gobby.

Wir haben noch ein paar Einladungen übrig, wer sich also seine eigene Meinung bilden möchte kann diesen Beitrag hier einfach Kommentieren und wir schicken dann eine Einladung vorbei.