Minnesläcka

Jag hatar minnesluckor. Vet inte varför jag har en från igår kväll. Måste varit jättetrött för jag drack inte speciellt mycket. Bara två eller tre glas absint. Vi lyssnade på Fela Kuti och jag dansade lite själv. Vad hände sen då?

Vaknade klockan 10:20 påklädd i hennes säng. Trodde att jag var hemma, men det var jag inte. Inga spår som skulle kunna förklara någonting. Snövit var där, fast han verkade undvika mig. Han undrade nog vad jag gjorde. Världen kändes inte verklig och jag undrade om jag drömde. Jag måste tillbaka ikväll och leta efter ledtrådar.

Jag var väldigt törstig och köpte en yogurtflaska att dricka. Av någon anledning var jag mycket ledsen. Jag ville gråta och ögonen var fuktiga.

Kommer ihåg bröst. Röd blus och svarta byxor. Små tuttar. Tafsade jag på henne? Antastade jag henne? Nähä?? Var det en dröm. Antastade de mig? Jag brukar inte drömma porriga drömmar när jag är full. De sitter på flyget just nu och jag kan inte ringa och fråga.

Det är dags att bli försiktigare med spriten.

Joining stringlists

Here is how you join a list of strings in elisp:

(mapconcat (lambda (x) x) load-path "\n")

It is equivalent to this Python code:

'\n'.join(stringlist)

Example of the LZW algorithm

This is probably old stuff for most of you, but here is my Python implementation of the LZW algorithm.

# The initial LZW tables that maps codes to strings and vice-versa. code_to_str = [chr(i) for i in range(256)] str_to_code = dict((chr(i), i) for i in range(256)) def compress(seq): ''' Returns an LZW compressed list of the input character sequence. ''' output = [] table = dict(str_to_code) s = '' for ch in seq: it = s + ch if it in table: s = it else: output.append(table[s]) table[it] = len(table) s = ch output.append(table[s]) return output def decompress(seq): ''' Returns a decompressed list of the LZW compressed input. ''' table = code_to_str[:] prevcode = seq[0] output = [] output.append(table[prevcode]) for code in seq[1:]: try: entry = table[code] except IndexError: # The lzw special case when code is not yet defined. entry = table[prevcode] entry += entry[0] output.append(entry) table.append(table[prevcode] + entry[0]) prevcode = code return output

Used like this:

data = open('somefile.txt').read() data = compress(data) print decompress(data)

Explanation for how the algorithm works can be found in other places on the net.

Mina nya glasögon

I fredags var jag i Stockholm och hämtade mina nya glasögon. Jag har aldrig haft glasögon förut men eftersom jag märkt att min syn blivit sämre på längre avståd gissade jag på att jag kanske behövde ett par. Det är svårt för mig att läsa skyltarna i t-banan och stationsklockorna även på relativt korta avstånd.

Så jag gjorde ett syntest förra veckan på BlicOptik i Solna Centrum. Där finns det en jättestor galleria som heter Solna Torg där butiken ligger. Enligt syntestet ser jag såpass dåligt att jag precis måste ha på mig glasögon när jag kör bil. Men tur då att jag inte har varken bil eller körkort.

Optikerbutiker är jobbiga tycker jag. Det fanns alldeles för många olika fina glasögonmodeller att välja mellan. Tillslut valde jag två stycken par eftersom butiken hade ett erbjudande där man fick köpa två stycken för samma pris som ett. Det ena paret var ett par svarta kantiga glasögon med två millimeter tjocka bågar runt glasen. Jag tyckte de var snygga eftersom bågarna passade bra och eftersom underkanten på glasögonen var i silver. Dessutom var det extremt svårt att hitta glasögon som jag inte tyckte var för breda.

Det andra paret var också svarta fast med ultratunna böjbara skalmar. Jag tycker inte att de var lika snygga som det första paret men optikern som hette Stephanie och som hjälpte mig med smakråd tyckte de var snyggare.

Det är fan svårt att veta tycker jag vilka glasögon som är snygga. Eftersom de sitter precis mitt i ansiktet vill man ju att de ska vara så fina som möjligt. Men samtidigt tänker man inte ofta på hur de ska se ut. Tänk om de reflekterar ljuset på ett sådant sätt att ögonen ser extra små ut? Då ser det ut som om man har grisögon och det är inte bra. Kanske gör för breda och mörka bågar att man ser sur ut? Ungefär som ett extra par ögonbryn. Det är heller inte bra.

