Archive 26.7.2005 - 4.8.2005

Shoot-to-Kill Directives - and the World Becomes a First-Person Shooter

Bruce Schneier on Shoot-to-Kill and specifically a proposal by the International Association of Chiefs of Police. Translated from the proposal:

... such a person exhibits "various unusual behaviors" such as wearing a heavy coat or thick jacket in warm weather, carrying a suitcase, shoulder bag, or backpack with bulges or visible wires. The person shows nervousness, avoids eye contact, or sweats profusely. There may be chemical residues on the clothing or hands. The person may be mumbling prayers or rocking back and forth.

Note what is to be done with such persons is clear to the Chiefs of Police: shoot them in the head. Final killing shot. And of course, no further reason is needed for this:

... the threat to the officer does not need to be immediate, as taught in normal procedure. Officers do not need to wait until a person suspected of being an attacker makes a move, as would be necessary in the normal use of firearms. An officer only needs to have a reasonable suspicion that the suspect could detonate a bomb.

Bruce Schneier rightly asks if we would really feel safe if such a directive were implemented. Every pickpocket shows enough characteristics to be shot down at some point if such a dehumanizing directive were actually implemented.

We know how quickly dehumanizing ideas suddenly make it onto the agenda here ...

A Treeview in JavaScript that can be used within pages (without frames) and still remembers its state.

Cisco customer passwords are gone - this is so embarrassing, it really hurts. Oops. And it's Cisco.

Django, Apache and FCGI

In Django, lighttpd and FCGI, second take I described a method how to run Django with FCGI behind a lighttpd installation. I did run the Django FCGIs as standalone servers so that you can run them under different users than the webserver. This document will give you the needed information to do the same with Apache 1.3.

Update: I maintain my descriptions now in my trac system. See the Apache+FCGI description for Django.

Update: I changed from using unix sockets to using tcp sockets in the description. The reason is that unix sockets need write access from both processes - webserver and FCGI server - and that's a bit hard to setup right, sometimes. tcp sockets are only a tad bit slower but much easier to set up.

First the main question some might ask: why Apache 1.3? The answer is simple: many people still have Apache 1.3 running as their main server and can't easily upgrade to Apache 2.0 - for example if they run large codebases in mod perl or mod python they will run into troubles with migrating because Apache 2.0 will require mod perl2 or mod python2 and both are not fully compatible with older versions. And even though lighttpd is a fantastic webserver, if you already run Apache 1.3 there might just not be the need for another webserver.

So what do you need - besides the python and django stuff - for Apache 1.3 with FastCGI? Just the mod rewrite module and mod fastcgi module installed, that's all. Both should come with your systems distribution. You will still need all the python stuff I listed in the lighttpd article.

