Damian Brunold
Counter Strings in Python
2011-11-29 11:51
James Bach hat in seinem Blog die Counter Strings vorgestellt. Eine geniale Idee. Er erzeugt sie mit einem Perl-Programm (PerlClip). Ich habe nun den Teil der Counter-String-Erzeugung nach Python übersetzt:
#!/usr/bin/env python3
# counterstring adapted from the code in "perlclip" package (see e.g. james bach)
# The idea is to start at the end of the string. The end must be a *
# character (or whatever the indicator character is). So the preceding
# number is obviously the target length. Preceding to this number is a
# * again, whose position can be calculated in the same manner.
#
# Since this builds the counter string in reverse, the position
# strings have to be added reversed and the final result string is
# reversed also.
def generate_counter_string(target_length, char="*"):
result = ""
pos = target_length
while True:
if len(result) + len(str(pos)) + 1 > target_length:
result += char * (target_length - len(result))
break
result += char + str(pos)[::-1]
pos -= len(str(pos)) + 1
return result[::-1]
if __name__ == "__main__":
print(generate_counter_string(int(sys.argv[1])))
Und hier die ersten paar Strings:
>>> from counterstring import * >>> for length in range(20): ... print(generate_counter_string(length)) ... * 2* *3* 2*4* *3*5* 2*4*6* *3*5*7* 2*4*6*8* *3*5*7*9* *3*5*7*10* 2*4*6*8*11* *3*5*7*9*12* *3*5*7*10*13* 2*4*6*8*11*14* *3*5*7*9*12*15* *3*5*7*10*13*16* 2*4*6*8*11*14*17* *3*5*7*9*12*15*18* *3*5*7*10*13*16*19*
Schöne Liste mit Webdev Tools für Firefox
2011-11-28 16:56
http://hacks.mozilla.org/2011/11/firefox-tons-of-tools-for-web-developers/
Klassischer Trojaner
2011-11-01 07:19
Ein Link auf den klassischen Trojaner-Artikel von Ken Thompson: man baut den Compiler so um, dass er a) beim Kompilieren von login ein Backdoor einbaut und b) beim Kompilieren des C-Compilers die Backdoor-Einbau-Funktionalität wieder einbaut. Hat man das und hat man den Compiler und Login kompiliert, kann man die Sourcen in den ursprünglichen Zustand zurückversetzen. Man sieht also nichts, aber die Löcher sind da und bleiben auch beim Rekompilieren der sauberen Sourcen weiter da. Nur ein Blick auf das Kompilat kann helfen.
jQuery Ajax
2011-10-04 11:15
Gestern hatte ich ein Problem mit jQuery. Ich hatte von 1.4.x nach 1.6.x aktualisiert. Danach liefen verschiedene Ajax-Aufrufe nicht mehr. Es gab keine Fehlermeldung, in Firebug war der Request mit Status 200 erfolgreich, aber die Success-Funktion wurde nicht aufgerufen.
Der Aufruf sah in etwa so aus:
$.get("url", function (data) { ... }, "text/plain");
Nach längerem Suchen und Werweisen fand ich heraus, dass folgendes funktioniert:
$.get("url", function (data) { ... }, "text");
Also keinen Mimetype nehmen, sondern aus der (dokumentierten) Liste der möglichen Werte. Seufz. Seltsam nur, dass es in 1.4.x noch lief.
Bei der Gelegenheit habe ich auch noch $.getJSON entdeckt. Bisher habe ich immer mit $.get den Text geholt und dann mit Crockfords JSON-Parser geparst. So geht es natürlich einfacher und ich kann den JSON-Parser weglassen.
Umlaute bei CGI in Python 3
2011-10-03 11:22
Nochmals zum Thema Umlaute bei CGI in Python 3.
Mittlerweile habe ich eine einfachere Lösung gefunden. Wenn die Umgebungsvariable PYTHONIOENCODING korrekt gesetzt ist (also auf utf8) dann macht Python von sich aus alles richtig.
In Apache kann man das mit der SetEnv Direktive machen:
SetEnv PYTHONIOENCODING utf8
Dann braucht es keine Verrenkungen à la
sys.stdin = codecs.getreader('utf8')(sys.stdin.buffer)
sys.stdout = codecs.getwriter('utf8')(sys.stdout.buffer)
Diese Lösung gefällt mir.
Search-Replace in Java
2011-09-06 08:49
Java besitzt eine ReplaceAll Methode auf der String-Klasse. Diese nimmt eine Regexp als erstes Argument und einen Replacement-String als zweiten. Im Replacement-String haben Backslash und Dollar besondere Bedeutungen. Um diese zu verhindern, kann man die statische Methode Matcher.quoteReplacement verwenden.
Ein Beispiel: ich möchte alle Quotes mit einem Backslash escapen, d.h. a"b zu a\"b verändern.
Das folgende ist falsch:
token.replaceAll("\"", "\\\"")
hingegen funktioniert
token.replaceAll("\"", Matcher.quoteReplacement("\\\""))
korrekt.
Bilder in Div mit CSS zentrieren
2011-06-23 13:36
Heute musste ich Bilder zentrieren. Es handelte sich um eine Galerieansicht, die eine Reihe von Bildern mit je ein paar Textdaten darstellt. Bisher habe ich das mit Javascript gemacht, was aber nicht genügt, weil die Bilder dann erst nach vollständigem Laden der Seite (inklusive Bilder) zentriert werden. Das führt zu einem Hüpfeffekt. Je mehr Bilder die Seite umfasst, umso verzögerter und damit ausgeprägter wird der Effekt. Darum ist es richtig und gut, sowas über CSS zu lösen.
Diese Seite beschreibt eine Lösung des Problems.
Checkinstall Tool
2011-06-05 12:10
Ein ganz tolles Tool im Linux Umfeld ist checkinstall. Es protokolliert die Installation einer nicht-paketierten Software und erstellt ein Paket dafür (deb, rpm, ...). Damit kann die Software sauber deinstalliert werden.
Als Beispiel habe ich ein script setup.sh gemacht, das ein paar Dateien nach /opt/x kopiert.
Mit
sudo checkinstall --pkgname=x --pkgversion "1.0.0" --backup=no --default ./setup.sh
wird es ausgeführt, erstellt ein Paket x und installiert es. Danach kann man es mit dpkg -r x wieder entfernen.
Umlaute bei CGI in Python 3.2
2011-06-04 17:22
In Python 3.0 und 3.1 musste ich folgendes machen, damit Umlaute korrekt behandelt werden:
sys.stdin = codecs.getreader('utf8')(sys.stdin.buffer)
sys.stdout = codecs.getwriter('utf8')(sys.stdout.buffer)
form = cgi.FieldStorage()
Dieser Code funktioniert bei Python 3.2 nicht mehr. Der Grund dafür ist, dass Python 3.2 im cgi Modul explizit ein encoding hinzugefügt hat und dafür direkt auf sys.stdin.buffer zugreift. Der StreamReader von codecs.getreader hat aber keinen buffer. Also knallts.
Da aber das Encoding direkt angegeben werden kann, funktioniert der folgende Code:
sys.stdout = codecs.getwriter('utf8')(sys.stdout.buffer)
form = cgi.FieldStorage(sys.stdin, encoding="utf8")
sys.stdin wird also nicht mehr gewrappt, dafür das richtige encoding in cgi.FieldStorage angegeben.
Ich habe das Ganze nun in ein Modul gepackt und je nach Version wird das korrekte Verhalten ausgeführt:
# module stdio.py
import cgi
import codecs
import sys
def is_at_least_3_2():
return sys.version_info.major > 3 or sys.version_info.minor >= 2
def init():
if is_at_least_3_2():
pass
else:
sys.stdin = codecs.getreader('utf8')(sys.stdin.buffer)
sys.stdout = codecs.getwriter('utf8')(sys.stdout.buffer)
def cgi_form():
if is_at_least_3_2():
return cgi.FieldStorage(sys.stdin, encoding="utf8")
else:
return cgi.FieldStorage()
Damit sieht der Code dann so aus:
import stdio stdio.init() form = stdio.cgi_form()
Java Shutdown Hook
2011-05-26 15:58
Heute benötigt: Wenn der Publisher Lasttest abgebrochen wird, soll eine Zusammenfassung mit den wichtigsten Kennzahlen ausgegeben werden. In Java kann man das mit einem Shutdown-Hook machen:
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
reporter.reportOverall(stats.snapshot());
server.stop();
}
});
Die run-Methode wird vor dem Beenden der JVM aufgerufen. Sie gibt - in dem Fall - einen Statusreport aus und stoppt den Infowebserver.
Classpath in Ant
2011-05-26 09:26
Heute herausgefunden: statt alle jars in einem langen Classpath einzeln aufzuzählen, kann man in ant auch folgendes Konstrukt verwenden:
<path id="lib.classpath">
<fileset dir="lib">
<include name="*.jar" />
</fileset>
</path>
Damit werden alle jars im Verzeichnis lib in den Klassenpfad aufgenommen. Simpel aber effektiv.
Apache HttpClient
2011-05-23 15:45
Um den ims Publisher sinnvoll testen zu können (Lasttests, Ausdauertests) habe ich in der Imagic ein Projekt gestartet das dass Verhalten von Benutzern simulieren kann. Um die eigentlichen Requests durchzuführen verwende ich Apache HttpClient.
Das hat sich als erstaunlich einfach und problemlos erwiesen. Insbesondere werden die Cookies automatisch korrekt behandelt, sodass es trivial ist, eine ganze Usersession zu simulieren.
Im wesentlichen muss man nur
HttpClient client = new DefaultHttpClient(); HttpGet request = new HttpGet(url); HttpResponse response = client.execute(request);
aufrufen. Ich habe entsprechende Builtins in Scriptlang eingebaut und kann nun eine ganze Seite inklusive Bilder mit ein bisschen Scriptcode laden:
var http = http_client();
var imagerx = regexp(r'img\s+src="([^"]+)"');
def get_page_with_images(u) {
var start = now();
var response = http.get(u);
log(response.timestamp() + " " + u + " " + response.status());
var images = imagerx.matcher(response.contents()).findall();
for match in images {
var image = match[1][0];
var response = http.get(url + image);
log(response.timestamp() + " " + url + image + " " + response.status());
}
}
Das rufe ich dann in einem Loop einige Male auf
for r in range(1, 10) {
get_page_with_images(url + "?showall");
for i in range(1, 500) {
get_page_with_images(url + "?from=" + (20 * i));
}
}
und schon ist ein simpler Lasttest am Laufen. Das nächste wäre dann realistischere User zu simulieren, diese parallel laufen zu lassen und vor allem Metriken zu Requestduration und Memoryload etc. zu sammeln und verfügbar zu machen.
Java Memory Probleme
2011-05-19 10:45
Immer mal wieder läuft man bei Java in Probleme mit dem Speicher. Sei es dass man in OutOfMemoryErrors hineinläuft, oder dass man übermässig viele GCs hat, oder dass die PermGen überläuft. All das tritt normalerweise aufgrund von Programmierfehlern auf. Die JVM hat eine Unmenge von Optionen und viele davon helfen solche Probleme zu diagnostizieren und/oder zu beheben.
Mit
-XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintHeapAtGC
kann man ziemlich umfassende Statistiken und Infos bezüglich der auftretenden GC ausgeben.
Mit
-XX:+PrintClassHistogram
kann man eine Zusammenstellung der verwendeten Klassen ausgeben. Dazu muss man ein SIGQUIT schicken (kill -3 <pid>)
Mit
-XX:+TraceClassLoading -XX:+TraceClassUnloading
bekommt man Infos über das Laden und Entladen von Klassen (die in die PermGen kommen).
Die PermGen kann man mit
-XX:MaxPermSize=128m
erhöhen. Das dynamische Entladen von Klassen kann man mit
-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled
einschalten.
Die Seite jvm-options-list listet alle diese Optionen und noch viele mehr auf. Man kann wohl tagelang nur schon mit den GC Optionen rumspielen, wenn man denn Zeit und Geduld dafür hat. Die Defaulteinstellung ist aber normalerweise relativ gut. Vielleicht noch mit -Xmx und -X:MaxPermSize um die Heapgrösse und die PermGen hinaufzusetzen.
Safari Books abbestellt
2011-05-18 09:20
Vor ein paar Tagen habe ich mein Safari Books Abo gekündigt. Es ist zwar ein tolles Angebot, aber einfach ein Tick zu teuer für mich. Und seit ich den Kindle habe, habe ich fast alle nötige Fachliteratur auf den Kindle geladen (und dafür ein Vermögen ausgegeben!) So brauche ich Safari Books zuwenig für den stattlichen Monatspreis.
Content Security Policy in Firefox 4
2011-05-13 12:31
Heise hat einen guten Artikel zum neuen Content Security Policy Header in Firefox 4. Es geht dabei um das Verhindern von Cross-Site-Scripting Attacken. Ist der Header gesetzt, wird JavaScript nur noch von den definierten Sites nachgeladen und in die Seite eingebetteter Code nicht ausgeführt.
ScrollTop für alle Browser
2011-05-03 15:31
Um korrekt ScrollTop des Dokuments feststellen zu können, sollte man
$(window).scrollTop()
verwenden. Das funktioniert mit allen Browsern.
Link: Dictionary of Algorithms and Data Structures
2011-04-29 09:46
Umrechnung Koordinaten WGS84-CH1903
2011-04-28 13:31
Von Swisstopo gibt es ein Javascript um Koordinaten zwischen WGS84 und CH1903 umzurechnen:
<script language="Javascript">
// Convert WGS lat/long (° dec) to CH y
function WGStoCHy(lat, lng) {
lat = DECtoSEX(lat);
lng = DECtoSEX(lng);
lat = DEGtoSEC(lat);
lng = DEGtoSEC(lng);
// Axiliary values (% Bern)
var lat_aux = (lat - 169028.66)/10000;
var lng_aux = (lng - 26782.5)/10000;
y = 600072.37
+ 211455.93 * lng_aux
- 10938.51 * lng_aux * lat_aux
- 0.36 * lng_aux * Math.pow(lat_aux,2)
- 44.54 * Math.pow(lng_aux,3);
return y;
}
// Convert WGS lat/long (° dec) to CH x
function WGStoCHx(lat, lng) {
lat = DECtoSEX(lat);
lng = DECtoSEX(lng);
lat = DEGtoSEC(lat);
lng = DEGtoSEC(lng);
// Axiliary values (% Bern)
var lat_aux = (lat - 169028.66)/10000;
var lng_aux = (lng - 26782.5)/10000;
x = 200147.07
+ 308807.95 * lat_aux
+ 3745.25 * Math.pow(lng_aux,2)
+ 76.63 * Math.pow(lat_aux,2)
- 194.56 * Math.pow(lng_aux,2) * lat_aux
+ 119.79 * Math.pow(lat_aux,3);
return x;
}
// Convert CH y/x to WGS lat
function CHtoWGSlat(y, x) {
// Converts militar to civil and to unit = 1000km
// Axiliary values (% Bern)
var y_aux = (y - 600000)/1000000;
var x_aux = (x - 200000)/1000000;
lat = 16.9023892
+ 3.238272 * x_aux
- 0.270978 * Math.pow(y_aux,2)
- 0.002528 * Math.pow(x_aux,2)
- 0.0447 * Math.pow(y_aux,2) * x_aux
- 0.0140 * Math.pow(x_aux,3);
return lat * 100/36;
}
// Convert CH y/x to WGS long
function CHtoWGSlng(y, x) {
// Converts militar to civil and to unit = 1000km
// Axiliary values (% Bern)
var y_aux = (y - 600000)/1000000;
var x_aux = (x - 200000)/1000000;
lng = 2.6779094
+ 4.728982 * y_aux
+ 0.791484 * y_aux * x_aux
+ 0.1306 * y_aux * Math.pow(x_aux,2)
- 0.0436 * Math.pow(y_aux,3);
return lng * 100/36;
}
function SEXtoDEC(angle) {
var deg = parseInt( angle );
var min = parseInt( (angle-deg)*100 );
var sec = (((angle-deg)*100) - min) * 100;
// Result in degrees sex (dd.mmss)
return deg + (sec/60 + min)/60;
}
function DECtoSEX(angle) {
var deg = parseInt( angle );
var min = parseInt( (angle-deg)*60 );
var sec = (((angle-deg)*60)-min)*60;
// Result in degrees sex (dd.mmss)
return deg + min/100 + sec/10000;
}
function DEGtoSEC(angle) {
var deg = parseInt( angle );
var min = parseInt( (angle-deg)*100 );
var sec = (((angle-deg)*100) - min) * 100;
// Result in degrees sex (dd.mmss)
return sec + min*60 + deg*3600;
}
</script>