November 2009 Archives

Nov 25

E accent?

Posted in dutch; comments: 4

Het begon met een simpele vraag: 'Miek, kun je zorgen dat e accent karakters enzo het gaan doen onder X?'

Dit is voor ons project bij het Octrooi Centrum Nederland waar we een Open Source Desktop aan het implementeren zijn. Nu zijn er nog wat andere zaken die eea wat meer ingewikkeld maken:

  • we gebruiken thin clients en dus XDMCP;
  • de omgeving is XFCE. Geen GNOME of KDE vanwege de snelheid en hun geheugen gebruik;
  • De xfce-keyboard-switcher die we hier hebben (4.4) crasht tijdens het gebruik;
  • Ik heb een voorkeur om het via de commandline te kunnen scripten.

Theorie

Het gaat wat ver om de gehele theorie achter de toetsenbord settings in X uit te leggen, zelf begrijp ik het ook niet voor 100%. Maar in X heb je:

  1. een toetsenbord model: model
  2. een layout: layout; op welke toetsen horen welke karakters
  3. een variant: variant; dode toetsen (= alt+e, geeft e accent)

Al deze zaken kun je in GNOME, KDE en ook XFCE zetten via een grafische client. Maar deze tools kunnen onverwacht stuk gaan zodra je XDMCP gaat gebruiken. De lowlevel tool zou setxkbmap moeten zijn.

Hoe het zou moeten werken?

Via de commandline zou het volgende iets moeten doen:

% setxkbmap

Met een lokaal draaiende X server gaat het waarschijnlijk goed. Draai je XDMCP (thin clients) dan kom je hier niet mee weg. De behulpzame melding die je krijg als het niet werkt is:

% setxkbmap
Error loading new keyboard description

En dat was het dan. Het volgende zou dan moeten wel werken:

% setxkbmap -print | xkbcomp - $DISPLAY

Dit werkt inderdaad, er zijn geen errors, maar het heeft ook weinig effect...

Omdat dit toch op een of andere manier zou moeten gaan werken, ben ik eens naar gnome-control-center gaan kijken, ondanks dat we werken met XFCE. Als je gnome-control-center start en dan twee keer naar keyboard settings gaat dan wordt de gnome-settings-daemon gestart en verrek, setxkbmap print de juiste info en mijn toetsenbord werkt.

Helaas ¨verziekt" gnome-settings-daemon de achtergrond van XFCE waardoor de desktop icons niet meer zichtbaar zijn. Dus dit is geen permanente oplossing.

Maar nu is dus de vraag:

Waarom werkt het niet met setxkbmap en wel via gnome-control-center?

Na diep graven in de sources van gnome-settings-daemon, gnome-control-center en libxklavier bleek dat libxklavier een eigen interface heeft naar de keyboard settings van X. Als je libxklavier compileert wordt er in de tests/ directory een 2-tal tooltjes gemaakt: test_config en test_monitor. Waarvan test_config er veelbelovend uit ziet:

Usage: test_config (-g)|(-s -m <model> -l <layouts> -o <options>)
        |(-h)|(-ws)|(-wb)(-d <debugLevel>)

Options:
 -al - list all available layouts and variants
 -am - list all available models
 -ao - list all available options groups and options
 -ac - list all available ISO country codes
 -ag - list all available ISO language codes
 -g - Dump the current config, load original system settings and revert back
 -s - Set the configuration given my -m -l -o options. Similar to setxkbmap
 -ws - Write the binary XKB config file (libxklavier.xkm)
 -wb - Write the source XKB config file (libxklavier.xkb)
 -d - Set the debug level (by default, 0)
 -h - Show this help

Dit lijkt wel heel veel op wat setxkbmap kan... En ja hoor:

Print de huidige instellingen:

% setxkbmap -print
xkb_keymap {
    xkb_keycodes  { include "xfree86+aliases(qwerty)"   };
    xkb_types     { include "complete"  };
    xkb_compat    { include "complete"  };
    xkb_symbols   { include "pc+us" };
    xkb_geometry  { include "pc(pc105)" };
};

