Microblog: A very long article Wikipedia article on the orientation of toilet paper [Jun 7th, 22:52] [R]

## Sunday, February 18th, 2018

### From How Far to Watch TV?

Categories: [ Science ]

The distance l from the TV depends on the desired horizontal viewing angle a, the screen's diagonal d and the number N of pixels on a row. Additionally, we will assume the screen's aspect ratio r to be 16:9 and the human eye's smallest angle that can be seen e to be 31.5 arcseconds.

Let R be the ratio between the diagonal and the width of the screen:

R = √(1 + 1/r2)

We can then write a relationship between a, N and e:

tan(a / 2) = NR tan(e / 2)    (1)

From (1) we can deduce that for any given e, there is a maximum horizontal viewing angle amax above which pixels can theoretically be distinguished.

For N = 1920 (FullHD), amax = 19.1°. With a 4K screen, amax = 37.2°.

We can also write a relationship between horizontal viewing angle, screen diagonal and distance:

d / l = 2 R tan(a / 2)    (2)

The ideal value or a is a matter of debate, but THX defines a horizontal viewing angle of at least 36° (the screen viewed from the rear seat of a THX theatre), while SMPTE suggests 30°. A value of 20° is also mentioned.

With a 4K screen, amax = 37.2° and (2), we draw that the ideal distance is 1.30 times the screen's diagonal. For example:

• 132 cm for a 40" screen
• 165 cm for a 50" screen
• 197 cm for a 60" screen

With a = 30°, the ideal screen distance is 1.63 times the screen's diagonal. For example:

• 132 cm for a 32" screen
• 166 cm for a 40" screen
• 207 cm for a 50" screen
• 248 cm for a 60" screen

With a FullHD screen and a compromise angle a = 20°, the ideal distance is 2.47 times the screen diagonal. For example:

• 201 cm for a 32" screen
• 251 cm for a 40" screen
• 314 cm for a 50" screen

EDIT: The value of e is valid for a high contrast between two pixels. Most images do not have such a high contrast, and therefore a value of e = 1 arcminute is a reasonnable assumption in practice.

From this follows that for N = 1920 (FullHD), amax = 35.5° (1.36 times the screen diagonal). With a 4K screen, amax = 65.3° (0.68 times the screen diagonal). This also gives a reasonnable value for standard definition PAL TV with N = 1024, amax = 19.4° (2.55 times the screen diagonal).

That would allow for larger horizonat viewing angles, such as 45° (1.05 times the screen diagonal) or 60° (0.75 times the screen diagonal) when viewing a 4K screen. At such short distances one must however take into account the possible lack of comfort due to the physical closeness of smaller screens.

[ Posted on February 18th, 2018 at 18:41 | no comment | ]

## Saturday, January 27th, 2018

### Petits pains pour hamburgers

Translation: [ Google | Babelfish ]

Categories: [ Cooking ]

Recette adaptée de la recette de pain de mie du blog Pique-assiette.

#### Ingrédients

• 300 g farine
• 3 g levure sèche
• 1 c. café poudre à lever
• 1 c. soupe sucre
• 200 mL lait tiède
• 5 g sel
• 30 g beurre mou
• huile
• 9 cercles métalliques de 9 cm de diamètre, huilés à l'intérieur
• plaque à four et papier cuisson
• lèche-frite (profonde si possible)
• pinceau

#### Préparation

• Mélanger tous les ingrédients secs, ajouter le lait et mélanger.
• Ajouter le beurre et pétrir 5 min
• Laisser reposer 1 h
• Former 9 boules (de 61 g chacune), les étirer en disque et placer chaque disque sur la plaque couverte du papier cuisson, au centre d'un cercle
• Passer le desssus des disque à l'eau à l'aide du pinceau
• Laisser reposer 2 h
• Préchauffer le four à 200 °C. Une fois chaud, y placer sur le fond la lèche-frite avec 1 L d'eau bouillante
• Cuire les petits pains pendant 15 min
• Les petits pains se conservent plusieurs jours dans une boite hermétique

[ Posted on January 27th, 2018 at 23:54 | no comment | ]

## Wednesday, June 7th, 2017

### DNS 3: NSEC3

Categories: [ IT ]

Third part of my DNS setup notes: changing the DNSSEC config from NSEC to NSEC3. This has be on my TODO list for over a year now, and despite the tutorial at the ISC Knowledge Base, the ride was a bit bumpy.

#### Generating new keys

The previous keys were using the default RSASHA1 algorithm (number 5), and we need new keys using RSASHA256 (number 8).

Generating those keys was easy. On a machine with enough available entropy in /dev/random (such as a Raspberry Pi with its hardware random number generator) run:
```dnssec-keygen -a RSASHA256 -b 2048 -3 example.com
dnssec-keygen -a RSASHA256 -b 2048 -3 -fk example.com
```

Transfer the keys to the server where Bind is running, into the directory where Bind is looking for them.

The documentation says to load the keys with
```rndc loadkeys example.net
```
but that ended with a cryptic message in the logs:
```NSEC only DNSKEYs and NSEC3 chains not allowed
```

