# rss_item

guid: http://korben.info/?p=88721
title: Translate Shell – Un traducteur pour votre terminal
author: Korben
url: https://korben.info/translate-shell-traducteur-terminal.html
feedurl: https://korben.info/feed
content:
<p>Si vous aimez faire des scripts ou utiliser des petits outils, voici Trans, un traducteur en ligne de commande utilisant Google Translate et/ou Bing, Yandex Apertium.</p>
<p>Pour fonctionner, Trans nécessite zsh ou Bash ainsi que gawk. Ensuite pour l'installer, il suffit d'ouvrir un terminal et d'y entrer :</p>
<blockquote><p>wget git.io/trans</p>
<p>chmod +x ./trans</p></blockquote>
<p>Son fonctionnement est assez simple : Il suffit d'entrer la commande ./trans suivi du mot ou de la phrase que vous voulez traduire.</p>
<blockquote><p>./trans "truth is out there"</p></blockquote>
<p><a href="http://korben.info/wp-content/uploads/2017/09/capture-decran-2017-09-19-15-05-53.jpg"><img class="size-full wp-image-88722 alignnone" src="http://korben.info/wp-content/uploads/2017/09/capture-decran-2017-09-19-15-05-53.jpg" alt="" width="339" height="155" /></a></p>
<p>Quand il le peut, il détecte la langue d'origine et fournit alors une traduction et parfois une définition, voir des noms et des adjectifs associés en français. Autrement, il faudra indiquer la langue source à l'aide d'un paramètre.</p>
<p>Si je veux demander la traduction de "extraterrestre" en russe, je dois donc faire :</p>
<blockquote><p>./trans :ru extraterrestre</p></blockquote>
<p>et ainsi obtenir :</p>
<p><a href="http://korben.info/wp-content/uploads/2017/09/capture-decran-2017-09-19-15-04-47.jpg"><img class="size-full wp-image-88723 alignnone" src="http://korben.info/wp-content/uploads/2017/09/capture-decran-2017-09-19-15-04-47.jpg" alt="" width="302" height="188" srcset="//korben.info/wp-content/uploads/2017/09/capture-decran-2017-09-19-15-04-47.jpg 302w, //korben.info/wp-content/uploads/2017/09/capture-decran-2017-09-19-15-04-47-300x188.jpg 300w" sizes="(max-width: 302px) 100vw, 302px" /></a></p>
<p>Ensuite il y a quelques paramètres comme "-brief" qui permet d'obtenir uniquement la traduction sans les explications ou les noms qui vont avec, ou le paramètre Shell qui permet d'avoir un Shell interactif avec trans pour lui envoyer plusieurs demandes de traduction à la suite. Trans est aussi capable de traduire un fichier, une page web, d'identifier une langue que vous ne connaissez pas ou de se brancher en text2speech pour que votre ordinateur prononce les traductions.</p>
<p>En somme, un outil super pratique ! <code> </code></p>
<p>Cet article merveilleux et sans aucun égal intitulé : <a rel="nofollow" href="https://korben.info/translate-shell-traducteur-terminal.html">Translate Shell &#8211; Un traducteur pour votre terminal</a> ; a été publié sur <a rel="nofollow" href="https://korben.info">Korben</a>, le seul site qui t'aime plus fort que tes parents.</p>
<hr><p>Si vous aimez faire des scripts ou utiliser des petits outils, voici Trans, un traducteur en ligne de commande utilisant Google Translate et/ou Bing, Yandex Apertium. Pour fonctionner, Trans nécessite zsh ou Bash ainsi que gawk. Ensuite pour l'installer, il suffit d'ouvrir un terminal et d'y entrer : wget git.io/trans chmod +x ./trans Son fonctionnement <a class="read-more" href="https://korben.info/translate-shell-traducteur-terminal.html">> Lire la suite</a></p>
<p>Cet article merveilleux et sans aucun égal intitulé : <a rel="nofollow" href="https://korben.info/translate-shell-traducteur-terminal.html">Translate Shell &#8211; Un traducteur pour votre terminal</a> ; a été publié sur <a rel="nofollow" href="https://korben.info">Korben</a>, le seul site qui t'aime plus fort que tes parents.</p>


guid: http://korben.info/?p=88729
title: Démonstration d’une attaque à base d’interception de SMS (2FA)
author: Korben
url: https://korben.info/demonstration-dune-attaque-a-base-dinterception-de-sms-2fa.html
feedurl: https://korben.info/feed
content:
<p>Quand en juillet, <a href="https://korben.info/authentification-double-facteur-2fa.html">j'expliquais qu'activer le 2FA</a> (authentification double facteur) c'était important, mais qu'il valait mieux éviter de recevoir le code par SMS et préférer une application générant des codes uniques (Authenticator ou équivalent), certains me répondaient : "<em>Oui, mais pffff</em>"... (Ou un truc du genre).</p>
<p>Et pourtant, l'exploitation de la faille dans SS7 est tout à fait réalisable. Alors quand je suis tombé sur cette démonstration en vidéo, je me suis dit que j'allais la poster ici pour que vous voyiez comment ça se passe en vrai. Frissons dans le dos garantis</p>
<p>L'exemple de la vidéo cible le site Coinbase (broker de bitcoins) via une récupération de compte Gmail avec code envoyé par SMS. Mais globalement, n'importe quel service qui envoie des codes uniques par SMS (comme votre banque ou votre service email) peut tout à fait être exploité de la même façon.</p>
<p style="text-align: center;"><iframe title="Bitcoin wallet hacked via SMS interception" src="https://player.vimeo.com/video/232678861" width="640" height="360" frameborder="0" allowfullscreen="allowfullscreen" data-mce-fragment="1"></iframe></p>
<p>Pour réussir ce hack, il a suffit à l'attaquant de connaitre le nom, le pseudo et le numéro de téléphone de la victime. Bref, des informations relativement faciles à trouver.</p>
<p>Vous savez ce qu'il vous reste à faire : utiliser des outils comme Authenticator (ou autre) et exiger de vos services web préférés qu'ils proposent d'autres options que de la 2FA par SMS.</p>
<p><a href="https://techcrunch.com/2017/09/18/ss7-coinbase-bitcoin-hack-2fa-vulnerable/">Source</a></p>
<p>Cet article merveilleux et sans aucun égal intitulé : <a rel="nofollow" href="https://korben.info/demonstration-dune-attaque-a-base-dinterception-de-sms-2fa.html">Démonstration d&#8217;une attaque à base d&#8217;interception de SMS (2FA)</a> ; a été publié sur <a rel="nofollow" href="https://korben.info">Korben</a>, le seul site qui t'aime plus fort que tes parents.</p>
<hr><p>Quand en juillet, j'expliquais qu'activer le 2FA (authentification double facteur) c'était important, mais qu'il valait mieux éviter de recevoir le code par SMS et préférer une application générant des codes uniques (Authenticator ou équivalent), certains me répondaient : "Oui, mais pffff"... (Ou un truc du genre). Et pourtant, l'exploitation de la faille dans SS7 est <a class="read-more" href="https://korben.info/demonstration-dune-attaque-a-base-dinterception-de-sms-2fa.html">> Lire la suite</a></p>
<p>Cet article merveilleux et sans aucun égal intitulé : <a rel="nofollow" href="https://korben.info/demonstration-dune-attaque-a-base-dinterception-de-sms-2fa.html">Démonstration d&#8217;une attaque à base d&#8217;interception de SMS (2FA)</a> ; a été publié sur <a rel="nofollow" href="https://korben.info">Korben</a>, le seul site qui t'aime plus fort que tes parents.</p>


guid: http://korben.info/?p=88733
title: Skeep – Contrôler vos données personnelles facilement
author: Korben
url: https://korben.info/skeep-controler-vos-donnees-personnelles-facilement.html
feedurl: https://korben.info/feed
content:
<p>Même si vous êtes vigilant concernant vos données personnelles, il y a toujours un moment où vous relâchez la pression... Un petit coup de Facebook Connect par ci, un petit coup de "J'inscris mon email" par là...etc. Et de fil en aiguille, année après année, sans même sans rendre compte, ce sont des centaines de sociétés qui ont accès à un profil de vous très détaillé : Âge, numéro de téléphone, amis, centres d'intérêt et j'en passe.</p>
<p>Alors pour les plus experts, il y a toujours moyen de contrôler ces autorisations que nous donnons à des sociétés tierces, au travers de menus bien planqués dans les paramètres de Facebook, mais si pour vous tout cela est fastidieux, j'ai la solution. Il s'agit de <strong>Skeep</strong>, une application mobile qui permet de gérer de manière très fine l'ensemble des autorisations que nous avons accordé via Facebook à tous ces sites, apps et autres.</p>
<p style="text-align: center;"><a href="http://korben.info/wp-content/uploads/2017/09/2017-09-19-11-16-30-e1505897313578.png"><img class="aligncenter wp-image-88738 " src="http://korben.info/wp-content/uploads/2017/09/2017-09-19-11-16-30-e1505897313578-650x1124.png" alt="" width="327" height="566" srcset="//korben.info/wp-content/uploads/2017/09/2017-09-19-11-16-30-e1505897313578-650x1124.png 650w, //korben.info/wp-content/uploads/2017/09/2017-09-19-11-16-30-e1505897313578-116x200.png 116w, //korben.info/wp-content/uploads/2017/09/2017-09-19-11-16-30-e1505897313578-768x1328.png 768w, //korben.info/wp-content/uploads/2017/09/2017-09-19-11-16-30-e1505897313578-592x1024.png 592w, //korben.info/wp-content/uploads/2017/09/2017-09-19-11-16-30-e1505897313578-475x821.png 475w, //korben.info/wp-content/uploads/2017/09/2017-09-19-11-16-30-e1505897313578-750x1296.png 750w, //korben.info/wp-content/uploads/2017/09/2017-09-19-11-16-30-e1505897313578-400x691.png 400w, //korben.info/wp-content/uploads/2017/09/2017-09-19-11-16-30-e1505897313578.png 1242w" sizes="(max-width: 327px) 100vw, 327px" /></a></p>
<p style="text-align: center;"><a href="http://korben.info/wp-content/uploads/2017/09/2017-09-19-11-16-53.png"><img class="aligncenter wp-image-88736" src="http://korben.info/wp-content/uploads/2017/09/2017-09-19-11-16-53-650x1156.png" alt="" width="343" height="610" srcset="//korben.info/wp-content/uploads/2017/09/2017-09-19-11-16-53-650x1156.png 650w, //korben.info/wp-content/uploads/2017/09/2017-09-19-11-16-53-113x200.png 113w, //korben.info/wp-content/uploads/2017/09/2017-09-19-11-16-53-768x1365.png 768w, //korben.info/wp-content/uploads/2017/09/2017-09-19-11-16-53-576x1024.png 576w, //korben.info/wp-content/uploads/2017/09/2017-09-19-11-16-53-475x844.png 475w, //korben.info/wp-content/uploads/2017/09/2017-09-19-11-16-53-750x1333.png 750w, //korben.info/wp-content/uploads/2017/09/2017-09-19-11-16-53-400x711.png 400w, //korben.info/wp-content/uploads/2017/09/2017-09-19-11-16-53.png 1242w" sizes="(max-width: 343px) 100vw, 343px" /></a></p>
<p style="text-align: center;"><a href="http://korben.info/wp-content/uploads/2017/09/scan-e1505897213285.png"><img class="aligncenter wp-image-88741 " src="http://korben.info/wp-content/uploads/2017/09/scan-e1505897213285-650x1135.png" alt="" width="341" height="595" srcset="//korben.info/wp-content/uploads/2017/09/scan-e1505897213285-650x1135.png 650w, //korben.info/wp-content/uploads/2017/09/scan-e1505897213285-115x200.png 115w, //korben.info/wp-content/uploads/2017/09/scan-e1505897213285-768x1341.png 768w, //korben.info/wp-content/uploads/2017/09/scan-e1505897213285-586x1024.png 586w, //korben.info/wp-content/uploads/2017/09/scan-e1505897213285-475x830.png 475w, //korben.info/wp-content/uploads/2017/09/scan-e1505897213285-750x1310.png 750w, //korben.info/wp-content/uploads/2017/09/scan-e1505897213285-400x699.png 400w, //korben.info/wp-content/uploads/2017/09/scan-e1505897213285.png 1242w" sizes="(max-width: 341px) 100vw, 341px" /></a></p>
<p>Concernant les emails, Skeep permet aussi, stats à l'appui de voir à quelles newsletters vous êtes abonnés et vous proposer un désabonnement propre.</p>
<p>Notez que pour le moment, seuls des services email et Facebook sont proposés. L'équipe de Skeep a prévu d'intégrer le support de Twitter et Google+ d'ici quelques mois.</p>
<p>Je trouve cette appli plutôt bien fichue et indispensable pour reprendre la main sur ses données personnelles sans y passer trop de temps. Je vous invite à la tester.</p>
<p>Vous pouvez <a href="https://www.skeep.co/">télécharger Skeep ici pour Android et iPhone</a>.</p>
<p>Cet article merveilleux et sans aucun égal intitulé : <a rel="nofollow" href="https://korben.info/skeep-controler-vos-donnees-personnelles-facilement.html">Skeep &#8211; Contrôler vos données personnelles facilement</a> ; a été publié sur <a rel="nofollow" href="https://korben.info">Korben</a>, le seul site qui t'aime plus fort que tes parents.</p>
<hr><p>Même si vous êtes vigilant concernant vos données personnelles, il y a toujours un moment où vous relâchez la pression... Un petit coup de Facebook Connect par ci, un petit coup de "J'inscris mon email" par là...etc. Et de fil en aiguille, année après année, sans même sans rendre compte, ce sont des centaines de <a class="read-more" href="https://korben.info/skeep-controler-vos-donnees-personnelles-facilement.html">> Lire la suite</a></p>
<p>Cet article merveilleux et sans aucun égal intitulé : <a rel="nofollow" href="https://korben.info/skeep-controler-vos-donnees-personnelles-facilement.html">Skeep &#8211; Contrôler vos données personnelles facilement</a> ; a été publié sur <a rel="nofollow" href="https://korben.info">Korben</a>, le seul site qui t'aime plus fort que tes parents.</p>


guid: https://blog.genma.fr/?Yunohost-et-les-applications-Framasoft
title: Yunohost et les applications Framasoft
author: Genma
url: https://blog.genma.fr/?Yunohost-et-les-applications-Framasoft
feedurl: https://blog.genma.fr/spip.php?page=backend
content:
<img class='spip_logo spip_logo_right spip_logos' alt="" style='float:right' src='https://blog.genma.fr/IMG/arton2681.jpg?1502297294' width='150' height='79' />
		<div class='rss_texte'><p>Comme je le disais dans mon billet et ma conférence <a href="https://blog.genma.fr/?De-Framasoft-a-Yunohost-reapproprions-nous-le-cloud" title="De Framasoft à Yunohost, réapproprions nous le cloud">De Framasoft à Yunohost, réapproprions nous le cloud</a> un partenariat avait été mis en place entre Framasoft et Yunohost avec du temps d'un salarié de Framasoft consacré au packaging d'application Framasoft pour Yunohost.</p>
<p><strong>Quelques mois après, où en est-on ?</strong></p>
<p>L'idée n'est pas de parler au nom de Framasoft mais plus de remettre en avant cette collaboration et de faire un petit suivi de l'avancement. Une image valant mieux qu'un long discours :</p>
<p><span class='spip_document_2509 spip_documents spip_documents_center'>
<img src='https://blog.genma.fr/IMG/png/yunohost_degooglisons.png?1502296864' width='500' height='69' alt="" /></span></p>
<p>On peut donc voir qu'il reste donc encore des applications à packagées, il faut maintenir les packages existant (en les faisant évoluer pour que les applications installées sur une instance Yunohost soient mises à jour ou qu'une installation fraîche installe la dernière version de l'application...)</p>
<p>Si vous souhaitez aider, si vous avez un peu de temps ou tout simplement des retours d'expérience à faire, <a href="https://forum.yunohost.org/t/applications-framasoft/1680" title="Applications framasoft pour Yunohost">il y a un topic dédié dans le forum Yunohost sur le sujet.</a></p>
<p><strong>Contribuez à Yunohost</strong></p>
<p>D'une façon plus générale, Yunohost a besoin de contributeurs pour tous les aspects du projet. A savoir :
<br /><img src='https://blog.genma.fr/local/cache-vignettes/L8xH11/puce-32883.gif?1494182300' width='8' height='11' class='puce' alt="-" /> backend : python (simple), bash (lua)
<br /><img src='https://blog.genma.fr/local/cache-vignettes/L8xH11/puce-32883.gif?1494182300' width='8' height='11' class='puce' alt="-" /> frontend : html/js (sammy.js)
<br /><img src='https://blog.genma.fr/local/cache-vignettes/L8xH11/puce-32883.gif?1494182300' width='8' height='11' class='puce' alt="-" /> packging des apps : full bash, et des connaissance en sysadmin sont nécessaires (configuration nginx)
<br /><img src='https://blog.genma.fr/local/cache-vignettes/L8xH11/puce-32883.gif?1494182300' width='8' height='11' class='puce' alt="-" /> sécurité : revue de code
<br /><img src='https://blog.genma.fr/local/cache-vignettes/L8xH11/puce-32883.gif?1494182300' width='8' height='11' class='puce' alt="-" /> infrastructure du projet : debian, deb toolchain, ruby
<br /><img src='https://blog.genma.fr/local/cache-vignettes/L8xH11/puce-32883.gif?1494182300' width='8' height='11' class='puce' alt="-" /> relation avec la communauté : communication, support via le forum, dans les issues de Git...
<br /><img src='https://blog.genma.fr/local/cache-vignettes/L8xH11/puce-32883.gif?1494182300' width='8' height='11' class='puce' alt="-" /> aide à la traduction et à la documentation
<br /><img src='https://blog.genma.fr/local/cache-vignettes/L8xH11/puce-32883.gif?1494182300' width='8' height='11' class='puce' alt="-" /> testing (les versions beta) avec rapport de bugs
<br /><img src='https://blog.genma.fr/local/cache-vignettes/L8xH11/puce-32883.gif?1494182300' width='8' height='11' class='puce' alt="-" /> ...</p></div>
		
		<hr>
<p>Comme je le disais dans mon billet et ma conférence De Framasoft à Yunohost, réapproprions nous le cloud un partenariat avait été mis en place entre Framasoft et Yunohost avec du temps d'un salarié de Framasoft consacré au packaging d'application Framasoft pour Yunohost. <br class='autobr' />
Quelques mois après, où en est-on ? <br class='autobr' />
L'idée n'est pas de parler au nom de Framasoft mais plus de remettre en avant cette collaboration et de faire un petit suivi de l'avancement. Une image valant mieux qu'un long discours : <br class='autobr' />
On peut (...)</p>


-
<a href="https://blog.genma.fr/?-Autohebergement-" rel="directory">Autohébergement</a>

/ 
<a href="https://blog.genma.fr/?+-Yunohost-+" rel="tag">Yunohost</a>, 
<a href="https://blog.genma.fr/?+-Framasoft-+" rel="tag">Framasoft</a>, 
<a href="https://blog.genma.fr/?+-Planet-Libre-+" rel="tag">Planet Libre</a>

		


guid: https://blog.genma.fr/?Il-y-a-un-an-Ma-lettre-de-motivation
title: Il y a un an - Ma lettre de motivation
author: Genma
url: https://blog.genma.fr/?Il-y-a-un-an-Ma-lettre-de-motivation
feedurl: https://blog.genma.fr/spip.php?page=backend
content:
<img class='spip_logo spip_logo_right spip_logos' alt="" style='float:right' src='https://blog.genma.fr/IMG/arton2678.jpg?1502290260' width='150' height='79' />
		<div class='rss_texte'><p>Dans le cadre des entretiens que je suis amené à faire passé et c'est la plupart du temps du très classique et conventionnel, parfois même minimaliste. Il manque le petit plus, le côté qui apporte quelque chose. J'avais d'ailleurs fait un billet sur le sujet <a href="https://blog.genma.fr/?Ou-sont-les-passionne-e-s" title="Où sont les passionné.e.s ?">Où sont les passionné.e.s ?</a> (qui m'a permit de faire de belles rencontres dont deux ont abouties sur des embauches de personnes qui travailleront dans mon équipe).</p>
<p>Dans le présent billet je voudrais tout simplement copier coller le contenu de ma lettre de motivation que j'avais envoyé à la mi-septembre 2016 et qui avait conduit à mon entretien et à mon changement de vie.</p>
<p>Cette lettre, elle avait été travaillée et retravaillée un certain nombre de fois, depuis des mois, car je cherchais un nouvel emploi depuis le début de l'année et j'avais eu quelques retours et entretiens ; j'en profitais alors pour la remanier.</p>
<p>Pour moi, cette lettre se voulait complémentaire de mon CV complet (que je fournissais). Avec CV (de deux pages) et cette lettre de motivation (qui fait un format A4), je joignais aussi un résumé de carrière, complémentaire du CV qui expliquait en une page A4 le parcours, la cohérence entre les différentes missions de ma carrière et mon parcours personnel. Ce résumé (qu'on retrouvera ci-dessous) présentais donc à la fois mon parcours professionnel et mon parcours personnel sous pseudonyme. Je liais alors définitivement les deux comme je l'ai expliqué dans mon billet <a href="https://blog.genma.fr/?Du-pseudonymat-au-pseudonyme" title="Du pseudonymat au pseudonyme">Du pseudonymat au pseudonyme</a>.</p>
<p>Avec ces trois documents, j'estimais donner ainsi toutes les informations nécessaires aux recruteurs, ce qui permettait d'avoir un entretien où on savait déjà qui j'étais, ce que je prétendais savoir faire, mon parcours.. Cela a permis une discussion plus directe et me semble donc avoir été bénéfique.</p>
<p><strong>Voici donc ma lettre</strong></p>
<p>Par la présente lettre, je vous présenterai mes motivations et aspirations quand à ma candidature que je présente à Linagora.</p>
<p><strong>Ce que je recherche ?</strong><br class='autobr' />
Je suis arrivé à un moment de ma vie où j'ai besoin de travailler et mobiliser mes compétences pour des valeurs qui me sont chères, pour m'épanouir au sein de mon travail, dans un cadre motivant et avec une équipe qui me tire vers le haut et me permet d'exploiter mon plein potentiel. Je souhaite en particulier pouvoir travailler avec le système d'exploitation de mon choix (Debian ou Ubuntu) sur des technologies à base de logiciel libre - open-source. Et je pense que Linagora répond à ces différents critères.</p>
<p>Pour moi, l'informatique est un outil destiné à répondre aux besoins "métiers" du client. Le cœur de son métier n'étant pas l'informatique, nous pouvons l'accompagner dans la mise en place des meilleures solutions afin de satisfaire ses impératifs tout en respectant ses contraintes. Je considère que l'informaticien doit être l'interface entre le client et les architectes, développeurs et autres équipes techniques spécialisées, en leur donnant des directives précises, ciblées et faisant appel à leur meilleur niveau de technicité.<br class='autobr' />
Je recherche donc un poste dans de la MOA, avec à la fois du relationnel et de l'accompagnement client, et de la gestion d'équipe technique et développeur.</p>
<p><strong>Ce que je peux apporter à Linagora ?</strong></p>
<p>Mon expérience. Mes parcours professionnel et personnel sont présentés dans le document ci-joint et mon CV, mais en quelques mots, il y a mon expérience de consultant et la maturité acquise au cours de mes 11 années passées au sein de Capgemini. Et mon expérience du monde du logiciel libre et de l'open-source, étant donné que je suis un utilisateur, autodidacte, depuis plus de 12 ans, impliqué au sein de différentes communautés du logiciel libre.</p>
<p>Mon expérience de consultant et ma maturité dans ce domaine, tout comme mon expérience personnelle riche dans le monde du logiciel libre, ma capacité de communication écrite et mon aisance orale, seront des atouts pour Linagora. Avoir quelqu'un qui puisse comprendre les besoins du client, les exprimer en spécifications fonctionnelles et techniques, qui sachent présenter aux clients les avantages et spécificités des produits open-source et plus particulièrement ceux de Linagora, la plus value qu'à Linagora pour mener à bien les projets informatiques des clients, les accompagner dans leur transition informatique. Cette personne, c'est moi.</p>
<p>De plus j'ai une très forte capacité d'adaptabilité. Selon les besoins du moment, les temps forts, je pourrais également intervenir pour faire de la revue de code, tester des applications, rédiger des cahiers des charges. Je pourrais contribuer à de la localisation d'applications, valider l'accessibilité des tutoriaux d'installation, aider à leur amélioration. Je pourrais aider à la gestion et aux interactions avec les différentes communautés de l'open-source et du logiciel libre...</p>
<p><strong>Me contacter ?</strong></p>
<p>Je vois, de mon point de vue, plein de choses diverses et variées au sein desquelles je pourrais m'épanouir pleinement, contribuant au déploiement et au rayonnement de Linagora... Si ma présentation et mon profil vous intéressent, je me tiens disponible pour répondre aux questions éventuelles, donner des informations complémentaires et m'entretenir avec des membres de Linagora.<br class='autobr' />
Jérôme « Genma »</p>
<p><strong>Résumé de carrière</strong></p>
<p><strong>Résumé de carrière</strong></p>
<p>Voici un résumé de carrière qui apporte quelques précisions sur mon parcours. J'ai donc commencé ma carrière en 2005 chez Capgemini en tant que consultant AMOA. Le client était l'Etablissement Français du Sang et ma mission a consisté à assurer le suivi de la migration (du lancement du projet au suivi en garantie en passant par la mise en production) de leur logiciel métier au sein de différentes régions. J'ai travaillé sur l'accompagnement et la conduite du changement, les reprises des données, le suivi du projet... J'ai en particulier été sensibilisé aux problématiques des données personnelles médicales et à l'importance de la cohérence et de l'intégrité de ces dernières.</p>
<p>De 2008 à 2011, j'ai été développeur junior sur les technologies Java/J2EE, dans le cadre d'un grand projet pour la Direction générale des Finances publiques (DGFiP) puis le Ministère de l'Education Nationale.</p>
<p>Entre 2011 et 2013, j'ai travaillé sur un petit projet d'évolution d'un logiciel métier pour la société Sécuritas. Ce travail consistait en l'accompagnement du client dans la rédaction des spécifications en langue anglaise, le développement de ces dernières en .NET/C# ou la gestion du développement en offshore (au Vietnam) avec revue de code et recettes, la tenue et le suivi des réunions parfois en anglais. Le tout en méthodologie AGIL.</p>
<p>Depuis mars 2013, je suis sur une TMA d'un projet aux technologies obsolètes (.NET 1.1, PL/SQL, VBS). Sur ce projet, j'ai effectué la rédaction des spécifications et des évolutions fonctionnelles. Pour palier les problématiques des pannes matérielles, j'ai participé à la virtualisation des serveurs (Windows Server 2003) sous VMWare ESX.</p>
<p><strong>Résumé du parcours personnel</strong></p>
<p>A titre personnel, depuis plus de 12 ans, je suis intéressé par les nouvelles technologies (je fais beaucoup de veille sur ces sujets) et l'open-source. J'utilise GNU/Linux comme système d'exploitation pour mon serveur (Debian) et mon desktop (Ubuntu). Je suis impliqué au sein de différentes communautés (Mozilla, CozyCloud, Yunohost, Debian, Framasoft). Je participe à des install-party, je fais de l'auto-hébergement (administration système et devops), du support, je donne régulièrement des conférences (Ubuntu-Party, JDLL de Lyon, Capitole du Libre de Toulouse, ou encore en médiathèque parisienne) Je rédige des tutoriels, un peu de documentation et surtout un blog, depuis plus de 12 ans sur lequel je synthétise et partage toutes mes connaissances nouvellement acquises : <a href="https://blog.genma.fr" class='spip_url spip_out auto' rel='nofollow'>https://blog.genma.fr</a>.</p>
<p>Je m'intéresse également aux technologies liées au chiffrement, à la virtualisation, au Cloud, ainsi qu'aux problématiques concernant les données personnelles et la vie privée (par exemple, je suis un utilisateur de Tor dont je suis les développements et évolutions, j'utilise TrueCrypt - maintenant Veracrypt - depuis 2008, je chiffre mes mails avec GPG, je chiffre mes disques durs (Luks), pour ne citer que ces technologies). Je suis sensible aux problématiques des fuites de données, de pentest, de hacking, de failles de sécurité, d'injection SQL et autres techniques utilisées par les attaquants potentiels. Je coanime des café vie privée / cryptoparty, et je donne à ce titre des cours et des conférences dans des domaines qui vont de l'hygiène numérique (pour le grand public, sensibilisation à différentes problématiques autour des données personnelles..) à l'autodéfense numérique (formation de journalistes aux techniques de chiffrement, par exemple).</p></div>
		
		<hr>
<p>Dans le cadre des entretiens que je suis amené à faire passé et c'est la plupart du temps du très classique et conventionnel, parfois même minimaliste. Il manque le petit plus, le côté qui apporte quelque chose. J'avais d'ailleurs fait un billet sur le sujet Où sont les passionné.e.s ? (qui m'a permit de faire de belles rencontres dont deux ont abouties sur des embauches de personnes qui travailleront dans mon équipe). <br class='autobr' />
Dans le présent billet je voudrais tout simplement copier coller le contenu de ma (...)</p>


-
<a href="https://blog.genma.fr/?-Blog-35-" rel="directory">Blog</a>

/ 
<a href="https://blog.genma.fr/?+-Les-reflexions-du-Genma-+" rel="tag">Les réflexions du Genma</a>

		


guid: urn:md5:0660aa98820eb35869479d5dd689c7fb
title: Pas toujours facile de promouvoir le libre quand on n'est pas convaincu
author: alterlibriste
feedurl: http://alterlibriste.free.fr/index.php?feed/atom
url:
http://alterlibriste.free.fr/index.php?post/2017/09/18/Pas-toujours-facile-de-promouvoir-le-libre-quand-on-n-est-pas-convaincu

content:
<p><img src="http://ici.radio-canada.ca/mesAbonnements/baladodiffusion/img/lasphere_itunes.jpg" alt="" /></p> <p>Encore un billet un peu sous forme de dépêche, mais il va falloir oublier quelque temps les longues réflexions, car je n&rsquo;ai ni vraiment l&rsquo;envie, ni vraiment le temps. Je préfère profiter du temps plutôt agréable pour aller faire du sport dehors. Même la lecture de mes flux rss est plus ou moins expédiée sans m&rsquo;attarder sur les annonces de versions, les billets techniques ni les aspects sécurité.</p>


<p>Je n&rsquo;en reste pas moins dans la mouvance libriste et continue d&rsquo;écouter les podcasts traitant le sujet de près ou de loin. Je signale donc que l&rsquo;émission canadienne (<a href="http://alterlibriste.free.fr/index.php?post/2014/12/01/Podcasting-%3A-La-Sph%C3%A8re">précédemment chroniquée</a>) <a href="http://ici.radio-canada.ca/premiere/emissions/la-sphere/episodes/389873/logiciels-libres">traitait ce week-end des logiciels libres</a>. Bon, pour des addicts aux iPhone et aux réseaux sociaux de masse, ça sonnait un peu faux et il y a même eu une petite remarque assez désobligeante comme quoi les développeurs faisaient d&rsquo;abord du libre pour se faire un CV avant d&rsquo;intégrer les grosses boîtes privatrices.</p>


<p>La partie la plus intéressante était celle consacré à Purism avec ses machines libres : laptop et futur téléphone. Ce dernier fait pas mal parler de lui, à voir s&rsquo;il fera mieux que la tentative ratée de Canonical ; ils en sont actuellement à 30 % de <a href="https://puri.sm/shop/librem-5/">leur campagne de financement</a>, 35 jours avant la fin. Il y a une demande mais à ce prix (600 $) et avec un tel délai (presque un an et demi), il faut être motivé !</p>


<p>La fin de l&rsquo;émission a été consacrée aux CHATONS de Framasoft que l&rsquo;on ne présente plus ici. Encore une fois, ça sentait un peu l&rsquo;œuvre de charité, <q>pourquoi quitter le monde Google quand on s&rsquo;y sent si bien et que tout y est tellement mieux fait&thinsp;?</q>, avouent certains intervenants.</p>


<p>Cela me fait penser que finalement, tous ceux qui relaient ce genre d&rsquo;informations se donnent en quelque sorte bonne conscience en montrant qu&rsquo;une alternative existe pour ceux qui se plaignent des géants du web. Encore faudrait-il avoir le courage de ses opinions et parfois accepter un peu moins de clinquant pour plus de liberté.</p>


<p>EDIT du 22/09&nbsp;: la critique concerne l&rsquo;attitude de quelques animateurs de l&rsquo;émission qui regardaient le libre du haut de leurs habitudes propriétaires, pas du tout vis-à-vis de l&rsquo;intervention de Jean-François FORTIN TAM venu défendre les avancées des technologies et logiciels libres <a href="https://forumsdulibre.quebec/t/une-emission-sur-le-logiciel-libre-infrastructure-et-materiel-libre-a-radio-canada-lors-de-la-jill-2017/80">au pied levé</a>.</p>


guid: https://shaar.libox.fr/?lwDDqA
title: Introducing Atom-IDE | blog.atom.io
url: http://blog.atom.io/2017/09/12/announcing-atom-ide.html
feedurl: https://shaar.libox.fr/?do=atom
content:
<div class="markdown"><p>&#8212; <a href="https://shaar.libox.fr/?lwDDqA" title="Permalink">Permalink</a></p></div>


guid: https://shaar.libox.fr/?UWSt9Q
title: Cas d’usage de Last | Fiat Tux
url: https://fiat-tux.fr/2017/09/16/cas-dusage-de-last/
feedurl: https://shaar.libox.fr/?do=atom
content:
<div class="markdown"><blockquote>
<p>Last est un logi­ciel que j’ai codé il y a peu. Il veut dire « Let’s Aggre­gate Superb Toots » et permet de créer un site à partir d’une liste de pouets (toots en anglais, c’est le terme dési­gnant les mini-articles du réseau social libre et décen­tra­lisé Masto­don).<br />
&#8212; <a href="https://shaar.libox.fr/?UWSt9Q" title="Permalink">Permalink</a></p>
</blockquote></div>


guid: https://shaar.libox.fr/?FSPyWA
title: Reprenez le contrôle de vos feuilles de style avec Sass • Tutoriels • Zeste de Savoir
url: https://zestedesavoir.com/tutoriels/672/reprenez-le-controle-de-vos-feuilles-de-style-avec-sass/
feedurl: https://shaar.libox.fr/?do=atom
content:
<div class="markdown"><p>Via river.<br />
&#8212; <a href="https://shaar.libox.fr/?FSPyWA" title="Permalink">Permalink</a></p></div>


guid: https://shaar.libox.fr/?by3fRQ
title: Web Concepts
url: http://webconcepts.info/
feedurl: https://shaar.libox.fr/?do=atom
content:
<div class="markdown"><blockquote>
<p>The Web's &quot;Uniform Interface&quot; is based on a large and growing set of specifications. These specifications establish the shared concepts that providers and consumers of Web services can rely on. Web Concepts is providing an overview of these concepts and of the specifications defining them.</p>
</blockquote>
<p>Via <a href="https://mastodon.gougere.fr/users/bortzmeyer/updates/47434">https://mastodon.gougere.fr/users/bortzmeyer/updates/47434</a><br />
&#8212; <a href="https://shaar.libox.fr/?by3fRQ" title="Permalink">Permalink</a></p></div>


guid: https://shaar.libox.fr/?HFdMSA
title: 作品一覧 | 日本アニメーション映画クラシックス
url: http://animation.filmarchives.jp/works
feedurl: https://shaar.libox.fr/?do=atom
content:
<div class="markdown"><blockquote>
<p>Le Centre Cinématographique du Musée d'Art Moderne de Tokyo met en accès libre des dizaines de vieux dessins animés!</p>
</blockquote>
<p>Via <a href="https://twitter.com/Bouletcorp/status/909360721342947329">https://twitter.com/Bouletcorp/status/909360721342947329</a><br />
&#8212; <a href="https://shaar.libox.fr/?HFdMSA" title="Permalink">Permalink</a></p></div>


guid: https://shaar.libox.fr/?yknN8w
url: https://github.com/rdlugosz/zfs-check
feedurl: https://shaar.libox.fr/?do=atom
title:
GitHub - rdlugosz/zfs-check: Simple shell script to be used with cron to monitor for a degraded ZFS Pool state.

content:
<div class="markdown"><blockquote>
<p>This is an extremely simple script that will return the output of zpool status if the word DEGRADED or FAULTED is seen when running the zpool status command.<br />
&#8212; <a href="https://shaar.libox.fr/?yknN8w" title="Permalink">Permalink</a></p>
</blockquote></div>


guid: https://shaar.libox.fr/?CoVRPg
title: Brest Death Experience – Partage Solidarité
url: http://www.partage-solidarite.fr/2017/09/17/brest-death-experience/
feedurl: https://shaar.libox.fr/?do=atom
content:
<div class="markdown"><p>&#8212; <a href="https://shaar.libox.fr/?CoVRPg" title="Permalink">Permalink</a></p></div>


guid: https://shaar.libox.fr/?a-D1TQ
title: Useful Excel Tricks that Will Impress Your Boss - Make Tech Easier
url: https://www.maketecheasier.com/useful-excel-tricks/
feedurl: https://shaar.libox.fr/?do=atom
content:
<div class="markdown"><p>&#8212; <a href="https://shaar.libox.fr/?a-D1TQ" title="Permalink">Permalink</a></p></div>


guid: https://shaar.libox.fr/?Ts6xzw
title: Comment utiliser les Gitlab Pages ? · GitBook
url: https://docs.framasoft.org/fr/gitlab/gitlab-pages.html
feedurl: https://shaar.libox.fr/?do=atom
content:
<div class="markdown"><blockquote>
<p>Les Gitlab Pages permettent à qui possède un compte sur <a href="https://framagit.org">https://framagit.org</a> (qui utilise Gitlab) de publier un site statique sur notre infrastructure, soit en sous-domaine de frama.io (par exemple : <a href="https://luc.frama.io">https://luc.frama.io</a>) soit avec un domaine rien qu'à vous.<br />
&#8212; <a href="https://shaar.libox.fr/?Ts6xzw" title="Permalink">Permalink</a></p>
</blockquote></div>


guid: https://shaar.libox.fr/?c_Qz1g
title: Ryanair annule des centaines de vols... pour respecter ses objectifs de ponctualité - Les Echos
feedurl: https://shaar.libox.fr/?do=atom
url:
https://www.lesechos.fr/industrie-services/tourisme-transport/030574491727-ryanair-annule-des-centaines-de-vol-pour-respecter-ses-objectifs-de-ponctualite-2114853.php#xtor=RSS37

content:
<div class="markdown"><blockquote>
<p>Ryanair annule des centaines de vols... pour respecter ses objectifs de ponctualité<br />
&#8212; <a href="https://shaar.libox.fr/?c_Qz1g" title="Permalink">Permalink</a></p>
</blockquote></div>


guid: https://shaar.libox.fr/?Q6ypMw
title: Le salarié qui refuse de remettre immédiatement une clé USB personnelle n’est pas fautif
feedurl: https://shaar.libox.fr/?do=atom
url:
https://www.nextinpact.com/news/105193-le-salarie-qui-refuse-remettre-immediatement-cle-usb-personnelle-nest-pas-fautif.htm

content:
<div class="markdown"><blockquote>
<p>La Cour de cassation vient de confirmer que le fait de ne pas remettre immédiatement à son employeur une clé USB personnelle ne pouvait être considéré comme une faute, même si l’on est suspecté d’avoir copié des fichiers internes à l’entreprise.<br />
&#8212; <a href="https://shaar.libox.fr/?Q6ypMw" title="Permalink">Permalink</a></p>
</blockquote></div>


guid: https://shaar.libox.fr/?jiacgA
title: Arch-Anywhere
url: https://arch-anywhere.org/news/Anarchy-Linux-replaces-Arch-Anywhere/
feedurl: https://shaar.libox.fr/?do=atom
content:
<div class="markdown"><blockquote>
<p>Arch Anywhere is no more due to a potential trademark violation pointed out by the Arch Linux(TM) team. I have decided to remove the name &quot;Arch&quot; entirely and go in the direction of my own Arch Linux(TM) based distrobution called Anarchy. The installer will remain the same and will still offer a full Arch base install with additional packages offered from the Arch official repos. The name Arch Anywhere will be migrated entirely over the next few days, along with the logo (new logo is now up).</p>
</blockquote>
<p>Via <a href="https://links.angristan.fr/?jBs0tQ">https://links.angristan.fr/?jBs0tQ</a><br />
&#8212; <a href="https://shaar.libox.fr/?jiacgA" title="Permalink">Permalink</a></p></div>


guid: https://shaar.libox.fr/?I9uIEg
feedurl: https://shaar.libox.fr/?do=atom
title:
Guillaume Meurice : “L'insulte d'Henry de Lesquen, c’est ma légion d’honneur !” - Sortir - Télérama.fr

url:
http://www.telerama.fr/sortir/guillaume-meurice-se-faire-insulter-par-henry-de-lesquen,-cest-ma-legion-dhonneur,n5203310

content:
<div class="markdown"><p>Via <a href="https://chaos.social/@SammyFisherJr/2187462">https://chaos.social/@SammyFisherJr/2187462</a><br />
&#8212; <a href="https://shaar.libox.fr/?I9uIEg" title="Permalink">Permalink</a></p></div>


guid: https://shaar.libox.fr/?QfoyLw
title: L’enfance du codeur : Tout le piratage | CommitStrip
url: http://www.commitstrip.com/fr/2017/09/18/childhood-of-a-coder-pirate-all-the-things/
feedurl: https://shaar.libox.fr/?do=atom
content:
<div class="markdown"><p><img src="https://www.commitstrip.com/wp-content/uploads/2017/09/Strip-Lenfance-du-codeur-Le-piratage-650-final2.jpg" alt="" /><br />
&#8212; <a href="https://shaar.libox.fr/?QfoyLw" title="Permalink">Permalink</a></p></div>


guid: https://shaar.libox.fr/?K6a6rg
title: La révolution, chacun dans son coin
url: https://www.franceinter.fr/emissions/le-moment-meurice/le-moment-meurice-18-septembre-2017
feedurl: https://shaar.libox.fr/?do=atom
content:
<div class="markdown"><blockquote>
<p>Guillaume Meurice a décidé de prendre la révolution en main, car il trouve que ça ne va pas assez vite. Il s'est donc rendu à la fête de l'Huma pour rencontrer les camarades.<br />
&#8212; <a href="https://shaar.libox.fr/?K6a6rg" title="Permalink">Permalink</a></p>
</blockquote></div>


guid: https://shaar.libox.fr/?G98N0Q
title: Allumer une led avec un Raspberrypi. Partie I un peu de théorie - Pansebete
feedurl: https://shaar.libox.fr/?do=atom
url:
https://pansebete.net/?d=2013/09/22/07/09/32-allumer-une-led-avec-un-raspberrypi-partie-i-un-peu-de-theorie

content:
<div class="markdown"><blockquote>
<p>Le Raspberrypi dispose d'un connecteur GPIO qui lui permet d'interagir avec le monde extérieur. Cet article est le premier d'un série qui devrait conduire à expliquer la réalisation d'un vrai objet utilisable. Pour cela, il va falloir faire un peu d'électronique. Pour rassurez ceux qui pensent que c'est trop difficile, sachez que je ne connaissais pas grand chose à l'électronique avant de commencer ce petit projet. J'ai cependant quelques notions en électricité, que j'essaye de présenter dans ce premier article. Ceux qui connaissent déjà le domaine ou qui n'aime pas la théorie peuvent passer directement à l'article suivant. Pour ces derniers, il sera toujours temps d'y revenir pour bien comprendre.<br />
&#8212; <a href="https://shaar.libox.fr/?G98N0Q" title="Permalink">Permalink</a></p>
</blockquote></div>


guid: https://shaar.libox.fr/?o5G8KQ
title: Vi Cheat Sheet
url: http://www.lagmonster.org/docs/vi.html
feedurl: https://shaar.libox.fr/?do=atom
content:
<div class="markdown"><p>&#8212; <a href="https://shaar.libox.fr/?o5G8KQ" title="Permalink">Permalink</a></p></div>


guid: https://shaar.libox.fr/?YaQbLw
title: 70 ans d’hostilité entre les Corées résumés en cartes
feedurl: https://shaar.libox.fr/?do=atom
url:
http://www.lemonde.fr/les-decodeurs/article/2016/01/08/soixante-dix-ans-d-hostilite-entre-les-corees-resumees-en-cartes-pour-ceux-qui-n-ont-rien-suivi_4844064_4355770.html

content:
<div class="markdown"><p>Très bon, via <a href="https://www.ascadia.net/links/?xJdcZw">https://www.ascadia.net/links/?xJdcZw</a><br />
&#8212; <a href="https://shaar.libox.fr/?YaQbLw" title="Permalink">Permalink</a></p></div>


guid: https://shaar.libox.fr/?iaIBbQ
title: Virtualisation VMware, NSX présentation (partie 1) - VXLAN | alainfaure.net
url: http://alainfaure.net/2017/09/19/virtualisation-vmware-nsx-presentation-partie-1-vxlan/
feedurl: https://shaar.libox.fr/?do=atom
content:
<div class="markdown"><blockquote>
<p>Voici une série d’articles d’introduction sur NSX pour aller plus en profondeur dans la technique et ainsi faciliter la lecture des autres articles de ce blog consacrés à l’aspect réseau et communication autour de VMware.<br />
&#8212; <a href="https://shaar.libox.fr/?iaIBbQ" title="Permalink">Permalink</a></p>
</blockquote></div>


guid: https://shaar.libox.fr/?sip_Jw
feedurl: https://shaar.libox.fr/?do=atom
title:
Le dernier épisode de South Park s'est servi d'Amazon Echo et de Google Home pour rendre fou les téléspectateurs

url:
http://www.journaldugeek.com/2017/09/15/le-dernier-episode-de-south-park-sest-servi-damazon-echo-et-de-google-home-pour-rendre-fou-les-telespectateurs/

content:
<div class="markdown"><blockquote>
<p>South Park est loin d’en être à sa première facétie. Mais cette fois, la série de Trey Parker et Matt Stone a décidé d’aller plus loin en titillant les téléspectateurs directement chez eux. En effet, l’épisode diffusé hier sur Comedy Central a activé sciemment les Google Home et les Amazon Echo des fans.<br />
&#8212; <a href="https://shaar.libox.fr/?sip_Jw" title="Permalink">Permalink</a></p>
</blockquote></div>


guid: https://shaar.libox.fr/?_wvEow
title: Saint-Martin-des-Champs. L’arcade en croisade chez Pierre et Mélaine !
feedurl: https://shaar.libox.fr/?do=atom
url:
https://www.ouest-france.fr/bretagne/morlaix-29600/saint-martin-des-champs-l-arcade-en-croisade-chez-pierre-et-melaine-5255356

content:
<div class="markdown"><blockquote>
<p>C’est l’histoire d’un couple passionné d’arcade, ces bornes de jeux vidéos que l’on trouvait dans tous les bars, dans les années 90. Un monde qu’ils font revivre dans le sous-sol de leur maison, avec l’asso First Attack.<br />
&#8212; <a href="https://shaar.libox.fr/?_wvEow" title="Permalink">Permalink</a></p>
</blockquote></div>


guid: https://shaar.libox.fr/?3en9nA
title: Sur quoi reposent nos infrastructures numériques ? – Framabook
url: https://framabook.org/sur-quoi-reposent-nos-infrastructures-numeriques/
feedurl: https://shaar.libox.fr/?do=atom
content:
<div class="markdown"><blockquote>
<p>Comprendre pourquoi nous devons soutenir l’open source<br />
&#8212; <a href="https://shaar.libox.fr/?3en9nA" title="Permalink">Permalink</a></p>
</blockquote></div>


guid: https://shaar.libox.fr/?eRptlw
title: How to Auto-Run Windows Programs When You Plug In a USB Drive
url: https://www.howtogeek.com/326049/how-to-auto-run-windows-programs-when-you-plug-in-a-usb-drive/
feedurl: https://shaar.libox.fr/?do=atom
content:
<div class="markdown"><blockquote>
<p>APO USB Autorun is a program that monitors USB drives as they’re plugged in, looking for the legacy autorun.inf script file and launching any programs directed within. Download it from Softpedia here, then double-click the installer file and install it like any other program.<br />
&#8212; <a href="https://shaar.libox.fr/?eRptlw" title="Permalink">Permalink</a></p>
</blockquote></div>


guid: https://shaar.libox.fr/?v2opGA
title: L'auto-hébergement facile · GitBook
url: https://framacloud.org/fr/auto-hebergement/
feedurl: https://shaar.libox.fr/?do=atom
content:
<div class="markdown"><blockquote>
<p>Puisqu’on n’est jamais mieux servi que par soi-même, créez l’internet que vous voulez<br />
&#8212; <a href="https://shaar.libox.fr/?v2opGA" title="Permalink">Permalink</a></p>
</blockquote></div>


guid: https://shaar.libox.fr/?qRdjbw
title: {samedi 30 septembre 2017} #installparty au centre social des Abeilles de Quimper « Linux Quimper
url: https://linuxquimper.org/3184/3184/
feedurl: https://shaar.libox.fr/?do=atom
content:
<div class="markdown"><blockquote>
<p>Le samedi 30 septembre 2017 de 14h à 18h le Centre des Abeilles 4 rue Sergent Le Flao à Quimper (plan d’accès) invite Linux Quimper à organiser une « Install Party ».<br />
&#8212; <a href="https://shaar.libox.fr/?qRdjbw" title="Permalink">Permalink</a></p>
</blockquote></div>


guid: https://shaar.libox.fr/?5SFfcQ
title: Cemu Emulator
url: http://cemu.info/#download
feedurl: https://shaar.libox.fr/?do=atom
content:
<div class="markdown"><blockquote>
<p>Highly experimental software to emulate Wii U applications on PC<br />
&#8212; <a href="https://shaar.libox.fr/?5SFfcQ" title="Permalink">Permalink</a></p>
</blockquote></div>


guid: https://shaar.libox.fr/?L851Eg
title: [Tutoriel] Démonter proprement un cluster Proxmox VE - Zwindler's Reflection
url: https://blog.zwindler.fr/2017/09/19/tutoriel-demonter-proprement-cluster-proxmox-ve/
feedurl: https://shaar.libox.fr/?do=atom
content:
<div class="markdown"><p>&#8212; <a href="https://shaar.libox.fr/?L851Eg" title="Permalink">Permalink</a></p></div>


guid: https://shaar.libox.fr/?0UICTg
title: ONU. Trump menace de "détruire totalement" la Corée du Nord - Monde - LeTelegramme.fr
feedurl: https://shaar.libox.fr/?do=atom
url:
http://www.letelegramme.fr/monde/onu-trump-menace-de-detruire-totalement-la-coree-du-nord-19-09-2017-11669825.php

content:
<div class="markdown"><blockquote>
<p>Le président américain Donald Trump a menacé ce mardi devant l'ONU de &quot;détruire totalement&quot; la Corée du Nord, un &quot;régime vicieux&quot; et &quot;corrompu&quot;, si les Etats-Unis ou leurs alliés étaient confrontés à une attaque de Pyongyang.<br />
&#8212; <a href="https://shaar.libox.fr/?0UICTg" title="Permalink">Permalink</a></p>
</blockquote></div>


guid: https://shaar.libox.fr/?pbRfcA
title: GLPI : générer automatiquement un ticket au changement de statut d’un ordinateur
feedurl: https://shaar.libox.fr/?do=atom
url:
https://www.dsfc.net/logiciel-libre/glpi/glpi-generer-automatiquement-ticket-changement-statut-ordinateur/

content:
<div class="markdown"><blockquote>
<p>GLPI : générer automatiquement un ticket au changement de statut d’un ordinateur<br />
&#8212; <a href="https://shaar.libox.fr/?pbRfcA" title="Permalink">Permalink</a></p>
</blockquote></div>


guid: https://shaar.libox.fr/?uUlXDw
title: Toute l’équipe est sur le pont | CommitStrip
url: http://www.commitstrip.com/fr/2017/09/19/the-whole-teams-working-on-it/
feedurl: https://shaar.libox.fr/?do=atom
content:
<div class="markdown"><p><img src="https://www.commitstrip.com/wp-content/uploads/2017/09/Strip-La-super-%C3%A9quipe-de-maintenance-650-final.jpg" alt="" /><br />
&#8212; <a href="https://shaar.libox.fr/?uUlXDw" title="Permalink">Permalink</a></p></div>


guid: https://shaar.libox.fr/?rJPBag
feedurl: https://shaar.libox.fr/?do=atom
title:
Mini-Transat. Petit bateau, petit confort pour le Roscovite Stéphane Gresset - Roscoff - LeTelegramme.fr

url:
http://www.letelegramme.fr/finistere/roscoff/mini-transat-petit-bateau-petit-confort-pour-le-roscovite-stephane-gresset-19-09-2017-11669895.php

content:
<div class="markdown"><p>&#8212; <a href="https://shaar.libox.fr/?rJPBag" title="Permalink">Permalink</a></p></div>


guid: https://shaar.libox.fr/?5TlrOg
title: Solférino. Le PS a décidé de mettre en vente son siège parisien - France - LeTelegramme.fr
feedurl: https://shaar.libox.fr/?do=atom
url:
http://www.letelegramme.fr/france/solferino-le-ps-a-decide-de-mettre-en-vente-son-siege-parisien-19-09-2017-11669914.php

content:
<div class="markdown"><blockquote>
<p>Le Parti socialiste a pris la &quot;décision de principe de mettre en vente&quot; son siège de la rue de Solférino à Paris, pour des raisons financières et symboliques, a annoncé son trésorier Jean-François Debat ce mardi soir.<br />
&#8212; <a href="https://shaar.libox.fr/?5TlrOg" title="Permalink">Permalink</a></p>
</blockquote></div>


guid: https://shaar.libox.fr/?cynKFw
title: Communauté Steam :: Annonces du groupe :: Steam Blog
url: http://steamcommunity.com/games/593110/announcements/detail/1448326897426987372
feedurl: https://shaar.libox.fr/?do=atom
content:
<div class="markdown"><p>Suite au bordel provoqué par un certain con de streamer, Valve répond.<br />
&#8212; <a href="https://shaar.libox.fr/?cynKFw" title="Permalink">Permalink</a></p></div>


guid: https://shaar.libox.fr/?Ox-s1A
title: Project Honolulu : La future GUI pour administrer Windows Server | | Logiciel - OS | IT-Connect
url: https://www.it-connect.fr/project-honolulu-la-future-gui-pour-administrer-windows-server/
feedurl: https://shaar.libox.fr/?do=atom
content:
<div class="markdown"><blockquote>
<p>L'avenir de l'administration est sans aucun doute dans le scripting, notamment avec PowerShell pour l'automatisation. Néanmoins, l'interface graphique n'est pas morte ! Elle est bien pratique notamment pour visualiser les données et comparer différents systèmes entre eux.<br />
&#8212; <a href="https://shaar.libox.fr/?Ox-s1A" title="Permalink">Permalink</a></p>
</blockquote></div>


guid: https://shaar.libox.fr/?6C7ISQ
title: 832 TB – ZFS on Linux – Configuring Storage: Part 3 | JonKensy.com
url: http://www.jonkensy.com/832-tb-zfs-on-linux-configuring-storage-part-3/
feedurl: https://shaar.libox.fr/?do=atom
content:
<div class="markdown"><p>&#8212; <a href="https://shaar.libox.fr/?6C7ISQ" title="Permalink">Permalink</a></p></div>


guid: https://shaar.libox.fr/?yXmYog
title: Run Linux containers on Windows | Ubuntu tutorials
url: https://tutorials.ubuntu.com/tutorial/tutorial-windows-ubuntu-hyperv-containers#0
feedurl: https://shaar.libox.fr/?do=atom
content:
<div class="markdown"><blockquote>
<p>It is now possible to run Docker containers on Windows 10 and Windows Server, leveraging Ubuntu as a hosting base.<br />
Imagine running your own Linux applications on Windows, using a Linux distribution you are comfortable with: Ubuntu!<br />
It is now possible to do so using the power of Docker technology and Hyper-V virtualization on Windows.</p>
</blockquote>
<p>Via <a href="https://www.it-connect.fr/les-containers-ubuntu-debarque-sur-windows/">https://www.it-connect.fr/les-containers-ubuntu-debarque-sur-windows/</a><br />
&#8212; <a href="https://shaar.libox.fr/?yXmYog" title="Permalink">Permalink</a></p></div>


guid: https://shaar.libox.fr/?wYxCKw
title: What Is VMware User Environment Manager? - ESX Virtualization
url: https://www.vladan.fr/what-is-vmware-user-environment-manager/
feedurl: https://shaar.libox.fr/?do=atom
content:
<div class="markdown"><blockquote>
<p>VMware User Environment Manager (UEM) is a product from a company called Immidio, which has been acquired by VMware in February 2015. After some time, VMware has released VMware User Environment Manager, which helps IT admins with profile management and setting up dynamic policies (also called “Smart Policies”. We’ll see that later).<br />
&#8212; <a href="https://shaar.libox.fr/?wYxCKw" title="Permalink">Permalink</a></p>
</blockquote></div>


guid: https://shaar.libox.fr/?PGuwwA
title: OsmAnd Local Indexes List
url: http://download.osmand.net/rawindexes/
feedurl: https://shaar.libox.fr/?do=atom
content:
<div class="markdown"><blockquote>
<p>Osmand Local Indexes List</p>
</blockquote>
<p>Via <a href="https://framapiaf.org/@sametmax/2700772">https://framapiaf.org/@sametmax/2700772</a><br />
&#8212; <a href="https://shaar.libox.fr/?PGuwwA" title="Permalink">Permalink</a></p></div>


guid: https://dooby.fr/links/?En6OQg
title: Change default network name (ens33) to old “eth0” on Ubuntu 16.04
url: https://dooby.fr/links/?En6OQg
feedurl: https://dooby.fr/links/?do=atom
content:
<div class="markdown"><pre><code>GRUB_CMDLINE_LINUX="net.ifnames=0 biosdevname=0"
</code></pre>
<p>fuck that shit</p>
<p>sans oublier de renommer les cartes dans <code>/etc/network/interfaces</code>  et aussi de mettre en <code>auto eth0</code> au lieu de <code>allow-hotplug eth0</code><br />
&#8212; <a href="http://www.itzgeek.com/how-tos/mini-howtos/change-default-network-name-ens33-to-old-eth0-on-ubuntu-16-04.html" title="Direct link">Direct link</a></p></div>


guid: http://sebsauvage.net/links/?T6o7fw
title: Waking Up - Fowl Language Comics
url: http://www.fowllanguagecomics.com/comic/waking-up/
feedurl: http://sebsauvage.net/links/?do=atom
content:
Oh mais c'est tellement ça ! &gt;&lt;<br>(<a href="http://sebsauvage.net/links/?T6o7fw">Permalink</a>)


guid: http://sebsauvage.net/links/?LzARTw
title: Remplacer avantageusement Shutter par HotShots | Cenwen's Blog
url: https://linuxevolution.wordpress.com/2017/09/16/remplacer-avantageusement-shutter-par-hotshots/
feedurl: http://sebsauvage.net/links/?do=atom
content:
J'utilise habituellement Shutter pour les captures d'écran. Il faudra peut-être que j'essaie HotShots.<br />
<br />
PS: Pour capturer des vidéos du bureau, je trouve que Kazam fait un excellent boulot.<br>(<a href="http://sebsauvage.net/links/?LzARTw">Permalink</a>)


guid: http://sebsauvage.net/links/?p7UmLw
title: Njalla — A privacy aware domain registration service
url: https://njal.la/#about
feedurl: http://sebsauvage.net/links/?do=atom
content:
Sous le coude: un vendeur de noms de domaine qui met l'accent sur la protection de l'identité et la vie privée des acheteurs de domaines.<br />
Ça peut être utile.<br />
Note: Selon les registry (donc selon les TLD: .com/.net/.eu/.fr...) les règles de confidentialité et de diffusion des identités dans les registres DNS diffèrent.<br />
Votre nom, prénom, adresse et téléphone peuvent se retrouver exposés.<br>(<a href="http://sebsauvage.net/links/?p7UmLw">Permalink</a>)


guid: http://sebsauvage.net/links/?LDUdGg
title: Sigal - Simple Static Gallery Generator — Sigal 1.3.0 documentation
url: http://sigal.saimon.org/en/latest/
feedurl: http://sebsauvage.net/links/?do=atom
content:
J'ai testé ce générateur de galeries photo statique (donc il génère juste du html+css+js+images, pas de code exécutable côté serveur), et il marche très bien.<br />
Quelques avantages:<br />
- il est vraiment très rapide (il exploite les multi-cœurs).<br />
- il ne met à jour que ce qui est nécessaire.<br />
- la navigation js est vraiment très bien (avec le thème colorbox).<br />
- on peut naviguer dans la galerie au clavier (flèches droite/gauche).<br />
- le thème colorbox passe remarquablement bien sur mobiles.<br />
- on peut commenter les galeries en markdown.<br />
- on peut lui faire afficher un lien vers l'image original (j'y tiens).<br />
<br />
Je préfère habituellement MinigalNano comme galerie (<a href="http://sebsauvage.net/wiki/doku.php?id=minigal_nano" rel="nofollow">http://sebsauvage.net/wiki/doku.php?id=minigal_nano</a>) , mais Sigal peut être utile quand vous voulez juste servir du contenu statique.<br />
<br />
Il y a 3 thèmes fournis:<br />
Colorbox : <a href="http://saimon.org/sigal-demo/colorbox/" rel="nofollow">http://saimon.org/sigal-demo/colorbox/</a><br />
Galleria : <a href="http://saimon.org/sigal-demo/galleria/" rel="nofollow">http://saimon.org/sigal-demo/galleria/</a><br />
Photoswipe : <a href="http://saimon.org/sigal-demo/photoswipe/" rel="nofollow">http://saimon.org/sigal-demo/photoswipe/</a><br>(<a href="http://sebsauvage.net/links/?LDUdGg">Permalink</a>)


guid: http://sebsauvage.net/links/?0vFdFg
title: Sales petits mouchards !: Quand les téléphones enregistrent les visages
url: http://sebsauvage.net/links/?0vFdFg
feedurl: http://sebsauvage.net/links/?do=atom
content:
Sur beaucoup de téléphones récents, les applications vous proposent de &quot;taguer&quot; les visages des amis (Facebook, Google+). Certains fabricants (comme Samsung) propose également cela dans leur galerie photo, et incluent souvent aussi la possibilité de déverrouiller votre téléphone avec votre visage, ou encore de temporiser le verrouillage automatique de l'écran s'il l'appareil détecte votre visage en train de regarder l'écran (fonction SmartStay).<br />
<br />
Pour cela, la plupart de ces applications utilisent un répertoire-cache contenant des miniatures des visages. Regardez donc à la racine du stockage de votre téléphone (pas sur la carte SD) si vous n'auriez pas un répertoire &quot;.face&quot;: Ces fichiers sans extensions (d'environ 7 ko) sont en fait des .jpg. (Il vous suffit de les renommer en .jpg pour voir le contenu.)<br />
<br />
A titre d'exemple, sur les téléphones Samsung, quelques minutes après avoir pris une photo (ou l'avoir simplement téléchargée d'internet), le téléphone va détecter les visages et en faire une copie dans ce répertoire. (Constaté sur un Samsung Galaxy S5 neo sous Android 6.0.1)<br />
<br />
Là où ça deviant glauque, c'est que non seulement on ne sait pas trop ce qu'en font ces applications, mais même en les désactivant toutes (Déverrouillage par visage, fonction SmartStay, désactivation de la gallerie Samsung....) ces foutus fichiers continuent être créés. &nbsp;:-(((<br />
<br />
Solution bourrin:<br />
- supprimez le répertoire &quot;.face&quot;<br />
- copier un fichier non vide à la racine et renommez-le en &quot;.face&quot;<br />
<br />
Et voilà, le système ne pourra plus créer ce répertoire.<br />
<br />
J'aurais aimé trouver une réponse officielle de Samsung (ou autre) sur ce répertoire... mais rien.<br />
Est-ce que les informations de détection des visages quittent votre téléphone ? &nbsp;Je n'en sais rien.<br />
Tout cela est probablement lié à l'API de détection des visages de Google: <a href="https://developer.android.com/reference/android/media/FaceDetector.html" rel="nofollow">https://developer.android.com/reference/android/media/FaceDetector.html</a><br />
<br />
Mainenant étant donné que Google a aussi accès à votre position géographique (dès le moment où GoogleMaps est installé sur votre téléphone, et même si vous ne l'utilisez pas), cela veut dire qu'ils sont capables de constituer une grosse base de données indiquant QUI était OÙ et QUAND. Tout cela de manière **totalement automatisée**, à partir du simple moment où vous appairaissez sur une photo, même en arrière-plan.<br />
Je ne dis pas qu'ils le font, mais qu'ils ont tout ce qu'il faut pour le faire.<br>(<a href="http://sebsauvage.net/links/?0vFdFg">Permalink</a>)


guid: http://sebsauvage.net/links/?swSfeg
url: https://boingboing.net/2017/09/18/antifeatures-for-all.html
feedurl: http://sebsauvage.net/links/?do=atom
title:
World Wide Web Consortium abandons consensus, standardizes DRM with 58.4% support, EFF resigns / Boing Boing

content:
Donc le W3C - déjà très critiqué - n'est plus. Il n'y a plus de compromis, des décisions ont été passées en force, et l'appel de l'EFF (le premier dans l'histoire W3C) a été rejeté.<br />
Le W3C a donné aux majors ce qu'ils voulaient: Le champ libre pour bourrer le web de DRM.<br />
Le web ouvert - celui qui a permis tout l'innovation actuelle - est mort.<br />
(Et l'EFF a claqué la porte du W3C.)<br>(<a href="http://sebsauvage.net/links/?swSfeg">Permalink</a>)


guid: http://sebsauvage.net/links/?oaJ9ZQ
title: Clickbait : l'actu version putaclic - Le racolage sur la voie publique c'est mal
url: http://www.clickbait.fr/
feedurl: http://sebsauvage.net/links/?do=atom
content:
Un site qui recence les titres les plus putaclic. <br />
(via <a href="http://www.ballajack.com/les-meilleurs-titres-racoleurs-pour-faire-mousser-son-site" rel="nofollow">http://www.ballajack.com/les-meilleurs-titres-racoleurs-pour-faire-mousser-son-site</a>)<br>(<a href="http://sebsauvage.net/links/?oaJ9ZQ">Permalink</a>)


guid: http://sebsauvage.net/links/?KSIWTA
title: Microsoft menace la sécurité de l’Etat « Youpress
url: http://youpress.fr/2017/09/microsoft-menace-la-securite-de-letat/
feedurl: http://sebsauvage.net/links/?do=atom
content:
Ah oui c'est quand même bien catastrophique et scandaleux.<br />
(via <a href="http://www.sammyfisherjr.net/Shaarli/?0YhJBQ" rel="nofollow">http://www.sammyfisherjr.net/Shaarli/?0YhJBQ</a>)<br>(<a href="http://sebsauvage.net/links/?KSIWTA">Permalink</a>)


guid: http://sebsauvage.net/links/?Iv3P8A
feedurl: http://sebsauvage.net/links/?do=atom
title:
Le dernier épisode de South Park s'est servi d'Amazon Echo et de Google Home pour rendre fou les téléspectateurs

url:
http://www.journaldugeek.com/2017/09/15/le-dernier-episode-de-south-park-sest-servi-damazon-echo-et-de-google-home-pour-rendre-fou-les-telespectateurs/

content:
Rhô putain je suis mort de rire ! &nbsp;C'est trop bon !<br />
(via <a href="http://www.sammyfisherjr.net/Shaarli/?ghar9Q" rel="nofollow">http://www.sammyfisherjr.net/Shaarli/?ghar9Q</a>)<br>(<a href="http://sebsauvage.net/links/?Iv3P8A">Permalink</a>)


guid: http://sebsauvage.net/links/?afiYRw
title: MachiaVillain sur Steam
url: http://store.steampowered.com/app/555510/MachiaVillain/
feedurl: http://sebsauvage.net/links/?do=atom
content:
Ohhh.... &nbsp;RimWorld/DwarfFortress rencontre Dungeon Keeper ? &nbsp;Je garde un oeil sur ce jeu. &nbsp;&lt;3<br>(<a href="http://sebsauvage.net/links/?afiYRw">Permalink</a>)


guid: http://sebsauvage.net/links/?GNEr9g
title: Calculatrice de durée (addition ou soustraction)
url: https://www.ma-calculatrice.fr/calculatrice-temps.php
feedurl: http://sebsauvage.net/links/?do=atom
content:
Une page web toute simple pour faire des additions et soustractions d'heures.<br>(<a href="http://sebsauvage.net/links/?GNEr9g">Permalink</a>)


guid: https://www.ecirtam.net/opennews/?m6Jwew
title: Pour fermer 25 réacteurs nucléaires, il faudra réduire la consommation d’électricité
url: https://reporterre.net/Pour-fermer-25-reacteurs-nucleaires-il-faudra-reduire-la-consommation-d
feedurl: https://www.ecirtam.net/opennews/?do=atom
content:
«un selfie Facebook peut consommer autant que quatre ampoules de 20 watts alimentées pendant une heure. Le stockage des photos, de films et de vidéos et le secteur en devenir des milliards d’objets connectés ne nous conduisent guère vers la sobriété.»<br>(<a href="https://www.ecirtam.net/opennews/?m6Jwew">Permalink</a>)


guid: https://www.ecirtam.net/opennews/?5uWx_w
title: Infographie les chiffres clés de la bio - Basta !
feedurl: https://www.ecirtam.net/opennews/?do=atom
content: (<a href="https://www.ecirtam.net/opennews/?5uWx_w">Permalink</a>)
url:
https://www.bastamag.net/Une-carte-interactive-pour-trouver-des-produits-bio-et-locaux-pres-de-chez-vous


guid: https://www.ecirtam.net/opennews/?WY4n2A
title: Emmanuel Macron invente le « travail jetable » - Attac France
feedurl: https://www.ecirtam.net/opennews/?do=atom
content: (<a href="https://www.ecirtam.net/opennews/?WY4n2A">Permalink</a>)
url:
https://france.attac.org/se-mobiliser/loi-travail-xxl-c-est-toujours-non/article/emmanuel-macron-invente-le-travail-jetable


guid: https://www.ecirtam.net/opennews/?rHNkEA
feedurl: https://www.ecirtam.net/opennews/?do=atom
content: (<a href="https://www.ecirtam.net/opennews/?rHNkEA">Permalink</a>)
title:
Une IA peut détecter les changements cérébraux causés par Alzheimer avec 10 ans d&#039;avance - Sciences - Numerama

url:
http://www.numerama.com/sciences/290254-une-ia-peut-detecter-les-changements-cerebraux-causes-par-alzheimer-avec-10-ans-davance.html


guid: 20170919205550-article
title: PolitiScales ?
url: https://lehollandaisvolant.net/?d=2017/09/19/20/55/50-politiscales
feedurl: https://lehollandaisvolant.net/rss.php
content:
<p>Un site (re)-fait surface en ce moment sur les rézosocio® : <a href="https://discordlacommune.github.io/politiscales/">PolitiScales</a>.</p>

<p>Après une centaine de questions, il est censé vous donner votre orientation politique, basé sur 6 axes différents. J’ai fait le test, les résultats sont <a href="https://discordlacommune.github.io/politiscales/results.html?b1=5&amp;b0=79&amp;c0=24&amp;c1=50&amp;e1=33&amp;e0=36&amp;j0=52&amp;j1=19&amp;p0=40&amp;p1=31&amp;s0=76&amp;s1=5&amp;t0=38&amp;t1=38&amp;m0=55&amp;m1=12&amp;femi=14&amp;prag=100&amp;comp=67">là</a>.</p>

<p>*judging hard*</p>

<p>Nul doute que ce genre de test a été fait avec un certains sérieux, mais je persiste à trouver dommage de résumer les idées d’une personne sur seulement 6 points.<br />
Je pense qu’il y a 7 milliards d’êtres humains sur la Terre et donc 7 milliards d’orientations politiques également.</p>

<p>Il n’y a pas 6 nuances de gris, <a href="http://lehollandaisvolant.net/?d=2015/10/17/15/29/33-la-verite-est-une-nuance-de-gris">mais une infinité de couleurs</a>.</p>

<p>Au delà de ça, je note quand même quelques trucs.<br />
Ça par exemple :</p>

<blockquote>La philosophie et les idéologies en générales sont mises de coté au profit de la gestion.</blockquote>

<p>En gros, regarder les problèmes au cas par cas plutôt qu’appliquer des méthodes toutes prêtes issues d’un bouquin.</p>

<p>C’est la raison d’être d’un tribunal présidé par des gens. On ne vit pas dans un État où un crime appelle à une punition toute faite, mais où chaque personne paye en fonction de ce qu’il est. Une même conséquence, mais avec des causes différentes appelle naturellement à des jugements différents (par exemple, c’est pour ça que l’on distingue l’homicide involontaire (ie un accident) de l’homicide volontaire (meurtre) de l’assassinat (prémédité) : le résultat est le même (une personne est tuée) mais pas les conséquences).</p>

<p>Pour le reste, ça confirme ce que je sais déjà : à l’exception notable de l’idée d’abolir les frontières politiques (pas culturelles : cultiver ses différences reste selon moi une force) et de celles d’accepter le progrès et le changement plutôt que s’encrasser dans les traditions qui ne fonctionne pas, je suis plutôt centriste avec une grande part d’incertitude sur chaque question (justement parce que je trouve que « ça dépend » ; ie le pragmatisme ; ie la phrase ci-dessus).</p>

<p>Par contre je ne comprends pas leur système de drapeaux. Encore un moyen de se coller mutuellement des étiquettes sur la tronche dans le but de se taper dessus ?</p>

<p>S’il ne devait en rester un, mon seul drapeau serait le drapeau <a href="http://lehollandaisvolant.net/?d=2016/05/24/18/29/50-code-des-pirates">Pirate</a>, mais là aussi, il n’est pas vraiment nécessaire ni utile car il y en a plein de différents (et faire des groupes à un seul membre à chaque fois, c’est un peu idiot).</p>

<p>Non pas pour le violence et le rhum, mais pour le côté « refus d’un système injuste » et « recherche d’un idéal personnalisé et <a href="https://lehollandaisvolant.net/?d=2013/10/01/23/39/17-je-regarde-des-idees-pas-ceux-qui-les-ont">concocté de mon propre coté</a> en piochant le meilleur où il se trouve sans regarder son origine ».</p>

<p>… et par conséquent avec une grosse dose de « <em>j’en ai rien à foutre d’avoir du monde à mes côté. Qui m’aime me suive, et les autres je vous encourage à voguer ailleurs si ça vous rend plus heureux : ce monde est assez vaste pour que chacun y construise ses idéaux</em> ».</p>


guid: http://orangina-rouge.org:80/shaarli/?rqnnWw
title: L'Armée des Douze Singes de Terry Gilliam (Libre Savoir)
url: http://www.libresavoir.org/index.php?title=L%27Arm%C3%A9e_des_Douze_Singes_de_Terry_Gilliam
feedurl: http://orangina-rouge.org/shaarli/?do=rss
content:
<div class="markdown"><p>Héhé, bonne analyse de ce film.<br />
Et pour conclure sans spoiler, je dois dire qu'il faut bien regarder les derniers moments du film pour se donner une bonne idée.<br />
&#8212; <a href="http://orangina-rouge.org:80/shaarli/?rqnnWw" title="Permalink">Permalink</a></p></div>


guid: http://orangina-rouge.org:80/shaarli/?1UhSvg
title: Rufus - Créez une clé USB démarrable/bootable ISO de manière facile
url: https://rufus.akeo.ie/?locale=fr_FR
feedurl: http://orangina-rouge.org/shaarli/?do=rss
content:
<div class="markdown"><p>Tiens faudrait que j'y jette un oeil.<br />
&#8212; <a href="http://orangina-rouge.org:80/shaarli/?1UhSvg" title="Permalink">Permalink</a></p></div>


guid: http://orangina-rouge.org:80/shaarli/?qfmYKw
title: Citation: « Quand tu n'as pas les bons moyens, il ta faut utiliser les bonnes méthodes. »
url: http://orangina-rouge.org:80/shaarli/?qfmYKw
feedurl: http://orangina-rouge.org/shaarli/?do=rss
content:
<div class="markdown"><p>&#8212; <a href="http://orangina-rouge.org:80/shaarli/?qfmYKw" title="Permalink">Permalink</a></p></div>


guid: http://orangina-rouge.org:80/shaarli/?sFFpYQ
title: learn-regex/README-fr.md at master · zeeshanu/learn-regex · GitHub
url: https://github.com/zeeshanu/learn-regex/blob/master/README-fr.md
feedurl: http://orangina-rouge.org/shaarli/?do=rss
content:
<div class="markdown"><p>learn-regex - Learn regex the easy way<br />
&#8212; <a href="http://orangina-rouge.org:80/shaarli/?sFFpYQ" title="Permalink">Permalink</a></p></div>


guid: http://orangina-rouge.org:80/shaarli/?9km1qQ
title: Codever - Manifestations sportives sur la voie publique : les règles changent
url: https://www.codever.fr/actu/1278-manifestations-sportives-sur-la-voie-publique--les-regles-changent
feedurl: http://orangina-rouge.org/shaarli/?do=rss
content:
&gt; Cinquante participants véhicules pour les concentrations de véhicules à moteur : voici les nouveaux seuils du régime de la déclaration préalable. Très attendu, le décret n° 2017-1279 du 9...<br />
<br />
Pratique ça! <br />
<br />
Avec le texte #quivabien : <a href="https://www.legifrance.gouv.fr/eli/decret/2017/8/9/INTD1708130D/jo/texte">https://www.legifrance.gouv.fr/eli/decret/2017/8/9/INTD1708130D/jo/texte</a>
<br>&#8212; <a href="http://orangina-rouge.org:80/shaarli/?9km1qQ" title="Permalink">Permalink</a>


guid: 26a6f288d2b9af9e5d0a71313e66b78f
title: Criticism of Israel
author: Richard Stallman
url: https://stallman.org/archives/2017-jul-oct.html#20_September_2017_%28Criticism_of_Israel%29
feedurl: https://www.stallman.org/rss/
content:
<p>
The City of Munich plans to
<a href="http://www.kibush.co.il/show_file.asp?num=76632">
equate opposition to the occupation of
Palestine with anti-Semitism,
</a>
and forbid speakers in municipal
auditoriums from criticizing the occupation.


guid: d781993a84ee6118cda5aeded3222a68
title: Palestinians on hunger strike
author: Richard Stallman
feedurl: https://www.stallman.org/rss/
url:
https://stallman.org/archives/2017-jul-oct.html#20_September_2017_%28Palestinians_on_hunger_strike%29

content:
<p>
Once again,
<a href="http://imemc.org/article/three-detainees-currently-holding-hunger-strikes/">
Palestinians imprisoned without charge in Israel are on
hunger strike.
</a>
<p>
Imprisonment without trial is itself tyranny.


guid: d8466a0ece1a9cd4ab99a32c7411512d
title: Spouses of Palestinians
author: Richard Stallman
url: https://stallman.org/archives/2017-jul-oct.html#20_September_2017_%28Spouses_of_Palestinians%29
feedurl: https://www.stallman.org/rss/
content:
<p>
Israel is
<a href="http://mondoweiss.net/2017/09/issuing-foreigners-palestinians/">
squeezing out foreigners married to Palestinians.
</a>


guid: c6a90a2f8190be5273766eebe018f2e9
title: Palestinian political rights
author: Richard Stallman
feedurl: https://www.stallman.org/rss/
url:
https://stallman.org/archives/2017-jul-oct.html#20_September_2017_%28Palestinian_political_rights%29

content:
<p>
Ruchama Marton, founder of Physicians for Human Rights-Israel discusses
<a href="https://972mag.com/war-crimes-and-open-wounds-the-physician-who-took-on-israeli-segregation/129700/">
the slaughter of Egyptian soldiers as they surrendered, and the sole
Israeli leader who did not allow torture.
</a>
And many other things.


guid: 613947a94e0a97218dc4cde17a872f56
title: Last-ditch Dontcare bill
author: Richard Stallman
url: https://stallman.org/archives/2017-jul-oct.html#20_September_2017_%28Last-ditch_Dontcare_bill%29
feedurl: https://www.stallman.org/rss/
content:
<p>
Progressives are organizing to
<a href="https://www.commondreams.org/news/2017/09/19/refusing-sit-down-and-shut-trumpcare-opponents-mobilize-against-gop">
stop the last-ditch <a href="/glossary.html#care">Dontcare</a> bill.
</a>


guid: cabb7864f2b3275c1e6c20d20e0b7349
title: Pressure for censorship
author: Richard Stallman
url: https://stallman.org/archives/2017-jul-oct.html#20_September_2017_%28Pressure_for_censorship%29
feedurl: https://www.stallman.org/rss/
content:
<p>
The social network Gab is threatened with
<a href="https://arstechnica.com/tech-policy/2017/09/twitter-rival-gab-faces-domain-loss-over-extremist-content/">
loss of its domain name
</a>
because it didn't censor right-wing insults against Heather Heyer.
<p>
I do not wish to defend those insults in any way, but the pressure for
censorship seems dangerous to me no matter how nasty the material
to be censored.


guid: 92f803302a37a1ac6c2f4c79025d128d
title: Autobahn privatization
author: Richard Stallman
url: https://stallman.org/archives/2017-jul-oct.html#20_September_2017_%28Autobahn_privatization%29
feedurl: https://www.stallman.org/rss/
content:
<p>
Merkel wants to
<a href="https://www.theguardian.com/world/2017/sep/20/row-over-autobahn-renewal-selling-it-off-like-a-second-hand-car-german-election">
privatize Germany's autobahns,
</a>
generating a lot of
opposition.
<p>
The pressure to let rich people own parts of public infrastructure
is a sign of not taxing them enough.


guid: de999bc49d0f315c5f8b3e86ce63aa33
title: The Rohingya crisis
author: Richard Stallman
url: https://stallman.org/archives/2017-jul-oct.html#20_September_2017_%28The_Rohingya_crisis%29
feedurl: https://www.stallman.org/rss/
content:
<p>
Fact Check:
<a href="https://www.theguardian.com/world/2017/sep/20/fact-check-aung-san-suu-kyi-rohingya-crisis-speech-myanmar">
Aung San Suu Kyi's Speech on the Rohingya Crisis.
</a>


guid: 2b235e0c1ddd2fb7d1889fe428e87685
title: Disinformation operation
author: Richard Stallman
url: https://stallman.org/archives/2017-jul-oct.html#20_September_2017_%28Disinformation_operation%29
feedurl: https://www.stallman.org/rss/
content:
<p>
The Russian state calls the movie,
<a href="https://www.theguardian.com/world/2017/sep/20/russia-considers-ban-armando-iannucci-film-death-of-stalin">
The Death of Stalin,
</a>
a disinformation operation.
<p>
Those who have put much effort into a certain kind of wrong also tend
to accuse their enemies of doing it.

Taking legal action against the wave of
<a href="http://reason.com/archives/2017/09/20/unlicensed-guide-tours-not-allowed-in-sa">
licensing requirements for lines
of work that shouldn't require licensing.
</a>


guid: 8fcd38c769d553c7e3206fd65fc2ba80
title: The sex offender list
author: Richard Stallman
url: https://stallman.org/archives/2017-jul-oct.html#21_September_2017_%28The_sex_offender_list%29
feedurl: https://www.stallman.org/rss/
content:
<p>
<a href="http://www.freerangekids.com/why-this-mom-cant-go-to-the-playground-with-her-kids/">More
depredations</a> of the sex offender list.


guid: c56bc84a6649bb06e930bb54868e7aa9
title: The Paris agreement
author: Richard Stallman
url: https://stallman.org/archives/2017-jul-oct.html#21_September_2017_%28The_Paris_agreement%29
feedurl: https://www.stallman.org/rss/
content:
<p>
Naomi Klein Warns Europe
<a href="http://www.truth-out.org/news/item/41973-naomi-klein-warns-europe-may-water-down-paris-accord-to-win-support-from-trump">May
Water Down Paris Accord</a> to Win Support From Trump.
<p>
The Paris agreement pledges were
<a href="https://stallman.org/archives/2015-sep-dec.html#05_September_2015_(Paris_climate_action)">inadequate
from the start</a>.  To forestall global heating disaster, we need to
make them stronger.


guid: b1960b7bff126f112855b3d248f2d34a
title: The Dontcare bill
author: Richard Stallman
url: https://stallman.org/archives/2017-jul-oct.html#21_September_2017_%28The_Dontcare_bill%29
feedurl: https://www.stallman.org/rss/
content:
<p>
The <a href="/glossary.html#care">Dontcare</a> bill would require people with cancer to pay amounts
<a href="https://thinkprogress.org/trumpcare-premium-increase-analysis-150828a5ead6/">$140,000
for treatment</a>.  People with asthma or diabetes would merely face
doubled charges.
<p>
In effect, medical "insurance" would not really cover expensive
procedures, just add the cost to your bills to continue coverage.


guid: 7620da2ffd4a3c869bd7e0252e766485
title: Football
author: Richard Stallman
url: https://stallman.org/archives/2017-jul-oct.html#21_September_2017_%28Football%29
feedurl: https://www.stallman.org/rss/
content:
<p>
One study suggests that Football players that started before age 12
may
<a href="https://www.theguardian.com/us-news/2017/sep/19/children-football-brain-study-boston-university">double
their chance of various mental problems</a> later.


guid: 3197356daf439d1b99169730c369683f
title: Germany's political censorship
author: Richard Stallman
feedurl: https://www.stallman.org/rss/
url:
https://stallman.org/archives/2017-jul-oct.html#21_September_2017_%28Germanys_political_censorship%29

content:
<p>
Germany's political censorship
<a href="http://www.bbc.com/news/blogs-trending-41042266">prohibits
"defamation of religions, religious and ideological associations."</a>
That law already is an injustice, but a new law threatens to make
internet platforms err on the side of censoring more than the law
requires.


guid: 1fa868b0901a2437800108e9a7c64c49
title: Urgent: Oppose the Dontcare bill
author: Richard Stallman
feedurl: https://www.stallman.org/rss/
url:
https://stallman.org/archives/2017-jul-oct.html#21_September_2017_%28Urgent%3A_Oppose_the_Dontcare_bill%29

content:
<p>
US citizens:
<a href="https://www.istandwithpp.org/call">phone your senators</a> to
oppose the <a href="/glossary.html#care">Dontcare</a> bill.


guid: 215faf8fa035a2d4c71e7ed42b8b98f9
title: Veterans For Peace
author: Richard Stallman
url: https://stallman.org/archives/2017-jul-oct.html#21_September_2017_%28Veterans_For_Peace%29
feedurl: https://www.stallman.org/rss/
content:
<p>
Veterans For Peace members <a href="https://www.commondreams.org/newswire/2017/09/18/veteran-group-reacts-first-episode-burnsnovick-vietnam-series">comment</a> on a documentary about the Vietnam
War.


guid: 0d37909181ae326873b7aea00a884694
title: Samim Bigzad
author: Richard Stallman
url: https://stallman.org/archives/2017-jul-oct.html#21_September_2017_%28Samim_Bigzad%29
feedurl: https://www.stallman.org/rss/
content:
<p>
It took <a href="https://www.theguardian.com/uk-news/2017/sep/18/samim-bigzad-asylum-seeker-deported-illegally-to-afghanistan-is-returned-to-uk">four court rulings</a> to overrule UK officials that were
determined to send Samim Bigzad back to Afghanistan. They defied the
first three rulings and sent him back anyway. Once there, he didn't
dare leave his hotel room since the Taliban were looking for him.


guid: 990e32fd199e944a3ae94403ca45392d
title: Turkish embassy thugs
author: Richard Stallman
url: https://stallman.org/archives/2017-jul-oct.html#21_September_2017_%28Turkish_embassy_thugs%29
feedurl: https://www.stallman.org/rss/
content:
<p>
Turkish embassy thugs in Washington DC attacked peaceful protesters
and were properly charged with crimes as a consequence. <a href="/glossary.html#bully">The bully</a>
<a href="https://www.theguardian.com/us-news/2017/sep/19/turkey-trump-erdogan-apology-washington">apologized to ErdoÄan</a> for this!


guid: a2d69f7f8578a359f82ea4a53762ddc9
title: Food in Venezuela
author: Richard Stallman
url: https://stallman.org/archives/2017-jul-oct.html#21_September_2017_%28Food_in_Venezuela%29
feedurl: https://www.stallman.org/rss/
content:
<p>
Food is <a href="https://www.bloomberg.com/news/articles/2017-09-18/weird-food-for-sale-in-venezuela-but-nothing-that-anyone-wants">now available</a> in Venezuela, but not easy to buy. The most
common food items, because of price controls, are hard to find.
Everything else is too expensive for most people.
<p>
(I verified this with a Venezuelan friend.)
<p>
In the long term, Venezuela needs to grow more food.
ChÃ¡vez had a program to encourage that, but it didn't work.


guid: 5533b7d13066dc3e1e8280dc0f7b6aeb
title: Arms Trade Treaty
author: Richard Stallman
url: https://stallman.org/archives/2017-jul-oct.html#21_September_2017_%28Arms_Trade_Treaty%29
feedurl: https://www.stallman.org/rss/
content:
<p>
The US signed the Arms Trade Treaty, but <a href="https://www.commondreams.org/views/2017/09/19/what-happened-arms-trade-treaty">disregards it</a> when its allies
want to attack.


guid: e00f558877beb583ea0f13519364b54d
title: Biofuels
author: Richard Stallman
url: https://stallman.org/archives/2017-jul-oct.html#21_September_2017_%28Biofuels%29
feedurl: https://www.stallman.org/rss/
content:
<p>
Biofuels made from farming crops is <a href="https://www.theguardian.com/sustainable-business/2017/sep/20/demand-for-biofuels-is-increasing-global-food-prices-says-study">competing with people</a> for
food, and poor people are losing out.


guid: 1628a3a4f5ced0cbcb50d5bdb481ce05
title: Hot roads
author: Richard Stallman
url: https://stallman.org/archives/2017-jul-oct.html#21_September_2017_%28Hot_roads%29
feedurl: https://www.stallman.org/rss/
content:
<p>
Parts of the US now get so hot that they <a href="https://arstechnica.com/science/2017/09/were-building-roads-to-withstand-last-centurys-climate/">ruin asphalt roads</a>.
Engineers still design roads using temperature ranges that the US
experienced from 1964 to 1995. Now it is hotter.


guid: 09da4cfae814d1b85886aa16bb1d53b8
title: Catalonia
author: Richard Stallman
url: https://stallman.org/archives/2017-jul-oct.html#21_September_2017_%28Catalonia%29
feedurl: https://www.stallman.org/rss/
content:
<p>
Spain is trying to drive advocacy of independence for Catalonia
off the internet, <a href="https://motherboard.vice.com/en_us/article/gy5qpj/pirate-bay-founder-is-offering-anonymous-hosting-to-fight-government-censorship">blocking access</a> using multiple tactics.
<p>
I have no opinion on the question of Catalan independence, except that
I criticize one of the arguments I've heard cited in favor: that
Catalonia's taxes support poorer regions of Spain. I think that is
right and proper.
<p>
What I think is wrong is that the Euro gives banksters
<a href="https://stallman.org/archives/2012-sep-dec.html#26_November_2012_(Catalonias_referendum_on_secession_from_Spain)">power over Catalonia</a> — and over the rest of Spain too.
But Catalonia seems to envision only a limited independence,
still inside the EU.
<p>
That said, I see the political censorship as very threatening.


guid: 56fda21092f278eabe0d482390e6d0b7
title: Competing for Amazon
author: Richard Stallman
url: https://stallman.org/archives/2017-jul-oct.html#21_September_2017_%28Competing_for_Amazon%29
feedurl: https://www.stallman.org/rss/
content:
<p>
The city that "wins" the competition to get Amazon's new subheadquarters
could pay so much for this that <a href="https://motherboard.vice.com/en_us/article/43aw8q/cities-are-competing-to-give-amazon-the-mother-of-all-civic-giveaways">it has a loss</a> instead of a benefit.
<p>
Even if the cost is not quite that big, the subsidy to Amazon will be
anticompetitive, thus unfair and damaging to society.
<p>
Beyond that, Amazon's operation increases concentration of wealth, and
increases surveillance. That's when it isn't pushing DRM and unjust
EULAs. So don't buy from Amazon, and tell your city and state
governments not to "compete for jobs" by giving companies tax breaks.


guid: 0221b043c149bd2ce28043a344fe95b9
title: Addiction app
author: Richard Stallman
url: https://stallman.org/archives/2017-jul-oct.html#21_September_2017_%28Addiction_app%29
feedurl: https://www.stallman.org/rss/
content:
<p>
There is a proprietary app that can be prescribed as a <a href="https://www.spectrum.ieee.org/the-human-os/biomedical/devices/first-prescription-app-for-substance-abuse-approved-by-fda">treatment for
addiction</a>.
<p>
I fear that in five years people will be ordered by courts
to use a smartphone and run this app or go to jail.
If it were me, I'd say "Put me in jail — I will never carry
a smartphone."


guid: 020059d098842aa039003fdd3db9f9a7
title: Worker exploitation
author: Richard Stallman
url: https://stallman.org/archives/2017-jul-oct.html#21_September_2017_%28Worker_exploitation%29
feedurl: https://www.stallman.org/rss/
content:
<p>
"Exploitation of the vulnerable is <a href="https://www.theguardian.com/commentisfree/2017/sep/20/modern-slavery-misery-uk-exploitation">rampant in Britain</a>, from nail bars
and car washes to building sites, hotels, restaurants and farms."
<p>
In Asia, workers on fishing boats <a href="https://stallman.org/archives/2016-sep-dec.html#29_December_2016_(Slaves_on_Thai_fishing_boats)">are enslaved</a>.
<p>
The article doesn't mention sex workers, but some of them too are
enslaved. Indeed, there is a powerful campaign to ban sex work (or
make it impossible to carry out) on the grounds that some sex workers
are enslaved, while some others are exploited.
<p>
Strangely, no one proposes to put an end to nail bars, car washes,
construction, hotels, restaurants, farms, or fishing boats on the
grounds that some of their workers are enslaved or exploited.
<p>
If the enslavement and exploitation of some workers were a valid
reason to ban sex work, or make it impossible to carry out, why not
for the other fields as well?


guid: 26b2ecb683cd91277252635cbd3e0ba1
title: Banning exercise
author: Richard Stallman
url: https://stallman.org/archives/2017-jul-oct.html#21_September_2017_%28Banning_exercise%29
feedurl: https://www.stallman.org/rss/
content:
<p>
US schools are starting to <a href="http://www.freerangekids.com/school-bans-cartwheels/">ban physical exercise</a> such as cartwheels.
I suspect fear of being sued is a contributing factor somehow.
<p>
It might make sense to forbid practices such as American football,
which cause <a href="https://stallman.org/archives/2012-mar-jun.html#7_May_2012_(NFL_Players)">grave permanent injuries</a> to a large fraction of
participants.
<p>
I have always been timid about physical exercise that struck me
as dangerous. I have never dared to do a cartwheel. But I
think I'd have had a better life if I had not been so timid.


guid: ec00933927841ce19b98b92256600bc7
title: "Protecting" girls
author: Richard Stallman
url: https://stallman.org/archives/2017-jul-oct.html#21_September_2017_%28Protecting_girls%29
feedurl: https://www.stallman.org/rss/
content:
<p>
Insistence on "protecting" girls 
<a href="https://www.theguardian.com/society/2017/sep/20/children-are-straitjacketed-into-gender-roles-in-early-adolescence-says-study">teaches
them that they are weak and vulnerable</a>.


guid: 2479b7fe73e0d677fcbb75f9572b2b3d
title: Catalan referendum on independence
author: Richard Stallman
feedurl: https://www.stallman.org/rss/
url:
https://stallman.org/archives/2017-jul-oct.html#21_September_2017_%28Catalan_referendum_on_independence%29

content:
<p>
The Spanish government is clamping down on the Catalan government to
stop a referendum on independence, 
<a href="https://www.commondreams.org/views/2017/09/20/urgent-forced-takeover-catalan-government-institutions-spanish-police">raiding
various Catalan agencies</a> and arresting some functionaries
specifically for trying to hold the referendum.  Crowds are resisting
this nonviolently.
<p>
It was not clear that the majority would vote for independence, and I
saw no reason to favor it.  But after this I think that no one in
Catalonia will want to argue against it.


guid: fe438916875206fa2116b6c2ac1efb67
title: Cryin'air pilots starting strike
author: Richard Stallman
feedurl: https://www.stallman.org/rss/
url:
https://stallman.org/archives/2017-jul-oct.html#21_September_2017_%28Cryinair_pilots_starting_strike%29

content:
<p>
The pilots of Cryin'air, forced to be "independent contractors" so as
to deny them employees' rights, are 
<a href="https://www.theguardian.com/business/2017/sep/20/more-ryanair-cancellations-likely-as-pilots-reject-offer-to-work-on-days-off">starting
a slowdown strike</a>.


guid: ad1b2080d610c37c1469f9833e33c898
title: Britons' ballooning personal debt
author: Richard Stallman
feedurl: https://www.stallman.org/rss/
url:
https://stallman.org/archives/2017-jul-oct.html#21_September_2017_%28Britons_ballooning_personal_debt%29

content:
<p>
The Tories have squeezed non-rich Britons from every direction at
once, and it came out as 
<a href="https://www.theguardian.com/commentisfree/2017/sep/20/tories-debt-crisis-thatcherite-credit">ballooning
personal debt</a>.
<p>
A state can run a deficit without hurting itself, but individuals
can't do this indefinitely.  With wages so low, they can never pay off
their debts.  Labour should promise to let them shed it through
bankruptcy without disaster.  Screw the banksters instead of the
people!


guid: 3b61137cb2b2fd3b0118a2d5b68e7053
title: Obama cashing in
author: Richard Stallman
url: https://stallman.org/archives/2017-jul-oct.html#21_September_2017_%28Obama_cashing_in%29
feedurl: https://www.stallman.org/rss/
content:
<p>
After Failing to Prosecute Bankers, Obama 
<a href="https://www.commondreams.org/news/2017/09/18/after-failing-prosecute-bankers-obama-cashes-wall-street-speeches">Cashes
In With Wall Street Speeches</a>.


guid: 6f4ea6c935f124d523fd338fe6360dba
title: Troll nominates saboteur for EPA
author: Richard Stallman
feedurl: https://www.stallman.org/rss/
url:
https://stallman.org/archives/2017-jul-oct.html#21_September_2017_%28Troll_nominates_saboteur_for_EPA%29

content:
<p>
The saboteur-in-chief has 
<a href="https://www.theguardian.com/us-news/2017/sep/20/trump-epa-michael-dourson-chemical-safety">nominated
a saboteur to head the EPA's department for chemical safety</a>.  He
has worked persistently for the chemical industry to oppose EPA
regulations.
<p>
<a href="/glossary.html#trump">The troll</a>'s political philosophy is, "If you're rich, you won't live
near any chemical plants.  If you're not rich, your life is not
important."


guid: 495b281febaf7661f99fe1ab7b8fbb06
title: Foster care
author: Richard Stallman
url: https://stallman.org/archives/2017-jul-oct.html#21_September_2017_%28Foster_care%29
feedurl: https://www.stallman.org/rss/
content:
<p>
Children in foster care were usually traumatized by the events that
put them there.  The instability of foster families, combined with the
prejudice they face, 
<a href="https://www.theguardian.com/commentisfree/2017/sep/21/foster-child-young-people-care-parsons-green">tends
to injure them more</a>.
<p>
We could help them better if we taxed the rich more.


guid: edb2db2aff2977999556c65c00f4e93b
title: Welfare
author: Richard Stallman
url: https://stallman.org/archives/2017-jul-oct.html#21_September_2017_%28Welfare%29
feedurl: https://www.stallman.org/rss/
content:
<p>
After centuries of reforms, and investigations of the causes of
poverty, the UK realized that poor people who were making enough at
the moment to live on were constantly in danger that some change would
push them into penury.  The welfare state eliminated that danger.
It 
<a href="https://www.theguardian.com/news/2017/sep/21/why-we-need-the-welfare-state-more-than-ever">needs
to be brought back</a>.
<p>
These lessons apply in general to the US as well, modulo some
differences in the details of welfare between the two countries.


guid: a9786a9ad110816fa4382328980657f8
title: Urgent: Oppose the Dontcare bill
author: Richard Stallman
feedurl: https://www.stallman.org/rss/
url:
https://stallman.org/archives/2017-jul-oct.html#21_September_2017_%28Urgent%3A_Oppose_the_Dontcare_bill%29

content:
<p>
US citizens: Phone your senators to 
<a href="https://act.credoaction.com/call/call_stop_trumpcare/">oppose
to the Dontcare bill</a>.
<p>
The Capitol Switchboard numbers are 202-224-3121, 888-818-6641
and 888-355-3588.


guid: f3bd5f8fe76d0e3cb2c413fd6e9989e3
title: Urgent: End support for bombardment of Yemen
author: Richard Stallman
feedurl: https://www.stallman.org/rss/
url:
https://stallman.org/archives/2017-jul-oct.html#21_September_2017_%28Urgent%3A_End_support_for_bombardment_of_Yemen%29

content:
<p>
US citizens: 
<a href="https://act.rootsaction.org/p/dia/action4/common/public/?action_KEY=13061">Tell
your congresscritter</a> to cut off US support for Salafi Arabia's
bombardment of Yemen.
<p>
To sign this without running nonfree Javascript, use the 
<a href="/salsalabs-method.html">Salsalabs workaround</a>.


guid: df4170cec8a5f37fc0b2c18f629e3de6
title: Dominica after Hurricane Maria
author: Richard Stallman
feedurl: https://www.stallman.org/rss/
url:
https://stallman.org/archives/2017-jul-oct.html#22_September_2017_%28Dominica_after_Hurricane_Maria%29

content:
<p>
In Dominica after Hurricane Maria, few were killed but 
<a href="https://www.theguardian.com/world/2017/sep/21/dominica-daze-hurricane-maria-island-caribbean-rescue">everything
is wrecked</a>.


guid: 3650f65f0f20180414eead35d6d57c7b
title: Religious beliefs and delusions
author: Richard Stallman
feedurl: https://www.stallman.org/rss/
url:
https://stallman.org/archives/2017-jul-oct.html#22_September_2017_%28Religious_beliefs_and_delusions%29

content:
<p>
<a href="https://www.theguardian.com/science/brain-flapping/2017/sep/21/why-religious-belief-isnt-a-delusion-in-psychological-terms-at-least">Distinguishing
between</a> religious beliefs and delusions.
<p>
Comparing knowledge of science with Windows 10 is unfortunate, though.
If Windows is some kind of "knowledge", it would be superstition.


guid: 79068cd21cde7dcef4fbd61a05425d3e
title: "Vietnam syndrome"
author: Richard Stallman
url: https://stallman.org/archives/2017-jul-oct.html#22_September_2017_%28Vietnam_syndrome%29
feedurl: https://www.stallman.org/rss/
content:
<p>
In the 1980s, US militarists bemoaned the "Vietnam syndrome" that 
<a href="https://reason.com/archives/2017/09/21/the-vietnam-syndrome-how-we-lost-it-why">made
the US hesitate to get involved in wars</a>, especially unwinnable
ones.  Too bad the US has "recovered" from this lesson.


guid: 97fdab8f6ccd3fbf7b549254bd46ee5c
title: Mueller's investigation of troll
author: Richard Stallman
feedurl: https://www.stallman.org/rss/
url:
https://stallman.org/archives/2017-jul-oct.html#22_September_2017_%28Muellers_investigation_of_troll%29

content:
<p>
Mueller's investigation of the troll's connections with Russia demands
records on some of the troll's 
<a href="https://www.theguardian.com/us-news/2017/sep/20/robert-mueller-donald-trump-white-house-actions-request">activities
in the White House</a>.


guid: 8aef36879813939fd44391add2966e79
title: Cutting off poor people's electricity
author: Richard Stallman
feedurl: https://www.stallman.org/rss/
url:
https://stallman.org/archives/2017-jul-oct.html#22_September_2017_%28Cutting_off_poor_peoples_electricity%29

content:
<p>
When Bob Crane's electricity was cut off, he began using fires to
cook.  Eventually a fire got out of control and 
<a href="https://www.theguardian.com/uk-news/2017/sep/20/mental-health-trust-pays-damages-over-mans-death-in-tower-block-fire">killed
him</a>.
<p>
Cutting off the electricity of a poor person is an act of stinginess,
typical of an anti-welfare state.


guid: 919ae623aeae1b42d9b449b4ea38f0fd
title: Australian welfare card tracks people
author: Richard Stallman
feedurl: https://www.stallman.org/rss/
url:
https://stallman.org/archives/2017-jul-oct.html#22_September_2017_%28Australian_welfare_card_tracks_people%29

content:
<p>
Distributing welfare payments through a card that 
<a href="https://www.theguardian.com/australia-news/2017/sep/21/cashless-welfare-card-to-be-rolled-out-in-bundaberg-and-hervey-bay">tracks
people</a> is being sold in Australia as a way to stop the money's
being spent on alcohol and drugs.  Apparently it is not very effective
at that, but it surely tracks people effectively.


guid: 9f0373f587fb062cdc0ae9c3c0e56bd2
title: Genital mutilation
author: Richard Stallman
url: https://stallman.org/archives/2017-jul-oct.html#22_September_2017_%28Genital_mutilation%29
feedurl: https://www.stallman.org/rss/
content:
<p>
Trying to help girls of African descent escape genital mutilation by
<a href="https://www.theguardian.com/society/2017/sep/21/fear-racism-label-deter-british-police-tackling-fgm-female-genital-mutilation">informing
them about the issue</a> on exit from the UK.


guid: 482d6ac8cc86fba888407f7522fcdde6
title: Fracking waste
author: Richard Stallman
url: https://stallman.org/archives/2017-jul-oct.html#22_September_2017_%28Fracking_waste%29
feedurl: https://www.stallman.org/rss/
content:
<p>
"Far away from any witnesses, my small town is being 
<a href='https://www.theguardian.com/us-news/2017/sep/21/appalachia-ohio-fracking-wells-toxic'>poisoned
by fracking waste</a>."


guid: 1a64b55aefc4264ae758c94e6db4116f
title: Thugs kill deaf man for ignoring orders
author: Richard Stallman
feedurl: https://www.stallman.org/rss/
url:
https://stallman.org/archives/2017-jul-oct.html#22_September_2017_%28Thugs_kill_deaf_man_for_ignoring_orders%29

content:
<p>
<a href="/glossary.html#thug">Thugs</a> 
<a href="https://www.theguardian.com/us-news/2017/sep/21/oklahoma-city-police-shooting-magdiel-sanchez-deaf">killed
a deaf man who ignored their orders</a>.  Bystanders were shouting
that he was deaf, but they didn't hear.
<p>
A man is 15 feet away from you, holding a pipe.  He has shown no
hostility.  Do you need to shoot him — or is that being on a
hair trigger and jumping the gun?


guid: 00681f113c8beb09808bcca127a83b84
title: Law against solar panels
author: Richard Stallman
url: https://stallman.org/archives/2017-jul-oct.html#23_September_2017_%28Law_against_solar_panels%29
feedurl: https://www.stallman.org/rss/
content:
<p>
Florida's electric company has used its influence on legistators
to obtain laws that
<a href="http://www.miaminewtimes.com/news/miami-frustrated-with-fpl-after-hurricane-irma-9666311">
prohibit people from connecting their solar
panels directly to their electric circuits.
</a>
They are required to go
through the power grid, and when the grid power is down, they can't
use the solar panels either.
<p>
Voting for such laws is an indication of some sort of corruption.


guid: 3ac6d79e019b10af7374f2bccdad05d5
title: Equifax
author: Richard Stallman
url: https://stallman.org/archives/2017-jul-oct.html#23_September_2017_%28Equifax%29
feedurl: https://www.stallman.org/rss/
content:
<p>
The deep problem of Equifax and other credit-reporting companies
is that
<a href="https://www.jacobinmag.com/2017/09/equifax-retail-credit-company-discrimination-loans">
they collect lots of data about people's way of life
and thus facilitate discrimination.
</a>
<p>
In the early days, this was entirely intentional.


guid: 733a67cd2724758858c716da97a6fcbd
title: Preexisting conditions
author: Richard Stallman
url: https://stallman.org/archives/2017-jul-oct.html#23_September_2017_%28Preexisting_conditions%29
feedurl: https://www.stallman.org/rss/
content:
<p>
The new <a href="/glossary.html#care">Dontcare</a> bill pretends to protect people with preexisting conditions,
<a href="https://www.washingtonpost.com/news/the-fix/wp/2017/09/21/pence-just-settled-it-republicans-obamacare-repeal-bill-wont-necessarily-protect-people-with-preexisting-conditions/">
but then it has a loophole to screw them.
</a>


guid: f8feb8c126265010059de92313b2e4aa
title: Crosscheck scheme
author: Richard Stallman
url: https://stallman.org/archives/2017-jul-oct.html#23_September_2017_%28Crosscheck_scheme%29
feedurl: https://www.stallman.org/rss/
content:
<p>
The ACLU and NAACP are suing to
<a href="http://mailchi.mp/gregpalast/v3tjxbfkb4-172685">
stop Illinois from using
the Crosscheck scheme of voter suppression.
</a>
<p>
<a href="https://stallman.org/archives/2016-jul-oct.html#21_September_2016_(Urgent:_Investigation_of_Crosscheck_scheme)">
Here's more information about Crosscheck.
</a>


guid: 619c859bf86a52f16f2557a77c20cadc
title: Racist juror
author: Richard Stallman
url: https://stallman.org/archives/2017-jul-oct.html#23_September_2017_%28Racist_juror%29
feedurl: https://www.stallman.org/rss/
content:
<p>
Georgia courts are ignoring a juror's signed statement that he
<a href="https://www.commondreams.org/views/2017/09/21/keith-tharpes-scheduled-execution-tests-our-tolerance-racial-bias-executions">
voted to convict Keith Tharpe of murder based on racist views.
</a>


guid: 6572bb50aac863d69a4c158457cef76f
title: Barbuda evacuated
author: Richard Stallman
url: https://stallman.org/archives/2017-jul-oct.html#23_September_2017_%28Barbuda_evacuated%29
feedurl: https://www.stallman.org/rss/
content:
<p>
<a href="http://mashable.com/2017/09/15/barbuda-civilization-destroyed/">
All the inhabitants of Barbuda have been evacuated.
</a>
All the infrastructure, and nearly all the buildings, were destroyed by hurricanes, rendering the island
uninhabitable, at least for now.
<p>
It was not terribly hard to evacuate Barbuda's 1,600 people.  Imagine
if a future storm causes a similar level of destruction in Puerto
Rico, with its 3,500,000 people.


guid: a329ec7b6151d0264e05be86c6db2828
title: Emission cheat deaths
author: Richard Stallman
url: https://stallman.org/archives/2017-jul-oct.html#23_September_2017_%28Emission_cheat_deaths%29
feedurl: https://www.stallman.org/rss/
content:
<p>
Estimating that
<a href="https://phys.org/news/2017-09-dieselgate-deaths-europe-year.html">
diesel cars designed to cheat on emissions tests
kill 5,000 people a year in Europe.
</a>


guid: f7224c2187c795b7087b53bbfdfc74e8
title: Predatory lenders
author: Richard Stallman
url: https://stallman.org/archives/2017-jul-oct.html#23_September_2017_%28Predatory_lenders%29
feedurl: https://www.stallman.org/rss/
content:
<p>
Large companies are buying up lots of family homes
and
<a href="https://www.nakedcapitalism.com/2017/09/wall-street-owns-main-street-literally.html">
renting them out for so much money that families struggle
to pay the rent.
</a>


guid: 5eb67f8ebd282206686b3ef05fa87a49
title: Recovery from Harvey
author: Richard Stallman
url: https://stallman.org/archives/2017-jul-oct.html#23_September_2017_%28Recovery_from_Harvey%29
feedurl: https://www.stallman.org/rss/
content:
<p>
Texas and Louisiana:
<a href="https://www.commondreams.org/news/2017/09/21/groups-harvey-recovery-must-serve-vulnerable-victims-not-corporate-polluters">
don't feed emergency funds for recovery from the damage
of Hurricane Harvey to companies!
</a>
The poor people need them.


guid: 239b5fbf019dd82f36f58ba42714bf18
title: Forbidden sharing
author: Richard Stallman
url: https://stallman.org/archives/2017-jul-oct.html#23_September_2017_%28Forbidden_sharing%29
feedurl: https://www.stallman.org/rss/
content:
<p>
The EU commissioned a study to prove that forbidden sharing of
published works reduces sales,
<a href="https://juliareda.eu/2017/09/secret-copyright-infringement-study/">
but the study was unable to demonstrate
the desired conclusion for most categories of works.
</a>
So the EU
decided to forget about it.
<p>
The one category where sharing did reduce sales is that of
"blockbuster" movies.  But even supposing repression of sharing
is necessary to encourage making those, they are not important
enough to justify such measures.


guid: f3171535f34535d1df0729250659cb92
title: Planet-roasters
author: Richard Stallman
url: https://stallman.org/archives/2017-jul-oct.html#23_September_2017_%28Planet-roasters%29
feedurl: https://www.stallman.org/rss/
content:
<p>
After firing the serious scientists, the EPA wants to fill its
scientific advisory groups with
<a href="https://theintercept.com/2017/09/22/epa-science-exxon-mobil-climate-change/">
representatives of polluters and
planet-roasters.
</a>


guid: 052b7adac9ba60e9b33fb45bd5e82388
title: Guber ruled unsafe
author: Richard Stallman
url: https://stallman.org/archives/2017-jul-oct.html#23_September_2017_%28Guber_ruled_unsafe%29
feedurl: https://www.stallman.org/rss/
content:
<p>
<a href="https://www.theguardian.com/commentisfree/2017/sep/22/uber-ban-london-safety">
<a href="/glossary.html#guber">Guber</a>'s license was cancelled in London -- on grounds of safety.
</a>
  The
<a href="https://stallman.org/uber.html">
big wrongs of <a href="/glossary.html#guber">Guber</a> -- harm to privacy, freedom, and drivers' pay --
are not even recognized by the mayor
</a>
as he lauds "innovation".
<p>
Innovation is an opportunity to change, and change can be good or bad.
When a possible change harms freedom, privacy, or working people's pay,
we should use our democratic government to reject it.


guid: 29ca47b6fce4166f5b745dbacbbfba7a
title: ISO rejects NSA crypto
author: Richard Stallman
url: https://stallman.org/archives/2017-jul-oct.html#23_September_2017_%28ISO_rejects_NSA_crypto%29
feedurl: https://www.stallman.org/rss/
content:
<p>
Resistance convinced ISO to
<a href="http://www.reuters.com/article/us-cyber-standards-insight/distrustful-u-s-allies-force-spy-agency-to-back-down-in-encryption-fight-idUSKCN1BW0GV">
reject two weak encryption standards
proposed by the NSA.
</a>

Uri Avnery denounces
<a href="http://zope.gush-shalom.org/home/en/channels/avnery/1506085931/">
the Israeli politician that advocates
either apartheid or genocide
</a>
as the way to deal with Palestinians.


guid: 0e85a22bf0309883280b5ce132d25010
title: Apple doesn't trust you
author: Richard Stallman
url: https://stallman.org/archives/2017-jul-oct.html#23_September_2017_%28Apple_doesn%27t_trust_you%29
feedurl: https://www.stallman.org/rss/
content:
<p>
<a href="https://motherboard.vice.com/en_us/article/bjvjd3/apple-doesnt-trust-you">
Apple doesn't trust, or respect, those who use its products.
</a>


guid: 0e64ad26375ca132bc073c532c63cd7c
title: Aid workers in Afghanistan
author: Richard Stallman
url: https://stallman.org/archives/2017-jul-oct.html#23_September_2017_%28Aid_workers_in_Afghanistan%29
feedurl: https://www.stallman.org/rss/
content:
<p>
Aid workers and medical personnel in Afghanistan
<a href="https://www.theguardian.com/global-development/2017/sep/22/we-are-not-safe-aid-workers-fearful-red-cross-shooting-afghanistan-mazar-i-sharif-lorena-enebral-perez">
fear attacks both
by religious fanatics and by the army.
</a>


guid: afb9b93fae4476cf5ba1642c197e425b
title: Pesticides
author: Richard Stallman
url: https://stallman.org/archives/2017-jul-oct.html#23_September_2017_%28Pesticides%29
feedurl: https://www.stallman.org/rss/
content:
<p>
Regulation of pesticides, world-wide, has considered the safety of
using each one in a small area,
<a href="https://www.theguardian.com/environment/2017/sep/21/assumed-safety-of-widespread-pesticide-use-is-false-says-top-government-scientist">
disregarding what happens when one is
used on large areas of farms.
</a>


guid: 7933576058af6a769192ca3de52bb92a
title: Mexico City earthquake
author: Richard Stallman
url: https://stallman.org/archives/2017-jul-oct.html#23_September_2017_%28Mexico_City_earthquake%29
feedurl: https://www.stallman.org/rss/
content:
<p>
Poor towns outside Mexico City
<a href="https://www.theguardian.com/world/2017/sep/21/entire-towns-in-mexico-flattened-as-scale-of-earthquake-damage-emerges">
suffered great damage from the earthquake.
</a>
<p>
The way to prevent this is by enforcing strong building codes, but in
Mexico the poverty and the corruption make that difficult.


guid: 9804cfe2691107d56d1d4efcd625759c
title: Enemy of the people
author: Richard Stallman
url: https://stallman.org/archives/2017-jul-oct.html#23_September_2017_%28Enemy_of_the_people%29
feedurl: https://www.stallman.org/rss/
content:
<p>
When St Louis thugs claimed the city streets belong to them,
<a href="https://www.theguardian.com/commentisfree/2017/sep/21/st-louis-police-violence-protest">
they
openly declared that they consider themselves the enemy of the people
of the city.
</a>


guid: 9c4fc13ce2702d53b795e5e7dd29e1fc
title: Honoring US war criminals
author: Richard Stallman
url: https://stallman.org/archives/2017-jul-oct.html#23_September_2017_%28Honoring_US_war_criminals%29
feedurl: https://www.stallman.org/rss/
content:
<p>
Prominent US universities
<a href="https://theintercept.com/2017/09/21/chelsea-manning-harvard-fellowship-sean-spicer/">
honor ex-officials responsible for horrible
crimes.
</a>


guid: 210d3aa3e368bd807604811335ecde80
title: Kim Jong-un's statement
author: Richard Stallman
url: https://stallman.org/archives/2017-jul-oct.html#23_September_2017_%28Kim_Jong-un%27s_statement%29
feedurl: https://www.stallman.org/rss/
content:
<p>
For once,
<a href="https://www.theguardian.com/world/2017/sep/22/a-rogue-and-a-gangster-kim-jong-uns-statement-on-trump-in-full">
Kim Jong-un said something reasonable
-- about the bully.
</a>
<p>
However, the threat to retaliate with war for a speech, even a deranged
speech by a gangster, is just as wrong from Kim as from the bully.


guid: 4f52a26981cd91b59233288c5aefc9a0
title: Russian pro-troll Facebook ads
author: Richard Stallman
feedurl: https://www.stallman.org/rss/
url:
https://stallman.org/archives/2017-jul-oct.html#23_September_2017_%28Russian_pro-troll_Facebook_ads%29

content:
<p>
It appears
<a href="http://www.thedailybeast.com/russians-appear-to-use-facebook-to-push-pro-trump-flash-mobs-in-florida">
Russians used Facebook to recruit people for the troll's rallies
</a>
during the election campaign.
<p>
Allowing them to do this fits Facebook's stated mission,
<a href="https://www.theguardian.com/technology/2017/sep/21/facebook-russia-advertising-mark-zuckerberg">
"Bringing
the world closer together".
</a>


guid: 7f2dedc4c3396fe42aebc87f02e65ac7
title: Driverless cars
author: Richard Stallman
url: https://stallman.org/archives/2017-jul-oct.html#23_September_2017_%28Driverless_cars%29
feedurl: https://www.stallman.org/rss/
content:
<p>
Finally, attention is paid to the main danger of driverless cars:
<a href="https://www.theguardian.com/technology/2017/sep/22/driverless-cars-safer-perhaps-but-professor-warns-of-privacy-risks">
surveillance of their users, and maybe of everyone else they go near.
</a>


guid: 78e36082238cbadff430217bcb6405d1
title: Global heating optimism
author: Richard Stallman
url: https://stallman.org/archives/2017-jul-oct.html#23_September_2017_%28Global_heating_optimism%29
feedurl: https://www.stallman.org/rss/
content:
<p>
Optimistic discussion of global heating has enabled people to
<a href="https://www.theguardian.com/commentisfree/2017/sep/21/climate-optimism-disaster-extreme-weather-catastrophe">
assume
that the problem is already being fixed
-- and it isn't.
</a>
We need to convert the recent disasters into an urgent demand to take
the necessary steps.
<p>
"We have been repeatedly asked: 'Don't you want to leave a better
Earth for your grandchildren,' And we've all collectively responded:
<a href="https://www.theguardian.com/environment/2017/sep/22/climate-deniers-protect-status-quo-that-made-them-rich">
'Ah, fuck 'em!'"
</a>
<p>
Having children not only means they will be caught up in the suffering
caused by global heating disaster.  It also makes the disaster bigger.
<p>
<a href="https://stallman.org/articles/children.html">
Conversely, deciding to have no children is the biggest contribution
you can make in your own life to reducing the disaster.
</a>
Please, think
<em>now</em> of the children, and avoid making any.


guid: c972aed958f69f33899b8879a5a5c677
title: Teaching sexual respect
author: Richard Stallman
url: https://stallman.org/archives/2017-jul-oct.html#23_September_2017_%28Teaching_sexual_respect%29
feedurl: https://www.stallman.org/rss/
content:
<p>
<a href="https://www.theguardian.com/us-news/2017/sep/22/betsy-devos-scraps-obama-rules-on-investigating-campus-sexual-assault">
DeVos authorized colleges to follow
a more strict standard of evidence
when judging accusations of rape or groping.
</a>
<p>
The term "sexual assault" is a bad term to use in formulating rules
for judging or punishing people, because it lumps together rape with
the much lesser crime of groping.  We would not judge those the same,
so we shouldn't lump them together in our discourse.  Any policy that
uses the term "sexual assault" will tend to be bad.
<p>
The way people are punished when a college declares them guilty of
rape is sufficiently grave that I think they must be judged by the
standard of "beyond a reasonable doubt".  I expect most of such
accusations are true, but certainly some are false.
<p>
However, it is a mistake for a school to conduct a substitute for a
trial.  The legal system exists for that, and schools can't do that
job.  Someone who has been raped and wants something like criminal
prosecution should go to the state, not to the school.
<p>
What schools could usefully do is teach sexual respect that goes
beyond merely not committing a crime.  The school could have a
stricter standard of sexual respect, as a school rule, not as a
criminal law.  Breaking that rule would not mean one is a rapist, or a
criminal at all, but the school would insist one never break it again.
<p>
Students that push too far sexually, even if not to the point of
crime, could be required to do counseling and make a strong and
visible effort to change their way of approaching sex.  Most of them
would not be rapists, so doing the counseling would not label them as
rapists.  Rather, they would be making sure they will not be rapists.
The school might also require them to avoid for some time campus
events where there is alcohol, and subsequently to follow rules so
that they don't drink to excess.
<p>
A system like this could prevent rape by teaching students
to avoid the sort of behavior that could turn into rape.


guid: 3e2a1399ca4c84d849dc005b75e4aeff
title: Sanders on foreign policy
author: Richard Stallman
url: https://stallman.org/archives/2017-jul-oct.html#23_September_2017_%28Sanders_on_foreign_policy%29
feedurl: https://www.stallman.org/rss/
content:
<p>
<a href="https://theintercept.com/2017/09/22/bernie-sanders-interview-foreign-policy/">
Sanders addresses several important foreign policy issues.
</a>
<p>
He doesn't go as far as I do on some of these issues,
but he's much better than anyone else that might get elected.


guid: fe3dad7bd99b110afcd836bbab2c0dfa
title: Social security number
author: Richard Stallman
url: https://stallman.org/archives/2017-jul-oct.html#23_September_2017_%28Social_security_number%29
feedurl: https://www.stallman.org/rss/
content:
<p>
A single ID number for a person
<a href="https://www.washingtonpost.com/news/innovations/wp/2017/09/20/your-social-security-number-may-not-be-secure-but-how-could-we-replace-it/">
exposes that person to a risk of fraud.
</a>
  Even worse, it facilitates massive surveillance.
<p>
The right solution is to have a separate identifying code for each
relationship.  And this should include most state agencies, too.


guid: 750e722e26b24db2c6e3372239da57eb
title: 35 in one house in UK
author: Richard Stallman
url: https://stallman.org/archives/2017-jul-oct.html#23_September_2017_%2835_in_one_house_in_UK%29
feedurl: https://www.stallman.org/rss/
content:
<p>
<a href="https://www.theguardian.com/uk-news/2017/sep/21/owner-of-house-where-35-men-are-living-threatens-to-sue-brent-council">
35 men were found occupying a single house in England, using
wall-to-wall mattresses.
</a>
The landlord was accused of abusive
treatment, but he said that three men rented the house and then
let the others live there.
<p>
People should not have to live in these conditions, but would it be
better if they were homeless?
<p>
Who really exploited those 35 men?  The Tories did.  They knowingly
drove rents up and wages down.


guid: 54803c2d2a34adf886fa722761c9a1aa
title: Women murdered by men
author: Richard Stallman
url: https://stallman.org/archives/2017-jul-oct.html#23_September_2017_%28Women_murdered_by_men%29
feedurl: https://www.stallman.org/rss/
content:
<p>
In 2015,
<a href="https://www.commondreams.org/newswire/2017/09/21/more-1600-women-murdered-men-one-year-new-study-finds">
1600 US women were murdered by men.
</a>
<p>
It surely is not a coincidence that the states with the highest rates
of killings of women are ruled by Republicans.


guid: a67b2ae1706ab816e9520238eab6253c
title: Society's safety net
author: Richard Stallman
url: https://stallman.org/archives/2017-jul-oct.html#23_September_2017_%28Societys_safety_net%29
feedurl: https://www.stallman.org/rss/
content:
<p>
"Remove society's safety net and what do we get? 
<a href='https://www.theguardian.com/commentisfree/2017/sep/21/remove-safety-net-disabled-toddlers-dirty-clothes-social-fund'>Disabled
toddlers in dirty clothes</a>."


guid: 8663804b12798a0c9c9c54cf3fe7013b
title: Aid for North Korean infants and pregnant women
author: Richard Stallman
feedurl: https://www.stallman.org/rss/
url:
https://stallman.org/archives/2017-jul-oct.html#23_September_2017_%28Aid_for_North_Korean_infants_and_pregnant_women%29

content:
<p>
South Korea has given North Korea 
<a href="https://www.theguardian.com/world/2017/sep/21/south-korea-approves-8m-aid-package-for-north-korea">aid
for infants and pregnant women</a>.
<p>
The US, with China's help, have applied plenty of stick.  Some carrot
is a good idea.


guid: 50b9d6bdacf71d33e6613142c0296495
title: Parts of Mexico impoverished by NAFTA
author: Richard Stallman
feedurl: https://www.stallman.org/rss/
url:
https://stallman.org/archives/2017-jul-oct.html#23_September_2017_%28Parts_of_Mexico_impoverished_by_NAFTA%29

content:
<p>
The Mexican earthquake of Sep 9 destroyed 17,000 houses in the poor
southern parts of the country, which has been 
<a href="https://theconversation.com/twin-earthquakes-expose-mexicos-deep-inequality-84012">impoverished
by NAFTA</a>.


guid: d7cef7ed4fff54c258670865f7f7139f
title: Cameroon students face prison for joke
author: Richard Stallman
feedurl: https://www.stallman.org/rss/
url:
https://stallman.org/archives/2017-jul-oct.html#23_September_2017_%28Cameroon_students_face_prison_for_joke%29

content:
<p>
Students in Cameroon 
<a href="https://www.theguardian.com/global-development/2017/sep/21/no-laughing-matter-cameroon-students-face-10-years-in-jail-for-boko-haram-joke">could
be imprisoned for 10 years</a> for a joke that referred to Boko Haram.


guid: f9b523e21bfc15fda8e9bf669890e4b9
title: Sabotaging the EPA
author: Richard Stallman
url: https://stallman.org/archives/2017-jul-oct.html#23_September_2017_%28Sabotaging_the_EPA%29
feedurl: https://www.stallman.org/rss/
content:
<p>
<a href="/glossary.html#saboteur">Saboteur</a> Pruitt found a way to block the EPA from investigating
environmental crimes: 
<a href="https://www.commondreams.org/news/2017/09/20/instead-protecting-earth-epa-agents-now-forced-serve-pruitt-bodyguards">making
the investigators work as his personal bodyguards.


guid: e49bfd7a3f1eab032845624a02335649
title: The new Dontcare bill
author: Richard Stallman
url: https://stallman.org/archives/2017-jul-oct.html#23_September_2017_%28The_new_Dontcare_bill%29
feedurl: https://www.stallman.org/rss/
content:
<p>
The new <a href="/glossary.html#care">Dontcare</a> bill would ban state-supported medical insurance from
covering abortion in all states.  It would also eliminate support for
prenatal care for
<a href="https://www.commondreams.org/news/2017/09/20/latest-gop-plan-even-worse-womens-health-previous-repeal-bills">13
million women</a>.


guid: e4f9a89d2f3af87c12a75ed38db6bf9b
title: UN Nuclear Disarmament Treaty
author: Richard Stallman
feedurl: https://www.stallman.org/rss/
url:
https://stallman.org/archives/2017-jul-oct.html#23_September_2017_%28UN_Nuclear_Disarmament_Treaty%29

content:
<p>
Nuclear weapons would threaten world disaster even if all national
leaders were sane and calm.  The 
<a href="https://www.commondreams.org/views/2017/09/20/negotiated-curbing-north-koreas-nuclear-capabilities-good-not-good-enough">UN
Nuclear Disarmament Treaty</a> offers a way to stop that.


guid: 1e90e4c80def0bf63c29688a17cdad41
title: US mainstream news
author: Richard Stallman
url: https://stallman.org/archives/2017-jul-oct.html#23_September_2017_%28US_mainstream_news%29
feedurl: https://www.stallman.org/rss/
content:
<p>
Ralph Nader: US mainstream news media now 
<a href="https://www.commondreams.org/views/2017/09/20/censorious-vortex-flash-news-barons">focusing
narrowly on recent shocking events that mainstream news media are
mainly talking about</a>.


guid: 5c3136e42da0ffb416b25782db4f04c0
title: Independence referendum in Catalonia
author: Richard Stallman
feedurl: https://www.stallman.org/rss/
url:
https://stallman.org/archives/2017-jul-oct.html#23_September_2017_%28Independence_referendum_in_Catalonia%29

content:
<p>
Spain has effectively suspended the government of Catalonia to 
<a href="https://www.commondreams.org/news/2017/09/20/street-protests-erupt-spain-accused-stomping-democracy-catalonia">prevent
it from holding the planned independence referendum</a>, or doing
basically anything else.


guid: dc209f2240bbcd3992d0760185732e6f
title: Australia's system for deterring refugees
author: Richard Stallman
feedurl: https://www.stallman.org/rss/
url:
https://stallman.org/archives/2017-jul-oct.html#23_September_2017_%28Australias_system_for_deterring_refugees%29

content:
<p>
Australia's system for deterring refugees includes 
<a href="https://www.theguardian.com/world/2017/sep/22/an-impossible-choice-the-nauru-refugee-forced-to-choose-between-family-and-freedom">separating
families forever</a>.


guid: tag:linuxfr.org,2005:News/38200
title: devops REX - publication du programme du 2 octobre 2017
author: Nÿco
url: https://linuxfr.org/news/devops-rex-publication-du-programme-du-2-octobre-2017
feedurl: http://linuxfr.org/news.atom
content:
<div><p>La conférence <a href="http://www.devopsrex.fr">devops REX</a> revient pour sa deuxième édition le <strong>lundi 2 octobre 2017</strong>, dans tout juste 10 jours !</p>

<p><img src="//img.linuxfr.org/img/68747470733a2f2f7777772e6465766f70737265782e66722f77702d636f6e74656e742f75706c6f6164732f323031362f30372f7765622d736d616c6c2e706e67/web-small.png" alt="devops REX" title="Source : https://www.devopsrex.fr/wp-content/uploads/2016/07/web-small.png"></p>

<p>La conférence est 100% dédiée aux retours d'expérience devops (aucune publicité produit sur scène, que des présentations de ceux qui ont mené ou vécu des transformations devops), et toutes les sessions sont en français. L'organisation est menée par la communauté du <a href="https://www.meetup.com/Paris-Devops-Meetup/">meetup Paris Devops</a>.</p>

<p>Le <a href="https://www.devopsrex.fr/programme/">programme quasi complet</a> est en ligne, dont un extrait se trouve dans cette dépêche. Une réduction sur le prix des places est offerte aux lecteurs de LinuxFr — voir ci-dessous.</p>

<p>On y retrouve un contenu très riche mais aussi très varié, avec les retours d’expérience de startups comme de très grands comptes, et un contenu à plusieurs niveaux — depuis la vision en direct des DSI jusqu’au focus technique plus détaillé là où c’est pertinent.</p></div><ul><li>lien n°1 : <a title="http://www.devopsrex.fr" hreflang="fr" href="https://linuxfr.org/redirect/100638">devops REX - site de la conférence</a></li><li>lien n°2 : <a title="https://www.devopsrex.fr/programme/" hreflang="fr" href="https://linuxfr.org/redirect/100639">Programme de la conférence</a></li><li>lien n°3 : <a title="https://devopsrex.eventbrite.fr/?discount=MERCI-LINUXFR#tickets" hreflang="fr" href="https://linuxfr.org/redirect/100640">Billeterie en ligne (avec réduction LinuxFr)</a></li></ul><div><h3 id="devops-et-logiciel-libre">devops et logiciel libre</h3>

<p>« devops », un terme indéniablement à la mode dans notre industrie en ce moment, est le nom donné à la méthodologie qui a pour but d'aligner les objectifs des développeurs (dev en anglais) et des administrateurs systèmes (ops en anglais), et de leur permettre de mieux collaborer. Souvent expliqué par l'acronyme CAMP pour Culture, Automatisation, Mesure et Partage, l'objectif est d'utiliser ces leviers d'action pour supprimer les traditionnels silos développeurs/sysadmin et encourager une collaboration améliorée, qui résulte en une facilité de travail au quotidien, et au final, une informatique qui tourne mieux au service de l'organisation globale.</p>

<p>Quel rapport entre devops et logiciel libre, me direz-vous ? Il y en a plein ! D'abord, les personnes. Le libre est né dans les couches d'infrastructure, et encore aujourd'hui c'est là où il règne vraiment en roi — du coup, nombre de libristes travaillent de près ou de loin dans l'infrastructure, et sont donc très directement concernés par la méthodologie devops. Ensuite, nombre de valeurs sont communes, par exemple si on prend la définition de devops ci-dessus — Culture, Automatisation, Mesure et Partage — on s'y retrouve rapidement. Et finalement, même si rien n'empêche de faire du devops sans logiciel libre, c'est tout de même assez rare, alors profitons-en pour y aller, en parler et porter la bonne parole !</p>
<h3 id="extrait-du-programme">Extrait du programme</h3>

<ul>
<li>
<a href="http://www.devopsrex.fr/cth_speaker/bastien-semene/">Comment intégrer une démarche devops au sein d’une startup en hyper-croissance ?</a> par Bastien SEMENE, Engineering Manager Agile chez ContentSquare</li>
<li>
<a href="http://www.devopsrex.fr/cth_speaker/laurent-nyffels/">Comment une DSI de la taille d’AXA France peut-elle tirer avantages de la mise en place de DevOps ?</a> par Laurent NYFFELS, Architecte SI chez AXA France</li>
<li>
<a href="http://www.devopsrex.fr/cth_speaker/benjamin-gakic/">Days of Chaos : le développement de la culture devops chez Voyages-Sncf à l’aide de la gamification</a>, par Christophe ROCHEFOLLE, Directeur Excellence Opérationnelle chez Voyages-SNCF.com et Benjamin GAKIC, Expert Sûreté de fonctionnement, Facilitateur ExOp chez Voyages-SNCF.com</li>
<li>
<a href="http://www.devopsrex.fr/cth_speaker/pauline-bourjot/">Dev rencontre Ops, un an après</a>, par Aurore MALHERBES, Développeur web agile chez Theodo, Pauline BOURJOT, Consultante Cloud et Automatisation chez D2SI et Richard BURBAUD, IT Solutions Director chez Tarkett</li>
<li>
<a href="https://www.devopsrex.fr/cth_speaker/claire-mayaux/">Le DEVOPS comme moteur de la Transformation, la Forge Logicielle comme carburant !</a> par Claire MAYAUX, Directrice du Digital et des Systèmes d’Information et Daniel Wozniak, Responsable des Infrastructures – RSSI chez Mutuelle Nationale Territoriale</li>
<li>
<a href="http://www.devopsrex.fr/cth_speaker/jonathan-fontana/">Une démarche DevOps outillée pour accompagner la transformation du SI PMU</a> par Jonathan FONTANA, Leader ingénieur SI Responsable de la cellule Automatisation et des tests de performances, responsable du DevOps et de l’Industrialisation côté Production chez PMU</li>
<li>
<a href="http://www.devopsrex.fr/cth_speaker/jean-francois-menou-2/">Transformation DevOps à la DSI de La Poste Courrier</a>, par Michel LEJEUNE, Facteur de changements et Jean-François MENOU, Facteur de changements chez Groupe La Poste – Branche Services-Courrier-Colis</li>
<li>
<a href="http://www.devopsrex.fr/cth_speaker/remy-christophe-schermesser/">Comment les opérations ont rendu nos clients heureux et nos commerciaux plus efficaces ?</a> par Rémy-Christophe SCHERMESSER,  Site Reliability Engineer chez Algolia</li>
<li>
<a href="http://www.devopsrex.fr/cth_speaker/maziar-dowlatabadi/">L’humain d’abord !</a> par Maziar DOWLATABADI, Directeur adjoint à la direction numérique de Radio France, chargé de la technique et Pierre-Gilles MIALLON</li>
<li>
<em>Un Ops parmis les Devs : retour des deux côtés</em> par Anna Dao, Développeuse Back-End chez Photobox et Alexis "Horgix" Chotard, Consultant DevOps chez Xebia</li>
</ul><h3 id="inscription">Inscription</h3>

<p>Pour les lecteurs de LinuxFR, une petite remise est offerte (15% sur le prix du billet) : <a href="https://devopsrex.eventbrite.fr/?discount=MERCI-LINUXFR#tickets">prendre sa place avec le code MERCI-LINUXFR</a>.</p></div><div><a href="https://linuxfr.org/news/devops-rex-publication-du-programme-du-2-octobre-2017.epub">Télécharger ce contenu au format Epub</a></div>    <p><a href="https://linuxfr.org/news/devops-rex-publication-du-programme-du-2-octobre-2017#comments">Lire les commentaires</a></p>


guid: tag:linuxfr.org,2005:News/38206
title: Weboob sort une nouvelle version qui va vous porter chance
author: Benoît Sibaud
url: https://linuxfr.org/news/weboob-sort-une-nouvelle-version-qui-va-vous-porter-chance
feedurl: http://linuxfr.org/news.atom
content:
<div><p><a href="http://weboob.org">Weboob</a> (<em>Web Outside Of Browsers</em>) est un ensemble d’applications et de modules interagissant avec des sites Web.</p>

<p>Ce projet peut également être utilisé comme une bibliothèque permettant de grandement simplifier l’extraction de données des sites Web. Pour du prêt à l’emploi, Weboob compte aujourd’hui 241 <a href="http://weboob.org/modules">modules</a> qui permettent d’accéder à de nombreux sites Web sans passer par un navigateur standard.</p>

<p>Sans être exhaustive, la suite de la dépêche vous propose de découvrir quelques nouveautés de la nouvelle version 1.3, sortie mercredi 20 septembre 2017, que ce soit pour les utilisateurs et utilisatrices ou les développeuses et développeurs. Nous détaillons également la vie du projet en fin de dépêche, notamment notre participation à la <a href="//linuxfr.org/news/programme-de-la-pyconfr-2017"><em>PyConFr</em> du 21 au 24 septembre 2017</a>.</p></div><ul><li>lien n°1 : <a title="http://weboob.org" hreflang="en" href="https://linuxfr.org/redirect/100652">Site Web</a></li><li>lien n°2 : <a title="http://weboob.org/news" hreflang="en" href="https://linuxfr.org/redirect/100653">Liste complète des changements</a></li><li>lien n°3 : <a title="http://weboob.org/install" hreflang="en" href="https://linuxfr.org/redirect/100654">Installation</a></li><li>lien n°4 : <a title="http://weboob.org/modules" hreflang="en" href="https://linuxfr.org/redirect/100655">Modules</a></li><li>lien n°5 : <a title="http://weboob.org/applications/" hreflang="en" href="https://linuxfr.org/redirect/100656">Applications</a></li><li>lien n°6 : <a title="https://git.weboob.org/weboob/devel" hreflang="en" href="https://linuxfr.org/redirect/100657">Code sur le GitLab du projet</a></li><li>lien n°7 : <a title="https://linuxfr.org/news/programme-de-la-pyconfr-2017" hreflang="fr" href="https://linuxfr.org/redirect/100658">Dépêche sur la PyConFr 2017</a></li></ul><div><h2 class="sommaire">Sommaire</h2>
<ul class="toc">
<li>
<a href="#services-bancaires-et-administratifs">Services bancaires et administratifs</a><ul>
<li><a href="#ajout-de-b%C3%A9n%C3%A9ficiaire-pour-les-virements">Ajout de bénéficiaire pour les virements</a></li>
<li><a href="#nouveaux-modules">Nouveaux modules</a></li>
</ul>
</li>
<li><a href="#logements">Logements</a></li>
<li><a href="#vie-priv%C3%A9e-et---auto-update">Vie privée et --auto-update</a></li>
<li><a href="#nouvelle-application-qgalleroob">Nouvelle application QGalleroob</a></li>
<li>
<a href="#dans-les-entrailles-du-d%C3%A9veloppement">Dans les entrailles du développement</a><ul>
<li><a href="#prise-en-charge-des-versions-de-python">Prise en charge des versions de Python</a></li>
<li><a href="#nouveaux-filtres">Nouveaux filtres</a></li>
<li><a href="#outils-de-d%C3%A9bogage">Outils de débogage</a></li>
</ul>
</li>
<li><a href="#liste-exhaustive-des-nouveaux-modules">Liste exhaustive des nouveaux modules</a></li>
<li>
<a href="#communaut%C3%A9">Communauté</a><ul>
<li><a href="#derni%C3%A8re-assembl%C3%A9e-g%C3%A9n%C3%A9rale">Dernière assemblée générale</a></li>
<li><a href="#pyconfr2017">PyConFr 2017</a></li>
</ul>
</li>
<li><a href="#contributeurs">Contributeurs</a></li>
</ul><h2 id="services-bancaires-et-administratifs">Services bancaires et administratifs</h2>
<h3 id="ajout-de-bénéficiaire-pour-les-virements">Ajout de bénéficiaire pour les virements</h3>

<p>Le système de virement avait été revu lors de la précédente version, afin de permettre un processus plus complet notamment lors de la demande d’informations complémentaires (exemple : un code envoyé par SMS). Nous franchissons une nouvelle étape dans la prise en charge de ces virements en permettant désormais l’ajout  de bénéficiaires pour les virements (grâce à la sous‐capacité <code>CapBankTransferAddRecipient</code>). Si le site utilise un code unique par SMS, <em>boobank</em> le demandera pour finaliser l’ajout de la même manière que pour les virements. Neuf modules ont déjà cette fonctionnalité activée.</p>
<h3 id="nouveaux-modules">Nouveaux modules</h3>

<p>Les modules bancaires sont de nouveau à la pointe grâce au soutien de l’entreprise <a href="https://www.budget-insight.com/">Budget Insight</a> qui utilise et contribue massivement à Weboob. On compte ainsi dix nouveaux modules bancaires et la liste des changements sur les modules existants est assez impressionnante.</p>

<p>Les modules qui permettent de simplifier la gestion administrative au quotidien ne sont pas en reste. On peut noter le téléchargement des fiches de paie pour tous les fonctionnaires d’état via le module <a href="https://ensap.gouv.fr/web/accueilnonconnecte">ENSAP</a>, ainsi que le téléchargement des factures du fournisseur de gaz Lampiris. N’oublions pas, pour les Parisiens, la gestion des réservations de livres dans les bibliothèques (module <em>bibliothequesparis</em>). On regrettera en revanche la disparition du module pour les bibliothèques rennaises, qui n’était plus maintenu.</p>
<h2 id="logements">Logements</h2>

<p>Il est très difficile de chercher un logement en zone densément peuplée. Les offres sont très nombreuses, souvent dupliquées sur plusieurs sites. Le travail de veille est lourd et les logements partent très vite. C’est ainsi qu’un contributeur a développé <a href="https://git.phyks.me/Phyks/flatisfy">Flatisfy</a>, en utilisant les modules immobiliers de Weboob comme <em>backend</em>. L’objectif de cette application est de vous permettre de spécifier des filtres pour votre recherche de logements (secteur, loyer, nombre de pièces, temps de trajet), puis d’offrir une interface conviviale autour de ces résultats, en groupant les doublons et en affichant tous les résultats de façon uniforme, quel que soit le site d’origine de l’annonce. Flatisfy a été testé et approuvé à Lyon et Paris pour l’instant. Pour plus d’informations, vous pouvez regarder <a href="https://phyks.me/2017/08/looking-for-a-flat-the-modern-way.html#looking-for-a-flat-the-modern-way">cet article de l’auteur</a>.</p>

<p>Le développement de Flatisfy a été l’occasion de tester et mettre à jour les modules de recherche de logements. Outre les corrections de bogues sur les modules existants, les principaux changements sont :</p>

<ul>
<li>l’ajout d’un module pour récupérer les annonces de Foncia ;</li>
<li>l’homogénéisation des résultats retournés par les divers modules, afin que les numéros de téléphone soient formatés de façon similaire, et que toutes les informations disponibles soient bien récupérées ;</li>
<li>l’ajout d’un nouveau champ <code>utilities</code> sur les <code>Housing</code>, afin de mentionner si les charges sont incluses ou non dans le loyer récupéré par le module ;</li>
<li>l’ajout de deux nouveaux champs <code>rooms</code> et <code>bedrooms</code> sur <code>Housing</code>, afin d’avoir une façon homogène entre les modules de représenter le nombre de pièces et de chambres du bien.</li>
</ul><h2 id="vie-privée-et---auto-update">Vie privée et --auto-update</h2>

<p>Par défaut, les applications Weboob vérifiaient automatiquement les mises à jour des modules quand un module rencontrait une erreur. C’est très pratique dans un projet comme Weboob qui est face à des sites volatiles, mais a des conséquences négatives en termes de respect de la vie privée. Un utilisateur a ouvert un <a href="https://git.weboob.org/weboob/devel/issues/8">ticket avec un argumentaire détaillé</a> et nous avons pris en compte ses remarques. La mise à jour automatique est donc désormais optionnelle, désactivée par défaut et peut être réactivée à l’aide de <code>--auto-update</code>.</p>

<p>Rappelons qu’il est dans tous les cas toujours possible de rechercher des mises à jour manuellement avec <code>weboob update</code>.</p>
<h2 id="nouvelle-application-qgalleroob">Nouvelle application QGalleroob</h2>

<p>Une nouvelle application Qt permet de faire des recherches d’images et de galeries : QGalleroob.<br><img src="//img.linuxfr.org/img/68747470733a2f2f6c75742e696d2f344a694848654b626f502f326958336e7436346a6a684c38723056/2iX3nt64jjhL8r0V" alt="Screenshot QGalleroob" title="Source : https://lut.im/4JiHHeKboP/2iX3nt64jjhL8r0V"></p>
<h2 id="dans-les-entrailles-du-développement">Dans les entrailles du développement</h2>
<h3 id="prise-en-charge-des-versions-de-python">Prise en charge des versions de Python</h3>

<p>Le cœur de Weboob ainsi que les applications Weboob sont maintenant compatibles Python 2.7 et Python 3.<br>
De nombreux modules sont déjà compatibles Python 2 et Python 3, et de nouveaux seront portés au fur et à mesure. Les modules n’étant toujours pas compatibles sont dans une grande majorité des modules abandonnés, dont le fonctionnement est probablement douteux. Ils seront donc probablement supprimés dans les prochaines versions.</p>

<p>En fonction des retours sur Python 3 et de l’avancée du portage, il ne restera plus qu’une ou deux versions de Weboob qui prendront encore en charge Python 2.7. Nous prévoyons de changer de numéro majeur de version (et de passer donc à Weboob 2.0) au cours de l’année 2018, et donc à une version qui n’aura plus Python 2.7.</p>
<h3 id="nouveaux-filtres">Nouveaux filtres</h3>

<p>Les filtres sont des aides essentiels dans les modules Weboob, ils permettent notamment de simplifier l’extraction des données en utilisant une syntaxe très déclarative (il y a beaucoup de magie dedans). De nouveaux filtres spécialisés font leur apparition dans cette version :</p>

<ul>
<li>
<strong>AbsoluteLink</strong> : construit une adresse URL absolue à partir d’un lien HTML (contrairement au filtre <em>Link</em> qui retourne la valeur brute) ;</li>
<li>
<strong>FormValue</strong> : permet d’obtenir la valeur courante d’un élément de formulaire (par exemple dans un tag <em>select</em>) ;</li>
<li>
<strong>HasElement</strong> : retourne une valeur suivant la présence ou non d’un élément HTML ;</li>
<li>
<strong>QueryValue</strong> : retourne la valeur d’un paramètre contenu dans la partie <em>query</em> d’une URL (par exemple, <em>value</em> pour <code>url?param=value</code>).</li>
</ul><h3 id="outils-de-débogage">Outils de débogage</h3>

<p>Deux nouveaux mécanismes ont été ajoutés pour aider à trouver les problèmes quand on écrit un module.</p>

<p>Dans une session de débogage avec <em>pdb</em> (ou temporairement dans le code d’un module) :</p>

<pre><code class="python"><span class="o">&gt;&gt;&gt;</span> <span class="kn">import</span> <span class="nn">weboob</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">weboob</span><span class="o">.</span><span class="n">browser</span><span class="o">.</span><span class="n">elements</span><span class="o">.</span><span class="n">magic_highlight</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">el</span><span class="o">.</span><span class="n">xpath</span><span class="p">(</span><span class="s1">'.//div[has-class("foo")]'</span><span class="p">))</span></code></pre>

<p>Cela ouvrira la page courante dans un navigateur pour déboguer, avec tous les éléments correspondants à l’expression XPath, mis en surbrillance. Il est possible de mettre également en surbrillance toutes les zones d’une page qui sont extraites par le module. Pour cela, il faut ajouter <code>_highlight_el = 1</code> à la configuration du module que l’on veut déboguer.</p>

<p>Un autre outil très pratique est l’exportation de sessions et son chargement via une extension Web dans Firefox ou chrome. Dans le dossier <code>contrib</code>, un dossier complet nommé <code>webextension-session-importer</code> permet cette performance (voir le fichier <code>README</code> pour plus de détails).</p>
<h2 id="liste-exhaustive-des-nouveaux-modules">Liste exhaustive des nouveaux modules</h2>

<ul>
<li>bibliothequesparis (CapBook) ;</li>
<li>billetreduc (CapCalendarEvent) ;</li>
<li>blogspot (CapMessages) ;</li>
<li>bnppere (CapBank) ;</li>
<li>btpbanque (CapBank) ;</li>
<li>capeasi (CapBank) ;</li>
<li>cices (CapBank) ;</li>
<li>cityscoot (CapDocument) ;</li>
<li>cmes (CapBank) ;</li>
<li>cmmc (CapBank, CapContact) ;</li>
<li>ensap (CapDocument) ;</li>
<li>erehsbc (CapBank) ;</li>
<li>esalia (CapBank) ;</li>
<li>foncia (CapHousing) ;</li>
<li>lameteoagricole (CapWeather) ;</li>
<li>lampiris (CapDocument) ;</li>
<li>larousse (CapTranslate) ;</li>
<li>linebourse (CapBank) ;</li>
<li>myfoncia (CapDocument) ;</li>
<li>pixabay (CapFile, CapImage) ;</li>
<li>pradoepargne (CapBank) ;</li>
<li>tumblr (CapGallery) ;</li>
<li>zerobin (CapPaste).</li>
</ul><h2 id="communauté">Communauté</h2>
<h3 id="dernière-assemblée-générale">Dernière assemblée générale</h3>

<p>Le projet Weboob est protégé par une association qui a pour but de soutenir le développement et de permettre l’indépendance du projet par rapport à des entreprises qui peuvent être très contributrices (on les en remercie beaucoup). Si cette association n’est pas toujours très active, nous avons réuni une assemblée générale le 10 juillet 2017 à Paris. Le bureau de l’association (qui nomme notamment le <em>release manager</em>, ayant le pouvoir d’accepter ou refuser des contributions) a été entièrement reconduit.</p>

<p>Les membres du bureau sont cependant tous investis depuis longtemps dans le projet et seraient très volontiers prêts à céder leurs places à de nouveaux contributeurs ou contributrices.</p>
<h3 id="pyconfr2017">PyConFr 2017</h3>

<p>Les développeurs Weboob seront présents en force à cette édition de <a href="//linuxfr.org/news/programme-de-la-pyconfr-2017"><em>PyConFr</em></a> ! L’ensemble des membres du bureau de l’association sera notamment présent.</p>

<p>Un <a href="https://www.pycon.fr/2017/programme.html#atelier-presentation-weboob">atelier</a> sera animé le samedi 23 septembre 2017 de 14 h à 16 h, ce sera l’occasion de développer votre premier module. Deux conférences seront présentées le dimanche 24 septembre 2017 de 15 h à 16 h :</p>

<ul>
<li>
<a href="https://www.pycon.fr/2017/programme.html#weboob-le-navigatueur"><em>Weboob, le navigatueur</em></a> ;</li>
<li>
<a href="https://www.pycon.fr/2017/programme.html#la-puissance-du-scraping-web-avec-weboob"><em>La puissance du scraping Web avec Weboob</em></a>.</li>
</ul><p>N’hésitez pas à passer nous voir, poser des questions, faire vos premières contributions, discuter de l’avenir du projet, etc.</p>
<h2 id="contributeurs">Contributeurs</h2>

<p>Merci aux contributeurs qui ont participé à cette version :</p>

<ul>
<li>Baptiste Delpey ;</li>
<li>Barthélemy Gouby ;</li>
<li>Benjamin Bouvier ;</li>
<li>Benjamin Carton ;</li>
<li>Benjamin Tampigny ;</li>
<li>Christophe Lampin ;</li>
<li>David Kremer ;</li>
<li>Edouard Lambert ;</li>
<li>Florent Fourcot ;</li>
<li>Florian ;</li>
<li>Florian Duguet ;</li>
<li>François Revol ;</li>
<li>Frédéric Lépy ;</li>
<li>Guillaume Lundy ;</li>
<li>Guillaume Seznec ;</li>
<li>James Galt ;</li>
<li>Jean Walrave ;</li>
<li>Jonathan Schmidt ;</li>
<li>Juliette Fourcot ;</li>
<li>Laurent Bachelier ;</li>
<li>Louis Debeve ;</li>
<li>Matthieu Weber ;</li>
<li>Nicolas Cornu ;</li>
<li>
<em>P4ncake</em> ;</li>
<li>
<em>Phyks</em> (Lucas Verney) ;</li>
<li>Raymonde Philibert ;</li>
<li>Roger Philibert ;</li>
<li>Romain Bignon ;</li>
<li>Sébastien Jean ;</li>
<li>Simon Lipp ;</li>
<li>Théo Dorée ;</li>
<li>Vincent Ardisson ;</li>
<li>Vincent Paredes ;</li>
<li>
<em>ZeHiro</em>.</li>
</ul><p><a href="http://weboob.org">Weboob</a> est un projet qui vit grâce à ses <a href="http://weboob.org/#authors">contributeurs</a>. Si vous souhaitez l’améliorer et que vous connaissez le Python (ou pas, des besoins sur la documentation et la qualité des icônes se font sentir), n’hésitez pas à <a href="http://dev.weboob.org/guides/contribute">contribuer</a>.</p></div><div><a href="https://linuxfr.org/news/weboob-sort-une-nouvelle-version-qui-va-vous-porter-chance.epub">Télécharger ce contenu au format Epub</a></div>    <p><a href="https://linuxfr.org/news/weboob-sort-une-nouvelle-version-qui-va-vous-porter-chance#comments">Lire les commentaires</a></p>


guid: tag:linuxfr.org,2005:News/38171
title: XOSAN : un SAN virtuel pour XenServer
author: Xavier Claude
url: https://linuxfr.org/news/xosan-un-san-virtuel-pour-xenserver
feedurl: http://linuxfr.org/news.atom
content:
<div><p>XOSAN est une solution d’hyperconvergence destinée à XenServer actuellement en cours de développement par Vates, la société éditrice de Xen Orchestra.  Il s’agit d’un SAN virtuel pour créer un espace de stockage partagé en utilisant vos différents espaces de stockages existants. C’est une solution orientée 100 % logicielle.</p>

<p>La seconde phase de la bêta est maintenant déployée et accessible à tous les utilisateurs qui veulent y participer.</p>

<p><em>N. D. M. : XOSAN n’est pas <a href="https://xen-orchestra.com/forum/topic/500/xosan-licence/5">sous licence libre</a>.</em></p></div><ul><li>lien n°1 : <a title="https://xen-orchestra.com/#!/xosan-beta" hreflang="en" href="https://linuxfr.org/redirect/100540">Site officiel</a></li><li>lien n°2 : <a title="https://xen-orchestra.com/docs/xosan.html" hreflang="en" href="https://linuxfr.org/redirect/100541">documentation en ligne</a></li><li>lien n°3 : <a title="https://xen-orchestra.com/blog/tag/xosan/" hreflang="en" href="https://linuxfr.org/redirect/100542">Blog</a></li><li>lien n°4 : <a title="https://linuxfr.org/news/xen-orchestra-5-10-interface-web-pour-xenserver" hreflang="fr" href="https://linuxfr.org/redirect/100543">Dernière dépêche sur Xen Orchestra 5.10</a></li></ul><div><h3 id="fonctionnement">Fonctionnement</h3>

<p>XOSAN réunit tous les disques locaux existants de votre infrastructure dans un espace de stockage partagé et virtuel, sans aucune limitation. C’est une solution entièrement orientée logicielle qui ne nécessite pas l’achat de matériel additionnel à votre infrastructure déjà existante. Cette solution est capable de fonctionner sur un disque où XenServer est déjà installé.<br><img src="//img.linuxfr.org/img/68747470733a2f2f78656e2d6f72636865737472612e636f6d2f626c6f672f636f6e74656e742f696d616765732f323031372f30312f584f53414e706f6f6c2e6a7067/XOSANpool.jpg" alt="XoSAN" title="Source : https://xen-orchestra.com/blog/content/images/2017/01/XOSANpool.jpg"></p>
<h3 id="objectifs">Objectifs</h3>

<p>Les objectifs et bénéfices de la solution sont multiples :</p>

<ul>
<li>protéger vos données grâce à la réplication des données sur des hôtes multiples ;</li>
<li>rendre possible la haute disponibilité pour XenServer, sans avoir besoin d’utiliser un <a href="https://fr.wikipedia.org/wiki/Serveur_de_stockage_en_r%C3%A9seau" title="Network Attached Storage — serveur de stockage en réseau">NAS</a> ou un <a href="https://fr.wikipedia.org/wiki/R%C3%A9seau_de_stockage_SAN" title="Storage Area Network — réseau de stockage">SAN</a> ;</li>
<li>rendre son infrastructure plus agile en ajoutant de nouveaux nœuds pour agrandir votre espace de stockage ;</li>
<li>offrir la possibilité de travailler sur n’importe quel matériel : du disque dur au SSD en configuration RAID ou non.</li>
</ul><h3 id="phases-de-bêta-pour-xosan">Phases de bêta pour XOSAN</h3>
<h4 id="phase-i">Phase I</h4>

<p>La première phase de la bêta est terminée et a permis la réalisation d’une solution techniquement solide et performante exploitant la technologie GlusterFS.</p>
<h4 id="phase-ii">Phase II</h4>

<p>La deuxième phase de la bêta XOSAN est maintenant ouverte. Cette deuxième phase de bêta a pour objectif d’améliorer l’interface utilisateur et d’apporter une solution clé en main et « <em>user friendly</em> ». Son second objectif est de rendre la solution plus flexible en offrant la possibilité d’ajouter ou de supprimer des nœuds ou encore de remplacer un nœud défaillant.</p>
<h4 id="phase-iii-finale">Phase III (finale)</h4>

<p>La troisième et dernière phase se concentrera sur le « <em>tiering</em> », c’est‐à‐dire la possibilité d’utiliser un SSD comme système de cache pour les fichiers qui sont beaucoup utilisés dans le but de gagner en vitesse d’exécution.</p>
<h4 id="rejoindre-la-beta">Rejoindre la beta</h4>

<p>Tous les utilisateurs de XenServer désireux de tester la solution peuvent le faire lors de cette seconde phase de bêta. Il suffit de disposer d’une version gratuite de Xen Orchestra et d’une infrastructure XenServer sur laquelle déployer XOSAN. Pour plus d’infos, vous pouvez consulter la <a href="https://xen-orchestra.com/docs/xosan.html">documentation</a>.</p>

<p><strong>ATTENTION : Il s’agit d’un logiciel en version bêta, ne l’utilisez pas en production !</strong></p></div><div><a href="https://linuxfr.org/news/xosan-un-san-virtuel-pour-xenserver.epub">Télécharger ce contenu au format Epub</a></div>    <p><a href="https://linuxfr.org/news/xosan-un-san-virtuel-pour-xenserver#comments">Lire les commentaires</a></p>


guid: tag:linuxfr.org,2005:News/38185
title: AlternC Camp à Lyon du 6 au 8 octobre 2017
author: Nahuel
url: https://linuxfr.org/news/alternc-camp-a-lyon-du-6-au-8-octobre-2017
feedurl: http://linuxfr.org/news.atom
content:
<div><p>Cela fait un petit moment qu’on n’a pas parlé ici d’AlternC, ce  projet libre dont la vocation est d’aider la gestion de l’hébergement de vos noms de domaines, courriels, sites Web, listes de diffusion, etc. L’organisation du prochain <em>dev camp</em> est l’occasion de corriger tout ceci.<br>
Le principe est de se retrouver dans un même espace physique et temporel pour coder, corriger des points bloquants immédiats et préparer la suite.</p>

<p><img src="//img.linuxfr.org/img/687474703a2f2f616c7465726e632e636f6d2f6c6f676f2e706e67/logo.png" alt="Logo AlternC" title="Source : http://alternc.com/logo.png"></p>

<p>Ces derniers temps les contributeurs principaux n’ont pu se focaliser comme voulu sur le suivi des versions Debian. Actuellement, peu de contributions ont permis de rattraper ce retard. C’est une des nos premières urgences.</p></div><ul><li>lien n°1 : <a title="http://alternc.com/Home-fr" hreflang="fr" href="https://linuxfr.org/redirect/100651">AlternC</a></li></ul><div><h2 id="alternc">AlternC ?</h2>

<p>AlternC est utilisé tant par des sociétés d’hébergement que par des particuliers, des associations ou toute autre entité voulant héberger plus d’un projet Internet. Il est fortement lié au fonctionnement de Debian et peut être dans certains cas utilisé avec des distributions telles qu’Ubuntu</p>
<h2 id="plan-daction">Plan d’action</h2>

<p>Nous souhaitons, durant trois jours, travailler en priorité sur les points suivants :</p>

<ul>
<li>publier des paquets 3.x.10 (principalement des corrections diverses et variées pour les versions <em>Wheezy</em> et <em>Jessie</em>) ;</li>
<li>finaliser l’intégration de <a href="http://letsencrypt.org/"><em>Let’s Encrypt</em></a> ;</li>
<li>corriger les incidents restants sur la version stable (principalement suivre le mouvement d’Apache 2.2 vers 2.4) ;</li>
<li>valider une méthodologie de migration de <em>Wheezy</em> vers <em>Jessie</em> (pour rattraper notre retard avec les versions LTS de Debian) ;</li>
<li>publier une version stable pour <em>Jessie</em> (<em>old‐stable</em>) ;</li>
<li>identifier les problèmes pour la compatibilité avec <em>Stretch</em>.</li>
</ul><p>Comme vous pouvez le lire, notre volonté est de rattraper autant que possible notre retard par rapport au cycle de vie de Debian.</p>
<h2 id="et-vous-et-nous">Et vous, et nous ?</h2>

<p>Ces trois journées sont ouvertes à toute personne. Vous pourrez nous aider à améliorer l’existant, nous suggérer les améliorations pour la suite, montrer nos défauts et qualités, traduire, boire un café, un thé ou un chocolat chaud…</p>

<p>Vous pouvez vous inscrire sur <a href="https://framadate.org/Cneh4GSGfgKLctWF"><em>Framadate</em></a> et faire vos remarques ci‐dessous.</p>
<h2 id="où">Où ?</h2>

<p>Le lieu n’est pas encore déterminé, l’information sera transmise par courriel et sur le <em>Framadate</em>. Nous allons réserver une maison ou un appartement pour les trois jours, ce qui nous laissera un maximum de liberté durant cette période. Vous pourrez venir et partir librement. ;)</p></div><div><a href="https://linuxfr.org/news/alternc-camp-a-lyon-du-6-au-8-octobre-2017.epub">Télécharger ce contenu au format Epub</a></div>    <p><a href="https://linuxfr.org/news/alternc-camp-a-lyon-du-6-au-8-octobre-2017#comments">Lire les commentaires</a></p>


guid: tag:linuxfr.org,2005:Diary/37500
title: associalibre 19 et 20 octobre 2017 à Bruxelles
author: mjhvc
url: https://linuxfr.org/users/mjhvc/journaux/associalibre-19-et-20-octobre-2017-a-bruxelles
feedurl: http://linuxfr.org/journaux.atom
content:
<h2 id="associalibre-19--20-octobre-2017">Associalibre (19 +) 20 Octobre 2017</h2>

<p>3ème édition <a href="http://2017.associalibre.be">d'Associalibre</a>, la journée belge du libre à destination des associations et des enseignants.</p>

<p>Pour la troisième année consécutive, <a href="http://abelli-asbl.be">l'association de promotion du logiciel libre Abelli</a> organise une journée atelier/formation de sensibilisation aux logiciels libres à destination du public associatif et des enseignants. </p>

<p>En 2017, le fil rouge de la journée sera <strong>la protection des données privées numériques</strong>. </p>

<p>Nouveauté 2017 : Cette journée du 20 sera précédée la veille, le 19 au soir, d'une double conférence sur la thématique: <br><strong>Le respect des données en réseaux sociaux</strong>. </p>

<p>Conférences respectivement animées par </p>

<ul>
<li>Olivier Bogaert, Commissaire de la Federal Computer Crime Unit </li>
<li>André Loconte, représentant de <a href="https://nurpa.be">l'Association de protection des internautes</a>, qui défend en Belgique depuis de nombreuses années la vision d'un internet neutre, libre, accessible et vecteur de progrès. 
Les conférences seront suivie d’un débat avec le public.</li>
</ul><h4 id="une-journée-du-libre-pour-toutes-et-tous-pensée-pour-le-monde-associatif-et-les-enseignant-dans-les-locaux-de-lisib-rue-royale-n150-à-bruxelles">Une journée du libre, pour toutes et tous, pensée pour le monde associatif et les enseignant dans les locaux de l'ISIB, Rue Royale n°150 à Bruxelles</h4>

<p>Depuis 2015, la journée Associalibre est un espace convivial présentant des solutions concrètes, efficaces et éthiques pour soutenir et faciliter l'action associative et militante</p>

<p>Les valeurs portées par les logiciels libres trouvent écho dans celles portées par le monde associatif. Elles distinguent radicalement de ce qui est proposé à la consommation, et, face à la prolifération d'usages virtuels, constituent des clés de développement d'un esprit critique nécessaire dans une culture numérique.</p>

<p>Venez découvrir les possibilités offertes par "le Libre".<br>
Venez rencontrer des représentants locaux de la communauté du Logiciel Libre.<br>
Venez débattre de l'importance du développement d'un esprit critique numérique.</p>

<p>Au programme , conférences, ateliers pratiques, présentations d'outils accessibles et destinés à une utilisation dans le monde associatif et enseignant : la protection de la vie privée, les hébergements alternatifs, les suites LibreOffice et Framasoft, OpenStreetMap, l'autodéfense numérique, la brique Internet.</p>

<p><strong>Participation libre et gratuite,</strong><br>
inscription préalable souhaitée via <a href="http://2017.associalibre.be/?Inscriptions">http://2017.associalibre.be/?Inscriptions</a></p>

<p>L'équipe Staff Associalibre</p><div><a href="https://linuxfr.org/users/mjhvc/journaux/associalibre-19-et-20-octobre-2017-a-bruxelles.epub">Télécharger ce contenu au format Epub</a></div>    <p><a href="https://linuxfr.org/users/mjhvc/journaux/associalibre-19-et-20-octobre-2017-a-bruxelles#comments">Lire les commentaires</a></p>


guid: tag:linuxfr.org,2005:Diary/37501
title: Après le kit HiFive, QWERTY Embedded Design propose un nouveau kit lowcost : LoFive
author: martoni
feedurl: http://linuxfr.org/journaux.atom
url:
https://linuxfr.org/users/martoni/journaux/apres-le-kit-hifive-qwerty-embedded-design-propose-un-nouveau-kit-lowcost-lofive

content:
<p><a href="//linuxfr.org/users/martoni/journaux/hifive1-un-arduino-a-320mhz-entierement-libre-pour-2017">Dans un premier journal</a>, je vous avais parlé du kit de développement HiFive permettant de développer sur le microcontrôleur libre E310 et compatible avec la chaîne de développement arduino. Une petite société (QWERTY Embedded Design) avait lancé un financement «participatif» pour produire un kit compatible arduino basé sur ce processeur.</p>

<p>La production de ce premier batch s'étant bien déroulée, la société a lancé un autre module plus petit basé sur ce même processeur.</p>

<p>Le module minimaliste (25$) permet tout de même de stocker des données sur une mémoire de masse en spi (16Mo) de générer des PWM, communiquer par uart et bien d'autres joyeusetés en gpio.</p>

<p>L'avantage de ce module c'est que justement c'est un module ! donc on peut envisager de l'intégrer dans un éventuel produit. Le module est toujours intégralement open-source, avec les schéma et routage fait via Kicad.</p>

<p>La livraison du kit est prévue pour la fin de cette année.</p>

<ul>
<li><p><a href="https://groupgets.com/campaigns/353-lofive-risc-v">Le financement participatif du module</a></p></li>
<li><p><a href="https://www.sifive.com/documentation/chips/freedom-e310-g000-manual/">La datasheet du E310</a></p></li>
<li><p><a href="https://github.com/mwelling/lofive">Le github des fichiers de fabrication du module</a></p></li>
<li><p><a href="http://www.qwertyembedded.com/">La société  QWERTY Embedded Design, LLC ayant conçu les modules HiFive1 et LoFive</a></p></li>
<li><p><a href="https://www.sifive.com">La société SiFive ayant fabriqué le E310 basé sur le jeux d'instruction Risc-V</a></p></li>
<li><p><a href="https://riscv.org/">La fondation Risc-V (initiée par l'université de berkley) qui maintient les spécifications du jeux d'instruction<br>
éponyme</a></p></li>
</ul><div><a href="https://linuxfr.org/users/martoni/journaux/apres-le-kit-hifive-qwerty-embedded-design-propose-un-nouveau-kit-lowcost-lofive.epub">Télécharger ce contenu au format Epub</a></div>    <p><a href="https://linuxfr.org/users/martoni/journaux/apres-le-kit-hifive-qwerty-embedded-design-propose-un-nouveau-kit-lowcost-lofive#comments">Lire les commentaires</a></p>


guid: tag:linuxfr.org,2005:Diary/37502
title: Un rapport montre que le téléchargement n'est pas si néfaste…
author: postroutine
feedurl: http://linuxfr.org/journaux.atom
url:
https://linuxfr.org/users/postroutine/journaux/un-rapport-montre-que-le-telechargement-n-est-pas-si-nefaste

content:
<p>…Et l'union européenne ne veut pas le montrer.</p>

<p>Un petit journal "bookmark" pour parler du téléchargement illégal.</p>

<p>En 2014, la Commission Européenne a commandé un rapport sur le téléchargement illégal. Ce rapport couvre les films, la musique, les livres numériques et les jeux vidéos.</p>

<p>Il fut terminé en mai 2015 mais jamais publié. Le rapport démontre qu'à l'exception des films "blockbuster", une analyse statistique ne démontre pas qu'il y ai d'effets négatifs du téléchargement illégal sur la vente.</p>

<p>Et visiblement, il a été difficile d'obtenir le dit rapport. Comme l'explique Julia Reda, la seul Pirate du Parlement Européen, sur son blog.</p>

<p>Voici les liens:<br>
-   <a href="https://thenextweb.com/eu/2017/09/21/eu-paid-report-concluded-piracy-isnt-harmful-tried-hide-findings/">Article sur The Next Web</a><br>
-   <a href="https://juliareda.eu/2017/09/secret-copyright-infringement-study/">Article sur le blog de Julia Reda</a><br>
-   [Échanges d'e-mails entre Julia Reda et et le secrétariat général de la commission européenne] <a href="https://www.asktheeu.org/en/request/estimating_displacement_rates_of">https://www.asktheeu.org/en/request/estimating_displacement_rates_of</a>)</p><div><a href="https://linuxfr.org/users/postroutine/journaux/un-rapport-montre-que-le-telechargement-n-est-pas-si-nefaste.epub">Télécharger ce contenu au format Epub</a></div>    <p><a href="https://linuxfr.org/users/postroutine/journaux/un-rapport-montre-que-le-telechargement-n-est-pas-si-nefaste#comments">Lire les commentaires</a></p>


guid: tag:linuxfr.org,2005:Diary/37503
title: Java 9 est dehors
author: devnewton
url: https://linuxfr.org/users/devnewton/journaux/java-9-est-dehors
feedurl: http://linuxfr.org/journaux.atom
content:
<p>Bonjour Nal,</p>

<p>Je t'écris pour t'informer de la sortie de la nouvelle et très attendue version majeure de <a href="https://docs.oracle.com/javase/9/">Java</a>, l'une des plus grosses plateformes de développement du marché. Voici un petit tour des nouveautés:</p>

<p><img src="//img.linuxfr.org/img/68747470733a2f2f646f63732e6f7261636c652e636f6d2f6a61766173652f392f64636f6d6d6f6e2f696d672f312d6a6176612e706e67/1-java.png" alt="Titre de l'image" title="Source : https://docs.oracle.com/javase/9/dcommon/img/1-java.png"></p>
<h3 id="victime-de-jmod">Victime de jmod</h3>

<p>La principale nouveauté est l'introduction d'un système de modules. Ce système mérite un journal complet, mais le principal apport sera de debloated (un peu) le runtime et les applications java.</p>
<h3 id="dans-les-poèmes-de-jshell">Dans les poèmes de jshell</h3>

<p>Un outil <a href="https://docs.oracle.com/javase/9/jshell/introduction-jshell.htm">jshell</a> permets de jouer avec le langage en ligne de commande et utiliser le langage pour faire du <a href="https://docs.oracle.com/javase/9/jshell/scripts.htm">scripting</a>: pratique pour remplacer des scripts shell ou python!</p>

<pre><code>    jshell&gt; double PI = 3.1415926535
    PI ==&gt; 3.1415926535
    |  created variable PI : double

    jshell&gt; volume(2)
    |  attempted to call method volume(double) which cannot be invoked until method cube(double) is declared

    jshell&gt; double cube(double x) { return x * x * x; }
    |  created method cube(double)
    |    update modified method volume(double)

    jshell&gt; volume(2)
    $5 ==&gt; 33.510321637333334
    |  created scratch variable $5 : double
</code></pre>
<h3 id="applet-mon-numéro">Applet mon numéro</h3>

<p>Une excellente nouvelle: le plugin java pour navigateur va rejoindre Flash et Silverlight dans le purgatoire des technologies pénibles.</p>
<h3 id="what-string-color">What string color</h3>

<p>Les chaînes de caractères prendront <a href="http://openjdk.java.net/jeps/254">moins de place</a> en mémoire si elles contiennent des caractères latin1.</p>
<h3 id="ramasse-miettes-chouette-cest-sympa">Ramasse miettes, chouette, c'est sympa</h3>

<p>G1 sera désormais le ramasse miettes par défaut. L'idée est de privilégier la faible latence. Des impacts sont à prévoir sur les applications en production: il faudra faire des tests sérieux pour voir s'il y a un gain ou perte, chaque application ayant des besoins et des objectifs différents.</p>
<h3 id="trololog">Trololog</h3>

<p>Une nouvelle API de <a href="http://openjdk.java.net/jeps/264">logging minimaliste</a> a été ajoutée. Je n'ai pas compris pourquoi ce changement, l'API actuelle n'étant pas bien compliquée.</p>
<h3 id="utf-8-vaincra">UTF-8 vaincra</h3>

<p>Les fichiers *.properties pourront enfin être écrits en <a href="http://openjdk.java.net/jeps/226">UTF-8</a>. Ces fichiers, souvent utilisés pour l'internationalisation, étaient limités à ISO-8859-1…</p>
<h3 id="autres-changements">Autres changements</h3>

<ul>
<li>les chauves seront contents d'apprendre l'ajout d'une API pour manipuler des <a href="http://openjdk.java.net/jeps/262">TIFF</a>
</li>
<li>la gestion du HiDPI permettra de ne plus saigner des yeux sous <a href="http://openjdk.java.net/jeps/263">linux et windows</a>
</li>
<li>GTK3 est enfin géré, il faudra toutefois l'activer via la propriété jdk.gtk.version</li>
</ul><div><a href="https://linuxfr.org/users/devnewton/journaux/java-9-est-dehors.epub">Télécharger ce contenu au format Epub</a></div>    <p><a href="https://linuxfr.org/users/devnewton/journaux/java-9-est-dehors#comments">Lire les commentaires</a></p>


guid: tag:linuxfr.org,2005:Diary/37504
title: En marche
author: devnewton
url: https://linuxfr.org/users/devnewton/journaux/en-marche
feedurl: http://linuxfr.org/journaux.atom
content:
<p>Ah Nal,</p>

<p>J'ai oublié dans mon précédent journal de te rappeler qu'aujourd'hui est prévu une <em>marche contre le coup d'État social d'Emmanuel Macron, qui veut détruire le code du travail à coup d'ordonnances</em>.</p>

<p><img src="//img.linuxfr.org/img/68747470733a2f2f62332e6263692e696d2f7061737465642f64303831353763312d313834302d343261332d623034652d6461303939663566316439652e6a7067/d08157c1-1840-42a3-b04e-da099f5f1d9e.jpg" alt="ordonnances" title="Source : https://b3.bci.im/pasted/d08157c1-1840-42a3-b04e-da099f5f1d9e.jpg"></p>

<p>Outre les habituels défilés et revendications, la rumeur indique que Philippe Martinez et Pierre Laurent danseront le mambo sur l'air de <em>Je suis Sancho de Cuba</em> pour clore la journée.</p>

<p>On prétends aussi que, jaloux, Jean Luc Mélenchon aurait fait venir l'orchestre national de Caracas par le premier avion (en seconde classe) afin d'entonner l'hymne vénézuélienne au même moment.</p>

<p>Quoiqu'il en soit, l'évènement sera expertisé en direct depuis la <a href="//linuxfr.org/board/">tribune</a>.</p><div><a href="https://linuxfr.org/users/devnewton/journaux/en-marche.epub">Télécharger ce contenu au format Epub</a></div>    <p><a href="https://linuxfr.org/users/devnewton/journaux/en-marche#comments">Lire les commentaires</a></p>


guid: tag:linuxfr.org,2005:Diary/37505
title: [Btrfs et openSUSE] Épisode 5 : les quotas
author: AR7
url: https://linuxfr.org/users/ar7/journaux/btrfs-et-opensuse-episode-5-les-quotas
feedurl: http://linuxfr.org/journaux.atom
content:
<h2 class="sommaire">Sommaire</h2>
<ul class="toc">
<li>
<a href="#btrfs-et-les-quotas-intro">Btrfs et les quotas : <em>intro</em></a><ul>
<li><a href="#les-quotas-quest-ce-que-cest">Les quotas, qu'est-ce que c'est ?</a></li>
<li><a href="#les-qgroups">Les <code>qgroups</code></a></li>
</ul>
</li>
<li>
<a href="#jouons-avec-les-quotas">Jouons avec les quotas</a><ul>
<li><a href="#activer-les-quotas-btrfs-quota">Activer les quotas : <code>btrfs quota</code></a></li>
<li>
<a href="#g%C3%A9rer-les-qgroups-btrfs-qgroup">Gérer les <em>qgroups</em> : <code>btrfs qgroup</code></a><ul>
<li><a href="#afficher-les-qgroups-show">Afficher les <em>qgroups</em> : <code>show</code></a></li>
<li><a href="#supprimer-des-qgroups-destroy">Supprimer des <em>qgroups</em> : <code>destroy</code></a></li>
<li><a href="#cr%C3%A9er-des-hi%C3%A9rarchies-de-qgroups-create-et-assign">Créer des hiérarchies de <em>qgroups</em> : <code>create</code> et <code>assign</code></a></li>
<li><a href="#fixer-des-limites-%C3%A0-un-qgroup-limit">Fixer des limites à un <em>qgroup</em> : <code>limit</code></a></li>
</ul>
</li>
<li><a href="#transactions-estimations-reflink-et-quotas">Transactions, estimations, <code>reflink</code> et quotas</a></li>
</ul>
</li>
<li>
<a href="#cas-pratique-avec-snapper">Cas pratique avec snapper</a><ul>
<li><a href="#un-probl%C3%A8me-de-taille">Un problème de taille</a></li>
<li><a href="#la-commande-magique-snapper-setup-quota">La commande magique : <code>snapper setup-quota</code></a></li>
</ul>
</li>
<li>
<a href="#btrfs-et-les-quotas-outro">Btrfs et les quotas : <em>outro</em></a><ul>
<li><a href="#statut-de-la-fonctionnalit%C3%A9-mostly-ok">Statut de la fonctionnalité : <em>Mostly OK</em></a></li>
<li><a href="#sur-opensuse">Sur openSUSE</a></li>
</ul>
</li>
<li><a href="#liens">Liens</a></li>
</ul><p><img src="//img.linuxfr.org/img/68747470733a2f2f6f70656e636c69706172742e6f72672f696d6167652f33303070782f7376675f746f5f706e672f3137303336392f486172642d4469736b2e706e67/Hard-Disk.png" alt="Btrfs is hard" title="Source : https://openclipart.org/image/300px/svg_to_png/170369/Hard-Disk.png"></p>

<p><strong>« Btrfs et openSUSE »</strong> est une série de journaux sur le système de fichiers Btrfs, basée sur ma propre expérience d'utilisateur d'openSUSE. Au menu :</p>

<ul>
<li>des généralités sur Btrfs <a href="//linuxfr.org/users/ar7/journaux/btrfs-et-opensuse-episode-0-l-ex-fs-du-futur">☑</a>
</li>
<li>des noms qui pètent : sous-volumes, <em>snapshots</em>, <em>rollbacks</em> <a href="//linuxfr.org/users/ar7/journaux/btrfs-et-opensuse-episode-1-sous-volumes-snapshots-et-rollbacks">☑</a>
</li>
<li>du snapper <a href="//linuxfr.org/users/ar7/journaux/btrfs-et-opensuse-episode-2-snapper-et-grub2#snapper--un-gestionnaire-dinstantan%C3%A9s">☑</a>
</li>
<li>du grub <a href="//linuxfr.org/users/ar7/journaux/btrfs-et-opensuse-episode-2-snapper-et-grub2#grub2--booter-sur-du-btrfs">☑</a>
</li>
<li>de la mise à jour incrémentale <a href="//linuxfr.org/users/ar7/journaux/btrfs-et-opensuse-episode-4-le-transfert-de-sous-volume">☑</a>
</li>
<li>des quotas</li>
<li>de la maintenance <a href="//linuxfr.org/users/ar7/journaux/btrfs-et-opensuse-episode-3-un-peu-de-maintenance">☑</a>
</li>
<li>des trucs spécifiques à openSUSE</li>
<li>des tentatives désespérées pour rester applicable à d'autres distributions</li>
<li>des erreurs (pas taper)</li>
<li>des bugs</li>
<li>des cris</li>
<li>des larmes</li>
<li>et bien plus ! ou bien moins</li>
</ul><p><strong>Aujourd'hui, l'épisode 5 : les quotas.</strong></p>
<h2 id="btrfs-et-les-quotas-intro">Btrfs et les quotas : <em>intro</em>
</h2>
<h3 id="les-quotas-quest-ce-que-cest">Les quotas, qu'est-ce que c'est ?</h3>

<p>Un quota, dans le contexte d'un système de fichiers, c'est une limite imposée à un ou plusieurs utilisateurs sur la quantité de données qu'il(s) peu(ven)t conserver dans un ou plusieurs emplacements de l'arborescence.</p>

<p>Typiquement, cela est utile dans le cas d'un système multi-utilisateurs, afin de garantir un partage équitable des ressources.</p>
<h3 id="les-qgroups">Les <code>qgroups</code>
</h3>

<p>Btrfs n'utilise pas la définition traditionnelle des quotas. Pour lui, un quota ne s'applique pas directement à un utilisateur mais plutôt à <a href="//linuxfr.org/users/ar7/journaux/btrfs-et-opensuse-episode-1-sous-volumes-snapshots-et-rollbacks#sousvolume">un sous-volume</a> (par exemple <code>@/home/toto</code>) ou à un groupe de sous-volumes (par exemple <code>@/home/toto/</code> + <code>@/home/toto/.snapshots</code>).</p>

<p>On parle alors de <em>qgroup</em> pour exprimer ces ensembles limités en taille. Ou plutôt en taille​<strong>s</strong>.</p>

<p>En effet, l'utilisation du <a href="//linuxfr.org/users/ar7/journaux/btrfs-et-opensuse-episode-0-l-ex-fs-du-futur#cow--copy-on-write"><em>Copy-on-Write</em></a> fait que des fichiers situés dans des sous-volumes différents – et donc comptabilisés dans des <em>qgroups</em> différents – peuvent partager la même donnée au niveau bloc, par exemple suite à la création d'un instantané.</p>

<p>Dans ce cas, à quel sous-volume appliquer une limite ? Au sous-volume d'origine ? À tous les sous-volumes ?</p>

<p>Btrfs résout ce problème en permettant de fixer des limites pour deux types de taille :</p>

<ul>
<li>la taille totale des données référencées par ce <em>qgroup</em>, potentiellement partagées avec d'autres <em>qgroups</em> ;</li>
<li>la taille des données exclusives à ce <em>qgroup</em>, non partagées avec d'autres <em>qgroups</em>.</li>
</ul><h2 id="jouons-avec-les-quotas">Jouons avec les quotas</h2>
<h3 id="activer-les-quotas-btrfs-quota">Activer les quotas : <code>btrfs quota</code>
</h3>

<p><img src="//img.linuxfr.org/img/68747470733a2f2f692e67697068792e636f6d2f6d656469612f4e777a364e5a6b546f5943344d2f67697068792d646f776e73697a65642e676966/giphy-downsized.gif" alt="wake up" title="Source : https://i.giphy.com/media/Nwz6NZkToYC4M/giphy-downsized.gif"></p>

<p>Sur un système de fichiers fraîchement créé, les quotas sont désactivés.</p>

<p>La commande <code>btrfs quota</code> permet de les activer :</p>

<pre><code>~# btrfs quota
usage: btrfs quota &lt;command&gt; [options] &lt;path&gt;

    btrfs quota enable &lt;path&gt;
        Enable subvolume quota support for a filesystem.
    btrfs quota disable &lt;path&gt;
        Disable subvolume quota support for a filesystem.
    btrfs quota rescan [-sw] &lt;path&gt;
        Trash all qgroup numbers and scan the metadata again with the current config.

manage filesystem quota settings
~# btrfs quota enable /
~#
</code></pre>

<p>Lors de la première activation, Btrfs va automatiquement lancer une réanalyse des quotas et créer des <em>qgroups</em> pour les sous-volumes existants.</p>
<h3 id="gérer-les-qgroups-btrfs-qgroup">Gérer les <em>qgroups</em> : <code>btrfs qgroup</code>
</h3>
<h4 id="afficher-les-qgroups-show">Afficher les <em>qgroups</em> : <code>show</code>
</h4>

<p>Tout simplement :</p>

<pre><code class="sh">~# btrfs qgroup show /
qgroupid         rfer         excl 
--------         ----         ---- 
<span class="m">0</span>/5          <span class="m">16</span>.00KiB     <span class="m">16</span>.00KiB 
<span class="m">0</span>/257         <span class="m">2</span>.36MiB      <span class="m">2</span>.36MiB 
<span class="m">0</span>/258        <span class="m">16</span>.00KiB     <span class="m">16</span>.00KiB 
<span class="m">0</span>/259        <span class="m">16</span>.00KiB     <span class="m">16</span>.00KiB 
<span class="m">0</span>/260         <span class="m">1</span>.23MiB      <span class="m">1</span>.23MiB 
<span class="m">0</span>/261        <span class="m">12</span>.58MiB     <span class="m">12</span>.58MiB 
<span class="m">0</span>/262        <span class="m">16</span>.00KiB     <span class="m">16</span>.00KiB 
<span class="m">0</span>/263        <span class="m">16</span>.00KiB     <span class="m">16</span>.00KiB 
<span class="m">0</span>/264        <span class="m">16</span>.00KiB     <span class="m">16</span>.00KiB 
<span class="m">0</span>/265        <span class="m">16</span>.00KiB     <span class="m">16</span>.00KiB 
<span class="m">0</span>/266        <span class="m">16</span>.00KiB     <span class="m">16</span>.00KiB 
<span class="m">0</span>/267       <span class="m">403</span>.54MiB    <span class="m">403</span>.54MiB 
<span class="m">0</span>/268        <span class="m">16</span>.00KiB     <span class="m">16</span>.00KiB 
<span class="m">0</span>/269       <span class="m">340</span>.00KiB    <span class="m">340</span>.00KiB 
<span class="m">0</span>/270         <span class="m">2</span>.16GiB      <span class="m">2</span>.16GiB 
<span class="m">0</span>/275        <span class="m">16</span>.00KiB     <span class="m">16</span>.00KiB 
<span class="m">0</span>/2779       <span class="m">16</span>.00KiB     <span class="m">16</span>.00KiB 
<span class="m">0</span>/5692        <span class="m">1</span>.23GiB      <span class="m">1</span>.23GiB 
<span class="m">0</span>/6046       <span class="m">16</span>.00KiB     <span class="m">16</span>.00KiB 
<span class="m">0</span>/6047        <span class="m">8</span>.03GiB    <span class="m">248</span>.00KiB 
<span class="m">0</span>/6048        <span class="m">8</span>.03GiB    <span class="m">276</span>.00KiB 
<span class="m">0</span>/6049        <span class="m">8</span>.03GiB    <span class="m">160</span>.33MiB 
<span class="m">0</span>/6050        <span class="m">8</span>.03GiB    <span class="m">424</span>.00KiB 
<span class="m">0</span>/6051        <span class="m">8</span>.03GiB     <span class="m">30</span>.09MiB 
~#</code></pre>

<p>Ici, on voit les <em>qgroups</em> qui ont été créés automatiquement lors de l'activation des quotas. Chaque sous-volume est rangé dans un <em>qgroup</em>, <code>0/x</code> ou <code>x</code> est l'identifiant du sous-volume. On parle de <em>qgroup</em> de niveau 0.</p>

<p>Deux autres colonnes sont présentes :</p>

<ul>
<li>
<strong>rfer</strong>, qui représente la quantité de données que référence le <em>qgroup</em>.</li>
<li>
<strong>excl</strong>, qui représente la quantité de données exclusive à ce <em>qgroup</em>.</li>
</ul><p>Par exemple, pour le sous-volume 6051 :</p>

<pre><code class="sh">~# btrfs subvolume list / <span class="p">|</span> grep <span class="m">6051</span>
ID <span class="m">6051</span> gen <span class="m">447643</span> top level <span class="m">275</span> path @/.snapshots/101/snapshot <span class="c1"># c'est un instantané</span>
~# btrfs qgroup show / <span class="p">|</span> awk <span class="s1">'NR &lt;= 2 || /6051/'</span>
qgroupid         rfer         excl 
--------         ----         ---- 
<span class="m">0</span>/6051        <span class="m">8</span>.03GiB     <span class="m">30</span>.11MiB 
~#</code></pre>

<p>Le <em>qgroup</em> associé <code>0/6051</code> référence 8,03 Gio de données dont 30,11 Mio ne sont pas partagées avec d'autres <em>qgroups</em> (donc d'autres sous-volumes).</p>

<p>C'est beaucoup plus rapide de connaître la taille d'un sous-volume entier avec <code>btrfs qgroup show</code>, qui garde le compte de la quantité de données présentes, qu'avec <a href="//linuxfr.org/users/ar7/journaux/btrfs-et-opensuse-episode-3-un-peu-de-maintenance#quelle-taille-prennent-mes-instantan%C3%A9s"><code>btrfs filesystem du</code></a>, qui doit faire le compte à chaque appel.</p>

<p>Enfin, il est possible d'utiliser des options pour détailler l'affichage :</p>

<ul>
<li>Les options <code>-r</code> et <code>-e</code> permettent de rajouter deux autres colonnes pour afficher les limites de tailles appliquées. Par défaut, aucune limite n'est appliquée.</li>
<li>Les options <code>-p</code> et <code>-c</code> permettent d'afficher les liens de parenté entre les <em>qgroups</em>.</li>
</ul><pre><code class="sh">~# btrfs qgroup show -pcre / <span class="p">|</span> awk <span class="s1">'NR &lt;= 2 || /6051/'</span>
qgroupid         rfer         excl     max_rfer     max_excl parent   child
--------         ----         ----     --------     -------- ------   -----
<span class="m">0</span>/6051        <span class="m">8</span>.03GiB     <span class="m">30</span>.11MiB         none         none ---      ---
~#</code></pre>
<h4 id="supprimer-des-qgroups-destroy">Supprimer des <em>qgroups</em> : <code>destroy</code>
</h4>

<p>Si les quotas sont activés, un nouveau <em>qgroup</em> <code>0/x</code> est créé automatiquement à la création d'un sous-volume/<em>snapshot</em> avec l'ID <code>x</code>. Cependant, aucun <em>qgroup</em> n'est détruit à la suppression d'un sous-volume. Cela se voit très bien après la suppression de quelques instantanés :</p>

<pre><code class="sh">~# btrfs subvolume delete <span class="m">6063</span> /
~# btrfs subvolume delete <span class="m">6064</span> /
~# btrfs subvolume delete <span class="m">6065</span> /
~# btrfs qgroup show / <span class="p">|</span> awk <span class="s1">'NR &lt;= 2 || /606/'</span>
qgroupid         rfer         excl 
--------         ----         ---- 
<span class="m">0</span>/6063          <span class="m">0</span>.00B        <span class="m">0</span>.00B 
<span class="m">0</span>/6064          <span class="m">0</span>.00B        <span class="m">0</span>.00B 
<span class="m">0</span>/6065          <span class="m">0</span>.00B        <span class="m">0</span>.00B 
~#</code></pre>

<p>Il est possible de supprimer ces <em>qgroups</em> vides avec <code>btrfs qgroup destroy</code> :</p>

<pre><code class="sh">~# btrfs qgroup destroy <span class="m">0</span>/6063 /
~# btrfs qgroup destroy <span class="m">0</span>/6064 /
~# btrfs qgroup destroy <span class="m">0</span>/6065 /
~#</code></pre>

<p>La suppression automatique de ces <em>qgroups</em> de niveau 0 <a href="https://www.mail-archive.com/linux-btrfs@vger.kernel.org/msg67939.html">sera peut-être implémentée prochainement</a>. En attendant, on peut utiliser <a href="//linuxfr.org/users/ar7/journaux/btrfs-et-opensuse-episode-2-snapper-et-grub2#cr%C3%A9er-et-supprimer-des-instantan%C3%A9s">snapper</a> qui se charge de ce nettoyage.</p>
<h4 id="créer-des-hiérarchies-de-qgroups-create-et-assign">Créer des hiérarchies de <em>qgroups</em> : <code>create</code> et <code>assign</code>
</h4>

<p>Un <em>qgroup</em> est un groupe de sous-volumes…</p>

<p><img src="//img.linuxfr.org/img/68747470733a2f2f696d672e6d656d6563646e2e636f6d2f6275742d77686f2d69732d696e2d6368617267655f635f353131373032372e6a7067/but-who-is-in-charge_c_5117027.jpg" alt="hiérarchie" title="Source : https://img.memecdn.com/but-who-is-in-charge_c_5117027.jpg"></p>

<p>… ou un groupe de <em>qgroups</em>.</p>

<p>En effet, on n'est pas limité à un seul niveau on peut avoir un arbre de <em>qgroups</em> !</p>

<pre><code>                          +---+
                          |2/1|
                          +---+
                         /     \
                   +---+/       \+---+
                   |1/1|         |1/2|
                   +---+         +---+
                  /     \       /     \
            +---+/       \+---+/       \+---+
qgroups     |0/1|         |0/2|         |0/3|
            +-+-+         +---+         +---+
              |          /     \       /     \
              |         /       \     /       \
              |        /         \   /         \
extents       1       2            3            4

</code></pre>

<p>La commande pour assigner un <em>qgroup</em> à un <em>qgroup</em> parent est la suivante :</p>

<pre><code>~# btrfs qgroup assign --help
usage: btrfs qgroup assign [options] &lt;src&gt; &lt;dst&gt; &lt;path&gt;

    Assign SRC as the child qgroup of DST

    --rescan       schedule qutoa rescan if needed
    --no-rescan    don't schedule quota rescan

</code></pre>

<p>Du coup, pour créer un arbre similaire à celui représenté plus haut :</p>

<pre><code class="sh">~# <span class="c1"># qgroups de niveau 1</span>
~# btrfs qgroup create <span class="m">1</span>/1 /
~# btrfs qgroup create <span class="m">1</span>/2 /
~#
~# <span class="c1"># qgroup de niveau 2</span>
~# btrfs qgroup create <span class="m">2</span>/1 /
~#
~# <span class="c1"># Assignation</span>
~# btrfs qgroup assign <span class="m">1</span>/1 <span class="m">2</span>/1 /
~# btrfs qgroup assign <span class="m">1</span>/2 <span class="m">2</span>/1 /</code></pre>

<p>Cela n'a pas de sens de créer les <em>qgroups</em> de niveau 0 à la main, vu qu'ils correspondent directement à un sous-volume et que Btrfs les crée pour nous.</p>

<p>Il est cependant possible de combiner la création d'un sous-volume à l'assignation à un <em>qgroup</em> parent :</p>

<pre><code class="sh">~# <span class="c1"># L'option -i ("inherit") est aussi disponible sur btrfs subvolume snapshot</span>
~# btrfs subvolume create -i <span class="m">1</span>/1 /a
~# btrfs subvolume create -i <span class="m">1</span>/1 -i <span class="m">1</span>/2 /b
~# btrfs subvolume create -i <span class="m">1</span>/2 /c</code></pre>

<p>Et voilà le résultat !</p>

<pre><code class="sh">~# btrfs qgroup show -pc / <span class="p">|</span> awk <span class="s1">'NR &lt;= 2 || /1\/[12]/'</span>
qgroupid         rfer         excl parent   child
--------         ----         ---- ------   -----
<span class="m">0</span>/6119       <span class="m">16</span>.00KiB     <span class="m">16</span>.00KiB <span class="m">1</span>/1      ---
<span class="m">0</span>/6120       <span class="m">16</span>.00KiB     <span class="m">16</span>.00KiB <span class="m">1</span>/1,1/2  ---
<span class="m">0</span>/6121       <span class="m">16</span>.00KiB     <span class="m">16</span>.00KiB <span class="m">1</span>/2      ---
<span class="m">1</span>/1          <span class="m">32</span>.00KiB     <span class="m">32</span>.00KiB <span class="m">2</span>/1      <span class="m">0</span>/6119,0/6120
<span class="m">1</span>/2          <span class="m">32</span>.00KiB     <span class="m">32</span>.00KiB <span class="m">2</span>/1      <span class="m">0</span>/6120,0/6121
<span class="m">2</span>/1          <span class="m">48</span>.00KiB     <span class="m">48</span>.00KiB ---      <span class="m">1</span>/1,1/2
~#</code></pre>
<h4 id="fixer-des-limites-à-un-qgroup-limit">Fixer des limites à un <em>qgroup</em> : <code>limit</code>
</h4>

<p><img src="//img.linuxfr.org/img/687474703a2f2f7069782e746f696c652d6c696272652e6f72672f75706c6f61642f6f726967696e616c2f313530363031343339392e676966/1506014399.gif" alt="limites" title="Source : http://pix.toile-libre.org/upload/original/1506014399.gif"></p>

<p>Voilà, voilà, on y arrive : il est possible de mettre des limites aux tailles d'un <em>qgroup</em>. Et c'est heureux parce que c'est un peu le but de toute cette affaire.</p>

<pre><code>~# btrfs qgroup limit --help
usage: btrfs qgroup limit [options] &lt;size&gt;|none [&lt;qgroupid&gt;] &lt;path&gt;

    Set the limits a subvolume quota group.

    -c   limit amount of data after compression. This is the default,
         it is currently not possible to turn off this option.
    -e   limit space exclusively assigned to this qgroup

~#
</code></pre>

<p>Exemple :</p>

<pre><code class="sh">~# <span class="c1"># Créons les sous-volumes '/test', '/test/a' et '/test/b'</span>
~# btrfs subvolume create /test/
Create subvolume <span class="s1">'//test'</span>
~# btrfs subvolume create /test/a
Create subvolume <span class="s1">'//test/a'</span>
~# btrfs subvolume create /test/b
Create subvolume <span class="s1">'//test/b'</span>
~# btrfs qgroup show -erF /test/a/
qgroupid         rfer         excl     max_rfer     max_excl 
--------         ----         ----     --------     -------- 
<span class="m">0</span>/6067       <span class="m">16</span>.00KiB     <span class="m">16</span>.00KiB         none         none
~#
~# <span class="c1"># Assignons des limites à '/test/a'</span>
~# btrfs qgroup limit 10m <span class="m">0</span>/6067 /
~# btrfs qgroup limit -e 5m <span class="m">0</span>/6067 /
~# btrfs qgroup show -erF /test/a/
qgroupid         rfer         excl     max_rfer     max_excl 
--------         ----         ----     --------     -------- 
<span class="m">0</span>/6067       <span class="m">16</span>.00KiB     <span class="m">16</span>.00KiB     <span class="m">10</span>.00MiB      <span class="m">5</span>.00MiB
~#</code></pre>

<p>On a créé nos limites. Maintenant, testons si elles marchent :</p>

<pre><code class="sh">~# dd <span class="k">if</span><span class="o">=</span>/dev/urandom <span class="nv">of</span><span class="o">=</span>/test/a/bigfile <span class="nv">bs</span><span class="o">=</span>1M <span class="nv">count</span><span class="o">=</span><span class="m">50</span>
dd: erreur d´écriture de <span class="s1">'/test/a/bigfile'</span>: Débordement du quota d´espace disque
<span class="m">5</span>+0 enregistrements lus
<span class="m">4</span>+0 enregistrements écrits
<span class="m">5046272</span> bytes <span class="o">(</span><span class="m">5</span>,0 MB, <span class="m">4</span>,8 MiB<span class="o">)</span> copied, <span class="m">1</span>,04639 s, <span class="m">4</span>,8 MB/s
~# btrfs qgroup show --sync -erF /test/a/
qgroupid         rfer         excl     max_rfer     max_excl 
--------         ----         ----     --------     -------- 
<span class="m">0</span>/6067        <span class="m">4</span>.83MiB      <span class="m">4</span>.83MiB     <span class="m">10</span>.00MiB      <span class="m">5</span>.00MiB
~#</code></pre>

<p>Pour la taille exclusive, cela semble marcher. On a essayé de créer un fichier de 50 Mio en faisant 50 blocs de 1 Mio, mais une erreur quota est survenue au moment de l'écriture du 5<sup>e</sup> Mio.</p>

<p>Mais essayons d'aller plus loin, pour la taille <code>rfer</code> :</p>

<pre><code class="sh">~# rm /test/a
~# dd <span class="k">if</span><span class="o">=</span>/dev/urandom <span class="nv">of</span><span class="o">=</span>/test/b/bigfile <span class="nv">bs</span><span class="o">=</span>1M <span class="nv">count</span><span class="o">=</span><span class="m">50</span>
<span class="m">50</span>+0 enregistrements lus
<span class="m">50</span>+0 enregistrements écrits
<span class="m">52428800</span> bytes <span class="o">(</span><span class="m">52</span> MB, <span class="m">50</span> MiB<span class="o">)</span> copied, <span class="m">0</span>,251852 s, <span class="m">208</span> MB/s
~# cp --reflink /test/b/bigfile /test/a/
~# btrfs qgroup show --sync -erF /test/a/
qgroupid         rfer         excl     max_rfer     max_excl 
--------         ----         ----     --------     -------- 
<span class="m">0</span>/6067       <span class="m">50</span>.02MiB     <span class="m">16</span>.00KiB     <span class="m">10</span>.00MiB      <span class="m">5</span>.00MiB
~# touch /test/b/nothing
~# cp --reflink /test/b/nothing /test/a/
cp: impossible de créer le fichier standard <span class="s1">'/test/a/nothing'</span>: Débordement du quota d´espace disque
~#</code></pre>

<p>On remarque truc bizarre : sur un premier <code>cp --reflink</code>, le quota est allègrement dépassé, sans message d'erreur. Une fois le quota dépassé, une erreur est effectivement levée sur le second <code>cp --reflink</code>. Mais pourquoi ?</p>
<h3 id="transactions-estimations-reflink-et-quotas">Transactions, estimations, <code>reflink</code> et quotas</h3>

<p><strong>tl;dr</strong> C'est un bug (<a href="https://bugzilla.opensuse.org/show_bug.cgi?id=1057962">boo#1057962</a>).</p>


<p>Chaque opération sur le système de fichiers est encapsulée dans une transaction. La transaction n'est pas écrite immédiatement : elle est d'abord construire en mémoire. L'espace disque est d'abord <em>réservé</em>.</p>

<p>Avec Btrfs, les données et métadonnées sont mises à des adresses distinctes des données et métadonnées précédentes (<em>Copy-on-Write</em>) ; des arbres (B) distincts les référençant sont créés. Au bout de 30 secondes (durée réglable via <a href="https://btrfs.wiki.kernel.org/index.php/Mount_options">l'option de montage <code>commit</code></a>) ou sur une synchronisation demandée (par exemple avec la commande <code>btrfs filesystem sync</code>), ce qui était en mémoire est écrit sur le disque. En tout dernier, le <a href="https://btrfs.wiki.kernel.org/index.php/Btrfs_design#Btree_Roots"><em>superblock</em></a> est réécrit de façon atomique pour pointer vers les nouveaux arbres. Ce mécanisme garantit que le système de fichiers est toujours consistant à un instant t.</p>

<p>Bref, toute cette digression inutile pour dire que pour les quotas, c'est pareil : l'espace par rapport aux quotas est d'abord <em>réservé</em>. Le seul moment où une erreur de dépassement de quota peut être levée, c'est au début de l'opération, pas au milieu. Le système de fichiers – ce n'est pas spécifique à Btrfs – doit donc estimer l'impact que va avoir l'opération sur la quantité de données référencées par les sous-volumes.</p>

<p>Et c'est là que le bât blesse.</p>

<p>Pour l'opération <code>cp --reflink</code>, c'est-à-dire l'opération de clonage de fichier <a href="http://elixir.free-electrons.com/linux/latest/ident/btrfs_file_operations"><code>clone_file_range</code></a> implémentée par <a href="http://elixir.free-electrons.com/linux/latest/ident/btrfs_clone_file_range"><code>btrfs_clone_file_range</code></a>, l'estimation n'est pas faite. Plus exactement : elle semble faite pour les métadonnées mais pas pour les données. D'où le comportement observé. <a href="https://www.mail-archive.com/linux-btrfs@vger.kernel.org/msg67940.html">Pour le moment</a> du moins ☺</p>
<h2 id="cas-pratique-avec-snapper">Cas pratique avec snapper</h2>

<p><em>Note : pour cette partie, je réutilise des bouts <a href="https://www.alionet.org/content.php?731-Sortie-de-snapper-0-3">d'un article</a> que j'ai écrit sur le forum Alionet.</em></p>
<h3 id="un-problème-de-taille">Un problème de taille</h3>


<p>On en avait parlé <a href="//linuxfr.org/users/ar7/journaux/btrfs-et-opensuse-episode-2-snapper-et-grub2#gare-%C3%A0-la-configuration">dans l'épisode 2</a> : la configuration par défaut de snapper est aussi agressive sur la prise d'instantanés qu'elle est laxiste sur leur nettoyage. D'où des problèmes de systèmes de fichiers saturés par des instantanés.</p>

<p>Depuis la version 0.3, snapper permet d'utiliser les quotas pour nettoyer les instantanés en fonction de l'espace disque utilisé.</p>

<p>Il est à noter qu'il n'y a pas d'utilisation des limites telles qu'on peut les définir avec <code>btrfs qgroup limit</code> : snapper n'utilise les quotas que pour récupérer rapidement la taille des <em>snapshots</em>.</p>

<p>En outre, snapper peut avoir avoir plusieurs configurations, chacune gérant les instantané d'un sous-volume. Par exemple, on peut imaginer la configuration <code>toto</code> pour <code>@/home/toto</code>, <code>tata</code> pour <code>@/home/tata</code>, etc. Chaque configuration aurait un <em>qgroup</em> distinct (<code>1/1</code>, <code>1/2</code>, …) dans le rôle de parent, permettant de fixer à chaque utilisateur des quotas pour ses <em>snapshots</em>.</p>
<h3 id="la-commande-magique-snapper-setup-quota">La commande magique : <code>snapper setup-quota</code>
</h3>

<p>snapper propose une commande pour activer les quotas comme il faut : <code>snapper setup-quota</code>. Le principe est simple :</p>

<ol>
<li>Créer un <em>qgroup</em> de niveau 1, <code>1/0</code> (<code>btrfs qgroup create 1/0 /</code>).</li>
<li>Définir le <em>qgroup</em> de tout nouvel instantané comme enfant de <code>1/0</code> (<code>btrfs subvolume snapshot -i 1/0 /.snapshots/&lt;id&gt;/snapshot</code>).</li>
<li>Supprimer les instantanés les plus anciens quand la taille exclusive de <code>1/0</code> dépasse un seuil prédéfini.</li>
</ol><p>La commande va donc créer les paramètres <code>QGROUP</code> et <code>SPACE_LIMIT</code> dans la configuration de snapper (<code>/etc/snapper/configs/root</code>) :</p>

<pre><code class="sh"><span class="c1"># QGROUP est l'identifiant de votre groupe d'instantanés ; par défaut 1/0</span>
<span class="c1"># Les instantanés seront enregistrés comme des qgroups enfants de $QGROUP</span>
<span class="nv">QGROUP</span><span class="o">=</span><span class="s2">"1/0"</span>

<span class="c1"># Fraction maximale d’espace disque que snapper peut utiliser pour stocker les instantanés</span>
<span class="c1"># 50 % ici, soit tout de même 20 Go pour une partition racine de 40 Go ; vous pouvez l'ajuster comme vous le voulez</span>
<span class="nv">SPACE_LIMIT</span><span class="o">=</span><span class="s2">"0.5"</span></code></pre>

<p>50% c'est beaucoup quand même… mettons 10% plutôt :</p>

<pre><code class="sh">~# snapper set-config <span class="nv">SPACE_LIMIT</span><span class="o">=</span><span class="m">0</span>.1
~#</code></pre>

<p>Pour le reste de la configuration, soyons fous et laissons les valeurs par défaut.</p>

<p>On laisse tourner quelques jours :</p>

<pre><code class="sh">~# btrfs subvolume list -s /
ID <span class="m">258</span> gen <span class="m">12588</span> top level <span class="m">257</span> path .snapshots/1/snapshot
ID <span class="m">366</span> gen <span class="m">12102</span> top level <span class="m">257</span> path .snapshots/3/snapshot
ID <span class="m">369</span> gen <span class="m">12102</span> top level <span class="m">257</span> path .snapshots/6/snapshot
ID <span class="m">370</span> gen <span class="m">12102</span> top level <span class="m">257</span> path .snapshots/7/snapshot
ID <span class="m">371</span> gen <span class="m">12102</span> top level <span class="m">257</span> path .snapshots/8/snapshot
ID <span class="m">372</span> gen <span class="m">12102</span> top level <span class="m">257</span> path .snapshots/9/snapshot
ID <span class="m">373</span> gen <span class="m">12102</span> top level <span class="m">257</span> path .snapshots/10/snapshot
ID <span class="m">379</span> gen <span class="m">12102</span> top level <span class="m">257</span> path .snapshots/15/snapshot
ID <span class="m">382</span> gen <span class="m">12102</span> top level <span class="m">257</span> path .snapshots/18/snapshot
ID <span class="m">383</span> gen <span class="m">12102</span> top level <span class="m">257</span> path .snapshots/19/snapshot
ID <span class="m">389</span> gen <span class="m">12102</span> top level <span class="m">257</span> path .snapshots/25/snapshot
ID <span class="m">394</span> gen <span class="m">12102</span> top level <span class="m">257</span> path .snapshots/30/snapshot
ID <span class="m">396</span> gen <span class="m">12102</span> top level <span class="m">257</span> path .snapshots/31/snapshot
ID <span class="m">401</span> gen <span class="m">12102</span> top level <span class="m">257</span> path .snapshots/35/snapshot
ID <span class="m">402</span> gen <span class="m">12102</span> top level <span class="m">257</span> path .snapshots/36/snapshot
ID <span class="m">403</span> gen <span class="m">12102</span> top level <span class="m">257</span> path .snapshots/37/snapshot
ID <span class="m">404</span> gen <span class="m">12102</span> top level <span class="m">257</span> path .snapshots/38/snapshot
ID <span class="m">406</span> gen <span class="m">12102</span> top level <span class="m">257</span> path .snapshots/39/snapshot
ID <span class="m">411</span> gen <span class="m">12102</span> top level <span class="m">257</span> path .snapshots/44/snapshot
ID <span class="m">416</span> gen <span class="m">12102</span> top level <span class="m">257</span> path .snapshots/49/snapshot
ID <span class="m">417</span> gen <span class="m">12102</span> top level <span class="m">257</span> path .snapshots/50/snapshot
ID <span class="m">418</span> gen <span class="m">12102</span> top level <span class="m">257</span> path .snapshots/51/snapshot
ID <span class="m">419</span> gen <span class="m">12102</span> top level <span class="m">257</span> path .snapshots/52/snapshot
ID <span class="m">421</span> gen <span class="m">12102</span> top level <span class="m">257</span> path .snapshots/54/snapshot
ID <span class="m">426</span> gen <span class="m">12102</span> top level <span class="m">257</span> path .snapshots/59/snapshot
ID <span class="m">428</span> gen <span class="m">12120</span> top level <span class="m">257</span> path .snapshots/60/snapshot
ID <span class="m">429</span> gen <span class="m">12120</span> top level <span class="m">257</span> path .snapshots/61/snapshot
ID <span class="m">430</span> gen <span class="m">12120</span> top level <span class="m">257</span> path .snapshots/62/snapshot
ID <span class="m">431</span> gen <span class="m">12120</span> top level <span class="m">257</span> path .snapshots/63/snapshot
ID <span class="m">432</span> gen <span class="m">12120</span> top level <span class="m">257</span> path .snapshots/64/snapshot
ID <span class="m">433</span> gen <span class="m">12120</span> top level <span class="m">257</span> path .snapshots/65/snapshot
ID <span class="m">434</span> gen <span class="m">12120</span> top level <span class="m">257</span> path .snapshots/66/snapshot
ID <span class="m">435</span> gen <span class="m">12120</span> top level <span class="m">257</span> path .snapshots/67/snapshot
ID <span class="m">436</span> gen <span class="m">12120</span> top level <span class="m">257</span> path .snapshots/68/snapshot
ID <span class="m">437</span> gen <span class="m">12120</span> top level <span class="m">257</span> path .snapshots/69/snapshot
ID <span class="m">438</span> gen <span class="m">12120</span> top level <span class="m">257</span> path .snapshots/70/snapshot
ID <span class="m">439</span> gen <span class="m">12120</span> top level <span class="m">257</span> path .snapshots/71/snapshot
ID <span class="m">441</span> gen <span class="m">12161</span> top level <span class="m">257</span> path .snapshots/72/snapshot
ID <span class="m">442</span> gen <span class="m">12243</span> top level <span class="m">257</span> path .snapshots/73/snapshot
ID <span class="m">443</span> gen <span class="m">12319</span> top level <span class="m">257</span> path .snapshots/74/snapshot
ID <span class="m">444</span> gen <span class="m">12394</span> top level <span class="m">257</span> path .snapshots/75/snapshot
ID <span class="m">445</span> gen <span class="m">12495</span> top level <span class="m">257</span> path .snapshots/76/snapshot
ID <span class="m">446</span> gen <span class="m">12587</span> top level <span class="m">257</span> path .snapshots/77/snapshot
~#</code></pre>

<p>Je vous l'avais dit, les réglages de snapper sont barbares ! Et là les quotas sont activés, je vous laisse imaginer sans ! Bref, ça passe :</p>

<pre><code class="sh">~# btrfs qgroup show / <span class="p">|</span> awk <span class="s1">'NR &lt;= 2 || /1\/0/'</span>
qgroupid         rfer         excl
--------         ----         ---- 
<span class="m">1</span>/0          <span class="m">10</span>.20GiB      <span class="m">4</span>.16GiB
~#</code></pre>

<p><code>1/0</code> est le <em>qgroup</em> parent de tous les instantanés pris par snapper. Il référence 10,20 Gio de données mais seulement 4,16 Gio ne sont pas partagés avec d'autres <em>qgroups</em> (hors enfants), c'est-à-dire avec le sous-volume <code>/</code> actuel.</p>

<p>Ainsi, tous les instantanés « pèsent » 4,16 Gio, soit environ 10% de mon espace disque</p>
<h2 id="btrfs-et-les-quotas-outro">Btrfs et les quotas : <em>outro</em>
</h2>
<h3 id="statut-de-la-fonctionnalité-mostly-ok">Statut de la fonctionnalité : <em>Mostly OK</em>
</h3>

<p>Le wiki Btrfs indique que <a href="https://btrfs.wiki.kernel.org/index.php/Status">la fonctionnalité des quotas est <em>mostly ok</em></a>. Des bugs et des limitations subsistent.</p>

<p>En voici <a href="https://btrfs.wiki.kernel.org/index.php/Quota_support#Known_issues">une liste non-exhaustive</a>, en plus de ce que l'on a vu plus haut :</p>

<ul>
<li>La commande <code>btrfs qgroup show</code> n'affiche pas certaines informations : par exemple, il n'est pas possible pour un <em>qgroup</em> parent de voir les sous-volumes des <em>qgroups</em> enfants.</li>
<li>Créer un <em>qgroup</em> à partir d'un dossier existant affichera une utilisation de 0 jusqu'à une réanalyse complète ne soit effectué (avec <code>btrfs quota rescan</code>).</li>
<li>Combiner les quotas avec beaucoup d'instantanés peut causer des problèmes de performances, notamment au moment de supprimer des instantanés (<a href="https://bugzilla.opensuse.org/show_bug.cgi?id=1017461">boo#1017461</a>, a priori résolu maintenant).</li>
<li>Il est possible que le <em>flag</em> indiquant une réanalyse des quotas en cours se bloque (<a href="https://bugzilla.opensuse.org/show_bug.cgi?id=1047152">boo#1047152</a>) ; le correctif appliqué sur openSUSE Leap a été mergé dans le noyau 4.14.</li>
</ul><h3 id="sur-opensuse">Sur openSUSE</h3>


<p>Malgré ces soucis et limitations, openSUSE active les quotas Btrfs par défaut depuis la sortie de <a href="//linuxfr.org/news/opensuse-leap-42-2-est-sortie">Leap 42.2</a>.</p>

<p>À cette époque, la fonctionnalité avait une implémentation encore plus fragile. Son activation – avant tout pour exploiter les fonctionnalités de snapper 0.3 – avait alors entraîné de <a href="https://lists.opensuse.org/opensuse-factory/2016-09/msg00032.html">vives discussions sur la liste de diffusion opensuse-factory</a>, alors que la distribution n'était qu'en beta. Cette dernière est tout de même sortie comme prévue, moyennant des <em>backports</em> et même quelques correctifs en avance de l'<em>upstream</em>.</p>

<p>Au final, malgré quelques bugs gênants, notamment ces cas de forts ralentissements en cas de <code>btrfs balance</code> ou de suppression d'instantanés, j'ai l'impression que cela aurait pu être pire.</p>

<p>openSUSE continue d'utiliser la fonctionnalité, uniquement pour snapper et les instantanés de <code>/</code> et toujours avec quelques patchs en avance sur l'<em>upstream</em>.</p>

<p><em>That's all folks!</em></p>
<h2 id="liens">Liens</h2>

<ul>
<li>Sur le wiki Btrfs, <a href="https://btrfs.wiki.kernel.org/index.php/Quota_support">la page sur les quotas</a>.</li>
<li>
<a href="http://sensille.com/qgroups.pdf"><em>Btrfs Subvolume Quota Groups</em></a>, par Arne Jansen : un aperçu du concept des <em>qgroups</em> et de leur implémentation originelle.</li>
<li>Dans la série <a href="https://lwn.net/Articles/576276/"><em>LWN's guide to Btrfs</em></a> par Jonathan Corbet, il y a une partie sur les quotas dans l'épisode <a href="https://lwn.net/Articles/579009/">Btrfs: Subvolumes and snapshots</a>.</li>
<li>
<a href="https://github.com/kdave/btrfs-progs/blob/master/Documentation/btrfs-quota.asciidoc"><code>man btrfs-quota</code></a>.</li>
</ul><div><a href="https://linuxfr.org/users/ar7/journaux/btrfs-et-opensuse-episode-5-les-quotas.epub">Télécharger ce contenu au format Epub</a></div>    <p><a href="https://linuxfr.org/users/ar7/journaux/btrfs-et-opensuse-episode-5-les-quotas#comments">Lire les commentaires</a></p>


guid: tag:linuxfr.org,2005:Diary/37506
title: À propos de boohu, un nouveau jeu roguelike, et puis de quelques autres
author: anaseto
feedurl: http://linuxfr.org/journaux.atom
url:
https://linuxfr.org/users/anaseto/journaux/a-propos-de-boohu-un-nouveau-jeu-roguelike-et-puis-de-quelques-autres

content:
<h2 class="sommaire">Sommaire</h2>
<ul class="toc">
<li><a href="#break-out-of-harekas-underground">Break Out Of Hareka's Underground</a></li>
<li>
<a href="#mes-exp%C3%A9riences-avec-dautres-roguelikes">Mes expériences avec d'autres roguelikes</a><ul>
<li><a href="#dungeon-crawl-stone-soup">Dungeon Crawl Stone Soup</a></li>
<li><a href="#brogue">Brogue</a></li>
<li><a href="#tales-of-majeyal">Tales of Maj'Eyal</a></li>
<li><a href="#cataclysm-dark-days-ahead">Cataclysm: Dark Days Ahead</a></li>
<li><a href="#hyperrogue">Hyperrogue</a></li>
<li><a href="#autres-roguelikes-angband-nethack-etc">Autres roguelikes : Angband, Nethack, etc.</a></li>
</ul>
</li>
</ul><p>Bonjour Nal,</p>

<p>Aujourd'hui je viens te parler de <em>boohu</em>, un jeu <a href="https://fr.wikipedia.org/wiki/Rogue-like">roguelike</a> libre que je suis en train de coder. Je vais aussi te parler de mon expérience avec quelques autres jeux libres du même genre, histoire de t'encourager à les essayer : il y en a pour tous les goûts ou presque !</p>

<p>Donc, d'abord, un roguelike, c'est quoi ? Traditionnellement, c'est un jeu d'exploration de donjon au tour par tour, comme le tout premier jeu du genre qui, surprise, s'appelle <a href="https://fr.wikipedia.org/wiki/Rogue_(jeu_vid%C3%A9o)">Rogue</a> et date des années 80. Depuis, le genre a beaucoup évolué, mais l'idée de base est souvent la même : le joueur contrôle un personnage sur une carte générée procéduralement et choisit à chaque tour d'effectuer une action. La priorité est donnée en général au <em>gameplay</em>, même si de nos jours certains jeux du genre font plus attention aussi au reste. Il y a souvent tout plein de monstres et d'objets divers et variés, et il s'agit de se dépatouiller avec pour survivre, car, contrairement à d'autres jeux comme les jeux de rôle, on ne meurt normalement qu'une fois par partie. Il y a parfois un objectif final particulier mais, les premières fois, c'est rarement important : on meurt souvent et pas que d'une seule façon :)</p>
<h2 id="break-out-of-harekas-underground">Break Out Of Hareka's Underground</h2>

<p><em>boohu</em> c'est le pseudo pour <em>Break Out Of Hareka's Underground</em> (Échappe des Souterrains d'Haréka). C'est un roguelike classique en bonne partie inspiré de <a href="https://crawl.develz.org/wordpress/">DCSS</a>, avec quelques idées de <a href="https://sites.google.com/site/broguegame/">Brogue</a>, mais visant à offrir des parties beaucoup plus courtes, pas de construction élaborée de personnage et une gestion d'inventaire simplifiée. Un roguelike dit <em>coffee-break</em> (pause café).</p>

<p><img src="//img.linuxfr.org/img/68747470733a2f2f62617264696e666c6f722e706572736f2e617175696c656e65742e66722f626f6f68752f696e74726f2d73637265656e2e706e67/intro-screen.png" alt="Écran de démarrage" title="Source : https://bardinflor.perso.aquilenet.fr/boohu/intro-screen.png"></p>

<p>Pour l'installer, c'est plutôt facile et expliqué sur la <a href="https://github.com/anaseto/boohu">page github du projet</a>.</p>

<p>Le joueur commence dans les Souterrains où il a atterri on ne sait trop comment et, pour en échapper, il doit trouver des escaliers magiques quelque part dans les profondeurs. Il s'agit alors de trouver des trésors et de s'équiper d'armes, armures, potions et bâtons magiques tout en survivant au milieu de monstres variés, allant du simple groupe de gobelins, aux hydres à quatre têtes, en passant par des grenouilles géantes qui te téléportent.  Parfois le plus sage est de fuir, possibilité à prendre particulièrement en compte si le monstre est en train de dormir. D'autres fois, pas le choix, il faut se battre ou prendre des mesures d'urgence.</p>

<p>Toute la difficulté du jeu réside dans ces décisions tactiques et dans le positionnement astucieux du joueur sur la carte, ainsi que sur l'utilisation appropriée des divers objets.  En particulier, il ne faut pas hésiter à utiliser ses potions et bâtons magiques ! Bien sûr, il ne faut pas non plus gaspiller les ressources inutilement, mais chez le débutant l'erreur principale est en général d'oublier simplement d'utiliser ce qu'il possède aux moments les plus critiques :) C'est d'ailleurs un conseil qui vaut pour la quasi-totalité des roguelikes.  Parmi les caractéristiques particulières de <em>boohu</em> et non présentes forcément dans tous les roguelikes, il y a en particulier :</p>

<ul>
<li>Pas d'XP, ni de nourriture, ni d'escaliers pour revenir à la carte précédente ; gestion simplifiée d'inventaire : par exemple, on ne peut pas porter plus d'une arme à la fois (sans compter certains projectiles). Tout est fait pour simplifier tout ce qui n'est pas positionnement tactique et utilisation stratégique des ressources. Le joueur acquiert aléatoirement un petit nombre d'aptitudes, au fur et à mesure qu'il descend, sans contrôle de la part du joueur.</li>
<li>Des parties très courtes (pour un roguelike).</li>
<li>Exploration automatique avec possibilité de marquage manuel de zones non sûres (un peu comme DCSS, ça permet de contourner un ogre pas sympa, par exemple).</li>
<li>Un nombre modéré de monstres différents : l'idée est de faire dans le qualitatif, donc il n'y a pas dans le jeu deux monstres dont l'un est une simple amélioration des stats du précédent. Il faut qu'il y ait une différence qualitative, comme une attaque spéciale, une différence de vitesse, de comportement (en groupe ou solitaire), etc. Bref, quelque chose qui fasse que l'expérience est potentiellement vraiment différente.</li>
<li>Une fusion des systèmes magiques à base de points de magie (mana) et des systèmes à base de charges: les bâtons magiques. L'utilisation de mana limite le nombre d'utilisations successives de magie, tandis qu'un nombre de charges limité (rechargés au fur et à mesure que l'on descend plus profondément dans les Souterrains) impose de savoir ne pas les gaspiller inutilement.</li>
</ul><p>Le jeu est en développement, mais il a atteint la phase où c'est devenu un jeu relativement complet et plutôt stable, même s'il y aura sans doute de nouveaux trucs et des petits rééquilibrages régulièrement ; peut-être une version avec des tuiles, un jour. Je serais donc ravi d'avoir des testeurs ou autres contributions ! :)</p>

<p>Au début, j'avais pensé un peu te raconter aussi les différents algorithmes de génération procédurale de cartes, mais ça allait faire un journal un peu long, donc ça sera peut-être pour une autre fois si je trouve le temps.</p>
<h2 id="mes-expériences-avec-dautres-roguelikes">Mes expériences avec d'autres roguelikes</h2>

<p>Si je me suis mis à coder un roguelike, c'est parce que j'aime plutôt ce genre et ai joué à un certain nombre de ces jeux, donc je vais te faire part de mes expériences en espérant te tenter avec une de ces petites merveilles. Petite remarque en passant : c'est intéressant de voir qu'il s'agit d'un des rares genres où une bonne partie des jeux les plus connus sont libres, à quelques exceptions près et sans compter les roguelikes temps-réel, aussi appelés parfois roguelites ou roguelike-like, qui semblent assez différents et que je n'ai jamais eu l'occasion de tester encore.</p>
<h3 id="dungeon-crawl-stone-soup">Dungeon Crawl Stone Soup</h3>

<p><a href="https://crawl.develz.org/wordpress/">DCSS</a> est le roguelike auquel j'ai le plus joué et qui a influencé le plus boohu : les méchanismes de combat et d'utilisation de ressources sont assez similaires. J'avais fait <a href="//linuxfr.org/news/dungeon-crawl-stone-soup-0-13-est-sorti">une dépêche</a> il y a quelques années. Le jeu évolue vite et la communauté de joueurs est de nos jours devenue assez grande, avec plusieurs milliers de joueurs qui participent à des tournois bi-annuels.</p>

<p>Contrairement à boohu, il offre une version avec des tuiles plutôt réussie et est jouable entièrement à la souris, pour ceux qui sont plus à l'aise ainsi. Il offre aussi un vaste panorama d'espèces et d'origines variées parmi lesquelles choisir, donnant des possibilités de rejouabilité assez énormes. Un système d'habiletés permet de contrôler un peu l'évolution du personnage. Ainsi, on pourra commencer par un minotaure berserker, puis finir avec une momie chevalier du chaos, en passant par un octopode mage sans armure mais huit anneaux magiques.  Les combinaisons possibles sont énormes, et toutes ne sont pas aussi viables les unes que les autres, donc ça permet de relever des défis plus difficiles quand on connaît bien le jeu.</p>

<p>Le donjon est aussi très vaste, avec un certain nombre de branches thématiques optionnelles, au sens, l'objectif minimal du jeu est juste de trouver trois runes et d'échapper avec l'orbe de Zot, mais on peut trouver jusqu'à 15 runes.</p>

<p>Le jeu est relativement facile à prendre en main et a fait des efforts d'accessibilité pour les débutants, mais est quand même complexe et les parties sont relativement longues, plusieurs heures, en général autour de 6 en ce qui me concerne pour échapper avec 3 runes, mais des joueurs chevronnés terminent ça régulièrement en trois heures voire moins pour certains. Ça dépend assez de l'approche du jeu de chacun aussi, certains aiment prendre leur temps, d'autres moins. Enfin, pour les débutants les parties risquent d'être assez courtes ! ;)</p>
<h3 id="brogue">Brogue</h3>

<p><a href="https://sites.google.com/site/broguegame/">Brogue</a> est un roguelike récent plus proche des origines, c'est-à-dire du jeu Rogue originel, mais en plus moderne avec une interface plutôt réussie, jouable à la souris et qui utilise des caractères Unicode avec des couleurs de façon très artistique ! Les parties sont de longueur moyenne, et l'accent est mis sur la simplicité. Il n'y a donc pas d'XP (seulement des potions de vie et de force), et pas d'habiletés : on peut par contre améliorer les objets en utilisant des parchemins d'enchantement avec des effets très divers. Les interactions entre objets et avec le terrain sont assez élaborées (on peut mettre le feu à certaines zones, par exemple). On se retrouve parfois à poursuivre des singes qui ont volé notre nourriture, ou à se cacher dans des coins sombres pour passer inaperçu. Les monstres sont variés et chacun a ses points forts et ses points faibles.  Bref, c'est prenant.</p>

<p>À tester pour ceux qui veulent un roguelike classique plus simple que DCSS, mais plus amical que le Rogue originel et qui veulent découvrir de l'art Unicode bien fait. J'y ai personnellement pas joué autant que j'aurais voulu, parce que sous OpenBSD ça crashe malheureusement parfois, mais j'ai bien aimé.  </p>
<h3 id="tales-of-majeyal">Tales of Maj'Eyal</h3>

<p>Aussi appelé <a href="https://te4.org/">ToME4</a>, Tales of Maj'Eyal est un roguelike qui s'éloigne un peu des classiques. Il y a eu aussi <a href="//linuxfr.org/news/tome-tales-of-maj-eyal">une dépêche</a> il y a quelques années. C'est un jeu bien fait, riche en contenu et utilisable complètement à la souris. Il y a plusieurs niveaux de difficulté parmi lesquels choisir et, en particulier, un mode exploration qui peut être pratique pour les débutants.  De plus, par défaut, le jeu offre plusieurs vies plutôt qu'une seule, la logique étant, je suppose, que le jeu étant si long une faute d'attention pourrait devenir un peu agaçante autrement.</p>

<p>Plus important, contrairement aux roguelikes classiques, il n'y a pas de gestion stratégique de ressources périssables : le jeu utilise uniquement des pouvoirs qui se rechargent au bout de quelques tours après utilisation pour la plupart, ainsi que d'autres qui doivent être maintenus à l'aide d'un coût en énergie, fatigue, etc. L'évolution du personnage utilise un système de classes avec des arbres d'habiletés assez complexes : à chaque nouveau niveau d'expérience le joueur choisit de répartir un certain nombre de points parmi différents pouvoirs ou aptitudes diverses. On peut choisir entre un certain nombre d'espèces et, en fonction des aventures, on débloque des espèces et des classes en plus.</p>

<p>L'absence de ressources périssables est quelque chose qui m'a un peu manqué dans ce jeu, et j'ai trouvé qu'il y a un léger excès d'abondance d'objets pas forcément toujours très différents les uns des autres. Le jeu est aussi un peu trop axés sur des considérations numériques à mon goût et pas forcément toujours très bien équilibré. Ceci dit, je me suis quand même bien amusé et ai insisté suffisamment pour venir au bout du jeu, qui est quand même très long (je me souviens plus exactement, mais ça a dû me prendre largement plus de dix heures pour finir, peut-être vingt, sans compter les fois où je suis mort bêtement au début). La deuxième moitié du jeu m'a d'ailleurs semblé plutôt facile, à part une mauvaise surprise ou deux, mais sans doute parce que je me suis contenté de la difficulté normale.</p>

<p>Bref, à tester pour ceux qui sont attirés par le système complexe d'habiletés, un monde riche et vaste, l'existence de plusieurs niveaux de difficultés et qui n'ont pas peur des nombres.</p>

<p>Un petit détail : les tuiles utilisées par défaut sont jolies, mais malheureusement pas libres. A priori il est possible de les changer, ceci dit.</p>
<h3 id="cataclysm-dark-days-ahead">Cataclysm: Dark Days Ahead</h3>

<p>En abbrégé, <a href="http://en.cataclysmdda.com/">CataclysmDDA</a>. C'est un roguelike de survie dans un monde post-apocalyptique. Contrairement à la plupart des roguelikes, il n'y a pas d'objectif particulier, pour autant que je sache. La communauté semble assez active. Il y a plusieurs ensembles de tuiles différents.</p>

<p>Le jeu fait extrêmement dans les détails. Il faudra par exemple bouillir l'eau sous risque d'attraper des maladies, manger varié et cuisiner (il y a tout un tas de recettes différentes) en faisant gaffe si on veut pas faire brûler toute la maison. Contrairement à la plupart des jeux qui utilisent des points de vie, le système est plus granulaire et s'intéresse aux différentes parties du corps.  On peut s'amuser à conduire et réparer des automobiles et construire tout un tas de trucs. Bref, c'est très impressionant.</p>

<p>Honnêtement, je ne me suis pas encore vraiment plongé dedans, parce que ça semble demander un investissement conséquent et c'est un peu tout le contraire d'une partie courte. Mais c'est en tout cas quelque chose, donc j'avais envie de le mentionner ! :)</p>
<h3 id="hyperrogue">Hyperrogue</h3>

<p><a href="http://www.roguetemple.com/z/hyper/">Hyperrogue</a> est un roguelike un peu spécial, plus proche des jeux type casse-tête, qui se déroule sur le <a href="https://fr.wikipedia.org/wiki/G%C3%A9om%C3%A9trie_hyperbolique">plan hyperbolique</a>, donc c'est très spécial. C'est une bonne façon de découvrir de façon intuitive cet objet mathématique, d'ailleurs.</p>

<p>Je le mentionne surtout parce que c'est original, je n'y ai pas joué tant que ça, car ça s'éloigne du genre originel et c'est légèrement répétitif à mon goût, mais d'autres semblent apprécier beaucoup.  Le jeu est libre, bien qu'il semble y avoir quelques extensions qui ne le sont pas.</p>
<h3 id="autres-roguelikes-angband-nethack-etc">Autres roguelikes : Angband, Nethack, etc.</h3>

<p>Il y en a beaucoup d'autres que j'ai pas ou peu testés. Je conseille la visite du site <a href="http://www.roguebasin.com/index.php?title=Main_Page">roguebasin</a> qui liste beaucoup de jeux du genre (tous ne sont pas libres). </p>

<p>Dans les classiques que j'ai pas mentionnés avant il y a <a href="http://rephial.org/">Angband</a> et ses multiples variantes, dont <a href="http://www.amirrorclear.net/flowers/game/sil/">Sil</a> qui est vraiment pas mal et qui partage avec boohu l'absence de progression pour les points de vie. Ils s'inspirent principalement des œuvres de Tolkien (sauf quelques variantes). Le jeu vanilla m'avait semblé long et plus enclin à encourager des actions prudentes plus ennuyantes qui sont souvent plus difficiles dans d'autres jeux du genre (comme rester très longtemps quelque part pour tuer des monstres et gagner de l'XP), tandis que Sil par contre est un jeu plus court et plus équilibré, mais chacun ses goûts !</p>

<p>Il y a aussi le fameux <a href="http://nethack.org/">Nethack</a> (et ses variantes), le jeu aux mille surprises, qui continue à faire son bout de chemin avec une communauté active (c'est probablement l'un des plus vieux jeux encore en développement). Faut vouloir être prêt à mourir des dizaines et dizaines de fois, ou à aller consulter des spoilers régulièrement. Mais ça veut pas dire que c'est pas amusant : le nombre de façons différentes de perdre une partie dans ce jeu de façon originale est absolument hilarant :) Ça va de l'intoxication alimentaire à la noyade, en passant par la transformation en pierre, quand c'est pas juste la colère des dieux !</p>

<p>Voilà !</p><div><a href="https://linuxfr.org/users/anaseto/journaux/a-propos-de-boohu-un-nouveau-jeu-roguelike-et-puis-de-quelques-autres.epub">Télécharger ce contenu au format Epub</a></div>    <p><a href="https://linuxfr.org/users/anaseto/journaux/a-propos-de-boohu-un-nouveau-jeu-roguelike-et-puis-de-quelques-autres#comments">Lire les commentaires</a></p>


guid: https://liens.strak.ch/?vhAzeQ
title: Set-MailboxAutoReplyConfiguration
url: https://technet.microsoft.com/fr-fr/library/dd638217(v=exchg.160).aspx
feedurl: https://liens.strak.ch/?do=rss
content:
<div class="markdown"><p>Pour configurer l'autoreply d'un user avec l'Exchange Shell: </p>
<p><code>Set-MailboxAutoReplyConfiguration -Identity user@domain -AutoReplyState Enabled -ExternalMessage $(get-content “C:\Scripts\OOF-message.txt”)</code></p>
<p>Contenu de OOF-message.txt (formatage HTML!):</p>
<p><code>&lt;html&gt;&lt;body&gt;Madam, Sir,&lt;br&gt;Many thanks for your email.&lt;br&gt;This address is no longer valid. Please forward all messages to xxx&lt;br&gt;Best regards,&lt;br&gt;&lt;/html&gt;&lt;/body&gt;</code></p>
<p>&#8212; <a href="https://liens.strak.ch/?vhAzeQ" title="Permalink">Permalink</a></p></div>


guid: https://liens.strak.ch/?_oK3ZQ
title: The Humble Store: Outlast Deluxe Edition
url: https://www.humblebundle.com/store/outlast-deluxe
feedurl: https://liens.strak.ch/?do=rss
content:
<div class="markdown"><p>Un peu moins de 2 jours pour profiter de Outlast gratuitement !</p>
<p>via Liandri, merci à toi ! :)<br />
&#8212; <a href="https://liens.strak.ch/?_oK3ZQ" title="Permalink">Permalink</a></p></div>


guid: http://tkpx.wordpress.com/?p=1494
title: Cryptoparty – Café Vie Privée
author: takopix
url: https://tkpx.wordpress.com/2017/09/23/cryptoparty-cafe-vie-privee/
feedurl: https://tkpx.wordpress.com/feed/
enclosure_url: http://tkpx.files.wordpress.com/2017/08/1f512.png
content:
<p style="text-align:justify;">La semaine prochaine (samedi 30 septembre de 14h à 18h), je serai à la cryptoparty (ou <a href="https://cafevieprivee-nantes.fr" target="_blank" rel="noopener">café vie privée</a>) organisée par l&rsquo;association <a href="https://www.faimaison.net/" target="_blank" rel="noopener">FAIMAISON</a> à la Dérive Social Club à Nantes (<a href="https://www.openstreetmap.org/node/5095736864" target="_blank" rel="noopener">1 Rue du Gué Robert</a>). Cet événement ouvert à tous sera l&rsquo;occasion d&rsquo;échanger sur la protection des données personnelles lors de plusieurs ateliers thématiques.<span id="more-1494"></span></p>
<h3 style="text-align:justify;">Mais c&rsquo;est quoi une cryptoparty ?</h3>
<p style="text-align:justify;">Le terme de cryptoparty peut être francisé sous le terme de chiffrofête qui se veut une traduction moins connotée de ce terme. Ce type d’événement est également appelé café vie privée.</p>
<p style="text-align:justify;">Les outils techniques qui permettent de conserver une vie privée sur Internet où nous sommes constamment espionnés et surveillés (par les publicités, les réseaux sociaux, les gouvernements…) ne doivent pas être l’apanage d’une petite poignée de gens plus habiles que les autres avec l’informatique. Chacun est en droit de s’approprier, à la hauteur de son niveau de compréhension, de ses besoins, de ses envies, ses différents outils. Les cryptoparty sont donc des événements dédiés à l’apprentissage de la sécurité des communications en environnement numérique.</p>
<p>&nbsp;</p>
<h3>D&rsquo;accord, mais moi je n&rsquo;ai rien à cacher !</h3>
<p>Au lieu de copier/coller le site, je vous invite le lire <a href="http://jenairienacacher.fr/" target="_blank" rel="noopener">http://jenairienacacher.fr/</a></p>
<p><a href="https://tkpx.files.wordpress.com/2017/08/1f441-1f5e8.png"><img data-attachment-id="1464" data-permalink="https://tkpx.wordpress.com/2017/09/23/cryptoparty-cafe-vie-privee/1f441-1f5e8/" data-orig-file="https://tkpx.files.wordpress.com/2017/08/1f441-1f5e8.png?w=67&#038;h=67" data-orig-size="128,128" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="1f441-1f5e8" data-image-description="" data-medium-file="https://tkpx.files.wordpress.com/2017/08/1f441-1f5e8.png?w=67&#038;h=67?w=128" data-large-file="https://tkpx.files.wordpress.com/2017/08/1f441-1f5e8.png?w=67&#038;h=67?w=128" class="wp-image-1464 aligncenter" src="https://tkpx.files.wordpress.com/2017/08/1f441-1f5e8.png?w=67&#038;h=67" alt="" width="67" height="67" srcset="https://tkpx.files.wordpress.com/2017/08/1f441-1f5e8.png?w=67&amp;h=67 67w, https://tkpx.files.wordpress.com/2017/08/1f441-1f5e8.png 128w" sizes="(max-width: 67px) 100vw, 67px" /></a></p>
<h3>Bon d&rsquo;accord, c&rsquo;est quoi le programme ?</h3>
<p style="text-align:justify;"><strong>De 14h30 à 16h: 4 ateliers au choix</strong></p>
<ul style="text-align:justify;">
<li>Protéger sa vie privée en ligne : échanges sur les bonnes pratiques d’hygiènes numériques (naviguer sur Internet, gérer ses mots de passe, etc.), les alternatives libres, les metadonnées, le cyberharcèlement, etc.</li>
<li>Chiffrer ses communications : initiation au chiffrement de mails avec PGP et de sms avec Silence ou Signal.</li>
<li>Chiffrer son trafic sur Internet : découvrir pourquoi et comment chiffrer son trafic avec un VPN (réseau privé virtuel).</li>
<li>Protéger son anonymat : présentation du système d’exploitation Tails et du réseau Tor.</li>
</ul>
<p style="text-align:justify;"><strong>De 16h30 à 18h: 3 ateliers au choix</strong></p>
<ul style="text-align:justify;">
<li>Chiffrer ses communications : initiation au chiffrement de mails avec PGP et de sms avec Silence ou Signal.</li>
<li>Chiffrer son trafic sur Internet : aller plus loin en apprenant à configurer un VPN.</li>
<li>Protéger ses données sur son smartphone : démonstration pratique des traces laissées par les applications<strong>.</strong></li>
</ul>
<p>&nbsp;</p>
<p style="text-align:justify;">N’hésitez pas à venir avec votre ordinateur! Vous pourrez en profiter pour installer des outils lors des ateliers pour protéger votre vie privée.</p>
<p style="text-align:justify;">Si vous souhaitez installer le système Tails, pensez à prendre une clé USB avec au moins 4Go d&rsquo;espace.</p>
<p style="text-align:justify;">Vous pouvez également suivre le groupe <a href="https://twitter.com/CryptoPartyNTS" target="_blank" rel="noopener">CryptoPartyNTS</a> sur Twitter.</p>
<p><a href="https://tkpx.files.wordpress.com/2017/08/1f512.png"><img data-attachment-id="1463" data-permalink="https://tkpx.wordpress.com/2017/09/23/cryptoparty-cafe-vie-privee/1f512/" data-orig-file="https://tkpx.files.wordpress.com/2017/08/1f512.png?w=85&#038;h=85" data-orig-size="128,128" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="1f512" data-image-description="" data-medium-file="https://tkpx.files.wordpress.com/2017/08/1f512.png?w=85&#038;h=85?w=128" data-large-file="https://tkpx.files.wordpress.com/2017/08/1f512.png?w=85&#038;h=85?w=128" class=" wp-image-1463 aligncenter" src="https://tkpx.files.wordpress.com/2017/08/1f512.png?w=85&#038;h=85" alt="" width="85" height="85" srcset="https://tkpx.files.wordpress.com/2017/08/1f512.png?w=85&amp;h=85 85w, https://tkpx.files.wordpress.com/2017/08/1f512.png 128w" sizes="(max-width: 85px) 100vw, 85px" /></a></p><br />Classé dans:<a href='https://tkpx.wordpress.com/category/free-software/'>Free Software</a>, <a href='https://tkpx.wordpress.com/category/life/'>Life</a>, <a href='https://tkpx.wordpress.com/category/privacy/'>Privacy</a>, <a href='https://tkpx.wordpress.com/category/security/'>Security</a>  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/tkpx.wordpress.com/1494/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/tkpx.wordpress.com/1494/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/tkpx.wordpress.com/1494/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/tkpx.wordpress.com/1494/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/tkpx.wordpress.com/1494/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/tkpx.wordpress.com/1494/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/tkpx.wordpress.com/1494/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/tkpx.wordpress.com/1494/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/tkpx.wordpress.com/1494/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/tkpx.wordpress.com/1494/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/tkpx.wordpress.com/1494/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/tkpx.wordpress.com/1494/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/tkpx.wordpress.com/1494/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/tkpx.wordpress.com/1494/" /></a> <img alt="" border="0" src="https://pixel.wp.com/b.gif?host=tkpx.wordpress.com&#038;blog=44759582&#038;post=1494&#038;subd=tkpx&#038;ref=&#038;feed=1" width="1" height="1" /><hr>La semaine prochaine (samedi 30 septembre de 14h à 18h), je serai à la cryptoparty (ou café vie privée) organisée par l&#8217;association FAIMAISON à la Dérive Social Club à Nantes (1 Rue du Gué Robert). Cet événement ouvert à tous sera l&#8217;occasion d&#8217;échanger sur la protection des données personnelles lors de plusieurs ateliers thématiques. Mais [&#8230;]<img alt="" border="0" src="https://pixel.wp.com/b.gif?host=tkpx.wordpress.com&#038;blog=44759582&#038;post=1494&#038;subd=tkpx&#038;ref=&#038;feed=1" width="1" height="1" />


guid: https://blog.rom1v.com/2017/09/gnirehtet-reecrit-en-rust
title: Gnirehtet réécrit en Rust
url: https://blog.rom1v.com/2017/09/gnirehtet-reecrit-en-rust/
feedurl: http://blog.rom1v.com/feed/
content:
<p>Il y a quelques mois, j’ai présenté <a href="/2017/03/gnirehtet/">Gnirehtet</a>, un outil de
<em>reverse tethering</em> pour Android que j’ai écrit en Java.</p>

<p>Depuis, <strong>je l’ai réécrit en <a href="https://www.rust-lang.org/">Rust</a></strong>.</p>

<p>Et il est également open source ! <a href="https://github.com/Genymobile/gnirehtet">Téléchargez-le</a>, branchez un
téléphone ou une tablette Android, et exécutez :</p>

<div class="highlighter-rouge"><pre class="codehilite"><code>./gnirehtet run
</code></pre></div>

<p><em>(adb doit être installé)</em></p>

<ul id="markdown-toc">
  <li><a href="#pourquoi-rust" id="markdown-toc-pourquoi-rust">Pourquoi Rust?</a></li>
  <li><a href="#apprendre-rust" id="markdown-toc-apprendre-rust">Apprendre Rust</a></li>
  <li><a href="#difficults" id="markdown-toc-difficults">Difficultés</a>    <ul>
      <li><a href="#encapsulation" id="markdown-toc-encapsulation">Encapsulation</a></li>
      <li><a href="#observateur" id="markdown-toc-observateur">Observateur</a></li>
      <li><a href="#partage-de-donnes-mutables" id="markdown-toc-partage-de-donnes-mutables">Partage de données mutables</a></li>
      <li><a href="#limitations-du-compilateur" id="markdown-toc-limitations-du-compilateur">Limitations du compilateur</a></li>
    </ul>
  </li>
  <li><a href="#sret-et-piges" id="markdown-toc-sret-et-piges">Sûreté et pièges</a>    <ul>
      <li><a href="#leakpocalypse" id="markdown-toc-leakpocalypse">Leakpocalypse</a></li>
      <li><a href="#infinit-indfinie" id="markdown-toc-infinit-indfinie">Infinité indéfinie</a></li>
      <li><a href="#erreur-de-segmentation" id="markdown-toc-erreur-de-segmentation">Erreur de segmentation</a></li>
    </ul>
  </li>
  <li><a href="#stats" id="markdown-toc-stats">Stats</a>    <ul>
      <li><a href="#nombre-de-lignes" id="markdown-toc-nombre-de-lignes">Nombre de lignes</a></li>
      <li><a href="#taille-des-binaires" id="markdown-toc-taille-des-binaires">Taille des binaires</a></li>
      <li><a href="#utilisation-mmoire" id="markdown-toc-utilisation-mmoire">Utilisation mémoire</a></li>
      <li><a href="#utilisation-cpu" id="markdown-toc-utilisation-cpu">Utilisation CPU</a></li>
    </ul>
  </li>
  <li><a href="#conclusion" id="markdown-toc-conclusion">Conclusion</a></li>
</ul>

<h2 id="pourquoi-rust">Pourquoi Rust?</h2>

<p>À Genymobile, nous voulions que <em>Gnirehtet</em> ne nécessite pas d’environnement
d’exécution Java (JRE), donc le besoin principal était de compiler l’application
vers un binaire exécutable <em>natif</em>.</p>

<p>Par conséquent, j’ai d’abord pensé la réécrire en C ou C++. Mais à ce moment-là
(début mai), apprendre Rust m’intéressait, après avoir vaguement entendu parler
de ses fonctionnalités:</p>
<ul>
  <li><a href="https://blog.rust-lang.org/2015/04/10/Fearless-Concurrency.html">sûreté mémoire sans <em>garbage collection</em></a>,</li>
  <li><a href="https://blog.rust-lang.org/2015/04/10/Fearless-Concurrency.html">concurrence sans <em>data races</em></a>,</li>
  <li><a href="https://blog.rust-lang.org/2015/05/11/traits.html">abstraction sans coût</a>.</li>
</ul>

<p>Cependant, je n’avais jamais écrit une ligne de Rust ni entendu parler de son
système de <a href="https://doc.rust-lang.org/book/first-edition/ownership.html">possession</a>, d’<a href="https://doc.rust-lang.org/book/first-edition/references-and-borrowing.html">emprunt</a> ou de <a href="https://doc.rust-lang.org/book/first-edition/lifetimes.html">durées de
vie</a>.</p>

<p>Mais je suis convaincu que le meilleur moyen d’apprendre un langage de
programmation est de travailler à plein temps sur un projet dans ce langage.</p>

<p>J’étais motivé, donc après avoir vérifié que ça pouvait convenir (en gros, j’ai
écrit un exemple utilisant la bibliothèque d’<a href="https://en.wikipedia.org/wiki/Asynchronous_I/O">I/O asynchrone</a> <a href="https://crates.io/crates/mio">mio</a>,
et je l’ai exécuté à la fois sur Linux et Windows), j’ai décidé de réécrire
<em>Gnirehtet</em> en Rust.</p>

<h2 id="apprendre-rust">Apprendre Rust</h2>

<p>Pendant la réécriture, j’ai <em>dévoré</em> successivement le <a href="https://doc.rust-lang.org/book/first-edition/">Rust book</a>, <a href="https://rustbyexample.com/">Rust by
example</a> et le <a href="https://doc.rust-lang.org/nomicon/">Rustonomicon</a>. J’ai beaucoup appris, et j’aime énormément ce
langage. Beaucoup de ses fonctionnalités me manquent maintenant quand je
travaille sur un projet C++ :</p>
<ul>
  <li><a href="https://rustbyexample.com/cast/inference.html">inférence de type avancée</a>,</li>
  <li><a href="https://doc.rust-lang.org/book/first-edition/enums.html">enums</a>,</li>
  <li><a href="https://doc.rust-lang.org/book/first-edition/patterns.html">patterns</a>,</li>
  <li><a href="https://doc.rust-lang.org/book/first-edition/traits.html">trait bounds</a>,</li>
  <li><a href="https://doc.rust-lang.org/std/option/"><code class="highlighter-rouge">Option&lt;T&gt;</code></a> (comme <a href="https://github.com/tvaneerd/cpp17_in_TTs/blob/master/ALL_IN_ONE.md#stdoptionalt"><code class="highlighter-rouge">std::optional&lt;T&gt;</code></a> en C++17, mais tirant bénéfice des
enums et des patterns),</li>
  <li><a href="https://doc.rust-lang.org/book/first-edition/macros.html">macros hygiéniques</a>,</li>
  <li>l’absence de fichiers d’en-têtes,</li>
  <li>le (si simple) système de <em>build</em>, <em>et bien sûr</em></li>
  <li>la garantie de sûreté mémoire.</li>
</ul>

<p>À propos de l’apprentissage, Paul Graham <a href="http://paulgraham.com/know.html">a écrit</a>:</p>

<blockquote>
  <p><strong>Reading and experience train your model of the world.</strong> And even if you
forget the experience or what you read, its effect on your model of the world
persists. Your mind is like a compiled program you’ve lost the source of. It
works, but you don’t know why.</p>
</blockquote>

<p>Pour les non-anglophones, ma propre traduction :</p>

<blockquote>
  <p><strong>La lecture et l’expérience entraînent votre modèle du monde.</strong> Et même si
vous oubliez l’expérience ou ce que vous avez lu, son effet sur votre modèle
du monde persiste. Votre esprit est comme un programme compilé dont vous
auriez perdu le code source. Ça fonctionne, mais vous ne savez pas pourquoi.</p>
</blockquote>

<p>Certains des concepts de Rust (comme les <a href="https://doc.rust-lang.org/book/first-edition/lifetimes.html">durées de vie</a> ou la
<a href="https://doc.rust-lang.org/book/first-edition/ownership.html#move-semantics">sémantique de mouvement</a> par défaut) m’ont fourni un <em>jeu de
données</em> significativement différent, qui a sans aucun doute affecté mon modèle
du monde (de la programmation).</p>

<p>Je ne vais pas présenter toutes ces fonctionnaliés (cliquez sur les liens de la
documentation si ça vous intéresse). À la place, je vais essayer d’expliquer où
et pourquoi Rust a resisté au <em>design</em> que je voulais implémenter, et comment
repenser les problèmes dans le périmètre des contraintes de Rust.</p>

<p><em>La partie suivant nécessite une certaine connaissance de Rust. Vous pourriez
vouloir la passer pour aller directement aux <a href="#stats">stats</a>.</em></p>

<h2 id="difficults">Difficultés</h2>

<p>Je trouvais la conception de l’application Java plutôt réussie, donc je voulais
reproduire l’architecture globale dans la version Rust (avec d’éventuelles
adaptations pour la <em>rustifier</em>).</p>

<p>Mais j’ai lutté sur les détails, en particulier pour satisfaire le <a href="https://doc.rust-lang.org/book/first-edition/references-and-borrowing.html"><em>borrow
checker</em></a>. Les <a href="https://doc.rust-lang.org/book/first-edition/references-and-borrowing.html#the-rules">règles</a> sont simples:</p>

<blockquote>
  <p>First, any borrow must last for a scope no greater than that of the owner.
Second, you may have one or the other of these two kinds of borrows, but not
both at the same time:</p>
  <ul>
    <li>one or more references (<code class="highlighter-rouge">&amp;T</code>) to a resource,</li>
    <li>exactly one mutable reference (<code class="highlighter-rouge">&amp;mut T</code>).</li>
  </ul>
</blockquote>

<p>En français :</p>

<blockquote>
  <p>Premièrement, aucun emprunt ne doit avoir une portée plus grande que celle de
son propriétaire.
Deuxièmement, vous pouvez avoir l’un ou l’autre de ces types d’emprunts, mais
pas les deux à la fois:</p>
  <ul>
    <li>une ou plusieurs références (<code class="highlighter-rouge">&amp;T</code>) vers une ressource,</li>
    <li>exactement une référence mutable (<code class="highlighter-rouge">&amp;mut T</code>).</li>
  </ul>
</blockquote>

<p>Cependant, il m’a fallu un peu de temps pour réaliser comment elles entrent en
conflit avec certains principes ou modèles de conception.</p>

<p>Voici donc mes retours. J’ai sélectionné 4 sujets qui sont suffisamment généraux
pour être indépendants de ce projet particulier :</p>

<ul>
  <li>les conflits avec l’<a href="#encapsulation">encapsulation</a> ;</li>
  <li>le <em>design pattern</em> <a href="#observateur">observateur</a> ;</li>
  <li>comment <a href="#partage-de-donnes-mutables">partager des données mutables</a> ;</li>
  <li>un retour rapide sur les <a href="#limitations-du-compilateur">limitations ennuyeuses du
compilateur</a>.</li>
</ul>

<h3 id="encapsulation">Encapsulation</h3>

<p><strong>Les règles d’emprunt contraignent l’encapsulation.</strong> C’est la première
conséquence que j’ai réalisée.</p>

<p>Voici un exemple canonique :</p>

<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="k">pub</span> <span class="k">struct</span> <span class="n">Data</span> <span class="p">{</span>
    <span class="n">header</span><span class="p">:</span> <span class="p">[</span><span class="nb">u8</span><span class="p">;</span> <span class="mi">4</span><span class="p">],</span>
    <span class="n">payload</span><span class="p">:</span> <span class="p">[</span><span class="nb">u8</span><span class="p">;</span> <span class="mi">20</span><span class="p">],</span>
<span class="p">}</span>

<span class="k">impl</span> <span class="n">Data</span> <span class="p">{</span>
    <span class="k">pub</span> <span class="k">fn</span> <span class="nf">new</span><span class="p">()</span> <span class="k">-&gt;</span> <span class="n">Self</span> <span class="p">{</span>
        <span class="n">Self</span> <span class="p">{</span>
            <span class="n">header</span><span class="p">:</span> <span class="p">[</span><span class="mi">0</span><span class="p">;</span> <span class="mi">4</span><span class="p">],</span>
            <span class="n">payload</span><span class="p">:</span> <span class="p">[</span><span class="mi">0</span><span class="p">;</span> <span class="mi">20</span><span class="p">],</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="k">pub</span> <span class="k">fn</span> <span class="nf">header</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="p">[</span><span class="nb">u8</span><span class="p">]</span> <span class="p">{</span>
        <span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="py">.header</span>
    <span class="p">}</span>

    <span class="k">pub</span> <span class="k">fn</span> <span class="nf">payload</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="p">[</span><span class="nb">u8</span><span class="p">]</span> <span class="p">{</span>
        <span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="py">.payload</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="k">fn</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">let</span> <span class="k">mut</span> <span class="n">data</span> <span class="o">=</span> <span class="nn">Data</span><span class="p">::</span><span class="nf">new</span><span class="p">();</span>
    <span class="k">let</span> <span class="n">header</span> <span class="o">=</span> <span class="n">data</span><span class="nf">.header</span><span class="p">();</span>
    <span class="k">let</span> <span class="n">payload</span> <span class="o">=</span> <span class="n">data</span><span class="nf">.payload</span><span class="p">();</span>
<span class="p">}</span></code></pre></figure>

<p>Nous créons juste une nouvelle instance de <code class="highlighter-rouge">Data</code>, puis associons à des
variables locales des références mutables vers les tableaux <code class="highlighter-rouge">header</code> et
<code class="highlighter-rouge">payload</code>, en passant par des accesseurs.</p>

<p>Cependant, cela ne compile pas :</p>

<div class="highlighter-rouge"><pre class="codehilite"><code>$ rustc sample.rs
error[E0499]: cannot borrow `data` as mutable more than once at a time
  --&gt; sample.rs:21:19
   |
25 |     let header = data.header();
   |                  ---- first mutable borrow occurs here
26 |     let payload = data.payload();
   |                   ^^^^ second mutable borrow occurs here
27 | }
   | - first borrow ends here
</code></pre></div>

<p>Le compilateur ne peut pas faire l’hypothèse que <code class="highlighter-rouge">header()</code> et <code class="highlighter-rouge">payload()</code>
retournent des références vers des données disjointes dans la structure <code class="highlighter-rouge">Data</code>.
Par conséquent, chacun <em>emprunte</em> la structure <code class="highlighter-rouge">data</code> entièrement. Vu que les
règles d’emprunt interdisent d’obtenir deux références mutables vers la même
ressource, il rejette le second appel.</p>

<p>Parfois, nous faisons face à des limitations temporaires parce que le
compilateur n’est pas (encore) assez malin. Ce n’est pas le cas ici :
l’implémentation de <code class="highlighter-rouge">header()</code> pourrait très bien retourner une référence vers
<code class="highlighter-rouge">payload</code>, ou écrire dans le tableau <code class="highlighter-rouge">payload</code>, enfreignant ainsi les règles
d’emprunt. Et la validité d’un appel d’une méthode ne peut pas dépendre de
l’implementation de la méthode.</p>

<p>Pour corriger le problème, le compilateur doit être capable de savoir que les
variables locales <code class="highlighter-rouge">header</code> et <code class="highlighter-rouge">payload</code> référencent des <strong>données disjointes</strong>,
par exemple en accédant aux champs directement :</p>

<figure class="highlight"><pre><code class="language-rust" data-lang="rust">    <span class="k">let</span> <span class="n">header</span> <span class="o">=</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="n">data</span><span class="py">.header</span><span class="p">;</span>
    <span class="k">let</span> <span class="n">payload</span> <span class="o">=</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="n">data</span><span class="py">.payload</span><span class="p">;</span></code></pre></figure>

<p>ou en exposant une méthode fournissant les deux références simultanément :</p>

<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="k">struct</span> <span class="n">Data</span> <span class="p">{</span>
    <span class="k">fn</span> <span class="nf">header_and_payload</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="p">[</span><span class="nb">u8</span><span class="p">],</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="p">[</span><span class="nb">u8</span><span class="p">])</span> <span class="p">{</span>
        <span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="py">.header</span><span class="p">,</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="py">.payload</span><span class="p">)</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="k">fn</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">let</span> <span class="k">mut</span> <span class="n">data</span> <span class="o">=</span> <span class="nn">Data</span><span class="p">::</span><span class="nf">new</span><span class="p">();</span>
    <span class="k">let</span> <span class="p">(</span><span class="n">header</span><span class="p">,</span> <span class="n">payload</span><span class="p">)</span> <span class="o">=</span> <span class="n">data</span><span class="nf">.header_and_payload</span><span class="p">();</span>
<span class="p">}</span></code></pre></figure>

<p>De même, dans l’implémentation d’une structure, les règles d’emprunt empêchent
de factoriser du code dans une méthode privée facilement. Prenons cet exemple
(artificiel) :</p>

<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="k">pub</span> <span class="k">struct</span> <span class="n">Data</span> <span class="p">{</span>
    <span class="n">buf</span><span class="p">:</span> <span class="p">[</span><span class="nb">u8</span><span class="p">;</span> <span class="mi">20</span><span class="p">],</span>
    <span class="n">prefix_length</span><span class="p">:</span> <span class="nb">usize</span><span class="p">,</span>
    <span class="n">sum</span><span class="p">:</span> <span class="nb">u32</span><span class="p">,</span>
    <span class="n">port</span><span class="p">:</span> <span class="nb">u16</span><span class="p">,</span>
<span class="p">}</span>

<span class="k">impl</span> <span class="n">Data</span> <span class="p">{</span>
    <span class="k">pub</span> <span class="k">fn</span> <span class="nf">update_sum</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">let</span> <span class="n">content</span> <span class="o">=</span> <span class="o">&amp;</span><span class="k">self</span><span class="py">.buf</span><span class="p">[</span><span class="k">self</span><span class="py">.prefix_length</span><span class="err">..</span><span class="p">];</span>
        <span class="k">self</span><span class="py">.sum</span> <span class="o">=</span> <span class="n">content</span><span class="nf">.iter</span><span class="p">()</span><span class="nf">.cloned</span><span class="p">()</span><span class="nf">.map</span><span class="p">(</span><span class="nn">u32</span><span class="p">::</span><span class="n">from</span><span class="p">)</span><span class="nf">.sum</span><span class="p">();</span>
    <span class="p">}</span>

    <span class="k">pub</span> <span class="k">fn</span> <span class="nf">update_port</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">let</span> <span class="n">content</span> <span class="o">=</span> <span class="o">&amp;</span><span class="k">self</span><span class="py">.buf</span><span class="p">[</span><span class="k">self</span><span class="py">.prefix_length</span><span class="err">..</span><span class="p">];</span>
        <span class="k">self</span><span class="py">.port</span> <span class="o">=</span> <span class="p">(</span><span class="n">content</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="k">as</span> <span class="nb">u16</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="mi">8</span> <span class="p">|</span> <span class="n">content</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span> <span class="k">as</span> <span class="nb">u16</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span></code></pre></figure>

<p>Ici, le champ <code class="highlighter-rouge">buf</code> est un tableau stockant un préfixe et un contenu de manière
contiguë.</p>

<p>Nous voulons factoriser la manière dont nous récupérons la <em>slice</em> <code class="highlighter-rouge">content</code>,
pour que les méthodes <code class="highlighter-rouge">update_*()</code> n’aient pas à se préoccuper des détails.
Essayons :</p>

<figure class="highlight"><pre><code class="language-diff" data-lang="diff"> impl Data {
     pub fn update_sum(&amp;mut self) {
<span class="gd">-        let content = &amp;self.buf[self.prefix_length..];
</span><span class="gi">+        let content = self.content();
</span>         self.sum = content.iter().cloned().map(u32::from).sum();
     }

     pub fn update_port(&amp;mut self) {
<span class="gd">-        let content = &amp;self.buf[self.prefix_length..];
</span><span class="gi">+        let content = self.content();
</span>         self.port = (content[2] as u16) &lt;&lt; 8 | content[3] as u16;
     }
<span class="gi">+
+    fn content(&amp;mut self) -&gt; &amp;[u8] {
+        &amp;self.buf[self.prefix_length..]
+    }
</span> }</code></pre></figure>

<p>Malheureusement, cela ne compile pas :</p>

<div class="highlighter-rouge"><pre class="codehilite"><code>error[E0506]: cannot assign to `self.sum` because it is borrowed
  --&gt; facto2.rs:11:9
   |
10 |         let content = self.content();
   |                       ---- borrow of `self.sum` occurs here
11 |         self.sum = content.iter().cloned().map(u32::from).sum();
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.sum` occurs here

error[E0506]: cannot assign to `self.port` because it is borrowed
  --&gt; facto2.rs:16:9
   |
15 |         let content = self.content();
   |                       ---- borrow of `self.port` occurs here
16 |         self.port = (content[2] as u16) &lt;&lt; 8 &amp; content[3] as u16;
   |
</code></pre></div>

<p>Comme dans l’exemple précédent, récupérer une référence à travers une méthode
<em>emprunte</em> la structure complète (ici, <code class="highlighter-rouge">self</code>).</p>

<p>Pour contourner le problème, nous pouvons expliquer au compilateur que les
champs sont disjoints :</p>

<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="k">impl</span> <span class="n">Data</span> <span class="p">{</span>
    <span class="k">pub</span> <span class="k">fn</span> <span class="nf">update_sum</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">let</span> <span class="n">content</span> <span class="o">=</span> <span class="nn">Self</span><span class="p">::</span><span class="nf">content</span><span class="p">(</span><span class="o">&amp;</span><span class="k">self</span><span class="py">.buf</span><span class="p">,</span> <span class="k">self</span><span class="py">.prefix_length</span><span class="p">);</span>
        <span class="k">self</span><span class="py">.sum</span> <span class="o">=</span> <span class="n">content</span><span class="nf">.iter</span><span class="p">()</span><span class="nf">.cloned</span><span class="p">()</span><span class="nf">.map</span><span class="p">(</span><span class="nn">u32</span><span class="p">::</span><span class="n">from</span><span class="p">)</span><span class="nf">.sum</span><span class="p">();</span>
    <span class="p">}</span>

    <span class="k">pub</span> <span class="k">fn</span> <span class="nf">update_port</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">let</span> <span class="n">content</span> <span class="o">=</span> <span class="nn">Self</span><span class="p">::</span><span class="nf">content</span><span class="p">(</span><span class="o">&amp;</span><span class="k">self</span><span class="py">.buf</span><span class="p">,</span> <span class="k">self</span><span class="py">.prefix_length</span><span class="p">);</span>
        <span class="k">self</span><span class="py">.port</span> <span class="o">=</span> <span class="p">(</span><span class="n">content</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="k">as</span> <span class="nb">u16</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="mi">8</span> <span class="p">|</span> <span class="n">content</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span> <span class="k">as</span> <span class="nb">u16</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">fn</span> <span class="nf">content</span><span class="p">(</span><span class="n">buf</span><span class="p">:</span> <span class="o">&amp;</span><span class="p">[</span><span class="nb">u8</span><span class="p">],</span> <span class="n">prefix_length</span><span class="p">:</span> <span class="nb">usize</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="o">&amp;</span><span class="p">[</span><span class="nb">u8</span><span class="p">]</span> <span class="p">{</span>
        <span class="o">&amp;</span><span class="n">buf</span><span class="p">[</span><span class="n">prefix_length</span><span class="err">..</span><span class="p">]</span>
    <span class="p">}</span>
<span class="p">}</span></code></pre></figure>

<p>Ça compile, mais cela va totalement à l’encontre de la factorisation :
l’appelant doit fournir les champs nécessaires.</p>

<p>Comme alternative, nous pouvons utiliser une <a href="https://doc.rust-lang.org/book/first-edition/macros.html">macro</a> pour <em>inliner</em> le
code :</p>

<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="nd">macro_rules!</span> <span class="n">content</span> <span class="p">{</span>
    <span class="p">(</span><span class="nv">$self:ident</span><span class="p">)</span> <span class="k">=&gt;</span> <span class="p">{</span>
        <span class="o">&amp;</span><span class="nv">$self</span><span class="py">.buf</span><span class="p">[</span><span class="nv">$self</span><span class="py">.prefix_length</span>..<span class="p">]</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="k">impl</span> <span class="n">Data</span> <span class="p">{</span>
    <span class="k">pub</span> <span class="k">fn</span> <span class="nf">update_sum</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">let</span> <span class="n">content</span> <span class="o">=</span> <span class="nd">content!</span><span class="p">(</span><span class="k">self</span><span class="p">);</span>
        <span class="k">self</span><span class="py">.sum</span> <span class="o">=</span> <span class="n">content</span><span class="nf">.iter</span><span class="p">()</span><span class="nf">.cloned</span><span class="p">()</span><span class="nf">.map</span><span class="p">(</span><span class="nn">u32</span><span class="p">::</span><span class="n">from</span><span class="p">)</span><span class="nf">.sum</span><span class="p">();</span>
    <span class="p">}</span>

    <span class="k">pub</span> <span class="k">fn</span> <span class="nf">update_port</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">let</span> <span class="n">content</span> <span class="o">=</span> <span class="nd">content!</span><span class="p">(</span><span class="k">self</span><span class="p">);</span>
        <span class="k">self</span><span class="py">.port</span> <span class="o">=</span> <span class="p">(</span><span class="n">content</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="k">as</span> <span class="nb">u16</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="mi">8</span> <span class="p">|</span> <span class="n">content</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span> <span class="k">as</span> <span class="nb">u16</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span></code></pre></figure>

<p>Mais c’est loin d’être idéal.</p>

<p>Je pense que nous devons juste l’accepter : l’encapsulation entre parfois en
conflit avec les règles d’emprunt. Après tout, ce n’est pas si surprenant :
imposer les règles d’emprunt nécessite de suivre chaque accès concret aux
ressources, alors que l’encapsulation vise à les abstraire.</p>

<h3 id="observateur">Observateur</h3>

<p>Le <em>design pattern</em> <a href="https://en.wikipedia.org/wiki/Observer_pattern">observateur</a> est utile pour enregistrer des
événements sur un objet.</p>

<p>Dans certains cas, <strong>ce pattern pose des difficultés d’implémentation en Rust</strong>.</p>

<p>Pour faire simple, considérons que les événements sont des valeurs <code class="highlighter-rouge">u32</code>. Voici
une implémentation possible :</p>

<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="k">pub</span> <span class="k">trait</span> <span class="n">EventListener</span> <span class="p">{</span>
    <span class="k">fn</span> <span class="nf">on_event</span><span class="p">(</span><span class="o">&amp;</span><span class="k">self</span><span class="p">,</span> <span class="n">event</span><span class="p">:</span> <span class="nb">u32</span><span class="p">);</span>
<span class="p">}</span>

<span class="k">pub</span> <span class="k">struct</span> <span class="n">Notifier</span> <span class="p">{</span>
    <span class="n">listeners</span><span class="p">:</span> <span class="nb">Vec</span><span class="o">&lt;</span><span class="nb">Box</span><span class="o">&lt;</span><span class="n">EventListener</span><span class="o">&gt;&gt;</span><span class="p">,</span>
<span class="p">}</span>

<span class="k">impl</span> <span class="n">Notifier</span> <span class="p">{</span>
    <span class="k">pub</span> <span class="k">fn</span> <span class="nf">new</span><span class="p">()</span> <span class="k">-&gt;</span> <span class="n">Self</span> <span class="p">{</span>
        <span class="n">Self</span> <span class="p">{</span> <span class="n">listeners</span><span class="p">:</span> <span class="nn">Vec</span><span class="p">::</span><span class="nf">new</span><span class="p">()</span> <span class="p">}</span>
    <span class="p">}</span>

    <span class="k">pub</span> <span class="k">fn</span> <span class="n">register</span><span class="o">&lt;</span><span class="n">T</span><span class="p">:</span> <span class="n">EventListener</span> <span class="o">+</span> <span class="err">'</span><span class="k">static</span><span class="o">&gt;</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">,</span> <span class="n">listener</span><span class="p">:</span> <span class="n">T</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">self</span><span class="py">.listeners</span><span class="nf">.push</span><span class="p">(</span><span class="nn">Box</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="n">listener</span><span class="p">));</span>
    <span class="p">}</span>

    <span class="k">pub</span> <span class="k">fn</span> <span class="nf">notify</span><span class="p">(</span><span class="o">&amp;</span><span class="k">self</span><span class="p">,</span> <span class="n">event</span><span class="p">:</span> <span class="nb">u32</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">for</span> <span class="n">listener</span> <span class="n">in</span> <span class="o">&amp;</span><span class="k">self</span><span class="py">.listeners</span> <span class="p">{</span>
            <span class="n">listener</span><span class="nf">.on_event</span><span class="p">(</span><span class="n">event</span><span class="p">);</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span></code></pre></figure>

<p>Par commodité, implémentons notre trait <code class="highlighter-rouge">EventListener</code> pour les closures :</p>

<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="k">impl</span><span class="o">&lt;</span><span class="n">F</span><span class="p">:</span> <span class="nf">Fn</span><span class="p">(</span><span class="nb">u32</span><span class="p">)</span><span class="o">&gt;</span> <span class="n">EventListener</span> <span class="k">for</span> <span class="n">F</span> <span class="p">{</span>
    <span class="k">fn</span> <span class="nf">on_event</span><span class="p">(</span><span class="o">&amp;</span><span class="k">self</span><span class="p">,</span> <span class="n">event</span><span class="p">:</span> <span class="nb">u32</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">self</span><span class="p">(</span><span class="n">event</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span></code></pre></figure>

<p>Ainsi, son utilisation est simple :</p>

<figure class="highlight"><pre><code class="language-rust" data-lang="rust">    <span class="k">let</span> <span class="k">mut</span> <span class="n">notifier</span> <span class="o">=</span> <span class="nn">Notifier</span><span class="p">::</span><span class="nf">new</span><span class="p">();</span>
    <span class="n">notifier</span><span class="nf">.register</span><span class="p">(|</span><span class="n">event</span><span class="p">|</span> <span class="nd">println!</span><span class="p">(</span><span class="s">"received [{}]"</span><span class="p">,</span> <span class="n">event</span><span class="p">));</span>
    <span class="nd">println!</span><span class="p">(</span><span class="s">"notifying..."</span><span class="p">);</span>
    <span class="n">notifier</span><span class="nf">.notify</span><span class="p">(</span><span class="mi">42</span><span class="p">);</span></code></pre></figure>

<p>Cela affiche :</p>

<div class="highlighter-rouge"><pre class="codehilite"><code>notifying...
received [42]
</code></pre></div>

<p>Jusqu’ici, tout va bien.</p>

<p>Cependant, les choses se compliquent si nous voulons modifier un état sur la
réception d’un événement. Par exemple, implémentons une structure pour stocker
tous les événements reçus :</p>

<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="k">pub</span> <span class="k">struct</span> <span class="n">Storage</span> <span class="p">{</span>
    <span class="n">events</span><span class="p">:</span> <span class="nb">Vec</span><span class="o">&lt;</span><span class="nb">u32</span><span class="o">&gt;</span><span class="p">,</span>
<span class="p">}</span>

<span class="k">impl</span> <span class="n">Storage</span> <span class="p">{</span>
    <span class="k">pub</span> <span class="k">fn</span> <span class="nf">new</span><span class="p">()</span> <span class="k">-&gt;</span> <span class="n">Self</span> <span class="p">{</span>
        <span class="n">Self</span> <span class="p">{</span> <span class="n">events</span><span class="p">:</span> <span class="nn">Vec</span><span class="p">::</span><span class="nf">new</span><span class="p">()</span> <span class="p">}</span>
    <span class="p">}</span>

    <span class="k">pub</span> <span class="k">fn</span> <span class="nf">store</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">,</span> <span class="n">value</span><span class="p">:</span> <span class="nb">u32</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">self</span><span class="py">.events</span><span class="nf">.push</span><span class="p">(</span><span class="n">value</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="k">pub</span> <span class="k">fn</span> <span class="nf">events</span><span class="p">(</span><span class="o">&amp;</span><span class="k">self</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="o">&amp;</span><span class="nb">Vec</span><span class="o">&lt;</span><span class="nb">u32</span><span class="o">&gt;</span> <span class="p">{</span>
        <span class="o">&amp;</span><span class="k">self</span><span class="py">.events</span>
    <span class="p">}</span>
<span class="p">}</span></code></pre></figure>

<p>Pour pouvoir remplir ce <code class="highlighter-rouge">Storage</code> sur chaque événement reçu, nous devons d’une
manière ou d’une autre le passer avec l’<em>event listener</em>, qui sera stocké dans
le <code class="highlighter-rouge">Notifier</code>. Par conséquent, nous avons besoin qu’une instance de <code class="highlighter-rouge">Storage</code>
soit <strong>partagée</strong> entre le code appelant et le <code class="highlighter-rouge">Notifier</code>.</p>

<p>Avoir deux références mutables vers le même objet enfreint évidemment les règles
d’emprunt, donc nous avons besoin d’un <a href="https://doc.rust-lang.org/std/rc/">pointeur à compteur de références</a>.</p>

<p>Cependant, un tel pointeur est en lecture seul, donc nous avons également besoin
d’un <a href="https://doc.rust-lang.org/std/cell/index.html"><code class="highlighter-rouge">RefCell</code></a> pour la <a href="https://ricardomartins.cc/2016/06/08/interior-mutability"><em>mutabilité intérieure</em></a>.</p>

<p>Ainsi, nous allons utiliser une instance de <code class="highlighter-rouge">Rc&lt;RefCell&lt;Storage&gt;&gt;</code>. Cela peut
sembler trop verbeux, mais utiliser <code class="highlighter-rouge">Rc&lt;RefCell&lt;T&gt;&gt;</code> (ou <code class="highlighter-rouge">Arc&lt;Mutex&lt;T&gt;&gt;</code> pour
la <em>thread-safety</em>) est très courant en Rust. Et <a href="https://www.reddit.com/r/rust/comments/33jv62/vecrcrefcellboxtrait_is_there_a_better_way/">il y a pire</a>.</p>

<p>Voici ce que donne le code client :</p>

<figure class="highlight"><pre><code class="language-rust" data-lang="rust">    <span class="k">use</span> <span class="nn">std</span><span class="p">::</span><span class="nn">cell</span><span class="p">::</span><span class="n">RefCell</span><span class="p">;</span>
    <span class="k">use</span> <span class="nn">std</span><span class="p">::</span><span class="nn">rc</span><span class="p">::</span><span class="nb">Rc</span><span class="p">;</span>

    <span class="k">let</span> <span class="k">mut</span> <span class="n">notifier</span> <span class="o">=</span> <span class="nn">Notifier</span><span class="p">::</span><span class="nf">new</span><span class="p">();</span>

    <span class="c">// first Rc to the Storage</span>
    <span class="k">let</span> <span class="n">rc</span> <span class="o">=</span> <span class="nn">Rc</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="nn">RefCell</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="nn">Storage</span><span class="p">::</span><span class="nf">new</span><span class="p">()));</span>

    <span class="c">// second Rc to the Storage</span>
    <span class="k">let</span> <span class="n">rc2</span> <span class="o">=</span> <span class="n">rc</span><span class="nf">.clone</span><span class="p">();</span>

    <span class="c">// register the listener saving all the received events to the Storage</span>
    <span class="n">notifier</span><span class="nf">.register</span><span class="p">(</span><span class="k">move</span> <span class="p">|</span><span class="n">event</span><span class="p">|</span> <span class="n">rc2</span><span class="nf">.borrow_mut</span><span class="p">()</span><span class="nf">.store</span><span class="p">(</span><span class="n">event</span><span class="p">));</span>

    <span class="n">notifier</span><span class="nf">.notify</span><span class="p">(</span><span class="mi">3</span><span class="p">);</span>
    <span class="n">notifier</span><span class="nf">.notify</span><span class="p">(</span><span class="mi">141</span><span class="p">);</span>
    <span class="n">notifier</span><span class="nf">.notify</span><span class="p">(</span><span class="mi">59</span><span class="p">);</span>
    <span class="nd">assert_eq!</span><span class="p">(</span><span class="o">&amp;</span><span class="nd">vec!</span><span class="p">[</span><span class="mi">3</span><span class="p">,</span> <span class="mi">141</span><span class="p">,</span> <span class="mi">59</span><span class="p">],</span> <span class="n">rc</span><span class="nf">.borrow</span><span class="p">()</span><span class="nf">.events</span><span class="p">());</span></code></pre></figure>

<p>De cette manière, le <code class="highlighter-rouge">Storage</code> est correctement modifié à partir de l’<em>event
listener</em>.</p>

<p>Tout n’est pas résolu pour autant. Dans cet exemple, c’était facile, nous avions
accès à l’instance <code class="highlighter-rouge">Rc&lt;RefCell&lt;Storage&gt;&gt;</code>. Comment faire si nous avons seulement
accès au <code class="highlighter-rouge">Storage</code>, par exemple si nous voulons que le <code class="highlighter-rouge">Storage</code> s’enregistre
lui-même à partir de l’une de ses méthodes, sans que l’appelant n’ait à fournir
l’instance <code class="highlighter-rouge">Rc&lt;RefCell&lt;Storage&gt;&gt;</code> ?</p>

<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="k">impl</span> <span class="n">Storage</span> <span class="p">{</span>
    <span class="k">pub</span> <span class="k">fn</span> <span class="nf">register_to</span><span class="p">(</span><span class="o">&amp;</span><span class="k">self</span><span class="p">,</span> <span class="n">notifier</span><span class="p">:</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="n">Notifier</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">notifier</span><span class="nf">.register</span><span class="p">(</span><span class="k">move</span> <span class="p">|</span><span class="n">event</span><span class="p">|</span> <span class="p">{</span>
            <span class="cm">/* how to retrieve a &amp;mut Storage from here? */</span>
        <span class="p">});</span>
    <span class="p">}</span>
<span class="p">}</span></code></pre></figure>

<p>Nous devons trouver un moyen de récupérer le <code class="highlighter-rouge">Rc&lt;RefCell&lt;Storage&gt;&gt;</code> à partir du
<code class="highlighter-rouge">Storage</code>.</p>

<p>Pour cela, l’idée consiste à rendre <code class="highlighter-rouge">Storage</code> conscient de son pointeur à
compteur de références. <em>Bien sûr, cela n’a du sens que si <code class="highlighter-rouge">Storage</code> est
construit dans un <code class="highlighter-rouge">Rc&lt;RefCell&lt;Storage&gt;&gt;</code>.</em></p>

<p>C’est exactement ce que <a href="http://en.cppreference.com/w/cpp/memory/enable_shared_from_this"><code class="highlighter-rouge">enable_shared_from_this</code></a> fournit en C++, donc nous
pouvons nous inspirer de <a href="https://stackoverflow.com/a/34062114/1987178">son fonctionnement</a> : juste
stocker un <code class="highlighter-rouge">Weak&lt;RefCell&lt;…&gt;&gt;</code>, <a href="https://doc.rust-lang.org/std/rc/struct.Rc.html#method.downgrade"><em>downgradé</em></a> à partir du
<code class="highlighter-rouge">Rc&lt;RefCell&lt;…&gt;&gt;</code>, dans la structure elle-même. De cette manière, nous pouvons
l’utiliser pour récupérer une référence <code class="highlighter-rouge">&amp;mut Storage</code> à partir de l’<em>event
listener</em> :</p>

<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="k">use</span> <span class="nn">std</span><span class="p">::</span><span class="nn">rc</span><span class="p">::{</span><span class="nb">Rc</span><span class="p">,</span> <span class="n">Weak</span><span class="p">};</span>
<span class="k">use</span> <span class="nn">std</span><span class="p">::</span><span class="nn">cell</span><span class="p">::</span><span class="n">RefCell</span><span class="p">;</span>

<span class="k">pub</span> <span class="k">struct</span> <span class="n">Storage</span> <span class="p">{</span>
    <span class="n">self_weak</span><span class="p">:</span> <span class="n">Weak</span><span class="o">&lt;</span><span class="n">RefCell</span><span class="o">&lt;</span><span class="n">Storage</span><span class="o">&gt;&gt;</span><span class="p">,</span>
    <span class="n">events</span><span class="p">:</span> <span class="nb">Vec</span><span class="o">&lt;</span><span class="nb">u32</span><span class="o">&gt;</span><span class="p">,</span>
<span class="p">}</span>

<span class="k">impl</span> <span class="n">Storage</span> <span class="p">{</span>
    <span class="k">pub</span> <span class="k">fn</span> <span class="nf">new</span><span class="p">()</span> <span class="k">-&gt;</span> <span class="nb">Rc</span><span class="o">&lt;</span><span class="n">RefCell</span><span class="o">&lt;</span><span class="n">Self</span><span class="o">&gt;&gt;</span> <span class="p">{</span>
        <span class="k">let</span> <span class="n">rc</span> <span class="o">=</span> <span class="nn">Rc</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="nn">RefCell</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="n">Self</span> <span class="p">{</span>
            <span class="n">self_weak</span><span class="p">:</span> <span class="nn">Weak</span><span class="p">::</span><span class="nf">new</span><span class="p">(),</span> <span class="c">// initialize empty</span>
            <span class="n">events</span><span class="p">:</span> <span class="nn">Vec</span><span class="p">::</span><span class="nf">new</span><span class="p">(),</span>
        <span class="p">}));</span>
        <span class="c">// set self_weak once we get the Rc instance</span>
        <span class="n">rc</span><span class="nf">.borrow_mut</span><span class="p">()</span><span class="py">.self_weak</span> <span class="o">=</span> <span class="nn">Rc</span><span class="p">::</span><span class="nf">downgrade</span><span class="p">(</span><span class="o">&amp;</span><span class="n">rc</span><span class="p">);</span>
        <span class="n">rc</span>
    <span class="p">}</span>

    <span class="k">pub</span> <span class="k">fn</span> <span class="nf">register_to</span><span class="p">(</span><span class="o">&amp;</span><span class="k">self</span><span class="p">,</span> <span class="n">notifier</span><span class="p">:</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="n">Notifier</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">let</span> <span class="n">rc</span> <span class="o">=</span> <span class="k">self</span><span class="py">.self_weak</span><span class="nf">.upgrade</span><span class="p">()</span><span class="nf">.unwrap</span><span class="p">();</span>
        <span class="n">notifier</span><span class="nf">.register</span><span class="p">(</span><span class="k">move</span> <span class="p">|</span><span class="n">event</span><span class="p">|</span> <span class="n">rc</span><span class="nf">.borrow_mut</span><span class="p">()</span><span class="nf">.store</span><span class="p">(</span><span class="n">event</span><span class="p">))</span>
    <span class="p">}</span>
<span class="p">}</span></code></pre></figure>

<p>Voici comment l’utiliser :</p>

<figure class="highlight"><pre><code class="language-rust" data-lang="rust">    <span class="k">let</span> <span class="k">mut</span> <span class="n">notifier</span> <span class="o">=</span> <span class="nn">Notifier</span><span class="p">::</span><span class="nf">new</span><span class="p">();</span>
    <span class="k">let</span> <span class="n">rc</span> <span class="o">=</span> <span class="nn">Storage</span><span class="p">::</span><span class="nf">new</span><span class="p">();</span>
    <span class="n">rc</span><span class="nf">.borrow</span><span class="p">()</span><span class="nf">.register_to</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="n">notifier</span><span class="p">);</span>
    <span class="n">notifier</span><span class="nf">.notify</span><span class="p">(</span><span class="mi">3</span><span class="p">);</span>
    <span class="n">notifier</span><span class="nf">.notify</span><span class="p">(</span><span class="mi">141</span><span class="p">);</span>
    <span class="n">notifier</span><span class="nf">.notify</span><span class="p">(</span><span class="mi">59</span><span class="p">);</span>
    <span class="nd">assert_eq!</span><span class="p">(</span><span class="o">&amp;</span><span class="nd">vec!</span><span class="p">[</span><span class="mi">3</span><span class="p">,</span> <span class="mi">141</span><span class="p">,</span> <span class="mi">59</span><span class="p">],</span> <span class="n">rc</span><span class="nf">.borrow</span><span class="p">()</span><span class="nf">.events</span><span class="p">());</span></code></pre></figure>

<p>Il est donc possible d’implémenter le design pattern <em>observateur</em> en Rust, mais
c’est un peu plus difficile qu’en Java ;-)</p>

<p>Lorsque c’est possible, il est probablement préférable de l’éviter.</p>

<h3 id="partage-de-donnes-mutables">Partage de données mutables</h3>

<blockquote>
  <p>Mutable references cannot be <a href="https://doc.rust-lang.org/nomicon/references.html">aliased</a>.</p>
</blockquote>

<p>En français :</p>

<blockquote>
  <p>Les références mutables ne peuvent pas être <a href="https://doc.rust-lang.org/nomicon/references.html">aliasées</a>.</p>
</blockquote>

<p>Comment partager des données mutables, alors ?</p>

<p>Nous avons vu que nous pouvions utiliser <code class="highlighter-rouge">Rc&lt;RefCell&lt;…&gt;&gt;</code> (ou <code class="highlighter-rouge">Arc&lt;Mutex&lt;…&gt;&gt;</code>),
qui impose les règles d’emprunt à l’exécution. Cependant, ce n’est pas toujours
désirable :</p>
<ul>
  <li>cela force une nouvelle allocation sur le tas,</li>
  <li>chaque accès a un coût à l’exécution,</li>
  <li>l’emprunt concerne toujours la ressource entière.</li>
</ul>

<p>Au lieu de cela, nous pourrions utiliser des pointeurs <em>bruts</em> manuellement dans
du code <a href="https://doc.rust-lang.org/book/first-edition/unsafe.html">non-sûr</a>, mais alors ce serait <em>non-sûr</em>.</p>

<p>Et il y a une autre solution, qui consiste à exposer des <strong>vues temporaires
d’emprunt</strong> d’un objet. Laissez-moi expliquer.</p>

<p>Dans <em>Gnirehtet</em>, un paquet contient une référence vers les données brutes
(stockées dans un buffer quelque part) ainsi que les valeur des champs des
en-têtes <a href="https://en.wikipedia.org/wiki/IPv4#Packet_structure">IP</a> et <a href="https://en.wikipedia.org/wiki/Transmission_Control_Protocol#TCP_segment_structure">TCP</a>/<a href="https://en.wikipedia.org/wiki/User_Datagram_Protocol#Packet_structure">UDP</a> (parsées à partir du tableau d’octets brut). Nous
aurions pu utiliser une structure à plat pour tout stocker :</p>

<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="k">pub</span> <span class="k">struct</span> <span class="n">Packet</span><span class="o">&lt;</span><span class="err">'</span><span class="n">a</span><span class="o">&gt;</span> <span class="p">{</span>
    <span class="n">raw</span><span class="p">:</span> <span class="o">&amp;</span><span class="err">'</span><span class="n">a</span> <span class="k">mut</span> <span class="p">[</span><span class="nb">u8</span><span class="p">],</span>
    <span class="n">ipv4_source</span><span class="p">:</span> <span class="nb">u32</span><span class="p">,</span>
    <span class="n">ipv4_destination</span><span class="p">:</span> <span class="nb">u32</span><span class="p">,</span>
    <span class="n">ipv4_protocol</span><span class="p">:</span> <span class="nb">u8</span><span class="p">,</span>
    <span class="c">// + other ipv4 fields</span>
    <span class="n">transport_source</span><span class="p">:</span> <span class="nb">u16</span><span class="p">,</span>
    <span class="n">transport_destination</span><span class="p">:</span> <span class="nb">u16</span><span class="p">,</span>
    <span class="c">// + other transport fields</span>
<span class="p">}</span></code></pre></figure>

<p>Le <code class="highlighter-rouge">Packet</code> aurait fourni des <em>setters</em> pour tous les champs d’en-têtes
(modifiant à la fois les champs du paquet et le tableau d’octets). Par exemple :</p>

<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="k">impl</span><span class="o">&lt;</span><span class="err">'</span><span class="n">a</span><span class="o">&gt;</span> <span class="n">Packet</span><span class="o">&lt;</span><span class="err">'</span><span class="n">a</span><span class="o">&gt;</span> <span class="p">{</span>
    <span class="k">pub</span> <span class="k">fn</span> <span class="nf">set_transport_source</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">,</span> <span class="n">transport_source</span><span class="p">:</span> <span class="nb">u16</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">self</span><span class="py">.transport_source</span> <span class="o">=</span> <span class="n">transport_source</span><span class="p">;</span>
        <span class="k">let</span> <span class="n">transport</span> <span class="o">=</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="py">.raw</span><span class="p">[</span><span class="mi">20</span><span class="err">..</span><span class="p">];</span>
        <span class="nn">BigEndian</span><span class="p">::</span><span class="nf">write_u16</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="n">transport</span><span class="p">[</span><span class="mi">0</span><span class="err">..</span><span class="mi">2</span><span class="p">],</span> <span class="n">port</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span></code></pre></figure>

<p>Mais cette conception ne serait pas terrible (surtout que les champs d’en-têtes
TCP et UDP sont différents).</p>

<p>À la place, nous voudrions extraire les en-têtes d’IP et de transport vers des
structures séparées, gérant leur propre partie du tableau d’octets :</p>

<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="c">// violates the borrowing rules</span>

<span class="k">pub</span> <span class="k">struct</span> <span class="n">Packet</span><span class="o">&lt;</span><span class="err">'</span><span class="n">a</span><span class="o">&gt;</span> <span class="p">{</span>
    <span class="n">raw</span><span class="p">:</span> <span class="o">&amp;</span><span class="err">'</span><span class="n">a</span> <span class="k">mut</span> <span class="p">[</span><span class="nb">u8</span><span class="p">],</span> <span class="c">// the whole packet (including headers)</span>
    <span class="n">ipv4_header</span><span class="p">:</span> <span class="n">Ipv4Header</span><span class="o">&lt;</span><span class="err">'</span><span class="n">a</span><span class="o">&gt;</span><span class="p">,</span>
    <span class="n">transport_header</span><span class="p">:</span> <span class="n">TransportHeader</span><span class="o">&lt;</span><span class="err">'</span><span class="n">a</span><span class="o">&gt;</span><span class="p">,</span>
<span class="p">}</span>

<span class="k">pub</span> <span class="k">struct</span> <span class="n">Ipv4Header</span><span class="o">&lt;</span><span class="err">'</span><span class="n">a</span><span class="o">&gt;</span> <span class="p">{</span>
    <span class="n">raw</span><span class="p">:</span> <span class="o">&amp;</span><span class="err">'</span><span class="n">a</span> <span class="k">mut</span> <span class="p">[</span><span class="nb">u8</span><span class="p">],</span> <span class="c">// slice related to ipv4 headers</span>
    <span class="n">source</span><span class="p">:</span> <span class="nb">u32</span><span class="p">,</span>
    <span class="n">destination</span><span class="p">:</span> <span class="nb">u32</span><span class="p">,</span>
    <span class="n">protocol</span><span class="p">:</span> <span class="nb">u8</span><span class="p">,</span>
    <span class="c">// + other ipv4 fields</span>
<span class="p">}</span>

<span class="k">pub</span> <span class="k">struct</span> <span class="n">TransportHeader</span><span class="o">&lt;</span><span class="err">'</span><span class="n">a</span><span class="o">&gt;</span> <span class="p">{</span>
    <span class="n">raw</span><span class="p">:</span> <span class="o">&amp;</span><span class="err">'</span><span class="n">a</span> <span class="k">mut</span> <span class="p">[</span><span class="nb">u8</span><span class="p">],</span> <span class="c">// slice related to transport headers</span>
    <span class="n">source</span><span class="p">:</span> <span class="nb">u16</span><span class="p">,</span>
    <span class="n">destination</span><span class="p">:</span> <span class="nb">u16</span><span class="p">,</span>
    <span class="c">// + other transport fields</span>
<span class="p">}</span></code></pre></figure>

<p>Vous avez immédiatement repéré le problème : <strong>il y a plusieurs références vers
la même ressource, le tableau d’octets <code class="highlighter-rouge">raw</code>, en même temps</strong>.</p>

<p><em>Remarquez que <a href="https://doc.rust-lang.org/std/primitive.slice.html#method.split_at_mut">diviser</a> le tableau n’est pas une possibilité ici, vu
que les slices de <code class="highlighter-rouge">raw</code> se chevauchent : nous avons besoin d’écrire le paquet
complet en une seule fois vers la couche réseau, donc le tableau <code class="highlighter-rouge">raw</code> dans
<code class="highlighter-rouge">Packet</code> doit inclure les headers.</em></p>

<p>Nous avons besoin d’une solution compatible avec les règles d’emprunt.</p>

<p>Voici celle à laquelle je suis parvenu :</p>
<ul>
  <li>stocker les données des en-têtes séparément, sans les <em>slices</em> de <code class="highlighter-rouge">raw</code>,</li>
  <li>créer des structures de <em>vues</em> pour les en-têtes d’IP et de transport, liées
à une <a href="https://doc.rust-lang.org/book/first-edition/lifetimes.html#in-structs">durée de vie</a>,</li>
  <li>exposer des méthodes de <code class="highlighter-rouge">Packet</code> retournant des instances de <em>vues</em>.</li>
</ul>

<p>Et voici une simplification de l’implémentation réelle :</p>

<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="k">pub</span> <span class="k">struct</span> <span class="n">Packet</span><span class="o">&lt;</span><span class="err">'</span><span class="n">a</span><span class="o">&gt;</span> <span class="p">{</span>
    <span class="n">raw</span><span class="p">:</span> <span class="o">&amp;</span><span class="err">'</span><span class="n">a</span> <span class="k">mut</span> <span class="p">[</span><span class="nb">u8</span><span class="p">],</span>
    <span class="n">ipv4_header</span><span class="p">:</span> <span class="n">Ipv4HeaderData</span><span class="p">,</span>
    <span class="n">transport_header</span><span class="p">:</span> <span class="n">TransportHeaderData</span><span class="p">,</span>
<span class="p">}</span>

<span class="k">pub</span> <span class="k">struct</span> <span class="n">Ipv4HeaderData</span> <span class="p">{</span>
    <span class="n">source</span><span class="p">:</span> <span class="nb">u32</span><span class="p">,</span>
    <span class="n">destination</span><span class="p">:</span> <span class="nb">u32</span><span class="p">,</span>
    <span class="n">protocol</span><span class="p">:</span> <span class="nb">u8</span><span class="p">,</span>
    <span class="c">// + other ipv4 fields</span>
<span class="p">}</span>

<span class="k">pub</span> <span class="k">struct</span> <span class="n">TransportHeaderData</span> <span class="p">{</span>
    <span class="n">source</span><span class="p">:</span> <span class="nb">u16</span><span class="p">,</span>
    <span class="n">destination</span><span class="p">:</span> <span class="nb">u16</span><span class="p">,</span>
    <span class="c">// + other transport fields</span>
<span class="p">}</span>

<span class="k">pub</span> <span class="k">struct</span> <span class="n">Ipv4Header</span><span class="o">&lt;</span><span class="err">'</span><span class="n">a</span><span class="o">&gt;</span> <span class="p">{</span>
    <span class="n">raw</span><span class="p">:</span> <span class="o">&amp;</span><span class="err">'</span><span class="n">a</span> <span class="k">mut</span> <span class="p">[</span><span class="nb">u8</span><span class="p">],</span>
    <span class="n">data</span><span class="p">:</span> <span class="o">&amp;</span><span class="err">'</span><span class="n">a</span> <span class="k">mut</span> <span class="n">Ipv4HeaderData</span><span class="p">,</span>
<span class="p">}</span>

<span class="k">pub</span> <span class="k">struct</span> <span class="n">TransportHeader</span><span class="o">&lt;</span><span class="err">'</span><span class="n">a</span><span class="o">&gt;</span> <span class="p">{</span>
    <span class="n">raw</span><span class="p">:</span> <span class="o">&amp;</span><span class="err">'</span><span class="n">a</span> <span class="k">mut</span> <span class="p">[</span><span class="nb">u8</span><span class="p">],</span>
    <span class="n">data</span><span class="p">:</span> <span class="o">&amp;</span><span class="err">'</span><span class="n">a</span> <span class="k">mut</span> <span class="n">TransportHeaderData</span><span class="p">,</span>
<span class="p">}</span>

<span class="k">impl</span><span class="o">&lt;</span><span class="err">'</span><span class="n">a</span><span class="o">&gt;</span> <span class="n">Packet</span><span class="o">&lt;</span><span class="err">'</span><span class="n">a</span><span class="o">&gt;</span> <span class="p">{</span>
    <span class="k">pub</span> <span class="k">fn</span> <span class="nf">ipv4_header</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="n">Ipv4Header</span> <span class="p">{</span>
        <span class="n">Ipv4Header</span> <span class="p">{</span>
            <span class="n">raw</span><span class="p">:</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="py">.raw</span><span class="p">[</span><span class="err">..</span><span class="mi">20</span><span class="p">],</span>
            <span class="n">data</span><span class="p">:</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="py">.ipv4_header</span><span class="p">,</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="k">pub</span> <span class="k">fn</span> <span class="nf">transport_header</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="n">TransportHeader</span> <span class="p">{</span>
        <span class="n">TransportHeader</span> <span class="p">{</span>
            <span class="n">raw</span><span class="p">:</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="py">.raw</span><span class="p">[</span><span class="mi">20</span><span class="err">..</span><span class="mi">40</span><span class="p">],</span>
            <span class="n">data</span><span class="p">:</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="py">.transport_header</span><span class="p">,</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span></code></pre></figure>

<p>Les <em>setters</em> sont implémentés sur les vues, où ils détiennent une référence
mutable vers le tableau brut :</p>

<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="k">impl</span><span class="o">&lt;</span><span class="err">'</span><span class="n">a</span><span class="o">&gt;</span> <span class="n">TransportHeader</span><span class="o">&lt;</span><span class="err">'</span><span class="n">a</span><span class="o">&gt;</span> <span class="p">{</span>
    <span class="k">pub</span> <span class="k">fn</span> <span class="nf">set_source</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">,</span> <span class="n">source</span><span class="p">:</span> <span class="nb">u16</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">self</span><span class="py">.data.source</span> <span class="o">=</span> <span class="n">source</span><span class="p">;</span>
        <span class="nn">BigEndian</span><span class="p">::</span><span class="nf">write_u16</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="n">raw</span><span class="p">[</span><span class="mi">0</span><span class="err">..</span><span class="mi">2</span><span class="p">],</span> <span class="n">source</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="k">pub</span> <span class="k">fn</span> <span class="nf">set_destination</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">,</span> <span class="n">destination</span><span class="p">:</span> <span class="nb">u16</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">self</span><span class="py">.data.destination</span> <span class="o">=</span> <span class="n">destination</span><span class="p">;</span>
        <span class="nn">BigEndian</span><span class="p">::</span><span class="nf">write_u16</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="n">raw</span><span class="p">[</span><span class="mi">2</span><span class="err">..</span><span class="mi">4</span><span class="p">],</span> <span class="n">destination</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span></code></pre></figure>

<p>De cette manière, les règles d’emprunt sont respectées, et l’API est élégante :</p>

<figure class="highlight"><pre><code class="language-rust" data-lang="rust">    <span class="k">let</span> <span class="k">mut</span> <span class="n">packet</span> <span class="o">=</span> <span class="err">…</span><span class="p">;</span>
    <span class="c">// "transport_header" borrows "packet" during its scope</span>
    <span class="k">let</span> <span class="k">mut</span> <span class="n">transport_header</span> <span class="o">=</span> <span class="n">packet</span><span class="nf">.transport_header</span><span class="p">();</span>
    <span class="n">transport_header</span><span class="nf">.set_source</span><span class="p">(</span><span class="mi">1234</span><span class="p">);</span>
    <span class="n">transport_header</span><span class="nf">.set_destination</span><span class="p">(</span><span class="mi">1234</span><span class="p">);</span></code></pre></figure>

<h3 id="limitations-du-compilateur">Limitations du compilateur</h3>

<p>Rust est un langage jeune, et le compilateur a quelques problèmes ennuyeux.</p>

<p>Le pire, d’après moi, est lié aux <a href="http://smallcultfollowing.com/babysteps/blog/2016/04/27/non-lexical-lifetimes-introduction/#problem-case-2-conditional-control-flow">durées de vie non-lexicales</a>, qui provoque des <a href="https://stackoverflow.com/questions/44417491/non-lexical-lifetime-workaround-failure">erreurs inattendues</a> :</p>

<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="k">struct</span> <span class="n">Container</span> <span class="p">{</span>
    <span class="n">vec</span><span class="p">:</span> <span class="nb">Vec</span><span class="o">&lt;</span><span class="nb">i32</span><span class="o">&gt;</span><span class="p">,</span>
<span class="p">}</span>

<span class="k">impl</span> <span class="n">Container</span> <span class="p">{</span>
    <span class="k">fn</span> <span class="nf">find</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">,</span> <span class="n">v</span><span class="p">:</span> <span class="nb">i32</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="nb">Option</span><span class="o">&lt;&amp;</span><span class="k">mut</span> <span class="nb">i32</span><span class="o">&gt;</span> <span class="p">{</span>
        <span class="nb">None</span> <span class="c">// we don't care the implementation</span>
    <span class="p">}</span>

    <span class="k">fn</span> <span class="nf">get</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">,</span> <span class="n">v</span><span class="p">:</span> <span class="nb">i32</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="nb">i32</span> <span class="p">{</span>
        <span class="k">if</span> <span class="k">let</span> <span class="nf">Some</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="o">=</span> <span class="k">self</span><span class="nf">.find</span><span class="p">(</span><span class="n">v</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">return</span> <span class="n">x</span><span class="p">;</span>
        <span class="p">}</span>
        <span class="k">self</span><span class="py">.vec</span><span class="nf">.push</span><span class="p">(</span><span class="n">v</span><span class="p">);</span>
        <span class="k">self</span><span class="py">.vec</span><span class="nf">.last_mut</span><span class="p">()</span><span class="nf">.unwrap</span><span class="p">()</span>
    <span class="p">}</span>
<span class="p">}</span></code></pre></figure>

<div class="highlighter-rouge"><pre class="codehilite"><code>error[E0499]: cannot borrow `self.vec` as mutable more than once at a time
  --&gt; sample.rs:14:9
   |
11 |         if let Some(x) = self.find(v) {
   |                          ---- first mutable borrow occurs here
...
14 |         self.vec.push(v);
   |         ^^^^^^^^ second mutable borrow occurs here
15 |         self.vec.last_mut().unwrap()
16 |     }
   |     - first borrow ends here
</code></pre></div>

<p>Heureusement, <a href="http://smallcultfollowing.com/babysteps/blog/2017/07/11/non-lexical-lifetimes-draft-rfc-and-prototype-available/">cela devrait être corrigé prochainement</a>.</p>

<p>La fonctionnalité d’<a href="https://github.com/rust-lang/rfcs/blob/master/text/1522-conservative-impl-trait.md"><em>Impl Trait</em></a>, permettant aux fonctions de
retourner des types abstraits <em>non-boxés</em>, devrait aussi améliorer l’expérience
(il y a aussi une proposition <a href="https://github.com/rust-lang/rfcs/blob/master/text/1951-expand-impl-trait.md">étendue</a>).</p>

<p>Le compilateur produit généralement des messages d’erreur très utiles. Mais
quand ce n’est pas le cas, ils peuvent être très <a href="https://stackoverflow.com/questions/44003622/implementing-trait-for-fnsomething-in-rust">déroutants</a>.</p>

<h2 id="sret-et-piges">Sûreté et pièges</h2>

<p>Le <a href="https://doc.rust-lang.org/nomicon/meet-safe-and-unsafe.html">premier chapitre du <em>Rustonomicon</em></a> dit :</p>

<blockquote>
  <p>Safe Rust is For Reals Totally Safe.</p>

  <p>[…]</p>

  <p>Safe Rust is the true Rust programming language. If all you do is write Safe
Rust, you will never have to worry about type-safety or memory-safety. You
will never endure a null or dangling pointer, or any of that Undefined
Behavior nonsense.</p>
</blockquote>

<p>En français :</p>

<blockquote>
  <p>La partie Sûre de Rust est Réellement Totallement Sûre.</p>

  <p>[…]</p>

  <p>Le Rust Sûr est le vrai langage de programmation Rust. Si vous n’écrivez que
du Rust Sûr, vous n’aurez jamais à vous inquiétez de la sûreté des types ou de
la mémoire. Vous n’aurez jamais à supporter un pointeur null ou <a href="https://fr.wikipedia.org/wiki/Dangling_pointer"><em>dangling</em></a>,
ou l’un de ces <a href="/2014/10/comportement-indefini-et-optimisation/"><em>comportements indéfinis</em></a> insensés.</p>
</blockquote>

<p>C’est le but. Et c’est <em>presque</em> vrai.</p>

<h3 id="leakpocalypse">Leakpocalypse</h3>

<p>Dans le passé, il a été <a href="https://github.com/rust-lang/rust/issues/24292">possible</a> d’écrire du code <em>Rust sûr</em>
<strong>accédant à de la mémoire libérée</strong>.</p>

<p>Cette “<a href="http://cglab.ca/~abeinges/blah/everyone-poops/">leakpocalypse</a>” a conduit à la <a href="https://github.com/alexcrichton/rfcs/blob/safe-mem-forget/text/0000-safe-mem-forget.md">clarification</a> des guaranties
de sûreté : ne pas exécuter un destructeur est maintenant <a href="https://github.com/rust-lang/rfcs/pull/1066">considéré
<em>sûr</em></a>. En d’autres termes, <strong>la sûreté mémoire ne peut plus
reposer sur <a href="https://en.wikipedia.org/wiki/Resource_acquisition_is_initialization">RAII</a></strong> (en fait, elle n’a jamais pu, mais cela n’a été remarqué
que tardivement).</p>

<p>En conséquence, <a href="https://doc.rust-lang.org/std/mem/fn.forget.html"><code class="highlighter-rouge">std::mem::forget</code></a> est maintenant <em>sûr</em>, et <a href="https://doc.rust-lang.org/1.0.0/std/thread/struct.JoinGuard.html"><code class="highlighter-rouge">JoinGuard</code></a> a
été déprécié et supprimé de la bibliothèque standard (il a été déplacé vers un
<a href="http://arcnmx.github.io/thread-scoped-rs/thread_scoped/">crate séparé</a>).</p>

<p>Les autres outils s’appuyant sur RAII (comme <a href="https://doc.rust-lang.org/std/vec/struct.Vec.html#method.drain"><code class="highlighter-rouge">Vec::drain()</code></a>) doivent prendre
des <a href="https://github.com/rust-lang/rust/blob/1.20.0/src/liballoc/vec.rs#L1094-L1102">précautions particulières</a> pour garantir que la mémoire
ne sera pas corrompue.</p>

<p>Ouf, la <em>sûreté mémoire</em> est (maintenant) sauvée.</p>

<h3 id="infinit-indfinie">Infinité indéfinie</h3>

<p>En C et C++, les <a href="https://stackoverflow.com/questions/3592557/optimizing-away-a-while1-in-c0x">boucles infinies</a> sans effets de bords sont un cas
d’<a href="http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1528.htm"><em>undefined behavior</em></a>. À cause de cela, il est possible d’écrire des
programmes qui, de façon inattendue, <a href="https://blog.regehr.org/archives/140">réfutent le dernier théorème de
Fermat</a>.</p>

<p>En pratique, le compilateur Rust s’appuie sur LLVM, qui (actuellement) applique
ses optimisations en faisant l’hypothèse que les boucles infinies sans effets de
bords ont un <em>comportement indéfini</em>. En conséquence, de tels <em>undefined
behaviors</em> se produisent également en Rust.</p>

<p>Voici un exemple minimal pour l’observer :</p>

<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="k">fn</span> <span class="nf">infinite</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">loop</span> <span class="p">{}</span>
<span class="p">}</span>

<span class="k">fn</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="nf">infinite</span><span class="p">();</span>
<span class="p">}</span></code></pre></figure>

<p>Quand on l’exécute sans optimisations, il se comporte comme “attendu” :</p>

<div class="highlighter-rouge"><pre class="codehilite"><code>$ rustc ub.rs &amp;&amp; ./ub
^C                    (infinite loop, interrupt it)
</code></pre></div>

<p>Mais activer les optimisations fait <em>paniquer</em> le programme :</p>

<div class="highlighter-rouge"><pre class="codehilite"><code>$ rustc -O ub.rs &amp;&amp; ./ub
thread 'main' panicked at 'assertion failed: c.borrow().is_none()', /checkout/src/libstd/sys_common/thread_info.rs:51
note: Run with `RUST_BACKTRACE=1` for a backtrace.
</code></pre></div>

<p>Nous pouvons aussi produire des résultats inattendus sans plantage :</p>

<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="k">fn</span> <span class="nf">infinite</span><span class="p">(</span><span class="k">mut</span> <span class="n">value</span><span class="p">:</span> <span class="nb">u32</span><span class="p">)</span> <span class="p">{</span>
    <span class="c">// infinite loop unless value initially equals 0</span>
    <span class="k">while</span> <span class="n">value</span> <span class="o">!=</span> <span class="mi">0</span> <span class="p">{</span>
        <span class="k">if</span> <span class="n">value</span> <span class="o">!=</span> <span class="mi">1</span> <span class="p">{</span>
            <span class="n">value</span> <span class="o">-=</span> <span class="mi">1</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="k">fn</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="nf">infinite</span><span class="p">(</span><span class="mi">42</span><span class="p">);</span>
    <span class="nd">println!</span><span class="p">(</span><span class="s">"end"</span><span class="p">);</span>
<span class="p">}</span></code></pre></figure>

<div class="highlighter-rouge"><pre class="codehilite"><code>$ rustc ub.rs &amp;&amp; ./ub
^C                    (infinite loop, interrupt it)
</code></pre></div>

<p>Mais avec optimisations :</p>

<div class="highlighter-rouge"><pre class="codehilite"><code>$ rustc -O ub.rs &amp;&amp; ./ub
end
</code></pre></div>

<p>C’est un cas particulier, qui sera probablement corrigé dans le futur. En
pratique, <strong>les garanties de sûreté de Rust sont très fortes</strong> (au prix d’être
contraignantes).</p>

<h3 id="erreur-de-segmentation">Erreur de segmentation</h3>

<p><em>Cette section a été ajoutée après la publication.</em></p>

<p>Il y a d’autres sources d’<em>undefined behaviors</em> (voir les <a href="https://github.com/rust-lang/rust/labels/I-unsound"><em>issues</em> taggées
<em>I-unsound</em></a>).</p>

<p>Par exemple, <em>caster</em> une valeur flottante ne pouvant pas être représentée dans
le type cible est un <em>undefined behavior</em>, qui peut être <a href="https://github.com/rust-lang/rust/issues/10184#issuecomment-139858153">propagé</a> pour
provoquer une erreur de segmentation :</p>

<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="err">#</span><span class="p">[</span><span class="nf">inline</span><span class="p">(</span><span class="n">never</span><span class="p">)]</span>
<span class="k">pub</span> <span class="k">fn</span> <span class="nf">f</span><span class="p">(</span><span class="n">ary</span><span class="p">:</span> <span class="o">&amp;</span><span class="p">[</span><span class="nb">u8</span><span class="p">;</span> <span class="mi">5</span><span class="p">])</span> <span class="k">-&gt;</span> <span class="o">&amp;</span><span class="p">[</span><span class="nb">u8</span><span class="p">]</span> <span class="p">{</span>
    <span class="k">let</span> <span class="n">idx</span> <span class="o">=</span> <span class="mf">1e100f64</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">;</span>
    <span class="o">&amp;</span><span class="n">ary</span><span class="p">[</span><span class="n">idx</span><span class="err">..</span><span class="p">]</span>
<span class="p">}</span>

<span class="k">fn</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="nd">println!</span><span class="p">(</span><span class="s">"{}"</span><span class="p">,</span> <span class="nf">f</span><span class="p">(</span><span class="o">&amp;</span><span class="p">[</span><span class="mi">1</span><span class="p">;</span> <span class="mi">5</span><span class="p">])[</span><span class="mi">0xdeadbeef</span><span class="p">]);</span>
<span class="p">}</span></code></pre></figure>

<div class="highlighter-rouge"><pre class="codehilite"><code>rustc -O ub.rs &amp;&amp; ./ub
Erreur de segmentation
</code></pre></div>

<h2 id="stats">Stats</h2>

<p>C’est tout pour mes retours sur le langage lui-même.</p>

<p>En supplément, comparons les versions <em>Java</em> et <em>Rust</em> du serveur relais.</p>

<h3 id="nombre-de-lignes">Nombre de lignes</h3>

<div class="highlighter-rouge"><pre class="codehilite"><code>$ cloc relay-{java,rust}/src
-------------------------------------------------------------------------------
Language                     files          blank        comment           code
-------------------------------------------------------------------------------
Rust                            29            687            655           4506
Java                            37            726            701           2931
-------------------------------------------------------------------------------
</code></pre></div>

<p><em>(tests included)</em></p>

<p>Le projet Rust est significativement plus gros, pour plusieurs raisons :</p>
<ul>
  <li>il y a beaucoup de classes de <a href="#partage-de-donnes-mutables"><em>vues d’emprunt</em></a> ;</li>
  <li>la version Rust définit sa propre classe de <em>selecteur</em> d’I/O asynchrone,
encapsulant <a href="https://docs.rs/mio/0.6.10/mio/struct.Poll.html"><code class="highlighter-rouge">Poll</code></a> de plus bas niveau, alors que la version Java
utilise le <a href="https://docs.oracle.com/javase/8/docs/api/java/nio/channels/Selector.html"><code class="highlighter-rouge">Selector</code></a> standard ;</li>
  <li>la <a href="https://doc.rust-lang.org/book/first-edition/error-handling.html">gestion d’erreur</a> pour l’analyse de la ligne de commande
est plus verbeuse.</li>
</ul>

<p>La version Java contient plus de fichiers car les tests unitaires sont séparés,
alors qu’en Rust ils se trouvent dans le même fichier que les classes qu’ils
testent.</p>

<p>Juste pour information, voici les résultats pour le client Android :</p>

<div class="highlighter-rouge"><pre class="codehilite"><code>$ cloc app/src
-------------------------------------------------------------------------------
Language                     files          blank        comment           code
-------------------------------------------------------------------------------
Java                            15            198            321            875
XML                              6              7              2             76
-------------------------------------------------------------------------------
SUM:                            21            205            323            951
-------------------------------------------------------------------------------
</code></pre></div>

<h3 id="taille-des-binaires">Taille des binaires</h3>

<div class="highlighter-rouge"><pre class="codehilite"><code>--------------------------------------------
Java     gnirehtet.jar                   61K
--------------------------------------------
Rust     gnirehtet                      3.0M
         after "strip -g gnirehtet"     747K
         after "strip gnirehtet"        588K
--------------------------------------------
</code></pre></div>

<p>Le binaire Java lui-même est bien plus petit. La comparaison n’est pas juste
cependant, vu qu’il nécessite l’<em>environnement d’exécution Java</em> :</p>

<div class="highlighter-rouge"><pre class="codehilite"><code>$ du -sh /usr/lib/jvm/java-1.8.0-openjdk-amd64/
156M	/usr/lib/jvm/java-1.8.0-openjdk-amd64/
</code></pre></div>

<h3 id="utilisation-mmoire">Utilisation mémoire</h3>

<p>Avec une seule connection TCP ouvert, voici la consommation mémoire pour le
serveur relais en Java :</p>

<div class="highlighter-rouge"><pre class="codehilite"><code>$ sudo pmap -x $RELAY_JAVA_PID
                  Kbytes     RSS   Dirty
total kB         4364052   86148   69316
</code></pre></div>

<p><em>(résultat filtré)</em></p>

<p>Et pour le serveur relais en Rust :</p>

<div class="highlighter-rouge"><pre class="codehilite"><code>$ sudo pmap -x $RELAY_RUST_PID
                  Kbytes     RSS   Dirty
total kB           19272    2736     640
</code></pre></div>

<p><em>Regardez la valeur <a href="https://en.wikipedia.org/wiki/Resident_set_size">RSS</a>, qui indique la mémoire réellement utilisée.</em></p>

<p>Comment on pouvait s’y attendre, la version Java consomme plus de mémoire
(86Mo) que la version Rust (moins de 3Mo). De plus, sa valeur est instable à
cause de l’allocation de petits objets et leur <a href="https://en.wikipedia.org/wiki/Garbage_collection_(computer_science)"><em>garbage collection</em></a>, qui
génère aussi davantage de <em>dirty pages</em>. La valeur pour Rust, quant à elle, est
très stable : une fois la connection créée, il n’y a plus d’allocations mémoire
<em>du tout</em>.</p>

<h3 id="utilisation-cpu">Utilisation CPU</h3>

<p>Pour comparer l’utilisation CPU, voici mon scénario : un fichier de 500Mo est
hébergé par Apache sur mon ordinateur, je démarre le serveur relais avec <code class="highlighter-rouge">perf
stat</code>, puis je télécharge le fichier à partir de Firefox sur Android. Dès que le
fichier est téléchargé, je stoppe le serveur relais (Ctrl+C).</p>

<p>Voici les résultats pour la version Java :</p>

<div class="highlighter-rouge"><pre class="codehilite"><code>$ perf stat -B java -jar gnirehtet.jar relay
 Performance counter stats for 'java -jar gnirehtet.jar relay':

      11805,458302      task-clock:u (msec)       #    0,088 CPUs utilized
                 0      context-switches:u        #    0,000 K/sec
                 0      cpu-migrations:u          #    0,000 K/sec
            28 618      page-faults:u             #    0,002 M/sec
    17 908 360 446      cycles:u                  #    1,517 GHz
    13 944 172 792      stalled-cycles-frontend:u #   77,86% frontend cycles idle
    18 437 279 663      instructions:u            #    1,03  insn per cycle
                                                  #    0,76  stalled cycles per insn
     3 088 215 431      branches:u                #  261,592 M/sec
        70 647 760      branch-misses:u           #    2,29% of all branches

     133,975117164 seconds time elapsed
</code></pre></div>

<p>Et pour la version Rust :</p>

<div class="highlighter-rouge"><pre class="codehilite"><code>$ perf stat -B ./gnirehtet relay
 Performance counter stats for 'target/release/gnirehtet relay':

       2707,479968      task-clock:u (msec)       #    0,020 CPUs utilized
                 0      context-switches:u        #    0,000 K/sec
                 0      cpu-migrations:u          #    0,000 K/sec
             1 001      page-faults:u             #    0,370 K/sec
     1 011 527 340      cycles:u                  #    0,374 GHz
     2 033 810 378      stalled-cycles-frontend:u #  201,06% frontend cycles idle
       981 103 003      instructions:u            #    0,97  insn per cycle
                                                  #    2,07  stalled cycles per insn
        98 929 222      branches:u                #   36,539 M/sec
         3 220 527      branch-misses:u           #    3,26% of all branches

     133,766035253 seconds time elapsed
</code></pre></div>

<p>Je ne suis pas un expert pour analyser les résultats, mais de ce que je
comprends de la valeur <code class="highlighter-rouge">task-clock:u</code>, la version Rust consomme 4× moins de
temps CPU.</p>

<h2 id="conclusion">Conclusion</h2>

<p>Réécrire <em>Gnirehtet</em> en Rust a été une formidable expérience, où j’ai appris un
super langage et de nouveaux concepts de programmation. Et maintenant, nous
avons une application native avec de meilleures performances.</p>

<p>Bon reverse tethering !</p>

<p><em>Discussions sur <a href="https://www.reddit.com/r/rust/comments/71ks57/gnirehtet_a_reverse_tethering_tool_for_android/">reddit</a> et <a href="https://news.ycombinator.com/item?id=15326106">Hacker News</a>.</em></p>


guid: https://blog.rom1v.com/2017/09/gnirehtet-rewritten-in-rust
title: Gnirehtet rewritten in Rust
url: https://blog.rom1v.com/2017/09/gnirehtet-rewritten-in-rust/
feedurl: http://blog.rom1v.com/feed/
content:
<p>Several months ago, I introduced <a href="https://medium.com/genymobile/gnirehtet-reverse-tethering-android-2afacdbdaec7">Gnirehtet</a>, a reverse tethering tool
for Android I wrote in Java.</p>

<p>Since then, <strong>I rewrote it in <a href="https://www.rust-lang.org/">Rust</a></strong>.</p>

<p>And it’s also open source! <a href="https://github.com/Genymobile/gnirehtet">Download it</a>, plug an Android device,
and execute:</p>

<div class="highlighter-rouge"><pre class="codehilite"><code>./gnirehtet run
</code></pre></div>

<p><em>(adb must be installed)</em></p>

<ul id="markdown-toc">
  <li><a href="#why-rust" id="markdown-toc-why-rust">Why Rust?</a></li>
  <li><a href="#learning-rust" id="markdown-toc-learning-rust">Learning Rust</a></li>
  <li><a href="#difficulties" id="markdown-toc-difficulties">Difficulties</a>    <ul>
      <li><a href="#encapsulation" id="markdown-toc-encapsulation">Encapsulation</a></li>
      <li><a href="#observer" id="markdown-toc-observer">Observer</a></li>
      <li><a href="#mutable-data-sharing" id="markdown-toc-mutable-data-sharing">Mutable data sharing</a></li>
      <li><a href="#compiler-limitations" id="markdown-toc-compiler-limitations">Compiler limitations</a></li>
    </ul>
  </li>
  <li><a href="#safety-pitfalls" id="markdown-toc-safety-pitfalls">Safety pitfalls</a>    <ul>
      <li><a href="#leakpocalypse" id="markdown-toc-leakpocalypse">Leakpocalypse</a></li>
      <li><a href="#undefined-infinity" id="markdown-toc-undefined-infinity">Undefined infinity</a></li>
      <li><a href="#segfault" id="markdown-toc-segfault">Segfault</a></li>
    </ul>
  </li>
  <li><a href="#stats" id="markdown-toc-stats">Stats</a>    <ul>
      <li><a href="#number-of-lines" id="markdown-toc-number-of-lines">Number of lines</a></li>
      <li><a href="#binary-size" id="markdown-toc-binary-size">Binary size</a></li>
      <li><a href="#memory-usage" id="markdown-toc-memory-usage">Memory usage</a></li>
      <li><a href="#cpu-usage" id="markdown-toc-cpu-usage">CPU usage</a></li>
    </ul>
  </li>
  <li><a href="#conclusion" id="markdown-toc-conclusion">Conclusion</a></li>
</ul>

<h2 id="why-rust">Why Rust?</h2>

<p>At Genymobile, we wanted <em>Gnirehtet</em> not to require the <em>Java Runtime
Environment</em>, so the main requirement was to compile the application to a
<em>native</em> executable binary.</p>

<p>Therefore, I first considered rewriting it in C or C++. But at that time (early
May), I was interested in learning Rust, after vaguely hearing what it
<a href="https://blog.rust-lang.org/2017/02/06/roadmap.html">provided</a>, namely:</p>
<ul>
  <li><a href="https://blog.rust-lang.org/2015/04/10/Fearless-Concurrency.html">memory safety without garbage collection</a>,</li>
  <li><a href="https://blog.rust-lang.org/2015/04/10/Fearless-Concurrency.html">concurrency without data races</a>,</li>
  <li><a href="https://blog.rust-lang.org/2015/05/11/traits.html">abstraction without overhead</a>.</li>
</ul>

<p>However, I had never written a line of Rust code nor heard about Rust
<a href="https://doc.rust-lang.org/book/first-edition/ownership.html">ownership</a>, <a href="https://doc.rust-lang.org/book/first-edition/references-and-borrowing.html">borrowing</a> or <a href="https://doc.rust-lang.org/book/first-edition/lifetimes.html">lifetimes</a>.</p>

<p>But I am convinced that the best way to learn a programming language is to work
full-time on a real project in that language.</p>

<p>I was motivated, so after checking that it could fit our requirements
(basically, I wrote a sample using the <a href="https://en.wikipedia.org/wiki/Asynchronous_I/O">async I/O</a> library <a href="https://crates.io/crates/mio">mio</a>, and
executed it on both Linux and Windows), I decided to rewrite <em>Gnirehtet</em> in
Rust.</p>

<h2 id="learning-rust">Learning Rust</h2>

<p>During the rewriting, I <em>devoured</em> successively the <a href="https://doc.rust-lang.org/book/first-edition/">Rust book</a>, <a href="https://rustbyexample.com/">Rust by
example</a> and the <a href="https://doc.rust-lang.org/nomicon/">Rustonomicon</a>. I learned a lot, and <em>Rust</em> is an awesome
language. I now miss many of its features when I work on a C++ project,
including:</p>
<ul>
  <li><a href="https://rustbyexample.com/cast/inference.html">advanced type inference</a>,</li>
  <li><a href="https://doc.rust-lang.org/book/first-edition/enums.html">enums</a>,</li>
  <li><a href="https://doc.rust-lang.org/book/first-edition/patterns.html">patterns</a>,</li>
  <li><a href="https://doc.rust-lang.org/book/first-edition/traits.html">trait bounds</a>,</li>
  <li><a href="https://doc.rust-lang.org/std/option/"><code class="highlighter-rouge">Option&lt;T&gt;</code></a> (like <a href="https://github.com/tvaneerd/cpp17_in_TTs/blob/master/ALL_IN_ONE.md#stdoptionalt"><code class="highlighter-rouge">std::optional&lt;T&gt;</code></a> in C++17, but benefiting from enums
and patterns),</li>
  <li><a href="https://doc.rust-lang.org/book/first-edition/macros.html">hygienic macros</a>,</li>
  <li>the absence of header files,</li>
  <li>the (so simple) build system, <em>and of course</em></li>
  <li>guaranteed memory safety.</li>
</ul>

<p>About learning, Paul Graham <a href="http://paulgraham.com/know.html">wrote</a>:</p>

<blockquote>
  <p><strong>Reading and experience train your model of the world.</strong> And even if you
forget the experience or what you read, its effect on your model of the world
persists. Your mind is like a compiled program you’ve lost the source of. It
works, but you don’t know why.</p>
</blockquote>

<p>Some of Rust concepts (like <a href="https://doc.rust-lang.org/book/first-edition/lifetimes.html">lifetimes</a> or <a href="https://doc.rust-lang.org/book/first-edition/ownership.html#move-semantics">move semantics</a> by default)
provided a significantly different new <em>training set</em> which definitely affected
my model of the world (of programming).</p>

<p>I am not going to present all these features (just click on the links to the
documentation if you are interested). Instead, I will try to explain where and
why Rust resisted to the design I wanted to implement, and how to rethink the
problems within Rust constraints.</p>

<p><em>The following part requires some basic knowledge of Rust. You may want to skip
directly to the <a href="#stats">stats</a>.</em></p>

<h2 id="difficulties">Difficulties</h2>

<p>The <a href="https://github.com/Genymobile/gnirehtet/blob/master/DEVELOP.md#relay-server">design</a> of the Java application was pretty effective, so I wanted to
reproduce the global architecture in the Rust version (with adaptations to make
it more <em>Rust</em> idiomatic if necessary).</p>

<p>But I struggled on the details, especially to make the <a href="https://doc.rust-lang.org/book/first-edition/references-and-borrowing.html"><em>borrow
checker</em></a> happy. The <a href="https://doc.rust-lang.org/book/first-edition/references-and-borrowing.html#the-rules">rules</a> are simple:</p>

<blockquote>
  <p>First, any borrow must last for a scope no greater than that of the owner.
Second, you may have one or the other of these two kinds of borrows, but not
both at the same time:</p>
  <ul>
    <li>one or more references (<code class="highlighter-rouge">&amp;T</code>) to a resource,</li>
    <li>exactly one mutable reference (<code class="highlighter-rouge">&amp;mut T</code>).</li>
  </ul>
</blockquote>

<p>However, it took me some time to realize how they conflict with some patterns or
principles.</p>

<p>Here are my feedbacks. I selected 4 subjects which are general enough to be
independent of this particular project:</p>
<ul>
  <li>the conflicts with <a href="#encapsulation">encapsulation</a>;</li>
  <li>the <a href="#observer">observer</a> pattern;</li>
  <li>how to <a href="#mutable-data-sharing">share mutable data</a>;</li>
  <li>a quick note about annoying <a href="#compiler-limitations">compiler limitations</a>.</li>
</ul>

<h3 id="encapsulation">Encapsulation</h3>

<p><strong>The borrowing rules constrain encapsulation.</strong> This was the first consequence
I realized.</p>

<p>Here is a canonical sample:</p>

<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="k">pub</span> <span class="k">struct</span> <span class="n">Data</span> <span class="p">{</span>
    <span class="n">header</span><span class="p">:</span> <span class="p">[</span><span class="nb">u8</span><span class="p">;</span> <span class="mi">4</span><span class="p">],</span>
    <span class="n">payload</span><span class="p">:</span> <span class="p">[</span><span class="nb">u8</span><span class="p">;</span> <span class="mi">20</span><span class="p">],</span>
<span class="p">}</span>

<span class="k">impl</span> <span class="n">Data</span> <span class="p">{</span>
    <span class="k">pub</span> <span class="k">fn</span> <span class="nf">new</span><span class="p">()</span> <span class="k">-&gt;</span> <span class="n">Self</span> <span class="p">{</span>
        <span class="n">Self</span> <span class="p">{</span>
            <span class="n">header</span><span class="p">:</span> <span class="p">[</span><span class="mi">0</span><span class="p">;</span> <span class="mi">4</span><span class="p">],</span>
            <span class="n">payload</span><span class="p">:</span> <span class="p">[</span><span class="mi">0</span><span class="p">;</span> <span class="mi">20</span><span class="p">],</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="k">pub</span> <span class="k">fn</span> <span class="nf">header</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="p">[</span><span class="nb">u8</span><span class="p">]</span> <span class="p">{</span>
        <span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="py">.header</span>
    <span class="p">}</span>

    <span class="k">pub</span> <span class="k">fn</span> <span class="nf">payload</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="p">[</span><span class="nb">u8</span><span class="p">]</span> <span class="p">{</span>
        <span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="py">.payload</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="k">fn</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">let</span> <span class="k">mut</span> <span class="n">data</span> <span class="o">=</span> <span class="nn">Data</span><span class="p">::</span><span class="nf">new</span><span class="p">();</span>
    <span class="k">let</span> <span class="n">header</span> <span class="o">=</span> <span class="n">data</span><span class="nf">.header</span><span class="p">();</span>
    <span class="k">let</span> <span class="n">payload</span> <span class="o">=</span> <span class="n">data</span><span class="nf">.payload</span><span class="p">();</span>
<span class="p">}</span></code></pre></figure>

<p>We just create a new instance of <code class="highlighter-rouge">Data</code>, then bind mutable references to the
<code class="highlighter-rouge">header</code> and <code class="highlighter-rouge">payload</code> arrays to local variables, through accessors.</p>

<p>However, this does not compile:</p>

<div class="highlighter-rouge"><pre class="codehilite"><code>$ rustc sample.rs
error[E0499]: cannot borrow `data` as mutable more than once at a time
  --&gt; sample.rs:21:19
   |
25 |     let header = data.header();
   |                  ---- first mutable borrow occurs here
26 |     let payload = data.payload();
   |                   ^^^^ second mutable borrow occurs here
27 | }
   | - first borrow ends here
</code></pre></div>

<p>The compiler may not assume that <code class="highlighter-rouge">header()</code> and <code class="highlighter-rouge">payload()</code> return references to
disjoint data in the <code class="highlighter-rouge">Data</code> struct. Therefore, each one borrows the whole <code class="highlighter-rouge">data</code>
structure. Since the borrowing rules forbid to get two mutables references to
the same resource, it rejects the second call.</p>

<p>Sometimes, we face temporary limitations because the compiler is not smart
enough (yet). This is not the case here: the implementation of <code class="highlighter-rouge">header()</code> might
actually return a reference to <code class="highlighter-rouge">payload</code>, or write to the <code class="highlighter-rouge">payload</code> array,
violating the borrowing rules. And the validity of a method call may not depend
on the method implementation.</p>

<p>To fix the problem, the compiler must be able to know that the local variables
<code class="highlighter-rouge">header</code> and <code class="highlighter-rouge">payload</code> reference <strong>disjoint data</strong>, for example by accessing
the fields directly:</p>

<figure class="highlight"><pre><code class="language-rust" data-lang="rust">    <span class="k">let</span> <span class="n">header</span> <span class="o">=</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="n">data</span><span class="py">.header</span><span class="p">;</span>
    <span class="k">let</span> <span class="n">payload</span> <span class="o">=</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="n">data</span><span class="py">.payload</span><span class="p">;</span></code></pre></figure>

<p>or by exposing a method providing both references simultaneously:</p>

<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="k">struct</span> <span class="n">Data</span> <span class="p">{</span>
    <span class="k">fn</span> <span class="nf">header_and_payload</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="p">[</span><span class="nb">u8</span><span class="p">],</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="p">[</span><span class="nb">u8</span><span class="p">])</span> <span class="p">{</span>
        <span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="py">.header</span><span class="p">,</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="py">.payload</span><span class="p">)</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="k">fn</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">let</span> <span class="k">mut</span> <span class="n">data</span> <span class="o">=</span> <span class="nn">Data</span><span class="p">::</span><span class="nf">new</span><span class="p">();</span>
    <span class="k">let</span> <span class="p">(</span><span class="n">header</span><span class="p">,</span> <span class="n">payload</span><span class="p">)</span> <span class="o">=</span> <span class="n">data</span><span class="nf">.header_and_payload</span><span class="p">();</span>
<span class="p">}</span></code></pre></figure>

<p>Similarly, inside a struct implementation, the borrowing rules also prevent
factoring code into a private method easily. Consider this (artificial) example:</p>

<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="k">pub</span> <span class="k">struct</span> <span class="n">Data</span> <span class="p">{</span>
    <span class="n">buf</span><span class="p">:</span> <span class="p">[</span><span class="nb">u8</span><span class="p">;</span> <span class="mi">20</span><span class="p">],</span>
    <span class="n">prefix_length</span><span class="p">:</span> <span class="nb">usize</span><span class="p">,</span>
    <span class="n">sum</span><span class="p">:</span> <span class="nb">u32</span><span class="p">,</span>
    <span class="n">port</span><span class="p">:</span> <span class="nb">u16</span><span class="p">,</span>
<span class="p">}</span>

<span class="k">impl</span> <span class="n">Data</span> <span class="p">{</span>
    <span class="k">pub</span> <span class="k">fn</span> <span class="nf">update_sum</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">let</span> <span class="n">content</span> <span class="o">=</span> <span class="o">&amp;</span><span class="k">self</span><span class="py">.buf</span><span class="p">[</span><span class="k">self</span><span class="py">.prefix_length</span><span class="err">..</span><span class="p">];</span>
        <span class="k">self</span><span class="py">.sum</span> <span class="o">=</span> <span class="n">content</span><span class="nf">.iter</span><span class="p">()</span><span class="nf">.cloned</span><span class="p">()</span><span class="nf">.map</span><span class="p">(</span><span class="nn">u32</span><span class="p">::</span><span class="n">from</span><span class="p">)</span><span class="nf">.sum</span><span class="p">();</span>
    <span class="p">}</span>

    <span class="k">pub</span> <span class="k">fn</span> <span class="nf">update_port</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">let</span> <span class="n">content</span> <span class="o">=</span> <span class="o">&amp;</span><span class="k">self</span><span class="py">.buf</span><span class="p">[</span><span class="k">self</span><span class="py">.prefix_length</span><span class="err">..</span><span class="p">];</span>
        <span class="k">self</span><span class="py">.port</span> <span class="o">=</span> <span class="p">(</span><span class="n">content</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="k">as</span> <span class="nb">u16</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="mi">8</span> <span class="p">|</span> <span class="n">content</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span> <span class="k">as</span> <span class="nb">u16</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span></code></pre></figure>

<p>Here, the <code class="highlighter-rouge">buf</code> field is an array storing some prefix and content contiguously.</p>

<p>We want to factorize the way we retrieve the <code class="highlighter-rouge">content</code> slice, so that
the <code class="highlighter-rouge">update_*()</code> methods are not bothered with the details. Let’s try:</p>

<figure class="highlight"><pre><code class="language-diff" data-lang="diff"> impl Data {
     pub fn update_sum(&amp;mut self) {
<span class="gd">-        let content = &amp;self.buf[self.prefix_length..];
</span><span class="gi">+        let content = self.content();
</span>         self.sum = content.iter().cloned().map(u32::from).sum();
     }

     pub fn update_port(&amp;mut self) {
<span class="gd">-        let content = &amp;self.buf[self.prefix_length..];
</span><span class="gi">+        let content = self.content();
</span>         self.port = (content[2] as u16) &lt;&lt; 8 | content[3] as u16;
     }
<span class="gi">+
+    fn content(&amp;mut self) -&gt; &amp;[u8] {
+        &amp;self.buf[self.prefix_length..]
+    }
</span> }</code></pre></figure>

<p>Unfortunately, this does not compile:</p>

<div class="highlighter-rouge"><pre class="codehilite"><code>error[E0506]: cannot assign to `self.sum` because it is borrowed
  --&gt; facto2.rs:11:9
   |
10 |         let content = self.content();
   |                       ---- borrow of `self.sum` occurs here
11 |         self.sum = content.iter().cloned().map(u32::from).sum();
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.sum` occurs here

error[E0506]: cannot assign to `self.port` because it is borrowed
  --&gt; facto2.rs:16:9
   |
15 |         let content = self.content();
   |                       ---- borrow of `self.port` occurs here
16 |         self.port = (content[2] as u16) &lt;&lt; 8 &amp; content[3] as u16;
   |
</code></pre></div>

<p>As in the previous exemple, retrieving the reference through a method borrows
the whole struct (here, <code class="highlighter-rouge">self</code>).</p>

<p>To workaround the problem, we can explain to the compiler that the fields are
disjoint:</p>

<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="k">impl</span> <span class="n">Data</span> <span class="p">{</span>
    <span class="k">pub</span> <span class="k">fn</span> <span class="nf">update_sum</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">let</span> <span class="n">content</span> <span class="o">=</span> <span class="nn">Self</span><span class="p">::</span><span class="nf">content</span><span class="p">(</span><span class="o">&amp;</span><span class="k">self</span><span class="py">.buf</span><span class="p">,</span> <span class="k">self</span><span class="py">.prefix_length</span><span class="p">);</span>
        <span class="k">self</span><span class="py">.sum</span> <span class="o">=</span> <span class="n">content</span><span class="nf">.iter</span><span class="p">()</span><span class="nf">.cloned</span><span class="p">()</span><span class="nf">.map</span><span class="p">(</span><span class="nn">u32</span><span class="p">::</span><span class="n">from</span><span class="p">)</span><span class="nf">.sum</span><span class="p">();</span>
    <span class="p">}</span>

    <span class="k">pub</span> <span class="k">fn</span> <span class="nf">update_port</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">let</span> <span class="n">content</span> <span class="o">=</span> <span class="nn">Self</span><span class="p">::</span><span class="nf">content</span><span class="p">(</span><span class="o">&amp;</span><span class="k">self</span><span class="py">.buf</span><span class="p">,</span> <span class="k">self</span><span class="py">.prefix_length</span><span class="p">);</span>
        <span class="k">self</span><span class="py">.port</span> <span class="o">=</span> <span class="p">(</span><span class="n">content</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="k">as</span> <span class="nb">u16</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="mi">8</span> <span class="p">|</span> <span class="n">content</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span> <span class="k">as</span> <span class="nb">u16</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">fn</span> <span class="nf">content</span><span class="p">(</span><span class="n">buf</span><span class="p">:</span> <span class="o">&amp;</span><span class="p">[</span><span class="nb">u8</span><span class="p">],</span> <span class="n">prefix_length</span><span class="p">:</span> <span class="nb">usize</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="o">&amp;</span><span class="p">[</span><span class="nb">u8</span><span class="p">]</span> <span class="p">{</span>
        <span class="o">&amp;</span><span class="n">buf</span><span class="p">[</span><span class="n">prefix_length</span><span class="err">..</span><span class="p">]</span>
    <span class="p">}</span>
<span class="p">}</span></code></pre></figure>

<p>This compiles, but totally defeats the purpose of factorization: the caller has
to provide the necessary fields.</p>

<p>As an alternative, we can use a <a href="https://doc.rust-lang.org/book/first-edition/macros.html">macro</a> to <em>inline</em> the code:</p>

<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="nd">macro_rules!</span> <span class="n">content</span> <span class="p">{</span>
    <span class="p">(</span><span class="nv">$self:ident</span><span class="p">)</span> <span class="k">=&gt;</span> <span class="p">{</span>
        <span class="o">&amp;</span><span class="nv">$self</span><span class="py">.buf</span><span class="p">[</span><span class="nv">$self</span><span class="py">.prefix_length</span>..<span class="p">]</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="k">impl</span> <span class="n">Data</span> <span class="p">{</span>
    <span class="k">pub</span> <span class="k">fn</span> <span class="nf">update_sum</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">let</span> <span class="n">content</span> <span class="o">=</span> <span class="nd">content!</span><span class="p">(</span><span class="k">self</span><span class="p">);</span>
        <span class="k">self</span><span class="py">.sum</span> <span class="o">=</span> <span class="n">content</span><span class="nf">.iter</span><span class="p">()</span><span class="nf">.cloned</span><span class="p">()</span><span class="nf">.map</span><span class="p">(</span><span class="nn">u32</span><span class="p">::</span><span class="n">from</span><span class="p">)</span><span class="nf">.sum</span><span class="p">();</span>
    <span class="p">}</span>

    <span class="k">pub</span> <span class="k">fn</span> <span class="nf">update_port</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">let</span> <span class="n">content</span> <span class="o">=</span> <span class="nd">content!</span><span class="p">(</span><span class="k">self</span><span class="p">);</span>
        <span class="k">self</span><span class="py">.port</span> <span class="o">=</span> <span class="p">(</span><span class="n">content</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="k">as</span> <span class="nb">u16</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="mi">8</span> <span class="p">|</span> <span class="n">content</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span> <span class="k">as</span> <span class="nb">u16</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span></code></pre></figure>

<p>But this seems far from ideal.</p>

<p>I think we must just live with it: encapsulation sometimes conflicts with the
borrowing rules. After all, this is not so surprising: enforcing the borrowing
rules requires to follow every concrete access to resources, while
encapsulation aims to abstract them away.</p>

<h3 id="observer">Observer</h3>

<p>The <a href="https://en.wikipedia.org/wiki/Observer_pattern"><em>observer</em> pattern</a> is useful for registering event listeners on
an object.</p>

<p>In some cases, <strong>this pattern may not be straightforward to implement in Rust</strong>.</p>

<p>For simplicity, let’s consider that the events are <code class="highlighter-rouge">u32</code> values. Here
is a possible implementation:</p>

<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="k">pub</span> <span class="k">trait</span> <span class="n">EventListener</span> <span class="p">{</span>
    <span class="k">fn</span> <span class="nf">on_event</span><span class="p">(</span><span class="o">&amp;</span><span class="k">self</span><span class="p">,</span> <span class="n">event</span><span class="p">:</span> <span class="nb">u32</span><span class="p">);</span>
<span class="p">}</span>

<span class="k">pub</span> <span class="k">struct</span> <span class="n">Notifier</span> <span class="p">{</span>
    <span class="n">listeners</span><span class="p">:</span> <span class="nb">Vec</span><span class="o">&lt;</span><span class="nb">Box</span><span class="o">&lt;</span><span class="n">EventListener</span><span class="o">&gt;&gt;</span><span class="p">,</span>
<span class="p">}</span>

<span class="k">impl</span> <span class="n">Notifier</span> <span class="p">{</span>
    <span class="k">pub</span> <span class="k">fn</span> <span class="nf">new</span><span class="p">()</span> <span class="k">-&gt;</span> <span class="n">Self</span> <span class="p">{</span>
        <span class="n">Self</span> <span class="p">{</span> <span class="n">listeners</span><span class="p">:</span> <span class="nn">Vec</span><span class="p">::</span><span class="nf">new</span><span class="p">()</span> <span class="p">}</span>
    <span class="p">}</span>

    <span class="k">pub</span> <span class="k">fn</span> <span class="n">register</span><span class="o">&lt;</span><span class="n">T</span><span class="p">:</span> <span class="n">EventListener</span> <span class="o">+</span> <span class="err">'</span><span class="k">static</span><span class="o">&gt;</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">,</span> <span class="n">listener</span><span class="p">:</span> <span class="n">T</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">self</span><span class="py">.listeners</span><span class="nf">.push</span><span class="p">(</span><span class="nn">Box</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="n">listener</span><span class="p">));</span>
    <span class="p">}</span>

    <span class="k">pub</span> <span class="k">fn</span> <span class="nf">notify</span><span class="p">(</span><span class="o">&amp;</span><span class="k">self</span><span class="p">,</span> <span class="n">event</span><span class="p">:</span> <span class="nb">u32</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">for</span> <span class="n">listener</span> <span class="n">in</span> <span class="o">&amp;</span><span class="k">self</span><span class="py">.listeners</span> <span class="p">{</span>
            <span class="n">listener</span><span class="nf">.on_event</span><span class="p">(</span><span class="n">event</span><span class="p">);</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span></code></pre></figure>

<p>For convenience, make closures implement our <code class="highlighter-rouge">EventListener</code> trait:</p>

<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="k">impl</span><span class="o">&lt;</span><span class="n">F</span><span class="p">:</span> <span class="nf">Fn</span><span class="p">(</span><span class="nb">u32</span><span class="p">)</span><span class="o">&gt;</span> <span class="n">EventListener</span> <span class="k">for</span> <span class="n">F</span> <span class="p">{</span>
    <span class="k">fn</span> <span class="nf">on_event</span><span class="p">(</span><span class="o">&amp;</span><span class="k">self</span><span class="p">,</span> <span class="n">event</span><span class="p">:</span> <span class="nb">u32</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">self</span><span class="p">(</span><span class="n">event</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span></code></pre></figure>

<p>Thus, its usage is simple:</p>

<figure class="highlight"><pre><code class="language-rust" data-lang="rust">    <span class="k">let</span> <span class="k">mut</span> <span class="n">notifier</span> <span class="o">=</span> <span class="nn">Notifier</span><span class="p">::</span><span class="nf">new</span><span class="p">();</span>
    <span class="n">notifier</span><span class="nf">.register</span><span class="p">(|</span><span class="n">event</span><span class="p">|</span> <span class="nd">println!</span><span class="p">(</span><span class="s">"received [{}]"</span><span class="p">,</span> <span class="n">event</span><span class="p">));</span>
    <span class="nd">println!</span><span class="p">(</span><span class="s">"notifying..."</span><span class="p">);</span>
    <span class="n">notifier</span><span class="nf">.notify</span><span class="p">(</span><span class="mi">42</span><span class="p">);</span></code></pre></figure>

<p>This prints:</p>

<div class="highlighter-rouge"><pre class="codehilite"><code>notifying...
received [42]
</code></pre></div>

<p>So far, so good.</p>

<p>However, things get a bit more complicated if we want to mutate a state when an
event is received. For example, let’s implement a struct storing all the events
we received:</p>

<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="k">pub</span> <span class="k">struct</span> <span class="n">Storage</span> <span class="p">{</span>
    <span class="n">events</span><span class="p">:</span> <span class="nb">Vec</span><span class="o">&lt;</span><span class="nb">u32</span><span class="o">&gt;</span><span class="p">,</span>
<span class="p">}</span>

<span class="k">impl</span> <span class="n">Storage</span> <span class="p">{</span>
    <span class="k">pub</span> <span class="k">fn</span> <span class="nf">new</span><span class="p">()</span> <span class="k">-&gt;</span> <span class="n">Self</span> <span class="p">{</span>
        <span class="n">Self</span> <span class="p">{</span> <span class="n">events</span><span class="p">:</span> <span class="nn">Vec</span><span class="p">::</span><span class="nf">new</span><span class="p">()</span> <span class="p">}</span>
    <span class="p">}</span>

    <span class="k">pub</span> <span class="k">fn</span> <span class="nf">store</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">,</span> <span class="n">value</span><span class="p">:</span> <span class="nb">u32</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">self</span><span class="py">.events</span><span class="nf">.push</span><span class="p">(</span><span class="n">value</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="k">pub</span> <span class="k">fn</span> <span class="nf">events</span><span class="p">(</span><span class="o">&amp;</span><span class="k">self</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="o">&amp;</span><span class="nb">Vec</span><span class="o">&lt;</span><span class="nb">u32</span><span class="o">&gt;</span> <span class="p">{</span>
        <span class="o">&amp;</span><span class="k">self</span><span class="py">.events</span>
    <span class="p">}</span>
<span class="p">}</span></code></pre></figure>

<p>To be able to fill this <code class="highlighter-rouge">Storage</code> on each event received, we somehow have to
pass it along with the event listener, which will be stored in the <code class="highlighter-rouge">Notifier</code>.
Therefore, we need a single instance of <code class="highlighter-rouge">Storage</code> to be <strong>shared</strong> between the
caller code and the <code class="highlighter-rouge">Notifier</code>.</p>

<p>Holding two mutable references to the same object obviously violates the
borrowing rules, so we need a <a href="https://doc.rust-lang.org/std/rc/">reference-counting pointer</a>.</p>

<p>However, such a pointer is read-only, so we also need a <a href="https://doc.rust-lang.org/std/cell/index.html"><code class="highlighter-rouge">RefCell</code></a>
for <a href="https://ricardomartins.cc/2016/06/08/interior-mutability">interior mutability</a>.</p>

<p>Thus, we will use an instance of <code class="highlighter-rouge">Rc&lt;RefCell&lt;Storage&gt;&gt;</code>. It may seem too
verbose, but using <code class="highlighter-rouge">Rc&lt;RefCell&lt;T&gt;&gt;</code> (or <code class="highlighter-rouge">Arc&lt;Mutex&lt;T&gt;&gt;</code> for thread-safety) is
very common in Rust. And <a href="https://www.reddit.com/r/rust/comments/33jv62/vecrcrefcellboxtrait_is_there_a_better_way/">there is worse</a>.</p>

<p>Here is the resulting client code:</p>

<figure class="highlight"><pre><code class="language-rust" data-lang="rust">    <span class="k">use</span> <span class="nn">std</span><span class="p">::</span><span class="nn">cell</span><span class="p">::</span><span class="n">RefCell</span><span class="p">;</span>
    <span class="k">use</span> <span class="nn">std</span><span class="p">::</span><span class="nn">rc</span><span class="p">::</span><span class="nb">Rc</span><span class="p">;</span>

    <span class="k">let</span> <span class="k">mut</span> <span class="n">notifier</span> <span class="o">=</span> <span class="nn">Notifier</span><span class="p">::</span><span class="nf">new</span><span class="p">();</span>

    <span class="c">// first Rc to the Storage</span>
    <span class="k">let</span> <span class="n">rc</span> <span class="o">=</span> <span class="nn">Rc</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="nn">RefCell</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="nn">Storage</span><span class="p">::</span><span class="nf">new</span><span class="p">()));</span>

    <span class="c">// second Rc to the Storage</span>
    <span class="k">let</span> <span class="n">rc2</span> <span class="o">=</span> <span class="n">rc</span><span class="nf">.clone</span><span class="p">();</span>

    <span class="c">// register the listener saving all the received events to the Storage</span>
    <span class="n">notifier</span><span class="nf">.register</span><span class="p">(</span><span class="k">move</span> <span class="p">|</span><span class="n">event</span><span class="p">|</span> <span class="n">rc2</span><span class="nf">.borrow_mut</span><span class="p">()</span><span class="nf">.store</span><span class="p">(</span><span class="n">event</span><span class="p">));</span>

    <span class="n">notifier</span><span class="nf">.notify</span><span class="p">(</span><span class="mi">3</span><span class="p">);</span>
    <span class="n">notifier</span><span class="nf">.notify</span><span class="p">(</span><span class="mi">141</span><span class="p">);</span>
    <span class="n">notifier</span><span class="nf">.notify</span><span class="p">(</span><span class="mi">59</span><span class="p">);</span>
    <span class="nd">assert_eq!</span><span class="p">(</span><span class="o">&amp;</span><span class="nd">vec!</span><span class="p">[</span><span class="mi">3</span><span class="p">,</span> <span class="mi">141</span><span class="p">,</span> <span class="mi">59</span><span class="p">],</span> <span class="n">rc</span><span class="nf">.borrow</span><span class="p">()</span><span class="nf">.events</span><span class="p">());</span></code></pre></figure>

<p>That way, the <code class="highlighter-rouge">Storage</code> is correctly mutated from the event listener.</p>

<p>All is not solved, though. In this example, we had access to the
<code class="highlighter-rouge">Rc&lt;RefCell&lt;Storage&gt;&gt;</code> instance. What if we only have access to the <code class="highlighter-rouge">Storage</code>,
e.g. if we want <code class="highlighter-rouge">Storage</code> to register itself from one of its methods, without
requiring the caller to provide the <code class="highlighter-rouge">Rc&lt;RefCell&lt;Storage&gt;&gt;</code> instance?</p>

<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="k">impl</span> <span class="n">Storage</span> <span class="p">{</span>
    <span class="k">pub</span> <span class="k">fn</span> <span class="nf">register_to</span><span class="p">(</span><span class="o">&amp;</span><span class="k">self</span><span class="p">,</span> <span class="n">notifier</span><span class="p">:</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="n">Notifier</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">notifier</span><span class="nf">.register</span><span class="p">(</span><span class="k">move</span> <span class="p">|</span><span class="n">event</span><span class="p">|</span> <span class="p">{</span>
            <span class="cm">/* how to retrieve a &amp;mut Storage from here? */</span>
        <span class="p">});</span>
    <span class="p">}</span>
<span class="p">}</span></code></pre></figure>

<p>We need to retrieve the <code class="highlighter-rouge">Rc&lt;RefCell&lt;Storage&gt;&gt;</code> from the <code class="highlighter-rouge">Storage</code> in some way.</p>

<p>To do so, the idea consists in making the <code class="highlighter-rouge">Storage</code> aware of its
reference-counting pointer. <em>Of course, this only makes sense if <code class="highlighter-rouge">Storage</code> is
constructed inside a <code class="highlighter-rouge">Rc&lt;RefCell&lt;Storage&gt;&gt;</code>.</em></p>

<p>This is exactly what <a href="http://en.cppreference.com/w/cpp/memory/enable_shared_from_this"><code class="highlighter-rouge">enable_shared_from_this</code></a> provides in C++, so we can draw
inspiration from <a href="https://stackoverflow.com/a/34062114/1987178">how it works</a>: just store a
<code class="highlighter-rouge">Weak&lt;RefCell&lt;…&gt;&gt;</code>, <a href="https://doc.rust-lang.org/std/rc/struct.Rc.html#method.downgrade">downgraded</a> from the <code class="highlighter-rouge">Rc&lt;RefCell&lt;…&gt;&gt;</code>, into the structure
itself. That way, we can use it to get a <code class="highlighter-rouge">&amp;mut Storage</code> reference back in the
event listener:</p>

<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="k">use</span> <span class="nn">std</span><span class="p">::</span><span class="nn">rc</span><span class="p">::{</span><span class="nb">Rc</span><span class="p">,</span> <span class="n">Weak</span><span class="p">};</span>
<span class="k">use</span> <span class="nn">std</span><span class="p">::</span><span class="nn">cell</span><span class="p">::</span><span class="n">RefCell</span><span class="p">;</span>

<span class="k">pub</span> <span class="k">struct</span> <span class="n">Storage</span> <span class="p">{</span>
    <span class="n">self_weak</span><span class="p">:</span> <span class="n">Weak</span><span class="o">&lt;</span><span class="n">RefCell</span><span class="o">&lt;</span><span class="n">Storage</span><span class="o">&gt;&gt;</span><span class="p">,</span>
    <span class="n">events</span><span class="p">:</span> <span class="nb">Vec</span><span class="o">&lt;</span><span class="nb">u32</span><span class="o">&gt;</span><span class="p">,</span>
<span class="p">}</span>

<span class="k">impl</span> <span class="n">Storage</span> <span class="p">{</span>
    <span class="k">pub</span> <span class="k">fn</span> <span class="nf">new</span><span class="p">()</span> <span class="k">-&gt;</span> <span class="nb">Rc</span><span class="o">&lt;</span><span class="n">RefCell</span><span class="o">&lt;</span><span class="n">Self</span><span class="o">&gt;&gt;</span> <span class="p">{</span>
        <span class="k">let</span> <span class="n">rc</span> <span class="o">=</span> <span class="nn">Rc</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="nn">RefCell</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="n">Self</span> <span class="p">{</span>
            <span class="n">self_weak</span><span class="p">:</span> <span class="nn">Weak</span><span class="p">::</span><span class="nf">new</span><span class="p">(),</span> <span class="c">// initialize empty</span>
            <span class="n">events</span><span class="p">:</span> <span class="nn">Vec</span><span class="p">::</span><span class="nf">new</span><span class="p">(),</span>
        <span class="p">}));</span>
        <span class="c">// set self_weak once we get the Rc instance</span>
        <span class="n">rc</span><span class="nf">.borrow_mut</span><span class="p">()</span><span class="py">.self_weak</span> <span class="o">=</span> <span class="nn">Rc</span><span class="p">::</span><span class="nf">downgrade</span><span class="p">(</span><span class="o">&amp;</span><span class="n">rc</span><span class="p">);</span>
        <span class="n">rc</span>
    <span class="p">}</span>

    <span class="k">pub</span> <span class="k">fn</span> <span class="nf">register_to</span><span class="p">(</span><span class="o">&amp;</span><span class="k">self</span><span class="p">,</span> <span class="n">notifier</span><span class="p">:</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="n">Notifier</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">let</span> <span class="n">rc</span> <span class="o">=</span> <span class="k">self</span><span class="py">.self_weak</span><span class="nf">.upgrade</span><span class="p">()</span><span class="nf">.unwrap</span><span class="p">();</span>
        <span class="n">notifier</span><span class="nf">.register</span><span class="p">(</span><span class="k">move</span> <span class="p">|</span><span class="n">event</span><span class="p">|</span> <span class="n">rc</span><span class="nf">.borrow_mut</span><span class="p">()</span><span class="nf">.store</span><span class="p">(</span><span class="n">event</span><span class="p">))</span>
    <span class="p">}</span>
<span class="p">}</span></code></pre></figure>

<p>Here is how to use it:</p>

<figure class="highlight"><pre><code class="language-rust" data-lang="rust">    <span class="k">let</span> <span class="k">mut</span> <span class="n">notifier</span> <span class="o">=</span> <span class="nn">Notifier</span><span class="p">::</span><span class="nf">new</span><span class="p">();</span>
    <span class="k">let</span> <span class="n">rc</span> <span class="o">=</span> <span class="nn">Storage</span><span class="p">::</span><span class="nf">new</span><span class="p">();</span>
    <span class="n">rc</span><span class="nf">.borrow</span><span class="p">()</span><span class="nf">.register_to</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="n">notifier</span><span class="p">);</span>
    <span class="n">notifier</span><span class="nf">.notify</span><span class="p">(</span><span class="mi">3</span><span class="p">);</span>
    <span class="n">notifier</span><span class="nf">.notify</span><span class="p">(</span><span class="mi">141</span><span class="p">);</span>
    <span class="n">notifier</span><span class="nf">.notify</span><span class="p">(</span><span class="mi">59</span><span class="p">);</span>
    <span class="nd">assert_eq!</span><span class="p">(</span><span class="o">&amp;</span><span class="nd">vec!</span><span class="p">[</span><span class="mi">3</span><span class="p">,</span> <span class="mi">141</span><span class="p">,</span> <span class="mi">59</span><span class="p">],</span> <span class="n">rc</span><span class="nf">.borrow</span><span class="p">()</span><span class="nf">.events</span><span class="p">());</span></code></pre></figure>

<p>So it is possible to implement the <em>observer</em> pattern in Rust, but this is a bit
more challenging than in Java ;-)</p>

<p>When possible, it might be preferable to avoid it.</p>

<h3 id="mutable-data-sharing">Mutable data sharing</h3>

<blockquote>
  <p>Mutable references cannot be <a href="https://doc.rust-lang.org/nomicon/references.html">aliased</a>.</p>
</blockquote>

<p>How to share mutable data, then?</p>

<p>We saw that we can use <code class="highlighter-rouge">Rc&lt;RefCell&lt;…&gt;&gt;</code> (or <code class="highlighter-rouge">Arc&lt;Mutex&lt;…&gt;&gt;</code>), that enforces the
borrowing rules at runtime. However, this is not always desirable:</p>
<ul>
  <li>it forces a new allocation on the heap,</li>
  <li>each access has a runtime cost,</li>
  <li>it always borrows the whole resource.</li>
</ul>

<p>Alternatively, we could use <a href="https://doc.rust-lang.org/book/first-edition/raw-pointers.html">raw pointers</a> manually inside <a href="https://doc.rust-lang.org/book/first-edition/unsafe.html">unsafe</a> code, but
then this would be <em>unsafe</em>.</p>

<p>And there is another way, which consists in exposing <strong>temporary borrowing
views</strong> of an object. Let me explain.</p>

<p>In <em>Gnirehtet</em>, a packet contains a reference to the raw data (stored in some
buffer elsewhere) along with the <a href="https://en.wikipedia.org/wiki/IPv4#Packet_structure">IP</a> and <a href="https://en.wikipedia.org/wiki/Transmission_Control_Protocol#TCP_segment_structure">TCP</a>/<a href="https://en.wikipedia.org/wiki/User_Datagram_Protocol#Packet_structure">UDP</a> header fields values
(parsed from the raw data). We could have used a flat structure to store
everything:</p>

<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="k">pub</span> <span class="k">struct</span> <span class="n">Packet</span><span class="o">&lt;</span><span class="err">'</span><span class="n">a</span><span class="o">&gt;</span> <span class="p">{</span>
    <span class="n">raw</span><span class="p">:</span> <span class="o">&amp;</span><span class="err">'</span><span class="n">a</span> <span class="k">mut</span> <span class="p">[</span><span class="nb">u8</span><span class="p">],</span>
    <span class="n">ipv4_source</span><span class="p">:</span> <span class="nb">u32</span><span class="p">,</span>
    <span class="n">ipv4_destination</span><span class="p">:</span> <span class="nb">u32</span><span class="p">,</span>
    <span class="n">ipv4_protocol</span><span class="p">:</span> <span class="nb">u8</span><span class="p">,</span>
    <span class="c">// + other ipv4 fields</span>
    <span class="n">transport_source</span><span class="p">:</span> <span class="nb">u16</span><span class="p">,</span>
    <span class="n">transport_destination</span><span class="p">:</span> <span class="nb">u16</span><span class="p">,</span>
    <span class="c">// + other transport fields</span>
<span class="p">}</span></code></pre></figure>

<p>The <code class="highlighter-rouge">Packet</code> would provide <em>setters</em> for all the header fields (updating both
the packet fields and the raw data). For example:</p>

<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="k">impl</span><span class="o">&lt;</span><span class="err">'</span><span class="n">a</span><span class="o">&gt;</span> <span class="n">Packet</span><span class="o">&lt;</span><span class="err">'</span><span class="n">a</span><span class="o">&gt;</span> <span class="p">{</span>
    <span class="k">pub</span> <span class="k">fn</span> <span class="nf">set_transport_source</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">,</span> <span class="n">transport_source</span><span class="p">:</span> <span class="nb">u16</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">self</span><span class="py">.transport_source</span> <span class="o">=</span> <span class="n">transport_source</span><span class="p">;</span>
        <span class="k">let</span> <span class="n">transport</span> <span class="o">=</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="py">.raw</span><span class="p">[</span><span class="mi">20</span><span class="err">..</span><span class="p">];</span>
        <span class="nn">BigEndian</span><span class="p">::</span><span class="nf">write_u16</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="n">transport</span><span class="p">[</span><span class="mi">0</span><span class="err">..</span><span class="mi">2</span><span class="p">],</span> <span class="n">port</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span></code></pre></figure>

<p>But this would be poor design (especially since TCP and UDP header fields
are different).</p>

<p>Instead, we would like to extract IP and transport headers to separate structs,
managing their own part of the raw data:</p>

<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="c">// violates the borrowing rules</span>

<span class="k">pub</span> <span class="k">struct</span> <span class="n">Packet</span><span class="o">&lt;</span><span class="err">'</span><span class="n">a</span><span class="o">&gt;</span> <span class="p">{</span>
    <span class="n">raw</span><span class="p">:</span> <span class="o">&amp;</span><span class="err">'</span><span class="n">a</span> <span class="k">mut</span> <span class="p">[</span><span class="nb">u8</span><span class="p">],</span> <span class="c">// the whole packet (including headers)</span>
    <span class="n">ipv4_header</span><span class="p">:</span> <span class="n">Ipv4Header</span><span class="o">&lt;</span><span class="err">'</span><span class="n">a</span><span class="o">&gt;</span><span class="p">,</span>
    <span class="n">transport_header</span><span class="p">:</span> <span class="n">TransportHeader</span><span class="o">&lt;</span><span class="err">'</span><span class="n">a</span><span class="o">&gt;</span><span class="p">,</span>
<span class="p">}</span>

<span class="k">pub</span> <span class="k">struct</span> <span class="n">Ipv4Header</span><span class="o">&lt;</span><span class="err">'</span><span class="n">a</span><span class="o">&gt;</span> <span class="p">{</span>
    <span class="n">raw</span><span class="p">:</span> <span class="o">&amp;</span><span class="err">'</span><span class="n">a</span> <span class="k">mut</span> <span class="p">[</span><span class="nb">u8</span><span class="p">],</span> <span class="c">// slice related to ipv4 headers</span>
    <span class="n">source</span><span class="p">:</span> <span class="nb">u32</span><span class="p">,</span>
    <span class="n">destination</span><span class="p">:</span> <span class="nb">u32</span><span class="p">,</span>
    <span class="n">protocol</span><span class="p">:</span> <span class="nb">u8</span><span class="p">,</span>
    <span class="c">// + other ipv4 fields</span>
<span class="p">}</span>

<span class="k">pub</span> <span class="k">struct</span> <span class="n">TransportHeader</span><span class="o">&lt;</span><span class="err">'</span><span class="n">a</span><span class="o">&gt;</span> <span class="p">{</span>
    <span class="n">raw</span><span class="p">:</span> <span class="o">&amp;</span><span class="err">'</span><span class="n">a</span> <span class="k">mut</span> <span class="p">[</span><span class="nb">u8</span><span class="p">],</span> <span class="c">// slice related to transport headers</span>
    <span class="n">source</span><span class="p">:</span> <span class="nb">u16</span><span class="p">,</span>
    <span class="n">destination</span><span class="p">:</span> <span class="nb">u16</span><span class="p">,</span>
    <span class="c">// + other transport fields</span>
<span class="p">}</span></code></pre></figure>

<p>You immediately spotted the problem: <strong>there are several references to the
same resource, the <code class="highlighter-rouge">raw</code> byte array, at the same time</strong>.</p>

<p><em>Note that <a href="https://doc.rust-lang.org/std/primitive.slice.html#method.split_at_mut">splitting</a> the array is not a possibility here, since the <code class="highlighter-rouge">raw</code>
slices overlap: we need to write the whole packet at once to the network, so the
<code class="highlighter-rouge">raw</code> array in <code class="highlighter-rouge">Packet</code> must include the headers.</em></p>

<p>We need a solution compatible with the borrowing rules.</p>

<p>Here is the one I came up with:</p>

<ul>
  <li>store the header data separately, without the <code class="highlighter-rouge">raw</code> slices,</li>
  <li>create <em>view</em> structs for IP and transport headers, with <a href="https://doc.rust-lang.org/book/first-edition/lifetimes.html#in-structs">lifetime bounds</a>,</li>
  <li>expose <code class="highlighter-rouge">Packet</code> methods returning <em>view</em> instances.</li>
</ul>

<p>And here is a simplification of the actual implementation:</p>

<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="k">pub</span> <span class="k">struct</span> <span class="n">Packet</span><span class="o">&lt;</span><span class="err">'</span><span class="n">a</span><span class="o">&gt;</span> <span class="p">{</span>
    <span class="n">raw</span><span class="p">:</span> <span class="o">&amp;</span><span class="err">'</span><span class="n">a</span> <span class="k">mut</span> <span class="p">[</span><span class="nb">u8</span><span class="p">],</span>
    <span class="n">ipv4_header</span><span class="p">:</span> <span class="n">Ipv4HeaderData</span><span class="p">,</span>
    <span class="n">transport_header</span><span class="p">:</span> <span class="n">TransportHeaderData</span><span class="p">,</span>
<span class="p">}</span>

<span class="k">pub</span> <span class="k">struct</span> <span class="n">Ipv4HeaderData</span> <span class="p">{</span>
    <span class="n">source</span><span class="p">:</span> <span class="nb">u32</span><span class="p">,</span>
    <span class="n">destination</span><span class="p">:</span> <span class="nb">u32</span><span class="p">,</span>
    <span class="n">protocol</span><span class="p">:</span> <span class="nb">u8</span><span class="p">,</span>
    <span class="c">// + other ipv4 fields</span>
<span class="p">}</span>

<span class="k">pub</span> <span class="k">struct</span> <span class="n">TransportHeaderData</span> <span class="p">{</span>
    <span class="n">source</span><span class="p">:</span> <span class="nb">u16</span><span class="p">,</span>
    <span class="n">destination</span><span class="p">:</span> <span class="nb">u16</span><span class="p">,</span>
    <span class="c">// + other transport fields</span>
<span class="p">}</span>

<span class="k">pub</span> <span class="k">struct</span> <span class="n">Ipv4Header</span><span class="o">&lt;</span><span class="err">'</span><span class="n">a</span><span class="o">&gt;</span> <span class="p">{</span>
    <span class="n">raw</span><span class="p">:</span> <span class="o">&amp;</span><span class="err">'</span><span class="n">a</span> <span class="k">mut</span> <span class="p">[</span><span class="nb">u8</span><span class="p">],</span>
    <span class="n">data</span><span class="p">:</span> <span class="o">&amp;</span><span class="err">'</span><span class="n">a</span> <span class="k">mut</span> <span class="n">Ipv4HeaderData</span><span class="p">,</span>
<span class="p">}</span>

<span class="k">pub</span> <span class="k">struct</span> <span class="n">TransportHeader</span><span class="o">&lt;</span><span class="err">'</span><span class="n">a</span><span class="o">&gt;</span> <span class="p">{</span>
    <span class="n">raw</span><span class="p">:</span> <span class="o">&amp;</span><span class="err">'</span><span class="n">a</span> <span class="k">mut</span> <span class="p">[</span><span class="nb">u8</span><span class="p">],</span>
    <span class="n">data</span><span class="p">:</span> <span class="o">&amp;</span><span class="err">'</span><span class="n">a</span> <span class="k">mut</span> <span class="n">TransportHeaderData</span><span class="p">,</span>
<span class="p">}</span>

<span class="k">impl</span><span class="o">&lt;</span><span class="err">'</span><span class="n">a</span><span class="o">&gt;</span> <span class="n">Packet</span><span class="o">&lt;</span><span class="err">'</span><span class="n">a</span><span class="o">&gt;</span> <span class="p">{</span>
    <span class="k">pub</span> <span class="k">fn</span> <span class="nf">ipv4_header</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="n">Ipv4Header</span> <span class="p">{</span>
        <span class="n">Ipv4Header</span> <span class="p">{</span>
            <span class="n">raw</span><span class="p">:</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="py">.raw</span><span class="p">[</span><span class="err">..</span><span class="mi">20</span><span class="p">],</span>
            <span class="n">data</span><span class="p">:</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="py">.ipv4_header</span><span class="p">,</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="k">pub</span> <span class="k">fn</span> <span class="nf">transport_header</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="n">TransportHeader</span> <span class="p">{</span>
        <span class="n">TransportHeader</span> <span class="p">{</span>
            <span class="n">raw</span><span class="p">:</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="py">.raw</span><span class="p">[</span><span class="mi">20</span><span class="err">..</span><span class="mi">40</span><span class="p">],</span>
            <span class="n">data</span><span class="p">:</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="py">.transport_header</span><span class="p">,</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span></code></pre></figure>

<p>The <em>setters</em> are implemented on the views, where they hold a mutable reference
to the raw array:</p>

<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="k">impl</span><span class="o">&lt;</span><span class="err">'</span><span class="n">a</span><span class="o">&gt;</span> <span class="n">TransportHeader</span><span class="o">&lt;</span><span class="err">'</span><span class="n">a</span><span class="o">&gt;</span> <span class="p">{</span>
    <span class="k">pub</span> <span class="k">fn</span> <span class="nf">set_source</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">,</span> <span class="n">source</span><span class="p">:</span> <span class="nb">u16</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">self</span><span class="py">.data.source</span> <span class="o">=</span> <span class="n">source</span><span class="p">;</span>
        <span class="nn">BigEndian</span><span class="p">::</span><span class="nf">write_u16</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="n">raw</span><span class="p">[</span><span class="mi">0</span><span class="err">..</span><span class="mi">2</span><span class="p">],</span> <span class="n">source</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="k">pub</span> <span class="k">fn</span> <span class="nf">set_destination</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">,</span> <span class="n">destination</span><span class="p">:</span> <span class="nb">u16</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">self</span><span class="py">.data.destination</span> <span class="o">=</span> <span class="n">destination</span><span class="p">;</span>
        <span class="nn">BigEndian</span><span class="p">::</span><span class="nf">write_u16</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="n">raw</span><span class="p">[</span><span class="mi">2</span><span class="err">..</span><span class="mi">4</span><span class="p">],</span> <span class="n">destination</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span></code></pre></figure>

<p>That way, the borrowing rules are respected, and the API is elegant:</p>

<figure class="highlight"><pre><code class="language-rust" data-lang="rust">    <span class="k">let</span> <span class="k">mut</span> <span class="n">packet</span> <span class="o">=</span> <span class="err">…</span><span class="p">;</span>
    <span class="c">// "transport_header" borrows "packet" during its scope</span>
    <span class="k">let</span> <span class="k">mut</span> <span class="n">transport_header</span> <span class="o">=</span> <span class="n">packet</span><span class="nf">.transport_header</span><span class="p">();</span>
    <span class="n">transport_header</span><span class="nf">.set_source</span><span class="p">(</span><span class="mi">1234</span><span class="p">);</span>
    <span class="n">transport_header</span><span class="nf">.set_destination</span><span class="p">(</span><span class="mi">1234</span><span class="p">);</span></code></pre></figure>

<h3 id="compiler-limitations">Compiler limitations</h3>

<p>Rust is a young language, and the compiler has some annoying pitfalls.</p>

<p>The worst, in my opinion, is related to <a href="http://smallcultfollowing.com/babysteps/blog/2016/04/27/non-lexical-lifetimes-introduction/#problem-case-2-conditional-control-flow">non-lexical lifetimes</a>, which leads to
<a href="https://stackoverflow.com/questions/44417491/non-lexical-lifetime-workaround-failure">unexpected errors</a>:</p>

<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="k">struct</span> <span class="n">Container</span> <span class="p">{</span>
    <span class="n">vec</span><span class="p">:</span> <span class="nb">Vec</span><span class="o">&lt;</span><span class="nb">i32</span><span class="o">&gt;</span><span class="p">,</span>
<span class="p">}</span>

<span class="k">impl</span> <span class="n">Container</span> <span class="p">{</span>
    <span class="k">fn</span> <span class="nf">find</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">,</span> <span class="n">v</span><span class="p">:</span> <span class="nb">i32</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="nb">Option</span><span class="o">&lt;&amp;</span><span class="k">mut</span> <span class="nb">i32</span><span class="o">&gt;</span> <span class="p">{</span>
        <span class="nb">None</span> <span class="c">// we don't care the implementation</span>
    <span class="p">}</span>

    <span class="k">fn</span> <span class="nf">get</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">,</span> <span class="n">v</span><span class="p">:</span> <span class="nb">i32</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="nb">i32</span> <span class="p">{</span>
        <span class="k">if</span> <span class="k">let</span> <span class="nf">Some</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="o">=</span> <span class="k">self</span><span class="nf">.find</span><span class="p">(</span><span class="n">v</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">return</span> <span class="n">x</span><span class="p">;</span>
        <span class="p">}</span>
        <span class="k">self</span><span class="py">.vec</span><span class="nf">.push</span><span class="p">(</span><span class="n">v</span><span class="p">);</span>
        <span class="k">self</span><span class="py">.vec</span><span class="nf">.last_mut</span><span class="p">()</span><span class="nf">.unwrap</span><span class="p">()</span>
    <span class="p">}</span>
<span class="p">}</span></code></pre></figure>

<div class="highlighter-rouge"><pre class="codehilite"><code>error[E0499]: cannot borrow `self.vec` as mutable more than once at a time
  --&gt; sample.rs:14:9
   |
11 |         if let Some(x) = self.find(v) {
   |                          ---- first mutable borrow occurs here
...
14 |         self.vec.push(v);
   |         ^^^^^^^^ second mutable borrow occurs here
15 |         self.vec.last_mut().unwrap()
16 |     }
   |     - first borrow ends here
</code></pre></div>

<p>Hopefully, <a href="http://smallcultfollowing.com/babysteps/blog/2017/07/11/non-lexical-lifetimes-draft-rfc-and-prototype-available/">it should be fixed soon</a>.</p>

<p>The <a href="https://github.com/rust-lang/rfcs/blob/master/text/1522-conservative-impl-trait.md"><em>Impl Trait</em></a> feature, allowing to return <em>unboxed</em> abstract
types from functions, should also improve the experience (there is also an
<a href="https://github.com/rust-lang/rfcs/blob/master/text/1951-expand-impl-trait.md">expanded</a> proposal).</p>

<p>The compiler generally produces very helpful error messages. But when it does
not, they can be very <a href="https://stackoverflow.com/questions/44003622/implementing-trait-for-fnsomething-in-rust">confusing</a>.</p>

<h2 id="safety-pitfalls">Safety pitfalls</h2>

<p>The <a href="https://doc.rust-lang.org/nomicon/meet-safe-and-unsafe.html">first chapter of the <em>Rustonomicon</em></a> says:</p>

<blockquote>
  <p>Safe Rust is For Reals Totally Safe.</p>

  <p>[…]</p>

  <p>Safe Rust is the true Rust programming language. If all you do is write Safe
Rust, you will never have to worry about type-safety or memory-safety. You
will never endure a null or dangling pointer, or any of that Undefined
Behavior nonsense.</p>
</blockquote>

<p>That’s the goal. And that’s <em>almost</em> true.</p>

<h3 id="leakpocalypse">Leakpocalypse</h3>

<p>In the past, it was <a href="https://github.com/rust-lang/rust/issues/24292">possible</a> to write <em>safe-Rust</em> code <strong>accessing
freed memory</strong>.</p>

<p>This “<a href="http://cglab.ca/~abeinges/blah/everyone-poops/">leakpocalypse</a>” led to a <a href="https://github.com/alexcrichton/rfcs/blob/safe-mem-forget/text/0000-safe-mem-forget.md">clarification</a> of the safety
guarantees: not running a destructor is now <a href="https://github.com/rust-lang/rfcs/pull/1066">considered <em>safe</em></a>. In
other words, <strong>memory-safety may not rely on <a href="https://en.wikipedia.org/wiki/Resource_acquisition_is_initialization">RAII</a></strong> anymore (in fact, it never
could, but it has been noticed only belatedly).</p>

<p>As a consequence, <a href="https://doc.rust-lang.org/std/mem/fn.forget.html"><code class="highlighter-rouge">std::mem::forget</code></a> is now <em>safe</em>, and <a href="https://doc.rust-lang.org/1.0.0/std/thread/struct.JoinGuard.html"><code class="highlighter-rouge">JoinGuard</code></a> has been
deprecated and removed from the standard library (it has been moved to a
<a href="http://arcnmx.github.io/thread-scoped-rs/thread_scoped/">separate crate</a>).</p>

<p>Other tools relying on RAII (like <a href="https://doc.rust-lang.org/std/vec/struct.Vec.html#method.drain"><code class="highlighter-rouge">Vec::drain()</code></a>) must <a href="https://github.com/rust-lang/rust/blob/1.20.0/src/liballoc/vec.rs#L1094-L1102">take special care</a> to
prevent memory corruption.</p>

<p>Whew, <em>memory-safety</em> is (now) safe.</p>

<h3 id="undefined-infinity">Undefined infinity</h3>

<p>In C and C++, <a href="https://stackoverflow.com/questions/3592557/optimizing-away-a-while1-in-c0x">infinite loops</a> without side-effects are <a href="http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1528.htm">undefined
behavior</a>. This makes it possible to write programs that unexpectedly
<a href="https://blog.regehr.org/archives/140">disprove Fermat’s Last Theorem</a>.</p>

<p>In practice, the Rust compiler relies on LLVM, which (currently) applies its
optimizations assuming that infinite loops without side-effects are <em>undefined
behavior</em>. As a consequence, such <em>undefined behaviors</em> also occur in Rust.</p>

<p>Here is a minimal sample to trigger it:</p>

<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="k">fn</span> <span class="nf">infinite</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">loop</span> <span class="p">{}</span>
<span class="p">}</span>

<span class="k">fn</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="nf">infinite</span><span class="p">();</span>
<span class="p">}</span></code></pre></figure>

<p>Running without optimizations, it behaves as “expected”:</p>

<div class="highlighter-rouge"><pre class="codehilite"><code>$ rustc ub.rs &amp;&amp; ./ub
^C                    (infinite loop, interrupt it)
</code></pre></div>

<p>Enabling optimizations makes the program panic:</p>

<div class="highlighter-rouge"><pre class="codehilite"><code>$ rustc -O ub.rs &amp;&amp; ./ub
thread 'main' panicked at 'assertion failed: c.borrow().is_none()', /checkout/src/libstd/sys_common/thread_info.rs:51
note: Run with `RUST_BACKTRACE=1` for a backtrace.
</code></pre></div>

<p>Alternatively, we can produce unexpected results without crashing:</p>

<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="k">fn</span> <span class="nf">infinite</span><span class="p">(</span><span class="k">mut</span> <span class="n">value</span><span class="p">:</span> <span class="nb">u32</span><span class="p">)</span> <span class="p">{</span>
    <span class="c">// infinite loop unless value initially equals 0</span>
    <span class="k">while</span> <span class="n">value</span> <span class="o">!=</span> <span class="mi">0</span> <span class="p">{</span>
        <span class="k">if</span> <span class="n">value</span> <span class="o">!=</span> <span class="mi">1</span> <span class="p">{</span>
            <span class="n">value</span> <span class="o">-=</span> <span class="mi">1</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="k">fn</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="nf">infinite</span><span class="p">(</span><span class="mi">42</span><span class="p">);</span>
    <span class="nd">println!</span><span class="p">(</span><span class="s">"end"</span><span class="p">);</span>
<span class="p">}</span></code></pre></figure>

<div class="highlighter-rouge"><pre class="codehilite"><code>$ rustc ub.rs &amp;&amp; ./ub
^C                    (infinite loop, interrupt it)
</code></pre></div>

<p>But with optimizations:</p>

<div class="highlighter-rouge"><pre class="codehilite"><code>$ rustc -O ub.rs &amp;&amp; ./ub
end
</code></pre></div>

<p>This is a corner case, that will probably be solved in the future. In practice,
<strong>Rust safety guarantees are pretty strong</strong> (at a cost of being constraining).</p>

<h3 id="segfault">Segfault</h3>

<p><em>This section has been added after the publication.</em></p>

<p>There are other sources of <em>undefined behaviors</em> (look at the <a href="https://github.com/rust-lang/rust/labels/I-unsound">issues tagged
<em>I-unsound</em></a>).</p>

<p>For instance, casting a <em>float</em> value that cannot fit into the target type is
<em>undefined behavior</em>, which can be <a href="https://github.com/rust-lang/rust/issues/10184#issuecomment-139858153">propagated</a> to trigger a segfault:</p>

<figure class="highlight"><pre><code class="language-rust" data-lang="rust"><span class="err">#</span><span class="p">[</span><span class="nf">inline</span><span class="p">(</span><span class="n">never</span><span class="p">)]</span>
<span class="k">pub</span> <span class="k">fn</span> <span class="nf">f</span><span class="p">(</span><span class="n">ary</span><span class="p">:</span> <span class="o">&amp;</span><span class="p">[</span><span class="nb">u8</span><span class="p">;</span> <span class="mi">5</span><span class="p">])</span> <span class="k">-&gt;</span> <span class="o">&amp;</span><span class="p">[</span><span class="nb">u8</span><span class="p">]</span> <span class="p">{</span>
    <span class="k">let</span> <span class="n">idx</span> <span class="o">=</span> <span class="mf">1e100f64</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">;</span>
    <span class="o">&amp;</span><span class="n">ary</span><span class="p">[</span><span class="n">idx</span><span class="err">..</span><span class="p">]</span>
<span class="p">}</span>

<span class="k">fn</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="nd">println!</span><span class="p">(</span><span class="s">"{}"</span><span class="p">,</span> <span class="nf">f</span><span class="p">(</span><span class="o">&amp;</span><span class="p">[</span><span class="mi">1</span><span class="p">;</span> <span class="mi">5</span><span class="p">])[</span><span class="mi">0xdeadbeef</span><span class="p">]);</span>
<span class="p">}</span></code></pre></figure>

<div class="highlighter-rouge"><pre class="codehilite"><code>rustc -O ub.rs &amp;&amp; ./ub
Segmentation fault
</code></pre></div>

<h2 id="stats">Stats</h2>

<p>That’s all for my feedbacks about the language itself.</p>

<p>As an appendix, let’s compare the current <em>Java</em> and <em>Rust</em> versions of the
relay server.</p>

<h3 id="number-of-lines">Number of lines</h3>

<div class="highlighter-rouge"><pre class="codehilite"><code>$ cloc relay-{java,rust}/src
-------------------------------------------------------------------------------
Language                     files          blank        comment           code
-------------------------------------------------------------------------------
Rust                            29            687            655           4506
Java                            37            726            701           2931
-------------------------------------------------------------------------------
</code></pre></div>

<p><em>(tests included)</em></p>

<p>The Rust project is significantly bigger, for several reasons:</p>
<ul>
  <li>there are many <a href="#mutable-data-sharing"><em>borrowing views</em></a> classes;</li>
  <li>the Rust version contains its own <em>selector</em> class, wrapping the lower-level
<a href="https://docs.rs/mio/0.6.10/mio/struct.Poll.html"><code class="highlighter-rouge">Poll</code></a>, while the Java version uses the standard
<a href="https://docs.oracle.com/javase/8/docs/api/java/nio/channels/Selector.html"><code class="highlighter-rouge">Selector</code></a>;</li>
  <li>the <a href="https://doc.rust-lang.org/book/first-edition/error-handling.html">error handling</a> for command-line parsing is more verbose.</li>
</ul>

<p>The Java version has more files because the unit tests are separate, while in
Rust they are in the same file as the classes they test.</p>

<p>Just for information, here are the results for the Android client:</p>

<div class="highlighter-rouge"><pre class="codehilite"><code>$ cloc app/src
-------------------------------------------------------------------------------
Language                     files          blank        comment           code
-------------------------------------------------------------------------------
Java                            15            198            321            875
XML                              6              7              2             76
-------------------------------------------------------------------------------
SUM:                            21            205            323            951
-------------------------------------------------------------------------------
</code></pre></div>

<h3 id="binary-size">Binary size</h3>

<div class="highlighter-rouge"><pre class="codehilite"><code>--------------------------------------------
Java     gnirehtet.jar                   61K
--------------------------------------------
Rust     gnirehtet                      3.0M
         after "strip -g gnirehtet"     747K
         after "strip gnirehtet"        588K
--------------------------------------------
</code></pre></div>

<p>The Java binary itself is far smaller. The comparison is not fair though, since
it requires the <em>Java Runtime Environment</em>:</p>

<div class="highlighter-rouge"><pre class="codehilite"><code>$ du -sh /usr/lib/jvm/java-1.8.0-openjdk-amd64/
156M	/usr/lib/jvm/java-1.8.0-openjdk-amd64/
</code></pre></div>

<h3 id="memory-usage">Memory usage</h3>

<p>With a single TCP connection opened, here is the memory consumption for the Java
relay server:</p>

<div class="highlighter-rouge"><pre class="codehilite"><code>$ sudo pmap -x $RELAY_JAVA_PID
                  Kbytes     RSS   Dirty
total kB         4364052   86148   69316
</code></pre></div>

<p><em>(output filtered)</em></p>

<p>And for the Rust relay server:</p>

<div class="highlighter-rouge"><pre class="codehilite"><code>$ sudo pmap -x $RELAY_RUST_PID
                  Kbytes     RSS   Dirty
total kB           19272    2736     640
</code></pre></div>

<p><em>Look at the <a href="https://en.wikipedia.org/wiki/Resident_set_size">RSS</a> value, which indicates the actual memory used.</em></p>

<p>As expected, the Java version consumes more memory (86Mb) than the Rust one
(less than 3Mb). Moreover, its value is unstable due to the allocation of tiny
objects and their <a href="https://en.wikipedia.org/wiki/Garbage_collection_(computer_science)">garbage collection</a>, which also generates more dirty pages.
On the contrary, the Rust value is very stable: once the connection is created,
there are no memory allocations <em>at all</em>.</p>

<h3 id="cpu-usage">CPU usage</h3>

<p>To compare CPU usage, here is my scenario: a 500Mb file is hosted by Apache on
my laptop, I start the relay server through <code class="highlighter-rouge">perf stat</code>, then I download the
file from Firefox on Android. As soon as the file is downloaded, I stop the
relay server (Ctrl+C).</p>

<p>Here are the results for the Java version:</p>

<div class="highlighter-rouge"><pre class="codehilite"><code>$ perf stat -B java -jar gnirehtet.jar relay
 Performance counter stats for 'java -jar gnirehtet.jar relay':

      11805,458302      task-clock:u (msec)       #    0,088 CPUs utilized
                 0      context-switches:u        #    0,000 K/sec
                 0      cpu-migrations:u          #    0,000 K/sec
            28 618      page-faults:u             #    0,002 M/sec
    17 908 360 446      cycles:u                  #    1,517 GHz
    13 944 172 792      stalled-cycles-frontend:u #   77,86% frontend cycles idle
    18 437 279 663      instructions:u            #    1,03  insn per cycle
                                                  #    0,76  stalled cycles per insn
     3 088 215 431      branches:u                #  261,592 M/sec
        70 647 760      branch-misses:u           #    2,29% of all branches

     133,975117164 seconds time elapsed
</code></pre></div>

<p>And for the Rust version:</p>

<div class="highlighter-rouge"><pre class="codehilite"><code>$ perf stat -B ./gnirehtet relay
 Performance counter stats for 'target/release/gnirehtet relay':

       2707,479968      task-clock:u (msec)       #    0,020 CPUs utilized
                 0      context-switches:u        #    0,000 K/sec
                 0      cpu-migrations:u          #    0,000 K/sec
             1 001      page-faults:u             #    0,370 K/sec
     1 011 527 340      cycles:u                  #    0,374 GHz
     2 033 810 378      stalled-cycles-frontend:u #  201,06% frontend cycles idle
       981 103 003      instructions:u            #    0,97  insn per cycle
                                                  #    2,07  stalled cycles per insn
        98 929 222      branches:u                #   36,539 M/sec
         3 220 527      branch-misses:u           #    3,26% of all branches

     133,766035253 seconds time elapsed
</code></pre></div>

<p>I am not an expert in analyzing the results, but as far as I understand from
the <code class="highlighter-rouge">task-clock:u</code> value, the Rust version consumes 4× less CPU-time.</p>

<h2 id="conclusion">Conclusion</h2>

<p>Rewriting <em>Gnirehtet</em> in Rust was an amazing experience, where I learnt a great
language and new programming concepts. And now, we get a native application
showing better performances.</p>

<p>Happy reverse tethering!</p>

<p><em>Discuss on <a href="https://www.reddit.com/r/rust/comments/71ks57/gnirehtet_a_reverse_tethering_tool_for_android/">reddit</a> and <a href="https://news.ycombinator.com/item?id=15326106">Hacker News</a>.</em></p>