Nu nieuwe gegevens inladen met behulp van test_config. We zetten (-s) het toetsenbord op 105 tekens (-m pc105) en gebruiken de nl layout (-l nl):

% ./libxklavier-3.9/tests/test_config -s -m pc105 -l nl

Checken:

setxkbmap -print
xkb_keymap {
    xkb_keycodes  { include "xfree86+aliases(qwerty)"   };
    xkb_types     { include "complete"  };
    xkb_compat    { include "complete"  };
    xkb_symbols   { include "pc+nl" };
    xkb_geometry  { include "pc(pc105)" };
};

Werkt! :-) Geen foutmelding en het toetsenbord werkt ook echt.

Waarom dit wel werkt en setxkbmap niet is mij een raadsel. Maar goed, ik kan het instellen.

Nu nog de losse eindjes opruimen en eventueel een klein shell scriptje maken met zenity zodat de eindgebruikers hiermee aan de slag kunnen.


Nov 24

Prime sieve (in Go ofcourse)

Posted in programming; comments: 1

After reading up on the prime sieve, and playing with Go for the past week I thought needed to implement this algorithm in Go and make it parallel.

I want to create a set (n in 2..N) goroutines. Each of these routines will check if it can divide a number (i) by n (integer division). If so the number i is not prime, otherwise it is given to the next goroutine. Communication between the goroutines is done via channels as in this example.

Sieve

In this small example I have 5 goroutines, and we give it the number 3 and 4. The table shows the reminder when dividing by n.

            n = 2   3   4   5  ... ...
-------------------------------------------
i  = 3 % n      1   0   3   3   3   3   ...
i  = 4 % n      0   1   0   4   4   3   ...

From here we see that i = 3 is prime, because it has an 1 in the column where n = 2, i = 4 is not prime, because it has a zero in the column where n = 2.

The algorithm for each goroutine thus becomes (in pseudo code):

function(n, i) {
if i == 0 then copy to next goroutine; return
if n >= i then copy to next goroutine; return

// test for primeness, if not prime return the *magic* 
// number 0
if i % n == 0 then
    // not prime
    give 0 to the next goroutine
fi

give i to the next goroutine
}

Or in Go's syntax:

func f(left, right chan int, n int) {
    i := <-right;
    if i == 0 || n >= i {
        left <- i;
        return;
    }
    if i%n == 0 {
        // too bad
        left <- 0;
        return;
    }
    left <- i;
}

Main

The rest of the Go program should setup the goroutines, channels and handle the flags. N - 1 goroutines are set up, and each is connected to its neighbor.

Even nicer would be to really do this in parallel, i.e. send i to all goroutines, and then just see if one of them returned zero. If none of them do, its a prime. For now the following must suffice.

In Go code:

leftmost := make(chan int);
var left, right chan int = nil, leftmost;
for n := 0; n < *prime-1; n++ {
    left, right = right, make(chan int);
    go f(left, right, *prime-n);
}
right <- *prime;        // bang!
x := <-leftmost;        // wait for completion
fmt.Println(x);

This outputs 0 when the number tested is not prime, it outputs the number itself given when it is prime.

% ./sieve -p 32
0           # not prime

% ./sieve -p 11
11          # prime ;-)

Complete listing

package main

import (
    "flag";
    "fmt";
    "os";
)

var prime = flag.Int("p", 13, "test for primeness")

func f(left, right chan int, n int) {
    i := <-right;
    if i == 0 || n >= i { 
        left <- i;
        return;
    }   
    if i%n == 0 { 
        // too bad
        left <- 0;
        return;
    }   
    left <- i;
}