Apparently, the algorithm of the old keys does not allow to use NSEC3 (which I knew) so Bind refuses to load these keys (which I didn't anticipate). I eventually resorted to stopping Bind completely, moving away the old keys, deleting the `*.signed` and `*.signed.jnl` files in `/var/cache/bind/` and restarting Bind. The new keys got then automatically loaded, and the zone was re-signed using NSEC.

#### NSEC3 at last

I could then resume with the tutorial.

First, generate a random salt:

```openssl rand -hex 4
```
(let's assume the result of that operation was “d8add234”).

Then tell Bind the parameters it needs to create NSEC3 records:
`rndc signing -nsec3param 1 0 10 d8add234 example.com.`
Then check that the zone is signed with
`rndc signing -list example.com`

Since the keys have changed, you need to update your domain's DS record in your parent domains DNS, using the tool provided to you by your registrar. This step is the same as in the “Linking the zones” of the previous part of this tutorial.

[ Posted on June 7th, 2017 at 23:15 | no comment | ]

## Sunday, April 2nd, 2017

### Gâteau arc-en-ciel

Translation: [ Google | Babelfish ]

Categories: [ Cooking ]

Préparer une recette de gâteau au yaourt simple. J'ai ajouté 12g de sucre vanillé pour le goût. À la place du moule à cake, utiliser un moule à manqué beurré et fariné.

Séparer la pâte en six portions, et colorer chaque portion avec un colorant alimentaire (rouge, jaune plus rouge pour l'orange, jaune, vert, bleu et rouge plus bleu pour le violet)

Verser la pâte rouge au centre du moule. Par dessus, verser lentement la pâte orange en la faisant tomber d'une hauteur la plus faible possible. Si possible, tourner le moule d'un quart de tour au cours du versement pour que la pâte forme un disque plutôt qu'une ellipse.

Verser de la même manière le jaune, puis le vert, le bleu et le violet.

Cuire 20-25 min au four à 200 °C. Une aiguille enfoncée dans le gâteau doit ressortir propre.

Déguster avec les yeux avant de manger :)

[ Posted on April 2nd, 2017 at 18:35 | no comment | ]

## Sunday, February 19th, 2017

### Cookies aux pépites de chocolat

Translation: [ Google | Babelfish ]

Categories: [ Cooking ]

Une recette adaptée de Cookwise avec des ingrédients disponibles en Finlande.

#### Ingrédients

• 140g + 20g beurre doux, mou
• 125g noix de pécan
• 200g fariinisokeri
• 1 c. à soupe extrait de vanille liquide Dr. Oetker
• 1 petit oeuf (53g)
• 200g Kinnusen myllyn luomu vehnäjauho (10.4 % de protéines)
• 1,5 c. à café poudre à lever
• 1 pincée de sel
• 80g chocolat noir 72% Pirkka luomu
• 100g chocolat au lait Panda

#### Préparation

• Préchauffer le four à 180 °C, étaler les noix de pécan sur une plaque à biscuits.
• Mélanger (30s au mixeur) la farine, la levure chimique et le sel.
• Battre (au batteur éléctrique équipé d'un fouet) 140g de beurre avec le sucre et l'extrait de vanille pour obtenir un mélange homogène. Ajouter l'oeuf et continuer à battre.
• Faire griller les noix de pécan au four pendant 8 min.
• Incorporer peu à peu le mélange de farine à l'appareil.
• Lorsque les noix sont grillées, les mélanger à 20g de beurre et laisser refroidir un peu.
• Hacher le chocolat au couteau en morceaux d'au plus 5mm et mélanger brièvement à l'appareil.
• Hacher les noix au couteau en morceaux d'au plus 5mm et mélanger brièvement à l'appareil.
• Laisser reposer 2h30 au réfrigérateur.
• Préchauffer le four à 180 °C.
• Placer 8 ou 9 boules de pâte grossièrement formées d'environ 35 – 40mm de diamètre sur une plaque en aluminium recouverte d'une feuille de cuisson réutilisable. Replacer le reste de pâte au réfrigérateur.
• Cuire pendant 10 min au four à chaleur tournante.
• Laisser refroidir 5 min puis déplacer les cookies à l'aide d'une spatule sur une grille.
• Répéter les trois étapes précédentes avec le reste de la pâte.
• Conserver dans une boite à biscuits en métal.

[ Posted on February 19th, 2017 at 11:45 | 1 comment | ]

## Sunday, February 5th, 2017

Categories: [ IT ]

My old NAS that I use for backups is now over 10 years old, and while it still works and faithfully backs-up my files every night, it has an always increasing probability to fail.

I decided to replace it with a Buffalo Linkstation 210, that offers 2 TB of space for 140 EUR, making it cheaper than building my own device, at the risk of not being able to use it the way I want it, being a commercial device that wasn't designed with my needs in mind.

The way I want to use the NAS is that it boots automatically at a given time, after which the backup script on the desktop starts, transfers the needed files, and puts the NAS to sleep mode again. That last feature was available on my previous device, but not anymore on the LS210. Hence the need to make it do my bidding.

Moreover, the Web UI for administrating the LS210 is horribly slow on my desktop due to bad Javascript code, so the less I have to use it, the better.

#### The device

The way to gain SSH access seems to vary depending on the exact version of the device and the firmware. Mine is precisely a LS210D0201-EU device with firmware version 1.63-0.04, bought in January 2017.

#### Initial setup

I found instructions on the nas-central.com forum. It relies on a Java tool called ACP_COMMANDER that apparently uses a backdoor of the device that is used for firmware updates and whatnots, but can apparently be used for running any kind of shell command on the device, as root, using the device's admin user's password.

You can test that ACP_COMMANDER works with the following command that runs `uname -a` on the device:
```java -jar acp_commander.jar -t \$IP -ip \$IP -pw password -c "uname -a"
```
It will output some amount of information (including a weird message about changing the IP and a wrong password ), but if you find the following in the middle of it, it means that it worked:
```>uname -a
Linux LS210D 3.3.4 #1 Thu Sep 17 22:55:58 JST 2015 armv7l GNU/Linux
```

Starting the SSH server is then a matter of

• enabling the SSH feature (which, on this cheap model, is disabled by default),
• starting the SSH server,
• changing root's password to "root" so that we can login (the password can be changed to something more secure later).
This is achieved through the following commands:
```java -jar acp_commander.jar -t \$IP -ip \$IP -pw password -c "sed -i 's/SUPPORT_SFTP=0/SUPPORT_SFTP=1/g' /etc/nas_feature"

java -jar acp_commander.jar -t \$IP -ip \$IP -pw password -c "/etc/init.d/sshd.sh start"

java -jar acp_commander.jar -t \$IP -ip \$IP -pw password -c "(echo root;echo root)|passwd"
```

On some older version of the firmware, root login was disabled in SSH, and needed to be allowed with

```java -jar acp_commander.jar -t \$IP -ip \$IP -pw password -c "sed -i 's/#PermitRootLogin/PermitRootLogin/g' /etc/sshd_config"
```
but that is not the case on my device.

Once this is done, I can run
```ssh root@\$IP
```

One nasty feature of the device is that the `/etc/nas_feature` file gets rewritten on each boot through the initrd. One last step is then to edit `/etc/init.d/sshd.sh` and to comment out near the beginning of the file the few lines that check for the SSH/SFTP support and exit in case SSH is not supported:
``` #if [ "\${SUPPORT_SFTP}" = "0" ] ; then
#        echo "Not support sftp on this model." > /dev/console
#        exit 0
#fi
```

According to a comment on the nas-central forum,

“The /etc/nas_feature is restored on each reboot, so sshd does not run on boot. Even if you change the init script.”

but I found this not to be true.

I checked that this setup really resists reboots, by logging in as root and typing `reboot`. SSH access was still possible after the device had restarted.

#### Going further

It was then possible to setup SSH access using keys; RSA and ECDSA are supported but not ED25519.

One missing feature is the sudo command, but I can live without it I guess.

I have then setup the device to wake up at a given time (through the “Sleep timer” feature in the administration Web UI). It is then possible to put the device to sleep by running as root
```PowerSave.sh standby
```
The command is located in `/usr/local/sbin`, and this path is not available for non-interactive logins, so I wrote the following wrapper script to shutdown the device:
```#!/bin/sh

ssh root@\$IP 'bash -l -c "PowerSave.sh standby"'
```

After having been put into standby, the device will then start automatically on the set time, or when the “function” button on the back is pressed.

[ Posted on February 5th, 2017 at 12:52 | 6 comments | ]

## Wednesday, August 3rd, 2016

### Patching a Debian Package

Categories: [ IT ]

I finally found a tutorial that explains how to patch existing Debian packages. I just did that for wmweather that stopped working after NOAA changed the URL where the METAR data is published.

In a nutshell, and in case the original web page disappears, it goes like that:

```apt-get source wmweather
cd wmweather-2.4.5
dch --nmu
mkdir debian/patches # because it didn't exist
quilt new update-url.patch
quilt edit src/wmweather.c
quilt refresh
debuild -us -uc
```

After that I could simply install the new package that had been created.

[ Posted on August 3rd, 2016 at 22:10 | no comment | ]

## Tuesday, July 12th, 2016

### Harmonie et Gamme

Translation: [ Google | Babelfish ]

Categories: [ Science ]

Les musiciens et les mathématiciens se sont cassés les dents pendant des milliers d'années sur la définition de la gamme, des notes, des intervalles et des accords. Ce qui suit est le résultat de mes refexions sur la raison dei ces difficultés.

Soit une note, appelée C1, de fréquence f. Lorsqu'on joue cette note sur un instrument, des harmoniques de fréquence 2 f, 3 f… sont produites en même temps. L'octave C2 (de fréquence 2 f) est donc naturellement en harmonie avec C1. Lorsqu'on joue en même temps C1 et C2 de même niveau sonore, les deux fréquences interfèrent et produisent un son de fréquence égal à la moyenne de C1 et C2, donc 3/2 f, que l'on appellera G1. Ce nouveau son est modulé par une fréquence perçue 2 f - f = f, trop élevée dans la pratique pour entendre le battement. L'intervalle de fréquence C1 – G1 est appelé une quinte juste.

De la même manière, lorsqu'on joue en même temps C1 et G1 de même niveau sonore, on obtient une interférence de fréquence égale à la moyenne des fréquences de C1 et G1, soit 5/4 f. On appelle cette nouvelle note E1. L'intervalle C1 – E1 est appelé une tierce majeure, et l'accord C1 – E1 – G1 est appelé accord majeur.

En théorie de la musique, on peut traverser toutes les notes de la gamme en partant de C1 et montant d'une quinte, puis en répétant l'opération. Ainsi, on passe de C1 à G1, puis en montant encore d'une quinte on passe de G1 à D2, puis A2, puis E3 et B3. Enfin, en montant d'une quinte depuis F0, on arrive à C1. On pourrait donc imaginer calculer les fréquences de D, F, A et B de cette manière:

• En augmentant F0 (fréquence 2/3 f) d'une quinte (donc en multipliant par 3/2) on arrive bien à C1 (fréquence f) ; ceci donne une fréquence de 4/3 f pour F1.
• G1 (3/2 f) augmenté d'une quinte (multiplié par 3/2) donne D2 (9/4 f), et donc D1, une octave plus bas, a une fréquence de 9/8 f.
• D1 augmenté d'une quinte donne de la même manière A1 (27/16 f).
• A1 augmenté d'une quinte donne E2 (81/32 f), donc E1 a une fréquence de 81/64 f.

Mais on a vu plus haut que E1 devait avoir une fréquence de 5/4 f (soit 80/64 f) pour être en harmonie avec C1 et G1 ! C'est donc là que l'édifice commence à s'écrouler : la tierce C1 – E1 n'a pas le même rapport de fréquences que la tierce C2 – E2 ; en d'autres termes, E2 n'est pas exactement une octave au dessus de E1 si on s'en tient à la définition « par quintes ». Les deux définitions de la tierce étant incompatibles, il a fallu trouver une solution.

La manière dont les fréquences des notes sont définies s'appelle le tempérament, et de nombreux tempéraments on été inventés au fil des siècles. La solution retenue depuis le XIXè siècle est le tempérament égal, où tous les demi-tons sont séparés d'un rapport de fréquence égal à 21/12. Ce tempérament donne des accords qui sont tous faux, mais suffisamment peu faux pour que ce ne soit pas gênant.

[ Posted on July 12th, 2016 at 12:43 | no comment | ]

## Wednesday, April 27th, 2016

### DNS 2: DNSSEC

Categories: [ IT ]

Second part of my DNS setup notes, this time about DNSSEC. The following notes assumes there is already a running instance of Bind 9 on a Debian Jessie system for an imaginary domain `example.com`, served by a name server named `ns.example.com`.

The version of Bind 9 (9.9.5) on Debian Jessie supports "inline signing" of the zones, meaning that the setup is much easier than in the tutorials mentioning dnssec-tools or opendnssec.

Again these notes are mostly based on the example from the ISC Knowledge Base.

#### Setting up a signed zone

If you have a delegated zone (like `home.example.com` from the first part), do the following for both `example.com` and `home.example.com`.

##### Generate the keys
On a machine with enough available entropy in `/dev/random` (such as a Raspberry Pi with its hardware random number generator ) run
```dnssec-keygen example.com
dnssec-keygen -fk example.com
```

(you can add the `-r /dev/urandom` option to the command if you dare, if /dev/random is too slow. It can literaly take hours to generate those keys otherwise).

Transfer the keys to the server where Bind is running.

##### Configure Bind

Create a `/etc/bind/keys` directory where to put the keys. Ensure the `.private` files belong to root, are readable by the group bind and not by other users.

In `named.conf.options` add to the options block:
```options {
…
dnssec-enable yes;
dnssec-validation auto;
dnssec-lookaside auto;
…
};
```

Create in `/var/cache/bind` a symbolic link to `/etc/bind/db.example.com`.

In `named.conf.local`, in the `zone "example.com"` block, add
```zone "example.com" {
…
#file "/etc/bind/db.example.com";
file "/var/cache/bind/db.example.com";
key-directory "/etc/bind/keys";
auto-dnssec maintain;
inline-signing yes;
};
```

Note that the `db` file must point to a file in `/var/cache/bind`, not in `/etc/bind`. This is because bind will create a `db.example.com.signed` file (among other related journal files), constructed from the path of the "file" entry in the zone declaration, and it will fail doing so if the file is in `/etc/bind`, because Bind would attempt to create the `.signed` file in this read-only directory.

```rndc reconfig
```
Then check that the zone is signed with
```rndc signing -list example.com
```

Your registrar should provide a tool (most probably Web based) where to put DS records for your domain.

On the DNS server, generate a `DS` record with
```dig @localhost dnskey example.com | /usr/sbin/dnssec-dsfromkey -f - example.com
```
Copy and paste these lines in the registrar's tool. After a little while, you should be able to query the `DS` record with
```dig @localhost -t ds example.org
```
If you have a delegated zone such as `home.example.com`, generate a `DS` record for that zone with
```dig @localhost dnskey home.example.com | /usr/sbin/dnssec-dsfromkey -f - home.example.com
```
and place these lines in `db.example.com` (i.e., the `db` file for the parent zone). Change the serial number of the zone in the same file and run
```rndc reload
```
You should then be able to query the `DS` record with
```dig @localhost -t ds home.example.org
```

You can use Verisign's DNS debugging tool to check that the signatures are valid and DNSViz to view the chain of signatures from the TLD DNS down to your DNS. This also helped me figure out that my zone delegation was incorrect and caused discrepancies between my primary DNS server and the secondary server.

[ Posted on April 27th, 2016 at 19:21 | 1 comment | ]

### DNS 1: Dynamic DNS

Categories: [ IT ]

Now that I have my own server, I can finally have my own DNS server and my own domain name for my home computer that has a (single) dynamic IP address.

The following notes assumes there is already a running instance of Bind 9 on a Debian Jessie system for an imaginary domain `example.com`, served by a name server named `ns.example.com` and you want to dynamically update the DNS records for `home.example.com`. This is largely based on the Debian tutorial on the subject, solving the problem that `bind` cannot modify files in `/etc/bind`.

#### On the server

Create a shared key that will allow to remotely update the dynamic zone:
```dnssec-keygen -a HMAC-MD5 -b 128 -r /dev/urandom -n USER DDNS_UPDATE
```
This creates a pair of files (`.key` and `.private`) with names starting with `Kddns_update.+157+`. Look for the value of `Key:` entry in the `.private` file and put that value in a file named `/etc/bind/ddns.key` with the following content (surrounding it with double quotes):
```key DDNS_UPDATE {
algorithm HMAC-MD5.SIG-ALG.REG.INT;
secret "THIS IS WHERE YOU PUT THE KEY";
};
```

You can then delete the two `Kddns_update.+157+` files. Ensure that `/etc/bind/ddns.key` belongs to "root" and to the "bind" group, and is not readable by other users.

Then in `named.conf.local`, include the key file and declare a new zone:

```include "/etc/bind/ddns.key";

zone "home.example.com" {
type master;
file "/var/cache/bind/db.home.example.com";
allow-update { key DDNS_UPDATE; };
journal "/var/cache/bind/db.home.example.com.jnl";
};
```

In `/var/cache/bind` create the file `db.home.example.com` by copying `/etc/bind/db.empty` and adapting it to your needs. For convinience, create a `db.home.example.com` symbolic link in `/etc/bind` pointing to `/var/cache/bind/db.home.example.com`.

In `db.example.com` (that is, the parent zone), add a `NS` entry to delegate the name `home.example.com` to the DNS server of the parent zone:
```home.example.com NS ns.example.com
```

You can now reload the `bind` service to apply the configuration changes.

I also found examples of how to test the dynamic zone with `nsupdate`.

#### On the home computer

I decided to use `ddclient` 3.8.3 because it supports dynamic dns updates using the `nsupdate` tool. I backported that version of `ddclient` manually from a Debian Testing package; it's written in Perl and the backporting is trivial.

Copy `/etc/bind/ddns.key` from the server to `/etc/ddns.key` on the home computer (the one running ddclient), ensuring only root can read it. Then add the following to `/etc/ddclient.conf` (be careful with the commas, there is no comma at the end of the second last line):
```protocol=nsupdate, \
zone=home.example.com, \
ttl=600, \
home.example.com
```

You can then try out the new setup.

[ Posted on April 27th, 2016 at 18:15 | 1 comment | ]

## Wednesday, April 13th, 2016

Categories: [ IT ]

What is the minimum entropy for my home computer's password?

In recent (post-2007) Debian (and probably other) Linux distributions, the passwords are stored in `/etc/shadow` using the `sha512crypt` algorithm. According to Per Thorsheim, with 2012 hardware, a single Nvidia GTX 580 could make 11,400 attempts at brute-force cracking such a password. This means that a log2 11,400 = 13.5 bit password could be cracked in 1 second.

To have a password that would resist a year to such a brute-force attack, one must multiply the password complexity by 86,400×365 (seconds per year) i.e., add 24.5 bits to the password for a total of 38 bits.

But this password is guaranteed to be cracked in a year. To make the probability of cracking such a password much lower, let's say less than 0.01, one must increase the password's complexity by a hundred times i.e., add 6.7 bits. We now have a minimum of 44.7 bits.

If one does not want to change the password for the next 10 years (because one is lazy), one must again increase the complexity tenfold (that's another 3.3 bits for a total of 48 bits) and account for the increase in processing power in the coming years. Between 2002 and 2011, CPU and GPU computing power has been multiplied by 10 and 100 respectively i.e., +0.37 and +0.74 bits/year. That means that the password's complexity must be increased by 0.74 ×10 = 7.4 bits. We have now reached 55.4 bits.

Now we need to guess who are the password crackers. How many such GPU will they put together? Titan has 18,688 GPUs (add another 14.2 bits to stay ahead of it), and the (more affordable) machine that cracked LinkedIn leaked passwords had 25 GPUs (requiring to add only extra 4.6 bits).

Assuming the crackers have a 25-GPU setup and not a gigantic cluster, 60 bits should be perfectly safe. If they are a government agency with huge resources and your data is worth spending the entirety of that cluster's energy for 10 years, 70 bits is still enough.

The same article also mentions an Intel i7, 6-core CPU would make 1,800 attempts per second i.e., 10.8 bits. For a password that must resist for 10 years, that would mean 49 bits. Titan has 300,000 CPU cores (50,000 times more than the i7), so that makes an extra 15.6 bits for a total of 64.6 bits. The Tianhe-2 has 3,120,000 cores, adding 19 bits to the original 49 bits, leading to 68 bits total.

In summary, 70 bits is enough. If you are lazy and not paranoid, 60 bits are still enough. If you think the crackers will not use more than 32 i7 CPUs for a month to try and break your password (adding 2.4 + 21.3 bits to the original 10.2 bits), 48.5 bits are still enough.

[ Posted on April 13th, 2016 at 19:20 | no comment | ]

## Sunday, March 13th, 2016

### Galettes de Sarrassin

Translation: [ Google | Babelfish ]

Categories: [ Cooking ]

#### Ingrédients

• 150g farine de sarrassin
• 20g farine de froment
• 1 pincée de sel
• 1 oeuf
• 250 mL lait
• 200 mL cidre

#### Préparation

Mélanger les farines et de sel. Y ajouter l'oeuf et mélanger pour absorber une partie de la farine et obtenir une pâte épaisse. Délayer progressivement avec le lait, puis avec le cidre. Laisser reposer 1 à 2 heures. Faire cuire chaque galette dans une poële très chaude et huilée.

[ Posted on March 13th, 2016 at 20:27 | no comment | ]

## Saturday, March 12th, 2016

### Nouveau serveur

Translation: [ Google | Babelfish ]

Categories: [ IT ]

Le blog (et le reste de mes pages Web) a déménagé sur un nouveau serveur (une machine virtuelle hébergée chez shellit.org. Après longue réflexion et tergiversations, et afin de continuer la série des machines dont le nom se termine en « kone », j'ai décidé de l'appeler « lentokone », koska se on kone joka on pilvissä.

J'en ai profité pour recommencer à jouer les administrateurs système et j'ai installé des serveurs DNS, SMTP, IMAP, HTTP pour gérer mon domaine moi-même.

[ Posted on March 12th, 2016 at 15:30 | no comment | ]

## Sunday, January 17th, 2016

### Vue du bureau

Translation: [ Google | Babelfish ]

Categories: [ Grumbling ]

Il faisait beau vendredi, alors j'ai pris des photos depuis les fenêtres du bureau.

Coté lac.

Coté lac aussi. On peut voir la piste de patin à glace sur le lac.

Coté gare.

[ Posted on January 17th, 2016 at 14:10 | no comment | ]

## Wednesday, December 23rd, 2015

### Photo haute vitesse

Translation: [ Google | Babelfish ]

Categories: [ DIY/Arduino ]

Cet appareil n'a pas de nom, mais il sert à controller un appareil photo et un flash pour prendre des photos d'objets qui tombent. Un rayon laser (récupéré d'un pointeur laser rouge bas de gamme) dont la présence est détectée par un phototrasistor sensible à la lumière visible est interrompu par l'objet qui tombe, et après un temps déterminé, le flash est déclenché.

Le code est disponible.

L'appareil utilise un RBBB (compatible Arduino, mais dans un format plus compact) pour contrôler un écran LCD alphanumérique, l'appareil photo via sa télécommande par câble, et le flash via son sabot. Il permet aussi de règler le délai entre la détection de la chute de l'objet et la prise de la photo. On peut en outre règler la longueur de l'impulsion du flash (ce qui n'est pas très utile apparemment, étant donné que cette durée n'a pas l'air d'avoir d'influence sur la durée du flash, mais cette durée détermine aussi le délai entre le déclenchement du flash et la fermeture de l'obturateur de l'appareil photo). En outre, on peut choisir à quel moment l'obturateur sera ouvert (avant de faire tomber l'objet à photographier, au moment où celui-ci coupe le faisceau laser, ou le mode manuel où l'utilisateur a la responsabilité d'ouvrir l'obturateur), et l'envoi ou non d'une impulsion pour effectuer la mise au point (la télécommande filaire est conçue de sorte à ce que le signal de mise au point soit toujours envoyé avant le signal d'ouverture de l'obturateur, il se peut que l'appareil ne fonctionne pas correctement si le second n'est pas précédé du premier).

Le RBBB est alimenté par 4 batteries rechargeables NiMH, qui fournissent ensemble une tension maximale de 5,4 V, juste en dessous de la limite maximum du microcontrolleur (5,5 V). Ceci permet de se passer d'un régulteur de tension, à condition de ne pas utiliser de piles alcalines (qui produiraient une tension trop élevée, 6,6 V au maximum).

Une des difficultés a été que le laser tend à chauffer, ce qui diminue environ de moitié sa luminosité au bout de 30 s. À ce moment, le laser n'est alors plus assez puissant pour être détecté par le phototransitor. La seule solution est de ne pas laisser au laser le temps de chauffer.

Une autre difficulté a été la construction du cadre en bois qui porte le laser et le phototransistor : il n'est pas parfaitement plan (je voulais le rendre démontable et j'ai donc utilisé des angles en acier à visser, mais comme je n'ai pas réussi à visser les vis bien verticalement, elles ont déplacé légèrement les angles et tordu les quatre morceaux de bois). De plus, il n'est pas facile de percer un trou bien droit (pour recevoir le laser) et aligné avec un trou similaire (pour recevoir le phototransitor) sur le coté opposé du cadre.

Pour aligner le laser sur le phototransistor, il faut donc tourner un peu le premier dans son logement jusqu'à ce que le point rouge atteigne le centre du phototransistor. L'appareil dispose d'ailleurs d'un mode de fonctionnement où le laser est allumé en permanence et où l'utilisateur peut voir si le phototransistor est correctement éclairé.

La dernière difficulté a été de me rendre compte que le temps de chute de l'objet (entre le moment où le laser est interrompu et le moment où la photo doit être prise) dépend de la vitesse de l'objet au moment où il passe dans le faisceau laser, donc de la hauteur (au dessus du faisceau) d'où l'objet a été laché. Pour obtenir des expériences répétables, il faut donc faire tomber l'objet à partir du support sur lequel il repose, et il faut donc que ce support soit à une distance connue du faisceau. Le support est donc un morceau de carton ondulé percé d'un trou assez grand pour laisser passer l'objet (mais pas trop grand pour que l'objet ne puisse pas tomber à coté du faiscea) posé sur le cadre en bois. La distance d entre le haut du carton et le faisceau, la hauteur de chute h du haut du carton jusq'à l'endroit où la photo est prise et le temps de chute t sont liés par l'équation suivante : t = √(2/g) × (√h - √d) où g est l'accélération de la pesanteur.

[ Posted on December 23rd, 2015 at 23:45 | no comment | ]

## Wednesday, December 9th, 2015

### BÉPO 3

Translation: [ Google | Babelfish ]

Categories: [ IT ]

Au bout de 6 semaines, j'arrive à taper lentement en aveugle (ou alors vite en faisant énormément de fautes). J'ai tendace à confondre mains droite/gauche et majeur/annulaire. Si je me concentre ça va, mais c'est vite fatigant.

Sur le Typematrix du boulot ça va plus ou moins, mais le clavier normal (donc tordu) de la maison est une plaie, les doigts tombent systématiquement entre les touches du quart droit.

[ Posted on December 9th, 2015 at 22:18 | no comment | ]

## Saturday, October 31st, 2015

### BÉPO 2

Translation: [ Google | Babelfish ]

Categories: [ IT ]

Après 8 jours, ça commence à venir, mais pas vite. Taper en aveugle demande beaucoup de concentration.

BÉPO en disposition par défaut (tout du moins jusqu'au prochain redémarrage du serveur X), Scroll Lock permettant de basculer vers la disposition fi :

`setxkbmap "fr,fi" "bepo,classic" "grp:sclk_toggle"`

[ Posted on October 31st, 2015 at 12:12 | no comment | ]

## Sunday, October 25th, 2015

### Bépo 1

Translation: [ Google | Babelfish ]

Categories: [ IT ]

Vendredi (il y a 2 jours), je me suis mis au BÉPO. C'est dur et je ne tape pas vite. Je fais des exercices.

[ Posted on October 25th, 2015 at 11:18 | no comment | ]

## Sunday, September 6th, 2015

### Noursella v2

Translation: [ Google | Babelfish ]

Categories: [ Cooking/Choco Noursy ]

Deuxième version du Noursella, cette fois-ci tartinable à température ambiante.

#### Ingrédients

• 20g chocolat au lait
• 50g sucre glace
• 30g huile neutre (navette)
• 25g cacao
• 80g pâte de noisette (100% noisettes, grillées puis broyées)

#### Préparation

Faire fondre le chocolat au lait (p. ex. 1 min au micro-ondes). Y ajouter le sucre glace et le cacao tamisés, et mélanger. Délayer avec l'huile puis avec la pâte de noisette. Laisser reposer une nuit.

#### Commentaires

• Liquide visqueux juste après préparation, devient tartinable après un temps de repos.

[ Posted on September 6th, 2015 at 11:06 | 1 comment | ]

## Saturday, August 22nd, 2015

### Noursella v1

Translation: [ Google | Babelfish ]

Categories: [ Cooking/Choco Noursy ]

Après des années de pause, j'ai retenté de fabriquer ma propre pâte à tartiner chocolat et noisette, cette fois-ci à partir de pâte de noisette.

#### Ingrédients

• 60g sucre glace
• 30g huile neutre (navette)
• 30g cacao
• 80g pâte de noisette (100% noisettes, grillées puis broyées)

#### Préparation

Tamiser le sucre glace et le cacao, le mélanger puis délayer avec l'huile puis avec la pâte de noisette. Conserver au réfrigérateur.

#### Commentaires

• Liquide visqueux (comme du miel) à température ambiante, devient tartinable à température du réfrigérateur.
• Facile à préparer, contrairement aux expériences précédentes (ici, un bol et une cuillère suffisent).
• La texture granuleuse au début semble devenir moins granuleuse avec le temps.

[ Posted on August 22nd, 2015 at 14:41 | 1 comment | ]

## Friday, March 6th, 2015

### It will be URxvt after all...

Categories: [ IT ]

I just switched from using Xterm to using evilvte but then I noticed that evilvte cannot be resize smaller. It can become bigger, but there is no way back. Then I learned that URxvt does everything I want (it even uses the same font as Xterm by default) with a bit of configuration. And it's much more lightweight than evilvte (it doesn't use GTK, that helps).

This is my `.Xresources` (everything you need to know is in the man page).
```*VT100*foreground: black
*VT100*background: white

URxvt.scrollBar: false
URxvt.secondaryScreen: 1
URxvt.secondaryScroll: 0
URxvt.perl-ext-common: default,matcher
! old keyword
URxvt.urlLauncher: firefox
! new keyword
URxvt.url-launcher: firefox
URxvt.matcher.button: 1
URxvt.keysym.C-Up: \033[1;5A
URxvt.keysym.C-Down: \033[1;5B
URxvt.keysym.C-Left: \033[1;5D
URxvt.keysym.C-Right: \033[1;5C
URxvt.keysym.C-Page_Up: \033[5;5
URxvt.keysym.C-Page_Down: \033[6;5
```
You need to merge it with X's resource database
`xrdb -merge .Xresources`

and then you can run the terminal.

And Firefox just restored the --remote option, so `wmnetselect` should even work again (until next time, anyway). Let's say it was an opportunity to learn about stuff…

[ Posted on March 6th, 2015 at 19:09 | no comment | ]

## Thursday, March 5th, 2015

### Local Debian Repository

Categories: [ IT ]

Since I built a customized Debian package I could as well have my own repository. I started from this tutorial but it's a bit out of date and has a dead link to the reprepro short-howto, so here's a record of what I did.

First, you will need to install the `reprepro` package.

Then, choose a place where to put your repository (I chose my \$HOME). `Origin`, `Label` and `Description` are free-form fields. `Codename` is the same as my current Debian version, and `Architectures` matches the architectures I'm using. Then run:
```mkdir -p packages/debian/conf

cd packages/debian

cat <<EOF > conf/distributions
Origin: Matthieu
Label: Mathieu's Personal Debs
Codename: wheezy
Architectures: i386 amd64 source
Components: main
Description: Matthieu's Personal Debian Repository
SignWith: yes
DebOverride: override.wheezy
DscOverride: override.wheezy
EOF

cat <<EOF > conf/options
verbose
basedir .
EOF

touch conf/override.wheezy```
Now's the time to add the packages. Since `SignWith` was set to `yes` in the `conf/distributions` file, your GPG key will be used for signing the manifest files.
```reprepro -Vb . includedeb wheezy  /src/evilvte_0.5.1-1+custom_amd64.deb
reprepro -Vb . includedsc wheezy  /src/evilvte_0.5.1-1+custom.dsc```
Next configure your system to use the newly created repository by adding to your `/etc/apt/sources.list` (replace \$HOME with the actual path to your repository):
```deb file:\$HOME/packages/debian/ wheezy main
deb-src file:\$HOME/packages/debian/ wheezy main```
Add your GPG key to apt's keyring (replacing KEY-ID with the one of the GPG key that was used when adding the packages earlier):
`gpg -a  – export KEY-ID | sudo apt-key add -`
You can now run `apt-get update` and it should pick the content of your local repository. You can check that it is indeed the case:
```apt-cache showpkg evilvte
Package: evilvte
Versions:
0.5.1-1+custom …
0.5.1-1 …
…```

[ Posted on March 5th, 2015 at 23:19 | no comment | ]

### Bitmap Fonts for my Terminal

Categories: [ IT ]

Since I started with Linux, back in 1997, my xterm have been using always the same font: a bitmap, fixed font which produces 6x13 pixels glyphs. I'm convinced that a bitmap font is the best possible choice for not-so-high resolution LCD monitors (I have a 17" 1280x1024 monitor which results in a 96 dpi resolution) where any vector font would inevitably produce aliased or fuzzy glyphs. My bitmap font is crisp and has no rainbow edges (who in his right mind could imagine that subpixel antialiasig is a good idea?).

With the xterm, I could simply specify the font as 6x13 and it would use it. That was simple, because it was meant for it.

Today I switched from pure X11 xterm to GTK-based evilvte and while evilvte is apparently a great tool, it didn't want to use my beloved 6x13 bitmap font. It would use 6x12 or 7x13, but not the one in the middle. The font is however available on the system through fontconfig, since I could find it with `fc-match`:
```\$ fc-match Fixed-10:style=semicondensed
6x13-ISO8859-1.pcf.gz: "Fixed" "SemiCondensed"```
But evilvte, while showing "SemiCondensed" as an option in its font dialog, just seemed to ignore it. The fontconfig documentation mentions that one can trigger debug output by setting an environment variable `FC_DEBUG=1`. With it, I could see how Pango (GTK's font managemnt system) was interacting with fontconfig:
```fc-match Fixed-10:semicondensed
Match Pattern has 19 elts (size 32)
family: "Fixed"(s) …
style: "semicondensed"(s)
slant: 0(i)(s)
weight: 100(i)(s)
width: 100(i)(s)
…
Pattern has 18 elts (size 18)
family: "Fixed"(w)
style: "SemiCondensed"(w)
slant: 0(i)(w)
weight: 100(i)(w)
width: 87(i)(w)
…
file: "/usr/share/fonts/X11/misc/6x13-ISO8859-1.pcf.gz"(w)```

That's the right font file.

While Pango:
```python mygtk.py "Fixed SemiCondensed 10"
Match Pattern has 20 elts (size 32)
family: "Fixed"(s)  …
slant: 0(i)(s)
weight: 80(i)(s)
width: 87(i)(s)
…
Pattern has 18 elts (size 18)
family: "Fixed"(w)
style: "Regular"(w)
slant: 0(i)(w)
weight: 80(i)(w)
width: 100(i)(w)
…
file: "/usr/share/fonts/X11/misc/7x13-ISO8859-1.pcf.gz"(w)```

And that's not the right font file…

Notice the important difference: fc-match asks for a weight of 100 (and style SemiCondensed) while Pango asks for weight 80 and width 87 (which is apparently equivalent to semi-condensed). Since my font had a weight of 100, it was never selected. However, when requesting a bold version (```fc-match Fixed-10:semicondensed:bold``` or ```python mygtk.py "Fixed SemiCondensed Bold 10"```) the same font is found (6x13B-ISO8859-1.pcf.gz, which is the bold counterpart of my font). That took me several hours to find out.

Since the root of the problem seemd to be the weight, I needed to find out how to make Pango tell fontconfig to use a different weight, since there is apparently nothing between “Regular” (Pango 400, fontconfig 80) and “Bold” (Pango 700, fontconfig 200). And then, completely by accident, I found out there is actually a middle value: “Medium” (Pango 500, fontconfig 100), which is exactly what I neeed. But the outdated PyGTK documentation and the well-hidden man page (and very little help from Google and DuckDuckGo in finding a decent documentation for Pango, I must say) didn't make this any easy.

So finally, the magic font description I put in evilvte's config is “Fixed Medium SemiCondensed 10”. With it, Pango selects the font I want:
```\$ python mygtk.py "Fixed Medium SemiCondensed 10"
Match Pattern has 20 elts (size 32)
family: "Fixed"(s) …
slant: 0(i)(s)
weight: 100(i)(s)
width: 87(i)(s)
…
Pattern has 18 elts (size 18)
family: "Fixed"(w)
style: "SemiCondensed"(w)
slant: 0(i)(w)
weight: 100(i)(w)
width: 87(i)(w)
…
file: "/usr/share/fonts/X11/misc/6x13-ISO8859-1.pcf.gz"(w)```

#### Appendix

The `mygtk.py` script is a simple GTK tool I wrote for the purpose of using a specific Pango font description and producing the fontconfig debug output. This is the script:
```import gtk
import pango
import gobject
import sys

window = gtk.Window(gtk.WINDOW_TOPLEVEL)
tv = gtk.Label("Hello World")
tv.modify_font(pango.FontDescription(sys.argv[1]))
tv.show()
window.show()

gtk.main()```

[ Posted on March 5th, 2015 at 22:14 | no comment | ]

### Customized Debian Package

Categories: [ IT ]

Today I switched from using xterm (which I had been using for the past 15 years at least) to using evilvte. The reason is that evilvte allows to click on URLs and opens a new tab in Firefox, while xterm does not. Since Firefox removed the --remote option, `wmnetselect` did not anymore allow me to open a copied URL. Since `wmnetselect` has no been updated since forever and has even been removed from Debian, I thought it was time for a radical change (yes, I changed my terminal emulator because of the Web browser. I know).

Evilvte is one of those simplistic tools that you configure by editing the source code (the `config.h`, really), so I thought that after having done that, I may as well make my own custom Debian package. It wasn't too hard, but since I don't plan to do this regularly, here's the process.

Get the Debianized sources:
`apt-get source evilvte`
Enter the directory
`cd evilvte-0.5.1`

Edit the config file (or whatever you want to do for your own package), save it in the right place. In my case, the package contained a `debian/config.h` customized by the package's maintainer, so I needed to modify this one rather than the `src/config.h` one. During the building of the package, `src/config.h` is overwritten by `debian/config.h`.

Then edit `debian/changelog` and add a new entry. By doing that, you need to choose a new version number. I wanted to keep the original version number of the package (0.5.1-1) but make it known that it was slightly newer than 0.5.1-1: I decided to go for 0.5.1-1+custom (after discovering that my first choice, 0.5.1-1~custom, means that the package is slightly older than 0.5.1-1 and would therefore have been replaced during the next `apt-get dist-upgrade`) by 0.5.1-1 . The description of the change is simply “Custom configuration”. For the rest, follow the example of the existing entries in the changelog. Be careful, there are two spaces between the author and the date.

If you have changed the upstream source code instead of only Debia-specific files, the package building helpers will record a patch for your and let you write some comments in the patch file, based on the new entry in the changelog.

Then you just need to build the package:
`dpkg-buildpackage`
It will probably ask you for your GPG passphrase (when signing the package), and after that, you're done. The newly created package is in the parent directory, and ready to be installed.
```cd ..
sudo dpkg -i evilvte_0.5.1-1+custom_amd64.deb```

That's it!

[ Posted on March 5th, 2015 at 21:14 | 3 comments | ]

## Tuesday, December 2nd, 2014

Categories: [ Science ]

Let's consider base 10 logarithms and the basic equality
```log(a×b) = log(a) + log(b)
```
Rounding to two places after the decimal separator, we also start with
```log(2) = 0.30
```
and
```log(10) = 1
```
Therefore, we have
```log(4) = 2⋅log(2) = 0.60
```
and
```log(8) = 3⋅log(2) = 0.90
```
Also,
```log(10) = log(2) + log(5) = 1
```
therefore
```log(5) = 0.70
```
Then a bit more approximation: 81 ≈ 80, therefore
```2⋅log(9) ≈ log(10) + log(8)
```
This gives us
```log(9) ≈ 0.95
```
and
```log(3) = log(9)/2 = 0.48
```
as well as
```log(6) = log(2) + log(3) = 0.78
```
In the same way, 50 ≈ 49, therefore
```log(5) + log(10) ≈ 2⋅log(7)
```
in other words,
```log(7) ≈ 0.85
```

With more approximations, one will find the logs of more prime numbers without the need for a calculator.

[ Posted on December 2nd, 2014 at 00:02 | no comment | ]

## Friday, July 18th, 2014

### Circuit auto été 2014

Translation: [ Google | Babelfish ]

Categories: [ Games ]

Voici le circuit millésime juillet 2014, tout en virages, il n'est pas facile à parcourir. Cette année, les voitures rouge et bleue sont devenues poussives vers la fin des vacances. Difficile de savoir si le problème vient d'un mauvais contact entre les rails et la voiture, des balais ou d'un frottement mécanique (au niveau de l'axe du moteur ?). Un patin de la rouge s'est percé à force de frotter contre les rails, je l'ai réparé en y mettant un peu d'étain à souder (et comme il s'agit d'un alliage à 60% de plomb, ça doit polluer un peu en prime…)

[ Posted on July 18th, 2014 at 13:22 | no comment | ]

## Saturday, June 28th, 2014

### Interpreting Probabilities

Categories: [ Science ]

On the radio the other day, I heard a mathematician warning about too hastily interpreting probability results. Here's the example he gave.

Imagine a population of 100,000 people, 100 of which having a rare disease (but not knowing about it) and therefore 99,900 of which not being sick. Imagine moreover there is a test that can detect this disease with a 99% accuracy: this means that the test will on average give a positive result on 100 × 0.99 = 99 of the 100 sick persons and a negative result on 100 × (1 - 0.99) = 1 of them. It will also give a negative result on 99,900 × 0.99 = 98901 non-sick persons and a (false) positive result on 99,900 × (1 - 0.99) = 999 non-sick persons.

This means that out of the 99 + 999 = 1098 persons (out of the whole population) who got a positive result, only 99 actually have the disease. This means that the test indicates, for a random person taken from the whole population, only a 99 / 1098 ≈ 9% probability of being sick. In other words, even if the test is positive, there is still a 91% chance of not being sick! This new result needs to be put into perspective with the probability of being sick before doing the test (0.1%) and after getting a positive test result (9%, i.e., 90 times higher chance of being sick). But it also means that because of the imbalance between sick and non-sick populations, the 1% failure of the test will yield a lot more false positive results among the non-sick population than correct positive results among the sick population.

[ Posted on June 28th, 2014 at 19:38 | no comment | ]

## Sunday, May 4th, 2014

### New Leffakone Timer

Categories: [ DIY/Arduino | TV/Leffakone ]

I finally built the timer for the new Leffakone. It is based on an Arduino Uno, which controls two reed relays and one LED. The reed relays can be activated with a very low current (10 mA), meaning that the Arduino can drive them directly from any I/O pin. The relays' contacts are connected in parallel to the power button and the reset button. The Arduino's serial-over-USB port is connected to one of the USB headers of the motherboard with a home-made cable, and the timer is set by software through this serial connection. All the wires coming from the computer case's front panel are connected to the circuit (to the 8-pin header protruding from the protoboard), and wires go from there to the motherboard's front-panel header (2 white wires for the power button, 2 grey wires for the reset button, and 2 blue+black wires for the power-on LED. The two boards are screwed on the bottom plate of the case of an old CD drive; for installation, I closed the case and put it into the computer as a regular CD drive.

While the timer is counting down, it blinks the computer case's HDD LED (which therefore is not anymore indicating the HDD activity).

When the timer expires, it closes the power button's relay for 500 ms. An optional watchdog timer would close the reset button's relay if the machine does not boot correctly i.e., if the timer is not reset within 30 s. This watchdog timer is currently disabled in the code, since the problems I have had with GRUB freezing on startup seem to be related to manually powering the device and switching the TV on shortly after. I'll enable it if it seems necessary. Here is the code for the Arduino.

The software client for the timer is written in Python and is very straightforward: send ASCII digits to the serial port, ending with a newline character. It interprets this number as a number of seconds, and starts counting down. When disconnecting the client from the serial port, the Arduino resets and forgets all about the timer value; I found out that setting the DTR line to False in the Python Serial object prevents this from happeining. I haven't however found out how to prevent a reset when connecting to the Arduino; this is less a problem, since when I connect to it, I want to reset the timer, and reseting the whole program does just that. It seems that it's the Linux driver that asserts the DTR line when opening the serial port; I haven't investigated further. It is worth noting that when the machine boots, it does not reset the Arduino.

Finally, the cristal in the Arduino is accurate to 99.5% which is not enough to guarantee that the timer will wake up the computer within a minute after a countdown of several days. I therefore apply a corrective factor to the time sent to the Arduino. The factor was estimated from a 15.5 hour countdown, which lasted about 90s more than it should have. Over a 7-days countdown, it would cause the timer to expire about 16 minutes too late.

[ Posted on May 4th, 2014 at 20:38 | 1 comment | ]

## Saturday, April 26th, 2014

### Probabilities

Categories: [ Science ]

Before Easter, the supermarket was selling Rölli suprise-eggs, announcing that every fifth egg contained a figurine related to Rölli's universe. This made me wonder: how many eggs you need to buy to ensure that you get at least one such figurine?

The following formula gives the probability (p) of getting at least one Rölli figurine given that one has bought n eggs, and that every k egg contains such a figurine:

p = 1 − (1 − 1/k)n

The answer to the first question is not straightforward, though. To be absolutely sure to get at least one figurine, you need to buy 4/5 of the egg production plus one egg, because there is always an (admitedly slim) chance that the 4/5 of are made entirely of eggs containing something else than a Rölli figurine, and that the 1/5 that is left is made only of eggs containing Rölli figurines. The extra egg that you need to buy is therefore taken from this last 1/5, and is guaranteed to contain a Rölli figurine.

If you are not willing to spend so much time and money tracking and buying most of the egg production, you can trade time and money for a tiny bit of uncertainty. For example, if you can accept to have only 90% chance of getting a Rölli figurine instead of 100%, it is enough to buy 11 eggs. If you want a better chance yet and want to go for 95%, you need to buy 14 eggs. Finally, if you want a 99% chance, you need to get 21 eggs. These values were computed from the formula above, setting k = 5 (“every fifth egg”), p = 0.90 or p = 0.95 or p = 0.99, solving the equation for n and rounding the result to the nearest, larger integer.

It is also worth noticing that if you decide to buy 5 eggs (because every 5th egg contains a Rölli figurine), you have only about 2 in 3 chances of getting a Rölli figurine.

The table below gives the minimum values of n for a given value of k and different probability thresholds. It also gives the ratio n over k, i.e., given a “one in k” probability, how many times k does one need to get to have a probability greater than the thresold. The second column also indicates, given a “one in k” probability, what are you chances of getting what you want if you get k items. Notice that these values grow toward a given, finite limit when k grows larger.

kp(n=k)p≥0.90 (n/k)p≥0.95 (n/k)p≥0.99 (n/k)
20.750 4 (2.000) 5 (2.500) 7 (3.500)
30.704 6 (2.000) 8 (2.667) 12 (4.000)
40.684 9 (2.250) 11 (2.750) 17 (4.250)
50.672 11 (2.200) 14 (2.800) 21 (4.200)
60.665 13 (2.167) 17 (2.833) 26 (4.333)
70.660 15 (2.143) 20 (2.857) 30 (4.286)
80.656 18 (2.250) 23 (2.875) 35 (4.375)
90.654 20 (2.222) 26 (2.889) 40 (4.444)
100.651 22 (2.200) 29 (2.900) 44 (4.400)
200.642 45 (2.250) 59 (2.950) 90 (4.500)
370.637 85 (2.297) 110 (2.973) 169 (4.568)
500.636 114 (2.280) 149 (2.980) 228 (4.560)
1000.634 230 (2.300) 299 (2.990) 459 (4.590)
5000.6321151 (2.302)1497 (2.994)2301 (4.602)
10000.6322302 (2.302)2995 (2.995)4603 (4.603)

One can use this table to find out how many times one needs to play the roulette in a casino to have 95% chance of winning at least once: a european roulette has 37 numbers (k = 37), and the limit of the n/k ratio is about 3; one therefore needs to play about n ≅ 37 × 3 = 111 times (the row for k = 37 indicates the actual value is n = 110).

[ Posted on April 26th, 2014 at 15:40 | no comment | ]

## Thursday, February 6th, 2014

### Changing GRUB from EFI to BIOS

Categories: [ IT ]

My new computer has a UEFI firmware. I installed Debian Wheezy, which in turn installed the EFI variant of GRUB. For that purpose, the Debian installer made the first partition on the hard disk drive of type VFAT and mounted in `/boot/efi`.

My problem is that GRUB tends to freeze, either just before booting the kernel (showing forever “Loading initial ramdisk”) or just after the welcome message (“Welcome to Grub!”). Pressing the computer's reset button allowed to reboot the computer, and everying went then fine. It seems to be possible to reproduce the bug at will by switching off the power supply, waiting 15 seconds for the capacitors to get empty and then reboot the computer. Booting however also hangs quite often after powering the computer off in software (where the power supply still provides some power to the motherboard).

I read here and there that EFI GRUB was quite buggy, so I decided to switch to PC GRUB (the variant for booting with the Legacy firmware, aka BIOS).

In a first attempt, I configured the motherboard's firmware to use “Legacy ROM only” instead of “UEFI only”. Debian continued to boot normally with the still installed EFI GRUB, and the freeze when rebooting after having switched off the power supply seemed to have disappeared. It howerver froze again today and so I decided to change from EFI GRUB to BIOS GRUB.

I first ran `apt-get install grub-pc`, which complained that
```/usr/sbin/grub-setup: warn: This GPT partition label has no BIOS Boot
Partition; embedding won't be possible!.
/usr/sbin/grub-setup: warn: Embedding is not possible.
GRUB can only be installed in this setup by using blocklists.
However, blocklists are UNRELIABLE and their use is discouraged..
```

After a bit of research on the Web, I found someone's advice to change the flag of the FAT partition to `bios_grub`. I then forced the reinstallation of `grub-pc` with ```apt-get install --reinstall grub-pc```, which didn't complain anymore.

On the next reboot however, the startup script indicated that “fsck died with status 6”. I found out that it tried to check the VFAT partition, but since GRUB is now installed there, it is not anymore recognized as a VFAT partition, and fsck was legitimately skipping it. `parted` confirmed that fact, and `blkid` does not list the VFAT partition anymore either. I therefore commented it out in `/etc/fstab` and now the boot does not fail anymore.

[ Posted on February 6th, 2014 at 19:23 | no comment | ]

## Saturday, December 7th, 2013

### The Value of Money in Dodger

Categories: [ Science ]

Terry Pratchett's Dodger is said to take place in the first quarter of the Victorian Era. We'll assume it is the year 1840. According to the National Archive's currency converter, 1 £ in 1840 is worth about 45 GBP in 2005.

Moreover, the same source indicates that with 100 GBP (about 2£ 5s) you could buy 11 days work of a craftsman wages in the building trade, 3 stones (42 lbs) of wool or 1 quarter (28 lbs) of wheat. As a reference, a person's daily needs in energy are equivalent to about 2 lbs of wheat (representing 2950 kcal according to Wikipedia).

These are the coins mentionned in Dodger:

• Guinea: 21s = 252d (47.25 GBP)
• Sovereign: 1 £ = 20s = 240d (45 GBP)
• Crown: 5s = 60d (11.25 GBP)
• Half-Crown: 2.5s = 30d (5.63 GBP) (about 1.5 lbs of wheat)
• Shilling: 1s = 12d (2.25 GBP)
• Sixpence: 1/2s = 6d (1.13 GBP)
• Groat: 4d (0.75 GBP)
• Thruppence: 3d (0.56 GBP)
• Penny: 1d (0.19 GBP)
• Half-penny: 1/2d (0.10 GBP)
• Farthing: 1/4d (0.05 GBP)

A day worth of a craftman's wages is therfore 4s, which could buy 2.5 lbs of wheat or 4 lbs of wool.

[ Posted on December 7th, 2013 at 18:06 | no comment | ]

## Sunday, September 15th, 2013

### Instantiating Many Objects in Python

Categories: [ IT ]

I have a list of files in a text file, and I want to load this list into some kind of data structure. The list is quite long, and requires to instantiate 100,000 objects in Python, all of the same type. I found out that depending on what kind of object is used, the time it takes to instantiate all these can vary greatly. Essentially, each line of the file is composed of tab-separated fields, which are split into a list with Python's `str.split()` method. The question therefore is: what should I do with that list?

The object must hold a few values, so basically a list or a tuple would be enough. However, I need to perform various operations on those values, so additional methods would be handy and justify the use of a more complex object.

#### The Contenders

These are the objects I compared:

A simple `list`, as returned by `str.split()`. It is not very handy, but will serve as a reference.

A simple `tuple`, no more handy than the `list`, but it may exhibit better performance (or not).

A class named `List` that inherits from `list`:
```class List(list):
def a(self): return self[0]
def b(self): return self[1]
def c(self): return self[2]
```
A class named `Tuple` that inherits from `tuple`:
```class Tuple(tuple):
def a(self): return self[0]
def b(self): return self[1]
def c(self): return self[2]
```
A class named `ListCustomInitList` that inherits from `List` and adds a custom `__init__()` method:
```class ListCustomInitList(List):
def __init__(self, *args): List.__init__(self, args)
```
A class named `TupleCustomInitTuple` that inherits from `Tuple` and adds a custom `__init__()` method:
```class TupleCustomInitTuple(Tuple):
def __init__(self, *args): Tuple.__init__(self)
```
A class named `ListCustomInit` that inherits from the `list` basic type but has the same features as `ListCustomInitList` instead of inheriting them from the custom `List`:
```class ListCustomInit(list):
def __init__(self, *args): list.__init__(self, args)
def a(self): return self[0]
def b(self): return self[1]
def c(self): return self[2]
```
A class named `TupleCustomInit` that inherits from `tuple` basic type but has the same features as `TupleCustomInitTuple` instead of inheriting them from the custom `Tuple`:
```class TupleCustomInit(tuple):
def __init__(self, *args): tuple.__init__(self)
def a(self): return self[0]
def b(self): return self[1]
def c(self): return self[2]
```
A class named `NamedTuple` that is made from the `namedtuple` type in the `collections` module:
```NamedTuple = namedtuple("NamedTuple", ("a", "b", "c"))
```
A very basic class named `Class` and that inherits from `object`:
```class Class(object):
def __init__(self, args):
self.a = args[0]
self.b = args[1]
self.c = args[2]
```
A variant of the previous that uses the `__slots__` feature:
```class Slots(object):
__slots__ = ("a", "b", "c")
def __init__(self, args):
self.a = args[0]
self.b = args[1]
self.c = args[2]
```
A old-style class, named `OldClass`, that does not inherit from `object`:
```class OldClass:
def __init__(self, args):
self.a = args[0]
self.b = args[1]
self.c = args[2]
```

#### The Benchmark

Each class is instantiated 100,000 times in a loop, with the same, constant input data: `["a", "b", "c"]`; the newly created object is then appended to a list. This process it timed by calling `time.clock()` before and after it and retaining the difference between the two values. The `time.clock()` method has quite a poor resolution, but is immune to the process being set to sleep by the operating systems's scheduler.

This is then repeated 10 times, and the smallest of these 10 values is retained as the performance of the process.

#### The Results

The results from the benchmark are shown relatively the speed of using a simple `list`. As expected, the use of a simple `list` is the fastest, since it requires not additional object instantiation. Below are the results:

• 1.000 list
• 2.455 tuple
• 3.273 Tuple
• 3.455 List
• 4.636 Slots
• 5.818 NamedTuple
• 6.364 OldClass
• 6.455 Class
• 6.909 TupleCustomInit
• 7.091 TupleCustomInitTuple
• 7.545 ListCustomInit
• 7.818 ListCustomInitList

#### Conclusion

One can draw several conclusions from this experiment:

• Not instantiating anything is much faster, even instantiating a simple tuple out of the original list increases the run time by 150%
• The slots feature makes object instantiation 28% faster compared to a regular class
• Deriving a class from a basic type and adding a custom `__init__()` method that calls the parent's `__init__()` adds a lot of overhead (instantiation is 7 to 8 times slower)

[ Posted on September 15th, 2013 at 15:13 | no comment | ]

## Thursday, March 21st, 2013

Categories: [ IT ]

Passwords are difficult to generate and to remember, and once you finally know how to type yours quicky, you don't want to change it. That's usually the time when someone is forcing you to change it… Here is a synthesis of what I've found out about how to generate secure passwords.

#### Entropy as a measure of password strengh

The strength of a password is usually expressed as its entropy, measured in bits. In a nutshell, it expresses the total number of different passwords that can be created (given some construction rules), represented as the base 2 logarithm of that total number. For example, if you know that a password is composed of a single character which may be a letter (uppercase or lowercase), a digit, a white space or a period (which conveniently makes 64 different symbols: 26 lower case letters, plus 26 uppercase letters plus 10 digits plus 2 punctuation symbols), the entropy of that password is 6 bits (because 26 = 64). Non-integer entropy values are valid, so for example a single lowercase letter has an entropy of approximately 4.7 (because 24.7 ≈ 26). The addition of one bit of entropy multiplies the total number of different possible passwords by 2; a password made of 2 characters (64 symbols: upper/lowercase letters, digits and 2 punctuation signs) has therefore an entropy of 12 bits and a password made of 8 lowercase letters has an entropy of 37.6 bits.

#### The human factor

The above entropy measurement is true only if the password is truly randomly generated, and that each symbol has an equal probability of being selected. Humans seem to be rather bad at generating random passwords, and in Special Publication 800-63, the entropy of a human-generated password of length 8 is estimated to have an entropy of 18 bits.

Moreover, if the password is a word from a natural language, the number of possible different passwords is equal to the size of the vocabulary in that language; for English language this is estimated to be between 250,000 words. The entropy of a password made of a single English word is therefore approximately 17.9 bits.

#### Forcing more entropy

To increase the entropy of human-generated passwords, it is quite common to enforce rules, such as a minimum length, the use of more symbols than just the 26 lowercase letters and forbidding the use of common words. The NIST report above estimates that the additional symbols add 6 bits of entropy and the dictionary check adds 5 bits. An 8 character password following all the rules above is therefore estimated to have an entropy of 30 bits. For comparison, a randonly-generated password of 8 character chosen amongst the most common symbols on a computer keyword (80 symbols) has an entropy of 50.6 bits

Such password become however difficult to remember, especially if you have to memorize several of them and are forced to change them every few months.

And they are still pretty insecure.

There are two different methods for cracking a password.

The first method consists in connecting to the service asking for the password, and trying passwords until the right one is found. This method is slow, one can expect to test at most a few dozen of passwords per second (let's say 100 passwords per second). Using the entropy to measure the strength of the attack, that represents 6.6 bits per second, or 23.0 bits/day, or 27.9 bits/month, or 31.5 bits/year.

This gives the following times:

• 18 bits password: at most 45 minutes
• 30 bits password: at most 128 days
• 50.6 bits password: at most 560,000 years

The thing here is that reasonnably secure services will not allow that many trials.

The second method for cracking passwords requires a list of encrypted passwords e.g., stolen from a badly secured service. Depending on the encryption algorithm used with those passwords and the hardware at hand, one can expect an attacker to try between 2,000 and 15,500,000,000 passwords per second (between 11 and 33.8 bits/s) with a standard desktop computer (equipped with a modern GPU).

This gives the following times:

• 18 bits password: at best 128 seconds, at worst a few microseconds
• 30 bits password: at best 6 days, at worst less than a second
• 50.6 bits password: at best 274 years, at worst 32 hours.

#### How many bits are needed?

The times indicated above represent the maximum time needed for cracking the password. There is a 50% chance of cracking it in half that time, and a 10% chance of cracking it in a tenth of that time.

So if a password needs to be safe for at least 1 year, the time needed for cracking it needs to be at least a year i.e., 33.8 + 24.9 = 58.7 bits (entropy of the number of passwords tested per second plus the “entropy” of the number of seconds per year). There is however a chance that the password will be cracked in less time. Adding 1 bit of entropy will reduce the attacker's chance of finding the password in a given time by half, and adding 10 bits reduces it to 1 chance out of 1024 to crack it in that time. 7 bits would reduce it to 1 chance out of 128, which may be sufficient as well.

#### How to generate such a password?

A 68.7 bits password means 15 lowercase letters, or 11 common-keyboard-symbols. These have to be selected by a true random process, such as dice rolls, nuclear desintegration or electronic thermal noise. 6-sided dice are easy to come by, and the Diceware method is probably the easiest one for generating secure and easy-to-remember passwords. A rolls of 5 dice allows to select one word in a list of 7,776, providing 12.9 bits of entropy. The strenght of the password therefore depends on the number of words that are selected (by repeatedly rolling 5 dice):

• 1 word: 12.9 bits, cracked in less than a microsecond
• 2 words: 25.8 bits, cracked in less than 4 milliseconds
• 3 words: 38.3 bits, cracked in less than 30 seconds
• 4 words: 51.6 bits, cracked in less than 2 days
• 5 words: 64.5 bits, cracked in less than 55 years
• 6 words: 77.4 bits, cracked in less than 423,000 years
• 7 words: 90.3 bits, cracked in less than 3231 million years

The Diceware method also allows to add a random non-letter symbol to the password, adding about 9.5 bits of entropy for a 20 character password (about 5 words). Therefore a 5-word password with one random symbol can be considered secure for at least a few years.

#### How long will the password be safe?

Between 2002 and 2011, CPU and GPU computing power has been multiplied by 10 and 100 respectively i.e., +0.37 and +0.74 bits/year regarding password cracking. The rate of growth will probably not remain that high, but if one wants to keep a password for more than a year or two, it should be taken into consideration. For example, if a password must remain safe for the 4 next years, add 3 bits. The 5-word password with one random symbol will therefore be safe for the next 7 years.

One must also consider that computer clusters become affordable, and that a 25-GPU computer has been built exactly for the purpose of cracking passwords. This type of machine adds about 4 bits to capacity of cracking encrypted password (the “second method” above). That makes the 5-word diceware passphrase safe for barely over a year. Finally, cloud computing and parasitic computing using cloud-based browsers may reduce the safety period even further.

#### Conlcusion

The only truly secure passwords are long and truly random; any other method for generating passwords will lead to easily crackable passwords, and is therefore giving a false sense of security. Long enough passwords need to be changed, but not too often; 3 years is a reasonnable lifetime. The Diceware method allows to generate such password in a simple way.

Finally, memorizing a lot of passwords is difficult and induces people to reuse the same passwords. There is a simple solution to that, promoted by Bruce Schneier: write down your password and keep it in your wallet.

[ Posted on March 21st, 2013 at 22:50 | no comment | ]

## Tuesday, March 5th, 2013

### Seven Segment Display

Categories: [ Science ]

I recently discussed with a friend how to read with a computer the 3-digit numbers from a device using seven-segment displays. One solution we came up with was to put a phototransistor in front of each segment, read the seven on/off signals and recognize the digits. I then wondered if it's possible to use less than seven phototransistors per digit.

A minimum of four segments is obviously required, but after a bit of computer-aided experimentation, I found out that only 5 segments are enough: if you remove the lower and the lower-right segments, you can still identify all ten digits.

So with only 15 inputs instead of 21, you can read the 3 digits, using a 16 bit I/O expander (e.g., a MCP23017; this one even has internal 100 kΩ pull-up resistors, so it may be that nothing else than the phototransistors is needed).

[ Posted on March 5th, 2013 at 22:19 | no comment | ]

## Tuesday, February 19th, 2013

### Machine Inutile

Translation: [ Google | Babelfish ]

Categories: [ DIY ]

Quand on bascule l'interrupteur, un doigt sort de la boite et le rebascule dans l'autre sens. Strictement inutile, et donc parfaitement indispensable.

Vue de l'extérieur, c'est une boite en bois blanc, sans fioriture, à part l'interrupteur sur le couvercle.

Quand on pousse l'interrupteur, voici ce qui se passe:

La vidéo de la boite en action est également disponible.

Sous le capot, un moteur équipé d'une boite de vitesse 1:228, alimenté par 4 batteries rechargeables. Lorsqu'on bascule l'interrupteur, le « doigt » se lève, bascule l'interrupteur dans l'autre sens, ce qui renverse la la polarité et fait tourner le moteur dans le sens inverse. Le « doigt » revient alors à sa position initiale et finit sa course sur un deuxième interrupteur, qui coupe le courant. Le moteur s'arrête.

Mécaniquement et électriquement, il n'y a rien de compliqué, à part le fait de positionner les pièces au bon endroit.

Pour finir, une vidéo de la machine en action couvercle levé. On remarque que le « doigt » sursaute en arrivant sur l'interrupteur, au moment où le courant se coupe, et revient s'y poser une deuxième fois plus doucement, et reste en place.

[ Posted on February 19th, 2013 at 21:51 | no comment | ]

## Monday, December 10th, 2012

### Ugly Ruby

Categories: [ IT ]

A few months ago, I started to use ruby for work. Twice I burnt my fingers on the following behaviour in Ruby:

```def foo
"bar"
end

puts "foo = #{foo.inspect}"

if foo.nil?
foo = "quux"
puts "Not coming here"
end

puts "foo = #{foo.inspect}"
```
The method foo returns the string `"bar"`, which is therefore not `nil`. The result any sane coder expects would be
```foo = "bar"
foo = "bar"
```
What actually comes out when you run this snippet is
```foo = "bar"
foo = nil
```

I remember reading that in order to decide whether `foo` is a call to the foo method or the use of the local variable foo, Ruby checks the code before for any assignment to foo. As it happens, the local variable foo gets assigned inside the if clause, but the statement is never executed. My guess is that Ruby then decides that the local variable foo is put to use after the if clause, but is never actually assigned to, and therefore its value is `nil`. As it happens, the foo method still exists and returns `"bar"`, as expected, when called as `foo()`.

[ Posted on December 10th, 2012 at 22:30 | no comment | ]

## Saturday, June 16th, 2012

### Faut-il courir sous la pluie ?

Translation: [ Google | Babelfish ]

Categories: [ Science ]

Est-on moins mouillé si on court sous la pluie au lieu de marcher ? En modélisant un piéton comme un parallélépipède rectangle de hauteur h et d'épaisseur l, et en notant vm la vitesse du piéton et vp la vitesse de chute de la pluie, on obtient une vitesse v de la pluie relativement au piéton. Le vecteur vitesse fait un angle a avec la verticale. On peut alors calculer que la projection de la surface frontale du piéton dans la direction de ce vecteur est Sh, et la projection correspondant à la surface supérieur est Sl. Le produit de ces surfaces avec la vitesse de la pluie donne le débit d'eau, et si on multiple par le temps mis pour parcourir un trajet d'une longueur donnée d sous la pluie, on obtient le volume d'eau qui s'est déversé sur le piéton. Le détails des calculs est laissé en exercice au lecteur, mais le résultat est V = d(h + l vp / vm).

En conséquence, pour minimiser le volume d'eau V, il faut maximiser que vm / vp >> l / h. Si on considère un piéton de 1,80 m de hauteur et 0,3 m d'épaisseur, il faut que la vitesse du piéton soit plus grande que 1/6 vp. Diverses sources sur le Web ont indiqué que la vitesse de la pluie en arrivant près du sol est d'environ 9 m/s, il faut donc que le piéton se déplace à plus de 1,5 m/s, soit 5,4 km/h.

[ Posted on June 16th, 2012 at 18:35 | no comment | ]

## Tuesday, May 15th, 2012

### E-mail Git Patches

Categories: [ IT/Git ]

This is, in a nutshell, how to send commits to the (single) maintainer of a project by e-mail.

`git config --set sendemail.to "John Smith <john.smith@example.com>"`
Make a set of patches from the commits e.g.,
`git format-patch HEADˆ`
or
`git format-patch origin/master..master`

Send the patches by e-mail:

`git send-email *.patch`
(this sends one e-mail per patch).

On the receiving side, the maintainer can then feed the content of each e-mail into `git am` to apply the patches and record new commits.

The `git send-email` command is packaged separately in Debian, the package `git-email` needs to be installed.

[ Posted on May 15th, 2012 at 19:47 | no comment | ]

## Monday, May 14th, 2012

### More Git Recipes

Categories: [ IT/Git ]

Resolve a binary file conflict with Git

Found on lostechies.com

In case of conflict with a binary file during a merge, you have two choices for resolving it:

`git add thefile`
• Use the other version:
`git checkout --theirs -- thefile; git add thefile`

Then commit the changes.

Show the content of a deleted file

Found on stackoverflow.com

`git show commitid:path/to/file`

The trick here is that one must use the full path to the file (relatively to the repository's root)

Restore a deleted file in a Git repo

Found on stackoverflow.com

Find the last commit where the file was deleted:
`git rev-list -n 1 HEAD -- thefile`
Then checkout the file from the commit before that:
`git checkout commitid -- thefile`

[ Posted on May 14th, 2012 at 13:39 | no comment | ]

## Wednesday, May 9th, 2012

### Super Mario Dice

Translation: [ Google | Babelfish ]

Categories: [ Games ]

Je me suis récemment intéressé aux jeux de dés, et j'ai découvert Zombie Dice. Le principe est très simple, le jeu est rapide, mais le thème ne me plaisait pas. Alors j'ai décidé de changer le thème en Super Mario. J'avais d'abord songé au Super Mario Bros. original tournant sur NES, mais je trouvais les graphismes de la réédition pour SNES (Super Mario All Stars) nettement plus beaux, et donc j'ai repris les graphiques de cette version là.

Les dés viennent de blankdice.co.uk, chez qui j'ai déjà acheté un certain nombre de dés. Les faces ont un léger creux, qui permettent de coller un autocollant carré de 14,5 mm de coté. J'ai imprimé sur un autocollant au format A4 et découpé les carrés avec un cutter rotatif sans trop appuyer, ce qui permet de couper l'autocollant sans couper le papier-support et donc de décoller les petits autocollants bien plus facilement.

Zombie Dice est vendu sous blister et ne comprend qu'un gros gobelet et 13 dés. Il nécessite quelque chose pour marquer le score (papier/crayon, jetons…) J'ai donc fabriqué une piste pliante de 13 cases plus une case départ, encore une fois en imprimant sur un autocollant A4. À la place du gobelet, je vais fabriquer un sac en tissu, assez grand pour contenir tous les composants (il reste à trouver le tissu).

Une amie m'a proposé de fabriquer des pions en forme de personnages de Super Mario en échange de quoi je lui fabrique quelques copies du jeu. On verra ce que ça donne.

[ Posted on May 9th, 2012 at 18:28 | 3 comments | ]