Enligt Amanda såg jag sur ut i de glasögonen som Stephanie tyckte bäst om. Det kanske stämmer, men hur kan man se det? Som tur är behöver jag inte ha på mig glasögonen jämt, utan endast när jag ska titta på TV, bio eller liknande. Det kommer nog att ta lång tid att vänja sig vid dem. :(

Positivt att de fungerar som de ska iallafall. Tydligen har världen en massa detaljer som jag aldrig tidigare lagt märke till. Allting är extremt skarpt och jag kan se folks ansikten på myckte längre håll än jag kunde innan. Speciellt att titta rakt ner i backen är intressant. Eftersom bilden är extremt skarp känns det som om marken är mycket närmare än vad den egentligen är.

Känns mycket bättre nu

Hon och Urban är tydligen ett officiellt par nu, med allt vad det innebär. Jag säger bara en sak: stackars Urban! :) Han kommer får stå ut med mycket innan ljuset går upp för honom. Man måste vara mycket korkad eller desperat för att inleda ett förhållande med den flickan.

Värdelöst

Jag hatar Urban, jag hatar Mai. Varför blev det så här? Skit och fanskap! Jag vill inte vara utan henne. Hon är kall, hård och elak men jag måste ha henne. JÄvla helvete.

Magknip

Jag har ont i magen. Av sorg. Trodde inte jag skulle må dåligt av att göra slut. Kunde inte tänka mig att jag skulle sakna henne. Vill gråta men har inga tårar... Det är inte synd om mig. Allt är tråkigt och mörkt.

Tip of the day

if-statements in Makefile.am files cannot be indented. Thanks, that caught me off-guard.

Snip snapp snut,