func main() {
    flag.Parse();

    if *prime < 2 { 
        fmt.Fprint(os.Stderr, "You know this already\n");
        os.Exit(1);
    }   

    leftmost := make(chan int);
    var left, right chan int = nil, leftmost;
    for n := 0; n < *prime-1; n++ {
        left, right = right, make(chan int);
        go f(left, right, *prime-n);
    }   
    right <- *prime;        // bang!
    x := <-leftmost;        // wait for completion
    fmt.Println(x);
}

Nov 23

More Go

Posted in programming; comments: 0

Still learning and playing with Go, I've rewritten my cat experiment, to use a *bufio.Reader, which is more correct I think. I'm also slowly wrapping my mind around the concept of Interfaces. As a non-OO programmer (C and non-OO Perl) is starting to see why this is useful.

So today's exercises:

  1. Write a cat implementation in Go. See below.
  2. Write a grep implementation in Go. See below.

Cat in go

package main

// A implementation of cat in Go

import (
    "os";
    "fmt";
    "bufio";
    "flag";
)

var numberFlag = flag.Bool("n", false, "number each line")

func cat(r *bufio.Reader) bool {
    i := 1;
    for {
        buf, e := r.ReadBytes('\n');
        if e == os.EOF {
            break
        }
        if *numberFlag {
            fmt.Fprintf(os.Stdout, "%5d  %s", i, buf);
            i++
        } else {
            fmt.Fprintf(os.Stdout, "%s", buf)
        }
    }
    return true;
}

func main() {
    flag.Parse();
    if flag.NArg() == 0 {
        cat(bufio.NewReader(os.Stdin))
    }
    for i := 0; i < flag.NArg(); i++ {
        f, e := os.Open(flag.Arg(i), os.O_RDONLY, 0);
        if e != nil {
            fmt.Fprintf(os.Stderr, "%s: error reading from %s: %s\n",
                os.Args[0], flag.Arg(i), e.String());
            continue;
        }
        if !cat(bufio.NewReader(f)) {
            os.Exit(1)
        }
    }
}

Grep in go

package main

// A implementation of Unix grep in Go
// TODO(mg) better error handling

import (
    "os";
    "fmt";
    "bufio";
    "regexp";
    "flag";
)

var numberFlag = flag.Bool("n", false, "number each line")
var filenameFlag = flag.Bool("l", false, "print names of matching files")

func grep(r *bufio.Reader, reg string) (match bool) {
    i := 0;
    for {
        buf, e := r.ReadBytes('\n');
        i++;
        if e == os.EOF {
            break
        }
        if m, _ := regexp.Match(reg, buf); m == true {
            match = true;
            if *filenameFlag {
                return match
            }
            if *numberFlag {
                fmt.Fprintf(os.Stdout, "%5.d:  %s", i, buf)
            } else {
                fmt.Fprintf(os.Stdout, "%s", buf)
            }
        }
    }
    return match;
}

func main() {
    flag.Parse();
    if flag.NArg() < 1 {
        fmt.Fprintf(os.Stderr, "%s: missing regexp\n", os.Args[0]);
        os.Exit(1);
    }
    if flag.NArg() == 1 {
        if grep(bufio.NewReader(os.Stdin), flag.Arg(0)) {
            if *filenameFlag {
                fmt.Fprintf(os.Stdout, "(standard input)\n");
            }
        }
    }
    for i := 1; i < flag.NArg(); i++ {
        f, e := os.Open(flag.Arg(i), os.O_RDONLY, 0);
        if e != nil {
            fmt.Fprintf(os.Stderr, "%s: error reading from %s: %s\n",
                os.Args[0], flag.Arg(i), e.String());
            continue;
        }
        if grep(bufio.NewReader(f), flag.Arg(0)) {
            if *filenameFlag {
                fmt.Fprintf(os.Stdout, "%s\n", flag.Arg(i))
            }
        }
    }
}

Nov 18

cat in Go

Posted in programming; comments: 2

After spending every free minute to Go I'm starting to get a feel for the language. Every one has to start somewhere, so I decided to "port" Unix utils to Go. I'm starting with cat, and thanks to the Go tutorial this is the result.