mod_fastcgi is a bit quirky in it's installation, I had to play a bit around with it. There are a few pitfalls I can think of:

  • the specification of the socket can't be an absolute path but must be a relative path with respect to the FastCgiIpcDir
  • the specification of the FCGI itself (even though it's purely virtual) must be in a fully qualified form with respect to the document root you want to use. If you use a relative path, it will be relative to the document root of the default virtual host - and that's most surely not the document root you will use if you want to set up a virtual host with the FCGI.
  • the FCGI itself can't be defined within a virtual host - it must be defined in the main server config. That's where the relative addressing problem comes into play.
  • the socket file must be both readable and writeable by the FCGI user and the Apache user. Usually you do this by changing the socket file to group writeable and changing the group of that socket file to a group where both the user and the apache are members of.

Now here is the config snippet you have to add to your httpd.conf. I use the same directories as with the lighttpd sample, you most surely will have to adapt that to your situation.


 FastCgiExternalServer /home/gb/work/myproject/publichtml/admin.fcgi -host 127.0.0.1:8000
FastCgiExternalServer /home/gb/work/myproject/publichtml/main.fcgi -host 127.0.0.1:8001

 <VirtualHost *> ServerAdmin gb@bofh.ms
 Servername www.example.com
 ErrorLog /home/gb/work/myproject/logs/django-error.log
 CustomLog /home/gb/work/myproject/logs/django-access.log combined
 DocumentRoot /home/gb/work/myproject/public_html
 RewriteEngine On
 RewriteRule ^(/admin/.)$ /admin.fcgi$1 [L]
 RewriteRule ^(/main/.)$ /main.fcgi$1 [L]
 </VirtualHost> ```

You have to allow the webserver write access to the logs directory, so you might want to use a different location for them - possibly in `/var/log/apache/ `or whereever your apache puts it's logs. The FastCgiExternalServer directives must be outside of the virtual host definitions, but must point to files within the virtual hosts document root. But those files needn't (and probably shouldn't) exist in the filesystem, they are purely virtual. The given setup reflects the setup I did for the lighttpd scenario.

Now restart your apache, start your django-fcgi.py and you should be able to access your django application. Keep in mind to copy the admin_media files over to the document root, otherwise your admin will look very ugly.

django-fcgi.py --settings=myproject.settings.main --host=127.0.0.1 --port=8000 --daemon django-fcgi.py --settings=myproject.settings.admin --host=127.0.0.1 --port=8001 --daemon


Have fun.

EU Brainless about Copyright Infringements

What nonsense. If the proposal goes through, using open-source software will become risky:

A new draft law by the European Commission aims to allow lawsuits against users in case of suspected copyright infringement in software. In addition to the perpetrator, companies that feel safe due to their licenses would also come under fire. This was reported by the British trade magazine 'ZDNet UK'.

Given the current impression of the SCO case, it should be clear to everyone that such an idea is complete nonsense - because that's exactly what SCO wanted to do, to extort all Linux users. There are hardly any ideas stupid enough that they couldn't occur to a politician ...

Geocaching in Münsterland

Now that I have a Garmin Geko 201, I naturally have to take a look at the information about Geocaching. Does anyone have a good link to Geocaching activists in Münster and the surrounding area? That would be something for our upcoming vacation. Jutta always complains that she doesn't know the Münsterland well enough, so checking out Geocaches would be the ideal method to explore the area.

As a first starting point, I will take a look at the entries on geocaching.de for Ruhrpott and Emsland - we are neither Ruhrpott nor Emsland, but close enough to be included in both.

In addition, I now have a good reason to tell Jutta why I bought the thing.

And when I look at instructions like those for Vaders Stein, it will even be perfect for Jutta - she loves puzzle games. Hey, it could easily become a new hobby ...

Again something new with Django

There's always news, but this time there's a very interesting feature again: the inspectdb command delivers all the tables and fields from a PostgreSQL database in the format of a Python data model. Additionally, foreign keys are also found if they are stored in the database. Very practical if you need to build an interface for an existing database, you save a lot of typing work.

Social Networking

Well, I've also registered in one of these great social (in this case rather business-social) networks, specifically the O'Reilly Connection. Don't want to be considered bitter and aged.

Anyone who manages to find me there can define a connection to me. And laugh at my silly photo ...

Ian Bicking on what's currently happening with SQLObject - it had become quite quiet around one of the nicest SQL object layers for Python, but now it's moving forward again. The most interesting point for me: Tool support for database upgrades. A point that, for example, is still missing in Django.

But patents are sooo great ...

... but only when your own central bank becomes the target of a patent infringement lawsuit: European Central Bank sued for patent infringement. Will this perhaps wake people up at the EU Council? Oh, forget it, they won't wake up in this life, then they would have to recognize their own corruption ...

The equivalent to Apple FileSafe under Linux: Automatically mount dm-crypt encrypted home with pam_mount. Very useful for laptops, but also for workstations of administrators (due to the many security-relevant files that accumulate in the home directory).

Coroutines for Python

Philip J. Eby has provided a patch for the implementation of PEP 342. This means that the chances of Python having coroutines in the future are very good.

And that, in turn, means that Python will get a - albeit primitive - form of continuations. Now all that's missing is for something like statesaver to be integrated into Python - for multishot continuations (ok, first just copyable coroutines, but that would be a start at least).

All of this, of course, just to finally be able to work with continuations in web frameworks. Ok, it's already possible with CherryFlow, but it would be nice if all of this would make it into mainstream Python.

Whoever wants to deal with larger Erlang software and try out a Jabber server, might find ejabberd interesting - a Jabber server that uses all the nice features of Erlang to offer, for example, simple clustering and good data distribution.

Hell freezes over - a second time

First Intel processors and now more than one mouse button. And even something similar to a scroll wheel. Shocking.

And another Linux-on-Mac story. This time an iBook and Gentoo. Quite useful for a small and affordable Linux box for on the go.

The Linux on an Apple Powerbook HOWTO provides exactly what I would need if I wanted to switch my 12" Powerbook to Linux - the author even uses exactly my model. And no, I don't want to switch yet.

The Illusive setdefaultencoding

Ian Bicking mentioned a nice trick in his article about setdefaultencoding: simply reload the sys module with reload(sys) to make setdefaultencoding available.

setdefaultencoding is used to set the default encoding for bytestrings. Normally, this is ASCII, but it can be changed to iso-8859-1 or utf-8 - if you have setdefaultencoding at all. Unfortunately, it is deleted when the Python runtime environment starts - because the Python developers want to patronize the users again.

reload(sys) is of course something that does not necessarily inspire confidence - sys is after all not an unimportant module. But in my experiments it has worked so far and it definitely helps with the whole Unicode problem if you can give your programs a different encoding as standard.

It would be nicer if setdefaultencoding were not deleted in the standard distribution. Of course, this can also be achieved by patching site.py, but that is not better than reloading sys ...

(Un)trusted platform Apple?

Since it's currently fashionable to explain that one switched when Apple uses TPA - or whatever it might be called in the future: first wait and see. See what Apple does and how - there are always rumors beforehand.

If TPA is actually included: Linux can also be a usable system, even if the interfaces are quite sick (although current XFCE versions don't look that bad) and if there is no more PPC in Apple hardware and you put Linux on it: you can also buy your notebook from IBM. They have nice devices that also work very well under Linux.

And last but not least: just because new Apple hardware is different, it doesn't change the already purchased hardware - and Apple-typically, this usually lasts a few years longer. And under Linux, some Macs even run faster than under OS X.

Where Cease and Desist Notices and Anticipatory Obedience Can Lead

Just what the FFII noticed: Nutzwerk shut down FFII.org (a bit more info as usual at Heise).

Although the corresponding IP address was consistently reachable, the DNS provider registered as the technical contact for the domain FFII.org complied with Nutzwerk's request and shut down the domain FFII.org on the previous Friday afternoon. The name resolution of FFII.org and corresponding subdomains did not work temporarily. After an intervention by the FFII, the DNS provider reactivated the domain that same evening and wants to ask Nutzwerk for a clarification of the demand, according to FFII board member Hartmut Pilch to Golem.de.

A real dilemma: service providers want to protect themselves and unfortunately the Telemedia Act makes life difficult for these service providers: if they are notified of content that constitutes a legal violation, they must remove this content immediately. But how can one assess whether content constitutes a legal violation? Especially when it comes to things like at Nutzwerk - where critical reporting by the company is defined as a legal violation?

In the end, this gives companies a means of censorship without giving service providers (and of course the website operators themselves!) reasonable means of defense. How, for example, is a smaller provider supposed to protect itself from cease-and-desist letters with absurd claim amounts - as the music industry particularly likes to use? Legal protection insurance doesn't help here.

No wonder that some providers see preemptive obedience as the right strategy in such cases - they lose at most the customer they shut down, perhaps a bit of negative press, but taking on a fight against a company with exaggerated ideas, they can't win much.

If you then sit on the board of a privately operated provider like me, you start to wonder what the actual goal of these legislative changes in the context of the Telemedia Act really was ...

Effects of Genetically Modified Rapeseed and Co.

At Isotopp I found a pointer to information about the British evaluation project on genetically modified seeds. Shocking, what effects this has, for example, on related wild plants and what this will mean for us in the long run. But of course, it's all sooo safe and sooo important for us - it's really just about the revenue for the genetic engineering companies, not about what consumers really want.

But of course, every critic of genetically modified seeds is dismissed as a crank by the economy and its henchmen (such as Clement and other politicians).

Dave's new OPML editor with blog

I'm currently playing around with Dave Winer's OPML Editor, which he now uses for his blog. It looks quite fun and has a lot of features. My OPML Blog has collected some of the insights I've gained from it. I certainly won't switch over just like that - that would be Quark, which is not necessarily my target software. But it's fun to play with something completely different again.

Unfortunately, the OPML Editor has inherited some of the ailments of Radio Userland and Frontier, especially the handling of umlauts is not really smooth (I would like to have consistent UTF-8 support finally) and the runtime behavior is better than in Radio, but it still occasionally consumes too much CPU.

The concept of rendered outlines does have a certain charm. However, many parts of the rendering are not really accessible to normal users - you can edit the ancient table layout and make something else out of it, but the OPMLs are implemented with the internal OPML renderer and the HTML fragments are not so easy to change - and thus, for example, changing the language is quite cumbersome, as is the complete removal of layout tables.

More will certainly appear on the OPML blog from time to time, here I will write at most a few conclusions.

HEW Cyclassics 2005

A really nice race - it's always amazing how even a nearly quarter-hour lead isn't enough to bring home a victory in this race. It's also always amazing how the commentators every time say that the main field starts too late - by now they should know.

The Quickstep action was great - taking the victory and the podium positions away from the Fassa Bortolo guys after their sprint build-up is really super. Even if I would of course have preferred to see Zabel up front.

Merkelnix is also cramping

Just so no one thinks only the SPD has brainless slogans to shout into the world: "Make work possible in Germany again" is the reason why they want to increase the value-added tax:

Union Chancellor candidate Angela Merkel defended the planned increase in value-added tax by the CDU and CSU. The Union wants to achieve the goal of reducing labor costs with this, she said in an interview with "Bericht aus Berlin". It is about "making work possible in Germany again and thus enabling social security," the CDU chairwoman continued.

Sorry, but how incredibly stupid is that? Social security through an increase in value-added tax, which hits the hardest those who cannot further reduce their consumption because it already only consists of staple foods and other expenses necessary for survival?

Software Patents - Commentary in the NY Times

The NY Times asks why Bill Gates wants 3,000 new patents and finds a massive siege of the patent office with mountains of software patents, which are often just trivial patents (like the cited patent for adding/removing spaces in documents). The commentator makes a demand in the comment (after considering whether Microsoft should not simply have all the patents it already has revoked):

Perhaps that is going too far. Certainly, we should go through the lot and reinstate the occasional invention embodied in hardware. But patent protection for software? No. Not for Microsoft, nor for anyone else.

And this from the country that has had software patents for a long time and that is repeatedly cited by software patent proponents in the EU as a reason for a necessary worldwide harmonization.

No, software patents are also not popular there and not really useful. Dan Bricklin, known to some as the father of VisiCalc, also thinks so:

Mr. Bricklin, who has started several software companies and defensively acquired a few software patents along the way, says he, too, would cheer the abolition of software patents, which he sees as the bane of small software companies. "The number of patents you can run into with a small product is immense," he said. As for Microsoft's aggressive accumulation in recent years, he asked, "Isn't Microsoft the poster child of success without software patents?"

And why is Microsoft doing this now? The manager responsible gives a reason, as only a business administrator could come up with, it's that stupid:

"We realized we were underpatenting," Mr. Smith explained. The company had seen studies showing that other information technology companies filed about two patents for every $1 million spent on research and development. If Microsoft was spending $6 billion to $7.5 billion annually on its R&D, it would need to file at least 3,000 applications to keep up with the Joneses.

Ok, the idea of patent applications alone being oriented towards numbers from the industry is absurd, but how stupid do you have to be to draw a connection between the number of patents and revenue in the field of research and development?

The NY Times also draws a parallel to the pharmaceutical industry, which - at least according to its own statements - is happy to get a patent for a drug when it invests 20 million in research (which is already critical enough, as can be seen in the fight against AIDS in Africa).

And the fallout is also well summarized in the NY Times:

Last year at a public briefing, Kevin R. Johnson, Microsoft's group vice president for worldwide sales, spoke pointedly of "intellectual property risk" that corporate customers should take into account when comparing software vendors. On the one side, Microsoft has an overflowing war chest and bulging patent portfolio, ready to fight - or cross-license with - any plaintiff who accuses it of patent infringement. On the other are the open-source developers, without war chest, without patents of their own to use as bargaining chips and without the financial means to indemnify their customers.

The question of what Jefferson (the founder of the US patent system) would say about what is now being patented is quite justified. In his sense - which was actually more about protecting real inventive genius from exploitation by corporations - this is definitely not the case.

Election Campaign, Election Agony ...

Münte on the Roll: Linkspartei "politically and legally absurd". I have the impression, however, that he would help the SPD more by giving them a program that appeals to ordinary citizens again, instead of simply stirring up fear of the left and spreading defamation (sorry, but the combination of PDS and WASG in the open list may be strange, but legally flawless - claiming otherwise is simply defamation).

If the SPD cannot achieve more in the election campaign than just to blow the horn of the Union parties against the alleged danger from the left, the SPD will simply put itself out of the political game - with such nonsense, you don't win an election. If the SPD is nothing more than a union with a red tie, it can stay away from me ...

Writing a Simple Filesystem Browser with Django

Dieser Artikel ist mal wieder in Englisch, da er auch für die Leute auf #django interessant sein könnte. This posting will show how to build a very simple filesystem browser with Django. This filesystem browser behaves mostly like a static webserver that allows directory traversal. The only speciality is that you can use the Django admin to define filesystems that are mounted into the namespace of the Django server. This is just to demonstrate how a Django application can make use of different data sources besides the database, it's not really meant to serve static content (although with added authentication it could come in quite handy for restricted static content!).

Even though the application makes very simple security checks on passed in filenames, you shouldn't run this on a public server - I didn't do any security tests and there might be buttloads of bad things in there that might expose your private data to the world. You have been warned. We start as usual by creating the filesystems application with the django-admin.py startapp filesystems command. Just do it like you did with your polls application in the first tutorial. Just as an orientation, this is how the myproject directory does look like on my development machine:


.
|-- apps
| |-- filesystems
| | |-- models
| | |-- urls
| | `-- views
| `-- polls
| |-- models
| |-- urls
| `-- views
|-- public_html
| `-- admin_media
| |-- css
| |-- img
| | `-- admin
| `-- js
| `-- admin
|-- settings
| `-- urls
`-- templates
 `-- filesystems

After creating the infrastructure, we start by building the model. The model for the filesystems is very simple - just a name for the filesystem and a path where the files are actually stored. So here it is, the model:


 from django.core import meta

class Filesystem(meta.Model):

fields = ( meta.CharField('name', 'Name', maxlength=64), meta.CharField('path', 'Path', maxlength=200), )

def repr(self): return self.name

def get_absolute_url(self): return '/files/%s/' % self.name

def isdir(self, path): import os p = os.path.realpath(os.path.join(self.path, path)) if not p.startswith(self.path): raise ValueError(path) return os.path.isdir(p)

def files(self, path=''): import os import mimetypes p = os.path.realpath(os.path.join(self.path, path)) if not p.startswith(self.path): raise ValueError(path) l = os.listdir(p) if path: l.insert(0, '..') return [(f, os.path.isdir(os.path.join(p, f)), mimetypes.guess_type(f)[0] or 'application/octetstream') for f in l]

def file(self, path): import os import mimetypes p = os.path.realpath(os.path.join(self.path, path)) if p.startswith(self.path): (t, e) = mimetypes.guess_type(p) return (p, t or 'application/octetstream') else: raise ValueError(path)

admin = meta.Admin( fields = ( (None, {'fields': ('name', 'path')}), ), list_display = ('name', 'path'), search_fields = ('name', 'path'), ordering = ['name'], )


As you can see, the model and the admin is rather boring. What is interesting, though, are the additional methods isdir , files and file . isdir just checks wether a given path below the filesystem is a directory or not. files returns the files of the given path below the filesystems base path and file returns the real pathname and the mimetype of a given file below the filesystems base path. All three methods check for validity of the passed in path - if the resulting path isn't below the filesystems base path, a ValueError is thrown. This is to make sure that nobody uses .. in the path name to break out of the defined filesystem area. So the model includes special methods you can use to access the filesystems content itself, without caring for how to do that in your views. It's job of the model to know about such stuff.

The next part of your little filesystem browser will be the URL configuration. It's rather simple, it consists of the line in settings/urls/main.py and the myproject.apps.filesystems.urls.filesystems module. Fist the line in the main urls module:


 from django.conf.urls.defaults import *

urlpatterns = patterns('',
 (r'^files/', include('myproject.apps.filesystems.urls.filesystems')),
 )

Next the filesystems own urls module:


 from django.conf.urls.defaults import *

urlpatterns = patterns('myproject.apps.filesystems.views.filesystems',
 (r'^$', 'index'),
 (r'^(?P<filesystem_name>.*?)/(?P<path>.*)$', 'directory'),
 )

You can now add the application to the main settings file so you don't forget to do that later on. Just look for the INSTALLED_APPS setting and add the filebrowser:


 INSTALLED_APPS = (
 'myproject.apps.polls',
 'myproject.apps.filesystems'
 )

One part is still missing: the views. This module defines the externally reachable methods we defined in the urlmapper. So we need two methods, index and directory . The second one actually doesn't work only with directories - if it get's passed a file, it just presents the contents of that file with the right mimetype. The view makes use of the methods defined in the model to access actual filesystem contents. Here is the source for the views module:


 from django.core import template_loader
 from django.core.extensions import DjangoContext as Context
 from django.core.exceptions import Http404
 from django.models.filesystems import filesystems
 from django.utils.httpwrappers import HttpResponse

def index(request):
 fslist = filesystems.getlist(orderby=['name'])
 t = templateloader.gettemplate('filesystems/index')
 c = Context(request, {
 'fslist': fslist,
 })
 return HttpResponse(t.render(c))

def directory(request, filesystem_name, path):
 import os
 try:
 fs = filesystems.getobject(name exact=filesystemname)
 if fs.isdir(path):
 files = fs.files(path)
 tpl = templateloader.gettemplate('filesystems/directory')
 c = Context(request, {
 'dlist': [f for (f, d, t) in files if d],
 'flist': [{'name':f, 'type':t} for (f, d, t) in files if not d],
 'path': path,
 'fs': fs,
 })
 return HttpResponse(tpl.render(c))
 else:
 (f, mimetype) = fs.file(path)
 return HttpResponse(open(f).read(), mimetype=mimetype)
 except ValueError: raise Http404
 except filesystems.FilesystemDoesNotExist: raise Http404
 except IOError: raise Http404

See how the elements of the directory pattern are passed in as parameters to the directory method - the filesystem name is used to find the right filesystem and the path is used to access content below that filesystems base path. Mimetypes are discovered using the mimetypes module from the python distribution, btw.

The last part of our little tutorial are the templates. We need two templates - one for the index of the defined filesystems and one for the content of some path below some filesystem. We don't need a template for the files content - file content is delivered raw. So first the main index template:


{% if fslist %}
<h1>defined filesystems</h1> <ul> {% for fs in fslist %}
<li><a href="{{ fs.get_absolute_url }}">{{ fs.name }}</a></li> {% endfor %}
</ul> {% else %}
<p>Sorry, no filesystems have been defined.</p> {% endif %}

The other template is the directory template that shows contents of a path below the filesystems base path:


 {% if dlist or flist %}
 <h1>Files in //{{ fs.name }}/{{ path }}</h1> <ul> {% for d in dlist %}
 <li> <a href="{{ fs.getabsoluteurl }}{{ path }}{{ d }}/" >{{ d }}</a> </li> {% endfor %}
 {% for f in flist %}
 <li> <a href="{{ fs.getabsoluteurl }}{{ path }}{{ f.name }}" >{{ f.name }}</a> ({{ f.type }})</li> {% endfor %}
 </ul> {% endif %}

Both templates need to be stored somewhere in your TEMPLATE PATH. I have set up a path in the TEMPLATE PATH with the name of the application: filesystems . In there I stored the files as index.html and directory.html . Of course you normally would build a base template for the site and extend that in your normal templates. And you would add a 404.html to handle 404 errors. But that's left as an exercise to the reader.After you start up your development server for your admin (don't forget to set DJANGO SETTINGS MODULE accordingly!) you can add a filesystem to your database (you did do django-admin.py install filesystems sometime in between? No? Do it now, before you start your server). Now stop the admin server, change your DJANGO SETTINGS MODULE and start the main settings server. Now you can surf to http://localhost:8000/files/(at least if you did set up your URLs and server like I do) and browse the files in your filesystem. That's it. Wasn't very complicated, right? Django is really simple to use

Zerospan seems to be a P2P software with encryption and Bonjour (ex-Rendevouz, ex-Zeroconf) integration. I'm not quite getting it, as the download contains no documentation and the wiki with the documentation is currently broken, so I'll just blogmark it to check it out later.

Training as a low-wage sector

What lies behind the DIHK's demand for halving the basic apprentice salary and flexibilizing working hours becomes clear when you look at quotes from the DIHK chairman:

"My proposal is to introduce a nationwide basic remuneration of 270 euros," he told the newspaper "Die Welt". He justified his initiative by saying that this would allow more apprenticeships to be financed. "An apprenticeship remuneration of up to 800 euros is simply too high for many businesses."

"Working hours must be better adapted to the needs of the industries." It makes no sense that a 17-year-old restaurant specialist has to leave at 10 p.m. "if all the tables are still occupied."

This is simply about having cheap labor, but not about ensuring proper training. But these demands are not new.

And what the German economy thinks of training can be seen in the fact that the number of training positions has again decreased by 10% compared to the previous year - and thus young people have again been left without training positions, despite all the promises of the economy. Without a non-training fee for larger companies, this will not change either. But complaining that there are no trained skilled workers, the economy can do quite famously ...

Beckstein on the Roll

No idea what the herb is called that he takes, but it leaves severe brain damage: Beckstein wants German Guantanamo. Apart from the fact that he also wants to shoot suspects in the head and pack foreigners into camps because potential terrorists must not be allowed to run around freely (politicians like him, who are completely crazy, are not only allowed to run around freely but also to express their opinions freely), he is also constitutionally hostile:

Beckstein also criticized the ruling of the Federal Constitutional Court, which in a ruling on Lower Saxony legislation had demanded clear limitations on preventive telephone surveillance. The balance between security and freedom of interests must be re-evaluated, said Beckstein: "That the intimate sphere of terrorists should be protected is for me hardly bearable."

I'm sorry, Mr. Beckstein, but you have failed the test. Because the Constitutional Court does not explicitly protect the intimate sphere of terrorists - but the intimate sphere of citizens. And this is listed in the Basic Law as a protected asset.

Why is someone like this not observed by the Federal Office for the Protection of the Constitution? His hostility to the constitution is really documented multiple times ...

Novell will go for SCO's throat

And their considerations on the legal situation would - if they were to hold up in court - really deliver a significant blow to SCO.

The whole SCO-Linux movie is quite exciting, but quite honestly: the lengths between the action scenes are a bit exaggerated.

Pluto out or a new one in?

Astronomers have found a clump of mud outside Pluto's orbit that is at least as large, and likely even significantly larger than Pluto - Planet or Not, Pluto Now Has Far-Out Rival:

Astronomers announced yesterday that they had found a lump of rock and ice that was larger than Pluto and the farthest known object in the solar system. The discovery will probably rekindle debate over the definition of "planet" and whether Pluto still merits the designation.

Now it's about whether Pluto loses its planet status, or the new one also becomes a planet.

Who wants to work with PostgreSQL and Frontier, simply install the PostgreSQL Extension for Frontier. For Mac and Windows.

On Dealing with Security

Under ISS takes action against publication of Cisco vulnerability talk you can find a description of how Cisco and ISS envision security: massive interference with the freedom of expression of a speaker at the Black-Hat conference. Okay, he was a former ISS employee and probably used information he shouldn't have published - but it's exactly this ridiculous secrecy that undermines security - because attackers will gain this knowledge sooner or later - if security vulnerabilities exist, they will be found sooner or later. If someone reports about it publicly, at least you can defend yourself and take countermeasures. If the publication is suppressed, the end user is ultimately the victim - who has no chance to protect themselves - and even in an emergency by switching to another router manufacturer.

Therefore, it is indeed the case: neither ISS nor Cisco make a good impression in the public eye. On the contrary, their censorship attempts are actually only another argument in future product decisions to decide against Cisco - because you can obviously not trust their security statements.

Who believed that ISO time specifications are just YYYY-MM-TT HH:MM:SS.HS, forget it: International standard date and time notation. Of course, it's an ISO standard ...

Bodies in the Basement

Every software has them - some skeletons in the closet that start to stink when you find them. Django unfortunately too. And that is the handling of Unicode. The automatically generated Admin in Django always sends XHTML and utf-8 to the browser. The browsers therefore also send utf-8 back. But there are browsers that use a slightly different format for the data to be sent in such cases - the so-called multipart format. This is used because it is the only guaranteed method in HTTP-POST where you can send a character set along.

Unfortunately, Django parses these multipart-POSTs with the email module from Python. This then diligently produces Unicode strings from the parts marked as utf-8. Which is correct in itself - only in the Django source code there are str() calls scattered everywhere in the source code. And these then naturally crash when they are given unicode with characters above chr(128) in them.

I took a look at the source code, the most realistic approach would be to make sure in Django that Unicode results are then converted back to utf-8, so that only normal Python strings are used internally. That works so far, but then there are still problems with some databases that recognize utf-8 content when saving and then produce Unicode again when reading the content - SQLite is such a database.

Well, this won't be easy to fix. I've already tried it, it's a pretty nasty topic and unfortunately not at all considered in Django - and therefore it crashes at all corners and edges. Let's see if I can't come up with something useful after all ...

What I also noticed: Django sends the Content-type only via a meta tag with http-equiv. That's a nasty hack, it would be much better if the Content-type were set correctly as a header, then nothing can go wrong if, for example, Apache wants to add a Default-Charset. And the browsers would also react in a much more reproducible way.

In any case, this is again the typical case of American programmers. They like to tell you that you just need to switch to Unicode and utf-8 when you report your character encoding problems, but I have never seen software from an American programmer that handled Unicode correctly ...

Otherwise, there are still one or two hinges in Django - especially annoying because they are not documented, but easy to solve: the default time zone in Django is America/Chicago. You just have to write a variable TIME_ZONE with 'Europe/Berlin' as value in your settings file and apply a small patch so that Django can handle the '-' as time zone separator. Oh man, when Americans write software ...

Somehow, my motivation to take a closer look at Ruby on Rails is increasing at the moment, after all, it was Danes who started it and they should at least get such things right (if only that nice automatic administration part of Django were not - that's exactly what I would be after. Why hasn't anyone built something like that for ROR, damn ...)

Update: I have attached a patch to the corresponding ticket for the Unicode problem (just scroll to the very bottom) that at least gets the problem somewhat under control - provided you don't use SQLite, because SQLite always returns Unicode strings and they then cause trouble again. But at least with PostgreSQL, umlauts now work in Django. The solution is not really perfect, but at least it can be brought in with only a little code change. A real solution would probably require larger code changes.

Another patch is attached to the ticket for the time zone problem, with the patch you can then also use TIME_ZONE = 'Europe/Berlin' to get the time specifications, for example in the change history, in the correct time zone.

In such moments you wish you had commit rights to Django, to be able to put such quite manageable patches in yourself

Another update: Adrian was in the chat yesterday and today and the problems with Unicode are largely gone. Only with SQLite there is still trouble, but I already have the patch finished. And the time zone issue is also fixed in the SVN. And he has started unit tests. Very useful, if you can then test the whole framework cleanly in the long run after a patch ...

Liability for Links after the Heise Judgment

After this interview with WDR, the following applies: "Anyone who sets such a link is in trouble":

You really have to be very careful. Due to these new rulings, you have to think: Who am I linking to? In the past, as a private individual, you would say: 'Come on, I'll put a hundred links one after the other' and be quite proud. Today, you really have to consider whether the person you are linking to is really trustworthy. You also have to check these links at regular intervals and see what is happening on the linked page.

Which - if it were actually the case - would factually mean the end of privately operated information offerings in the short or long term, as no one can check all their links. I have almost 5000 articles in my blog, which I certainly won't be able to check to see if there is something somewhere that offends someone.

And thus, this ruling has driven another nail into the coffin of the Internet, simply because judges repeatedly rate the alleged rights of rights extortionists higher than free speech and free reporting.

If you, like me, find yourself in a situation where you don't like the Unicode strings in PySQLite2 and need UTF-8 byte strings: PysqliteFactories are the solution here, not converters. Because converters would have to be registered for every variation of varchar that is in use - the row factories, on the other hand, are quite agnostic and practical. And if you already use your own cursor class: simply set this as the cursor factory, which then assigns a row factory to the instance with self.row_factory.

Sysadmins Day

Lisa9 shows how to properly pay tribute to a sysadmin! Even DAU-friendly with illustrated instructions

Abridged guide to HTTP Caching is a description of the most important caching headers in HTTP and how they should be used.

JSAN is what CPAN is for Perl - a central directory and download area for JavaScript sources and packages.

Linux-VServer is a kernel patch and a set of utilities that enable running a series of virtual Linux boxes on a base machine, with resources strongly isolated from each other. Chroot on steroids, or most comparable to BSD Jails. Interesting for hosting projects where virtual root servers are required. It's even included in the current Debian.

Tor Network Status provides an overview of exit nodes in the Tor network with traffic information, allowed ports, and IP data. Nice. (found via the Rabenhorst)

typo is a blog software for Ruby on Rails with seemingly already quite extensive features. Specifically also with good caching (produces static pages) for high-traffic sites, where parts are then kept dynamically via JavaScript. Sounds like I'll take a closer look at it when my ROR book arrives ...

The Earth is flat after all - nonsense. Sing against it!

Django, lighttpd and FCGI, second take

In my first take at this stuff I gave a sample on how to run django projects behind lighttpd with simple FCGI scripts integrated with the server. I will elaborate a bit on this stuff, with a way to combine lighttpd and Django that gives much more flexibility in distributing Django applications over machines. This is especially important if you expect high loads on your servers. Of course you should make use of the Django caching middleware, but there are times when even that is not enough and the only solution is to throw more hardware at the problem.

Update: I maintain my descriptions now in my trac system. See the lighty+FCGI description for Django.

Caveat: since Django is very new software, I don't have production experiences with it. So this is more from a theoretical standpoint, incorporating knowledge I gained with running production systems for several larger portals. In the end it doesn't matter much what your software is - it only matters how you can distribute it over your server farm.

To follow this documentation, you will need the following packages and files installed on your system:

  • [Django][2] itself - currently fetched from SVN. Follow the setup instructions or use python setup.py install .
  • [Flup][3] - a package of different ways to run WSGI applications. I use the threaded WSGIServer in this documentation.
  • [lighttpd][4] itself of course. You need to compile at least the fastcgi, the rewrite and the accesslog module, usually they are compiled with the system.
  • [Eunuchs][5] - only needed if you are using Python 2.3, because Flup uses socketpair in the preforked servers and that is only available starting with Python 2.4
  • [django-fcgi.py][6] - my FCGI server script, might some day be part of the Django distribution, but for now just fetch it here. Put this script somewhere in your $PATH, for example /usr/local/bin and make it executable.
  • If the above doesn't work for any reason (maybe your system doesn't support socketpair and so can't use the preforked server), you can fetch [django-fcgi-threaded.py][7] - an alternative that uses the threading server with all it's problems. I use it for example on Mac OS X for development.

Before we start, let's talk a bit about server architecture, python and heavy load. The still preferred Installation of Django is behind Apache2 with mod python2. mod python2 is a quite powerfull extension to Apache that integrates a full Python interpreter (or even many interpreters with distinguished namespaces) into the Apache process. This allows Python to control many aspects of the server. But it has a drawback: if the only use is to pass on requests from users to the application, it's quite an overkill: every Apache process or thread will incorporate a full python interpreter with stack, heap and all loaded modules. Apache processes get a bit fat that way.

Another drawback: Apache is one of the most flexible servers out there, but it's a resource hog when compared to small servers like lighttpd. And - due to the architecture of Apache modules - mod_python will run the full application in the security context of the web server. Two things you don't often like with production environments.

So a natural approach is to use lighter HTTP servers and put your application behind those - using the HTTP server itself only for media serving, and using FastCGI to pass on requests from the user to your application. Sometimes you put that small HTTP server behind an Apache front that only uses mod proxy (either directly or via mod rewrite) to proxy requests to your applications webserver - and believe it or not, this is actually a lot faster than serving the application with Apache directly!

The second pitfall is Python itself. Python has a quite nice threading library. So it would be ideal to build your application as a threaded server - because threads use much less resources than processes. But this will bite you, because of one special feature of Python: the GIL. The dreaded global interpreter lock. This isn't an issue if your application is 100% Python - the GIL only kicks in when internal functions are used, or when C extensions are used. Too bad that allmost all DBAPI libraries use at least some database client code that makes use of a C extension - you start a SQL command and the threading will be disabled until the call returns. No multiple queries running ...

So the better option is to use some forking server, because that way the GIL won't kick in. This allows a forking server to make efficient use of multiple processors in your machine - and so be much faster in the long run, despite the overhead of processes vs. threads.

For this documentation I take a three-layer-approach for distributing the software: the front will be your trusted Apache, just proxying all stuff out to your project specific lighttpd. The lighttpd will have access to your projects document root and wil pass on special requests to your FCGI server. The FCGI server itself will be able to run on a different machine, if that's needed for load distribution. It will use a preforked server because of the threading problem in Python and will be able to make use of multiprocessor machines.

I won't talk much about the first layer, because you can easily set that up yourself. Just proxy stuff out to the machine where your lighttpd is running (in my case usually the Apache runs on different machines than the applications). Look it up in the mod_proxy documentation, usually it's just ProxyPass and ProxyPassReverse.

The second layer is more interesting. lighttpd is a bit weird in the configuration of FCGI stuff - you need FCGI scripts in the filesystem and need to hook those up to your FCGI server process. The FCGI scripts actually don't need to contain any content - they just need to be in the file system.

So we start with your Django project directory. Just put a directory public html in there. That's the place where you put your media files, for example the admin media directory. This directory will be the document root for your project server. Be sure only to put files in there that don't contain private data - private data like configs and modules better stay in places not accessible by the webserver. Next set up a lighttpd config file. You only will use the rewrite and the fastcgi modules. No need to keep an access log, that one will be written by your first layer, your apache server. In my case the project is in /home/gb/work/myproject - you will need to change that to your own situation. Store the following content as /home/gb/work/myproject/lighttpd.conf


 server.modules = ( "mod_rewrite", "mod_fastcgi" )
 server.document-root = "/home/gb/work/myproject/public_html"
 server.indexfiles = ( "index.html", "index.htm" )
 server.port = 8000
 server.bind = "127.0.0.1"
 server.errorlog = "/home/gb/work/myproject/error.log"

fastcgi.server = (
"/main.fcgi" => (
"main" => (
"socket" => "/home/gb/work/myproject/main.socket"
 )
 ),
"/admin.fcgi" => (
"admin" => (
"socket" => "/home/gb/work/myproject/admin.socket"
 )
 )
 )

url.rewrite = (
"^(/admin/.*)$" => "/admin.fcgi$1",
"^(/polls/.*)$" => "/main.fcgi$1"
 )

mimetype.assign = (
".pdf" => "application/pdf",
".sig" => "application/pgp-signature",
".spl" => "application/futuresplash",
".class" => "application/octet-stream",
".ps" => "application/postscript",
".torrent" => "application/x-bittorrent",
".dvi" => "application/x-dvi",
".gz" => "application/x-gzip",
".pac" => "application/x-ns-proxy-autoconfig",
".swf" => "application/x-shockwave-flash",
".tar.gz" => "application/x-tgz",
".tgz" => "application/x-tgz",
".tar" => "application/x-tar",
".zip" => "application/zip",
".mp3" => "audio/mpeg",
".m3u" => "audio/x-mpegurl",
".wma" => "audio/x-ms-wma",
".wax" => "audio/x-ms-wax",
".ogg" => "audio/x-wav",
".wav" => "audio/x-wav",
".gif" => "image/gif",
".jpg" => "image/jpeg",
".jpeg" => "image/jpeg",
".png" => "image/png",
".xbm" => "image/x-xbitmap",
".xpm" => "image/x-xpixmap",
".xwd" => "image/x-xwindowdump",
".css" => "text/css",
".html" => "text/html",
".htm" => "text/html",
".js" => "text/javascript",
".asc" => "text/plain",
".c" => "text/plain",
".conf" => "text/plain",
".text" => "text/plain",
".txt" => "text/plain",
".dtd" => "text/xml",
".xml" => "text/xml",
".mpeg" => "video/mpeg",
".mpg" => "video/mpeg",
".mov" => "video/quicktime",
".qt" => "video/quicktime",
".avi" => "video/x-msvideo",
".asf" => "video/x-ms-asf",
".asx" => "video/x-ms-asf",
".wmv" => "video/x-ms-wmv"
 )

I bind the lighttpd only to the localhost interface because in my test setting the lighttpd runs on the same host as the Apache server. In multi server settings you will bind to the public interface of your lighttpd servers, of course. The FCGI scripts communicate via sockets in this setting, because in this test setting I only use one server for everything. If your machines would be distributed, you would use the "host" and "port" settings instead of the "socket" setting to connect to FCGI servers on different machines. And you would add multiple entries for the "main" stuff, to distribute the load of the application over several machines. Look it up in the lighttpd documentation what options you will have.

I set up two FCGI servers for this - one for the admin settings and one for the main settings. All applications will be redirected through the main settings FCGI and all admin requests will be routed to the admin server. That's done with the two rewrite rules - you will need to add a rewrite rule for every application you are using.

Since lighttpd needs the FCGI scripts to exist to pass along the PATH_INFO to the FastCGI, you will need to touch the following files: /home/gb/work/myprojectg/public_html/admin.fcgi ``/home/gb/work/myprojectg/public_html/main.fcgi

They don't need to contain any code, they just need to be listed in the directory. Starting with lighttpd 1.3.16 (at the time of this writing only in svn) you will be able to run without the stub files for the .fcgi - you just add "check-local" => "disable" to the two FCGI settings. Then the local files are not needed. So if you want to extend this config file, you just have to keep some very basic rules in mind:

  • every settings file needs it's own .fcgi handler
  • every .fcgi needs to be touched in the filesystem - this might go away in a future version of lighttpd, but for now it is needed
  • load distribution is done on .fcgi level - add multiple servers or sockets to distribute the load over several FCGI servers
  • every application needs a rewrite rule that connects the application with the .fcgi handler

Now we have to start the FCGI servers. That's actually quite simple, just use the provided django-fcgi.py script as follows:


 django-fcgi.py --settings=myproject.work.main
 --socket=/home/gb/work/myproject/main.socket
 --minspare=5 --maxspare=10 --maxchildren=100
 --daemon

django-fcgi.py --settings=myproject.work.admin
 --socket=/home/gb/work/myproject/admin.socket
 --maxspare=2 --daemon

Those two commands will start two FCGI server processes that use the given sockets to communicate. The admin server will only use two processes - this is because often the admin server isn't the server with the many hits, that's the main server. So the main server get's a higher-than-default setting for spare processes and maximum child processes. Of course this is just an example - tune it to your needs.

The last step is to start your lighttpd with your configuration file: lighttpd -f /home/gb/work/myproject/lighttpd.conf

That's it. If you now access either the lighttpd directly at http://localhost:8000/polls/ or through your front apache, you should see your application output. At least if everything went right and I didn't make too much errors.

Eunuchs provides a few functions that were not yet available in Python 2.3. Specifically, socketpair and recvmsg/sendmsg are very important - for server programming with preforked servers, for example.

Another Questionnaire

From Lisa Sonnabend's mailbox:

As part of my thesis at the Institute for Communication Studies and Media Research at Ludwig-Maximilians-Universität München, I am conducting a survey among weblog readers on the topic of "Credibility of Weblogs". This is one of the first scientific studies on the phenomenon of weblogs in Germany.

It is to be clarified whether weblogs are already considered as trustworthy and competent in certain points such as fairness or impartiality as traditional media – and in which points there are great differences. In addition, the survey examines which special qualities weblogs have from the perspective of the recipients and what importance they have for the users. Based on the results, a prognosis about the future importance of weblogs in the media landscape is to be made.

And I should put the link in the blog so that people can participate. Well, I'll do that, even though I wonder what competence and credibility the old media are supposed to have.

Here goes the questionnaire

Preventive telephone surveillance is not

The Constitutional Court declares preventive telephone surveillance null and void. Primarily affects Lower Saxony, but similar situations exist in other federal states. Good when something is finally put in the way of the whole surveillance fetishism.

There are days when my computer hates me

For example, when I play with Flup and instead of the threaded server I want to use a forked server. And I realize that the latter requires the socketpair function, which unfortunately is only available from Python 2.4, which is available on Debian Sarge, but for Python 2.4 there is no Psycopg in Debian Sarge - which in turn is a prerequisite for Django and PostgreSQL, which is why I am dealing with FastCGI in the first place. Installing Psycopg itself is no fun, as you not only need the PostgreSQL headers that are normally installed, but also a few internal headers - so in principle a build tree. And then you also need the egenix-mx-base headers, which you can only get for Python 2.3, so you would have to install that yourself as well. Backports from the next Debian version don't work either, as they are just switching to PostgreSQL 8.0 and Sarge is still using 7.4 and I didn't want to upgrade the whole system right away. And so you go in circles and feel a bit cheated by all the dependencies and version conflicts.

And what do you do as a solution, because the threaded server unfortunately only produces segfaults in Psycopg? You take the threaded server, forbid it to thread and start it via the spawn-fcgi from lighttpd, or directly from lighttpd. But that's somehow stupid again, because then there are always 3 threads per FCGI server, two of which just stand in the process list and do nothing. And all this just because mod python2 (which is needed for Django) requires Apache2, which in turn requires mod perl2, which is incompatible with the old mod perl, which is why a whole bunch of my sites wouldn't work anymore if I switched to Apache2. Which I don't want to do anyway, because Apache2 with mod python is damn slow. And once again I feel cheated. I really should have looked for a more meaningful job.

If you didn't understand anything: doesn't matter, it's technology, it's not important, I just wanted to say that.

Higher-Order Perl is a book (currently in paper form, but it is supposed to be freely available online soon) that deals with higher-order functions and Perl - could be quite interesting, Perl offers a lot of features hidden under all those curly braces and other special characters ...