så var förhållandet slut. :( Men det finns många fina tjejer kvar i världen och jag ska nog kunna hitta någon annan.

Public transport rocks

I read about the Blog Action Day on Slashdot and this is my "contribution."

For those who don't know, the object in the image is a tram. Trams are great because they run on electricity and not gasoline so they produce much less pollution than for example cars.

And this is an image of a commuter train. Those trains are also great because they don't pollute.

What is not so great is that not enough people use these services. The highways are crammed with cars (often with only a single person in them) trying to get in our out of the city centers. Trams and trains are great, but cars are bad because they pollute a lot.

What is not so great is that it costs you about 120 SEK to make a round trip from Södertälje to Stockholm. It's 160 SEK if you are travelling from Gnesta. That is to expensive. It takes longer and is not much cheaper to travel to Stockholm by mass transit than by driving a car. So if you have a car then you will use that to commute if you aren't particularly concerned about the enviroment.

Previously, it costed 40 SEK for a round trip to and from Stockholm. That price was much more palatable and quite a few people decided to use the mass transit instead of driving. It was changed because the current politicians thought it was to expensive for the state, but it was not. SL could have easily affored it, but the politicans prioritised tax cuts instead of social service.

Mass transit should be free, and it should be funded by taxes. Everyone should have equal and cheap access to travel for commuting and so on. Making the mass transit free is the simplest and cheapest way to drastically reduce carbon dioxide emissions and improving quality of life.

Lose weight with MIN, MAX and CLAMP

This article is related to two patches to cairo, #12717 and #12722. Many times in C, you want values in a certain range, or some that are not above or below a certain value. The process which ensures that values are within a certain range is called clamping.

Let us say that you have function that sets the position of something.

void set_pos (Obj *obj, int x, int y) { obj->x = x; obj->y = y; }

Further assume that the position must be contained within obj:s clip rectangle. That could be accomplished using this code:

void set_pos (Obj *obj, int x, int y) { // First clip the values if (x < obj->rect.x) x = obj->rect.x; if (x > obj->rect.x + obj->rect.width) x = obj->rect.x + obj->rect.width; if (y < obj->rect.y) y = obj->rect.y; if (y > obj->rect.y + obj->rect.height) y = obj->rect.y + obj->rect.height; // Then set them obj->x = x; obj->y = y; }

A mathematical way to write the clipping would be something like:

obj->x = x, obj->rect.x <= x <= obj->rect.x + obj->rect.width
obj->y = y, obj->rect.y <= y <= obj->rect.y + obj->rect.height

Time to introduce the MIN and MAX functions and see how they can help us. In C, they can be implemented as macros.

#define MAX(a, b) (((a) > (b)) ? (a) : (b)) #define MIN(a, b) (((a) < (b)) ? (a) : (b))

It should not be any surprise that

x = MAX (x, obj->rect.x)

and

if (x < obj->rect.x) x = obj->rect.x;

is exactly equivalent. We can therefore rewrite the boundary checking code in set_pos to take advantage of these macros:

void set_pos (Obj *obj, int x, int y) { x = MAX (x, obj->rect.x); x = MIN (x, obj->rect.x + obj->rect.width); y = MAX (y, obj->rect.y); y = MIN (y, obj->rect.y + obj->rect.height); obj->x = x; obj->y = y; }

But wait, there is more! The code can be further rewritten if we introduce a CLAMP macro.

#define CLAMP(x, l, h) (((x) > (h)) ? (h) : (((x) < (l)) ? (l) : (x)))

Now we can make the set_pos function even more readable:

void set_pos (Obj *obj, int x, int y) { obj->x = CLAMP (x, obj->rect.x, obj->rect.x + obj->rect.width); obj->y = CLAMP (y, obj->rect.y, obj->rect.y + obj->rect.height); }

Note how similar this code is to the imagined mathematical definition. It is also worth noting that the CLAMP macro doesn't work if the value of the upper bound is lower than the lower bound. That is, if obj->rect.width or obj->rect.height is negative, then the macro will give erroneous results.

Crashing is good for you

Found this post from Ryan Lortie interesting. Apparently, the optimization in this recent bug report will crash quite a lot of programs.

Totally great, now developers finally are forced to fix their (null) strings they dump in output and in configuration files. Programs become more portable and developers learn the important lession of being careful with NULL, what's not to like about that? :)

I very much like the way the gcc developers are going even if their changes affects me too. They seem to fully realize that following specified standards is much more important than preserving backwards compatibility.

Remember, what doesn't kill you only makes you stronger!

Interfaces uglier than C

I'm not to happy with what PyGTK does with my interfaces. In C, an implementation of GtkIImageTool looks like this. In Python, it looks like this:

import gobject import gtkimageview class MyTool(gobject.GObject, gtkimageview.IImageTool): def __init__(self): gobject.GObject.__init__(self) self.crosshair = gtk.gdk.Cursor(gtk.gdk.CROSSHAIR) self.cache = gtkimageview.PixbufDrawCache() def do_button_press(self, ev_button): pass def do_button_release(self, ev_button): pass def do_motion_notify(self, ev_motion): pass def do_pixbuf_changed(self, reset_fit, rect): print 'pixbuf changed' def do_paint_image(self, draw_opts, drawable): self.cache.draw(draw_opts, drawable) def do_cursor_at_point(self, x, y): return self.crosshair gobject.type_register(MyTool)

There are quite a few ugly warts here.

class MyTool(gobject.GObject, gtkimageview.IImageTool):

You have to subclass gobject.GObject, which I really would rather not. The whole point of writing programs in Python is to get rid of the stupid, annoying and complicated GObject system. Same for gtkimageview.IImageTool -- this is Python and you have duck-typing. You shouldn't need to subclass anything.

def do_cursor_at_point(self, x, y):

And why does PyGTK decide that all my interface methods should be prefixed with do_? I didn't tell it to do that. It is an extremely unpythonic convention.

gobject.type_register(MyTool)

Yet another GObject-ism. It would be plain simple to get rid of this step by making gobject.GObject a metaclass that registers the class when it is constructed. But no, PyGTK wants to remind you that you really are dealing with a C API and nothing more.

gobject.GObject.__init__(self)

As before, initialization like this shouldn't be needed for a plain Python class.

return self.crosshair

Don't try to return None, PyGTK:s code generator doesn't understand that an interface function can either return an object pointer or NULL.

But worst of all is probably that if you forget to do any of this, then IT WILL CRASH. Don't expect a nice exception, at best you'll get a cryptic GTK warning and a segfault with debug symbols.

PyGTK:s handling of GInterfaces is, as shown, currently very weak. But I expect it to be improved upon in the future. Meanwhile I'm thinking that PyGTK:s wrapping system with definition and override files isn't that good to begin with. It is fairly easy to whip something up fast, but when you want to make your binding pythonic, you run into problems.

I wonder if it wouldn't be possible to use ctypes to create more pythonic bindings with.

Fucking spam filter

GMail's spam filter seems to have gotten worse lately. Lots of "you have won!!! blaha blaha" is getting through and at the same time many non-spam mails to mailing lists are classified as spam. Why should it be so hard for GMail? They could just calculate a hash or check sum for each mail on their servers. Then if more than say 10,000 GMail users receive the exact same mail it must be spam. Problem solved, no?

Bloggarkiv