package main

// An implementation of Unix cat in Go

import (
    "os";
    "fmt";
    "flag";
)

func cat(filename string) bool {
    const NBUF = 512;
    var buf [NBUF]byte;
    if f, e := os.Open(filename, os.O_RDONLY, 0); e != nil {
        fmt.Fprintf(os.Stderr, "cat: error reading from %s: %s\n",
            filename, e.String());
        return true;
    } else {
        for {
            switch nr, _ := f.Read(&buf); true {
            case nr < 0:
                os.Exit(1)
            case nr == 0:   // EOF
                return true
            case nr > 0:
                if nw, ew := os.Stdout.Write(buf[0:nr]); nw != nr {
                    fmt.Fprintf(os.Stderr,
                        "cat: error writing from %s: %s\n",
                        filename, ew.String());
                    return false;
                }
            }
        }
    }
    return true;
}

func main() {
    flag.Parse();   // implement -n TODO
    if flag.NArg() == 0 {
        cat("/dev/stdin")
    }
    for i := 0; i < flag.NArg(); i++ {
        if !cat(flag.Arg(i)) {
            os.Exit(1)
        }
    }
}

In something like 50 lines you have a cat program. I'm really starting to like Go. Next up: extra features and a grep command.


Nov 16

First steps with Go

Posted in programming; comments: 1

I joined the go-nuts mailing list a few days ago and it really feels good to receive 200+ emails per day again. Just like in the good old days before good spam filtering (and anti-spam laws).

I also re-watched the presentation Rob Pike gave for Google Tech Talks on youtube.com. In there he presented the following program chain.go: (Formatted with gofmt as it should)

package main

import (
    "flag";
    "fmt";
)

var ngoroutine = flag.Int("n", 100000, "how may")

func f(left, right chan int)    { left <- 1+<-right }

func main() {
    flag.Parse();
    leftmost := make(chan int);

    var left, right chan int = nil, leftmost;
    for i := 0; i < *ngoroutine; i++ {
        left, right = right, make(chan int);
        go f(left, right);
    }
    right <- 0;             // bang!
    x := <-leftmost;        // wait for completion
    fmt.Println(x);         // 100000
}

In this short program we make a chain of 100000 goroutines which are connected to each other. Each one adds 1 to the value it gets from its right neighbor. We start it of by giving the last one (right) a value of 0. Then we wait until they are finished and print it.

Compile and run

To compile the above program you

8g chain.go 
8l -o chain chain.8

And then run it

./chain

On my crappy laptop this takes about 2.3 seconds. Not too bad :)

Vim

For Go code editing, I've added the following to my ~/.vimrc

autocmd Filetype go set textwidth=0
autocmd Filetype go set noexpandtab
autocmd Filetype go set tabstop=8
autocmd Filetype go set shiftwidth=8
autocmd Filetype go set softtabstop=8
autocmd Filetype go set number
autocmd Filetype go command! Fmt %!gofmt

The last line adds a new command which reformats your Go code. Just do <ESC>:Fmt and you'll end up with properly formatted Go code. The coding style rules for Go are simple. Its what you get when you run it through to gofmt.


Nov 13

Go language

Posted in programming; comments: 1

I've been wanting to learn (and do something) with the language Erlang for over two years now. But every time I fire up vim and start typing a get a this-is-not-Unix feeling (aka Java-sickness). The syntax is just not right for me.

But now Google, by the creators of Unix and C, give us Go! Which promises to give us Erlang functionality in a C-like language. Just what I wanted!

Basically just follow the steps on golang.org. In short it boils down to:

sudo apt-get install bison gcc libc6-dev ed
sudo apt-get install mercurial
hg clone -r release https://go.googlecode.com/hg/ ~/go

OK, now you have the source, set the Go variables to their correct values.

export GOROOT=~/go
export GOOS=linux
export GOARCH=386  # or amd64 for 64 bit

Now build and install it

