November 2009 Archives
E accent?
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:
- een toetsenbord model: model
- een layout: layout; op welke toetsen horen welke karakters
- 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
setxkbmapen 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.
Prime sieve (in Go ofcourse)
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);
}
More Go
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:
- Write a cat implementation in Go. See below.
- 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))
}
}
}
}
cat in Go
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.
First steps with Go
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.
Go language
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...
tvgids
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.
Finally
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.cfinstead 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.
Test entry, please ignore
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.
New layout
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.

