Damian Brunold

Counter Strings in Python

2011-11-29 11:51 Programmieren, Python, Testen

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 Programmieren, Web

http://hacks.mozilla.org/2011/11/firefox-tons-of-tools-for-web-developers/

Klassischer Trojaner

2011-11-01 07:19 Programmieren

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 JavaScript, Programmieren, Web

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 Programmieren, Python, Web

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, Programmieren

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 CSS, JavaScript, Programmieren, Web

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 Linux

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 Programmieren, Python, Web

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 Java, Programmieren

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 Java, Programmieren

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 Imagic, Java, Programmieren, Web

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 Java, Linux, Programmieren

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 Programmieren, Web

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.

http://www.heise.de/security/artikel/Abhilfe-gegen-Cross-Site-Scripting-und-Clickjacking-1214277.html

ScrollTop für alle Browser

2011-05-03 15:31 Programmieren, Web

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 Algorithmen, Programmieren

http://xlinux.nist.gov/dads/

Umrechnung Koordinaten WGS84-CH1903

2011-04-28 13:31 JavaScript, Mathe, Programmieren, Web

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>

Alle Einträge