cd ~/go/src
./all.bash

Typically to binaries are installed to ~/bin, so be sure that you have that directory in your path. The following is installed in my case:

% ls -l | grep 2009-11-12 | awk ' { print $8 } '
6cov
6nm
6prof
8a
8c
8g
8l
cgo
ebnflint
godefs
godoc
gofmt
gopack
gotest
goyacc
hgpatch
quietgcc

Now step two: learning and programming in the language itself...


Nov 10

tvgids

Posted in dutch; comments: 8

Alle jaren gebruik ik tot volle tevredenheid een teletekst script om via de prompt teletekst te kunnen lezen.

Gisteren avond bedacht ik me dat zoiets ook wel handig zou zijn voor tvgids.nl, en dan met name de nu/straks functionaliteit. Dus:

Perl to the rescue

Het script vergt Perl 5.10 omdat ik graag use switch wilde uit proberen, zodat je eindelijk ook in Perl switch-case achtige structuren kun gebruiken. Verder zit er geen HTML parser in, maar een simpele state-machine, het dus erg afhankelijk van hoe de HTML er precies uit ziet. Vooralsnog werkt het prima.

Er kunnen geen opties worden mee gegeven, je roept het gewoon aan als tv:

% tv | head -10
NEDERLAND 1     12:00 NOS Journaal          13:00 NOS Journaal        
NEDERLAND 2     12:35 Man bijt hond         13:00 NOS Journaal        
NEDERLAND 3     12:30 Het sprookjesboomfee  12:50 KRO Kindertijd      
RTL 4           12:00 RTL Travel            12:55 De bloemenstal      
RTL 5           10:00 Best of shopping      12:45 Blik op sterren     
SBS 6           08:00 Tommy Teleshopping    13:15 Two guys and a girl 
NET 5           11:00 Astro TV              13:00 Tommy Teleshopping  
NICKELODEON     12:30 Geronimo Stilton      12:55 Mighty B            
RTL 7           12:20 Business links        12:40 RTL Z Nieuws        
RTL 8           07:00 Tel sell              17:10 Huisdokter

Voor de geinteresseerde, hier kun je het vinden. Met de juiste Perl modules geinstalleerd:

  • LWP::Simple
  • HTML::Entities

moet het werken.


Nov 09

Finally

Posted in news; comments: 0

The last couple of weeks I'm staying in a hotel in The Hague to help a (pilot) migration to Open Source at the Octrooi Centrum Nederland. But now we can finally share some results (in Dutch).

To reiterate, we have:

  • All storage is Linux based (SLES)
  • CMS is migrated to Joomla
  • Application server are Linux (with Xming this will also work on Windows).
  • Active directory is connected to a MIT Kerberos server. Synchronization works with a massive shell/Awk script.
  • And now also Zarafa! Zarafa is a open source (GPL) Exchange replacement. Now we can just fiddle with /etc/postfix/main.cf instead of the some weird registry foo.

I must say I'm impressed with Zarafa, Campai and the IT staff at Octrooi Centrum as they were a tremendous help in implementing this.

Some other stuff I discovered during this migration:

There is still a lot to do and document. Sometime next year AT Computing will publish a white paper (or several white papers) which document this migration.


Nov 08

Test entry, please ignore

Posted in test; comments: 0

This is a test entry to see why (after my nb upgrade) the archives are mangled.

yes, tedious yes, very, tedious yes, very, very tedious

BUG FOUND, somehow I managed to give the -n flag to sort, which together with the -u only outputted the first column, i.e. 1 entry for each year.


Nov 07

New layout

Posted in linux; comments: 12

After running with the old style for a couple of years I wanted something new. And after a few days battling with Wordpress I decided to stay with nb, because it just rules.

The theme is loosly based on the design from Wordpress called SimplicitlyDark and the css from daring fireball.

But still a new (clean) style. During the restyling I also fixed the archives and found out that nb cannot handle articles with [[ in their name.