Chimrod//blog.chimrod.com/2023-04-06T00:00:00+02:00Des glyphes <span class="amp">&</span> du codeÀ tous ceux qui écrivent des scripts dans leur coin2023-04-06T00:00:00+02:002023-04-06T00:00:00+02:00Chimrodtag:blog.chimrod.com,2023-04-06:/2023/04/a-tous-ceux-qui-ecrivent-des-scripts-dans-leur-coin/<p>Un collègue m’a annoncé qu’il avait écrit un petit script python pour se
faciliter la vie sur une tâche assez complexe à faire manuellement, mais qui
peut être automatisée facilement.</p>
<p>C’est très bien, beaucoup sont passés par là avant de se lancer dans des sujets
plus complexes, et c’est toujours en pratiquant que l’on apprend. Moi aussi,
j’ai commencé à me faciliter la vie au travail, en prenant le temps de coder
quelque-chose qui a fini par me faire gagner du temps à force de l’utiliser.
Avec le recul, je voudrais juste faire …</p><p>Un collègue m’a annoncé qu’il avait écrit un petit script python pour se
faciliter la vie sur une tâche assez complexe à faire manuellement, mais qui
peut être automatisée facilement.</p>
<p>C’est très bien, beaucoup sont passés par là avant de se lancer dans des sujets
plus complexes, et c’est toujours en pratiquant que l’on apprend. Moi aussi,
j’ai commencé à me faciliter la vie au travail, en prenant le temps de coder
quelque-chose qui a fini par me faire gagner du temps à force de l’utiliser.
Avec le recul, je voudrais juste faire cet article sur une règle que je
m’impose aujourd’hui systématiquement dès que je commence ce genre de script<span style="white-space:nowrap"> </span>:</p>
<div class="admonition admonition-regle-dor">
<p class="first admonition-title">Règle d’or</p>
<p class="last">Toujours écrire un fichier de configuration.</p>
</div>
<p>Je ne vais pas rentrer dans des consignes de codage, de documentation ou de
couverture de test. Laissons ça aux développeurs pros qui passent leurs journées
à ça, et doivent s’organiser pour travailler ensemble de manière efficace. Non,
je parle d’autre chose<span style="white-space:nowrap"> </span>: le fichier de configuration est ce qui permet de
transformer un <em>script bidouillé dans son coin</em> en une application prévue pour
durer. En séparant le code de sa logique d’utilisation, on entre dans une
logique complètement différente, et c’est ce que je vais détailler ici.</p>
<p>Déjà pendant la phase de test de notre script, nous avons besoin de tester
notre script avec un premier fichier, puis un autre. Si cela est mis <em>en dur
dans le code</em> il est nécessaire de recompiler le code à chaque fois, ce qui
nous empêche de se concentrer sur l’essentiel<span style="white-space:nowrap"> </span>: le résultat que l’on veut obtenir.</p>
<div class="section" id="parametrer-son-script">
<h2>Paramétrer son script</h2>
<p>Une première solution est de passer les options au programme au lancement.
C’est rapide à faire, les librairies pour gérer les arguments sont disponibles
dans tous les langages. Par contre, cela change entièrement l’esprit du
programme. Au lieu d’avoir</p>
<pre class="code bash literal-block">
$<span class="w"> </span>mon_script.py
</pre>
<p>on obtient<span style="white-space:nowrap"> </span>:</p>
<pre class="code bash literal-block">
$<span class="w"> </span>mon_script.py<span class="w"> </span>fichier.txt<span class="w"> </span>--limit<span class="w"> </span><span class="m">42</span><span class="w"> </span>--keep<span class="w"> </span>even
</pre>
<p>Déjà, nous <em>rendons visible</em> ce qui est pertinent pour notre application. Nous
nommons les paramètres (éventuellement gérons des options par défaut), et nous
offrons un avenir à notre application. Au lieu de rester cantonnée dans l’usage
qui lui a été destinée initialement, elle s’ouvre à l’infinie combinaison des
options possibles.</p>
<p>Dans le code, cela oblige à se poser des questions<span style="white-space:nowrap"> </span>: ce comportement doit-il
être rendu paramétrable ou cela fait-il partie du fonctionnement de base<span style="white-space:nowrap"> </span>? Cette
option doit-elle être obligatoire<span style="white-space:nowrap"> </span>? Comment nommer ces paramètres<span style="white-space:nowrap"> </span>? J’ai dit que
je n’aborderai pas l’organisation du code, mais la source des problèmes est là
: si l’ajout d’une nouvelle option impose de tout réécrire, alors votre script
est mal pensé. Il n’est pas maintenable, et le temps passé dessus sera perdu.</p>
<p>Ici, l’application peut être partagée<span style="white-space:nowrap"> </span>: nous l’ouvrons à d’autres usages, ou
bien pour notre moi-futur, ou bien pour des collègues qui ont des besoins différents.</p>
</div>
<div class="section" id="configurer-son-application">
<h2>Configurer son application</h2>
<p>Mais au bout d’un moment, cela n’est pas suffisant. Pour reproduire le même
résultat à l’identique, il faut pouvoir retrouver les mêmes paramètres que ceux
utilisés alors. L’historique du shell peut aider, mais si les paramètres sont
trop nombreux, il devient fastidieux d’aller corriger l’option et relancer le
traitement. D’où ma règle d’or édictée plus haut<span style="white-space:nowrap"> </span>:</p>
<blockquote>
Toujours écrire un fichier de configuration.</blockquote>
<p>Dans un fichier <a class="reference external" href="https://fr.wikipedia.org/wiki/Fichier_INI">ini</a>, <a class="reference external" href="https://fr.wikipedia.org/wiki/JavaScript_Object_Notation">json</a> ou <a class="reference external" href="https://fr.wikipedia.org/wiki/toml_">toml</a>, peu importe. Mais dans un fichier à
part. Et donner ce fichier en argument au programme. Cela pousse à aller plus
loin que les arguments, mais offre une souplesse beaucoup plus importante<span style="white-space:nowrap"> </span>:
nous pouvons cette fois versionner la configuration d’un traitement
particulier, nous pouvons modifier notre configuration avec un bloc-note, et
ajouter des commentaires pour expliquer ce que l’on fait. Voire commenter
certaines options le temps de trouver le paramétrage idéal qui nous convient.</p>
<p>La configuration peut rester technique, comme dans cet exemple qui me permet de
définir comment représenter graphiquement des données, mais l’idée est de
pouvoir modifier directement ce fichier plutôt que notre code.</p>
<pre class="code json literal-block">
<span class="p">{</span><span class="w">
</span><span class="nt">"level_0"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="nt">"shape"</span><span class="p">:</span><span class="w"> </span><span class="s2">"circle"</span><span class="p">,</span><span class="w">
</span><span class="nt">"fontsize"</span><span class="p">:</span><span class="mi">36</span><span class="p">,</span><span class="w">
</span><span class="nt">"colorScheme"</span><span class="p">:[</span><span class="s2">"accent8"</span><span class="p">,</span><span class="w"> </span><span class="mi">8</span><span class="p">],</span><span class="w">
</span><span class="nt">"color"</span><span class="p">:</span><span class="s2">"lightgreen"</span><span class="p">,</span><span class="w">
</span><span class="nt">"rank"</span><span class="p">:</span><span class="mi">7</span><span class="w">
</span><span class="p">},</span><span class="w">
</span><span class="nt">"level_1"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="nt">"shape"</span><span class="p">:</span><span class="w"> </span><span class="s2">"box"</span><span class="p">,</span><span class="w">
</span><span class="nt">"fontsize"</span><span class="p">:</span><span class="mi">14</span><span class="p">,</span><span class="w">
</span><span class="nt">"colorScheme"</span><span class="p">:[</span><span class="s2">"set28"</span><span class="w"> </span><span class="p">,</span><span class="w"> </span><span class="mi">8</span><span class="p">],</span><span class="w">
</span><span class="nt">"rank"</span><span class="p">:</span><span class="mi">10</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="p">}</span>
</pre>
<p>L’autre avantage est de pouvoir <em>versionner</em> notre fichier de configuration. En
garder une copie qui nous savons fonctionner, et une version de travail sur
laquelle nous faisons nos tests et que l’on peut casser à tout moment.</p>
<p>Ce n’est plus un script que nous avons fait pour répondre à un besoin
particulier que nous avons entre les mains, nous avons créé un processus, qui
peut être repris par d’autres que nous. Cette fois, nous avons définitivement
fait sortir notre petit script qui avait codé dans un coin. C’est une
application que nous avons écrite.</p>
</div>
Une aide de jeu pour Wordle / Sutom2022-02-01T00:00:00+01:002022-02-01T00:00:00+01:00Chimrodtag:blog.chimrod.com,2022-02-01:/2022/02/une-aide-de-jeu-pour-wordle-sutom/<p class="first">Les jeux de lettres sont un bon moyen d’occuper ses méninges. On peut aussi
se poser la question de savoir comment optimiser les réponses, et prendre le
temps de s’aider de l’informatique pour gagner à tous les coups !</p>
<p class="last">Je suis parti du jeu Wordle, pour écrire une application autonome qui va
chercher à proposer à chaque coup le mot le plus intéressant.</p>
<p>J’ai entendu parler du jeu <a class="reference external" href="https://www.powerlanguage.co.uk/wordle/">Wordle</a> récemment, dans un <a class="reference external" href="https://www.francetvinfo.fr/replay-radio/l-etoile-du-jour/wordle-le-jeu-inspire-de-motus-qui-cartonne-sur-internet-au-grand-dam-de-son-createur_4898487.html">article</a> qui abordait le
phénomène. Le jeu, consiste à deviner un mot, à l’aide d’indices sur le
placement des lettres. J’ai depuis découvert qu’une version française existe
également<span style="white-space:nowrap"> </span>: <a class="reference external" href="https://sutom.nocle.fr/">sutom</a>, et je vais continuer l’article sur la base des mots français.</p>
<p>Comme nous avons un nombre de coups limités, il nous faut trouver des
propositions qui nous donnent le plus d’informations sur les coups suivants. On
est d’accord pour dire que <em>yoyos</em> n’est pas le meilleur coup à jouer<span style="white-space:nowrap"> </span>: déjà il
ne contient que trois lettres différentes, c’est pas top, en plus, il y a de
forte chance que le <em>y</em> soit déclaré comme absent, ce qui ne nous donne pas
beaucoup d’information pour la suite.</p>
<p>Mais si l’on est capable de déterminer qu’un mot n’est pas le plus pertinent,
est-ce qu’il est possible de trouver le meilleur mot possible<span style="white-space:nowrap"> </span>? Celui qui nous
donne le maximum d’information<span style="white-space:nowrap"> </span>?</p>
<p>Si l’on regarde la distribution des lettres parmi les mots de cinq lettres, on
se rend compte que certaines lettres sont à privilégier parmi d’autres<span style="white-space:nowrap"> </span>:</p>
<object class="align-center" data="//blog.chimrod.com/images/motus/french_5.svg" type="image/svg+xml">Distribution des lettres dans les mots de 5 lettres</object>
<p>Partant du principe que l’on ne connait pas le mot à trouver, si l’on choisit
un mot contenant un <cite>A</cite> lors de notre première proposition, <em>quel que soit le
résultat</em>, valide ou non, on élimine d’emblée la moitié des mots possibles. Dans
l’ordre, les lettres les plus intéressantes pour proposer un premier mot sont
les suivantes<span style="white-space:nowrap"> </span>: { a, e, s, i, r }. Nous pouvons donc proposer <em>siéra</em>, <em>serai</em>
ou <a class="reference external" href="https://fr.wiktionary.org/wiki/raise">raise</a>.</p>
<object class="align-center" data="//blog.chimrod.com/images/motus/decision.gv.svg" style="width: 75%;" type="image/svg+xml">Distribution des lettres dans les mots de 5 lettres</object>
<p>En prenant seulement trois lettres (sur les cinq de la proposition), on se rend
compte que même dans le pire des cas, on divise le nombre de mots par 5, en
passant de 7470 mots à 1398<span style="white-space:nowrap"> </span>! À chaque proposition, nous réduisons les mots
possibles et la seconde proposition sera déjà plus précise. Comme la
distribution des lettres va changer, nous allons pouvoir présenter une nouvelle
proposition qui va de nouveau diviser le nombre de mots restants, et ainsi de
suite jusqu’à arriver à une proposition unique<span style="white-space:nowrap"> </span>: le résultat.</p>
<div class="admonition note">
<p class="first admonition-title">Note</p>
<p class="last">J’ai utilisé ici les lettres qui identifiées au moment de la répartition
générale sur l’ensemble des mots. Si l’on refait le calcul à chaque branche
de l’arbre ci-dessus, nous allons obtenir une répartition finale plus
équilibrée (mais qui nécessite un recalcul des fréquences à chaque fois).</p>
</div>
<p>S’il est possible de préparer des tables (ou de les apprendre<span style="white-space:nowrap"> </span>!), il est plus
efficace de laisser l’ordinateur calculer de lui-même quelle est la fréquence
de chaque lettre, et donc de nous proposer le mot à chaque coup.</p>
<p>Si l’on comprend intuitivement comment choisir chaque lettre, on peut aller
plus loin en cherchant comment calculer le mot contenant le plus d’information.
C’est <a class="reference external" href="https://fr.wikipedia.org/wiki/Claude_Shannon">Claude Shannon</a> qui a posé les bases de cette approche mathématique, et
ses calculs sont encore utilisés aujourd’hui (par exemple pour identifier si <a class="reference external" href="https://fr.wikipedia.org/wiki/Robustesse_d%27un_mot_de_passe">un
mot de passe est faible ou non</a>). Je n’irai pas ici dans le détail du calcul
du <a class="reference external" href="https://fr.wikipedia.org/wiki/Entropie_de_Shannon">gain d’entropie</a>, l’idée étant d’expliquer le mécanisme de manière simple.</p>
<p>J’ai mis en place une <a class="reference external" href="//blog.chimrod.com/pages/motus/">application en ligne</a> qui fait ces calculs et permet
de trouver le mot en quelques coups (parfois en deux coups<span style="white-space:nowrap"> </span>!), exemple avec
une partie de <a class="reference external" href="https://sutom.nocle.fr/">sutom</a> :</p>
<div class="center line-block">
<div class="line">🟥🟦🟦🟡🟡🟡🟦</div>
<div class="line">🟥🟥🟥🟥🟥🟥🟥</div>
</div>
<p>Il n’y a pas de mécanisme d’apprentissage dans cette application, tout est
statistiquement explicable et entièrement reproductible, pour autant le
principe des <cite>arbres de décision</cite> est à la limite de l’intelligence
artificielle de part l’aide qu’il apporte à l’analyse. On le voit ici, que ce
soit en termes de temps de traitement, ou en nombre de propositions<span style="white-space:nowrap"> </span>: il ne
s’agit pas seulement d’évaluer toute une liste de propositions rapidement, mais
également d’aiguiller la décision le plus rapidement possible.</p>
<p>Si vous souhaitez quelque chose de plus <em>manuel</em> cet article vous expliquera
<a class="reference external" href="https://opensource.com/article/22/1/word-game-linux-command-line">comment jouer avec un terminal et grep</a> !</p>
Découverte de buildroot avec un raspberrypi2021-11-15T00:00:00+01:002021-11-15T00:00:00+01:00Chimrodtag:blog.chimrod.com,2021-11-15:/2021/11/decouverte-de-buildroot-avec-un-raspberrypi/<p class="first last">Comment construire un système complet pour un raspberry pi avec
Buildroot ? Présentation détaillée d’un projet permettant de
construire un serveur de son.</p>
<div class="section" id="presentation">
<h2>Présentation</h2>
<p>Il y a quelque temps, j’avais monté un système audio avec un raspberrypi pi 0,
permettant de brancher la carte à ma chaine hifi et diffuser ainsi la musique
dans le salon. En équipant la carte d’un <span class="caps">DAC</span> de qualité, je centralise la
musique qui peut etre jouée depuis n’importe quel <span class="caps">PC</span>, et comme la carte est
équipée d’une connexion bluetooth, cela permet aussi d’y connecter les smartphones.</p>
<p>Dans mon <a class="reference external" href="https://linuxfr.org/users/chimrod/journaux/utiliser-un-pi-zero-comme-serveur-de-son-et-lecteur-bluetooth">montage originel</a>, je partais d’une distribution raspbian que
j’avais modifié manuellement. À la suite d’une erreur de manipulation, j’ai dû
refaire le paramétrage une seconde fois, et c’est depuis quelque chose qui me
préoccupait<span style="white-space:nowrap"> </span>: il faudrait que je puisse disposer d’un système déjà configuré
qui fonctionnerait « out of the box », sans que j’aie à toucher à la configuration.</p>
<p>J’ai découvert entre-temps <a class="reference external" href="https://buildroot.org/">buildroot</a> (via le projet <a class="reference external" href="https://github.com/showmewebcam/showmewebcam/">showmewebcam</a>) qui est un
ensemble de scripts permettant de construire un système complet. Il prend en
charge un grand nombre d’architectures différentes, et possède une
configuration de base pour construire les applications les plus courantes. Il
ne reste plus qu’à l’utiliser pour reconstruire un client pulseaudio sur une
carte raspberrypi 0, qui offre un service via le wifi et le bluetooth.</p>
<p>Je vous propose ici de suivre le détail des modifications apportées pour
construire le système (le projet est disponible sur mon <a class="reference external" href="https://git.chimrod.com/piaudio.git/about/">dépôt git</a> – mais pas
l’image finale).</p>
<div class="admonition warning">
<p class="first admonition-title">Article avancé</p>
<p>Je ne pensais pas qu’un jour j’écrirais ce genre d’en tête, mais il s’agit ici
d’un article avancé, qui nécessite de connaître le fonctionnement du système linux.</p>
<p>Nous allons en effet construire un système de zéro, pour un usage spécifique,
ce qui oblige à sélectionner les services dont nous avons besoin (et savoir
lesquels sélectionner), et comment les configurer pour obtenir le système attendu.</p>
<p class="last">Aucune interface graphique ne sera installée sur la carte, et toute la
configuration devra être anticipée pour que la carte démarre dès son branchement.</p>
</div>
</div>
<div class="section" id="construction-du-systeme">
<h2>Construction du système</h2>
<div class="section" id="initialisation">
<h3>Initialisation</h3>
<p>Je fournis un script <a class="reference external" href="https://git.chimrod.com/piaudio.git/tree/build.sh">build.sh</a> qui prends en paramètres<span style="white-space:nowrap"> </span>:</p>
<ol class="arabic simple">
<li>une architecture</li>
<li>une commande buildroot (<cite>all</cite> pour lancer la création complète du système)</li>
</ol>
<p>pour l’instant, seules deux architectures ont été testées<span style="white-space:nowrap"> </span>: un raspberrypi3
(modèle A), et un raspberrypi0w<span style="white-space:nowrap"> </span>:</p>
<pre class="code bash literal-block">
./build.sh<span class="w">
</span>usage:<span class="w"> </span><span class="nv">BUILDROOT_DIR</span><span class="o">=</span>../buildroot<span class="w"> </span>./build.sh<span class="w"> </span><span class="o">{</span>boardname<span class="o">}</span><span class="w"> </span>all<span class="w">
</span>boardname:<span class="w"> </span>raspberrypi0w,<span class="w"> </span>raspberrypi3
</pre>
<p>Lors de l’exécution de la commande, le système va fusionner le paramétrage par
défaut de la carte, qui est chargé dans la configuration de buildroot, ainsi
qu’une liste de paquets spécifiques qui sont propres à notre installation, et
listés dans le fichier <a class="reference external" href="https://git.chimrod.com/piaudio.git/tree/configs/config">configs/config</a></p>
</div>
<div class="section" id="selection-des-paquets">
<h3>Sélection des paquets</h3>
<p>Cette configuration par défaut inclue les paquets nécessaires pour faire
fonctionner le réseau (wifi), pulseaudio, et le bluetooth (ainsi que les
dépendances pour mettre toute cette architecture en place). Si l’on souhaite
modifier un paquet, on peut regarder ceux disponibles en lançant une interface
de sélection<span style="white-space:nowrap"> </span>:</p>
<pre class="code bash literal-block">
./build.sh<span class="w"> </span>raspberrypi3<span class="w"> </span>menuconfig
</pre>
<img alt="L’interface menuconfig" class="align-center" src="//blog.chimrod.com/images/buildroot/buildroot.png" />
<p>Toutefois, je n’aime pas cette manière de procéder<span style="white-space:nowrap"> </span>: la configuration ainsi
générée se retrouve spécifique à une carte donnée, et l’on perd la possibilité
d’appliquer cette même configuration sur un matériel différent.</p>
<p>Aussi, et pour être sûr d’avoir un système qui soit reproductible, je préfère
noter les paquets dont j’ai besoin, et je les reporte dans le fichier
<a class="reference external" href="https://git.chimrod.com/piaudio.git/tree/configs/config">configs/config</a> qui sera utilisé lors de la prochaine construction.</p>
</div>
<div class="section" id="configuration-du-systeme">
<h3>Configuration du système</h3>
<p>En parallèle de la construction du système, nous avons à nous occuper de sa
configuration initiale.</p>
<p>Cela est réalisé à travers deux scripts, le premier, <a class="reference external" href="https://git.chimrod.com/piaudio.git/tree/board/post-build.sh">post-build.sh</a>, est
exécuté après l’installation des paquets, le second, <a class="reference external" href="https://git.chimrod.com/piaudio.git/tree/board/post-image.sh">post-image.sh</a> après la
finalisation de l’image finale. Dans le premier nous allons modifier les
fichiers de configuration du système, alors que dans le second nous traiterons
les paramètres donnés lors du boot.</p>
<p>Je présente ci-dessous quelques modifications apportées au système pour le
faire correspondre exactement au besoin<span style="white-space:nowrap"> </span>:</p>
<div class="section" id="carte-en-lecture-seule">
<h4>Carte en lecture seule</h4>
<p>Étant donné que nous n’aurons pas d’interface pour nous connecter à la carte,
elle va etre éteinte « sauvagement » régulièrement. Je préfère donc la basculer
en lecture seule, ce qui permet aussi d’etre sûr que tout le système restera
immuable sur la durée.</p>
<div class="highlight"><pre><span></span>sed<span class="w"> </span>-ie<span class="w"> </span><span class="s1">'/^\/dev\/root/ s/rw 0 1/ro 0 0/'</span><span class="w"> </span><span class="s2">"</span><span class="si">${</span><span class="nv">TARGET_DIR</span><span class="si">}</span><span class="s2">/etc/fstab"</span>
</pre></div>
<p>La modification est faite avec <cite>sed</cite>, et permet de suite de voir un peu comment
on va modifier le système<span style="white-space:nowrap"> </span>:</p>
<ul class="simple">
<li>Chaque modification sera faite à l’aide des outils disponibles dans bash
(sed, cp, cat, …), il faut donc déjà etre à l’aise avec le terminal avant
d’aller modifier la configuration</li>
<li>Chaque command nécessite de savoir comment sont construits les fichiers que
l’on veut modifier</li>
<li>Dans le cas où nous ajoutons des nouvelles entrées dans un fichier, il faudra
contrôler <em>avant</em> que cette entrée n’est pas déjà présente</li>
<li>Et enfin, nous allons avoir du boulot pour modifier chaque élément un à un…</li>
</ul>
<p>La variable <cite>${TARGET_DIR}</cite> est fournie par buildroot et permet de cibler
l’image que nous sommes en train de construire (par opposition au système hote
dans lequel nous compilons le système). Ici, nous modifions bien le fichier
<cite>/etc/fstab</cite> final, et non pas notre système linux<span style="white-space:nowrap"> </span>!</p>
<div class="admonition hint">
<p class="first admonition-title">Bonne pratique</p>
<p>Au vu des risques en cas d’erreur de saisie, il est bon de rajouter cette
ligne en début de script<span style="white-space:nowrap"> </span>:</p>
<div class="highlight"><pre><span></span><span class="c1"># Traite les variables non définies comme des erreurs lors de la substitution.</span>
<span class="nb">set</span><span class="w"> </span>-u
</pre></div>
<p class="last">Nous serons ainsi sûrs de ne pas modifier notre système par erreur (ce qui ne
devrait pas arriver, car nous ne travaillons pas sous <cite>root</cite>)</p>
</div>
</div>
<div class="section" id="ajout-du-wifi">
<h4>Ajout du wifi</h4>
<p>Pour activer le wifi, nous allons laisser systemd faire le travail,
<cite>wpa_supplicant</cite> propose en effet un service paramétré, qui active l’interface
spécifiée dans le nom (ici wlan0), il suffit donc de créer un lien symbolique
pour que celui-ci soit activé au démarrage<span style="white-space:nowrap"> </span>:</p>
<div class="highlight"><pre><span></span><span class="c1"># Create the link to interface wlan0 directly in the system configuration</span>
ln<span class="w"> </span>-sf<span class="w"> </span>/usr/lib/systemd/system/wpa_supplicant@.service<span class="w"> </span><span class="s2">"</span><span class="si">${</span><span class="nv">TARGET_DIR</span><span class="si">}</span><span class="s2">/usr/lib/systemd/system/multi-user.target.wants/wpa_supplicant@wlan0.service"</span>
</pre></div>
<p>(par contre, cela implique d’installer systemd sur la carte, ce qui surcharge
les dépendances, mais cela simplifie notre travail finalement…)</p>
<p>La configuration de la carte est comme d’habitude dans un fichier
<cite>wpa_supplicant.conf</cite> qui n’est pas versionné, mais qui sera copié s’il est
présent dans le répertoire.</p>
<div class="highlight"><pre><span></span><span class="k">if</span><span class="w"> </span><span class="o">[</span><span class="w"> </span>-f<span class="w"> </span><span class="s2">"</span><span class="nv">$BR2_EXTERNAL_PIAUDIO_PATH</span><span class="s2">/wpa_supplicant.conf"</span><span class="w"> </span><span class="o">]</span><span class="p">;</span><span class="w"> </span><span class="k">then</span>
<span class="w"> </span>cat<span class="w"> </span><span class="s2">"</span><span class="nv">$BR2_EXTERNAL_PIAUDIO_PATH</span><span class="s2">/wpa_supplicant.conf"</span><span class="w"> </span>><span class="w"> </span><span class="s2">"</span><span class="si">${</span><span class="nv">TARGET_DIR</span><span class="si">}</span><span class="s2">/etc/wpa_supplicant/wpa_supplicant-wlan0.conf"</span>
<span class="w"> </span>…
<span class="k">fi</span>
</pre></div>
<p>La variable <cite>$BR2_EXTERNAL_PIAUDIO_PATH</cite> correspond au répertoire de base du
système, c’est-à-dire notre répertoire racine. Il s’agit également d’une autre
variable d’environnement fournie par buildroot qui nous permet de ne pas avoir
à nous soucier de l’emplacement du script quand nous lançons notre compilation.</p>
</div>
<div class="section" id="pulseaudio">
<h4>Pulseaudio</h4>
<p>Vient ensuite pulseaudio. Nous n’avons pas à nous occuper de le démarrer avec
le système car cela est fourni par un paquet ayant été sélectionné.</p>
<p>Par contre, puisque le système est en lecture seule, nous avons quelques
modifications à réaliser pour que le service fonctionne<span style="white-space:nowrap"> </span>: nous allons créer un
répertoire, et le monter en mémoire au démarrage afin que pulseaudio puisse y
stocker ses fichiers<span style="white-space:nowrap"> </span>:</p>
<div class="highlight"><pre><span></span>create_missing_dir<span class="w"> </span><span class="s2">"/var/lib/pulse"</span>
<span class="k">if</span><span class="w"> </span>!<span class="w"> </span>grep<span class="w"> </span>-qE<span class="w"> </span><span class="s1">'/var/lib/pulse'</span><span class="w"> </span><span class="s2">"</span><span class="si">${</span><span class="nv">TARGET_DIR</span><span class="si">}</span><span class="s2">/etc/fstab"</span><span class="p">;</span><span class="w"> </span><span class="k">then</span>
<span class="w"> </span>cat<span class="w"> </span><span class="s"><< __EOF__ >> "${TARGET_DIR}/etc/fstab"</span>
<span class="s">tmpfs /var/lib/pulse tmpfs rw 0 0</span>
<span class="s">__EOF__</span>
<span class="k">fi</span>
</pre></div>
<p>Ensuite, nous allons modifier le fichier <cite>/etc/pulse/system.pa</cite> afin d’y
ajouter les modules bluetooth, et la connexion distante<span style="white-space:nowrap"> </span>:</p>
<div class="highlight"><pre><span></span><span class="k">if</span><span class="w"> </span>!<span class="w"> </span>grep<span class="w"> </span>-qE<span class="w"> </span><span class="s1">'^load-module module-native-protocol-tcp'</span><span class="w"> </span><span class="s2">"</span><span class="si">${</span><span class="nv">TARGET_DIR</span><span class="si">}</span><span class="s2">/etc/pulse/system.pa"</span><span class="p">;</span><span class="w"> </span><span class="k">then</span>
<span class="w"> </span>cat<span class="w"> </span><span class="s"><< __EOF__ >> "${TARGET_DIR}/etc/pulse/system.pa"</span>
<span class="s">load-module module-bluetooth-policy</span>
<span class="s">load-module module-bluetooth-discover</span>
<span class="s">load-module module-native-protocol-tcp auth-ip-acl=127.0.0.1;192.168.0.0/24;2a01:e35:8ac8:0e00::/64 auth-anonymous=1</span>
<span class="s">__EOF__</span>
<span class="k">fi</span>
</pre></div>
</div>
<div class="section" id="bluetooth">
<h4>Bluetooth</h4>
<p>D’abord, pour activer le bluetooth, nous allons indiquer au noyau de le charger
au démarrage<span style="white-space:nowrap"> </span>:</p>
<div class="highlight"><pre><span></span>cat<span class="w"> </span><span class="s"><< __EOF__ >> "${BINARIES_DIR}/rpi-firmware/config.txt"</span>
<span class="s">dtparam=krnbt=on</span>
<span class="s">__EOF__</span>
</pre></div>
<p>Cette option ajoutée récemment dans les raspberrypi va nous éviter d’avoir à
lancer les commande <cite>bt-attach</cite> ou <cite>hciattach</cite>. le bluetooth est
automatiquement branché sur le port uart, à la vitesse maximale prise en charge
par la carte. Cela résoud en une ligne énormément de problèmes rencontrés lors
de la configuration du bluetooth si l’on avait voulu faire cela manuellement.</p>
<p>Voir la liste des options possibles sur la page suivante<span style="white-space:nowrap"> </span>: <a class="reference external" href="https://github.com/raspberrypi/firmware/tree/master/boot/overlays">https://github.com/raspberrypi/firmware/tree/master/boot/overlays</a></p>
<p>Par contre, il faut libérer pour cela la connexion série, qui est configurée
par défaut sur le port <cite>ttyAMA0</cite>. Il nous faut supprimer la ligne suivante dans
le fichier <cite>cmdline.txt</cite> : <cite>console=ttyAMA0,115200</cite></p>
<p>Ensuite, comme précédemment, nous allons également créer un répertoire en
mémoire pour pallier le système en lecture seule de la carte<span style="white-space:nowrap"> </span>:</p>
<div class="highlight"><pre><span></span>create_missing_dir<span class="w"> </span><span class="s2">"/var/lib/bluetooth/"</span>
<span class="k">if</span><span class="w"> </span>!<span class="w"> </span>grep<span class="w"> </span>-qE<span class="w"> </span><span class="s1">'/var/lib/bluetooth'</span><span class="w"> </span><span class="s2">"</span><span class="si">${</span><span class="nv">TARGET_DIR</span><span class="si">}</span><span class="s2">/etc/fstab"</span><span class="p">;</span><span class="w"> </span><span class="k">then</span>
<span class="w"> </span>cat<span class="w"> </span><span class="s"><< __EOF__ >> "${TARGET_DIR}/etc/fstab"</span>
<span class="s">tmpfs /var/lib/bluetooth tmpfs rw 0 0</span>
<span class="s">__EOF__</span>
<span class="k">fi</span>
</pre></div>
<p>La configuration du bluetooth est lue dans le fichier
<cite>/etc/bluetooth/main.conf</cite>, c’est donc là que nous allons y stocker les
paramètres génériques<span style="white-space:nowrap"> </span>: classe de l’appareil et timeouts<span style="white-space:nowrap"> </span>:</p>
<div class="highlight"><pre><span></span><span class="k">[General]</span>
<span class="na">Class</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">200428</span>
<span class="na">DiscoverableTimeout</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">0</span>
<span class="na">PairableTimeout</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">0</span>
<span class="k">[Policy]</span>
<span class="na">AutoEnable</span><span class="o">=</span><span class="s">true</span>
</pre></div>
<p>Enfin, nous avons besoin d’autoriser les connexions externes, et ce, sans aucun
accès au système. Cela s’effectue par le biais d’un <em>agent</em> qui demande la
confirmation d’un code auprès des deux parties (celui qui veut se connecter, et
celui qui accepte les connexions) pour éviter les erreurs. Ici, nous faire fi
de la sécurité, et ouvrir les connexions à n’importe qui. Les risques sont
limités (le système est en lecture seule, aucune des applications de base
permettant de détourner l’ordinateur n’est installée).</p>
<p>C’est un problème que j’avais rencontré dans mon système d’origine, et qui
nécessitait de se connecter sur le raspberrypi pour autoriser le périphérique.
J’ai finalement trouvé une solution (qui se résume en quelques lignes, mais qui
m’a occupé quelques heures avant d’en arriver là).</p>
<p>On va se créer un service <em>systemd</em> (puisqu’il est là…) qui lance un agent
perpétuel chargé d’accepter toutes les connexions<span style="white-space:nowrap"> </span>:</p>
<div class="highlight"><pre><span></span>cat<span class="w"> </span><span class="s"><< __EOF__ > "${TARGET_DIR}/etc/systemd/system/bt-agent.service"</span>
<span class="s">[Unit]</span>
<span class="s">Description=Bluetooth Agent</span>
<span class="s">After=bt-audio.service</span>
<span class="s">Requires=bt-audio.service</span>
<span class="s">[Service]</span>
<span class="s">Type=simple</span>
<span class="s">ExecStartPre=bt-adapter --set Discoverable 1</span>
<span class="s">ExecStart=bt-agent -c NoInputNoOutput</span>
<span class="s">RestartSec=5</span>
<span class="s">Restart=always</span>
<span class="s">KillSignal=SIGUSR1</span>
<span class="s">[Install]</span>
<span class="s">WantedBy=bluetooth.target</span>
<span class="s">__EOF__</span>
</pre></div>
<p>Au passage, ce service déclare le bluetooth en mode « découvrable », ce qui rend
vraiment le service ouvert à tous.</p>
</div>
<div class="section" id="connexion-serie">
<h4>Connexion série</h4>
<p>Enfin, il faut que nous puissions nous connecter à la carte pour contrôler
qu’elle démarre correctement. Or, nous n’avons installé aucun serveur ssh<span style="white-space:nowrap"> </span>:
celle-ci est donc vérouillée. Par contre, le raspberrypi 0 nous offre une
chance, puisqu’il est possible de s’y connecter en le branchant directement en
usb, mais encore faut-il activer cette option au démarrage…</p>
<div class="admonition note">
<p class="first admonition-title">Note</p>
<p class="last">Cela fonctionne également avec un raspberrypi 4 ou un raspberrypi 3 A, mais
pour ce dernier, il faut trouver un cable <span class="caps">USB</span> male/male pour faire la
connexion. Dans mes tests avec ce dernier, j’ai triché et installé dropbear
qui est un serveur ssh<span style="white-space:nowrap"> </span>!</p>
</div>
<p>Il suffit d’ajouter une ligne dans le fichier <cite>cmdline.txt</cite> et le tour est joué :</p>
<div class="highlight"><pre><span></span><span class="k">if</span><span class="w"> </span>!<span class="w"> </span>grep<span class="w"> </span>-qE<span class="w"> </span><span class="s1">'modules-load=dwc2,g_serial'</span><span class="w"> </span><span class="s2">"</span><span class="si">${</span><span class="nv">BINARIES_DIR</span><span class="si">}</span><span class="s2">/rpi-firmware/cmdline.txt"</span><span class="p">;</span><span class="w"> </span><span class="k">then</span>
<span class="w"> </span>sed<span class="w"> </span><span class="s1">'/^root=/ s/$/ modules-load=dwc2,g_serial/'</span><span class="w"> </span>-i<span class="w"> </span><span class="s2">"</span><span class="si">${</span><span class="nv">BINARIES_DIR</span><span class="si">}</span><span class="s2">/rpi-firmware/cmdline.txt"</span>
<span class="k">fi</span>
</pre></div>
</div>
</div>
<div class="section" id="build">
<h3>Build</h3>
<p>Il ne nous reste plus qu’à lancer la compilation du système, et attendre le
résultat<span style="white-space:nowrap"> </span>:</p>
<pre class="code bash literal-block">
./build.sh<span class="w"> </span>raspberrypi0w<span class="w"> </span>all
</pre>
<p>Une fois terminé, on peut copier l’image générée et la brancher dans le
raspberry pi</p>
<pre class="code bash literal-block">
sudo<span class="w"> </span>dd<span class="w"> </span><span class="k">if</span><span class="o">=</span>output/raspberrypi0w/images/sdcard.img<span class="w"> </span><span class="nv">of</span><span class="o">=</span>/dev/XXX<span class="w"> </span><span class="nv">bs</span><span class="o">=</span>4k
</pre>
</div>
</div>
<div class="section" id="demarrage-et-premier-lancement">
<h2>Démarrage et premier lancement</h2>
<img alt="La carte connectée en USB" class="align-center" src="//blog.chimrod.com/images/buildroot/connexion.jpeg" />
<p>Une fois la carte branchée, on peut se connecter dessus à l’aide de la commande
suivante<span style="white-space:nowrap"> </span>:</p>
<pre class="code bash literal-block">
screen<span class="w"> </span>/dev/ttyACM0
</pre>
<div class="section" id="recuperer-le-nom-de-la-connexion-pulseaudio">
<h3>Récupérer le nom de la connexion pulseaudio</h3>
<pre class="code console literal-block">
<span class="gp"># </span>su<span class="w"> </span>-s<span class="w"> </span>/usr/bin/sh<span class="w"> </span>pulse<span class="w">
</span><span class="gp">$ </span>pactl<span class="w"> </span>info<span class="w">
</span><span class="go">…
Default Sink: alsa_output.0.stereo-fallback</span>
</pre>
<p>C’est cette valeur qui est à utiliser dans le tunnel que nous allons mettre en
place. Sur notre pc de bureau, nous allons modifier le fichier <cite>/etc/pulse/default.pa</cite> et ajouter cette ligne<span style="white-space:nowrap"> </span>:</p>
<pre class="code bash literal-block">
load-module<span class="w"> </span>module-tunnel-sink<span class="w"> </span><span class="nv">sink_name</span><span class="o">=</span>rpi_tunnel<span class="w"> </span><span class="nv">server</span><span class="o">=</span>tcp:<span class="si">${</span><span class="nv">IP</span><span class="si">}</span>:4713<span class="w"> </span><span class="nv">sink</span><span class="o">=</span>alsa_output.0.stereo-fallback
</pre>
<p>Comme notre raspberrypi se connecte en <span class="caps">DHCP</span>, son adresse <span class="caps">IP</span> est fournie par le
routeur. Je conseille de lui associer une <span class="caps">IP</span> fixe afin que la configuration ne
change pas<span style="white-space:nowrap"> </span>:)</p>
<img alt="La connexion pulseaudio" class="align-center" src="//blog.chimrod.com/images/buildroot/pulseaudio.png" />
</div>
<div class="section" id="nommage-du-service-bluetooth">
<h3>Nommage du service bluetooth</h3>
<p>Un dernier point que je n’ai pas réussi à comprendre, le nom du service
bluetooth est <cite>Bluez</cite> au lieu du nom de la carte (<cite>piaudio</cite>). Cela semble être
du au fait que la carte soit en lecture seule. La solution consiste à basculer
la carte en écriture, relancer le service bluetooth, et redémarrer<span style="white-space:nowrap"> </span>:</p>
<pre class="code bash literal-block">
mount<span class="w"> </span>-o<span class="w"> </span>remount,rw<span class="w"> </span>/<span class="w">
</span>systemctl<span class="w"> </span>restart<span class="w"> </span>bluetooth<span class="w">
</span>reboot
</pre>
<p>Cette opération est à faire une fois seulement, il n’est pas nécessaire d’y
revenir ensuite.</p>
</div>
<div class="section" id="se-connecter-en-bluetooth">
<h3>Se connecter en bluetooth</h3>
<img alt="La connexion bluetooth" class="align-center" src="//blog.chimrod.com/images/buildroot/bluetooth.png" />
<p>Comme nous avons tout automatisé, c’est encore plus simple<span style="white-space:nowrap"> </span>! en quelques clics
l’association est faite<span style="white-space:nowrap"> </span>!</p>
</div>
</div>
Écrire en tengwar2021-09-17T00:00:00+02:002021-09-17T00:00:00+02:00Chimrodtag:blog.chimrod.com,2021-09-17:/2021/09/ecrire-en-tengwar/<p class="first last">Une nouvelle application est apparue sur le blog, qui permet de transcrire
des mots dans l’alphabet Tengwar. Je décris les coulisses et le travail qui
se trouve derrière.</p>
<style>
@font-face {
font-family: "Tengwar Annatar" ;
src: url("/pages/tengwar/tngan.ttf") format("truetype");
}
.tengwar {
font-family: "Tengwar Annatar" ;
}
</style><div class="section" id="du-roman-au-reel">
<h2>Du roman au réel</h2>
<p>C’est en suivant le chemin de la calligraphie que je suis tombé sur l’écriture
en <em>tengwar</em> inventée par Tolkien pour les langues dans le monde du seigneur
des anneaux. Ce qui m’a plu de suite dans son alphabet était la correspondance
entre la représentation des lettres et les sons auxquels ils sont associés
(consonnes voisées, etc)</p>
<p>Dès sa conception, Tolkien avait envisagé que le même alphabet puisse être
utilisé dans les différentes langues de son œuvre, et avait prévu que des
variations puissent être apportées dans la prononciation en fonction de la
langue en question. Quand on y réfléchit, c’est la même chose avec notre
alphabet latin, et nous sommes tout à fait capables de changer notre lecture dès
que nous voyons un mot écrit en anglais pour le lire correctement.</p>
<p>Ces <em>modes</em> des tengwar ouvrent la portes à l’écriture dans le monde réel,
puisqu’il est possible de concevoir un mode de lecture qui serait adapté aux
langues vivantes, et plusieurs personnes s’y sont collées, chacune avec leur
propre interprétation.</p>
<p>Bien sur, l’informatique n’est pas en reste, et nous avons également de
nombreuses polices d’écriture qui permettent également d’afficher les tengwar à
l’écran. En combinant les deux j’ai donc essayé de créer une <a class="reference external" href="//blog.chimrod.com/pages/tengwar/">application (<span class="tengwar">aF77TÉ jiR 1g%s.7E</span>)</a> qui,
à partir d’un mot de la langue française, transcrit celui-ci dans l’alphabet
tengwar. Cette application doit donc réaliser deux opérations<span style="white-space:nowrap"> </span>:</p>
<ol class="arabic simple">
<li>À partir de l’écriture d’un mot, déterminer sa prononciation</li>
<li>À partir de sa prononciation, afficher les caractères dans la (une) police
en tengwar selon le mode français.</li>
</ol>
<p>Eh bien la partie 2 était en fait la plus simple<span style="white-space:nowrap"> </span>:)</p>
</div>
<div class="section" id="la-complexite-du-reel">
<h2>La complexité du réel</h2>
<p>C’est bien connu, l’informatique ne se contente pas d’à peu près. Il a donc
fallu me replonger dans quelque chose qui est tellement évident que nous le
faisons sans y penser<span style="white-space:nowrap"> </span>: comment faisons-nous pour lire les mots comme ils sont,
et surtout <em>comment faisons-nous pour lire un mot que nous ne connaissons pas
?</em> Bienvenue dans le monde du français, où la prononciation du <tt class="docutils literal">S</tt> se
transforme selon les lettres qui l’entourent, où le <tt class="docutils literal">N</tt> vient fusionner avec la
voyelle qui le précède, et les <tt class="docutils literal">U</tt> s’effacent derrière les <tt class="docutils literal">G</tt>, <tt class="docutils literal">Q</tt>…</p>
<p>Il est illusoire de vouloir obtenir quelque chose de parfait. En fait, la
prononciation correcte d’un mot nécessite de connaitre sa nature<span style="white-space:nowrap"> </span>; par exemple
<em>aiment</em> et <em>vraiment</em> ne different que deux lettres mais ont une prononciation
complètement différente (et ne parlons pas de <em>se fier</em> ou <em>être fier</em>). Hors
de tout contexte, il est donc impossible de viser juste (et cela pose question
sur le processus cognitif que l’on met en place quand nous lisons un texte…)</p>
<p>Heureusement, on peut quand même obtenir des résultats satisfaisants. Sans
entrer dans le détail, j’ai du en fait mettre trois opérations pour réaliser
mon application<span style="white-space:nowrap"> </span>:</p>
<ol class="arabic simple">
<li>Une transformation des lettres vers les sons,</li>
<li>Une transformation des sons en syllabes,</li>
<li>Des traitements d’homogénisation sur les syllabes.</li>
</ol>
<p>Pour la deuxième étape, la page de Wikipédia sur la <a class="reference external" href="https://fr.m.wiktionary.org/wiki/Annexe:Prononciation/fran%C3%A7ais#Structure_syllabique">structure syllabique du
français</a> a été la clef qui m’a permis d’organiser mon programme.</p>
</div>
<div class="section" id="retour-aux-lettres">
<h2>Retour aux lettres</h2>
<p>Ceci fait, il ne reste plus qu’à définir une dernière transformation pour
représenter chaque son dans un alphabet dédié. Le plus difficile étant fait, il
est même possible d’en définir deux<span style="white-space:nowrap"> </span>! Un qui servira à contrôler que
l’application a correctement compris notre mot, et un second qui sera
l’affichage en tengwar proprement dit. On pourrait également envisager d’autres
alphabets, comme l’aurebesh<span style="white-space:nowrap"> </span>:)</p>
</div>
Sauvegarder sa clef privée GPG2021-02-13T00:00:00+01:002021-02-13T00:00:00+01:00Chimrodtag:blog.chimrod.com,2021-02-13:/2021/02/sauvegarder-sa-clef-privee-gpg/<p class="first last">Comment exporter et sauvegarder sa clef privée proprement ? Le papier,
toujours du papier…</p>
<p>Comme beaucoup sûrement, je chiffre mes sauvegardes avant de les envoyer dans
le cloud, je chiffre mes mots de passes (et utilise une clef sécurisée pour les
lire), et utilise pour cela l’outil gpg. Cela me permet d’être sûr que les
fichiers ne seront pas lus si l’on ne dispose pas de la clef de déchiffrement adéquate.</p>
<p>Mais comment sauvegarder sa clef privée<span style="white-space:nowrap"> </span>? Est-ce que l’on peut la copier sur
une clef <span class="caps">USB</span> et la laisser dans un tiroir<span style="white-space:nowrap"> </span>? Comment s’assurer que la sauvegarde
sera pérenne<span style="white-space:nowrap"> </span>?</p>
<p>On recommande souvent l’outil paperkey pour cela, il génère un document texte
simple, pouvant être utilisé pour reconstruire la clef privée à partir de le
clef publique (en partant du principe que ladite clef publique est publique et
peut être retrouvée facilement). Le document peut ensuite être imprimé, et un
logiciel <span class="caps">OCR</span> permet ensuite de le régénérer.</p>
<p>Je propose une autre solution, basée sur le même principe, mais en qrcode et en
pdf<span style="white-space:nowrap"> </span>!</p>
<div class="section" id="le-qrcode">
<h2>Le qrcode</h2>
<img alt="Un qrcode généré" class="align-center" src="//blog.chimrod.com/resources/qrcode.png" style="width: 50%;" />
<p>Je ne présente plus les qrcode, que l’on rencontre déjà partout. La seule chose
qui est vraiment importante ici, est la taille limite des données qu’il peut
contenir (<a class="reference external" href="https://fr.wikipedia.org/wiki/Code_QR#Sp%C3%A9cification">source</a>) :</p>
<ul class="simple">
<li>Caractères numériques<span style="white-space:nowrap"> </span>: maximum 7<span style="white-space:nowrap"> </span>089</li>
<li>Caractères alphanumériques<span style="white-space:nowrap"> </span>: maximum 4<span style="white-space:nowrap"> </span>296</li>
<li>Binaires (8-bits) : <strong>maximum 2<span style="white-space:nowrap"> </span>953 octets</strong></li>
<li>Kanji/Kana<span style="white-space:nowrap"> </span>: maximum 1<span style="white-space:nowrap"> </span>817 caractères</li>
</ul>
<p>Ici, c’est la limite de données binaire qui nous intéresse<span style="white-space:nowrap"> </span>: 2953 octets. Notre
clef <span class="caps">GPG</span> dépassant probablement cette limite, nous allons la découper en
plusieurs lots, qui seront chacun d’eux transformés en image.</p>
<p>La commande est assez simple<span style="white-space:nowrap"> </span>:</p>
<div class="highlight"><pre><span></span><span class="c1"># Exporte la clef privée et découpe en lot de 2500 octets</span>
gpg<span class="w"> </span>--export-secret-keys<span class="w"> </span>--armor<span class="w"> </span><span class="p">|</span><span class="w"> </span>split<span class="w"> </span>-C<span class="w"> </span><span class="m">2500</span><span class="w"> </span>-<span class="w"> </span>splitkey-
</pre></div>
<p>(ici nous créons autant de fichier <tt class="docutils literal">splitkey</tt> que nécessaire, avec une taille
de 2500 octets chacun).</p>
<p>Ensuite, à l’aide de l’application qrencode, on transforme chaque fichier en
image<span style="white-space:nowrap"> </span>:</p>
<div class="highlight"><pre><span></span><span class="c1"># Génère un QRCode pour chacun d'eux</span>
<span class="k">for</span><span class="w"> </span>file<span class="w"> </span><span class="k">in</span><span class="w"> </span>tmp/splitkey-??<span class="p">;</span><span class="w"> </span><span class="k">do</span>
<span class="w"> </span>qrencode<span class="w"> </span>--size<span class="w"> </span><span class="m">3</span><span class="w"> </span>-d<span class="w"> </span><span class="m">150</span><span class="w"> </span>-t<span class="w"> </span>eps<span class="w"> </span>-o<span class="w"> </span><span class="s2">"</span><span class="si">${</span><span class="nv">file</span><span class="si">}</span><span class="s2">.ps"</span><span class="w"> </span>-r<span class="w"> </span><span class="s2">"</span><span class="si">${</span><span class="nv">file</span><span class="si">}</span><span class="s2">"</span>
<span class="k">done</span>
</pre></div>
<p>J’utilise ici le format postcript, afin de pouvoir l’intégrer facilement dans
un fichier pdf<span style="white-space:nowrap"> </span>: étape suivante<span style="white-space:nowrap"> </span>!</p>
</div>
<div class="section" id="recuperer-les-donnees">
<h2>Récupérer les données</h2>
<p>Il suffit pour cela de lire chaque image, puis concaténer tous les fichiers
entre eux. La lecture peut être faite à l’aide du lecteur zbarimg, qui fait
partie du paquet zbar-tool dans debian<span style="white-space:nowrap"> </span>:</p>
<div class="highlight"><pre><span></span><span class="k">for</span><span class="w"> </span>file<span class="w"> </span><span class="k">in</span><span class="w"> </span>*.png<span class="p">;</span><span class="w"> </span><span class="k">do</span>
<span class="w"> </span>zbarimg<span class="w"> </span>-1<span class="w"> </span>-q<span class="w"> </span>--raw<span class="w"> </span><span class="si">${</span><span class="nv">file</span><span class="si">}</span><span class="p">;</span>
<span class="k">done</span><span class="w"> </span>><span class="w"> </span>private.key
gpg<span class="w"> </span>--import<span class="w"> </span>private.key
</pre></div>
<p>(le plus long dans ce cas, est de scanner les fichiers pour en extraire les images…)</p>
</div>
<div class="section" id="le-pdf">
<h2>Le pdf</h2>
<p>L’idée est ensuite d’assembler tous ces qrcode dans un document pdf que l’on
va ensuite imprimer. Comme je suis un grand amateur de la combinaison rst +
latex, c’est avec ces deux outils que l’on va construire notre document final.</p>
<p>Puisque l’on dispose d’un fichier à imprimer, autant y ajouter une notice, avec
la manière dont les données ont été générées, et comment les récupérer. À
ce moment-là, le pdf devient autoporteur, et il est possible ensuite de
l’oublier puisqu’il contient en lui-même toutes les informations nécessaires.</p>
<p>Voilà un lien pour télécharger un package réalisant tout ça<span style="white-space:nowrap"> </span>:</p>
<div class="figure align-center">
<a class="reference external image-reference" href="//blog.chimrod.com/resources/gpg_export.tar.gz"><img alt="get the file" src="//blog.chimrod.com/images/mimetypes/package-x-generic.png" /></a>
<p class="caption">Télécharger</p>
</div>
<p>la commande <tt class="docutils literal">make</tt> permet de lancer les commandes ci-dessus, et générer un
fichier pdf avec les images, et une petite documentation avec les commandes
ci-dessus (voir le fichier <tt class="docutils literal">private.rst</tt> qui contient le modèle).</p>
<p>Vous pouvez ensuite imprimer le pdf, et supprimer les fichiers, et tester<span style="white-space:nowrap"> </span>!</p>
<p>À titre d’exemple, voilà ce que donne <a class="reference external" href="//blog.chimrod.com/images/chiffer/private.pdf">le fichier généré</a></p>
<a class="reference external image-reference" href="//blog.chimrod.com/images/chiffer/private.pdf"><img alt="Un rendu" class="align-center" src="//blog.chimrod.com/images/chiffer/private.png" style="width: 50%;" /></a>
</div>