<?xml version='1.0' encoding='utf-8'?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>Marien Fressinaud</title><link href="https://marienfressinaud.fr/feeds/all.atom.xml" rel="self" type="application/atom+xml" /><link href="https://marienfressinaud.fr/" rel="alternate" type="text/html" /><id>urn:uuid:9d7dea6b-d1f1-5b53-8b10-768b90e3ed88</id><updated>2026-02-07T14:30:00+01:00</updated><link href="https://websub.flus.io/" rel="hub" /><entry><title>Mes jeux 2025</title><id>urn:uuid:573b244e-4aba-5669-bb53-eb5f7ac8150c</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/mes-jeux-2025.html" rel="alternate" type="text/html" /><published>2026-02-07T14:30:00+01:00</published><updated>2026-02-07T14:30:00+01:00</updated><content type="html">&lt;p&gt;Comme pour &lt;a href="mes-jeux-2023.html"&gt;2023&lt;/a&gt; et &lt;a href="mes-jeux-2024.html"&gt;2024&lt;/a&gt;, voici la rétrospective des jeux auxquels j’ai joué en 2025.&lt;/p&gt;
&lt;p&gt;Contrairement aux années précédentes, j’ai joué principalement sur PC, au lieu de la Switch les autres années.
J’ai également bénéficié de l’accès à quelques jeux supplémentaires par le biais de la bibliothèque Steam partagée avec ma copine.&lt;/p&gt;
&lt;p&gt;Chaque début d’année, je me fais une liste des jeux auxquels je veux jouer pour éviter d’être trop tenté par les sorties du moment et des achats « coup de tête ».
La conséquence de la bibliothèque partagée a tout de même été que j’ai joué à sensiblement plus de jeux que les années précédentes.
Aucun regret pour autant !&lt;/p&gt;
&lt;p&gt;Dans cet article, je ne liste pas nécessairement la totalité des jeux auxquels j’ai joué.
J’ai par exemple pas mal joué à No Man’s Sky, comme en 2024, mais je n’ai pas considéré que cette poursuite méritait de le mentionner à nouveau ici.&lt;/p&gt;
&lt;p&gt;Je précise aussi que, cette année, j’ai tenté d’ordonner les jeux du moins apprécié au plus apprécié (et non par ordre chronologique de jeu).&lt;/p&gt;
&lt;h2&gt;Crisis Core - Final Fantasy VII - Reunion&lt;/h2&gt;
&lt;p&gt;Final Fantasy VII (1997) est un jeu à part dans mon expérience de joueur puisqu’il s’agit de l’une de mes premières et plus marquantes claques vidéoludiques.
Le jeu n’est clairement pas exempt de défauts et accuse aujourd’hui son âge… mais ça reste un doudou pour moi.&lt;/p&gt;
&lt;p&gt;Crisis Core est une préquelle à FF7, sortie en 2008.
Je me méfie toujours des suites, préquelles et autres remakes.
En l’occurrence, je suis ressorti de ce jeu très mitigé.&lt;/p&gt;
&lt;p&gt;J’ai adoré découvrir l’histoire de ce qui s’est passé 5 ans avant (et qui explique) le jeu initial.
Mais j’ai aussi été extrêmement déçu par la narration, son rythme avec les phases de gameplay, le peu de liberté accordée au joueur.
Quant au gameplay de combat qui était la chose que je craignais le plus (passage du tour par tour au temps réel), je n’ai pas été aussi gêné que ce que j’imaginais, mais je n’ai pas totalement accroché non plus.
J’ai fini le jeu en spammant toujours la même chose ; il n’y avait plus tellement d’enjeux et je n’avais plus qu’une chose en tête : finir le jeu pour passer à la suite.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://store.steampowered.com/app/1608070/CRISIS_CORE_FINAL_FANTASY_VII_REUNION/"&gt;Page Steam de Crisis Core&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Return to Monkey Island&lt;/h2&gt;
&lt;p&gt;Return to Monkey Island est un jeu point'n click, et le dernier épisode de la série culte des Monkey Island.
J’en avais toujours entendu beaucoup de bien, et même si je ne suis pas hyper fan des point'n click, il m’arrive de jouer à certains avec plaisir.
J’ai donc abordé le jeu dans un état d’esprit plutôt positif.&lt;/p&gt;
&lt;p&gt;J’ai cependant été rapidement rattrapé par ce que je n’aime pas dans ce genre de jeux : combiner à l’aveugle tous les objets de son inventaire pour espérer trouver la combinaison qui fera avancer.
Pour être honnête, je n’y ai été vraiment confronté qu’au début du jeu, mais cela m’a suffi à laisser le jeu de côté pendant quelques semaines.
Lorsque je l’ai relancé ensuite, je n’avais plus autant envie d’y jouer et la verbosité du jeu a fini par me rebuter.
J’ai terminé le jeu de la même manière que Crisis Core : juste suffisamment l’envie de connaitre la fin, mais sans plus.&lt;/p&gt;
&lt;p&gt;Mais à l’inverse du précédent, j’ai mieux perçu les qualités intrinsèques du jeu ; disons que je ne suis pas le public !&lt;/p&gt;
&lt;p&gt;&lt;a href="https://returntomonkeyisland.com/"&gt;Site de Return to Monkey Island&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Minishoot' Adventures&lt;/h2&gt;
&lt;p&gt;Minishoot' Adventures est un jeu d’aventure / twin stick shooter.
Je n’avais jamais vraiment joué à ce type de jeu, mais après avoir regardé quelqu’un jouer dessus, j’ai été très tenté par celui-ci.&lt;/p&gt;
&lt;p&gt;Grand bien m’en a pris : entre précision du gameplay, montée en puissance bien maitrisée, direction artistique sans prétention mais agréable, et boss bien équilibrés ; je trouve que c’est un sans-faute.&lt;/p&gt;
&lt;p&gt;De plus, le jeu se termine en une dizaine d’heures, ce qui est souvent un bon argument pour les personnes qui ne veulent pas s’investir corps et âme dans un jeu.
Parfait pour découvrir (et apprécier) le genre.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://store.steampowered.com/app/1634860/Minishoot_Adventures/"&gt;Page Steam de Minishoot' Adventures&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Blue Prince&lt;/h2&gt;
&lt;p&gt;J’aime les jeux d’énigmes, et ça tombe bien.&lt;/p&gt;
&lt;p&gt;Dans Blue Prince, l’objectif est d’atteindre la 46&lt;sup&gt;e&lt;/sup&gt; salle d’un manoir.
Or, les salles ne sont pas fixes : c’est à nous, chaque jour, d’agencer les salles une à une, en espérant trouver un agencement qui nous fera atteindre la fameuse salle 46.
Pour avancer, il faudra résoudre tout un tas d’énigmes plus ou moins compliquées.
En chemin, on découvre peu à peu les secrets et l’histoire du manoir et de ses habitant·es.&lt;/p&gt;
&lt;p&gt;La mécanique du jeu est originale, et le hasard qui sous-tend le jeu en fait à la fois son point fort et son point faible.
Il apporte de grands moments d’excitation quand on a enfin la salle ou l’enchainement d’évènements dont on rêve depuis plusieurs tentatives.
Mais il peut aussi être source de nombreuses frustrations quand on se retrouve bloqué à deux doigts de résoudre un mystère.&lt;/p&gt;
&lt;p&gt;Malgré ce défaut, j’ai trouvé l’ambiance du jeu très réussie.
Il faut accrocher aux graphismes — ça a été mon cas — et la musique se fait aussi rare qu’appréciable quand elle pointe le bout de son nez.&lt;/p&gt;
&lt;p&gt;Blue Prince est &lt;strong&gt;extrêmement&lt;/strong&gt; riche : une fois l’objectif atteint, on se rend compte qu’il reste encore d’innombrables choses à découvrir et explorer.
Je n’ai toutefois pas eu le courage de tirer beaucoup plus loin, un peu fatigué par la trop grande part laissée à la chance et un peu intimidé par la difficulté apparente de certaines énigmes.
Mais pour les personnes que ça ne rebuterait pas, le jeu est très généreux dans son « &lt;em lang="en"&gt;end game&lt;/em&gt; ».
Il n’est pas impossible que je le relance à l’occasion.&lt;/p&gt;
&lt;p&gt;À noter que le jeu, étant difficilement traduisible, n’existe qu’en anglais.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.blueprincegame.com/"&gt;Site de Blue Prince&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Clair Obscur: Expedition 33&lt;/h2&gt;
&lt;p&gt;Au-delà d’avoir battu tous les records en décrochant 9 prix sur 12 lors des derniers &lt;a href="https://fr.wikipedia.org/wiki/The_Game_Awards_2025"&gt;&lt;em lang="en"&gt;Game Awards&lt;/em&gt;&lt;/a&gt;, Clair Obscur est aussi un très bon jeu.&lt;/p&gt;
&lt;p&gt;Chaque année, une Peintresse marque un décompte de 100 à 0 sur un immense monolithe.
Les personnes dont l’âge correspond au décompte disparaissent alors en poussière.
Pour arrêter la Peintresse, la ville de Lumière envoie chaque année une expédition.
Dans le jeu, on incarne les membres de l’Expedition 33.&lt;/p&gt;
&lt;p&gt;La particularité du gameplay de ce &lt;abbr&gt;RPG&lt;/abbr&gt; repose sur les actions d’attaque et de défense qui sont timées.
Il faut appuyer sur la bonne touche dans un timing particulièrement serré pour, esquiver, bloquer les attaques, voire contre-attaquer si tout se passe bien.
J’ai plutôt bien accroché à cette mécanique difficile à appliquer correctement à chaque combat et qui demande pas mal de concentration.
Mais quel plaisir quand tout se passe comme prévu !&lt;/p&gt;
&lt;p&gt;J’ai surtout particulièrement accroché à la narration.
On reste dans le flou jusqu’à la toute fin du jeu, laissant mille interprétations possibles de la réalité.
J’ai vraiment un grand affect pour ce genre de narration qui ne nous prend pas par la main.&lt;/p&gt;
&lt;p&gt;La musique est à elle seule un petit bijou au milieu de tout ça, même si, avec le recul, elle m’a moins marqué que ce que j’imaginais.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.expedition33.com/"&gt;Site de Clair Obscur: Expedition 33&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Jusant&lt;/h2&gt;
&lt;p&gt;Jusant est un jeu d’escalade où l’on incarne une personne à la recherche de l’eau disparue du monde dans lequel on évolue.
On passe l’entièreté du jeu à escalader une gigantesque tour où l’on découvre peu à peu l’histoire des personnes qui ont peuplé les lieux par le passé.&lt;/p&gt;
&lt;p&gt;J’avais initialement joué à la démo sans être entièrement convaincu… et puis l’ambiance solitaire qu’offre Jusant m’a attrapé.
Le fait que le jeu ne soit pas difficile, mais plus centré sur un aspect méditatif est clairement un plus permettant de profiter de ce que le jeu a offrir.
Là aussi, c’est la narration — à travers l’environnement, ou des quelques lettres qui trainent ici et là — qui m’a le plus porté.
J’ai adoré avoir le sentiment de remonter le temps plus je montais la tour.
Aussi, c’est un jeu plutôt court (moins de 10h), ce qui est toujours appréciable.&lt;/p&gt;
&lt;p&gt;Je ne pense pas relancer le jeu, mais il m’en reste encore un sentiment de nostalgie qui me le fait entrer sans hésiter dans mon top 3 de 2025.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://dont-nod.com/en/games/jusant/"&gt;Site de Jusant&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Valheim&lt;/h2&gt;
&lt;p&gt;Je ne suis pas un grand fan des jeux de survie, mais je crois que Valheim était celui qu’il me fallait.
On y incarne un guerrier Viking tombé au combat qui doit se rendre digne d’entrer au Valhalla en tuant les ennemis d’Odin.&lt;/p&gt;
&lt;p&gt;La carte immense est générée procéduralement et dispose de différents biomes tous aussi différents les uns que les autres.
Le monde est ouvert, mais il est grandement recommandé de bien maitriser le biome dans lequel on se trouve avant d’attaquer le suivant.&lt;/p&gt;
&lt;p&gt;C’est un jeu exigeant et difficile, surtout si on ne prend pas son temps.
Chaque amélioration d’arme ou d’armure notamment fait la différence dans notre progression.&lt;/p&gt;
&lt;p&gt;Les graphismes sont très particuliers et peuvent rebuter au premier abord.
Personnellement je les adore : ils apportent une touche vraiment particulière à l’ambiance générale.
Combinés à une ambiance sonore réussie, j’ai été totalement happé par Valheim.&lt;/p&gt;
&lt;p&gt;On a joué une bonne partie du temps à deux à ce jeu, mais j’ai également fait une longue session solo à côté tellement j’avais envie d’apprécier Valheim à mon propre rythme.
Le jeu est aussi très généreux : malgré ma centaine d’heures passée sur le jeu, je ne l’ai toujours pas terminé !
On est clairement sur un jeu qui demande de l’investissement.&lt;/p&gt;
&lt;p&gt;Valheim est encore en accès anticipé, mais il devrait sortir en 2026 si tout va bien.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.valheimgame.com/"&gt;Site de Valheim&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Hades 2&lt;/h2&gt;
&lt;p&gt;Bastion, Transistor, Pyre, Hades, et maintenant Hades 2 : je suis en grand fan du studio Supergiant Games.
Mon avis est donc très biaisé !&lt;/p&gt;
&lt;p&gt;Si vous avez joué à Hades premier du nom, tout est démultiplié dans cette suite : les décors sont plus nombreux (et plus beaux encore !), les mécaniques de gameplay sont plus variées, les biomes et les boss multipliés par deux, la musique encore plus exceptionnelle, les combos mieux maitrisés.
C’est un jeu très généreux en contenu, donc foncez si vous avez aimé le 1 et que vous avez du temps à passer sur celui-ci.&lt;/p&gt;
&lt;p&gt;Bon, mais !
Le jeu est aussi plus compliqué à prendre en main, on se sent assez rapidement dépassé par tout ce qu’il y a à apprendre.
Il est aussi plus dur dans sa globalité.
Personnellement, c’est ce qu’il me fallait, mais cela pourrait rebuter.&lt;/p&gt;
&lt;p&gt;Pour moi, le plus gros défaut concerne toutefois la narration.
J’ai trouvé qu’il était plus compliqué de s’attacher à l’ensemble des nombreux personnages.
Il y a beaucoup de dialogues qui sonnent creux, donnant le sentiment d’être là pour le remplissage, sans rien apporter à l’histoire.&lt;/p&gt;
&lt;p&gt;Malgré cela, le scénario global ne m’a pas déçu comme il a pu décevoir d’autres joueurs.
Ça aurait pu être mieux, mais ça n’a pas franchement réduit le plaisir que j’avais à jouer.&lt;/p&gt;
&lt;p&gt;Puis rappelons que le gameplay principal consiste à tracer sa route à travers des vagues d’ennemis, boostée petit à petit par les bienfaits de notre famille de l’Olympe (et plus encore).
Pour le coup, on est rassasié sur ce plan-là !&lt;/p&gt;
&lt;p&gt;Il y a tellement de choses à découvrir, expérimenter et apprécier dans Hades 2, que je n’ai aucune hésitation à le considérer comme le meilleur jeu auquel j’ai joué en 2025.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.supergiantgames.com/games/hades-ii/"&gt;Site de Hades 2&lt;/a&gt;&lt;/p&gt;</content></entry><entry><title>Mise à jour 2026 du site</title><id>urn:uuid:70ca03e4-9645-5862-a301-666baecf290f</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/mise-a-jour-2026-du-site.html" rel="alternate" type="text/html" /><published>2026-01-26T22:30:00+01:00</published><updated>2026-01-26T22:30:00+01:00</updated><content type="html">&lt;p&gt;Après plusieurs années à ne plus toucher à ce site, l’envie m’a pris d’en revoir le design pour quelque chose d’encore plus minimaliste.
Je dois en être à la neuvième version de ce site depuis ~2010, ça commence à faire une belle longévité !&lt;/p&gt;
&lt;p&gt;J’ai viré la mini-couche de JavaScript qui restait.
J’ai aussi retiré le mode sombre&amp;nbsp;: pour un site avec si peu à lire, le cout de la maintenance n’en valait pas la peine.&lt;/p&gt;
&lt;p&gt;J’ai retravaillé très légèrement le texte de la &lt;a href="index.html"&gt;page d’accueil&lt;/a&gt; pour lister les projets principaux sur lesquels j’ai bossés récemment.
J’avais initialement envie de faire une page dédiée pour chacun d’eux, mais ça représentait plus de boulot, en contradiction avec mon envie de minimalisme.&lt;/p&gt;
&lt;p&gt;En 2023, j’ai décidé &lt;a href="de-l-ensevelissement-de-ce-blog.html"&gt;d’ensevelir le blog&lt;/a&gt; : les articles restent en ligne, mais ils ne sont plus accessibles depuis l’accueil.
Je n’ai pas décidé de revenir sur cette décision avec cette version.
Elle me satisfait toujours autant en me retirant toute forme de pression 😊&lt;/p&gt;</content></entry><entry><title>Mes jeux 2024</title><id>urn:uuid:1616119d-cea7-5524-8e42-78daf69d74ef</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/mes-jeux-2024.html" rel="alternate" type="text/html" /><published>2025-02-09T11:35:00+01:00</published><updated>2025-02-09T11:35:00+01:00</updated><content type="html">&lt;p&gt;Comme en 2023, j’ai décidé de faire une rétrospective des jeux auxquels j’ai joué l’année passée (voir &lt;a href="mes-jeux-2023.html"&gt;la rétrospective de mes jeux 2023&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Il faut savoir que je me fais en début d’année une petite liste des jeux auxquels j’aimerais jouer sur l’année.
Ça me permet d’être moins tenté par les nouveautés « à la mode », mais aussi de mieux profiter des jeux auxquels je joue.
Ça a été une très bonne pioche en 2024.&lt;/p&gt;
&lt;h2&gt;No Man’s Sky&lt;/h2&gt;
&lt;p&gt;J’ai commencé l’année en jouant à No Man’s Sky.
Il s’agit d’un jeu d’exploration et de survie spatiale dont l’univers (infini ?) est créé de manière procédurale&lt;sup id="fnref:1"&gt;&lt;a class="footnote-ref" href="#fn:1"&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;J’étais resté sur le souvenir d’un jeu hyper attendu mais qui avait énormément déçu à sa sortie.
J’avais néanmoins entendu dire qu’il s’était bonifié avec le temps et ses nombreuses mises à jour.&lt;/p&gt;
&lt;p&gt;Ça a failli être une déception car je n’ai pas été immédiatement happé par le jeu.
Comme tout jeu de survie, je me suis assez vite lassé et je l’ai mis de côté.
On discerne en effet assez rapidement certains des artefacts qui permettent au jeu d’être « infini » ; par exemple les dialogues avec les autres personnages scriptés à l’extrême, ou les planètes générées selon un même schéma répétitif.
De plus, j’y ai joué sur la Switch qui galère pas mal à faire tourner le jeu (quoique j’estime que le niveau de fluidité global soit un petit exploit pour ce jeu !)&lt;/p&gt;
&lt;p&gt;J’ai toutefois décidé de relancer le jeu en décembre, un peu par hasard.
C’était l’ambiance parfaite qu’il me fallait pour finir l’année : bien que les artefacts du jeu soient toujours aussi visibles, il y a aussi une ambiance très douce, presque mélancolique, qui se dégage de No Man’s Sky.
La musique transporte le joueur à travers l’immensité de l’univers du jeu et j’ai finalement pris plaisir à simplement suivre la quête principale, tout en construisant une base sur ma planète « paradisiaque » (elles ne le sont pas toutes !)&lt;/p&gt;
&lt;p&gt;J’ai finalement passé une cinquantaine d’heures supplémentaires sur le jeu 😅
Une très bonne surprise tout compte fait !&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.nomanssky.com/"&gt;Lien vers le site de No Man’s Sky.&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Story Teller&lt;/h2&gt;
&lt;p&gt;Story Teller est un petit jeu d’énigmes.
Chaque énigme consiste à narrer une histoire en quelques cases.
On agrémente chacune des cases avec une scène (= un lieu) et des personnages qui vont interagir entre eux.
Seulement, les interactions changent et évoluent en fonction des cases précédentes.
Par exemple, si on a fait se marier deux personnages à la première case, si la seconde case représente le décès de l’un des deux, l’épous·e sera triste.&lt;/p&gt;
&lt;p&gt;C’est un bon jeu pour se creuser les méninges, sans perdre trop de temps (quelques minutes pour chaque énigme).
Il a l’avantage d’être très simple à prendre en main.
La difficulté des énigmes est toutefois assez inégale et le jeu plutôt court (je l’ai terminé en environ 4h).
Cela n’empêche pas Story Teller d’être un jeu malin, bien pensé et agréable à jouer.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://annapurnainteractive.com/en/games/storyteller"&gt;Lien vers le site de Story Teller.&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Sea of Stars&lt;/h2&gt;
&lt;p&gt;Sea of Stars est un RPG « à l’ancienne » mais avec des mécaniques de gameplay remises au goût du jour.
On y incarne deux enfants du Solstice, élevé·es en guerriers pour botter le train des monstres d’un alchimiste malfaisant : le Fleshmancer.&lt;/p&gt;
&lt;p&gt;Le scénario est bien mené, parfois un peu simpliste sans que ce soit trop gênant puisque porté par des personnages très attachants&lt;sup id="fnref:2"&gt;&lt;a class="footnote-ref" href="#fn:2"&gt;2&lt;/a&gt;&lt;/sup&gt;.
Quelques twists dans l’histoire permettent de rester accrochés.
J’ai particulièrement aimé les petites énigmes qui parsèment le jeu, jamais bien compliquées, mais bien dosées.
Les quêtes secondaires rajoutent du contenu agréable et pas rébarbatif, ce qui permet d’en profiter quelques heures de plus.
Enfin, pour ne rien gâcher, le jeu est très beau avec son look rétro et sa musique soignée.&lt;/p&gt;
&lt;p&gt;Je rangerais Sea of Stars dans la catégorie de mes jeux un peu « doudous ».
Peut-être pas mon jeu de l’année, mais j’ai pris du très bon temps dessus, au point que je veuille terminer l’ensemble des quêtes secondaires pour ne rien manquer.
Je conseille vivement !&lt;/p&gt;
&lt;p&gt;&lt;a href="https://seaofstarsgame.co/"&gt;Lien vers le site de Sea of Stars.&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Return of the Obra Dinn&lt;/h2&gt;
&lt;p&gt;Il s’agit là encore d’un jeu d’énigme.
On débarque sur un bateau, l’Obra Dinn, pour enquêter sur la disparition mystérieuse de son équipage.
On est pourvu pour cela d’une montre à gousset un peu spéciale puisqu’elle permet de revivre les scènes qui ont mené à la mort des membres de l’équipage.
On dispose également d’un livre de bord que l’on renseigne au fil de nos déductions.
Le principe est de déterminer la cause du décès de chacun·e des membres du bateau.&lt;/p&gt;
&lt;p&gt;Au premier abord, les graphismes du jeu sont assez déstabilisants et la boucle de gameplay se révèle plutôt répétitive.
Il faut toutefois passer les premières appréhensions pour apprécier le jeu à sa juste valeur.
Il y a notamment un côté très addictif à découvrir ce qui est arrivé à l’ensemble de l’équipage du bateau.&lt;/p&gt;
&lt;p&gt;Ce n’est clairement pas un jeu facile — les déductions tiennent parfois à pas grand-chose —, mais il sait bien rétribuer le ou la joueuse quand elle finit par trouver la solution.
De plus, il n’y a pas de mécanique punitive (pas de mort ou de chronomètre pour mettre la pression par exemple), ce qui permet d’apprécier tranquillement le jeu.
J’ai fini par adorer les quelques heures passées dessus, et je pense que je retournerai sur l’Obra Dinn une fois que je l’aurai un peu oublié.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://obradinn.com/"&gt;Lien vers le site de Return of the Obra Dinn.&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Celeste&lt;/h2&gt;
&lt;p&gt;C’est un retour puisque Celeste faisait déjà partie de ma liste de jeux 2023 !&lt;/p&gt;
&lt;p&gt;Il s’agit d’un jeu de plateforme en deux dimensions particulièrement exigeant.
On y incarne Madeline, une jeune fille qui veut gravir une montagne : le Mont Celeste.
C’est finalement sa dépression et son anxiété qu’on finit par affronter au fil de l’ascension.&lt;/p&gt;
&lt;p&gt;Je concluais dans mon précédent article ainsi :&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Mon avis est (un peu) mitigé vis-à-vis de ce jeu.
Je pense que j’en attendais beaucoup, mais que le fait d’avoir atteint la « première » fin du jeu relativement rapidement ne m’a pas laissé le temps de l’apprécier à sa juste valeur.
Pour autant, j’ai beaucoup aimé y jouer.
J’ai de toute façon encore beaucoup de choses à faire, notamment les « faces B » des chapitres (des versions beaucoup plus ardues des cartes).
[…] Je pense que je l’apprécierai de plus en plus avec le temps.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Vous vous en doutez : ça n’a pas raté 😁&lt;/p&gt;
&lt;p&gt;Je ne pensais pas passer autant d’heures supplémentaires dessus (une centaine d’heures, oui oui…)
Pour autant, je me suis pris au jeu des défis supplémentaires qui m’attendaient après avoir gravi le Mont Celeste une première fois.&lt;/p&gt;
&lt;p&gt;Le défi qu’a représenté la « vraie » fin du jeu a mis mes nerfs à l’épreuve, mais m’a aussi apporté un plaisir que je n’avais encore jamais vécu en jouant.
Il faut vraiment prendre les défis que proposent Celeste comme des marches que l’on grimpe une par une.
Dès qu’on butte un peu, alors c’est qu’il est temps de revenir un peu en arrière pour assurer toujours un peu mieux ses pas.
C’est vraiment cette progression (et sa difficulté) qui porte tout au long du jeu.&lt;/p&gt;
&lt;p&gt;Une mention spéciale pour le DLC qui m’a énormément touché.
Il est non seulement absurdement dur, mais aussi très touchant et extrêmement généreux dans sa récompense finale.
Terminer le DLC a probablement été l’une de mes meilleures expériences vidéo-ludiques de ces dernières années.
J’ai rarement vu un gameplay aussi bien porter le message qu’il veut transmettre.
Rien qu’à me le remémorer, j’ai envie de relancer le jeu !&lt;/p&gt;
&lt;p&gt;J’ai poussé le bouchon encore un peu plus loin en visant de terminer la première fin du jeu en moins d’une heure.
Défi relevé, mais je ne crois pas avoir envie de m’y replonger toutefois 😅&lt;/p&gt;
&lt;p&gt;Bref, vous comprendrez que je recommande Celeste les yeux fermés.
Si la difficulté assumée du jeu vous fait peur, sachez qu’il est possible d’ajuster la difficulté afin de profiter du jeu en fonction de son niveau.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.celestegame.com/"&gt;Lien vers le site de Celeste.&lt;/a&gt;&lt;/p&gt;
&lt;div class="footnote"&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;De façon unique et aléatoire si vous voulez.&amp;#160;&lt;a class="footnote-backref" href="#fnref:1" title="Jump back to footnote 1 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:2"&gt;
&lt;p&gt;Mention spéciale au personnage de Garl, évidemment ♥️&amp;#160;&lt;a class="footnote-backref" href="#fnref:2" title="Jump back to footnote 2 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</content></entry><entry><title>Mes jeux 2023</title><id>urn:uuid:32987223-0130-5b97-b553-c85a2b3ba66d</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/mes-jeux-2023.html" rel="alternate" type="text/html" /><published>2023-12-24T10:00:00+01:00</published><updated>2023-12-24T10:00:00+01:00</updated><content type="html">&lt;p&gt;Début 2023, je me suis fait une liste de jeux à jouer durant l’année.
Je suis heureux d’avoir fait ça, car ça m’a permis d’être moins dans la « consommation » et de mieux apprécier mes découvertes.
Petite mise en avant des jeux qui m’ont le plus marqué.&lt;/p&gt;
&lt;h2&gt;Hollow Knight&lt;/h2&gt;
&lt;p&gt;Dans &lt;a href="https://www.hollowknight.com/"&gt;Hollow Knight&lt;/a&gt;, on incarne un chevalier insecte muni de son aiguillon.
On ne nous dit pas grand-chose, et c’est à nous de comprendre l’intrigue.
On y explore une immense carte en deux dimensions, tout en combattant tout un tas d’ennemis.
Les boss sont particulièrement velus.&lt;/p&gt;
&lt;p&gt;C’était l’un de mes défis de l’année car le jeu est connu pour sa difficulté.
De fait, j’ai eu du mal à me plonger dans le jeu, et il s’en est fallu de peu pour que je le laisse trainer dans un coin.
Au final, je me suis remotivé et j’ai fini par me prendre au jeu.
Et une fois le jeu fini une première fois… j’ai immédiatement lancé une seconde partie.
Je voulais jauger ma progression, et je n’ai pas été déçu : le sentiment de facilité sur les premiers niveaux est grisant.
J’ai rarement aussi bien ressenti le fait d’être devenu meilleur à un jeu.&lt;/p&gt;
&lt;h2&gt;Zelda Tears Of The Kingdom&lt;/h2&gt;
&lt;p&gt;Comme dans tout bon Zelda qui se respecte, on incarne Link qui doit sauver la Princesse Zelda, et tout le royaume d’Hyrule tant qu’à faire.
J’avais adoré le précédent opus (Breath of the Wild), donc je ne pouvais pas passer à côté de celui-ci.&lt;/p&gt;
&lt;p&gt;La particularité de &lt;a href="https://zelda.nintendo.com/tears-of-the-kingdom/fr/"&gt;Tears of the Kingdom&lt;/a&gt; réside dans la possibilité de fabriquer des outils.
J’avoue avoir relativement peu joué de cette mécanique, sauf à recréer un peu toujours les mêmes objets (notamment le scooter volant, très pratique dans les sous-terrains).&lt;/p&gt;
&lt;p&gt;J’ai trouvé le jeu un peu moins maîtrisé sur certains aspects comme les sanctuaires ou les pouvoirs.
En revanche, la mise en scène et l’ambiance sont folles, et j’ai savouré chaque minute sur ce jeu.
Mention spéciale à l’arrivée dans le Temple du Vent, incroyable.&lt;/p&gt;
&lt;h2&gt;Outer Wilds&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.mobiusdigitalgames.com/outer-wilds.html"&gt;Outer Wilds&lt;/a&gt; est une magnifique aventure d’exploration spatiale.
On est balancé aux manettes d’une navette et muni d’un traducteur capable de déchiffrer d’étranges symboles laissés par une civilisation disparue il y a longtemps.
À partir de là, on va devoir résoudre un puzzle à l’échelle de l’univers, en explorant chaque planète de notre système solaire une à une.&lt;/p&gt;
&lt;p&gt;La puissance du jeu réside dans la découverte des mécaniques du jeu.
Tout est sous nos yeux dès le début du jeu, et on pourrait résoudre le jeu en moins d’une heure (avec beaucoup de chance toutefois).
Il en faut toutefois une bonne vingtaine pour réussir à recoller tous les morceaux.&lt;/p&gt;
&lt;p&gt;Bon, clairement mon coup de cœur de l’année &amp;lt;3&lt;/p&gt;
&lt;p&gt;Je guettais ce jeu depuis plusieurs années.
Il était annoncé sur Switch, mais a été repoussé sans qu’une nouvelle date ne soit donnée.
On me l’a finalement offert sur Steam.
J’ai donc pu y jouer sur PC… juste avant que le jeu ne sorte sur Switch cette fin d’année !&lt;/p&gt;
&lt;p&gt;En revanche, une fois le jeu terminé, pas moyen d’y rejouer puisqu’on connait désormais les mécaniques.
Ce qui m’amène à ce conseil : ne vous spoilez pas le jeu !
Ne regardez pas la bande-annonce, ne recherchez pas d’informations en ligne, et suivez simplement le conseil de tous les joueurs et joueuses qui sont passés avant vous : ne vous spoilez pas (oui je me répète).&lt;/p&gt;
&lt;p&gt;Et si vous aimez le jeu, n’hésitez pas à jouer à son DLC, Echoes of the Eye (dans une ambiance plus angoissante, vous êtes prévenu⋅es !)&lt;/p&gt;
&lt;h2&gt;Celeste&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.celestegame.com/"&gt;Celeste&lt;/a&gt; est un jeu de plateforme en deux dimensions particulièrement exigeant.
Il raconte l’histoire d’une jeune fille qui veut gravir une montagne.
C’est finalement sa dépression et son anxiété qu’on finit par affronter au fil de l’ascension.&lt;/p&gt;
&lt;p&gt;C’est le dernier jeu auquel j’ai joué cette année et c’était mon deuxième défi de l’année.
En effet, je ne joue pas trop aux jeux de plateforme, mais Hollow Knight m’avait déjà redonné un peu goût au genre.&lt;/p&gt;
&lt;p&gt;Mon avis est (un peu) mitigé vis-à-vis de ce jeu.
Je pense que j’en attendais beaucoup, mais que le fait d’avoir atteint la « première » fin du jeu relativement rapidement ne m’a pas laissé le temps de l’apprécier à sa juste valeur.
Pour autant, j’ai beaucoup aimé y jouer.
J’ai de toute façon encore beaucoup de choses à faire, notamment les « faces B » des chapitres (des versions beaucoup plus ardues des cartes).&lt;/p&gt;
&lt;p&gt;Je continue donc d’y jouer et, comme Hollow Knight, le jeu sait faire progresser et nous en faire prendre conscience.
Je pense que je l’apprécierai de plus en plus avec le temps.&lt;/p&gt;
&lt;h2&gt;Quelques jeux en rab’&lt;/h2&gt;
&lt;p&gt;J’ai joué à plusieurs autres jeux en plus de ceux listés ci-dessus, je les balance ici en vrac :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://powerwash-simulator.square-enix-games.com/fr/"&gt;Powerwash Simulator&lt;/a&gt;, un simulateur de lavage à haute-pression, c’est très de niche, mais il procure une satisfaction énorme à laver des surfaces encrassées.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://thomasgervraud.com/press/brotato/"&gt;Brotato&lt;/a&gt;, un jeu de survie (à la Vampire Survivors pour celleux qui connaissent) où l’on équipe notre patate de divers armes pour survivre à des vagues d’ennemis ; c’est un gameplay très bête et méchant, mais ça peut détendre.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://studios.ptilouk.net/superflu-riteurnz/"&gt;Superflu Riteurnz&lt;/a&gt;, le jeu d’enquête développé par l’ami Gee, on y incarne Harpagon Lonion (aka Superflu), assisté de Sophie, pour débusquer un mystérieux voleur de pommes ; c’est idiot, c’est fun, c’est coloré, c’est très chouette, jouez-y !&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.nintendo.com/jp/switch/baypa/index.html"&gt;F-Zero 99&lt;/a&gt;, jeu de courses de voitures à l’ancienne, mais sauce battle royale ; chouette de jouer contre 98 adversaires, et assez exigeant, mais un peu répétitif à la longue (il y a peu de cartes).&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.minetest.net/"&gt;Minetest&lt;/a&gt;, un clone de Minecraft, on mine des cubes, on construit des bâtiments, et on occit des monstres ; bref, la routine.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Je recommande chacun des 4 premiers jeux cités sans hésitation (aux amateurs de ces genres de jeux en tout cas).
Et s’il ne devait y en avoir qu’un, ce serait Outer Wilds sans hésiter !
Je considère que cette année 2023 a été celle où je me suis le plus amusé d’un point de vue vidéoludique.&lt;/p&gt;
&lt;p&gt;Je suis particulièrement heureux de m’être fait cette liste de jeux en début d’année.
Ça m’a laissé le temps de m’impatienter pour chacun d’eux, un peu comme un cadeau de Noël qu’on attend de plus en plus à l’approche du 25 décembre.
J’ai aussi davantage apprécié chacun de ces jeux en faisant en sorte que ce ne soit pas des jeux achetés sur un coup de tête.
D’ailleurs, j’ai été beaucoup plus « consommateur » des jeux qui sortaient de cette liste ; j’ai moins pris le temps de les apprécier.&lt;/p&gt;
&lt;p&gt;En 2024, je compte réitérer l’expérience de manière élargie : je compte me faire une liste de livres, musiques, films, et bien sûr jeux vidéos à acheter.&lt;/p&gt;</content></entry><entry><title>De l’ensevelissement de ce blog</title><id>urn:uuid:60fb4957-888e-5720-a441-197b612d090c</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/de-l-ensevelissement-de-ce-blog.html" rel="alternate" type="text/html" /><published>2023-11-16T17:55:00+01:00</published><updated>2023-11-16T17:55:00+01:00</updated><content type="html">&lt;p&gt;Depuis que je suis petit, j’ai toujours aimé écrire.&lt;/p&gt;
&lt;p&gt;J’ai retrouvé récemment des écrits dans de vieux cahiers (CE2 et CM1) dont j’avais été particulièrement fier à l’époque.
Au collège, je m’amusais à écrire de courtes histoires qui mettaient en scène mes pions de l’époque et que je distribuais ensuite à mes copains d’internat et de classe.
Le jour où ma prof de français est tombée dessus, j’avoue avoir ressenti un mélange de honte et de fierté (elle m’a encouragé, merci à elle !)
Au lycée, j’ai débuté un blog sur lequel je publiais aussi bien des billets d’humeur, que des poésies ou encore des tutos HTML et CSS.&lt;/p&gt;
&lt;p&gt;Ce blog-ci existe depuis au moins 2011.
J’y ai parlé de mes premières tentatives de projets Web, tout comme de mes projets plus aboutis, comme FreshRSS.
Je n’ai jamais été extrêmement prolifique, mais j’ai toujours espéré trouver l’énergie de m’y mettre « vraiment ».
En fait, c’était l’envie qu’il me manquait surtout.&lt;/p&gt;
&lt;p&gt;La « ligne éditoriale » ne m’a jamais trop plu : j’aurais plutôt eu envie de publier de courts textes, peut-être plus expérimentaux.
J’aurais pu la faire évoluer, mais je n’étais pas à l’aise avec ça sur mon site personnel.
De plus, j’ai toujours eu du mal à voir attaché mon nom aux articles.
Je suis bien plus à l’aise sous une forme d’anonymat.&lt;/p&gt;
&lt;p&gt;Il y a quelques jours, j’ai donc décidé de supprimer la page principale du blog (celle qui listait les articles).
Mon site se réduit donc à la page d’accueil pour me présenter et une page expliquant comment me contacter.
Je suis plus à l’aise avec ça.&lt;/p&gt;
&lt;p&gt;En revanche, pour l’instant, j’ai décidé de conserver les articles et le flux Web.
Les personnes qui suivent ce blog depuis un agrégateur pourront donc continuer de le faire.
En effet, je ne me ferme pas non plus la porte à l’écriture d’autres articles à l’avenir.
Seulement, je n’ai aujourd’hui plus aucune pression pour le faire, et c’est bien mieux !&lt;/p&gt;
&lt;p&gt;Quant à mes envies d’écrire, je compte éventuellement ouvrir un blog ailleurs.
Mais ça, je n’en parlerai pas !&lt;/p&gt;</content></entry><entry><title>Refuser 10 000 dollars</title><id>urn:uuid:73803c89-6dc6-5390-b3bf-88d20ea3bc56</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/refuser-10000-dollars.html" rel="alternate" type="text/html" /><published>2023-05-03T18:30:00+02:00</published><updated>2023-05-03T18:30:00+02:00</updated><content type="html">&lt;p&gt;Aujourd’hui, j’ai refusé 10 000 dollars.&lt;/p&gt;
&lt;p&gt;J’ai reçu un mail en provenance d’un bureau d’enregistrement de noms de domaine — transmis par OVH — me proposant de me racheter un nom de domaine.
Voici le message (après traduction) :&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Je vous contacte au nom d’un de mes clients qui est très intéressé pour vous acheter votre nom de domaine lessy.io et je voulais savoir si vous étiez prêt à le vendre. Nous aimerions vous faire une offre de 10K USD.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Pour ce que j’en ai vérifié, la demande me semble légitime et honnête.
Quand bien même il s’agirait d’hameçonnage, ça ne change pas la principale raison de mon refus : &lt;strong&gt;je n’ai pas envie d’aider une boîte ou une personne qui a les moyens de mettre 10 000 dollars dans un nom de domaine.
On ne fait pas partie du même monde.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Alors non, ce choix n’est pas rationnel.
En revanche, il est politique.&lt;/p&gt;</content></entry><entry><title>Écrire une syntaxe de recherche</title><id>urn:uuid:f8f41c4e-2f6e-5f02-a585-1e8589b58bdb</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/ecrire-une-syntaxe-de-recherche.html" rel="alternate" type="text/html" /><published>2023-05-02T18:10:00+02:00</published><updated>2023-05-02T18:10:00+02:00</updated><content type="html">&lt;p&gt;J’aime plutôt bien la syntaxe de recherche de GitHub.
Elle permet à la fois de rechercher à partir de texte « brut », tout en ciblant des propriétés particulières (ex. &lt;code&gt;is:open label:bug&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;Ça faisait un moment que j’avais envie de développer un parser pour ce type de syntaxe.
Et ça tombe bien, j’ai eu l’occasion récemment d’en développer un !&lt;/p&gt;
&lt;p&gt;Je l’ai écrit pour &lt;a href="https://github.com/probesys/bileto"&gt;le projet Bileto&lt;/a&gt; (un gestionnaire de tickets et de parcs informatiques).
J’en ai profité pour &lt;a href="https://github.com/Probesys/bileto/blob/main/docs/developers/search-engine.md"&gt;documenter le fonctionnement du moteur de recherche&lt;/a&gt; à destination des développeurs et développeuses.
La documentation de la syntaxe, quant à elle, est directement intégrée à l’interface.&lt;/p&gt;
&lt;p&gt;Le projet est écrit avec &lt;a href="https://symfony.com/"&gt;Symfony&lt;/a&gt;, et une partie du moteur de recherche dépend de l’&lt;abbr&gt;ORM&lt;/abbr&gt; &lt;a href="https://www.doctrine-project.org/"&gt;Doctrine&lt;/a&gt;.
Ceci dit, il devrait être assez facilement adaptable.
Toute une partie est générique, tandis que la partie « génération des requêtes &lt;abbr&gt;DQL&lt;/abbr&gt; » (langage propre à Doctrine) est très proche du &lt;abbr&gt;SQL&lt;/abbr&gt;.&lt;/p&gt;</content></entry><entry><title>JdLL 2023</title><id>urn:uuid:77407e36-3060-5036-a505-808dc789b3da</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/jdll-2023.html" rel="alternate" type="text/html" /><published>2023-03-30T19:00:00+02:00</published><updated>2023-03-30T19:00:00+02:00</updated><content type="html">&lt;p&gt;J’avais déjà fait une première annonce le mois dernier sur le blog de Flus : &lt;strong&gt;je serai présent aux &lt;a href="https://jdll.org/"&gt;JdLL&lt;/a&gt;, ce weekend à Lyon.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;J’y donnerai deux conférences.&lt;/p&gt;
&lt;p&gt;La première se nomme « &lt;strong&gt;Bileto : un produit &amp;amp; une philosophie&lt;/strong&gt; ».
Elle aura lieu &lt;strong&gt;samedi 1&lt;sup&gt;er&lt;/sup&gt; avril de 11h à 11h55, atelier du mouvement.&lt;/strong&gt;
J’y présenterai le logiciel que je développe depuis l’an dernier au sein de &lt;a href="https://www.probesys.com/"&gt;Probesys&lt;/a&gt; : &lt;a href="https://github.com/Probesys/bileto"&gt;Bileto&lt;/a&gt;.
Il s’agit d’un logiciel de gestion de tickets et de parc informatique.
Le projet est encore jeune, mais on avance bien !
Ce sera l’occasion de faire le point sur où on en est et de parler un peu de communauté.&lt;/p&gt;
&lt;p&gt;Ma seconde conférence se nomme « &lt;strong&gt;Jouons avec les flux Web&lt;/strong&gt; ».
Elle aura lieu &lt;strong&gt;dimanche 2 avril de 13h à 13h55, salle des cultures.&lt;/strong&gt;
Je la donnerai avec ma casquette Flus.
J’y présenterai trois prototypes de logiciels qui utilisent des flux Web : &lt;a href="https://flus.fr/carnet/hitchhiker-generateur-de-planets-statiques.html"&gt;Hitchhiker&lt;/a&gt; (un planet), &lt;a href="https://flus.fr/carnet/flus-actualites.html"&gt;Flus Actualités / Hermès&lt;/a&gt; (une alternative collaborative à Google News) et &lt;a href="https://flus.fr/carnet/loquace-un-agregateur-social.html"&gt;Loquace&lt;/a&gt; (un réseau social).
L’objectif est de montrer d’autres manières d’utiliser les flux Web que les traditionnels agrégateurs.&lt;/p&gt;
&lt;p&gt;Le reste du weekend, je serai présent majoritairement sur le stand de Framasoft, et un peu sur le stand de Probesys.
N’hésitez pas à venir faire coucou !&lt;/p&gt;</content></entry><entry><title>Réflexions autour des IA spammeuses</title><id>urn:uuid:4ab82d98-131b-5fb4-ba26-5fcb41b33159</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/IA-spammeuses.html" rel="alternate" type="text/html" /><published>2023-03-26T20:30:00+02:00</published><updated>2023-03-26T20:30:00+02:00</updated><content type="html">&lt;p&gt;À l’inverse d’autres technos comme les &lt;abbr&gt;NFT&lt;/abbr&gt; ou le Metaverse, j’ai le sentiment que nous n’échapperons pas au raz-de-marée des technologies basées sur de l’Intelligence Artificielle.
Nous n’échapperons pas non plus aux dégâts qu’elles occasionneront.
Je note ici quelques réflexions que j’ai partagé en interne sur le Framateam de Framasoft.&lt;/p&gt;
&lt;p&gt;J’ai observé depuis quelques semaines du côté de &lt;a href="https://freshrss.org"&gt;FreshRSS&lt;/a&gt; une recrudescence de tickets faisant des demandes à priori légitimes.
Ces tickets ont été créés par des utilisateurs dont le compte GitHub a disparu quelques jours plus tard (exemples &lt;a href="https://github.com/FreshRSS/FreshRSS/issues/5126"&gt;1&lt;/a&gt;, &lt;a href="https://github.com/FreshRSS/FreshRSS/issues/5117"&gt;2&lt;/a&gt;, &lt;a href="https://github.com/FreshRSS/FreshRSS/issues/5115"&gt;3&lt;/a&gt;, &lt;a href="https://github.com/FreshRSS/FreshRSS/issues/5114"&gt;4&lt;/a&gt;).
Certains ont clairement des comportements bizarres, voir notamment &lt;a href="https://github.com/FreshRSS/xExtension-HelloWorld/issues/1"&gt;celui qui m’a amené à me poser ces questions&lt;/a&gt;.
Le ticket se trouve dans le mauvais dépôt, le titre &lt;em&gt;semble&lt;/em&gt; répondre à &lt;a href="https://github.com/FreshRSS/FreshRSS/issues/4295"&gt;un autre ticket&lt;/a&gt; du dépôt principal, mais le contenu est incohérent.
D’autres tickets sont plus cohérents, mais restent « étranges ».
Quoi qu’il en soit je n’avais encore jamais vu autant de comptes différents disparaître aussi vite qu’ils sont apparus.
Je me demande si ce n’est pas GitHub qui les a supprimés.&lt;/p&gt;
&lt;p&gt;J’ignore si ces comptes étaient gérés par des bots.
Le problème est que cela aurait pu l’être.
Quoi qu’il en soit, ça m’a amené à penser que les technologies comme &lt;abbr&gt;GPT&lt;/abbr&gt; vont ouvrir grandes les portes au spam dans le moindre interstice d’Internet.
Avec l’évolution de la technologie, ça va devenir de plus en plus compliqué de faire la distinction entre un compte légitime et un compte de spammeur.
Au point, j’imagine d’épuiser les mainteneurs de projets communautaires (dans le cas qui m’intéresse en l’occurrence, mais potentiellement toute personne amené à lire / réfléchir / réagir à du contenu posté par une autre personne).&lt;/p&gt;
&lt;p&gt;J’ai également de gros doutes sur la capacité des anti-spams actuels (ex. Rspamd, Akismet) à détecter du spam généré par une &lt;abbr&gt;IA&lt;/abbr&gt;.&lt;/p&gt;
&lt;p&gt;Enfin, je pressens une perte de confiance dans le contenu posté par autrui : si je ne sais pas si je fais face à une véritable personne intéressée par mes propos ou à un bot qui veut me faire tourner en bourrique, combien de temps vais-je tenir avant de me désintéresser des interactions sur le Web ?&lt;/p&gt;</content></entry><entry><title>Sonktionary</title><id>urn:uuid:2723d432-4557-5c11-843c-b910ffcf7682</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/sonktionary.html" rel="alternate" type="text/html" /><published>2023-03-04T15:18:00+01:00</published><updated>2023-03-04T15:18:00+01:00</updated><content type="html">&lt;p&gt;&lt;strong&gt;Dans la catégorie « projets bêtes », je vous présente &lt;a href="https://marienfressinaud.frama.io/sonktionary/"&gt;Sonktionary&lt;/a&gt;.&lt;/strong&gt;
Il s’agit d’une table de sons (aussi appelée « &lt;i lang="en"&gt;sound board&lt;/i&gt; ») avec des mots issus du &lt;a href="https://fr.m.wiktionary.org"&gt;Wiktionnaire&lt;/a&gt;.
Le principe est simple : vous cliquez sur un mot, Sonktionary prononce le mot.&lt;/p&gt;
&lt;p&gt;Là où il devient marrant, c’est qu’il est également capable de lire le « hash » de l’URL (i.e. ce qui se trouve après le &lt;code&gt;#&lt;/code&gt;).
Par exemple, si vous ouvrez l’URL &lt;a href="https://marienfressinaud.frama.io/sonktionary/#on%20veut%20la%20retraite%20à%20soixante%20ans"&gt;marienfressinaud.frama.io/sonktionary/#on veut la retraite à soixante ans&lt;/a&gt; et cliquez sur « Jouer », Sonktionary vous lira la phrase « on veut la retraite à soixante ans ».
Vous pouvez évidemment créer vous-même vos propres phrases en changeant les mots dans l’URL.
Les mots doivent être les mêmes que ceux de la page, mais vous pouvez les finir avec des virgules, des points et des point-virgules pour marquer les pauses.&lt;/p&gt;
&lt;p&gt;Précision utile : &lt;strong&gt;Sonktionary ne sert à rien&lt;sup id="fnref:1"&gt;&lt;a class="footnote-ref" href="#fn:1"&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/strong&gt; (j’avais seulement envie de m’amuser avec).&lt;/p&gt;
&lt;p&gt;Pour accéder au code source, c’est &lt;a href="https://framagit.org/marienfressinaud/sonktionary"&gt;sur Framagit&lt;/a&gt;.
Vous pouvez également ouvrir le code source de la page : tout tient dans l’unique fichier &lt;code&gt;index.html&lt;/code&gt; (à l’exception des fichiers sons).
Par contre, je n’ai pas fait d’effort sur la propreté du code ; vous êtes prévenu‧es.&lt;/p&gt;
&lt;div class="footnote"&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;C’est pourquoi c’est un chouette projet.&amp;#160;&lt;a class="footnote-backref" href="#fnref:1" title="Jump back to footnote 1 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</content></entry><entry><title>CSS minimale pour des sites moins moches</title><id>urn:uuid:fe2a69fc-9fd2-5326-b7a8-c80f83e9fe75</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/css-minimale.html" rel="alternate" type="text/html" /><published>2023-03-01T08:15:00+01:00</published><updated>2023-03-01T08:15:00+01:00</updated><content type="html">&lt;p&gt;Je suis retombé récemment sur les sites satiriques &lt;a href="http://motherfuckingwebsite.com"&gt;motherfuckingwebsite.com&lt;/a&gt; et &lt;a href="http://bettermotherfuckingwebsite.com"&gt;bettermotherfuckingwebsite.com&lt;/a&gt;&lt;sup id="fnref:1"&gt;&lt;a class="footnote-ref" href="#fn:1"&gt;1&lt;/a&gt;&lt;/sup&gt;.
Ce qui m’intéresse sur ce dernier, c’est qu’il se contente de 7 lignes de &lt;abbr&gt;CSS&lt;/abbr&gt; pour rendre le site beaucoup plus lisible.
En me basant dessus, je vous propose une variante légèrement améliorée :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;max-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="kt"&gt;ch&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="kt"&gt;rem&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;auto&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="kt"&gt;rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="kt"&gt;rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;#444&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="kt"&gt;%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;line-height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1.6&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;#f9f9ff&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;h3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;line-height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1.2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;img&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;max-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="kt"&gt;%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Quelques explications vis-à-vis de mes adaptations :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;j’utilise des unités relatives (rem, ch) pour que les tailles/marges s’adaptent au contenu ;&lt;/li&gt;
&lt;li&gt;la taille de la police est déclarée en pourcentage pour s’adapter aux préférences du navigateur de l’utilisateur ;&lt;/li&gt;
&lt;li&gt;l’espace en bas du contenu est élargi car il est moins agréable de lire le texte collé au bas de l’écran ;&lt;/li&gt;
&lt;li&gt;le fond de l’écran est légèrement grisé pour atténuer la luminosité de l’écran (et tire vers le bleu pour que ce soit moins terne) ;&lt;/li&gt;
&lt;li&gt;les images sont limitées à 100% de la taille maximale du contenu afin qu’elles ne dépassent pas de l’écran.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="footnote"&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;Notez que ces deux sites « minimalistes » ont réussi l’exploit d’intégrer Google Analytics. Sérieux ?&amp;#160;&lt;a class="footnote-backref" href="#fnref:1" title="Jump back to footnote 1 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</content></entry><entry><title>C’est quoi un bon langage Web ?</title><id>urn:uuid:77ffcd16-0548-5a23-a18f-6b4079a63930</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/c-est-quoi-un-bon-langage-web.html" rel="alternate" type="text/html" /><published>2023-02-22T09:00:00+01:00</published><updated>2023-02-22T09:00:00+01:00</updated><content type="html">&lt;p&gt;Pour m’amuser, je me suis mis en tête d’inventer un langage Web côté serveur.
Mon objectif est d’en faire un langage pédagogique pour enseigner la programmation de sites et d’applications Web.&lt;/p&gt;
&lt;p&gt;Jusque-là, le langage de prédilection pour cela est &lt;abbr&gt;PHP&lt;/abbr&gt;.
Deux raisons principales à cela selon moi :&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;il est à la fois un langage de programmation et un mini-framework (lecture directe des entrées via les variables globales &lt;code&gt;$_GET&lt;/code&gt;, &lt;code&gt;$_POST&lt;/code&gt;, etc. ; sortie avec de simples &lt;code&gt;echo&lt;/code&gt; ; c’est aussi un langage de templates)&lt;/li&gt;
&lt;li&gt;une fois bien configuré, un site en PHP peut s’installer très facilement sur un serveur : déposez les fichiers et ouvrez le site directement dans le navigateur&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;PHP s’est amélioré avec le temps, mais il possède toujours de gros défauts issus de son histoire.&lt;/p&gt;
&lt;p&gt;Quelques qualités pour un meilleur langage Web :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;très peu de concepts et de mot-clés à apprendre ;&lt;/li&gt;
&lt;li&gt;une seule manière de faire les choses ;&lt;/li&gt;
&lt;li&gt;une syntaxe claire et non ambigüe ;&lt;/li&gt;
&lt;li&gt;un ensemble cohérent.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Je pense m’inspirer de langages comme Python et Ruby pour le côté programmation, tout en simplifiant ; de Jinja2 pour le côté template.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;La question majeure que je me pose : à quoi ressemblerait un langage intuitif pour des personnes qui n’auraient jamais codé ?&lt;/strong&gt;
Dit autrement : comment appliquer des concepts d’expérience utilisateur (&lt;abbr&gt;UX&lt;/abbr&gt;) à la conception d’un langage informatique ?&lt;/p&gt;
&lt;p&gt;Je précise enfin qu’il s’agirait, pour moi, de (ré-&lt;sup id="fnref:1"&gt;&lt;a class="footnote-ref" href="#fn:1"&gt;1&lt;/a&gt;&lt;/sup&gt;)apprendre à développer un langage de zéro.
Je cherche à tâtonner et à faire mes propres erreurs.
Et je veux m’amuser à le créer.&lt;/p&gt;
&lt;p&gt;Mais je sais pas quand je le ferai !&lt;/p&gt;
&lt;div class="footnote"&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;J’ai quelques souvenirs de mes cours en école d’ingé, mais tout cela est bien loin !&amp;#160;&lt;a class="footnote-backref" href="#fnref:1" title="Jump back to footnote 1 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</content></entry><entry><title>Farandole de projets</title><id>urn:uuid:690cf885-5d30-5eab-88fe-156714e93669</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/farandole-de-projets.html" rel="alternate" type="text/html" /><published>2023-02-10T08:30:00+01:00</published><updated>2023-02-10T08:30:00+01:00</updated><content type="html">&lt;p&gt;&lt;strong&gt;Je multiplie les projets ces derniers jours.&lt;/strong&gt;
&lt;a href="https://framagit.org/marienfressinaud/exploratrices/"&gt;Exploratrices&lt;/a&gt; dont j’ai parlé &lt;a href="exploratrices.html"&gt;ici&lt;/a&gt;.
&lt;a href="https://framagit.org/marienfressinaud/hitchhiker/"&gt;Hitchhiker&lt;/a&gt; dont j’ai parlé &lt;a href="https://flus.fr/carnet/hitchhiker-generateur-de-planets-statiques.html"&gt;sur le carnet de Flus&lt;/a&gt;.
&lt;a href="https://framagit.org/marienfressinaud/sonktionary/"&gt;Sonktionary&lt;/a&gt; dont je n’ai pas encore parlé.
&lt;a href="https://framagit.org/marienfressinaud/hermes"&gt;Hermès&lt;/a&gt; sur lequel je travaille actuellement.
Sans compter &lt;a href="https://framagit.org/marienfressinaud/farandole"&gt;Farandole&lt;/a&gt; que je n’ai pas encore commencé.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Ça fait franchement du bien d’expérimenter autant de choses.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Pour Exploratrices, c’était la spécification complète du projet avant de démarrer, ainsi qu’une approche technique très différente de ce dont j’ai l’habitude.&lt;/p&gt;
&lt;p&gt;Pour Hitchhiker, c’était la contrainte minimaliste : faire autant que possible avec aussi peu de lignes de code que je pouvais me permettre.&lt;/p&gt;
&lt;p&gt;Sonktionary : un projet rigolo et fonctionnel démarré en milieu de soirée sur un coup de tête.&lt;/p&gt;
&lt;p&gt;Avec Hermès, je découvre &lt;a href="https://www.php.net/manual/language.attributes.php"&gt;les attributs PHP&lt;/a&gt; et je complète largement mon framework, &lt;a href="https://github.com/flusio/Minz"&gt;Minz&lt;/a&gt;.
Je compte aussi explorer avec ce projet la dimension collaborative (et ses difficultés).&lt;/p&gt;
&lt;p&gt;Je fais tout ça sans la contrainte de maintenance, car je ne développe que des prototypes de logiciels.
C’est une sorte d’exutoire pour se libérer l’esprit des projets qui me traînent dans la tête.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Libre à vous de vous en emparer.&lt;/em&gt;&lt;/p&gt;</content></entry><entry><title>Exploratrices, un prototype de jeu vidéo</title><id>urn:uuid:ce225823-2cdd-5405-a7f0-2ede0274a691</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/exploratrices.html" rel="alternate" type="text/html" /><published>2023-01-26T11:17:00+01:00</published><updated>2023-03-30T19:10:00+02:00</updated><content type="html">&lt;p&gt;J’ai créé un prototype de jeu vidéo.&lt;/p&gt;
&lt;p&gt;Il s’agit d’un jeu narratif qui se joue avec des commandes textuelles.
C’est-à-dire que c’est un jeu qui se « lit » et il vous faut écrire des commandes pour jouer.
Ce gameplay est inspiré des « &lt;a href="https://fr.wikipedia.org/wiki/Multi-user_dungeon"&gt;&lt;i lang="en"&gt;Multi-user dungeon&lt;/i&gt;&lt;/a&gt; » (aussi appelés MUD).
J’étais curieux d’en créer un dans un navigateur.&lt;/p&gt;
&lt;p&gt;Il se nomme « Exploratrices » et vous y incarnez une Exploratrice qui arrive dans le village de Sylvaluna.
Le but est simplement de vous balader pour en apprendre plus sur le village en observant ses habitantes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;del&gt;Vous pouvez y jouer sur exploratrices.yuzu.ovh.&lt;/del&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;del&gt;Information importante : ce prototype ne restera en ligne qu’au maximum pendant 2 mois.&lt;/del&gt;&lt;/p&gt;
&lt;p&gt;Mise à jour : le prototype n’est plus en ligne !&lt;/p&gt;
&lt;p&gt;Il est extrêmement court.&lt;br /&gt;
Il est extrêmement simple.&lt;br /&gt;
Il est extrêmement rudimentaire.&lt;br /&gt;
Mais il est terminé, et c’est le plus important.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Je ne compte pas continuer ce prototype.
Taper des commandes n’a pas beaucoup de sens en termes de gameplay dans un jeu dont ce n’est pas le thème.
C’est même assez vite chiant dans un navigateur Web.
C’était ce que je voulais tester et je sais désormais que je veux une expérience de jeu différente.&lt;/p&gt;
&lt;p&gt;Cela étant dit, les quelques lignes de code que j’ai pu écrire pour ce projet m’ont donné plein de perspectives, y compris du multi-joueurs.
Je ne sais pas si je passerai beaucoup de temps là-dessus cette année, mais je sais que ce ne serait pas si compliqué de faire quelque chose de chouette.&lt;/p&gt;
&lt;p&gt;Et puis je me suis attaché à l’univers, j’aimerais l’explorer un peu plus à l’occasion.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Si vous voulez en apprendre plus sur le projet, j’ai tout détaillé dans le fichier README du projet.
Vous le trouverez ici : &lt;a href="https://framagit.org/marienfressinaud/exploratrices/-/blob/main/README.md"&gt;framagit.org/marienfressinaud/exploratrices&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;J’y parle des mécaniques de jeu, de la technique et même du processus d’écriture avec… ChatGPT.&lt;/p&gt;</content></entry><entry><title>Le tout premier serveur Web</title><id>urn:uuid:f1063c5d-1c06-56d9-b44e-0fa878e92077</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/le-tout-premier-serveur-web.html" rel="alternate" type="text/html" /><published>2023-01-25T17:35:00+01:00</published><updated>2023-01-25T17:35:00+01:00</updated><content type="html">&lt;p&gt;Il y a quelques jours, je suis allé à Genève et j’y ai visité le &lt;a href="https://fr.wikipedia.org/wiki/Organisation_europ%C3%A9enne_pour_la_recherche_nucl%C3%A9aire"&gt;CERN&lt;/a&gt;.
Outre des accélérateurs de particules, on y trouve cet ordinateur dans une vitrine (désolé pour la qualité de la photo) :&lt;/p&gt;
&lt;figure&gt;
    &lt;img alt="" src="images/premier-serveur-web.jpg"&gt;

    &lt;figcaption&gt;
        &lt;p&gt;Une photo du tout premier serveur Web. Un autocollant est apposé dessus où l’on peut lire (en anglais) : « Cette machine est un serveur. NE L’ÉTEIGNEZ PAS !! »&lt;/p&gt;

        &lt;p&gt;Un écriteau explique en dessous : « Cet ordinateur NeXT a été utilisé par Tim Berners-Lee, l’inventeur du &lt;i lang="en"&gt;World Wide Web&lt;/i&gt; (&lt;abbr&gt;WWW&lt;/abbr&gt;) en 1989 lorsqu’il travaillait au CERN. Ce fut le premier serveur Web. À côté se trouve une copie du document dans lequel Tim Berners-Lee proposait le &lt;i lang="en"&gt;Word Wide Web&lt;/i&gt; : "&lt;i lang="en"&gt;Information management: A proposal&lt;/i&gt;". »&lt;/p&gt;

        &lt;p&gt;Le document lui-même est illisible, mais on peut y lire une appréciation (en anglais) : « Vague mais excitant… »&lt;/p&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Ça n’a pas fait immédiatement « tilt » dans ma tête, mais c’est vertigineux de se dire que ce petit machin est si proche de nous aussi bien en termes de lieu que de temporalité.
Le Web est à peine plus vieux que moi.&lt;/p&gt;</content></entry><entry><title>Publier sa veille Flus sur Mastodon</title><id>urn:uuid:3c886588-46ae-525a-97ff-a3e3c24c614b</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/publier-sa-veille-flus-sur-mastodon.html" rel="alternate" type="text/html" /><published>2022-09-19T18:15:00+02:00</published><updated>2022-09-19T18:15:00+02:00</updated><content type="html">&lt;p&gt;Aujourd’hui, je vous explique comment publier automatiquement un flux &lt;abbr&gt;RSS&lt;/abbr&gt; (ou Atom) sur Mastodon. Cet article pointe quelques particularités liées à &lt;a href="https://flus.fr"&gt;Flus&lt;/a&gt;&lt;sup id="fnref:1"&gt;&lt;a class="footnote-ref" href="#fn:1"&gt;1&lt;/a&gt;&lt;/sup&gt;, mais la majorité des informations peuvent s’appliquer à n’importe quel flux.&lt;/p&gt;
&lt;p&gt;Pour publier un flux sur Mastodon, vous avez besoin de 3 ingrédients :&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;un flux &lt;abbr&gt;RSS&lt;/abbr&gt; (ici je vais prendre comme exemple le flux de mon profil Flus : &lt;code&gt;https://app.flus.fr/p/1670839367044869607/feed&lt;/code&gt;) ;&lt;/li&gt;
&lt;li&gt;un compte &lt;a href="https://joinmastodon.org/"&gt;Mastodon&lt;/a&gt; (forcément) ;&lt;/li&gt;
&lt;li&gt;et un outil qui va lire votre flux pour publier sur votre compte Mastodon : &lt;a href="https://github.com/edsu/feediverse"&gt;&lt;strong&gt;feediverse&lt;/strong&gt;&lt;/a&gt;&lt;sup id="fnref:2"&gt;&lt;a class="footnote-ref" href="#fn:2"&gt;2&lt;/a&gt;&lt;/sup&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;feediverse étant un outil en ligne de commande, vous devrez vous sentir suffisamment à l’aise avec cette dernière. Eh oui, cet article est un peu technique.&lt;/p&gt;
&lt;h2&gt;Installer feediverse&lt;/h2&gt;
&lt;p&gt;Pour installer feediverse, vous aurez besoin de &lt;a href="https://www.python.org/"&gt;Python&lt;/a&gt; et de la commande &lt;code&gt;pip&lt;/code&gt;. Vérifiez que &lt;code&gt;pip&lt;/code&gt; est bien installé avec la commande :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;python&lt;span class="w"&gt; &lt;/span&gt;-m&lt;span class="w"&gt; &lt;/span&gt;pip&lt;span class="w"&gt; &lt;/span&gt;--version
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Si tout va bien, il vous affichera son numéro de version. En principe &lt;code&gt;pip&lt;/code&gt; est disponible par défaut dans les dernières versions de Python. Si ce n’est pas le cas, vous pouvez suivre &lt;a href="https://pip.pypa.io/en/stable/installation/"&gt;la documentation pour l’installer.&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;Une fois cela fait, installez feediverse :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;python&lt;span class="w"&gt; &lt;/span&gt;-m&lt;span class="w"&gt; &lt;/span&gt;pip&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;feediverse
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Puis configurez-le :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;feediverse
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Il va vous demander un certain nombre d’informations ; notamment votre instance / serveur Mastodon, de quoi générer un jeton d’authentification et… l’adresse de votre flux &lt;abbr&gt;RSS&lt;/abbr&gt;.&lt;/p&gt;
&lt;h2&gt;Configurer le format des messages&lt;/h2&gt;
&lt;p&gt;Une fois cela fait, c’est presque terminé ! Vous aurez toutefois peut-être envie de configurer le format des messages postés sur Mastodon. Ouvrez le fichier de configuration &lt;code&gt;~/.feediverse&lt;/code&gt; dans un éditeur de texte et adaptez la propriété &lt;code&gt;template&lt;/code&gt; à votre convenance. Par exemple :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nt"&gt;feeds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;{title}&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;{link}&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;#veille&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;https://app.flus.fr/p/1670839367044869607/feed&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Les liens (i.e. &lt;code&gt;{link}&lt;/code&gt;) pointeront vers la page de vos commentaires Flus. Si vous préférez toutefois que les liens pointent directement vers les sites, vous pouvez modifier l’&lt;abbr&gt;URL&lt;/abbr&gt; de votre flux en ajoutant le paramètre &lt;code&gt;?direct=true&lt;/code&gt; (exemple : &lt;code&gt;https://app.flus.fr/p/1670839367044869607/feed?direct=true&lt;/code&gt;).&lt;/p&gt;
&lt;h2&gt;Exécuter feediverse&lt;/h2&gt;
&lt;p&gt;Il ne vous reste plus qu’à lancer feediverse pour qu’il poste sur Mastodon :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;feediverse
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Pour l’exécuter automatiquement à intervalle régulier, créez une tâche Cron (&lt;code&gt;crontab -e&lt;/code&gt;) :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;*/15 &lt;span class="gs"&gt;* *&lt;/span&gt; * * /home/USER/.local/bin/feediverse
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Vous devrez probablement mettre le chemin absolu vers la commande (comme dans l’exemple ci-dessus). Vous le trouverez avec cette commande :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;whereis&lt;span class="w"&gt; &lt;/span&gt;feediverse
&lt;span class="go"&gt;feediverse: /home/USER/.local/bin/feediverse&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;Bonus : Publier les liens Flus ET directs&lt;/h2&gt;
&lt;p&gt;Si vous voulez publier à la fois les liens vers vos commentaires Flus et vers les articles pointés, il existe une méthode. Mais attention, il va falloir se relever les manches du clavier et traficoter directement dans le code de feediverse&lt;sup id="fnref:3"&gt;&lt;a class="footnote-ref" href="#fn:3"&gt;3&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;Commencez par trouver où il a été installé :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;python&lt;span class="w"&gt; &lt;/span&gt;-m&lt;span class="w"&gt; &lt;/span&gt;pip&lt;span class="w"&gt; &lt;/span&gt;show&lt;span class="w"&gt; &lt;/span&gt;feediverse&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;grep&lt;span class="w"&gt; &lt;/span&gt;Location
&lt;span class="go"&gt;Location: /home/USER/.local/lib/python3.10/site-packages&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Ouvrez ensuite le fichier &lt;code&gt;/home/USER/.local/lib/python3.10/site-packages/feediverse.py&lt;/code&gt; dans un éditeur de texte.&lt;/p&gt;
&lt;p&gt;Trouvez la ligne &lt;code&gt;def get_entry(entry):&lt;/code&gt; (ligne 85 chez moi), puis, quelques lignes plus bas, le &lt;code&gt;return { … }&lt;/code&gt;. Entre les accolades, ajoutez cette ligne :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;# ...&lt;/span&gt;
    &lt;span class="s2"&gt;&amp;quot;links&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;links&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Éditez maintenant le format de votre message (dans &lt;code&gt;~/.feediverse&lt;/code&gt;) :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nt"&gt;feeds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;{title}\nLien&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;:&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;{links[1].href}\nCommentaires&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;:&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;{links[0].href}\n#veille&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;https://app.flus.fr/p/1670839367044869607/feed.atom.xml&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Veillez à bien supprimer le paramètre &lt;code&gt;?direct=true&lt;/code&gt; de l’adresse du flux.&lt;/p&gt;
&lt;p&gt;Normalement, les prochains messages postés par feediverse sur votre compte Mastodon devraient contenir un lien vers Flus et un lien vers les articles pointés.&lt;/p&gt;
&lt;div class="footnote"&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;Je pensais initialement publier cet article dans le &lt;a href="https://flus.fr/carnet"&gt;carnet de Flus&lt;/a&gt;. Finalement, la méthode que je présente ici étant trop technique à mon goût et nécessitant l’utilisation de la ligne de commande, je me rabats sur mon blog perso.&amp;#160;&lt;a class="footnote-backref" href="#fnref:1" title="Jump back to footnote 1 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:2"&gt;
&lt;p&gt;Il existe aussi &lt;a href="https://gitlab.com/chaica/feed2toot/"&gt;feed2toot&lt;/a&gt;, mais je trouve son installation beaucoup plus compliquée.&amp;#160;&lt;a class="footnote-backref" href="#fnref:2" title="Jump back to footnote 2 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:3"&gt;
&lt;p&gt;J’ai ouvert une &lt;a href="https://github.com/edsu/feediverse/pull/30"&gt;&lt;i lang="en"&gt;pull request&lt;/i&gt;&lt;/a&gt; pour que la modification soit intégrée directement dans feediverse, mais le projet semble en sommeil.&amp;#160;&lt;a class="footnote-backref" href="#fnref:3" title="Jump back to footnote 3 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</content></entry><entry><title>Du plaisir de publier</title><id>urn:uuid:3d02affd-de32-50f3-a806-52d45d4283e8</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/du-plaisir-de-publier.html" rel="alternate" type="text/html" /><published>2022-06-22T20:14:00+02:00</published><updated>2022-06-22T20:14:00+02:00</updated><content type="html">&lt;p&gt;Depuis quelques mois, j’écris tous les jours.
C’est parfois seulement un ou deux paragraphes ;
souvent des notes écrites à la va-vite.
L’exercice est quotidien et je m’y applique sans grand effort.&lt;/p&gt;
&lt;p&gt;J’ai en revanche abandonné mes &lt;a href="publier-souvent.html"&gt;publications journalières&lt;/a&gt;.
J’ai essayé un rythme moins soutenu, mais je n’étais pas plus assidu.
Le plaisir n’y était pas.&lt;/p&gt;
&lt;p&gt;Je n’ai jamais pris le sujet de la publication très au sérieux.
Ça n’a toujours été qu’une étape pénible entre l’écriture et le fait d’être lu.
Publier est une étape exigeante.
C’est en la considérant comme telle que j’y trouverai du plaisir.&lt;/p&gt;</content></entry><entry><title>Supprimer ses comptes</title><id>urn:uuid:34b26b20-2f4b-5e93-adca-edbeac2a3061</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/supprimer-ses-comptes.html" rel="alternate" type="text/html" /><published>2022-05-13T17:11:00+02:00</published><updated>2022-05-13T17:11:00+02:00</updated><content type="html">&lt;p&gt;J’ai entrepris depuis quelques semaines de supprimer les comptes en ligne que je n’utilise plus.&lt;/p&gt;
&lt;p&gt;Pour cela, je pioche dans ma liste d’identifiants stockés dans mon gestionnaire de mots de passe (&lt;a href="https://bitwarden.com/"&gt;Bitwarden&lt;/a&gt;), je me connecte, je trouve l’endroit pour supprimer mon compte et je confirme.&lt;/p&gt;
&lt;p&gt;Ça, c’est quand ça se passe bien. À la louche, je dirais que c’est ce qu’il se passe deux fois sur trois. Le reste du temps, il me faut :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;passer par un formulaire de contact ;&lt;/li&gt;
&lt;li&gt;fouiller dans les mentions légales pour dénicher une adresse de contact (idéalement le &lt;abbr&gt;DPO&lt;/abbr&gt;) ;&lt;/li&gt;
&lt;li&gt;abandonner, tout simplement.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Lorsque je fais une demande, je mets à jour l’enregistrement dans Bitwarden pour préciser « (suppression demandée le XX/YY/ZZZZ) ». Souvent, je n’obtiens pas de réponse.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;On n’insistera jamais assez : si vous proposez ou imposez la création d’un compte en ligne, permettez également sa suppression dans des conditions satisfaisantes (un bouton dans une section « profil » ou « compte » fait l’affaire).&lt;/strong&gt;&lt;/p&gt;</content></entry><entry><title>Questions d’entretien</title><id>urn:uuid:b879645f-9031-58c3-a583-0ffe0a7494d6</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/questions-entretien.html" rel="alternate" type="text/html" /><published>2022-05-11T10:23:00+02:00</published><updated>2022-05-11T10:23:00+02:00</updated><content type="html">&lt;p&gt;J’ai passé un entretien il y a quelques jours. Je liste ci-dessous quelques questions que j’ai posées :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;quel est le modèle économique de l’entreprise ?&lt;/li&gt;
&lt;li&gt;par qui / comment les clients sont-ils choisis et démarchés ?&lt;/li&gt;
&lt;li&gt;arrive-t-il de travailler avec des clients parce que l’entreprise n’a pas le choix de faire autrement ?&lt;/li&gt;
&lt;li&gt;combien de personnes travaillent dans l’entreprise ?&lt;/li&gt;
&lt;li&gt;quelle est l’ancienneté moyenne des salarié·es ?&lt;/li&gt;
&lt;li&gt;quels sont les métiers exercés dans l’entreprise ?&lt;/li&gt;
&lt;li&gt;comment les personnes communiquent-elles entre elles ?&lt;/li&gt;
&lt;li&gt;vais-je travailler en équipe ?&lt;/li&gt;
&lt;li&gt;un mi-temps est-il possible ?&lt;/li&gt;
&lt;li&gt;combien serai-je payé ?&lt;/li&gt;
&lt;li&gt;de quelle convention collective dépend l’entreprise ?&lt;/li&gt;
&lt;li&gt;quels sont les avantages apportés par l’entreprise ?&lt;/li&gt;
&lt;li&gt;le télétravail est-il possible ?&lt;/li&gt;
&lt;li&gt;y a-t-il une flexibilité sur les horaires de travail ?&lt;/li&gt;
&lt;li&gt;comment sont organisés les entretiens annuels ?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Par ailleurs, on m’a parlé de &lt;a href="https://www.societe.ninja/"&gt;societe.ninja&lt;/a&gt; qui permet de retrouver toutes les informations publiques des entreprises, incluant notamment les comptes et les actes officiels. Ça peut aider à préparer son entretien. L’outil derrière est &lt;a href="https://git.cybertron.fr/lionel.vest/societe.ninja"&gt;libre&lt;/a&gt;, sous licence &lt;abbr&gt;AGPL&lt;/abbr&gt;.&lt;/p&gt;</content></entry><entry><title>Routines</title><id>urn:uuid:69ec5dcf-ecfd-567b-874e-d630dfe36f42</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/routines.html" rel="alternate" type="text/html" /><published>2022-04-25T20:15:00+02:00</published><updated>2022-04-25T20:15:00+02:00</updated><content type="html">&lt;p&gt;L’année dernière, j’ai commencé à m’organiser avec des routines. Le principe est de me donner de courtes tâches à faire de manière régulière. Cela m’a permis de m’assurer que mes tâches administratives étaient bien faites, ou mes plantes bien arrosées par exemple.&lt;/p&gt;
&lt;p&gt;Au début, tout était stocké dans un wiki. Il y a 2 mois et demi, j’ai poussé le principe un peu plus loin en les organisant dans un tableur. Ce changement m’a permis principalement d’ajouter la date de la dernière fois à laquelle j’effectue chaque tâche. Cette information, combinée à la fréquence (ex. 1, 7, 30 jours), permet d’afficher chaque jour les routines que j’ai à faire, ou celles qui prennent du retard.&lt;/p&gt;
&lt;p&gt;Par rapport au wiki, ce système a plusieurs avantages :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;présentation plus adaptée, je vois toutes les routines en un coup d’œil, c’est plus agréable ;&lt;/li&gt;
&lt;li&gt;facile d’accès (2 clics) et accessible hors-ligne, je l’ai donc toujours sous les yeux et je ne l’oublie pas ;&lt;/li&gt;
&lt;li&gt;facile de modifier, je peux ajouter (ou supprimer) plus aisément de nouvelles routines, j’y gère donc plus de choses ;&lt;/li&gt;
&lt;li&gt;le tableur me demande d’être actif pour modifier les dates, je suis donc amené à l’utiliser quotidiennement ;&lt;/li&gt;
&lt;li&gt;en récompense visuelle, le tableur me montre en vert ce que j’ai fait dans la journée, ça me motive à réaliser mes routines.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Je ne crois généralement pas aux solutions magiques d’organisation, mais je suis particulièrement content de ce système. En revanche, il ne permet pas de se motiver à faire les choses pour lesquelles on traîne des pieds (comprendre « ça ne m’a pas motivé à &lt;a href="publier-souvent.html"&gt;publier tous les jours&lt;/a&gt; »).&lt;/p&gt;
&lt;p&gt;En bref, je n’aurai jamais autant pris soin de mon dos, nettoyé mon appartement ou appelé mes parents que ces derniers mois. C’est pas mal, non ?&lt;/p&gt;</content></entry><entry><title>Lessy est terminé</title><id>urn:uuid:1eee93e8-6553-55f1-9e30-009bcd9abdd4</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/lessy-est-termine.html" rel="alternate" type="text/html" /><published>2022-04-12T10:18:00+02:00</published><updated>2022-04-12T10:18:00+02:00</updated><content type="html">&lt;p&gt;Lessy &lt;del&gt;est&lt;/del&gt; était un gestionnaire de temps mettant à disposition une liste de tâches et un gestionnaire de projets.&lt;/p&gt;
&lt;p&gt;Il y a un an, &lt;a href="des-nouvelles-de-lessy.html"&gt;j’écrivais&lt;/a&gt; :&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;En l’état, Lessy m’est en fait relativement peu utile. […] Ma manière de gérer mes tâches a évolué et j’arrive la plupart du temps à me contenter d’un bout de papier […].&lt;/p&gt;
&lt;p&gt;Lessy, dans sa version actuelle, correspond en fait pas mal à ce que je souhaitais avoir quand j’ai commencé son développement. […]&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tout bien pensé, je crois que Lessy est terminé.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Depuis, rien n’a vraiment changé. Je gère toujours mes tâches sur un bout de papier, aidé en plus par un mécanisme de routines qui ne nécessite que d’une feuille de tableur (je vous en reparle prochainement). Je continue également de penser que Lessy, dans sa forme actuelle, correspond à ce que j’imaginais initialement et qu’il n’a plus besoin de changer.&lt;/p&gt;
&lt;p&gt;Le problème, c’est que je ne savais pas trop quoi faire de lui. &lt;strong&gt;En octobre dernier, j’ai décidé de fermer les inscriptions sur &lt;a href="https://lessy.yuzu.ovh"&gt;lessy.yuzu.ovh&lt;/a&gt;.&lt;/strong&gt; C’était déjà un petit soulagement.&lt;/p&gt;
&lt;p&gt;Mais que faire alors du code existant ? Initialement, je pensais &lt;a href="terminer-ses-projets.html"&gt;terminer&lt;/a&gt; Lessy proprement en n’ajoutant plus de fonctionnalités, mais en continuant de mettre à jour les dépendances logicielles afin d’éviter des failles de sécurité. Mais je dois vous avouer que je n’en suis plus capable. Les dépendances JavaScript sont une véritable plaie à maintenir avec des trucs qui pètent dans tous les sens à chaque mise à jour. C’est une charge que je n’ai pas envie de gérer.&lt;/p&gt;
&lt;p&gt;Finalement, j’ai décidé de clore et archiver &lt;a href="https://github.com/lessy-community/lessy"&gt;le dépôt de code&lt;/a&gt; un peu plus sauvagement. Le fichier README a été mis à jour pour expliquer que le projet n’est plus maintenu. &lt;strong&gt;Je continuerai de maintenir le service &lt;a href="https://lessy.yuzu.ovh"&gt;lessy.yuzu.ovh&lt;/a&gt; ouvert tant que des gens l’utiliseront&lt;/strong&gt; (et il y en a !) ; les inscriptions, elles, resteront fermées.&lt;/p&gt;
&lt;p&gt;Je suis très heureux d’avoir bossé sur Lessy avec lequel j’aurai appris plein de choses. Mais je suis encore plus content de pouvoir annoncer qu’il est terminé et ainsi de ne plus avoir à m’en soucier 🙂&lt;/p&gt;</content></entry><entry><title>Courriel et page de contact</title><id>urn:uuid:e7d48f26-af94-5bff-9747-9502e11d2967</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/page-de-contact.html" rel="alternate" type="text/html" /><published>2022-04-11T18:15:00+02:00</published><updated>2022-04-11T18:15:00+02:00</updated><content type="html">&lt;p&gt;Il y a 2 mois, une entreprise travaillant dans le &lt;abbr&gt;RGPD&lt;/abbr&gt; m’a informé avoir collecté mon adresse courriel personnelle.&lt;/p&gt;
&lt;p&gt;Je les ai donc contactés pour savoir pourquoi et comment ils l’avaient collectée. Ils m’ont répondu créer un annuaire de sociétés françaises à partir de données publiques à des fins marketing. Ils m’ont également précisé que « [mon] adresse commençant par le mot "contact", cette dernière rentre dans le cadre des adresses email génériques ».&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Mon adresse se terminant en "@prénomnom.fr", elle n’est évidemment pas du tout générique.&lt;/strong&gt; De plus, le concept d’adresse générique ne s’applique que dans un cadre &lt;i lang="en"&gt;B to B&lt;/i&gt; ; jusqu’à preuve du contraire, je ne suis pas une entreprise&lt;sup id="fnref:1"&gt;&lt;a class="footnote-ref" href="#fn:1"&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;Pour m’assurer que les choses soient claires, j’ai donc créé &lt;a href="contact.html"&gt;une page de contact&lt;/a&gt; qui indique mon adresse tout en précisant que je refuse le démarchage commercial et que je refuse qu’elle soit stockée. J’ai également pris soin de virer l’adresse de toutes les autres pages du site afin qu’elle ne soit pas séparée de mes conditions.&lt;/p&gt;
&lt;p&gt;Je ne suis pas naïf : ce genre d’entreprises collecte les adresses automatiquement et ne vérifient rien du tout manuellement. Mais je pourrai au moins leur mettre le nez dans leur caca désormais.&lt;/p&gt;
&lt;div class="footnote"&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;En revanche ma micro-entreprise porte mon nom, ce que je trouve hyper relou. D’un point de vue &lt;abbr&gt;RGPD&lt;/abbr&gt;, c’est naze.&amp;#160;&lt;a class="footnote-backref" href="#fnref:1" title="Jump back to footnote 1 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</content></entry><entry><title>Logiciel libre et gratuit</title><id>urn:uuid:8577924a-0cbe-53e8-8059-84fb506970ce</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/logiciel-libre-et-gratuit.html" rel="alternate" type="text/html" /><published>2022-03-29T15:33:00+02:00</published><updated>2022-03-29T15:33:00+02:00</updated><content type="html">&lt;p&gt;On lit ou entend régulièrement&lt;sup id="fnref:1"&gt;&lt;a class="footnote-ref" href="#fn:1"&gt;1&lt;/a&gt;&lt;/sup&gt; qu’il y a confusion entre logiciel « libre » et « gratuit ». Il est alors généralement précisé qu’un logiciel libre n’est pas forcément gratuit, que cela viendrait du double sens en anglais du terme « &lt;i lang="en"&gt;free&lt;/i&gt; » (signifiant à la fois « libre » et « gratuit »).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Si je comprends la confusion dans le monde anglophone, cela ne l’explique pas ailleurs où le double sens n’existe pas.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Hypothèse toute bête : si le grand public se méprend souvent sur le caractère &lt;em&gt;nécessairement&lt;/em&gt; gratuit du logiciel libre, c’est tout simplement que les logiciels libres le sont dans leur très grande majorité.&lt;/p&gt;
&lt;p&gt;Réflexion supplémentaire : la gratuité ne facilite-t-elle pas la liberté en garantissant l’accès aux logiciels pour les budgets les plus serrés ? Ne ferait-on pas mieux de revendiquer ce caractère plutôt que de s’en défendre ?&lt;/p&gt;
&lt;div class="footnote"&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;J’abuse un peu parce que je ne le lis plus tant que ça. Je l’ai seulement revu récemment — je ne sais plus où – et ça me trotte dans la tête depuis.&amp;#160;&lt;a class="footnote-backref" href="#fnref:1" title="Jump back to footnote 1 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</content></entry><entry><title>Préparer les 10 ans de FreshRSS</title><id>urn:uuid:fb2f6132-18f9-5455-9fc1-d5f283c359ad</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/preparer-les-10-ans-de-freshrss.html" rel="alternate" type="text/html" /><published>2022-03-28T11:53:00+02:00</published><updated>2022-03-28T11:53:00+02:00</updated><content type="html">&lt;p&gt;&lt;a href="https://freshrss.org"&gt;FreshRSS&lt;/a&gt; va avoir 10 ans en octobre. J’aimerais célébrer ça d’une manière ou d’une autre, mais j’ai peur de me lancer dans quelque chose de trop grand pour moi. Je pensais simplement revoir le site pour le rendre plus attractif et ajouter des informations manquantes.&lt;/p&gt;
&lt;p&gt;J’ai ouvert une discussion &lt;a href="https://github.com/FreshRSS/FreshRSS/discussions/4294"&gt;sur GitHub&lt;/a&gt; pour que d’autres personnes puissent s’exprimer et éventuellement faire des choses ensemble.&lt;/p&gt;</content></entry><entry><title>Boop! 1.0</title><id>urn:uuid:c18736ea-428c-5f18-b0cc-d807454a4caa</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/boop-1.0.html" rel="alternate" type="text/html" /><published>2022-03-17T11:50:00+01:00</published><updated>2022-03-17T11:50:00+01:00</updated><content type="html">&lt;p&gt;Il était temps de le faire : &lt;strong&gt;je viens de sortir la version 1.0 de Boop!, mon générateur personnel de sites statiques.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Si je dis qu’il était temps de le faire, c’est que je considère qu’il est terminé depuis octobre dernier. Terminé, cela signifie que je ne compte plus ajouter de grosses fonctionnalités et limiter le polissage au strict minimum. Les bugs et failles de sécurité continueront d’être corrigées. Comme je l’ai dit dans un article plus ancien : s’il manque des choses, ce sont pour d’autres besoins que les miens.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bref, Boop! est stable.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Depuis la version 0.4 sortie en novembre 2019 (!), peu de choses ont été ajoutées :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;la possibilité d’exclure des articles de la page principale du blog (et de son flux) ;&lt;/li&gt;
&lt;li&gt;l’activation de toutes les extensions Markdown « &lt;a href="https://python-markdown.github.io/extensions/extra/"&gt;extra&lt;/a&gt; » ;&lt;/li&gt;
&lt;li&gt;le support des hubs &lt;a href="https://fr.wikipedia.org/wiki/WebSub"&gt;Websub&lt;/a&gt; pour les flux Atom ;&lt;/li&gt;
&lt;li&gt;la génération d’une page « &lt;a href="https://fr.wikipedia.org/wiki/Plan_de_site"&gt;sitemap&lt;/a&gt; » ;&lt;/li&gt;
&lt;li&gt;l’ajout d’un &lt;i lang="en"&gt;warning&lt;/i&gt; si aucun &lt;abbr&gt;UUID&lt;/abbr&gt; n’a été précisé dans la configuration ;&lt;/li&gt;
&lt;li&gt;et la vérification que plusieurs pages/articles ne s’écrasent pas les uns les autres.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;S’agissant d’un projet pensé par et pour moi, je ne vous invite pas à l’utiliser : &lt;strong&gt;les chances sont grandes pour qu’il ne vous convienne pas.&lt;/strong&gt; S’il vous prenait toutefois l’envie de jouer avec, la documentation devrait désormais être complète.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Vous trouverez &lt;a href="https://framagit.org/marienfressinaud/boop"&gt;le code et la documentation de Boop! sur Framagit.&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;</content></entry><entry><title>Projets secondaires</title><id>urn:uuid:6c960a02-9ba1-5233-b551-dd8e90f33acf</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/projets-secondaires.html" rel="alternate" type="text/html" /><published>2022-03-15T10:42:00+01:00</published><updated>2022-03-15T10:42:00+01:00</updated><content type="html">&lt;p&gt;J’accumule les projets secondaires depuis des années, principalement des bouts de code. J’ai expliqué il y a quelques semaines avoir commencé à « &lt;a href="terminer-ses-projets.html"&gt;terminer&lt;/a&gt; » ces projets, mais je n’avais pas de recul sur ce qu’il me restait à faire. Je me suis donc créé un document synthétique :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;13 sont déjà terminés / archivés ;&lt;/li&gt;
&lt;li&gt;10 pourraient l’être assez rapidement ;&lt;/li&gt;
&lt;li&gt;3 de plus seront amenés à l’être à moyen terme.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Il me resterait, en gros, 3 projets à maintenir (dont &lt;a href="https://gdpr-txt.org"&gt;GDPR.txt&lt;/a&gt;), auxquels s’ajoutent la maintenance de différents sites ainsi que… tout ce que je fais dans le cadre de &lt;a href="https://flus.fr"&gt;Flus&lt;/a&gt; et &lt;a href="https://framasoft.org"&gt;Framasoft&lt;/a&gt;, voire &lt;a href="https://freshrss.org"&gt;FreshRSS&lt;/a&gt; dans une moindre mesure. Bref, ça représente encore un peu de taf.&lt;/p&gt;
&lt;p&gt;J’ai (quasiment) tout déplacé de GitHub vers Framagit, vous trouverez donc (quasiment) tous ces projets &lt;a href="https://framagit.org/users/marienfressinaud/projects"&gt;sur ce dernier&lt;/a&gt;. Une fois que j’aurai fini d’archiver ce qui peut l’être, je pense que je créerai une page dédiée sur ce site : certains projets mériteraient mieux qu’un dépôt de code perdu dans un coin.&lt;/p&gt;</content></entry><entry><title>Sur l’objectif du GDPR.txt</title><id>urn:uuid:7f2d6c15-1878-5f75-9ca8-4a51cdc226e0</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/objectif-gdpr-txt.html" rel="alternate" type="text/html" /><published>2022-03-10T12:10:00+01:00</published><updated>2022-03-10T12:10:00+01:00</updated><content type="html">&lt;p&gt;J’ai publié &lt;a href="https://framablog.org/2022/03/08/faciliter-la-conformite-rgpd-le-fichier-gdpr-txt/"&gt;un article sur le Framablog&lt;/a&gt; pour présenter le fichier GDPR.txt (présenté &lt;a href="gdpr-txt.html"&gt;ici&lt;/a&gt; il y a quelques jours). Les premiers retours n’ont pas tardé, ainsi qu’une incompréhension majeure : celle de l’objectif même de ce fichier… c’est embêtant ! Cette incompréhension s’exprime sous la forme de deux suggestions :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;que le fichier soit placé sous une &lt;abbr&gt;URL&lt;/abbr&gt; de type &lt;code&gt;/.well-known/&lt;/code&gt; ;&lt;/li&gt;
&lt;li&gt;que le fichier utilise un format structuré existant (ex. YAML).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;i lang="la"&gt;In fine&lt;/i&gt;, il est demandé à ce que ce fichier soit facilement accessible à un navigateur — ou autre logiciel — afin d’exposer les informations de conformité &lt;abbr&gt;RGPD&lt;/abbr&gt; des sites. Je le redis ici : ce n’est pas la proposition que j’ai faite.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ma proposition est de mutualiser le travail de recherche des informations en laissant aux développeurs et développeuses le soin de déclarer les données et finalités de leurs logiciels.&lt;/strong&gt; C’est un fichier écrit par des humains, à destination d’autres humains ; de la documentation en somme.&lt;/p&gt;
&lt;p&gt;Cela étant dit, je trouve qu’un fichier standardisé sous &lt;code&gt;/.well-known/&lt;/code&gt; serait une excellente idée : c’est celle que j’avais en tête en commençant à travailler sur le &lt;abbr&gt;RGPD&lt;/abbr&gt; à Framasoft d’ailleurs 😊 Pourquoi ma proposition est différente alors ?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;dans l’immédiat ça ne nous aide pas à Framasoft et on a décidé de viser la conformité en priorité ;&lt;/li&gt;
&lt;li&gt;je ne veux pas proposer un tel format sans l’avis d’un ou une juriste spécialisée ;&lt;/li&gt;
&lt;li&gt;je n’ai pas l’énergie de m’occuper de ça (pour l’instant).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Ça viendra donc peut-être un jour, surtout si d’autres personnes s’emparent du sujet (et je vous y invite fortement !)&lt;/strong&gt; Je veux d’ailleurs bien servir de relais entre ces personnes.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Pour creuser l’incompréhension, j’ai identifié trois raisons :&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;les personnes qui se sont intéressées au fichier sont des personnes qui cherchent elles-mêmes à se conformer au &lt;abbr&gt;RGPD&lt;/abbr&gt;, pas nécessairement des développeurs et développeuses (qui sont ma cible principale) ;&lt;/li&gt;
&lt;li&gt;le nom même rappelle le fichier « robots.txt » qui est un fichier à destination de machines et non d’humains ;&lt;/li&gt;
&lt;li&gt;j’ai proposé un format pseudo-structuré, alors qu’un format libre aurait été largement suffisant (puisqu’on est plus sur de la documentation qu’autre chose).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Ma proposition serait donc de virer toute la partie structuration du fichier et de concentrer mes explications sur comment bien remplir le fichier. Je pense également laisser libre le format du fichier (&lt;code&gt;GDPR.md&lt;/code&gt; serait tout aussi bien par exemple).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;→ Je suis &lt;a href="https://framagit.org/marienfressinaud/gdpr-txt/-/issues"&gt;preneur de vos suggestions et remarques sur le sujet.&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;</content></entry><entry><title>Spam 2</title><id>urn:uuid:0cd18ebe-2bd1-5f71-8695-035af93b1ace</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/spam-2.html" rel="alternate" type="text/html" /><published>2022-03-07T12:55:00+01:00</published><updated>2022-03-07T12:55:00+01:00</updated><content type="html">&lt;p&gt;Je découvre une nouvelle forme de spam :&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;le spammeur s’inscrit sur un site random avec mon adresse courriel ;&lt;/li&gt;
&lt;li&gt;il met son message de spam avec un lien vers son site dans le champ nom d’utilisateur (ou autre) ;&lt;/li&gt;
&lt;li&gt;je reçois le courriel de confirmation de compte, incluant un récapitulatif des infos, donc le message de spam.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;J’imagine que ce mécanisme permet de passer à travers un certain nombre d’antispams puisque l’envoyeur du courriel est légitime (bon, en l’occurrence le serveur d’envoi semble mal configuré et le message a quand même été marqué comme spam).&lt;/p&gt;
&lt;p&gt;Finalement, ce qui me saoule le plus c’est que je me trouve inscrit de force sur un site allemand « spécialiste de la fourniture d’embrayages, de freins et de disques » dont je n’ai que faire.&lt;/p&gt;</content></entry><entry><title>Sélection d’articles</title><id>urn:uuid:cf17e94a-7849-540a-bf16-a889e6fcc152</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/selection-articles.html" rel="alternate" type="text/html" /><published>2022-03-06T19:00:00+01:00</published><updated>2022-03-06T19:00:00+01:00</updated><content type="html">&lt;p&gt;J’ai fait le choix de ne pas lister tous mes articles sur &lt;a href="blog.html"&gt;la page du blog&lt;/a&gt;. La liste est limitée à un maximum de 20 articles et remonte jusqu’à 6 mois en arrière.&lt;/p&gt;
&lt;p&gt;Certains articles plus vieux méritent tout de même de rester en première page, parce que je les aime bien, ou parce qu’ils marquent une étape importante dans mon parcours. Je veux garder cette sélection à un maximum de 10 articles.&lt;/p&gt;
&lt;p&gt;Jusqu’ici, tout allait bien. Mais depuis que &lt;a href="publier-souvent.html"&gt;je publie plus souvent&lt;/a&gt;, je me demande si je ne vais pas avoir besoin de critères supplémentaires… ou être plus souple sur la limite ?&lt;/p&gt;</content></entry><entry><title>Joué, vu, écouté, publié, lu (février 2022)</title><id>urn:uuid:3f09493c-307c-52d9-b106-b2bc97368233</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/2022-02-joue-vu-ecoute-publie-lu.html" rel="alternate" type="text/html" /><published>2022-03-04T14:39:00+01:00</published><updated>2022-03-04T14:39:00+01:00</updated><content type="html">&lt;p&gt;Joué à &lt;a href="https://www.supergiantgames.com/games/hades"&gt;Hadès&lt;/a&gt; en pointillé. J’ai quelque 340 heures de jeu dessus, mais je continue d’y trouver du plaisir (et de nouvelles lignes de dialogues !) Vraiment un très bon jeu. Officiellement le jeu auquel j’ai le plus joué sur Switch, devant &lt;a href="https://www.zelda.com/breath-of-the-wild/"&gt;&lt;i lang="en"&gt;Zelda Breath of the Wild&lt;/i&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Vu « &lt;a href="https://blogs.mediapart.fr/media-crash/blog/030222/media-crash-qui-tue-le-debat-public-mediapart-au-cinema-partir-du-16-fevrier"&gt;Media Crash, qui a tué le débat public ?&lt;/a&gt; » de Mediapart. Je n’ai pas l’impression d’avoir appris grand-chose, je ne sais pas si j’étais le public visé. Ça reste une analyse indispensable sur la concentration des médias.&lt;/p&gt;
&lt;p&gt;Écouté Dido, Coldplay, Muse et Pink une bonne partie du mois : l’impression d’être retombé dans mes années lycée. C’est l’effet &lt;a href="lollypop.html"&gt;Lollypop&lt;/a&gt; et c’était pas désagréable.&lt;/p&gt;
&lt;p&gt;Publié « &lt;a href="pour-batir-un-morceau-de-web.html"&gt;Pour bâtir un morceau de Web&lt;/a&gt; ». C’est un article qui me trottait dans la tête depuis un moment et j’en suis content. J’ai malgré tout eu du mal à l’écrire, avec notamment une réécriture de zéro.&lt;/p&gt;
&lt;p&gt;Lu « &lt;a href="https://www.bookstackapp.com/blog/contributing-to-open-source/"&gt;&lt;i lang="en"&gt;Contributing to BookStack (And Open Source)&lt;/i&gt;&lt;/a&gt; » (en anglais). C’est un bon guide qui fait le tour des différentes contributions possibles autour d’un projet open-source. &lt;/p&gt;</content></entry><entry><title>Publier un README sous forme de site Web</title><id>urn:uuid:506ad92b-af49-5706-a7cc-7383d5070919</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/readme-vers-site-web.html" rel="alternate" type="text/html" /><published>2022-03-02T23:49:00+01:00</published><updated>2022-03-02T23:49:00+01:00</updated><content type="html">&lt;p&gt;J’ai parlé l’autre jour de mon initiative de fichier &lt;a href="gdpr-txt.html"&gt;GDPR.txt&lt;/a&gt;. J’ai publié un site ce soir pour présenter tout ça : &lt;a href="https://gdpr-txt.org"&gt;gdpr-txt.org&lt;/a&gt;. J’ai saisi l’occasion pour réfléchir à la manière la plus simple que j’avais de publier ce site. &lt;strong&gt;En trois mots : un fichier README, Pandoc et GitLab.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Le fichier README contient le contenu de mon site au format Markdown. C’est donc un site simple qui ne contient qu’une seule page. Pour commencer, ça me suffit amplement.&lt;/p&gt;
&lt;p&gt;Pour le mettre en ligne, j’ai besoin de le transformer en &lt;abbr&gt;HTML&lt;/abbr&gt;. Il existe des tas de solutions à base de générateur de sites statiques, mais je voulais un truc encore plus simple. J’ai un petit faible pour &lt;a href="https://pandoc.org/"&gt;Pandoc&lt;/a&gt;, le couteau-suisse des convertisseurs de documents. La commande est simple :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;pandoc&lt;span class="w"&gt; &lt;/span&gt;--output&lt;span class="o"&gt;=&lt;/span&gt;index.html&lt;span class="w"&gt; &lt;/span&gt;README.md
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Pandoc va lire le fichier &lt;code&gt;README.md&lt;/code&gt; et générer un fichier &lt;code&gt;index.html&lt;/code&gt;. On peut également préciser un template à Pandoc, afin qu’il génère un &lt;abbr&gt;HTML&lt;/abbr&gt; plus complet :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;pandoc&lt;span class="w"&gt; &lt;/span&gt;--output&lt;span class="o"&gt;=&lt;/span&gt;index.html&lt;span class="w"&gt; &lt;/span&gt;--template&lt;span class="o"&gt;=&lt;/span&gt;template.html&lt;span class="w"&gt; &lt;/span&gt;README.md
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Le fichier &lt;code&gt;template.html&lt;/code&gt; n’est pas très compliqué à écrire&lt;sup id="fnref:1"&gt;&lt;a class="footnote-ref" href="#fn:1"&gt;1&lt;/a&gt;&lt;/sup&gt; :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;html&lt;/span&gt; &lt;span class="na"&gt;lang&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;en&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;meta&lt;/span&gt; &lt;span class="na"&gt;charset&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;UTF-8&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;title&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;GDPR.txt&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;title&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;meta&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;viewport&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;width=device-width, initial-scale=1.0&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;style&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nt"&gt;html&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;#2b0e44&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="kt"&gt;px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;line-height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1.3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;#fefcfe&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nt"&gt;main&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;max-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;700&lt;/span&gt;&lt;span class="kt"&gt;px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;margin-right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;margin-left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;padding-top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="kt"&gt;rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;padding-bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="kt"&gt;rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;#8445bc&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nd"&gt;hover&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;#793aaf&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;style&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;main&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            $body$
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;main&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;html&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Notez que j’ai décidé d’embarquer un peu de &lt;abbr&gt;CSS&lt;/abbr&gt; directement dans mon template pour éviter de m’encombrer d’un fichier supplémentaire. Ce sera un choix à revoir si le style devient plus complexe.&lt;/p&gt;
&lt;p&gt;Il ne reste plus qu’à mettre ce &lt;abbr&gt;HTML&lt;/abbr&gt; en ligne. Mon dépôt de code se trouve sur &lt;a href="https://framagit.org/"&gt;Framagit&lt;/a&gt;, une instance de GitLab. Celui-ci met à disposition un système pour publier facilement des sites statiques en ligne : &lt;a href="https://docs.gitlab.com/ee/user/project/pages/"&gt;GitLab Pages&lt;/a&gt;. Il suffit de créer un fichier &lt;code&gt;.gitlab-ci.yml&lt;/code&gt; et de lui faire générer le site dans un répertoire nommé &lt;code&gt;public/&lt;/code&gt; :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;

&lt;span class="nt"&gt;pages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;stage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;deploy&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;apt-get update -y &amp;amp;&amp;amp; apt-get install -y pandoc&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;mkdir public&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;pandoc --output=public/index.html --template=template.html README.md&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;artifacts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;paths&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;public&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;only&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;refs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;main&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;À partir de là, le site est automatiquement publié sur &lt;code&gt;marienfressinaud.frama.io/gdpr-txt&lt;/code&gt;. Il ne me reste plus qu’à configurer mon nom de domaine pour le faire pointer vers Framagit. Mon enregistrement &lt;abbr&gt;DNS&lt;/abbr&gt; ressemble à ça chez &lt;a href="https://gandi.net"&gt;Gandi&lt;/a&gt; :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;@ 10800 IN ALIAS marienfressinaud.frama.io.
_gitlab-pages-verification-code 10800 IN TXT &amp;quot;gitlab-pages-verification-code=90dff6058cf863ecb357ab2279e144fb&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Pas d’inquiétude : les informations sont bien entendues fournies par Framagit&lt;sup id="fnref:2"&gt;&lt;a class="footnote-ref" href="#fn:2"&gt;2&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;Je suis plutôt content de cette solution. Elle ne révolutionne rien et reste technique, mais elle se met rapidement en place et m’a demandé peu de connaissances supplémentaires. J’aurais pu me passer de la partie &lt;abbr&gt;DNS&lt;/abbr&gt;, voire également de Pandoc en écrivant directement le fichier &lt;abbr&gt;HTML&lt;/abbr&gt; (ça m’arrive), mais j’aime le confort de rédaction du Markdown.&lt;/p&gt;
&lt;div class="footnote"&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;Je l’ai tout de même légèrement simplifié par rapport à &lt;a href="https://framagit.org/marienfressinaud/gdpr-txt/-/blob/main/website/template.html"&gt;mon fichier d’origine&lt;/a&gt; pour des raisons de clarté.&amp;#160;&lt;a class="footnote-backref" href="#fnref:1" title="Jump back to footnote 1 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:2"&gt;
&lt;p&gt;Attention toutefois à l’enregistrement de vérification (le deuxième) qui est légèrement erroné dans Framagit : il faut soit ajouter un point à la fin de &lt;code&gt;_gitlab-pages-verification-code.gdpr-txt.org&lt;/code&gt;, soit virer la dernière partie (ce que j’ai moi-même fait). Il y a moins de risque d’erreur en passant par l’interface graphique de Gandi (pour une fois).&amp;#160;&lt;a class="footnote-backref" href="#fnref:2" title="Jump back to footnote 2 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</content></entry><entry><title>Lollypop</title><id>urn:uuid:255e191a-b9b6-58ec-b7b7-d9d7ace882ff</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/lollypop.html" rel="alternate" type="text/html" /><published>2022-03-01T12:34:00+01:00</published><updated>2022-03-01T12:34:00+01:00</updated><content type="html">&lt;p&gt;Comme je l’ai expliqué &lt;a href="debrancher-internet.html"&gt;précédemment&lt;/a&gt;, je passe plus de temps à travailler hors-ligne. Comme j’écoute également beaucoup de musiques, je redécouvre celles qui traînent sur mon disque dur. J’ai longtemps été satisfait par &lt;a href="https://wiki.gnome.org/Apps/Rhythmbox"&gt;Rhythmbox&lt;/a&gt; pour écouter ma musique, mais j’ai fait face à pas mal de bogues gênants en le rouvrant dernièrement. &lt;strong&gt;On m’a suggéré de jeter un œil à &lt;a href="https://wiki.gnome.org/Apps/Lollypop"&gt;Lollypop&lt;/a&gt; ; c’était exactement ce que je cherchais.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Non content d’être moins bogué, son interface est plus intuitive et plus pratique. L’interface ne ressemble pas à un gestionnaire de base de données, mais &lt;strong&gt;à une application dédiée à l’écoute de la musique.&lt;/strong&gt; La navigation se fait notamment par albums, artistes, voire par années ou genres de musique. Il y a également un système de suggestions ; j’apprécie tout spécialement la suggestion de l’« album du jour ».&lt;/p&gt;
&lt;p&gt;Il y a toutefois parfois de petites frictions à l’utilisation comme des incertitudes sur comment accéder à l’écran de l’album actuellement joué par exemple. Le plus gênant à mon sens est la synchronisation initiale des musiques : l’interface reste vide tant que la synchro n’est pas terminée, ce qui peut durer plusieurs minutes. J’ai cru que Lollypop ne fonctionnait pas, jusqu’à apercevoir une (discrète) barre de chargement en bas de l’écran. &lt;strong&gt;Mais malgré ces quelques petits défauts, je tiens à souligner la très grande qualité de Lollypop.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Mention spéciale à son auteur qui &lt;a href="https://linuxfr.org/users/gnumdk/journaux/eolie-le-petit-frere-de-lollypop"&gt;considère Lollypop comme « terminé »&lt;/a&gt;, signe de &lt;a href="terminer-ses-projets.html"&gt;maturité&lt;/a&gt; du projet. J’en ai profité pour lui faire un don de 10 €.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Capture d’écran de Lollypop affichant une liste d’albums" src="images/lollypop.png" /&gt;&lt;/p&gt;</content></entry><entry><title>Le fichier GDPR.txt</title><id>urn:uuid:3d5108aa-3ab0-5bf5-a127-829fa4c127ad</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/gdpr-txt.html" rel="alternate" type="text/html" /><published>2022-02-23T19:28:00+01:00</published><updated>2022-03-02T22:05:00+01:00</updated><content type="html">&lt;p&gt;Dans le cadre de mon bénévolat pour &lt;a href="https://framasoft.org/"&gt;Framasoft&lt;/a&gt;, je suis amené à travailler sur la conformité de l’association au &lt;a href="https://www.cnil.fr/fr/comprendre-le-rgpd"&gt;Règlement Général sur la Protection des Données&lt;/a&gt; (&lt;abbr&gt;RGPD&lt;/abbr&gt;). Ça fait des années qu’on essaye d’avancer sur le sujet, mais il faut bien reconnaître que, vu le nombre de services et d’activités qu’on gère, c’est la grosse galère. D’ailleurs, si ça vous étonne, on a une entrée claire &lt;a href="https://contact.framasoft.org/fr/faq/#gpdr"&gt;dans la &lt;abbr&gt;FAQ&lt;/abbr&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;On a quand même bien avancé depuis octobre dernier, accompagné‧es que nous sommes par &lt;a href="https://www.stella.coop/"&gt;stella.coop&lt;/a&gt;. Notre liste des traitements est sur pied, mais il nous reste à compléter les fiches des différents traitements (on en documente d’ailleurs l’avancement &lt;a href="https://wiki.framasoft.org/rgpd"&gt;publiquement&lt;/a&gt;). Il nous faut donc passer sur chaque service, déterminer les finalités des traitements, lister les données récupérées, vérifier si elles sont obligatoires, leur visibilité, etc.&lt;/p&gt;
&lt;p&gt;Face à cette montagne, une idée me trotte dans la tête depuis un moment : &lt;strong&gt;ce serait pratique (et bien sympa de leur part) que les développeurs et développeuses de logiciels proposent elles-mêmes un document synthétisant les informations utiles dans le cadre du &lt;abbr&gt;RGPD&lt;/abbr&gt;.&lt;/strong&gt; Ça faciliterait le travail de celles et ceux qui proposent des instances de leur logiciel, ça mutualiserait le travail ingrat et ça limiterait les erreurs.&lt;/p&gt;
&lt;p&gt;Comme on n’est jamais aussi bien servi que par soi-même, je teste actuellement un format dans le dépôt de &lt;a href="https://github.com/flusio/flusio"&gt;flusio&lt;/a&gt; : &lt;strong&gt;le fichier GDPR.txt.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Le format est simple : un système &lt;code&gt;clé: valeur&lt;/code&gt; organisé par blocs, chaque bloc étant séparé des autres par une ligne vide. Il existe deux types de blocs : celui pour indiquer les finalités et celui pour indiquer les données collectées.&lt;/p&gt;
&lt;p&gt;Une finalité est décrite par les clés suivantes :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;purpose&lt;/code&gt; : la finalité du traitement de données (champ libre) ;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;lawfulness&lt;/code&gt; : la base légale du traitement (&lt;i lang="en"&gt;consent, contract, legal, public interest, legitimate interest, vital&lt;/i&gt;, cf. &lt;a href="https://www.cnil.fr/fr/les-bases-legales/liceite-essentiel-sur-les-bases-legales"&gt;le site de la CNIL&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Une donnée est décrite par les clés suivantes :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;data&lt;/code&gt; : le nom de la donnée collectée (champ libre) ;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;required&lt;/code&gt; : si la donnée est obligatoire ou non (&lt;code&gt;true&lt;/code&gt; ou &lt;code&gt;false&lt;/code&gt;) ;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;visibility&lt;/code&gt; : par qui est accessible la donnée au sein de l’application (champ libre, ex. &lt;i lang="en"&gt;private&lt;/i&gt;, &lt;i lang="en"&gt;public&lt;/i&gt;, &lt;i lang="en"&gt;administrators&lt;/i&gt;) ;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;description&lt;/code&gt; : pour expliquer comment est utilisée la donnée (champ libre) ;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mitigation&lt;/code&gt; : pour détailler les mécanismes qui rendent la donnée moins vulnérable (champ libre facultatif, ex. « données supprimées après X jours », « pseudonyme autorisé »).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Si le format vous intéresse, j’ai créé &lt;a href="https://framagit.org/marienfressinaud/gdpr-txt"&gt;un dépôt Framagit pour en discuter et améliorer les choses publiquement&lt;/a&gt;. &lt;strong&gt;Je crois que ce fichier est plus qu’utile et faciliterait la conformité &lt;abbr&gt;RGPD&lt;/abbr&gt; pour beaucoup de monde.&lt;/strong&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;Mise à jour du 02 mars.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;J’ai finalement publié tout ça sous la forme d’un site dédié, &lt;a href="https://gdpr-txt.org"&gt;gdpr-txt.org&lt;/a&gt; et &lt;a href="https://framagit.org/marienfressinaud/gdpr-txt"&gt;d’un dépôt sur Framagit&lt;/a&gt; pour contribuer.&lt;/p&gt;</content></entry><entry><title>Publier souvent</title><id>urn:uuid:8c2e7aff-b4ec-539b-8a13-f2d0e41eed4c</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/publier-souvent.html" rel="alternate" type="text/html" /><published>2022-02-22T12:20:00+01:00</published><updated>2022-02-22T12:20:00+01:00</updated><content type="html">&lt;p&gt;Ça va bientôt faire un mois que je me suis fixé &lt;a href="billets-courts.html"&gt;l’objectif de publier un billet par jour&lt;/a&gt;. Le rythme était totalement arbitraire et je ne l’ai — évidemment — pas tenu : je ne tiens jamais ce genre de choses.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Le résultat est tout de même positif puisque j’ai publié 20 billets-articles : 17 ici et 3 dans &lt;a href="https://flus.fr/carnet/"&gt;le carnet de Flus&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Certains jours, j’ai également rédigé des billets sans les publier : soit pour le faire plus tard, soit parce que je n’avais plus envie de les publier. &lt;/p&gt;
&lt;p&gt;Quelques billets rédigés à l’avance se trouvent dans un état intermédiaire : je ne sais pas quoi en faire. Dans ce genre de cas, il m’est arrivé de les réécrire de zéro. Ça a été le cas de mon billet « &lt;a href="pour-batir-un-morceau-de-web.html"&gt;Pour bâtir un morceau de Web&lt;/a&gt; ».&lt;/p&gt;
&lt;p&gt;J’ai réalisé que, même pour de très courts billets, je pouvais passer beaucoup de temps de relecture. Après rédaction, j’ai encore corrigé et reformulé &lt;a href="apostrophe.html"&gt;le billet concernant Apostrophe&lt;/a&gt; pendant 30 minutes ; il fait quatre paragraphes. J’adore cette étape, mais j’ai parfois l’impression d’y perdre en spontanéité.&lt;/p&gt;
&lt;p&gt;En partageant des choses, on bénéficie également des lumières des autres. Je connais François depuis longtemps, mais je ne savais pas qu’il me lisait : il m’a corrigé &lt;a href="exploration-sql.html"&gt;ma requête &lt;abbr&gt;SQL&lt;/abbr&gt; infernale&lt;/a&gt; (&lt;i lang="la"&gt;confer&lt;/i&gt; la mise à jour en bas de page). Quant à lui, il devrait désormais utiliser l’attribut &lt;code&gt;lang&lt;/code&gt; sur les balises &lt;abbr&gt;HTML&lt;/abbr&gt; &lt;code&gt;&amp;lt;i&amp;gt;&lt;/code&gt; pour indiquer les mots de langues étrangères 🙂&lt;/p&gt;
&lt;p&gt;Publier, c’est utiliser son site. Le faire de manière régulière a été l’occasion d’améliorer un certain nombre de choses dessus : &lt;a href="yoga.html"&gt;l’optimisation des images&lt;/a&gt;, &lt;a href="theme-sombre.html"&gt;l’ajout d’un thème sombre&lt;/a&gt; et &lt;a href="turbolinks.html"&gt;de Turbolinks&lt;/a&gt;, &lt;a href="indieweb.html"&gt;le support de technos issues de l’IndieWeb&lt;/a&gt; et d’autres trucs qui n’ont pas eu le droit à un article. &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Dans l’ensemble j’ai pris du plaisir à rédiger. Je suis également content d’avoir publié certaines choses sans me poser la question de savoir si ça intéresserait d’autres personnes : je publie pour moi avant tout.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Je vais conserver cet objectif d’un billet par jour, toujours sans le tenir. J’ai envisagé de viser un billet par semaine, mais je sais que rater un objectif atteignable me démotiverait bien plus que de rater un objectif que je &lt;em&gt;sais&lt;/em&gt; inatteignable.&lt;/p&gt;</content></entry><entry><title>Spam</title><id>urn:uuid:7bbbadaf-1111-5edb-811e-043cb327a6d0</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/spam.html" rel="alternate" type="text/html" /><published>2022-02-13T23:59:00+01:00</published><updated>2022-02-13T23:59:00+01:00</updated><content type="html">&lt;p&gt;Je ne sais pas ce qu’il se passe en ce moment, mais ça semble être la foire aux spams.&lt;/p&gt;
&lt;p&gt;Ça a commencé avec les appels &lt;a href="https://www.moncompteformation.gouv.fr/espace-public/attention-arnaques-cpf-soyez-vigilant"&gt;d’arnaque au Compte Personnel de Formation&lt;/a&gt; à partir de fin décembre.&lt;/p&gt;
&lt;p&gt;Ça a continué avec des boîtes qui m’envoient de la pub à mon domicile sous couvert que mon adresse postale est une adresse professionnelle. Fonctionne évidemment aussi avec mes adresses courriel liées à Flus, même celles qui sont purement techniques.&lt;/p&gt;
&lt;p&gt;Sont venus d’autres numéros qui m’appellent régulièrement. Cette semaine, un numéro a tenté de me joindre quasiment tous les jours. Je l’ai bloqué.&lt;/p&gt;
&lt;p&gt;Aujourd’hui, ce sont 260 courriels que mon serveur a rejeté (contre 45 sur l’ensemble du reste de la semaine). Ce sont les quelques faux négatifs qui m’ont mis la puce à l’oreille. Heureusement que j’ai mis sur pied un blocage par nom de domaine il y a quelques semaines.&lt;/p&gt;
&lt;p&gt;Je ne sais pas ce qu’il se passe en ce moment, mais ça commence légèrement à m’agacer…&lt;/p&gt;</content></entry><entry><title>IndieWeb</title><id>urn:uuid:90dd3204-d454-5405-a6ba-c191e094f3d5</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/indieweb.html" rel="alternate" type="text/html" /><published>2022-02-12T13:15:00+01:00</published><updated>2022-02-12T13:15:00+01:00</updated><content type="html">&lt;p&gt;Ça faisait quelques années que je gardais &lt;a href="https://indieweb.org/"&gt;le site de l’IndieWeb&lt;/a&gt; dans un coin. Parfois il disparaissait de mes signets, mais il y revenait systématiquement. Comme je passe plus de temps sur mon site ces derniers temps, j’ai enfin saisi l’occasion de me pencher dessus le weekend dernier.&lt;/p&gt;
&lt;p&gt;Déjà, c’est quoi l’IndieWeb ? Voilà ma traduction de la définition donnée sur leur site :&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;L’IndieWeb est une communauté de sites Web personnels individuels, connectés par des standards simples, basés sur les principes de posséder votre nom de domaine, de l’utiliser comme identité principale, de publier sur votre propre site (éventuellement en syndiquant ailleurs) et de posséder vos données.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Plus concrètement, il s’agit d’une démarche qui vise à fédérer des sites Web personnels indépendants à travers des formats et des protocoles simples à mettre en place.&lt;/strong&gt; Par exemple, le protocole &lt;a href="https://indieweb.org/Webmention"&gt;Webmention&lt;/a&gt; permet de notifier un site lorsque vous le mentionnez sur votre propre site ou sur un réseau social. Le mécanisme de réponse ou de « &lt;i lang="en"&gt;likes&lt;/i&gt; » n’est ainsi plus restreint à une plateforme en particulier mais est entièrement décentralisé.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pour démarrer, la page &lt;a href="https://indieweb.org/Getting_Started"&gt;&lt;i lang="en"&gt;Getting started&lt;/i&gt;&lt;/a&gt; de leur wiki est plutôt bien faite,&lt;/strong&gt; bien que légèrement intimidante au premier abord. Voici les étapes que j’ai suivies :&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;publier mon propre site derrière un nom de domaine que je possède (ça, c’était bon 👍) ;&lt;/li&gt;
&lt;li&gt;déclarer mon identité au format &lt;a href="https://indieweb.org/h-card"&gt;&lt;code&gt;h-card&lt;/code&gt;&lt;/a&gt; ;&lt;/li&gt;
&lt;li&gt;relier mon site à mes comptes de réseaux sociaux à coup &lt;a href="https://indieweb.org/rel-me"&gt;de liens &lt;code&gt;rel=me&lt;/code&gt;&lt;/a&gt; ;&lt;/li&gt;
&lt;li&gt;déclarer mon contenu au format &lt;a href="https://indieweb.org/h-entry"&gt;&lt;code&gt;h-entry&lt;/code&gt;&lt;/a&gt; et &lt;a href="https://indieweb.org/h-feed"&gt;&lt;code&gt;h-feed&lt;/code&gt;&lt;/a&gt; ;&lt;/li&gt;
&lt;li&gt;syndiquer automatiquement mon contenu ailleurs (je pourrais éventuellement le faire vers Mastodon, mais je ne suis pas sûr de le vouloir ; par contre c’est le cas vers &lt;a href="https://app.flus.fr/collections/1697725238755346702"&gt;Flus&lt;/a&gt;) ;&lt;/li&gt;
&lt;li&gt;partager ma démarche (c’est maintenant fait !)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;C’est un peu plus simple si vous utilisez un &lt;abbr&gt;CMS&lt;/abbr&gt; comme Wordpress. Dans mon cas — un site statique généré à la main —, il a fallu plonger les mains dans le &lt;abbr&gt;HTML&lt;/abbr&gt;. &lt;strong&gt;Heureusement, les formats sont très simples à mettre en place : seulement quelques attributs &lt;code&gt;class&lt;/code&gt; à ajouter par-ci par-là.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;La page ne suggère pas de mettre en place &lt;a href="https://indieweb.org/webmention"&gt;Webmention&lt;/a&gt;, mais ça me grattait et je m’en suis occupé ce matin grâce à &lt;a href="https://webmention.io/"&gt;webmention.io&lt;/a&gt;. Les échanges sur Mastodon autour du sujet m’y ont largement encouragé. Mon but est d’être tenu au courant — via un flux Atom généré par webmention.io — lorsque mon site est mentionné ailleurs. Je ne sais pas encore si j’afficherai les mentions directement ici par contre.&lt;/p&gt;
&lt;p&gt;Maintenant se pose la question de l’intérêt d’avoir fait tout ça. Pour être honnête, ça ne me saute pas immédiatement aux yeux en l’absence d’un écosystème riche autour de ces technologies. &lt;strong&gt;L’écosystème ne se mettra toutefois pas en place de lui-même, sans adoption par celles et ceux qui font le Web&lt;sup id="fnref:1"&gt;&lt;a class="footnote-ref" href="#fn:1"&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/strong&gt;&lt;/p&gt;
&lt;div class="footnote"&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;Je le chuchote en fin de page, mais j’aimerais creuser ce qu’il est possible de faire avec &lt;a href="https://flus.fr"&gt;Flus&lt;/a&gt;. J’imagine déjà des choses avec les formats &lt;code&gt;h-entry&lt;/code&gt; et &lt;code&gt;h-feed&lt;/code&gt;, ou encore avec Webmention. Tout cela reste &lt;strong&gt;hypothétique&lt;/strong&gt; car j’ai encore bien d’autres choses à faire avant !&amp;#160;&lt;a class="footnote-backref" href="#fnref:1" title="Jump back to footnote 1 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</content></entry><entry><title>git revise</title><id>urn:uuid:6c0f8c28-71e6-5294-908c-fec2a6bcfc8e</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/git-revise.html" rel="alternate" type="text/html" /><published>2022-02-09T19:58:00+01:00</published><updated>2022-02-09T19:58:00+01:00</updated><content type="html">&lt;p&gt;J’utilise très peu de surcouches ou de commandes additionnelles à &lt;a href="https://git-scm.com/"&gt;Git&lt;/a&gt;. Il y a toutefois une sous-commande qui m’est devenue indispensable : &lt;a href="https://github.com/mystor/git-revise/"&gt;&lt;code&gt;git revise&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Si vous êtes du genre à réécrire l’historique de vos branches de travail — ce qui est une bonne chose à apprendre pour garder un historique clair —, vous devez connaître &lt;code&gt;git rebase&lt;/code&gt;. Cette commande permet de réappliquer des commits par-dessus une nouvelle base. Je l’utilise principalement avec l’option &lt;code&gt;-i&lt;/code&gt; qui permet de réécrire l’historique de manière interactive (pour fusionner ou éditer des commits à la volée par exemple).&lt;/p&gt;
&lt;p&gt;&lt;code&gt;git revise&lt;/code&gt; est sa petite sœur en plus intuitive et plus rapide. Elle permet notamment d’appliquer un patch sur un commit précis sans avoir à se fader la création d’un commit temporaire et la réorganisation des commits.&lt;/p&gt;</content></entry><entry><title>Technique de décrochage : débrancher Internet</title><id>urn:uuid:ec7185fa-1d6f-5cbd-b670-cb50109e3860</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/debrancher-internet.html" rel="alternate" type="text/html" /><published>2022-02-08T20:25:00+01:00</published><updated>2022-02-08T20:25:00+01:00</updated><content type="html">&lt;p&gt;En ayant &lt;a href="quitter-twitter.html"&gt;quitté Twitter&lt;/a&gt; le mois dernier, j’avais déjà bien diminué les distractions numériques. Il en subsistait toutefois encore : le tchat avec les copain‧es, Mastodon, les courriels qui arrivent, etc. Je n’allais quand même pas tout couper ! Quoique…&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Il y a environ un mois, j’ai commencé à m’accorder des sessions de travail hors-ligne.&lt;/strong&gt; C’est-à-dire que, selon les cas, je coupe la connexion dans les paramètres réseaux, voire je débranche littéralement mon câble &lt;abbr&gt;RJ45&lt;/abbr&gt;. C’est un peu radical, je vous l’accorde, mais l’expérience est intéressante pour le changement opéré dans ma manière d’aborder le numérique.&lt;/p&gt;
&lt;p&gt;Le premier impact, celui que je recherchais, est que je ne vérifie plus frénétiquement si j’ai de nouvelles choses à lire sur Mattermost ou Mastodon. C’est bête, mais c’est très efficace. Comme je ne suis plus happé par ces plateformes, &lt;strong&gt;mon cerveau se tourne plus facilement vers de l’écriture, ou vers des améliorations pour le site.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Ensuite, il faut s’adapter. J’écoute beaucoup de musique via des plateformes de &lt;i lang="en"&gt;streaming&lt;/i&gt; quand je travaille. &lt;strong&gt;Désormais, je redécouvre la musique en local et j’ai commencé à utiliser &lt;a href="https://wiki.gnome.org/Apps/Lollypop"&gt;Lollypop&lt;/a&gt; depuis peu&lt;sup id="fnref:1"&gt;&lt;a class="footnote-ref" href="#fn:1"&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/strong&gt; Heureusement, ma musicothèque est relativement fournie. Lollypop, via sa fonction de suggestions, me permet de redécouvrir des titres que je n’ai pas écoutés depuis longtemps ; c’est plutôt chouette.&lt;/p&gt;
&lt;p&gt;Côté pro, c’est un peu plus embêtant, mais on s’en sort. &lt;strong&gt;J’utilise &lt;a href="https://devdocs.io/"&gt;DevDocs&lt;/a&gt; pour avoir de la documentation technique hors-ligne.&lt;/strong&gt; Ça ne permet pas de répondre à tout, mais c’est souvent suffisant. Je me dis parfois qu’il manque l’équivalent pour &lt;a href="https://stackoverflow.com/"&gt;StackOverflow&lt;/a&gt;, mais ça me paraît plus compliqué à mettre en place. D’un côté, ça permet de passer plus de temps à se creuser les méninges et c’est peut-être pas plus mal.&lt;/p&gt;
&lt;p&gt;D’autre part, comme &lt;a href="https://flus.fr"&gt;Flus&lt;/a&gt; est avant tout un outil qui se connecte à d’autres sites, il a fallu ruser. &lt;strong&gt;J’ai créé &lt;a href="https://github.com/flusio/flusio/blob/6d7776c5fdd4446b3d82251bfc4cf1219721fdc4/tests/mock_server.php"&gt;un petit serveur de « mock »&lt;/a&gt; auquel je peux indiquer « pour telle requête &lt;abbr&gt;HTTP&lt;/abbr&gt;, renvoie telle réponse ».&lt;/strong&gt; Je l’utilise avant tout pour les tests — qui passent désormais (quasiment) tous en hors-ligne —, mais il peut aussi fonctionner en phase de développement lorsque j’en ai besoin. C’était moins compliqué à faire que ce que je pensais.&lt;/p&gt;
&lt;p&gt;Ça ne fait qu’un mois que j’ai commencé à travailler ainsi. Je ne prétends pas que c’est la panacée ; c’est une manière de faire évidemment très limitée. &lt;strong&gt;En revanche, l’effet est globalement positif sur ma capacité de concentration et sur ce que je suis en mesure de produire.&lt;/strong&gt; Expérience en cours donc.&lt;/p&gt;
&lt;div class="footnote"&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;Après de longues années de bons et loyaux services de la part de &lt;a href="https://wiki.gnome.org/Apps/Rhythmbox"&gt;Rhythmbox&lt;/a&gt;, beaucoup trop bugué ces derniers temps. Je ne regrette pas à vrai dire : je trouve Lollypop bien plus agréable à utiliser au quotidien.&amp;#160;&lt;a class="footnote-backref" href="#fnref:1" title="Jump back to footnote 1 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</content></entry><entry><title>Pour bâtir un morceau de Web</title><id>urn:uuid:ecfd9600-6d84-59aa-a837-64ac814afe05</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/pour-batir-un-morceau-de-web.html" rel="alternate" type="text/html" /><published>2022-02-07T21:40:00+01:00</published><updated>2022-02-07T21:40:00+01:00</updated><content type="html">&lt;p&gt;Je me souviens très bien de la toute première page Web que j’ai écrite&lt;sup id="fnref:1"&gt;&lt;a class="footnote-ref" href="#fn:1"&gt;1&lt;/a&gt;&lt;/sup&gt;. Elle ressemblait à ça :&lt;/p&gt;
&lt;p&gt;&lt;img alt="Une page Web blanche affichant « Bonjour tout le monde ! »" src="images/hello-world.png" /&gt;&lt;/p&gt;
&lt;p&gt;C’était incroyable : il m’avait suffi d’écrire &lt;strong&gt;une et une seule ligne de texte&lt;/strong&gt; dans un fichier texte pour qu’elle puisse s’afficher dans mon navigateur&lt;sup id="fnref:2"&gt;&lt;a class="footnote-ref" href="#fn:2"&gt;2&lt;/a&gt;&lt;/sup&gt;. Je venais d’apprendre la leçon la plus importante de ma carrière : le Web, ce n’est jamais que de bêtes fichiers textes.&lt;/p&gt;
&lt;p&gt;J’aimerais faire passer ce message aux personnes qui voudraient apprendre à faire du Web — et même aux plus expérimentées — : &lt;strong&gt;ce n’est pas plus compliqué que ça.&lt;/strong&gt; Vous vous sentez peut-être intimidé‧e par la complexité des outils qui permettent de faire du Web « moderne&lt;sup id="fnref:3"&gt;&lt;a class="footnote-ref" href="#fn:3"&gt;3&lt;/a&gt;&lt;/sup&gt; » ; la vérité, c’est que vous avez seulement besoin d’un éditeur de texte et d’un navigateur Web.&lt;/p&gt;
&lt;p&gt;Pour débuter, vous n’avez pas besoin de Webpack ou autre outil de &lt;i lang="en"&gt;build&lt;/i&gt;. Vous n’avez pas besoin non plus de framework React/Angular/Vue (surtout pas !) En fait, vous n’avez même pas besoin de JavaScript.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pour bâtir un morceau de Web à vous, vous avez seulement besoin d’apprendre à écrire du &lt;abbr&gt;HTML&lt;/abbr&gt; et — un tout petit peu — de &lt;abbr&gt;CSS&lt;/abbr&gt;.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Ouvrez un éditeur de texte (Notepad sur Windows, ou gedit&lt;sup id="fnref:4"&gt;&lt;a class="footnote-ref" href="#fn:4"&gt;4&lt;/a&gt;&lt;/sup&gt; sur Linux par exemple), collez-y le code suivant :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;html&lt;/span&gt; &lt;span class="na"&gt;lang&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;fr&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;title&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Mon site Web&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;title&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Vous pouvez modifier le fichier pour commencer à apprendre &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;abbr&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;HTML&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;abbr&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;html&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Enregistrez ça dans un fichier nommé &lt;code&gt;test.html&lt;/code&gt;, n’importe où sur votre &lt;abbr&gt;PC&lt;/abbr&gt;, puis cliquez dessus pour l’ouvrir dans votre navigateur. Voilà, vous avez devant vous votre première page Web&lt;sup id="fnref:5"&gt;&lt;a class="footnote-ref" href="#fn:5"&gt;5&lt;/a&gt;&lt;/sup&gt; !&lt;/p&gt;
&lt;p&gt;Pour la suite, il existe des cours en ligne. La référence semble toujours&lt;sup id="fnref:6"&gt;&lt;a class="footnote-ref" href="#fn:6"&gt;6&lt;/a&gt;&lt;/sup&gt; être le cours « &lt;a href="https://openclassrooms.com/fr/courses/1603881-apprenez-a-creer-votre-site-web-avec-html5-et-css3"&gt;Apprenez à créer votre site web avec &lt;abbr&gt;HTML5&lt;/abbr&gt; et &lt;abbr&gt;CSS3&lt;/abbr&gt;&lt;/a&gt; » de Mathieu Nebra sur OpenClassrooms (ex Site du Zéro pour les nostalgiques).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Un conseil avant tout : créez-vous un site personnel pour expérimenter des choses par vous-même.&lt;/strong&gt; C’est pas grave s’il ne marche qu’à moitié, c’est pas grave s’il est moche. Ne vous souciez pas trop non plus — pour le moment — d’éventuelles « bonnes pratiques ». Allez-y tranquillement.&lt;/p&gt;
&lt;p&gt;Si vous êtes plus expérimenté‧es, je vous invite à considérer un outillage minimaliste lorsque vous débuterez votre prochain projet. Réfléchissez à comment vous pourriez limiter votre dépendance à des outils externes. Le gain offert par ces outils ne vaut pas toujours le temps passé à les configurer et tenir à jour. Limiter les dépendances, c’est aussi faciliter l’accès à votre projet à d’autres personnes. Est-ce que vous avez &lt;em&gt;vraiment&lt;/em&gt; besoin de ce framework frontend ? Et rappelez-vous que, le Web, c’est du &lt;abbr&gt;HTML&lt;/abbr&gt; avant d’être du JavaScript.&lt;/p&gt;
&lt;div class="footnote"&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;Je m’en souviens tellement bien que je serais prêt à parier que mon voisin de bureau était en train de jouer à Dofus à ma droite tandis que je découvrais le Site du Zéro. Ça n’a pas beaucoup d’intérêt de se souvenir de ça, mais ça reste un jour important pour moi :)&amp;#160;&lt;a class="footnote-backref" href="#fnref:1" title="Jump back to footnote 1 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:2"&gt;
&lt;p&gt;Probablement Firefox 3.0 à l’époque, ça devait être en 2008 ou 2009.&amp;#160;&lt;a class="footnote-backref" href="#fnref:2" title="Jump back to footnote 2 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:3"&gt;
&lt;p&gt;Oubliez ce terme, il est généralement utilisé par des personnes qui aiment se compliquer la vie avec beaucoup trop d’outils. Il n’y a pas plus moderne qu’un site qui fonctionne.&amp;#160;&lt;a class="footnote-backref" href="#fnref:3" title="Jump back to footnote 3 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:4"&gt;
&lt;p&gt;On en dira ce qu’on veut, mais j’ai codé avec gedit pendant plusieurs années et il me convenait &lt;em&gt;très&lt;/em&gt; bien. Une autre leçon tiens : ne vous souciez pas trop de ce que les autres pensent de vos outils. Les guerres de chapelles, c’est fatigant.&amp;#160;&lt;a class="footnote-backref" href="#fnref:4" title="Jump back to footnote 4 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:5"&gt;
&lt;p&gt;Bonus : elle est valide &lt;abbr&gt;HTML5&lt;/abbr&gt;, accessible, extrêmement rapide à charger et s’affiche correctement sur mobile ! On fera difficilement plus moderne.&amp;#160;&lt;a class="footnote-backref" href="#fnref:5" title="Jump back to footnote 5 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:6"&gt;
&lt;p&gt;En recherchant un peu, j’ai été surpris qu’il n’existe pas tant de ressources supplémentaires. Les quelques cours que j’ai trouvés me semblent moins bons que celui d’OpenClassrooms. C’est un peu dommage si vous voulez mon avis.&amp;#160;&lt;a class="footnote-backref" href="#fnref:6" title="Jump back to footnote 6 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</content></entry><entry><title>Turbolinks</title><id>urn:uuid:f6e2d830-22f8-54c3-9752-0f7552651470</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/turbolinks.html" rel="alternate" type="text/html" /><published>2022-02-06T21:25:00+01:00</published><updated>2022-02-06T21:25:00+01:00</updated><content type="html">&lt;p&gt;Je continue de faire des améliorations sur le site et je viens d’y ajouter &lt;a href="https://github.com/turbolinks/turbolinks"&gt;Turbolinks&lt;/a&gt;. Le but est d’accélérer le chargement des pages et d’éviter les petits glitchs visuels en les chargeant intelligemment en JavaScript. La navigation était devenue gênante dans certaines situations&lt;sup id="fnref:1"&gt;&lt;a class="footnote-ref" href="#fn:1"&gt;1&lt;/a&gt;&lt;/sup&gt; avec &lt;a href="theme-sombre.html"&gt;le thème sombre&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Turbolinks n’est plus maintenu, remplacé par &lt;a href="https://turbo.hotwired.dev/"&gt;Turbo&lt;/a&gt; depuis 2021. Je n’avais toutefois besoin que de la partie « Drive » qui correspond plus ou moins à Turbolinks. J’économise ainsi quelques kilo-octets.&lt;/p&gt;
&lt;p&gt;J’en ai également profité pour activer la compression de certains fichiers côté serveur, histoire d’accélérer un peu plus le chargement des pages. Ça devrait être suffisamment rapide pour avoir la sensation de naviguer en local :)&lt;/p&gt;
&lt;div class="footnote"&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;Lorsque vous naviguiez sur une nouvelle page, si votre navigateur déclarait préférer le thème clair mais que vous forciez le thème sombre, la page « clignotait » rapidement.&amp;#160;&lt;a class="footnote-backref" href="#fnref:1" title="Jump back to footnote 1 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</content></entry><entry><title>Thème sombre</title><id>urn:uuid:b0c13e93-01fd-5399-a576-3c9fac964e84</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/theme-sombre.html" rel="alternate" type="text/html" /><published>2022-02-05T22:36:00+01:00</published><updated>2022-02-05T22:36:00+01:00</updated><content type="html">&lt;p&gt;Je viens d’ajouter un thème sombre à ce site. Par défaut, il s’affichera en suivant les préférences de votre système, mais vous pouvez forcer le thème à partir du sélecteur qui se trouve dans le pied de page du site.&lt;/p&gt;
&lt;p&gt;La peinture est fraîche, il est possible que des soucis d’affichage subsistent. N’hésitez pas à me faire signe si vous vous en apercevez !&lt;/p&gt;
&lt;p&gt;C’était l’occasion pour moi de découvrir comment m’y prendre. Je ne suis pas encore satisfait de ma technique, donc j’aurai l’occasion de creuser encore.&lt;/p&gt;</content></entry><entry><title>YOGA Image Optimizer</title><id>urn:uuid:a7613eef-b761-52ec-9f62-ac11aea48330</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/yoga.html" rel="alternate" type="text/html" /><published>2022-02-02T10:00:00+01:00</published><updated>2022-02-02T10:00:00+01:00</updated><content type="html">&lt;p&gt;J’ai découvert il y a quelque temps un utilitaire pour optimiser ses images en local : &lt;a href="https://yoga.flozz.org/"&gt;YOGA Image Optimizer&lt;/a&gt; (via &lt;a href="https://linuxfr.org/news/yoga-image-optimizer-v1-1-resultats-des-travaux-de-l-ete"&gt;LinuxFr&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Je sais qu’il existe des tas d’applis qui font ça en ligne et d’autres qui le font en ligne de commande ; je suis juste content d’avoir une interface simple pour le faire en quelques clics sur mon ordi. J’en ai profité pour filer 5 balles au développeur pour le remercier de son travail (à noter que le développement semble actuellement être en pause).&lt;/p&gt;
&lt;p&gt;J’ai passé les quelques images du site à la moulinette, ainsi que celles du &lt;a href="https://flus.fr/carnet/"&gt;carnet de Flus&lt;/a&gt;. J’estime avoir réduit en moyenne de 25 % le poids des images.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Capture d’écran de YOGA listant les fichiers du carnet de Flus" src="images/yoga.png" /&gt;&lt;/p&gt;</content></entry><entry><title>Template de pull requests</title><id>urn:uuid:6a598042-6a24-5a15-8bac-c8669930dd33</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/template-pull-request.html" rel="alternate" type="text/html" /><published>2022-02-01T22:56:00+01:00</published><updated>2022-02-01T22:56:00+01:00</updated><content type="html">&lt;p&gt;Je partage ici le &lt;i lang="en"&gt;template&lt;/i&gt; de &lt;i lang="en"&gt;pull requests&lt;/i&gt; (&lt;abbr&gt;PR&lt;/abbr&gt;) que j’utilise pour &lt;a href="https://github.com/flusio/flusio"&gt;flusio&lt;/a&gt;, légèrement adapté et traduit. Son but est de me faire vérifier plusieurs points critiques avant de fusionner mon code dans la branche principale. Son contenu est rempli automatiquement lorsque j’ouvre une &lt;abbr&gt;PR&lt;/abbr&gt; et je m’interdis de l’intégrer tant que chacun des points n’a pas été validé. Elle m’est d’autant plus importante que je travaille seul : je n’ai personne pour vérifier derrière moi que je n’oublie rien. J’imagine qu’elle pourrait être utile à d’autres.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Liste de vérifications :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;[ ] le code a été testé manuellement&lt;/li&gt;
&lt;li&gt;[ ] l’interface fonctionne sur mobile et grands écrans&lt;/li&gt;
&lt;li&gt;[ ] l’accessibilité a été testée&lt;/li&gt;
&lt;li&gt;[ ] les tests ont été mis à jour&lt;/li&gt;
&lt;li&gt;[ ] la traduction française a été synchronisée&lt;/li&gt;
&lt;li&gt;[ ] la documentation a été mise à jour (incluant les commentaires, messages de commit, notes de migrations…)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;Si l’un de ces points n’est pas applicable à la &lt;abbr&gt;PR&lt;/abbr&gt;, merci de quand même cocher la case et d’ajouter &lt;code&gt;(N/A)&lt;/code&gt; à la fin de la ligne.&lt;/em&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Pour ajouter un &lt;i lang="en"&gt;template&lt;/i&gt; de &lt;abbr&gt;PR&lt;/abbr&gt; à votre dépôt de code, vous pouvez suivre les instructions officielles pour &lt;a href="https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/creating-a-pull-request-template-for-your-repository"&gt;GitHub&lt;/a&gt; ou pour &lt;a href="https://docs.gitlab.com/ee/user/project/description_templates.html"&gt;GitLab&lt;/a&gt;.&lt;/p&gt;</content></entry><entry><title>Redirections</title><id>urn:uuid:7a92528f-d5e8-5d37-83a9-63d37e155bee</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/redirections.html" rel="alternate" type="text/html" /><published>2022-01-31T17:40:00+01:00</published><updated>2022-01-31T17:40:00+01:00</updated><content type="html">&lt;p&gt;J’ai migré en 2016 mon blog de &lt;a href="https://pluxml.org/"&gt;PluXml&lt;/a&gt; vers &lt;a href="https://blog.getpelican.com/"&gt;Pelican&lt;/a&gt; (avant une nouvelle migration vers &lt;a href="https://framagit.org/marienfressinaud/boop"&gt;Boop!&lt;/a&gt; en 2019). Si j’avais bien pensé à rediriger les adresses des flux &lt;abbr&gt;RSS&lt;/abbr&gt; à l’origine (ex. &lt;code&gt;/feed&lt;/code&gt; ou &lt;code&gt;/feed.php&lt;/code&gt;), les redirections ont fini par se perdre au gré des mises à jour. Je viens de les remettre en place. Re-bienvenue aux personnes qui découvriront une ribambelle de nouveaux articles 👋&lt;/p&gt;
&lt;p&gt;En plus des flux &lt;abbr&gt;RSS&lt;/abbr&gt;, j’ai eu un &lt;a href="https://shaarli.readthedocs.io"&gt;Shaarli&lt;/a&gt; pendant un certain temps. Celui-ci a fini par disparaître, mais je continuais à recevoir quelques visites à son ancienne adresse (en erreur 404 depuis longtemps). Désormais, cette adresse sera redirigée vers &lt;a href="https://app.flus.fr/p/1670839367044869607"&gt;mon profil Flus&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Enfin, j’ai pris le temps de rediriger les sous-domaines &lt;code&gt;www.&lt;/code&gt; et &lt;code&gt;next.&lt;/code&gt; (utilisé durant la conception de cette version du site) vers le nom de domaine de base.&lt;/p&gt;</content></entry><entry><title>Vu, lu, joué (janvier 2022)</title><id>urn:uuid:2ee1bf2a-7cad-5791-b0fd-ce1998fa406f</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/2022-01-vu-lu-joue.html" rel="alternate" type="text/html" /><published>2022-01-30T19:25:00+01:00</published><updated>2022-01-30T19:25:00+01:00</updated><content type="html">&lt;p&gt;Vu &lt;a href="https://fr.wikipedia.org/wiki/Belle_(film,_2021)"&gt;Belle&lt;/a&gt; de Mamoru Hosoda, réinterprétation de La Belle et la Bête au sein d’un monde « virtuel ». Magnifique pour les yeux et les oreilles, la fin m’a scotché malgré quelques grosses ficelles scénaristiques.&lt;/p&gt;
&lt;p&gt;Lu &lt;a href="https://fr.wikipedia.org/wiki/Bolchoi_Arena"&gt;Bolchoi Arena&lt;/a&gt;  — tome 3 — Révolutions qui explore, ici aussi, un monde « virtuel ». Peut-être 2 – 3 moments où j’ai eu du mal à suivre l’intrigue, mais on retombe sur nos pattes. J’aime tellement le style du dessin ♥️&lt;/p&gt;
&lt;p&gt;Joué à &lt;a href="https://fr.wikipedia.org/wiki/Animal_Crossing:_New_Horizons"&gt;&lt;i lang="en"&gt;Animal Crossing: New Horizons&lt;/i&gt;&lt;/a&gt; sur Switch une bonne partie du mois. C’était ce dont j’avais besoin en ce début d’année. J’ai découvert au passage le terme de « &lt;a href="https://www.youtube.com/watch?v=IgJ06XhvIgI"&gt;&lt;i lang="en"&gt;wholesome&lt;/i&gt;&lt;/a&gt; » pour décrire ce type de jeux.&lt;/p&gt;</content></entry><entry><title>Exploration SQL</title><id>urn:uuid:823aa826-ac2e-54fe-9a45-1a1631d9bec2</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/exploration-sql.html" rel="alternate" type="text/html" /><published>2022-01-29T12:00:00+01:00</published><updated>2022-02-12T08:35:00+01:00</updated><content type="html">&lt;p&gt;Article technique aujourd’hui. Lorsque j’ai développé &lt;a href="veille.html"&gt;la page des profils&lt;/a&gt; de Flus, j’ai fait face à un bug qui m’a bien occupé. Pas le genre de bug très grave, mais suffisamment pénible pour que je veuille le corriger.&lt;/p&gt;
&lt;p&gt;Contexte : un profil liste les six liens publiés le plus récemment par une personne. Pour qu’un lien soit publié, il doit faire partie d’une collection publique et ne pas être masqué. Un lien peut faire partie de plusieurs collections et une collection peut contenir plusieurs liens ; on a donc une relation « &lt;i lang="en"&gt;many-to-many&lt;/i&gt; ». La date de publication est associée à une collection ; il peut donc y avoir plusieurs dates de publication pour un même lien. Mon problème : les liens publiés dans plusieurs collections pouvaient apparaître plusieurs fois.&lt;/p&gt;
&lt;p&gt;Je vais vous illustrer tout ça par des requêtes &lt;abbr&gt;SQL&lt;/abbr&gt;. Pour simplifier le problème, on va considérer que toutes les collections sont publiques et les liens tous visibles.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;links&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;SERIAL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;PRIMARY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;TEXT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;collections&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;SERIAL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;PRIMARY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;TEXT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;links_to_collections&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;link_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;INTEGER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;REFERENCES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;links&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;collection_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;INTEGER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;REFERENCES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;collections&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;published_at&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TIMESTAMP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;INSERT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INTO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;links&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;VALUES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;flus.fr&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;marienfressinaud.fr&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;framasoft.org&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;INSERT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INTO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;collections&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;VALUES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Mes favoris&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Mes partages&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;INSERT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INTO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;links_to_collections&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;link_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;collection_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;published_at&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;VALUES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;2022-01-17&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;2022-01-18&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;2022-01-19&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;2022-01-20&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Que fait-on dans ces quelques lignes de &lt;abbr&gt;SQL&lt;/abbr&gt; ? On commence par créer les trois tables qui vont contenir les données (&lt;code&gt;links&lt;/code&gt;, &lt;code&gt;collections&lt;/code&gt; et la table faisant la jonction &lt;code&gt;links_to_collections&lt;/code&gt;). On insère ensuite trois liens et deux collections. Enfin, on fait le lien entre les liens et les collections :&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;flus.fr dans « Mes favoris » le 17 janvier ;&lt;/li&gt;
&lt;li&gt;marienfressinaud.fr dans « Mes partages » le 18 janvier ;&lt;/li&gt;
&lt;li&gt;framasoft.org dans « Mes partages » le 19 janvier ;&lt;/li&gt;
&lt;li&gt;enfin, à nouveau flus.fr dans « Mes partages » le 20 janvier.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Commençons par récupérer les trois liens les plus récents avec leur date de publication :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;published_at&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;links&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;

&lt;span class="k"&gt;INNER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;links_to_collections&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lc&lt;/span&gt;
&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;link_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;

&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;published_at&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;
&lt;span class="k"&gt;LIMIT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Cette requête nous retourne le résultat suivant :&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;id&lt;/th&gt;
&lt;th&gt;url&lt;/th&gt;
&lt;th&gt;published_at&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;flus.fr&lt;/td&gt;
&lt;td&gt;2022-01-20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;framasoft.org&lt;/td&gt;
&lt;td&gt;2022-01-19&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;marienfressinaud.fr&lt;/td&gt;
&lt;td&gt;2022-01-18&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;On a donc les lignes que l’on souhaite. Seulement, qu’arrive-t-il si on change la limite de trois à six ?&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;id&lt;/th&gt;
&lt;th&gt;url&lt;/th&gt;
&lt;th&gt;published_at&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;flus.fr&lt;/td&gt;
&lt;td&gt;2022-01-20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;framasoft.org&lt;/td&gt;
&lt;td&gt;2022-01-19&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;marienfressinaud.fr&lt;/td&gt;
&lt;td&gt;2022-01-18&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;flus.fr&lt;/td&gt;
&lt;td&gt;2022-01-17&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Mince, flus.fr apparaît désormais deux fois car il se trouve dans deux collections, avec deux dates de publication différentes. On ne le veut qu’une seule fois à sa date la plus récente ! Essayons d’ajouter une clause &lt;code&gt;DISTINCT&lt;/code&gt; :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DISTINCT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;published_at&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;links&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;

&lt;span class="k"&gt;INNER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;links_to_collections&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lc&lt;/span&gt;
&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;link_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;

&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;published_at&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;
&lt;span class="k"&gt;LIMIT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;id&lt;/th&gt;
&lt;th&gt;url&lt;/th&gt;
&lt;th&gt;published_at&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;flus.fr&lt;/td&gt;
&lt;td&gt;2022-01-20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;framasoft.org&lt;/td&gt;
&lt;td&gt;2022-01-19&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;marienfressinaud.fr&lt;/td&gt;
&lt;td&gt;2022-01-18&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;flus.fr&lt;/td&gt;
&lt;td&gt;2022-01-17&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Même résultat : normal, &lt;code&gt;DISTINCT&lt;/code&gt; s’applique à toutes les colonnes de la sélection, &lt;code&gt;published_at&lt;/code&gt; inclus. Heureusement, PostgreSQL propose &lt;a href="https://www.postgresql.org/docs/current/sql-select.html#SQL-DISTINCT"&gt;une autre syntaxe&lt;/a&gt; :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DISTINCT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;published_at&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;links&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;

&lt;span class="k"&gt;INNER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;links_to_collections&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lc&lt;/span&gt;
&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;link_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;

&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;published_at&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;
&lt;span class="k"&gt;LIMIT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Aïe, cette fois on obtient une erreur : « &lt;i lang="en"&gt;ERROR:  SELECT DISTINCT ON expressions must match initial ORDER BY expressions&lt;/i&gt; ». Elle indique que la colonne du &lt;code&gt;DISTINCT ON&lt;/code&gt; (&lt;code&gt;l.id&lt;/code&gt;) doit se trouver à gauche dans la liste de l’&lt;code&gt;ORDER BY&lt;/code&gt;. Mais si l’id se trouve à gauche, nos liens ne seront plus triés dans le bon ordre !&lt;/p&gt;
&lt;p&gt;À ce niveau-là, j’arrive au bout de ma créativité en termes de &lt;abbr&gt;SQL&lt;/abbr&gt; et il me faut faire appel à StackOverflow. Heureusement, je ne suis pas le premier à m’être posé &lt;a href="https://stackoverflow.com/q/9795660"&gt;la question&lt;/a&gt;. La piste était bonne&lt;sup id="fnref:1"&gt;&lt;a class="footnote-ref" href="#fn:1"&gt;1&lt;/a&gt;&lt;/sup&gt;, mais il nous faut maintenant déplacer tout ça dans une sous-requête qui sera triée à nouveau :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;l2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DISTINCT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;published_at&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;links&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;INNER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;links_to_collections&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lc&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;link_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;published_at&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DESC&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;l2&lt;/span&gt;

&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;l2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;published_at&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;l2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;
&lt;span class="k"&gt;LIMIT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Et…&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;id&lt;/th&gt;
&lt;th&gt;url&lt;/th&gt;
&lt;th&gt;published_at&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;flus.fr&lt;/td&gt;
&lt;td&gt;2022-01-20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;framasoft.org&lt;/td&gt;
&lt;td&gt;2022-01-19&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;marienfressinaud.fr&lt;/td&gt;
&lt;td&gt;2022-01-18&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Tadam ! C’est ce qu’il nous fallait !&lt;/p&gt;
&lt;p&gt;Maintenant ajoutez à ça toute la complexité d’un vrai système, avec le calcul du nombre de commentaires par lien, l’état de lecture pour l’utilisateur courant, d’autres trucs à calculer dynamiquement, etc. et vous obtenez &lt;a href="https://framagit.org/-/snippets/6456"&gt;une requête des plus agréables&lt;/a&gt; (non). N’hésitez pas à me faire savoir si vous avez une solution plus élégante ! 😄&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;Mise à jour du 12 février.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Heureusement, j’ai des copains plus malins que moi et qui apprécient particulièrement le &lt;abbr&gt;SQL&lt;/abbr&gt;. Merci à François pour cette solution bien meilleure à base de &lt;code&gt;MAX&lt;/code&gt; — pour récupérer le &lt;code&gt;published_at&lt;/code&gt; le plus récent — et de &lt;code&gt;GROUP BY&lt;/code&gt;, tout simplement.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;MAX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;published_at&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;published_at&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;links&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;

&lt;span class="k"&gt;INNER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;links_to_collections&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lc&lt;/span&gt;
&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;link_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;

&lt;span class="k"&gt;GROUP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;published_at&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;
&lt;span class="k"&gt;LIMIT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="footnote"&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;Notez que la réponse StackOverflow propose une seconde approche qui n’est pas propre à PostgreSQL. Je la trouve personnellement un poil moins facile à relire, donc je suis resté avec la solution présentée dans cet article. Ce ne sera pas forcément votre cas !&amp;#160;&lt;a class="footnote-backref" href="#fnref:1" title="Jump back to footnote 1 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</content></entry><entry><title>Terminer ses projets</title><id>urn:uuid:acd9a0e2-4d84-5810-a43e-a4d303fae9c6</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/terminer-ses-projets.html" rel="alternate" type="text/html" /><published>2022-01-28T10:22:00+01:00</published><updated>2022-01-28T10:22:00+01:00</updated><content type="html">&lt;p&gt;L’année dernière, j’ai commencé à clore un certain nombre de logiciels que j’ai écrit dans le passé. C’est le cas de &lt;a href="https://framagit.org/marienfressinaud/boop"&gt;Boop!&lt;/a&gt;, mon générateur de sites statiques, ou encore mon sélecteur de couleurs &lt;a href="https://github.com/marienfressinaud/Sweet-colors"&gt;&lt;i lang="en"&gt;Sweet Colors&lt;/i&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Pour l’instant, j’ai adopté deux stratégies pour les clore. La première consiste à simplement prévenir que le logiciel n’est plus du tout maintenu ; c’est simple et explicite. La seconde stratégie consiste à annoncer qu’aucune nouvelle fonctionnalité ne sera ajoutée au logiciel, mais que je continuerai de le maintenir en cas de faille de sécurité ou de bug. Je pourrais également être amené à mettre la documentation à jour si je la trouve incomplète.&lt;/p&gt;
&lt;p&gt;J’aimerais diffuser l’idée que terminer un logiciel peut être un signe de maturité du projet. Dans le cas de Boop!, par exemple, je considère que le projet a atteint le niveau fonctionnel que je lui souhaitais en le démarrant. Ça ne signifie pas qu’il répond à &lt;em&gt;tous&lt;/em&gt; les besoins, seulement qu’il est tel que je veux qu’il soit. &lt;strong&gt;Il n’a pas besoin d’être amélioré parce qu’il répond aux besoins auxquels il était censé répondre. C’est un logiciel fonctionnellement stable.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Terminer un projet est un acte positif.&lt;/p&gt;</content></entry><entry><title>Veille</title><id>urn:uuid:9a4dd4a3-ff44-5aeb-b1f6-1cff1fac529e</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/veille.html" rel="alternate" type="text/html" /><published>2022-01-27T20:49:00+01:00</published><updated>2022-01-27T20:49:00+01:00</updated><content type="html">&lt;p&gt;Les pages de profil commencent à arriver dans Flus. C’était ce qu’il me manquait pour me mettre à partager ma veille.&lt;/p&gt;
&lt;p&gt;Ma page de profil : &lt;a href="https://app.flus.fr/p/1670839367044869607"&gt;app.flus.fr/p/1670839367044869607&lt;/a&gt;. Vous y trouverez la liste de mes derniers liens partagés, ainsi que les collections dans lesquelles je les place. En ce moment, je range mes liens majoritairement dans la collection « &lt;a href="https://app.flus.fr/collections/1722493917394130742"&gt;📣 Partages en vrac&lt;/a&gt; », qui n’a donc pas de thème particulier.&lt;/p&gt;
&lt;p&gt;Les pages de profil disposent également d’un flux : &lt;a href="https://app.flus.fr/p/1670839367044869607/feed"&gt;app.flus.fr/p/1670839367044869607/feed&lt;/a&gt; (à ajouter dans votre agrégateur de flux &lt;abbr&gt;RSS&lt;/abbr&gt;).&lt;/p&gt;</content></entry><entry><title>Apostrophe, éditeur Markdown</title><id>urn:uuid:bef0b6d8-02a5-5783-ae39-71c10456e768</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/apostrophe.html" rel="alternate" type="text/html" /><published>2022-01-26T20:10:00+01:00</published><updated>2022-01-26T20:10:00+01:00</updated><content type="html">&lt;p&gt;Depuis quelques mois, j’utilise un éditeur Markdown pour rédiger mes articles et autres notes : &lt;a href="https://world.pages.gitlab.gnome.org/apostrophe/"&gt;Apostrophe&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Pour éditer du texte, j’utilise (Neo)Vim depuis des années, mais je ne l’ai jamais trouvé agréable pour rédiger des articles. C’est un &lt;i lang="en"&gt;feeling&lt;/i&gt; global que je n’arrive pas entièrement à expliquer.&lt;/p&gt;
&lt;p&gt;Apostrophe me fournit une interface épurée. Le peu de menu se masque dès lors que je commence à taper du texte. De plus, les quelques options de configuration sont très peu nombreuses, ce qui est parfait pour mon usage. Enfin, j’apprécie fortement le mode focus qui permet de se concentrer sur la phrase que l’on écrit. Son plus gros défaut est peut-être qu’il ne permet d’ouvrir qu’un seul document à la fois… mais, à l’usage, ça en fait une fonctionnalité plutôt intéressante.&lt;/p&gt;
&lt;p&gt;C’est en tout cas un éditeur de texte au parti pris très assumé, il ne conviendra certainement pas à tout le monde. Moi, je l’aime bien :)&lt;/p&gt;
&lt;p&gt;&lt;img alt="Capture du texte de cet article ouvert dans Apostrophe" src="images/apostrophe.png" /&gt;&lt;/p&gt;</content></entry><entry><title>Technique de décrochage : le fichier hosts</title><id>urn:uuid:3cbaa799-fca9-5086-82ba-4be1f6e23228</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/etc-hosts.html" rel="alternate" type="text/html" /><published>2022-01-25T09:00:00+01:00</published><updated>2022-01-25T09:00:00+01:00</updated><content type="html">&lt;p&gt;Certains sites mal conçus ont tendance à trop facilement voler mon attention à l’instar de Twitter et Twitch. Comme je suis très sensible à ce type de mauvais design, j’ai tenté plusieurs approches pour décrocher de ces sites. Le plus efficace à ce jour repose sur un détournement du fichier &lt;a href="https://fr.wikipedia.org/wiki/Hosts"&gt;&lt;code&gt;/etc/hosts&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Pour faire court, il s’agit d’un fichier Linux permettant de faire correspondre des noms de domaine avec des adresses IP sans passer par un serveur &lt;a href="https://fr.wikipedia.org/wiki/Domain_Name_System"&gt;&lt;abbr&gt;DNS&lt;/abbr&gt;&lt;/a&gt;. Pour ma part, je fais pointer les noms de domaine des sites que je veux bloquer vers mon adresse &lt;abbr&gt;IP&lt;/abbr&gt; locale (&lt;code&gt;127.0.0.1&lt;/code&gt;). Ainsi, lorsque j’ouvre Twitch par exemple, je me retrouve avec une belle page d’erreur, me rappelant que j’avais pris la décision de ne plus y mettre les pieds.&lt;/p&gt;
&lt;p&gt;La technique fonctionne bien car elle génère une friction importante pour la contourner, c’est-à-dire : ouvrir un terminal, taper la commande pour éditer le fichier et rentrer mon mot de passe. Par contre, elle ne fonctionne pas bien pour Twitter dans mon cas : j’ai besoin d’y accéder régulièrement &lt;a href="https://flus.fr"&gt;pour Flus&lt;/a&gt;. Ça fait partie des raisons qui m’ont poussé à &lt;a href="quitter-twitter.html"&gt;y fermer mon compte personnel&lt;/a&gt;.&lt;/p&gt;</content></entry><entry><title>Billets courts</title><id>urn:uuid:236efbd7-26d2-55ff-a259-f38a598275af</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/billets-courts.html" rel="alternate" type="text/html" /><published>2022-01-24T12:05:00+01:00</published><updated>2022-01-24T12:05:00+01:00</updated><content type="html">&lt;p&gt;J’ai pris la bonne résolution d’écrire plus souvent sur ce blog. Comme je suis plutôt mal parti en ce début d’année, j’ai pris la seconde bonne résolution de publier un billet — court — par jour&lt;sup id="fnref:1"&gt;&lt;a class="footnote-ref" href="#fn:1"&gt;1&lt;/a&gt;&lt;/sup&gt;, histoire de ne pas faire dans la demie-mesure. Pour me faciliter la tâche, j’en ai préparé quelques-uns à l’avance. J’emprunte le terme de « billet » à &lt;a href="https://nicolas-hoizey.com/billets/2022/01/12/"&gt;Nicolas&lt;/a&gt; ; j’aime bien le terme.&lt;/p&gt;
&lt;p&gt;Comme je risque de parler de Flus, il y a des chances que certains billets soient publiés &lt;a href="https://flus.fr/carnet"&gt;dans son carnet&lt;/a&gt; plutôt qu’ici.&lt;/p&gt;
&lt;p&gt;Je vois de plus en plus de blogs personnels apparaître dans mes lectures. Ça me fait plaisir de voir les usages revenir doucement vers ce format, alors autant y participer !&lt;/p&gt;
&lt;div class="footnote"&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;Remarquez que je ne parle pas de durée :)&amp;#160;&lt;a class="footnote-backref" href="#fnref:1" title="Jump back to footnote 1 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</content></entry><entry><title>Quitter Twitter</title><id>urn:uuid:d6a7dbb3-ee24-5ec5-9c66-162f8337cab3</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/quitter-twitter.html" rel="alternate" type="text/html" /><published>2022-01-06T18:16:00+01:00</published><updated>2022-01-06T18:16:00+01:00</updated><content type="html">&lt;p&gt;En ce début d’année 2022, j’ai décidé de fermer mon compte Twitter. J’avais beaucoup de bonnes raisons de le garder, mais j’en avais également pour le fermer.&lt;/p&gt;
&lt;p&gt;Mon usage de Twitter consistait essentiellement à &lt;em&gt;retweeter&lt;/em&gt; des choses, sans apporter de contenu supplémentaire ; parfois à « aimer » un contenu ; très rarement à balancer un commentaire rapide. &lt;strong&gt;Deux choses me gênaient là-dedans : la manière superficielle d’aborder le contenu, et le fait que mes partages ne bénéficient qu’aux personnes inscrites sur la plateforme.&lt;/strong&gt; En 2022, j’ai envie de prendre plus de temps pour digérer ce que je lis, écoute ou regarde. J’ai également envie de m’assurer que ce que je partage est accessible à toutes et tous : via le blog, &lt;a href="https://flus.fr"&gt;Flus&lt;/a&gt;, ou leurs flux &lt;abbr&gt;RSS&lt;/abbr&gt; respectifs. Pour suivre ce blog, vous pouvez d’ailleurs &lt;a href="abonnement.html"&gt;vous abonner à son flux&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;À cela s’ajoute que le contenu que je lisais sur Twitter était souvent négatif, voire énervé. Mon mental, déjà ébranlé par la période pandémique qui traîne en longueur, n’arrive plus à suivre. &lt;strong&gt;Je préfère prendre soin de moi en coupant ce moteur à énergie négative.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Mais ce qui aura eu raison de mon compte Twitter, c’est une fatigue accrue en fin d’année 2021 face à mon usage du numérique (j’en parle dans &lt;a href="2022.html"&gt;mon article précédent&lt;/a&gt;). J’ai réalisé à contre-temps que je croulais sous les articles de presse — souvent déprimants — et j’ai fini par me désabonner de quelques sites d’actualités que je suivais, bien que j’en apprécie le contenu. Le problème était similaire sur Twitter, mais je pensais réussir à m’en prémunir en limitant le nombre de comptes auxquels j’étais abonné. Mais le réseau social est fourbe et incite constamment à suivre plus de monde : &lt;strong&gt;lutter contre l’outil pour garder un fil d’actualité léger ne me convient plus.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Certaines de mes critiques peuvent par ailleurs s’appliquer de manière similaire à Mastodon. J’ai songé y supprimer mon compte également, mais je me laisse encore quelque temps pour me décider. Il est plus probable que je passe d’abord le compte en privé afin d’expérimenter une autre forme d’échanges.&lt;/p&gt;
&lt;p&gt;À côté de ça, je vais tout de même conserver les comptes Twitter de &lt;a href="https://twitter.com/flus_fr"&gt;Flus&lt;/a&gt; et &lt;a href="https://twitter.com/FreshRSS"&gt;FreshRSS&lt;/a&gt;, car ils servent à faire connaître les projets. Je n’y consomme de toute façon que très peu de contenu, et me contenterai à l’avenir de relayer les informations accessibles ailleurs.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Enfin, j’aime l’idée que quitter Twitter me redonne l’envie d’écrire sur ce blog, espace qui me correspond mieux en terme rédactionnel — je n’y ai aucune limite de taille, waouh ! — et de design — du fait-maison de A à Z ❤️&lt;/strong&gt;&lt;/p&gt;</content></entry><entry><title>2022</title><id>urn:uuid:15be8289-3a37-5d5a-8b95-f35d356bdf39</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/2022.html" rel="alternate" type="text/html" /><published>2022-01-04T19:30:00+01:00</published><updated>2022-01-04T19:30:00+01:00</updated><content type="html">&lt;p&gt;Les deux dernières années, j’ai trouvé plaisir à partager les grandes lignes que j’entrevoyais pour mes mois à venir (cf. &lt;a href="2020.html"&gt;2020&lt;/a&gt; et &lt;a href="2021.html"&gt;2021&lt;/a&gt;). Qui dit nouvelle année, dit donc nouvel article.&lt;/p&gt;
&lt;p&gt;Pour créer le cadre présenté ici, je me suis basé sur des notes personnelles rédigées tout au long de l’année de façon hebdomadaire. Je les ai relues ces derniers jours pour en tirer une version résumée qui m’a permis de savoir ce qui avait bien fonctionné ou non durant mon année. C’est enfin sur la base de ce résumé que j’ai décidé des grands axes que je voulais explorer cette année. Ici je ne vous en dévoile qu’une partie, le reste étant d’ordre plus personnel.&lt;/p&gt;
&lt;h2&gt;Changer de cadre&lt;/h2&gt;
&lt;p&gt;Depuis 2019, je rythmais ma façon de travailler au sein de cycles — six semaines initialement, puis un mois depuis l’an dernier — se concluant par des rétrospectives. Cela me permettait de garder un rythme de travail efficace, ce qui m’était important puisque je travaille seul chez moi. Les rétrospectives étaient des occasions de mettre en place des actions puissantes pour changer mon quotidien.&lt;/p&gt;
&lt;p&gt;Après trois ans à travailler ainsi, je ressens le besoin de fonctionner autrement. Le cadre me paraît désormais peu efficace et me fatigue. De plus, en relisant les notes des différentes rétrospectives, j’ai réalisé qu’elles tournaient toujours autour des mêmes problèmes, sans les résoudre. Leur résultat est donc mitigé.&lt;/p&gt;
&lt;p&gt;En 2021, j’ai commencé à fonctionner sur la base de « routines » hebdomadaires ou mensuelles. Une routine consiste en une liste de tâches à faire. Les tâches sont simples et répétitives, ce qui me permet de mettre en place des automatismes. Il s’agit de moments qui me demandent peu de réflexion et sont positifs pour mon moral.&lt;/p&gt;
&lt;p&gt;En 2022, je ne vais donc garder que ce système de routines. Je conserverai également une rétrospective en fin d’année et, éventuellement, quelques-unes au fil de l’eau si j’en ressens le besoin ; elles ne seront en tout cas plus faites automatiquement.&lt;/p&gt;
&lt;h2&gt;Évoluer professionnellement&lt;/h2&gt;
&lt;p&gt;Depuis fin 2019, je travaille sur &lt;a href="https://flus.fr"&gt;Flus&lt;/a&gt; à plein temps. Je pouvais me le permettre grâce à mes économies et aux  allocations que je percevais.&lt;/p&gt;
&lt;p&gt;Sans trop rentrer dans les détails — j’aurai l’occasion d’y revenir ici et dans &lt;a href="https://flus.fr/carnet"&gt;le carnet de Flus&lt;/a&gt; —, j’ai fait le choix en 2022 de trouver un job complémentaire. Mes allocations ont effectivement touché à leur fin et, même si mes économies me permettraient de tenir un an de plus, je ne pense pas que je serai en mesure de vivre de mon activité d’ici là. Enfin, je ressens de plus en plus l’envie de travailler avec d’autres personnes.&lt;/p&gt;
&lt;p&gt;Si je fais ce choix, c’est aussi parce que j’ai identifié que la seule manière pour moi d’être rapidement rentable serait de viser des entreprises. Or, ce n’est ni l’ambition ni la vision que je porte pour Flus, qui restera donc un outil à destination de particuliers. Je m’offre ainsi plus de liberté dans les choix fonctionnels puisque le critère de rentabilité ne sera pas / plus prépondérant.&lt;/p&gt;
&lt;p&gt;Idéalement, j’aimerais pouvoir continuer à dédier au moins 3 jours de travail par semaine à Flus.&lt;/p&gt;
&lt;h2&gt;Écrire ici et ailleurs&lt;/h2&gt;
&lt;p&gt;En 2020, j’avais annoncé mon envie d’écrire beaucoup plus sur ce blog ; cela s’était soldé par deux petits articles. En 2021, je ne me suis risqué à aucune prédiction pour un total de huit articles. J’ai espoir d’être plus prolifique cette année : ça me manque et l’évolution de mes pratiques numériques devrait me le permettre (j’y reviens en fin d’article).&lt;/p&gt;
&lt;p&gt;Si l’activité n’a pas été énorme sur ce blog en 2021, j’ai beaucoup plus écrit sur &lt;a href="https://flus.fr/carnet"&gt;le carnet de Flus&lt;/a&gt;. J’espère continuer cette année.&lt;/p&gt;
&lt;p&gt;Finalement, le gros changement par rapport aux années précédentes, c’est que j’ai écrit quasiment toutes les semaines en 2021. Mes notes hebdomadaires dont j’ai parlé plus haut ne se sont arrêtées que le temps de 4 semaines de vacances. Je suis le premier surpris d’avoir tenu sur la durée, mais mon système de routines n’y est pas étranger. Je compte bien continuer sur cette lancée en 2022.&lt;/p&gt;
&lt;h2&gt;Terminer des projets&lt;/h2&gt;
&lt;p&gt;En 2021, j’ai commencé à clore certains projets que j’avais développés au fil des années. Les clore a essentiellement consisté à terminer leur documentation et indiquer dans le fichier &lt;code&gt;README&lt;/code&gt; que le projet ne bénéficierait plus d’ajout de fonctionnalités. C’est notamment le cas de mon générateur de sites statiques, &lt;a href="https://framagit.org/marienfressinaud/boop"&gt;Boop!&lt;/a&gt; Terminer un projet ne consiste pas à dire qu’il est mort ; je les mettrai d’ailleurs à jour en cas de faille de sécurité ou de bug vraiment gênant par exemple. Par « terminer », je signifie simplement qu’ils sont dans un état que je considère comme complet. J’aurai — j’espère — l’occasion d’en reparler ici.&lt;/p&gt;
&lt;p&gt;En tout cas, j’aimerais continuer à clore certains projets en 2022, comme &lt;a href="https://lessy.yuzu.ovh"&gt;Lessy&lt;/a&gt;, ce qui représente toutefois une quantité de travail non négligeable compte-tenu du nombre de dépendances… Je devrai peut-être trouver une approche différente pour ce projet en particulier.&lt;/p&gt;
&lt;h2&gt;Améliorer mon assiduité&lt;/h2&gt;
&lt;p&gt;En 2021, j’ai commencé à apprendre à jouer du ukulélé. Je n’ai pas été très assidu et mon niveau n’a pas beaucoup décollé, mais j’y ai tout du moins pris du plaisir. Dans le même genre, je n’ai jamais réussi à faire des exercices physiques quotidiennement, alors que mon dos me le réclame. Il y a également cette envie de concevoir un jeu vidéo qui revient de manière cyclique, sans que je n’arrive à aller plus loin qu’un tutoriel.&lt;/p&gt;
&lt;p&gt;Bon, vous voyez où je veux en venir ! :)&lt;/p&gt;
&lt;p&gt;Pour enfin me mettre à ces activités en 2022, je compte sur un changement important dans mon quotidien : la diminution de mon temps passé sur Internet et à consommer du numérique.&lt;/p&gt;
&lt;h2&gt;Moins consommer le numérique&lt;/h2&gt;
&lt;p&gt;Je consomme énormément de numérique et ça me pose de gros soucis. En 2021, j’ai passé un temps incommensurable à regarder des vidéos YouTube, ou des gens jouer sur Twitch. J’ai également passé beaucoup trop de temps à scroller sur Twitter et, dans une moindre mesure, sur Mastodon. J’ai passé un peu moins de temps sur les plateformes de streaming, principalement parce que j’y ai arrêté mes abonnements. Enfin, j’ai lu vraiment beaucoup d’articles de presse sans pour autant être sûr de savoir ce que j’en retenais.&lt;/p&gt;
&lt;p&gt;Tout cela s’est fait à la place d’autres activités que j’aurais pu considérer comme plus utiles, des activités créatives notamment. À titre d’illustration, voici une sélection d’extraits de mes notes hebdomadaires sur le sujet.&lt;/p&gt;
&lt;p&gt;Le 9 mai :&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;J’ai passé trop de temps sur Twitch. Ce temps s’est forcément fait au détriment de temps plus « utile ».&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Le 31 août :&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Les barrières mises en place pour décrocher du PC semblent fonctionner.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Le 12 septembre :&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;C’était un weekend très inefficace et ça m’agace. Je comprends pas comment réussir à décrocher, mon cerveau trouve toujours autre chose à faire pour glander.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Le 30 décembre :&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Je viens de débrancher le câble Ethernet du PC.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Le sujet me suit depuis de nombreuses années. J’ai essayé de le traiter à quasiment chaque rétrospective 2021, avec un succès toujours mitigé. Finalement, la réponse trouvée le 30 décembre, sans être miraculeuse — la Switch trône toujours pas loin —, me permet au moins d’aborder mon &lt;abbr&gt;PC&lt;/abbr&gt; de manière différente. Débrancher Internet, peut-être est-ce ce que j’ai cherché toute l’année !&lt;/p&gt;
&lt;p&gt;Alors en 2022, je compte bien expérimenter cela à fond. Comment s’occuper sans Internet ? Comment travailler ? Les réponses ne sont sans doute pas si compliquées à trouver — d’autres s’en sortent très bien —, mais je manquais sans doute de motivation pour m’y atteler jusque-là. Je crains d’être tellement imprégné d’une culture numérique que la tâche ne soit plus compliquée qu’elle n’en a l’air. Toutefois, si je me base sur mon expérience &lt;a href="ordiphone.html"&gt;d’ordiphone déconnecté&lt;/a&gt;, cela ne devrait pas non plus être infaisable.&lt;/p&gt;
&lt;p&gt;Je suis très enthousiaste à l’idée de découvrir ce qui va émerger de cette expérience. Je compte bien la partager sur ce blog.&lt;/p&gt;</content></entry><entry><title>Ordiphone</title><id>urn:uuid:5da06594-8a78-5729-a0ee-2a0f64af3c67</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/ordiphone.html" rel="alternate" type="text/html" /><published>2021-10-04T21:38:00+02:00</published><updated>2021-10-04T21:38:00+02:00</updated><content type="html">&lt;p&gt;Je discutais hier avec un copain de nos usages respectifs de nos téléphones dits &lt;em&gt;intelligents&lt;/em&gt;. La discussion m’a permis de mieux mesurer le parcours que j’ai réalisé ces dernières années. De fait, j’ai totalement réussi à redonner à mon téléphone la place qui lui incombe : un simple outil à mon service. Je me disais que c’était l’occasion de partager quelques trucs et astuces que j’ai mises en place.&lt;/p&gt;
&lt;h2&gt;Désinstaller&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;La principale action que j’ai réalisée a aussi été la plus compliquée et la plus longue : désinstaller un maximum d’applications.&lt;/strong&gt; Ce fut compliqué car, pour chaque appli, on mesure facilement ce qu’elle nous apporte ; plus difficilement ce qu’elle nous impose. Surtout, on s’imagine difficilement vivre sans — on avait sûrement une bonne raison de l’installer en premier lieu ! De mémoire, voici les principales applications qui m’ont posé souci :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Twitter — positif : certain d’avoir toujours quelque chose de nouveau à lire ; négatif : chronophage, peut facilement générer des émotions négatives ;&lt;/li&gt;
&lt;li&gt;Signal — positif : discussion facilitée avec les proches, on ne rate aucune info ; négatif : beaucoup trop de notifications, l’appli s’impose rapidement comme indispensable ;&lt;/li&gt;
&lt;li&gt;Firefox — positif : le Web dans la poche, tout est à notre portée ; négatif : &lt;strong&gt;TOUT&lt;/strong&gt; est à notre portée ;&lt;/li&gt;
&lt;li&gt;K9 Mail (courriels) — positif : facilite encore un peu plus nos échanges, permet de transférer facilement des infos sur son téléphone via un simple courriel ; négatif : tendance à vérifier ses courriels dès qu’on a 2 minutes de libre ;&lt;/li&gt;
&lt;li&gt;Google Maps — positif : jamais perdu ; négatif : jamais perdu.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Plutôt que de peser de manière rationnelle le pour et le contre de garder ou non chaque application, je crois les avoir toutes désinstallées sur un coup de tête&lt;/strong&gt; (« je teste quelques jours, je vois ce qu’il se passe »). Le plus compliqué a été de se convaincre que je n’avais pas besoin de mes courriels sur le téléphone. Je pense que ça fait au moins 2 ans que j’ai désinstallé K9 Mail et je ne regrette absolument pas 🙂. Pour passer à l’action, je me suis imposé quelques contraintes.&lt;/p&gt;
&lt;h2&gt;Se contraindre&lt;/h2&gt;
&lt;p&gt;La première contrainte que je me suis imposée a été de limiter à deux les bureaux virtuels de l’écran d’accueil : un pour les applis, un autre pour mon agenda. &lt;strong&gt;J’ai fini par rendre cette contrainte encore plus stricte : un seul écran afin d’afficher mon agenda.&lt;/strong&gt; Les applications visibles sont dans le &lt;i lang="en"&gt;deck&lt;/i&gt; permanent et sont limitées à 4 en plus de l’icône pour ouvrir la liste des applications. Mes applications visibles sont les suivantes :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;l’appareil photo ;&lt;/li&gt;
&lt;li&gt;une application de prise de notes ;&lt;/li&gt;
&lt;li&gt;l’horloge pour les alarmes ;&lt;/li&gt;
&lt;li&gt;l’appli de &lt;abbr&gt;SMS&lt;/abbr&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;La seconde contrainte est très similaire : un seul écran pour lister mes applications.&lt;/strong&gt; Aujourd’hui, cet écran contient 24 applications. Je ne vous les liste pas toutes mais, pour les plus utiles, on retrouve les applications listées précédemment ainsi qu’un explorateur de fichiers, la galerie photo, un lecteur de musiques, l’appli de contacts, etc.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ma dernière contrainte forte a été de limiter au maximum les applications autorisées à générer des notifications.&lt;/strong&gt; Cette contrainte est très facile à s’imposer une fois qu’on a réduit la liste des applications, mais reste à mon avis importante à garder en tête. En l’occurrence, les seules applications qui me notifient sont les &lt;abbr&gt;SMS&lt;/abbr&gt;, le téléphone et l’agenda.&lt;/p&gt;
&lt;h2&gt;Accepter l’inconfort&lt;/h2&gt;
&lt;p&gt;À cette étape, vous vous dites que c’est n’importe quoi, que je dois aimer me faire mal — et alors ? —, que vous vous seriez incapable de limiter autant vos usages. Mais attendez, j’en rajoute :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;mon téléphone est un modèle de 2013, acheté en 2015 (&lt;i lang="en"&gt;fun fact&lt;/i&gt;: feu mon Firefox &lt;abbr&gt;OS&lt;/abbr&gt; venait de griller sur une prise en Bulgarie, je cherchais le modèle moins cher possible du magasin pensant que j’en rachèterais un en rentrant en France… 6 ans plus tard, il est toujours vivant !) ;&lt;/li&gt;
&lt;li&gt;il tourne sous LineageOS 11 (Android 4.4, soit une version datant de 2014) ;&lt;/li&gt;
&lt;li&gt;lié à ça, rien n’est vraiment à jour, il est donc bourré de failles et c’est sans doute ce qui m’enquiquine le plus ;&lt;/li&gt;
&lt;li&gt;le navigateur de base — que j’ai conservé — est extrêmement lent et pas du tout à jour… je n’ai donc pas besoin de me forcer pour ne pas l’utiliser ! Il est juste suffisant pour me dépanner de temps à autre, mais je pense que je pourrais tout à fait m’en passer ;&lt;/li&gt;
&lt;li&gt;l’appareil photo est nul nul nul, je suis incapable de faire des photos pas floue, mais c’est artistique.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Je ne vais pas non plus affirmer que tout est parfait : oui je rate parfois des infos qui passent par Signal, oui Google Maps aurait pu me dépanner plus d’une fois, oui ça va sans doute devenir de plus en plus pénible au fur et à mesure qu’on nous impose l’usage des &lt;i lang="en"&gt;smartphones&lt;/i&gt; (coucou les banques 👋). &lt;strong&gt;Mais, honnêtement ? je suis tellement plus serein vis-à-vis de mon téléphone depuis ces dernières années que je n’ai absolument aucune envie de revenir sur mes choix.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;Un ordiphone ?&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Finalement, la question qui reste en suspens est celle de savoir si j’ai toujours besoin d’un téléphone intelligent dans la poche ? Je pense que je pourrais effectivement m’en passer.&lt;/strong&gt; Les seules choses dont j’ai l’impression d’avoir vraiment besoin sont le téléphone et les &lt;abbr&gt;SMS&lt;/abbr&gt;. J’aurais du mal à me passer du réveil, de l’agenda, voire du lecteur de musiques, mais je suis sûr de trouver des moyens de contourner si cela venait à m’être imposé.&lt;/p&gt;
&lt;p&gt;Plusieurs points positifs à tout ça :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;je n’ai plus l’impression de faire d’efforts au quotidien pour me détacher du téléphone, mes habitudes ont totalement changé. Vous imaginez pas le bien fou que ça fait :) ce n’est plus qu’un bout de plastique qui traîne dans un coin de mon appartement et qui fait du bruit occasionnellement ;&lt;/li&gt;
&lt;li&gt;le jour où j’aurais besoin de changer de téléphone, j’aurais l’embarras du choix tout en pouvant privilégier des critères de durabilité (l’actuel s’en sort bien vu le nombre de fois où il est tombé) ;&lt;/li&gt;
&lt;li&gt;ça me réaligne un peu avec mon idéal écolo. Je ne sauverai pas la planète avec cette démarche, mais le jour où le monde fera face à une pénurie d’électricité, le manque de téléphone ne sera au moins pas un problème pour moi 😜.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Mon prochain objectif : avoir une démarche similaire avec le &lt;abbr&gt;PC&lt;/abbr&gt; qui me pose d’énormes problèmes de distractions. J’ai bien peur que ce soit plus compliqué !&lt;/p&gt;</content></entry><entry><title>Mes points médians sont-ils militants ?</title><id>urn:uuid:7273e2c4-c1e9-5659-bc40-ca0be35f1cc8</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/points-militants.html" rel="alternate" type="text/html" /><published>2021-04-28T09:10:00+02:00</published><updated>2021-04-28T09:10:00+02:00</updated><content type="html">&lt;p&gt;Il y a quelques mois, le journal Marianne a publié &lt;a href="https://www.marianne.net/agora/tribunes-libres/une-ecriture-excluante-qui-s-impose-par-la-propagande-32-linguistes-listent-les"&gt;une tribune&lt;/a&gt;
de 32 linguistes critiquant l’écriture inclusive. Cette tribune s’ouvre ainsi
(la mise en gras est de moi) :&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Présentée par ses promoteurs comme un progrès social, l’écriture inclusive
n’a paradoxalement guère été abordée sur le plan scientifique, la
linguistique se tenant en retrait des débats médiatiques. Derrière le souci
d’une représentation équitable des femmes et des hommes dans le discours,
l’inclusivisme désire cependant &lt;strong&gt;imposer des pratiques relevant d’un
militantisme ostentatoire&lt;/strong&gt; sans autre effet social que de produire des
clivages inédits. Rappelons une évidence : la langue est à tout le monde.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;La critique du militantisme est fréquente pour les « anti-inclusifs ». Elle m’a
questionné sur mon propre usage du point médian, la forme d’écriture inclusive
la plus critiquée.&lt;/p&gt;
&lt;p&gt;J’ai discrètement utilisé ce point pour la première fois en &lt;a href="2017-10-31-lessy-antlia.html"&gt;2017&lt;/a&gt;,
sur ce blog. J’ai ensuite étendu cet usage à d’autres formes écrites
(courriels, réseaux sociaux, etc.) sans en parler, et sans qu’on m’en parle. Au
final, c’est à travers les critiques portées en direction de &lt;a href="https://framasoft.org"&gt;Framasoft&lt;/a&gt;
que j’ai pris conscience de la sensibilité du sujet (&lt;a href="https://framablog.org/2018/08/13/ecriture-du-blog-nous-ne-transigerons-pas-sur-les-libertes/"&gt;lire le texte en réponse
à ces critiques&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Soyons clairs : le fait d’utiliser le point médian n’a jamais constitué une
volonté de ma part de l’« imposer » au reste de la société.&lt;/strong&gt; Qui fait donc
cela ? C’est un faux débat. Pour autant, inutile de le nier, il est
effectivement le marqueur d’un certain militantisme : celui qui revendique plus
d’égalité ainsi que la reconnaissance et la visibilité de toutes et tous au
sein de la société. Militantisme ostentatoire ? Vous jugerez.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;J’ai toujours considéré le point médian comme un outil à ma disposition.&lt;/strong&gt; Je
ne me souviens pas des raisons exactes qui m’ont poussé à l’utiliser la
première fois, mais aujourd’hui il me sert à m’adresser à un certain public. Il
me sert à dire que je suis sensible à la représentation des personnes, peu
importe le genre auquel elles s’identifient (ou non). Il me sert à m’exprimer
avec plus de précision. Il me sert à faire preuve d’empathie.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Comme tout outil, il est également imparfait et pose certainement des
problèmes d’accessibilité.&lt;/strong&gt; Je suis sensible à cet argument et c’est pour cela
que j’en fais un usage raisonné :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;je privilégie d’autres formes autant que possible : formes épicènes, accord
  de proximité, jusqu’à expérimenter quelques néologismes comme « utilisateurice » ;&lt;/li&gt;
&lt;li&gt;je ne l’utilise pas systématiquement : par exemple, plus haut, lorsque j’ai
  écrit « anti-inclusifs » par respect du choix des personnes visées à
  privilégier le masculin générique ;&lt;/li&gt;
&lt;li&gt;je privilégie une forme légère : « utilisateur‧ices » au lieu de « utilisateur‧ice‧s » ;&lt;/li&gt;
&lt;li&gt;et qui facilite la prononciation : « inclusi‧ve » au lieu de « inclusif‧ve » ;&lt;/li&gt;
&lt;li&gt;pour les puristes, j’utilise d’ailleurs le point d’hyphénation au lieu du
  point médian, car &lt;a href="https://matti-sg-fr.medium.com/point-m%C3%A9dian-final-point-dhyph%C3%A9nation-3f749c32b659"&gt;il serait ignoré par certaines synthèses vocales&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;J’ajoute que la question de l’accessibilité est bien trop sérieuse pour être
brandie comme un vulgaire « argument-chiffon ». Cela nécessiterait néanmoins un
article à part entière.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pour en revenir à la question des « militants du point médian », je n’en
comprends ni le fondement, ni la pertinence.&lt;/strong&gt; Je n’ai jamais croisé personne
affirmant qu’il fallait que cette forme devienne la norme. Je suis bien sûr
biaisé, peut-être avez-vous eu une expérience différente. Celle-ci vous
suffit-elle à généraliser ? La tribune aide justement à répondre à cette
question : « l’écriture inclusive n’a paradoxalement guère été abordée sur le
plan scientifique ». Bon courage pour prouver quoi que ce soit.&lt;/p&gt;
&lt;p&gt;Pour ma part, je ne crois ni ne souhaite que le point médian se généralise.
Paradoxal ? &lt;strong&gt;Je vois en fait le point médian comme un outil transitoire vers
quelque chose de plus accessible.&lt;/strong&gt; Peut-être un marqueur plus lisible ?
Peut-être une nouvelle forme neutre distincte du masculin ? Ou peut-être encore
la disparition du genre au sein la langue, qui sait ?&lt;/p&gt;
&lt;p&gt;Pour conclure cet article, je me contenterai de citer une fois de plus la
tribune : « &lt;strong&gt;la langue est à tout le monde&lt;/strong&gt; ».&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;J’effectue une veille active sur le sujet et &lt;a href="https://app.flus.fr/collections/1678881149731043972"&gt;partage tout un tas de ressources
sur Flus&lt;/a&gt;.
Si vous ne savez pas par où commencer et que vous souhaitez aborder le sujet
sérieusement, je vous conseille l’épisode « &lt;a href="https://www.binge.audio/podcast/parler-comme-jamais/ecriture-inclusive-pourquoi-tant-de-haine"&gt;Écriture inclusive : pourquoi tant
de haine ?&lt;/a&gt; »
du podcast « Parler comme jamais » (il dure 46 minutes, vous êtes prévenu‧e !)&lt;/p&gt;</content></entry><entry><title>Célébrer la technique</title><id>urn:uuid:1a4d635f-2bce-5dcc-9302-b0e8e85b76f4</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/celebrer-la-technique.html" rel="alternate" type="text/html" /><published>2021-04-24T21:50:00+02:00</published><updated>2021-04-24T21:50:00+02:00</updated><content type="html">&lt;p&gt;Je parle très peu de technique. Souvent, ce genre de conversations m’ennuient.
Mais à force de m’en tenir éloigné, j’ai fini par croire que la technique ne
m’intéressait pas tant que ça. J’ai fini par me dire que ce qui comptait
uniquement, c’était que le résultat final soit utile et que seule l’approche
utilisateur m’intéressait. Mais c’est faux : les deux approches m’intéressent
et je crois que je me serais reconverti depuis longtemps sans l’une ou l’autre.&lt;/p&gt;
&lt;p&gt;Aujourd’hui je vais donc parler technique en célébrant les choix que j’ai pris
depuis un an pour &lt;a href="https://github.com/flusio/flusio"&gt;flusio&lt;/a&gt;, le logiciel
derrière mon service &lt;a href="https://flus.fr"&gt;Flus&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Je suis heureux d’avoir fait le choix du &lt;abbr&gt;PHP&lt;/abbr&gt;.&lt;/strong&gt; Certains choix
de conception sont rageants, mais je suis très à l’aise avec ce langage au
quotidien. Il me permet également une certaine créativité que je ne trouve pas
avec d’autres langages.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Je suis heureux d’avoir fait le choix de (re)développer mon propre framework,
&lt;a href="https://github.com/flusio/Minz"&gt;Minz&lt;/a&gt;.&lt;/strong&gt; Il s’adapte à ma manière de penser en
fonction des problèmes que je rencontre, pas l’inverse.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Je suis heureux de son système d’abstraction des requêtes utilisateur et des
réponses serveur.&lt;/strong&gt; Cela me permet de tester une large portion du logiciel
facilement. Un effet de bord positif a été de me fournir un mécanisme de &lt;a href="https://github.com/flusio/flusio/blob/main/cli"&gt;ligne
de commande&lt;/a&gt; à peu de frais.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Je suis heureux de ne pas utiliser d’&lt;abbr&gt;ORM&lt;/abbr&gt; pour l’accès à la base de
données.&lt;/strong&gt; Le &lt;abbr&gt;SQL&lt;/abbr&gt; m’est souvent facile à lire et je me torture moins
l’esprit pour les requêtes compliquées.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Je suis heureux de mon &lt;a href="https://github.com/flusio/Minz/blob/main/src/Migrator.php"&gt;système de migrations&lt;/a&gt;
qui tient en moins de 300 lignes, commentaires inclus.&lt;/strong&gt; J’ai appris que ce
n’était pas si compliqué que ça à faire.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Je suis heureux du choix d’abstraire la création des dates derrière une classe
&lt;a href="https://github.com/flusio/Minz/blob/main/src/Time.php"&gt;&lt;code&gt;\Minz\Time&lt;/code&gt;&lt;/a&gt;.&lt;/strong&gt; Durant
les tests, cela me permet de figer le temps à une date précise et faciliter
ainsi le travail sur les dates relatives.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Je suis heureux d’avoir développé un système de jobs asynchrones au sein de
flusio plutôt qu’utiliser un logiciel dédié.&lt;/strong&gt; Ça me fait un logiciel de moins
à maîtriser et installer. Le cœur du système tient &lt;a href="https://github.com/flusio/flusio/blob/5beb930e887f7d14e0a3b774fe04c3fc9ceba8a1/src/cli/JobsWorker.php#L62-L94"&gt;en quelques lignes&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Je suis heureux de ma mini-bibliothèque &lt;a href="https://github.com/flusio/flusio/tree/main/lib/SpiderBits/src"&gt;SpiderBits&lt;/a&gt;
pour parser le Web.&lt;/strong&gt; Elle tient en 1 300 lignes de code relativement simples
et permet d’aller du &lt;a href="https://github.com/flusio/flusio/blob/main/lib/SpiderBits/src/Url.php"&gt;nettoyage d’&lt;abbr&gt;URL&lt;/abbr&gt;&lt;/a&gt;
à &lt;a href="https://github.com/flusio/flusio/blob/main/lib/SpiderBits/src/DomExtractor.php"&gt;l’extraction d’informations OpenGraph&lt;/a&gt;
en passant par &lt;a href="https://github.com/flusio/flusio/blob/main/lib/SpiderBits/src/feeds/RssParser.php"&gt;l’analyse de flux &lt;abbr&gt;RSS&lt;/abbr&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Je suis heureux du nombre de tests écrits.&lt;/strong&gt; Ça prend du temps à écrire, mais
ils m’ont sauvé plus d’une fois. Le résultat, c’est une application stable
depuis sa première version.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Je suis heureux du nombre réduit de dépendances à des bibliothèques externes
(&lt;a href="https://github.com/flusio/flusio/blob/main/composer.json"&gt;&lt;abbr&gt;PHP&lt;/abbr&gt;&lt;/a&gt;
et &lt;a href="https://github.com/flusio/flusio/blob/main/package.json"&gt;JavaScript&lt;/a&gt;).&lt;/strong&gt;
Le code externe, c’est du code que je ne maîtrise pas ; j’y fais appel avec
parcimonie.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Je suis heureux de prendre mon temps pour abstraire les concepts.&lt;/strong&gt; Je
préfère répéter du code de nombreuses fois tant que je n’ai pas trouvé
l’abstraction qui me satisfait, souvent pour mon plus grand bien.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Je suis heureux de traiter la dette technique comme l’évolution naturelle
de mon code répondant à de nouveaux problèmes,&lt;/strong&gt; pas comme de mauvais choix de
conception passés.&lt;/p&gt;
&lt;p&gt;Tout n’est pas parfait dans flusio, mais je suis heureux de chacun des choix
que j’ai pu faire, même ceux sur lesquels je souhaite revenir. Ils ont tous été
pris en connaissance de cause, en fonction de ce que j’avais comme information
à ma disposition à un instant T. Pour prendre mes décisions, je ne suis pressé
ni par une personne externe, ni par le temps. Il en résulte un logiciel
maintenable dont j’ai plaisir à parcourir le code. Même seulement au bout d’un
an de développement, ce n’est pas souvent le cas.&lt;/p&gt;
&lt;p&gt;Je crois que flusio est une bonne vitrine sur tout ce que j’ai appris en 10
ans, c’est un logiciel qui me ressemble.&lt;/p&gt;</content></entry><entry><title>De l’aléatoire en CSS ?</title><id>urn:uuid:0bdd7368-c03d-559c-8b4e-8c34e36a042d</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/css-aleatoire.html" rel="alternate" type="text/html" /><published>2021-04-09T17:00:00+02:00</published><updated>2021-04-09T17:00:00+02:00</updated><content type="html">&lt;p&gt;Ces derniers temps, un mini-projet me trottait en tête : un site qui propose
des idées de choses rapides à dessiner. La liste serait établie au préalable
par moi-même ou par des propositions externes, mais tout serait statique. Le
cahier des charges me semblait suffisamment simple pour que je puisse me passer
d’un langage dynamique à la fois côté serveur et client (ni &lt;abbr&gt;PHP&lt;/abbr&gt;,
ni JavaScript en somme). C’était sans compter que je voulais que les idées
soient suggérées de manière aléatoire.&lt;/p&gt;
&lt;p&gt;En y réfléchissant hier soir, je me suis demandé : « et si on pouvait générer
de l’aléatoire en &lt;abbr&gt;CSS&lt;/abbr&gt; ? » La réponse courte est « non », mais il
existe également une réponse longue et elle m’a été donnée par le site
CSS-Tricks : « &lt;a href="https://css-tricks.com/are-there-random-numbers-in-css/"&gt;&lt;em lang="en"&gt;Are There Random Numbers in CSS?&lt;/em&gt;&lt;/a&gt; ».&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Attention, n’utilisez pas cette technique en production.&lt;/strong&gt; Elle n’est ni
accessible, ni très maintenable. Il s’agit avant tout de jouer avec
&lt;abbr&gt;CSS&lt;/abbr&gt;. Vous êtes prévenu‧e ! 😄&lt;/p&gt;
&lt;p&gt;Le principe est assez simple : il consiste à superposer plusieurs &lt;code&gt;label&lt;/code&gt; avec
le même texte, les uns au-dessus des autres, puis à modifier leur &lt;code&gt;z-index&lt;/code&gt; en
boucle à l’infini grâce à une &lt;code&gt;animation&lt;/code&gt;. Ainsi, le clic surviendra sur un
&lt;code&gt;label&lt;/code&gt; que le visiteur ne saura pas prévoir. Les &lt;code&gt;label&lt;/code&gt; sont associés à des
champs &lt;code&gt;radio&lt;/code&gt; : il suffit alors d’adapter l’affichage en fonction du sélecteur
&lt;code&gt;input:checked&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Ce qui est marrant avec cette méthode, c’est que la génération d’aléatoire est
déplacée de l’ordinateur au visiteur.&lt;/p&gt;
&lt;p&gt;Pour ma part, j’ai adapté la solution parce qu’elle ne me convenait pas tout à
fait : j’ai préféré me baser sur des liens avec ancre et le sélecteur associé,
&lt;code&gt;:target&lt;/code&gt;. En effet, en cliquant sur un lien avec l’attribut &lt;code&gt;href="#1"&lt;/code&gt; par
exemple, le sélecteur &lt;abbr&gt;CSS&lt;/abbr&gt; &lt;code&gt;#1:target&lt;/code&gt; devient actif. Voici une
illustration :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;idee-dessin&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;1&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Un renard qui fait du surf&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;idee-dessin&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;2&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Une tomate amoureuse&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;idee-dessin&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;3&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Une pendule en retard à un rendez-vous&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;conteneur-boutons-nouvelle-idee&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt; &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;bouton-nouvelle-idee&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;#1&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Nouvelle idée ?&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt; &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;bouton-nouvelle-idee&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;#2&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Nouvelle idée ?&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt; &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;bouton-nouvelle-idee&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;#3&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Nouvelle idée ?&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Ainsi, le premier lien « Nouvelle idée ? » active le premier paragraphe, etc.
Il suffit alors de cacher en &lt;abbr&gt;CSS&lt;/abbr&gt; tous les paragraphes, sauf celui
visé par le sélecteur &lt;code&gt;:target&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;idee-dessin&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;idee-dessin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nd"&gt;target&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;block&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Il ne reste alors plus qu’à superposer les liens et animer leur &lt;code&gt;z-index&lt;/code&gt; :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;conteneur-boutons-nouvelle-idee&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;relative&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="k"&gt;keyframes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;changeOrdre&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;z-index&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;z-index&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;bouton-nouvelle-idee&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;animation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;changeOrdre&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="kt"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;infinite&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;linear&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;absolute&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;bouton-nouvelle-idee&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nd"&gt;nth-of-type&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;1&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;animation-delay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;-0.0&lt;/span&gt;&lt;span class="kt"&gt;s&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;bouton-nouvelle-idee&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nd"&gt;nth-of-type&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;2&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;animation-delay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;-0.5&lt;/span&gt;&lt;span class="kt"&gt;s&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;bouton-nouvelle-idee&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nd"&gt;nth-of-type&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;3&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;animation-delay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;-1.0&lt;/span&gt;&lt;span class="kt"&gt;s&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;bouton-nouvelle-idee&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nd"&gt;active&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;z-index&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;!important&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;La dernière règle est importante car les navigateurs génèrent un clic
uniquement si l’élément qui a reçu l’évènement &lt;code&gt;mousedown&lt;/code&gt; est le même qui
reçoit l’évènement &lt;code&gt;mouseup&lt;/code&gt;. Comme les &lt;code&gt;z-index&lt;/code&gt; changent en permanence, ce
n’est souvent pas le cas. Il faut donc forcer un peu les choses en mettant
l’élément &lt;code&gt;:active&lt;/code&gt; au premier plan. C’est expliqué dans l’article de
CSS-Tricks avec une solution plus compliquée, mais qui fait l’économie d’un
&lt;code&gt;!important&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Une dernière chose me chagrinait avec cette méthode, c’est qu’il était
compliqué d’ajouter de nouvelles phrases à la main. J’ai donc écrit un script
Python pour générer les fichiers &lt;abbr&gt;HTML&lt;/abbr&gt; et &lt;abbr&gt;CSS&lt;/abbr&gt; à partir
d’un fichier contenant des phrases.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Le code est &lt;a href="https://framagit.org/marienfressinaud/dessine-moi"&gt;sur Framagit&lt;/a&gt;,
et le résultat sur &lt;a href="https://marienfressinaud.frama.io/dessine-moi/#1"&gt;frama.io&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Avec ça je me serai bien marré, mais la prochaine fois j’utiliserai quand même
JavaScript, ce sera plus simple 😅&lt;/p&gt;</content></entry><entry><title>Des nouvelles de Lessy</title><id>urn:uuid:33490cc8-9bb4-55e5-9f1b-664945dcf7c4</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/des-nouvelles-de-lessy.html" rel="alternate" type="text/html" /><published>2021-03-14T14:43:00+01:00</published><updated>2021-03-14T14:43:00+01:00</updated><content type="html">&lt;p&gt;Je n’ai pas donné beaucoup de nouvelles de &lt;a href="https://lessy.yuzu.ovh"&gt;Lessy&lt;/a&gt; ces
derniers temps (le dernier article remonte à septembre 2018). Je profite donc
que le serveur ait cramé pour vous en retoucher deux mots.&lt;/p&gt;
&lt;p&gt;Pour rappel, Lessy est un gestionnaire de temps destiné à vous aider à mieux
vous organiser en associant à vos tâches des indicateurs clairs sur ce que vous
avez de plus urgent à réaliser (ou abandonner) dans l’immédiat. Un service est
mis à disposition gratuitement sur &lt;a href="https://lessy.yuzu.ovh"&gt;lessy.yuzu.ovh&lt;/a&gt; et le code est
&lt;a href="https://github.com/lessy-community/lessy"&gt;hébergé sur GitHub&lt;/a&gt;, le tout sous
&lt;a href="https://github.com/lessy-community/lessy/blob/master/LICENSE"&gt;licence libre&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Incendie OVH&lt;/h2&gt;
&lt;p&gt;Suite à &lt;a href="http://travaux.ovh.net/?do=details&amp;amp;id=49484&amp;amp;"&gt;l’incendie chez OVH&lt;/a&gt;
mercredi dernier, deux de mes serveurs ont été impactés : celui qui hébergeait
mes courriels, et celui qui hébergeait Lessy. J’ai remonté le premier
rapidement car il est critique pour mon quotidien (j’en ai parlé sur le &lt;a href="https://flus.fr/carnet/2021-03-10-serveur-courriels-hs.html"&gt;carnet
de Flus&lt;/a&gt;). J’ai
trainé pour celui de Lessy car j’avais l’espoir de le récupérer… finalement le
verdict est tombé vendredi soir : c’est non. J’ai donc pris le temps de
remonter le serveur ce matin. Je disposais de backups des données à la date de
mardi 9 à 18h, un moindre mal.&lt;/p&gt;
&lt;p&gt;Le serveur est toujours hébergé chez OVH, à Gravelines cette fois-ci.&lt;/p&gt;
&lt;h2&gt;Et ensuite ?&lt;/h2&gt;
&lt;p&gt;Si vous utilisez Lessy, vous vous demandez peut-être si je prévois encore de
bosser dessus. C’est une question difficile.&lt;/p&gt;
&lt;p&gt;En l’état, Lessy m’est en fait relativement peu utile. Je l’utilise
principalement pendant les périodes où j’ai la tête sous l’eau ; périodes qui
se font de plus en plus rares. Ma manière de gérer mes tâches a évolué et
j’arrive la plupart du temps à me contenter d’un bout de papier ou du tableau
blanc accroché dans ma cuisine. De plus, j’ai le sentiment qu’un outil a
tendance à figer l’évolution de mon organisation.&lt;/p&gt;
&lt;p&gt;J’aime également pouvoir accéder à ce dont j’ai besoin de me souvenir sans
avoir à allumer le PC. Je diminue ainsi le risque de me faire happer par des
activités numériques.&lt;/p&gt;
&lt;p&gt;Lessy, dans sa version actuelle, correspond en fait pas mal à ce que je
souhaitais avoir quand j’ai commencé son développement. J’ai bien des tas
d’idées, de choses à ajouter ou à changer, mais je crois qu’il s’agirait d’un
outil différent.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tout bien pensé, je crois que Lessy est terminé.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;Dites-moi ce que vous en pensez&lt;/h2&gt;
&lt;p&gt;Je vois toujours des gens s’inscrire à Lessy, j’ignore d’où elles viennent. Il
y a à l’heure actuelle plus de 3 500 comptes créés et je suis extrêmement
surpris.&lt;/p&gt;
&lt;p&gt;Je n’ai en revanche que (très) peu de retours des personnes qui l’utilisent et
j’ignore donc ce que vous en pensez. Aussi, il y a peut-être des
micro-changements à apporter qui me coûteraient peu de temps, mais qui vous
aideraient grandement au quotidien (je ne m’engage évidemment pas sur des
choses plus importantes).&lt;/p&gt;
&lt;p&gt;Bref, si vous utilisez Lessy, n’hésitez pas à &lt;a href="contact.html"&gt;me contacter&lt;/a&gt;
pour me faire vos retours, ça m’intéresse !&lt;/p&gt;</content></entry><entry><title>Une histoire de pizzas : les actions</title><id>urn:uuid:62922daf-9b0b-58de-9bcb-b0ccf34d1ba8</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/une-histoire-de-pizzas-7.html" rel="alternate" type="text/html" /><published>2021-02-14T18:00:00+01:00</published><updated>2021-02-14T18:00:00+01:00</updated><content type="html">&lt;p&gt;Hey salut, ça fait un bail hein ? Hein, quoi… plus d’un an ? Le temps passe
vite 😅 Je dois vous avouer que l’écriture de cet article m’angoissait
légèrement parce qu’il s’agissait d’un gros morceau. J’ai donc laissé trainer
quelques semaines… puis mois… puis une année entière. Mais nous y voilà !&lt;/p&gt;
&lt;p&gt;Pour redonner le contexte, j’ai donné un coup de main en 2019 à deux anciennes
collègue pour développer un mini-jeu. &lt;strong&gt;Le projet global est un site qui invite
à découvrir différents principes d’ergonomie à travers des jeux illustrant les
concepts : &lt;a href="https://www.ergogames.fr/"&gt;les Ergogames&lt;/a&gt;.&lt;/strong&gt; J’ai accepté à
condition que le code soit ouvert (&lt;a href="https://gitlab.com/sogilis/ergogames.fr"&gt;il l’est donc&lt;/a&gt;).
Le jeu sur lequel j’ai bossé consiste à déplacer un personnage (Meiko) dans une
cuisine en cliquant de case en case. L’objectif est de lui faire fabriquer une
pizza. Le principe illustré est celui des &lt;a href="https://www.ergogames.fr/principles/minimum-actions"&gt;actions minimales&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;J’ai commencé &lt;a href="serie/ergogames.html"&gt;une série d’articles&lt;/a&gt; pour expliquer
comment j’avais conçu ce jeu alors que je n’y connaissais pas grand-chose
auparavant.&lt;/strong&gt; J’y explique les étapes pas à pas en tentant d’être aussi
pédagogique que possible. Vous êtes invité‧es à lire les articles précédents
pour vous y retrouver.&lt;/p&gt;
&lt;p&gt;Durant les épisodes précédents, on s’est surtout concentré sur le visuel et les
déplacements. On a donc désormais un personnage qui peut aller de case en case,
tout en étant arrêté par des éléments « bloquants » (le frigo, le four, etc.)
Dans le dernier article, on avait ajouté la liste des étapes du jeu. Il nous
faut maintenant la rendre dynamique, en fonction des actions de Meiko !&lt;/p&gt;
&lt;p&gt;&lt;a href="une-histoire-de-pizzas/etape7.html"&gt;Le résultat du code de cet article se trouve ici.&lt;/a&gt;
Je vous invite à en lire le code source, les parties ajoutées par cet article
sont commentées.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Cette fois-ci, on ne va modifier que le JavaScript. Il nous faut commencer par
adapter quelques éléments.&lt;/p&gt;
&lt;p&gt;Premièrement, en fonction des étapes du jeu, Meiko et la pizza vont changer de
« look ». Par exemple, la pizza se trouve à l’état de boule au début du jeu,
puis Meiko va l’étaler, donc il faut adapter le visuel. Du côté de Meiko, son
look s’adapte en fonction des ingrédients qu’il porte (ou non). Ce qu’on va
faire, c’est ajouter un composant &lt;code&gt;look&lt;/code&gt;. Sa valeur sera modifiée en fonction
des actions effectuées par le joueur. On va également modifier le composant
&lt;code&gt;assets&lt;/code&gt; en l’indexant par les valeurs possibles du composant &lt;code&gt;look&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;gameStore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;meiko&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// Meiko va changer de &amp;quot;look&amp;quot; en fonction des actions, on ajoute&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// donc un nouveau composant pour le mémoriser&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;look&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;normal&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;assets&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;// On modifie notre composant &amp;quot;assets&amp;quot; pour indexer d’abord par&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;// le look et on conserve le système de &amp;quot;direction&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;normal&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;bottom&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;assets/meiko-face.svg&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;assets/meiko-droite.svg&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;assets/meiko-gauche.svg&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;top&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;assets/meiko-dos.svg&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;mozza&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;bottom&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;assets/meiko-face-mozza.svg&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;assets/meiko-droite-mozza.svg&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;assets/meiko-gauche-mozza.svg&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;top&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;assets/meiko-dos.svg&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;sauce&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;bottom&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;assets/meiko-face-sauce.svg&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;assets/meiko-droite-sauce.svg&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;assets/meiko-gauche-sauce.svg&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;top&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;assets/meiko-dos.svg&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;pizza&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;bottom&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;assets/meiko-face-pizza.svg&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;assets/meiko-droite-pizza.svg&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;assets/meiko-gauche-pizza.svg&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;top&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;assets/meiko-dos.svg&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Puis on fait la même chose avec la pizza (note : dans les articles&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// précédents, l&amp;#39;id était `dough`, j&amp;#39;ai modifié en `pizza` mais c&amp;#39;est&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// un détail)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;pizza&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// la pizza aussi change de look au fur et à mesure de la partie,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// mais pas de direction pour elle !&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;look&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;doughBall&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;assets&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;doughBall&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;assets/pate-pizza-boule.png&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;dough&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;assets/pate-pizza.svg&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;tomato&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;assets/pate-tomate.svg&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;mozza&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;assets/pizza.svg&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;profile&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;assets/pizza-plat.svg&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;/// ...&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Maintenant qu’on a modifié le fonctionnement du composant &lt;code&gt;assets&lt;/code&gt;, il faut
prendre ça en compte dans le code qui l’utilise. Heureusement pour nous il
s’agit d’une seule petite fonction simple : &lt;code&gt;entityAssetImage&lt;/code&gt;. On la retrouve
dans nos méthodes VueJS :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Vue&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;methods&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// On modifie légèrement le rendu ici puisqu’on a fait évoluer le&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// composant &amp;quot;assets&amp;quot; pour fonctionner avec le nouveau composant&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// &amp;quot;look&amp;quot;.&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;entityAssetImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;assets&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;look&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;// on récupère l&amp;#39;asset correspondant au &amp;quot;look&amp;quot; actuel&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;asset&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;assets&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;look&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;direction&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="c1"&gt;// si l&amp;#39;entité a un composant direction, il faut encore&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="c1"&gt;// piocher la bonne image&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;asset&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;direction&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="c1"&gt;// sinon, on retourne la valeur telle quelle&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;asset&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Désormais, lorsque la valeur de &lt;code&gt;look&lt;/code&gt; changera, VueJS changera pour nous
l’image affichée à l’écran. Idéalement il faudrait faire quelques vérifications
supplémentaires pour rendre le code plus robuste, mais on est sur un mini-jeu
pas critique, je privilégie la lisibilité en allant droit au but.&lt;/p&gt;
&lt;p&gt;Deuxième élément important à ajouter à notre jeu : le système qui va exécuter
les actions. Il va s’agir de fonctions exécutées quand on cliquera sur le bon
élément du jeu et qui modifieront l’état interne du jeu (&lt;code&gt;gameStore&lt;/code&gt;). Ces
fonctions vont donc être rattachées aux différentes entités via un nouveau
composant : &lt;code&gt;exec&lt;/code&gt;. Elles seront exécutées lorsqu’on cliquera sur l’entité
correspondante (au sein de la fonction &lt;code&gt;onClickSystem&lt;/code&gt;). Une facilité du jeu,
c’est qu’il n’y a toujours qu’une seule chose à faire à la fois, soit un seul
composant &lt;code&gt;exec&lt;/code&gt; à la fois. Ça nous évite quelques nœuds au cerveau. La
première action consiste à étaler la pâte, il faut donc rajouter le composant
&lt;code&gt;exec&lt;/code&gt; à la pizza-pâte :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;gameStore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;pizza&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// Le nouveau composant exec qui permet de faire avancer le jeu !&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// La première action consiste à étaler la pâte, on a donc un seul&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// composant exec qui pointe vers l&amp;#39;action `rollOutDough`.&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;exec&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;rollOutDough&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;/// ...&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;La fonction elle-même sera écrite un peu plus loin. En attendant on va ajouter
l’exécution de la fonction au sein de &lt;code&gt;onClickSystem&lt;/code&gt;, exécuté lorsqu’on clique
sur une case :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;onClickSystem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;meiko&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getEntity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;meiko&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;positionIsAccessibleFor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;meiko&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Avant de bouger Meiko, on recherche les entités situées sur la case&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// cliquée : s&amp;#39;il en existe avec le composant &amp;quot;exec&amp;quot;, alors on appelle&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// la fonction associée en lui passant le store et la position. La&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// fonction doit retourner un nouveau store mis à jour.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;entitiesAtPosition&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;searchEntitiesAt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;entitiesAtPosition&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ow"&gt;typeof&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;===&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;function&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Rien de sorcier ici, on se contente du fait que JavaScript nous permet de
référencer une fonction par son nom et de l’exécuter via cette référence en
ajoutant les parenthèses et les paramètres.&lt;/p&gt;
&lt;p&gt;On pourrait passer tout de suite à l’écriture des actions, mais il va nous
manquer une dernière mini-fonction. On va en effet avoir besoin de supprimer
des entités du &lt;code&gt;gameStore&lt;/code&gt; (ex. la sauce tomate va disparaître une fois que
Meiko l’aura attrapée).&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;// On a désormais besoin de supprimer des entités du jeu. On ne garde&lt;/span&gt;
&lt;span class="c1"&gt;// (`filter`) que les entités dont l&amp;#39;id est différent de celui passé en&lt;/span&gt;
&lt;span class="c1"&gt;// argument.&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;removeEntity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Nous avons désormais tous les éléments nécessaires pour faire avancer le jeu,
il n’y a plus qu’à écrire les actions ! Une action est en fait très simple :&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;elle commence par mettre à jour l’étape courante (l’entité &lt;code&gt;currentStep&lt;/code&gt;) ;&lt;/li&gt;
&lt;li&gt;elle ajoute un composant &lt;code&gt;exec&lt;/code&gt;, pointant vers la prochaine action, sur
   l’entité correspondante ;&lt;/li&gt;
&lt;li&gt;et supprime le composant &lt;code&gt;exec&lt;/code&gt; de l’entité actuelle ;&lt;/li&gt;
&lt;li&gt;elle peut également changer le look des entités, en supprimer, etc.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Commençons par notre première action : &lt;code&gt;rollOutDough&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;rollOutDough&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// on commence par mettre à jour l’étape actuelle&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;setEntityComponents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;currentStep&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;STEP_GRAB_TOMATO&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// puis on &amp;quot;installe&amp;quot; un composant exec sur l&amp;#39;entité &amp;quot;tomato&amp;quot; puisque&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// c’est la prochaine destination de Meiko&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;setEntityComponents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;tomato&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;exec&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;grabTomato&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;setEntityComponents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;pizza&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// Meiko vient d’étaler la pâte, il faut changer le &amp;quot;look&amp;quot; de la&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// pizza&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;look&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;dough&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// comme on n’a plus rien à faire pour le moment sur la pizza, on&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// pense à enlever son composant &amp;quot;exec&amp;quot; (sinon Meiko pourra étaler&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// la pizza plusieurs fois de suite).&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;exec&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// et finalement, on renvoie le nouveau store&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;On le voit, il s’agit uniquement de modifier le &lt;code&gt;store&lt;/code&gt; passé en paramètre à
l’aide de la fonction &lt;code&gt;setEntityComponents&lt;/code&gt; qu’on avait écrite dans un article
précédent. Si vous avez réussi à suivre jusqu’ici, ça devrait être vraiment
simple à comprendre ! Le fait de changer le &lt;code&gt;currentStep&lt;/code&gt; permet de changer
visuellement l’étape courante : c’est le code écrit dans l’article précédent.&lt;/p&gt;
&lt;p&gt;Nous avons maintenant une nouvelle action à écrire…&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;grabTomato&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// idem, on met à jour l’étape actuelle&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;setEntityComponents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;currentStep&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;STEP_SPREAD_TOMATO&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// puis on ajoute un &amp;quot;exec&amp;quot; sur la pizza car l&amp;#39;action suivante porte&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// sur elle&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;setEntityComponents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;pizza&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;exec&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;spreadTomato&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// on change le look de Meiko qui porte maintenant le pot de tomate&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;setEntityComponents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;meiko&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;look&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;sauce&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// et on enlève l&amp;#39;entité &amp;quot;tomato&amp;quot; car elle n&amp;#39;est plus présente sur le&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// plan de travail. On est d&amp;#39;accord que le pot de tomate est toujours&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// visible, mais on triche en l’intégrant visuellement à l&amp;#39;asset de&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Meiko.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;removeEntity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;tomato&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;En supprimant l’entité &lt;code&gt;tomato&lt;/code&gt;, on a supprimé par la même occasion son &lt;code&gt;exec&lt;/code&gt;.
Mais… oh non, on a encore une action à écrire ! Vous l’aurez compris, on va
continuer exactement de la même manière pour chaque action, car elles
s’enchaînent les unes après les autres. Je vous donne tout le code d’un coup.
Il y a quelques passages où j’ai triché par rapport à la version initiale du
jeu pour simplifier les explications. Ces passages sont signalés en
commentaire.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;spreadTomato&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;setEntityComponents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;currentStep&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;STEP_GRAB_MOZZA&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;setEntityComponents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;mozza&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;exec&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;grabMozza&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;setEntityComponents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;pizza&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;look&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;tomato&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;exec&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;setEntityComponents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;meiko&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;look&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;normal&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;grabMozza&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;setEntityComponents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;currentStep&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;STEP_SPREAD_MOZZA&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;setEntityComponents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;pizza&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;exec&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;spreadMozza&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;removeEntity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;mozza&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;setEntityComponents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;meiko&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;look&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;mozza&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;spreadMozza&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;setEntityComponents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;currentStep&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;STEP_GRAB_PIZZA_1&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;setEntityComponents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;pizza&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;look&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;mozza&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;exec&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;grabUncookedPizza&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;setEntityComponents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;meiko&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;look&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;normal&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;grabUncookedPizza&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;setEntityComponents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;currentStep&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;STEP_PUT_PIZZA_IN_OVEN&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;setEntityComponents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;oven&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;exec&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;putPizzaInOven&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Ici on triche un peu. On ne veut plus afficher la pizza dans le jeu.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Dans la version initiale, je supprimais le composant et le recréait&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// plus tard. Ça se basait cependant sur un mécanisme que je n&amp;#39;ai pas&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// expliqué dans ma série d&amp;#39;articles, donc je dois faire différemment.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Ici, je vire simplement le &amp;quot;look&amp;quot; pour cacher la pizza.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;setEntityComponents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;pizza&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;look&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;exec&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;setEntityComponents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;meiko&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;look&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;pizza&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;putPizzaInOven&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;setEntityComponents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;currentStep&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;STEP_GRAB_PIZZA_2&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;setEntityComponents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;oven&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;exec&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// la suite de l&amp;#39;action précédente : on redonne un look à la pizza, et&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// on change sa position à l&amp;#39;emplacement qui vient d&amp;#39;être cliqué.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;setEntityComponents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;pizza&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;look&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;profile&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// je triche encore ! Dans la version initiale on est sensé&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// attendre la cuisson de la pizza (5 secondes). Ça se base sur un&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// autre système que je n&amp;#39;ai pas expliqué dans la série d&amp;#39;articles,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// donc je saute l&amp;#39;étape de la cuisson (STEP_BAKE_PIZZA). Peut-être&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// que j&amp;#39;en parlerai dans un article bonus parce que le mécanisme&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// est intéressant.&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;exec&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;grabCookedPizza&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;setEntityComponents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;meiko&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;look&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;normal&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;grabCookedPizza&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;setEntityComponents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;currentStep&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;STEP_DELIVER_PIZZA&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;setEntityComponents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;hatch&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;exec&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;deliverPizza&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;setEntityComponents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;pizza&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;look&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;exec&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;setEntityComponents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;meiko&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;look&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;pizza&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;deliverPizza&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// et c&amp;#39;est la fin ! Remarquez qu&amp;#39;on vire le dernier &amp;quot;exec&amp;quot; sans en&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// rajouter un autre.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;setEntityComponents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;currentStep&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;STEP_FINISH&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;setEntityComponents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;hatch&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;exec&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;setEntityComponents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;pizza&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;look&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;profile&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;setEntityComponents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;meiko&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;look&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;normal&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Les actions se ressemblent vraiment toutes, la difficulté réside dans le fait
de ne pas se tromper dans l’enchaînement des étapes et des choses à faire. Un
avantage à la simplicité de ces fonctions, c’est qu’on peut écrire des tests
pour vérifier leur comportement extrêmement facilement.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Voici donc pour le dernier article « officiel » de cette série ! Celui-ci était
peut-être un peu plus dense que les autres, bien qu’au final pas excessivement
compliqué. Pour rappel, vous pouvez &lt;a href="une-histoire-de-pizzas/etape7.html"&gt;retrouver la version de cet article
ici&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;J’ai été surpris d’arriver à me replonger dans le code aussi facilement après
plus d’un an de pause dans l’écriture de la série, ce qui me conforte dans la
qualité de ce que j’ai développé (malgré les facilités et « hacks » utilisés
par endroits). &lt;strong&gt;J’aurais encore bien des choses à raconter :&lt;/strong&gt; la mise en
cache des images, les mécanismes asynchrones (dont la gestion du chronomètre),
les écrans de début et fin de jeu, etc. Certaines de ces choses m’intéressent à
écrire, d’autres moins. &lt;strong&gt;Dans tous les cas je ne veux pas m’engager à les
écrire, donc si je le fais ce sera à travers des articles « bonus ».&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;J’ai pris beaucoup de plaisir à expliquer les choses de manière didactiques, en
découpant les étapes autant que possible et en commentant un maximum de code.
Je ne sais pas si beaucoup de monde m’aura lu en intégralité, mais je serais
ravi si ça a pu être utile (ou même simplement intéresser quelqu’un).&lt;/p&gt;</content></entry><entry><title>Alléger</title><id>urn:uuid:0c378e99-a67b-54ab-9b19-bef9eea6ccb3</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/alleger.html" rel="alternate" type="text/html" /><published>2021-02-07T13:00:00+01:00</published><updated>2021-02-07T13:00:00+01:00</updated><content type="html">&lt;p&gt;J’ai parlé dans mon précédent article, &lt;a href="2021.html"&gt;2021&lt;/a&gt;, de ma volonté de
retrouver une part d’anonymat sur Internet. À l’époque je n’étais pas sûr de
savoir ce que cela signifierait pour ce site. J’envisageais notamment de
simplifier la page d’accueil et de virer le blog. J’ai trouvé une solution qui
me convenait mieux.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="index.html"&gt;La page d’accueil&lt;/a&gt; a effectivement subi un ravalement de façade
conséquent :&lt;/strong&gt; mon nom, 4 phrases et quelques liens. C’est largement suffisant
pour me présenter.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;J’ai conservé &lt;a href="blog.html"&gt;le blog&lt;/a&gt;. En revanche, j’ai décidé de garder dans
la liste principale uniquement les articles récents (6 mois et moins).&lt;/strong&gt; J’y ai
adjoint une seconde liste d’articles sélectionnés (parce qu’ils me parlent et
qu’ils racontent quelque chose sur moi). Celle-ci évoluera sans doute ;
j’aimerais n’en lister qu’une dizaine maximum. Enfin, j’ai conservé les séries
parce qu’elles recontextualisent certains articles. Finalement, peu d’anciens
articles ne sont plus accessibles directement, mais j’aime l’idée que certains
tombent dans une forme d’oubli. Ils existent toutefois toujours afin de ne pas
casser les liens pointant vers eux.&lt;/p&gt;
&lt;p&gt;De manière plus globale, j’ai allégé visuellement quelques éléments : l’en-tête
est plus simple, le pied de page ne contient plus qu’une poignée de liens. J’ai
aussi réorganisé quelques éléments pour mettre l’emphase sur le contenu
« utile ».&lt;/p&gt;
&lt;p&gt;Enfin, il n’y a plus de liens vers mes comptes de réseaux sociaux, seulement
mon adresse courriel sur la page d’accueil. Inversement, j’ai retiré les liens
vers mon site depuis mes comptes de réseaux sociaux. &lt;strong&gt;C’est une manière de
cloisonner mes identités en ligne.&lt;/strong&gt; Je continuerai sans doute de partager des
articles là-bas, mais ça ne sera pas automatique. Pour suivre le blog,
&lt;a href="abonnement.html"&gt;privilégiez les flux de syndication&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Je suis heureux de ces changements qui simplifient beaucoup de choses. Le site
est maintenant plus aligné avec ce que je veux partager en ligne. Reste plus
qu’à reprendre l’écriture d’articles 😏&lt;/p&gt;</content></entry><entry><title>2021</title><id>urn:uuid:811eb8a8-154b-5a40-80cd-83dfd4118d31</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/2021.html" rel="alternate" type="text/html" /><published>2021-01-16T19:11:00+01:00</published><updated>2021-01-16T19:11:00+01:00</updated><content type="html">&lt;p&gt;L’année dernière, dans mon article « &lt;a href="2020.html"&gt;2020&lt;/a&gt; », j’exprimais mon envie
de continuer à écrire plus d’articles sur ce blog. Si vous êtes passé‧e par
l’accueil, vous devez être en train de rigoler : je n’en ai publié que deux.&lt;/p&gt;
&lt;p&gt;Je ne suis pas certain de reprendre un meilleur rythme cette année, mais je
prends tout de même le temps de faire un point d’étape à ce moment charnière du
changement d’année (ok, avec quelques jours de retard). J’apprécie cet exercice
car il me permet de prendre du recul et de me fixer des résolutions pour
l’année à venir. Vous y lirez également en filigrane les raisons qui m’ont
poussé à moins écrire ici.&lt;/p&gt;
&lt;h2&gt;Flus, le gros morceau qui occupe&lt;/h2&gt;
&lt;p&gt;Je n’ai pas pris le temps d’en parler ici, mais &lt;a href="https://flus.fr"&gt;mon projet Flus&lt;/a&gt;
a bien décollé avec la sortie d’une deuxième version en décembre. Il s’agit
d’un média social de veille, qui s’articule autour de 3 principes : des signets
pour mettre de côté des liens à consulter plus tard, des collections pour
partager sa veille avec les autres personnes de la plateforme et un journal
qui vous suggère du contenu à lire. Il s’agit de mon activité à plein temps et
j’espère me dégager un premier revenu d’ici la fin de l’année.&lt;/p&gt;
&lt;p&gt;Le lancement de décembre a été réussi (&lt;abbr&gt;CA&lt;/abbr&gt; multiplié par 8 par
rapport aux mois précédents, 200 inscrit‧es), j’en suis content. Il reste à
transformer l’essai, mais les retours sont très positifs. Je me retrouve
maintenant sous une montagne de retours à prendre en compte (ou pas) ; c’est un
chouette problème à avoir je crois. &lt;a href="https://maiwann.net"&gt;Maiwann&lt;/a&gt; et son
expertise &lt;abbr&gt;UX&lt;/abbr&gt; m’ont été d’une aide énorme, mais j’ai toujours
l’impression de ne pas réussir à la remercier suffisamment.&lt;/p&gt;
&lt;p&gt;Flus dispose de son propre blog, &lt;a href="https://flus.fr/carnet"&gt;le carnet&lt;/a&gt;, qui a été
bien pourvu en 2020. J’espère continuer sur cette lancée en 2021, mais mon
expérience d’un tel objectif me laisse penser qu’il faut rester discret. Si
vous souhaitez en savoir plus, je vous invite à vous abonner à &lt;a href="https://flus.fr/carnet/feeds/all.atom.xml"&gt;son flux
&lt;abbr&gt;RSS&lt;/abbr&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Cycles, rythme de vie et expériences&lt;/h2&gt;
&lt;p&gt;Ces derniers mois j’ai eu l’occasion de revoir mon rapport à l’ordinateur.&lt;/p&gt;
&lt;p&gt;Les 2 confinements m’auront tapé sur le système, surtout le deuxième qui a été
compliqué. J’ai réussi à le traverser grâce à quelques jours de vacances et une
réorganisation de mon temps libre. Ça faisait quelque temps que je diminuais
le temps PC ; ça a été l’occasion de diminuer encore plus. Je me suis fixé
comme objectif de dessiner, d’écrire et de faire de l’exercice tous les jours.
Pour l’instant, à part le 25 décembre, c’est un succès. J’ai commencé par un
rythme de 5 minutes par jour – pas plus, pas moins – pendant 2 semaines. C’est
peu, mais ça m’a permis de tenir les premiers temps. J’augmente la durée au fil
des semaines, en variant selon les jours. Je commence à trouver un plaisir dans
ces activités que je n’avais pas lors de mes tentatives précédentes. C’est bon
signe.&lt;/p&gt;
&lt;p&gt;J’adapte également la place que me prend le boulot dans mon quotidien.
M’arrêter à 15h pour aller faire une balade devient possible sans que je m’en
« veuille ». Je trouve que c’est un processus difficile que de s’autoriser à
faire des journées plus courtes sans éprouver de remords ; c’est le deuxième
confinement qui a servi de déclic. Il m’est toutefois compliqué de mesurer
l’impact que ça a concrètement sur mon travail. Je travaille moins, c’est
certain, mais j’ai également la sensation d’être plus efficace. Je n’ai pas
envie de mesurer si le bilan « productif » est positif : je me sens mieux et
c’est le plus important.&lt;/p&gt;
&lt;p&gt;Enfin, je continue de fonctionner par cycles. J’ai toutefois récemment adopté
un rythme calqué sur les mois de l’année (ils faisaient 6 semaines
auparavant) : ça m’en facilite le suivi. Chaque cycle se conclut par une
rétrospective. Les actions qui en découlent sont souvent puissantes pour
changer mon quotidien. J’ai trouvé un format de rétro qui me plaît et qui est
efficace ; il m’aura fallu 2 ans.&lt;/p&gt;
&lt;h2&gt;Anonymat ?&lt;/h2&gt;
&lt;p&gt;La fin de l’année 2020 m’aura donné l’occasion de réfléchir à comment je
souhaite gérer ma présence en ligne. J’ai envie de plus d’anonymat et dévoiler
le strict minimum concernant mon identité. Ça questionne en partie la stratégie
que je voulais adopter avec Flus qui est de pouvoir mettre un nom et un visage
sur la personne qui gère le service, mais :&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;j’ai déjà créé &lt;a href="https://twitter.com/flus_fr"&gt;un compte Twitter&lt;/a&gt; séparé pour tester ;&lt;/li&gt;
&lt;li&gt;je ne souhaite pas adopter un anonymat strict ;&lt;/li&gt;
&lt;li&gt;mettre un peu de distance permettrait de mieux me protéger au cas où le
   service gagnerait en notoriété.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Tout ça est en douce réflexion et je trouve la question de la présence/identité
en ligne passionnante. J’ai envie d’explorer ça cette année.&lt;/p&gt;
&lt;p&gt;Le site et le blog s’en trouveraient potentiellement impactés. Simplification
du site ? Masquage ou arrêt du blog ? Essayer « autre chose » ? Mes envies
fluctuent sur ce point, affaire à suivre.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;J’ai eu une année plus tranquille que la précédente. Vous direz que forcément,
avec le confinement… Mais je suis persuadé que sans confinement, mon année
n’aurait pas été fondamentalement différente. Je consolide peu à peu le rythme
que j’ai adopté au début de mon chômage et apprend à prendre soin de moi au
quotidien. J’ai l’impression d’avoir plus appris sur moi durant les deux
dernières années qu’au cours des 27 années précédentes ; je me sens transformé.
Cela est sans doute dû également aux personnes que j’ai rencontrées ou que je
me suis mis à suivre sur les réseaux sociaux durant cette période. Je les
remercie.&lt;/p&gt;</content></entry><entry><title>La low-tech existe-t-elle dans le numérique ?</title><id>urn:uuid:a8897d20-20cc-56a8-93ae-38fb2c8c53ef</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/low-tech.html" rel="alternate" type="text/html" /><published>2020-03-08T10:30:00+01:00</published><updated>2020-03-08T10:30:00+01:00</updated><content type="html">&lt;p&gt;Je développe une gêne croissante vis-à-vis de la notion de « &lt;em&gt;low-tech&lt;/em&gt; » en
informatique : il me semble y déceler un biais inconfortable dans sa définition
même. Je précise que je parle en tant que développeur travaillant principalement
dans le Web. Cet article est – volontairement – biaisé.&lt;/p&gt;
&lt;p&gt;Pour comprendre l’origine de mon problème, il me faut commencer par définir ce
que j’entends par &lt;em&gt;low-tech&lt;/em&gt;. De mon point de vue, &lt;strong&gt;il s’agit avant tout d’une
notion qui s’oppose à celle de &lt;em&gt;high-tech&lt;/em&gt;.&lt;/strong&gt; Si vous effacez cette dernière du
paysage, la &lt;em&gt;low-tech&lt;/em&gt; disparaît par la même occasion car elle perdrait son
sens, sa raison d’exister. Je parle ici de la notion et non pas de l’existence
« d’objets &lt;em&gt;low-tech&lt;/em&gt; » (une roue en bois par exemple) qui ne disparaitront pas
par magie. Il nous faudrait toutefois désormais définir ce qui ferait la
spécificité d’un numérique &lt;em&gt;high-tech&lt;/em&gt; pour en tirer ce qui s’y oppose. &lt;strong&gt;Or le
numérique est intrinsèquement &lt;em&gt;high-tech&lt;/em&gt; car il se base sur des connaissances
et des techniques de pointe.&lt;/strong&gt; Le fonctionnement d’un ordinateur et déjà par
lui-même quelque chose de pointu ; que dire alors de sa fabrication ? de
celle de nos ordiphones ? et des milliers de kilomètres de câbles parcourant la
terre et les océans pour former l’Internet mondial ?&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Comment définir un terme – la low-tech numérique – si son existence même est
impossible ? &lt;sup id="fnref:1"&gt;&lt;a class="footnote-ref" href="#fn:1"&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Il est toutefois évident que certaines pratiques et outils numériques décrivent
une réalité &lt;em&gt;low-tech&lt;/em&gt;, ne serait-ce qu’à travers la définition que leur donne
leurs concepteurs et conceptrices. On peut notamment citer le site du « &lt;a href="https://solar.lowtechmagazine.com/"&gt;&lt;em&gt;low-tech
magazine&lt;/em&gt;&lt;/a&gt; », tournant sur un serveur
alimenté en énergie solaire et qui passe hors-ligne lorsque le soleil vient à
se cacher trop longtemps. En moins extrême, Gauthier Roussilhe a &lt;a href="http://gauthierroussilhe.com/fr/posts/convert-low-tech"&gt;raconté la
transition de son site vers un site « &lt;em&gt;low-tech&lt;/em&gt; »&lt;/a&gt;.
Plus récemment, Geoffrey Dorne &lt;a href="https://graphism.fr/quel-avenir-pour-les-sites-low-tech/"&gt;a également listé quelques sites (à inspiration)
&lt;em&gt;low-tech&lt;/em&gt;&lt;/a&gt;.
J’ai moi-même créé &lt;a href="https://framagit.org/marienfressinaud/boop"&gt;un générateur « low-tech » de sites statiques&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Une chose me frappe alors : le numérique &lt;em&gt;low-tech&lt;/em&gt; serait-il le Web « un point
zéro » des débuts ? de simples sites statiques à l’occasion d’un grand bond en
arrière dans nos usages ? C’est évidemment une manière très caricaturale de
voir les choses et il suffit de reprendre l’article de Geoffrey pour cela : il
y cite notamment Wikipédia et un thème pour Wordpress. On reste évidemment sur
des systèmes très simples, mais on voit que la &lt;em&gt;low-tech&lt;/em&gt; n’est pas uniquement
réservée aux sites statiques ; une part de « dynamique » y est autorisée.&lt;/p&gt;
&lt;p&gt;Reste à déterminer ce qui rentre dans la case et ce qui n’y rentre pas. Une
application métier peut-elle être &lt;em&gt;low-tech&lt;/em&gt; ? Si je me base sur mon ressenti
j’ai envie de répondre par l’affirmative. Qu’en est-il d’un service de
&lt;em&gt;streaming&lt;/em&gt; de vidéos ? Ici, j’ai envie de répondre par un franc « non »… mais
si les vidéos sont optimisées au poil de cul, mises en cache et partagées sur
le réseau local au point que leur impact écologique ne constitue plus qu’une
ridicule broutille ?&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Ce n’est peut-être pas aussi simple…&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;On voit toutefois sur cet exemple de site de &lt;em&gt;streaming&lt;/em&gt; que pour faire du
&lt;em&gt;low-tech&lt;/em&gt;, j’ai dû user de l’argument d’un certain savoir-faire technique ;
d’une technique qui me permette de réduire l’impact écologique du site en
question. Je m’étais d’ailleurs fait cette réflexion en lisant l’article de
Gauthier qui expliquait avoir réduit de 75 % le poids des vidéos qu’il
hébergeait, soit un passage de quelque 14 Go à un poids final d’environ 3 Go.
Finalement, les autres optimisations qu’il avait pu faire par ailleurs ne
représentaient plus grand-chose comparé au gain fait sur les vidéos. On aurait
pu le questionner sur l’impact de la démarche elle-même – le temps de calcul
pour optimiser les images par exemple – comparé aux gains. Quant aux vidéos il
avait fait le choix de les conserver, au moins en partie. Pourtant, tout cela
ne semblait pas avoir été fait en vain ; l’article a même été abondamment
relayé autour de moi, comme pour me certifier qu’il s’agissait bien là d’un
article de référence dans le paysage de la &lt;em&gt;low-tech&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;De tout cela, j’en tirai la conclusion que &lt;strong&gt;« faire de la &lt;em&gt;low-tech&lt;/em&gt; » n’est
pas tant lié au résultat final qu’à une démarche volontaire.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Finalement, c’est Bertrand Keller qui l’exprimait le mieux &lt;a href="https://bertrandkeller.info/2019/06/25/low-tech-concept-positif/"&gt;dans son article
« La Low-Tech, concept positif »&lt;/a&gt;
(la mise en gras est de moi) :&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Dans l’article (&lt;a href="https://bertrandkeller.info/2019/06/24/table-low-tech/"&gt;Les tables de la Low (Tech)&lt;/a&gt;),
j’ai repris la définition donnée par le &lt;a href="https://lowtechlab.org/"&gt;Low-Tech Lab&lt;/a&gt;,
pour la questionner. Je n’ai pas vu dans la définition, de notion de perte
d’usage. On parle d’utilité, d’accessibilité, de durabilité ; c’est-à-dire
&lt;strong&gt;un concept de but mais pas de perte d’usage&lt;/strong&gt; sous prétexte que ça consomme
moins d’énergie.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Pour comprendre la &lt;em&gt;low-tech&lt;/em&gt;, il faudrait donc prendre le problème par l’autre
bout : &lt;strong&gt;pour un usage donné que je considère utile, comment puis-je le rendre
le plus accessible et durable possible ?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;À ce point-là de mon article, je ne suis toujours pas aligné avec le terme
même de low-tech, mais sa finalité positive me parle bien.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Toutefois, quelque chose continue de me chiffonner et je vais l’illustrer avec
une petite anecdote. Lors du dernier &lt;a href="https://snowcamp.io/fr/"&gt;Snowcamp&lt;/a&gt;, une
conférence – Développement Zéro Déchet – a fait salle comble (c’est un
euphémisme tellement ça débordait de partout). Les intervenant·es n’abordaient
pas frontalement la notion de &lt;em&gt;low-tech&lt;/em&gt;, mais vous conviendrez que quand on
parle de « zéro déchet », on n’en est quand même pas bien loin. Il et elle
expliquaient les étapes pour optimiser une application développée précédemment
en se basant sur des principes « zéro déchet ». Sauf que – et je ne sais pas si
ça a été décidé consciemment avec le souci d’illustrer – l’application avait
été tellement mal conçue à l’origine que je trouvais l’exercice totalement
aberrant. J’ai plutôt eu l’impression d’assister à un cours d’optimisation
assez basique que réellement une réflexion autour d’un hypothétique
« développement zéro déchet ».&lt;/p&gt;
&lt;p&gt;La démarche n’en était pas moins intéressante, d’autant plus que c’est ce qui
m’a mis la puce à l’oreille qu’il pouvait y avoir un problème plus profond dans
cette histoire de &lt;em&gt;low-tech&lt;/em&gt; numérique. Finalement ne s’agirait-il pas d’une
forme de &lt;em&gt;green-washing&lt;/em&gt; pour développeur·ice en quête de sens dans son
métier ? &lt;strong&gt;Sous couvert de vouloir alléger notre empreinte carbone, nous
commencerions (enfin) à développer nos sites de manière correcte et optimisée ;
de l’optimisation technico-politique en fin de compte.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Cela cache par ailleurs un problème que je n’ai vu nulle part posé : de quel
impact concret parle-t-on ? Je n’en ai pas la réponse, mais si des études
existent sur le sujet je ne serais pas étonné que le gain du passage d’un site
dynamique à du statique soit ridiculement faible face au visionnage d’une vidéo
de chaton sur Youtube, lui-même minime face à la fabrication d’un terminal.
« Développer des sites statiques », bientôt dans les conseils du gouvernement
pour combattre le réchauffement climatique au côté de « faire pipi sous la
douche » et « trier ses courriels » !&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Mais ce serait considérer le problème uniquement d’un point de vue comptable.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;On en revient doucement à l’éternel débat : les actions individuelles de faible
impact valent-elles le coût d’être menées ? J’ai tranché pour mon cas personnel
depuis un moment en considérant que c’est très justement à chaque individu d’y
apporter une réponse. Les encourager ne me semble toutefois pas idiot en cela
qu’une action individuelle reste souvent un premier pas facile au sein d’une
démarche politique plus large (ici, « réduire notre impact environnemental »).
&lt;strong&gt;Cela ne doit pas occulter que les vrais changements surviendront à un niveau
systémique… mais est-ce qu’un ensemble d’individus ne peut pas former un
« système » en capacité de s’opposer à d’autres forces systémiques ?&lt;sup id="fnref:2"&gt;&lt;a class="footnote-ref" href="#fn:2"&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Pour résumer tout ce que j’ai dit jusque-là, on a vu que la notion de
&lt;em&gt;low-tech&lt;/em&gt; en numérique n’a pas tellement de réalité « physique » (ou alors
peut-on parler de « &lt;em&gt;low-tech-on-high-tech&lt;/em&gt; » ?) Il s’agirait aujourd’hui
plutôt d’un mouvement d’individus adoptant une démarche politique volontaire
d’optimisation de leurs sites Internet afin de réduire leur impact écologique.
Ça peut sembler extrêmement réducteur comme vision et je rappelle qu’il s’agit
uniquement de la mienne, exprimée à travers mes propres biais. Connaître
les limites d’une telle démarche me semble toutefois important pour prendre
conscience qu’il ne s’agit que d’un outil parmi d’autres pour ne pas s’en
contenter. Cela peut également aider à répondre à des critiques.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Vous ne sauverez certainement pas la planète avec des sites statiques, mais
vous aiguiserez vos engagements tout en rendant vos visiteur·heureuses&lt;sup id="fnref:3"&gt;&lt;a class="footnote-ref" href="#fn:3"&gt;3&lt;/a&gt;&lt;/sup&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Pour ma part, je ne pense pas / plus utiliser le terme de &lt;em&gt;low-tech&lt;/em&gt; car je
le trouve mal adapté à ce qu’il cherche à définir. Pour l’instant je lui
préfère la notion de « sobriété » qui a l’avantage de ne pas s’opposer
frontalement à la &lt;em&gt;high-tech&lt;/em&gt; (ce que le numérique &lt;em&gt;est&lt;/em&gt; intrinsèquement). Il
s’agit évidemment d’un choix personnel, et Bertrand – cité plus haut – s’est
aussi &lt;a href="https://bertrandkeller.info/2019/06/20/web-low-tech/"&gt;questionné&lt;/a&gt; sur le
sujet en faisant le choix inverse. Cela n’enlève rien à l’utilité de cet
&lt;em&gt;outil&lt;/em&gt; qui cherche à questionner l’impact du numérique sur le monde
physique qui nous entoure. Il vient donc s’ajouter à ma besace, en compagnie de
la notion de logiciel libre qui questionne le concept de propriété. &lt;strong&gt;Dans ces
deux cas, ce n’est pas tant leur finalité qui m’intéresse que les imaginaires
positifs qu’ils tentent de bâtir, ainsi que les cultures qui en émergent ;
comme des remèdes à un monde qui ne tourne parfois plus si rond.&lt;/strong&gt;&lt;/p&gt;
&lt;div class="footnote"&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;Sauf à vivre en Océania en 1984, évidemment.&amp;#160;&lt;a class="footnote-backref" href="#fnref:1" title="Jump back to footnote 1 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:2"&gt;
&lt;p&gt;J’avais initialement écrit « &lt;em&gt;qu’est-ce qu’un « système » si ce n’est un
  ensemble d’individus ?&lt;/em&gt; » On m’a très justement fait remarquer que cela
  occultait la présence d’autres « systèmes » comme les États ou Marchés.&amp;#160;&lt;a class="footnote-backref" href="#fnref:2" title="Jump back to footnote 2 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:3"&gt;
&lt;p&gt;L’écriture inclusive permet également d’inventer de nouveaux type de jeu
  de mots. On est d’accord que ce n’est pas super lisible par contre !&amp;#160;&lt;a class="footnote-backref" href="#fnref:3" title="Jump back to footnote 3 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</content></entry><entry><title>2020</title><id>urn:uuid:9ab29416-3f71-579c-bc70-1c9a39da3ca5</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/2020.html" rel="alternate" type="text/html" /><published>2020-01-03T10:57:00+01:00</published><updated>2020-01-03T10:57:00+01:00</updated><content type="html">&lt;p&gt;Mon année 2019 aura sans aucun doute été très riche sur le plan personnel.
J’ai notamment :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;refait mon site web ;&lt;/li&gt;
&lt;li&gt;repris goût à l’écriture (18 articles ici, 12 &lt;a href="https://flus.fr/carnet/"&gt;là-bas&lt;/a&gt;) ;&lt;/li&gt;
&lt;li&gt;participé à &lt;a href="https://framasoft.org/fr/"&gt;une super association&lt;/a&gt; ;&lt;/li&gt;
&lt;li&gt;co-organisé &lt;a href="https://sudweb.fr/"&gt;ma première conférence&lt;/a&gt; ;&lt;/li&gt;
&lt;li&gt;aidé à mettre en place &lt;a href="https://grenopolitains.fr/"&gt;une plateforme de démocratie participative&lt;/a&gt; ;&lt;/li&gt;
&lt;li&gt;développé &lt;a href="serie/ergogames.html"&gt;un mini-jeu&lt;/a&gt; ;&lt;/li&gt;
&lt;li&gt;appris à &lt;a href="https://photos.marienfressinaud.fr/pain.html"&gt;faire du pain&lt;/a&gt; ;&lt;/li&gt;
&lt;li&gt;et, surtout, entamé &lt;a href="https://flus.fr/"&gt;un nouveau projet professionnel&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Mais ce que j’ai fait ne m’intéresse guère, c’est plutôt le ressenti que tout
cela me laisse qui fait que je suis content de mon année. Pour l’année 2020, je
vais essayer de me recentrer pour approfondir quelques voies empruntées.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Valider que Flus est un projet viable&lt;/strong&gt; (ou non). Il y a encore du boulot, et
parfois beaucoup trop. J’avance pas (à pas) mais jamais aussi vite que ce que
j’aimerais, probablement lié à ma capacité à m’éparpiller. Je travaille
dessus. Et il faut que je m’améliore en communication et &lt;em&gt;marketing&lt;/em&gt;. En tout
cas ça m’amuse et je suis rentable pour l’instant, c’est déjà ça de pris.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Continuer de faire du pain&lt;/strong&gt; (genre, &lt;em&gt;beaucoup&lt;/em&gt;). J’ai commencé à en faire
après le passage de &lt;a href="https://oncletom.io/"&gt;Thomas&lt;/a&gt; à l’appartement, j’ai trouvé
ça chouette. Au début vraiment une fois de temps en temps, j’ai finalement pris
un rythme soutenu depuis la fermeture de ma boulangerie préférée à Grenoble
(&lt;a href="https://www.facebook.com/lafabriqueboulangeriefolliet"&gt;désormais à Chambéry&lt;/a&gt;).
Je me dis que ça ferait une chouette reconversion plus tard.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Continuer d’écrire&lt;/strong&gt; (genre, &lt;em&gt;pas mal&lt;/em&gt;). Pour ce blog, j’aimerais réussir à
faire quelque chose de peut-être plus &lt;em&gt;personnel&lt;/em&gt;. La liste des titres de mes
articles de 2019, dans leur majorité, me laisse une impression un peu
dérangeante, comme si je ne parlais jamais de moi dedans ; bizarre pour un blog
lié à un site personnel. Je le ressens aussi dans le « ton » que j’emploie,
dans les mots que je choisis. J’aimerais me rapprocher d’un ton plus « parlé ».
J’ai commencé à travailler dessus mais ne suis pas encore totalement satisfait.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Concevoir une &lt;abbr&gt;V2&lt;/abbr&gt; pour &lt;a href="https://lessy.yuzu.ovh/"&gt;Lessy&lt;/a&gt;&lt;/strong&gt; (et la
terminer). J’ai laissé trainer ce projet en 2019, mais je continue de
l’utiliser quotidiennement. J’ai eu une fulgurance le 1&lt;sup&gt;er&lt;/sup&gt; janvier,
et toutes les idées que j’avais pour l’améliorer se sont agencées correctement.
Je ne me vois pas « améliorer » la version actuelle, donc ce sera un
redéveloppement sur des bases plus simples, dans l’idéal tendant sur du
&lt;em lang="en"&gt;low-tech&lt;/em&gt; pour une maintenance minimale une fois que j’aurai
terminé. En tout cas la vision que j’ai des fonctionnalités est très claire.&lt;/p&gt;
&lt;p&gt;Bon, et puis j’ai décidé d’arrêter de procrastiner pour avoir le temps de faire
plus de choses. Ça fait quatre jours que je me suis fait une note mentale qui
fait qu’à chaque fois que « j’ai la flemme », je me réponds « bouge-toi » et
que ça marche. Vous inquiétez pas, ça va pas durer.&lt;/p&gt;
&lt;p&gt;Et bonne année !&lt;/p&gt;</content></entry><entry><title>Une histoire de pizzas : les étapes</title><id>urn:uuid:0617e942-946c-5132-92ad-9cbb8552b2a5</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/une-histoire-de-pizzas-6.html" rel="alternate" type="text/html" /><published>2019-12-31T10:39:00+01:00</published><updated>2019-12-31T10:39:00+01:00</updated><content type="html">&lt;p&gt;Après une petite pause, voici le sixième épisode de &lt;a href="serie/ergogames.html"&gt;ma série
d’articles&lt;/a&gt; retraçant la conception d’un mini-jeu vidéo.
Comme d’habitude, vous êtes invité·es à lire les articles précédents pour vous
y retrouver.&lt;/p&gt;
&lt;p&gt;Aujourd’hui, on va faire simple : on va afficher la liste des étapes que le
joueur devra suivre pour avancer dans le jeu. Le gros du travail se fera dans
l’article suivant.&lt;/p&gt;
&lt;p&gt;Pour ce faire, on va commencer par déclarer les étapes en JavaScript :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;// On déclare les étapes dans un objet...&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;steps&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;STEP_ROLL_OUT_DOUGH&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Étaler la pâte avec les doigts&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;STEP_GRAB_TOMATO&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Aller chercher la sauce tomate sur l’étagère&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;STEP_SPREAD_TOMATO&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Verser la sauce tomate sur la pizza&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;STEP_GRAB_MOZZA&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Aller chercher la mozzarella dans le frigo&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;STEP_SPREAD_MOZZA&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Disposer la mozzarella sur la sauce tomate&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;STEP_GRAB_PIZZA_1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Prendre la pizza&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;STEP_PUT_PIZZA_IN_OVEN&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Mettre la pizza au four&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;STEP_BAKE_PIZZA&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Cuire 5 secondes&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;STEP_GRAB_PIZZA_2&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Prendre la pizza&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;STEP_DELIVER_PIZZA&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Emporter la pizza jusqu’au passe-plat&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;STEP_FINISH&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Vue&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;#app&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;BOARD_SIZE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;gameStore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// ... que l&amp;#39;on passe ensuite à data pour pouvoir y accéder depuis la vue&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;steps&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;C’est tout bête, rien de bien méchant ici. Il nous faut désormais afficher
cette liste dans le &lt;abbr&gt;HTML&lt;/abbr&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;app&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;steps&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;steps-title&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Recette&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;transition&lt;/span&gt; &lt;span class="na"&gt;v-for&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;(step, index) in steps&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;:key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;step.id&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;
                &lt;span class="na"&gt;v-if&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;step.label&amp;quot;&lt;/span&gt;
                &lt;span class="na"&gt;:class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;[&amp;#39;steps-item&amp;#39;, { current: step.id === currentStep }]&amp;quot;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;steps-item-index&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;{{ index + 1 }}&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;steps-item-label&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;{{ step.label }}&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="cm"&gt;&amp;lt;!-- ... --&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Vous remarquerez peut-être que je déclare une class &lt;code&gt;.current&lt;/code&gt; pour indiquer
quelle est l’étape en cours. Néanmoins, je fais appel à une variable
&lt;code&gt;currentStep&lt;/code&gt; que nous n’avons pas encore déclarée. Il s’agit d’une valeur qui
va évoluer au fil du temps à travers des actions liées aux clics du joueur,
c’est-à-dire dans notre système &lt;code&gt;onClickSystem&lt;/code&gt;. Cette valeur doit donc être
déclarée dans le store du jeu. Retour dans le JavaScript :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;gameStore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="cm"&gt;/*&lt;/span&gt;
&lt;span class="cm"&gt;        On ajoute une nouvelle entité au store pour mémoriser l&amp;#39;étape&lt;/span&gt;
&lt;span class="cm"&gt;        courante. C&amp;#39;est cette valeur qui va permettre d’avancer dans le jeu&lt;/span&gt;
&lt;span class="cm"&gt;        plus tard.&lt;/span&gt;
&lt;span class="cm"&gt;    */&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;currentStep&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;STEP_ROLL_OUT_DOUGH&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Vue&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;computed&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// On déclare une donnée &amp;quot;computed&amp;quot; : il s&amp;#39;agit d&amp;#39;une donnée qui&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// est calculée depuis une autre donnée déjà stockée dans data&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// (ici, le store). Il s&amp;#39;agit juste de simplifier le code du&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// template HTML.&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;currentStep&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getEntity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;currentStep&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Avec ça, on a quasiment terminé pour cette fois-ci, on va juste ajouter un peu
de &lt;abbr&gt;CSS&lt;/abbr&gt; pour rendre le tout un poil plus joli.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c"&gt;/* Du CSS pour afficher le bloc des instructions à gauche de la zone de jeu */&lt;/span&gt;
&lt;span class="p"&gt;#&lt;/span&gt;&lt;span class="nn"&gt;app&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;justify-content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/*&lt;/span&gt;
&lt;span class="c"&gt;   Et du CSS pour styler les instructions elles-mêmes. Ironiquement, il y a&lt;/span&gt;
&lt;span class="c"&gt;   besoin de plus de CSS pour cette partie que pour la zone de jeu.&lt;/span&gt;
&lt;span class="c"&gt;*/&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;steps&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="kt"&gt;%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;margin-right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="kt"&gt;rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;.5&lt;/span&gt;&lt;span class="kt"&gt;rem&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="kt"&gt;rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;font-family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;sans-serif&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;#eee&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;.5&lt;/span&gt;&lt;span class="kt"&gt;rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;steps&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;steps-title&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;margin-bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="kt"&gt;rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;padding-bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;.25&lt;/span&gt;&lt;span class="kt"&gt;rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;text-align&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;border-bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="kt"&gt;px&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;solid&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;#ccc&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;steps&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;steps-item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;.25&lt;/span&gt;&lt;span class="kt"&gt;rem&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;.5&lt;/span&gt;&lt;span class="kt"&gt;rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;align-items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;baseline&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;#666&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;.8&lt;/span&gt;&lt;span class="kt"&gt;rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;.25&lt;/span&gt;&lt;span class="kt"&gt;rem&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;solid&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;transparent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;steps&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;steps-item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;current&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;#000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;font-weight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;bold&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;border-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;#00dbcb&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;.5&lt;/span&gt;&lt;span class="kt"&gt;rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;steps&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;steps-item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;steps-item-index&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1.25&lt;/span&gt;&lt;span class="kt"&gt;rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1.25&lt;/span&gt;&lt;span class="kt"&gt;rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;margin-right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;.25&lt;/span&gt;&lt;span class="kt"&gt;rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;flex-shrink&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;align-items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;justify-content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;#fff&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;#666&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="kt"&gt;%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;steps&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;steps-item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;current&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;steps-item-index&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;#000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;#00dbcb&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Avant de finir cet article, je veux juste pointer une petite différence
vis-à-vis du jeu initial. J’ai fait le choix ici d’afficher toutes les
instructions pour simplifier légèrement le code et ne pas rentrer dans des
détails inutiles d’implémentation. Dans le jeu des Ergogames, seulement deux
instructions sont affichées à la fois : l’étape courante et l’étape suivante.
Si le détail technique n’est pas important, il l’est cependant d’un point de
vue utilisabilité. Cette partie a beaucoup évolué avec les retours des
utilisateurs et utilisatrices, notamment pour satisfaire la contrainte de
l’écran réduit sur mobile. Ce n’est d’ailleurs même pas moi qui aie fait les
derniers changements.&lt;/p&gt;
&lt;p&gt;Il ne vous reste plus qu’à tester &lt;a href="une-histoire-de-pizzas/etape6.html"&gt;le résultat du code de cet article ici&lt;/a&gt;.
Il n’y a rien de plus à faire qu’à regarder puisque nous n’avons pas encore
implémenté les actions qui vont permettre d’avancer dans le jeu. Ce sera
l’objet du prochain article.&lt;/p&gt;</content></entry><entry><title>Sortie de Boop! 0.4 à l’arrache</title><id>urn:uuid:1b4f37ee-01ee-5dde-b4b3-aa900893e87c</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/sortie-de-boop-040-a-l-arrache.html" rel="alternate" type="text/html" /><published>2019-11-16T20:15:00+01:00</published><updated>2019-11-16T20:15:00+01:00</updated><content type="html">&lt;p&gt;Je me rends compte ce soir que cela fait un an que j’ai commencé mon générateur
de sites statiques, &lt;a href="https://framagit.org/marienfressinaud/boop"&gt;&lt;em lang="en"&gt;Boop!&lt;/em&gt;&lt;/a&gt;.
Comme je n’ai pas sorti de version depuis un petit moment, je fais donc ça
maintenant, au pied levé.&lt;/p&gt;
&lt;p&gt;Pour les personnes qui débarquent, il s’agit d’un projet totalement personnel,
sans ambition aucune : je fais ça pour m’amuser.&lt;/p&gt;
&lt;p&gt;Pour les personnes qui se posent la question : oui je continue de l’utiliser,
et même de plus en plus. C’est notamment &lt;em lang="en"&gt;Boop!&lt;/em&gt; qui est
utilisé pour mon blog « &lt;a href="https://flus.fr/carnet/"&gt;carnet de flus&lt;/a&gt; » ainsi que
pour le site indiquant &lt;a href="https://status.flus.io/"&gt;le statut de Flus&lt;/a&gt;. À chaque
fois, cela m’a permis d’améliorer un peu plus le programme. Petit tour
d’horizon des nouveautés.&lt;/p&gt;
&lt;p&gt;Le truc qui aurait dû être dans la dernière version – je sais pas pourquoi je
n’ai pas sorti une autre version d’ailleurs à l’époque – ce sont plus de
variables accessibles dans les &lt;em lang="en"&gt;templates&lt;/em&gt;. J’avais notamment
besoin d’afficher les séries sur la page du blog.&lt;/p&gt;
&lt;p&gt;Tant qu’on est dans les &lt;em lang="en"&gt;templates&lt;/em&gt;, j’ai ajouté un nouveau
mot clé (&lt;code&gt;set&lt;/code&gt;) permettant d’assigner des variables. &lt;a href="https://framagit.org/marienfressinaud/boop/commit/74706dc789a3879a6d4c7d8b08ed4be4700d4883"&gt;6 lignes de codes en plus&lt;/a&gt;,
c’est pas cher payé pour la prise de tête que &lt;a href="https://github.com/flusio/status/blob/master/templates/blog.html#L39-L41"&gt;je me suis ainsi
évité&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;J’ai également ajouté le support des articles privés (qui n’apparaissent ni dans
les flux Atom, ni sur la page principale du blog). C’était fait &lt;a href="https://framagit.org/marienfressinaud/boop/commit/5e73a2c1c037bd899216ed7250f675389c9bc13d"&gt;en 5
lignes&lt;/a&gt;,
je vois pas pourquoi je me serais privé (&lt;em&gt;*ba-dum tss*&lt;/em&gt; 🥁).&lt;/p&gt;
&lt;p&gt;Ensuite, la possibilité de modifier le « &lt;em&gt;slug&lt;/em&gt; » de la page principale du blog
permet notamment d’en faire une page d’accueil, &lt;a href="https://github.com/flusio/carnet/blob/master/configuration.yml#L6"&gt;comme sur « carnet de
flus »&lt;/a&gt;.
Cette fois-ci j’ai étonnamment &lt;a href="https://framagit.org/marienfressinaud/boop/commit/e4612f49fc6889f7c20c0938911185da0fbe7eb6"&gt;enlevé plus de lignes de code&lt;/a&gt;
que j’en ai ajoutées, ça fait plaisir.&lt;/p&gt;
&lt;p&gt;J’ai activé l’extension Markdown qui permet d’ajouter &lt;a href="https://framagit.org/marienfressinaud/boop/commit/5c5e783fbe27e10ced71bea2bb8db7b6324503a6"&gt;la coloration
syntaxique&lt;/a&gt;)
dans les articles. J’en avais particulièrement besoin pour ma série
« &lt;a href="serie/ergogames.html"&gt;Ergogames, une histoire de pizzas&lt;/a&gt; ». Ça aurait été
illisible sans ça.&lt;/p&gt;
&lt;p&gt;Un truc qui m’aura pris un peu plus de temps (&lt;a href="https://tutut.delire.party/@marien/103092297547337615"&gt;2h pour 50 lignes de code&lt;/a&gt;)
mais me permet de rester serein, c’est l’ajout d’&lt;a href="https://framagit.org/marienfressinaud/boop/commit/f1891cd5c955cc723d1b1211cfb71ca92e70b685"&gt;un système de cache&lt;/a&gt;
pour les articles. Le site est désormais généré en 0,3 seconde au lieu de 2
secondes avant. 2s ça peut paraître peu, mais c’est énorme lorsque je relis un
article et que je le régénère plusieurs fois par minute.&lt;/p&gt;
&lt;p&gt;J’ajoute à cela des micro-trucs, comme :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;le site qui est généré dans le répertoire &lt;code&gt;./_site&lt;/code&gt; au lieu de &lt;code&gt;./site&lt;/code&gt; (ça
  me permet de le distinguer très facilement des autres répertoires) ;&lt;/li&gt;
&lt;li&gt;le fait de pouvoir forcer la génération d’un flux RSS même lorsqu’il n’y a
  pas encore d’article publié ;&lt;/li&gt;
&lt;li&gt;l’affichage du temps de génération pour se rendre compte de si c’est trop
  long ou pas ;&lt;/li&gt;
&lt;li&gt;ou encore le fait d’afficher les derniers articles écrits en toute fin de
  terminal (ce qui m’évite de devoir scroller vers le haut pour retrouver mon
  article en cours d’écriture au milieu de la liste).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Je parle de « micro-trucs » mais ce n’est vraiment pas des détails pour moi :
c’est ce qui fait que je trouve mon expérience utilisateur bien au-dessus de
celles que j’ai pu avoir avec d’autres générateurs de sites statiques. Par
contre je parle bien de « mon » expérience : c’est totalement pensé par et pour
moi. Déjà il va falloir que j’améliore grandement la documentation pour en
faire un truc plus accessible à d’autres.&lt;/p&gt;
&lt;p&gt;Tout ça pour dire que &lt;em lang="en"&gt;Boop!&lt;/em&gt; 0.4 est sortie, youpi ! 🎉&lt;/p&gt;</content></entry><entry><title>Une histoire de pizzas : coup de pinceau</title><id>urn:uuid:c899de83-c8df-5777-81bc-bce4330bf8ad</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/une-histoire-de-pizzas-5.html" rel="alternate" type="text/html" /><published>2019-11-11T18:00:00+01:00</published><updated>2019-11-11T18:00:00+01:00</updated><content type="html">&lt;p&gt;Vous aimez les pizzas ? Vous aimez les ratons laveurs ? Alors voici déjà le
cinquième épisode de &lt;a href="serie/ergogames.html"&gt;ma série d’articles&lt;/a&gt; retraçant la
conception d’un mini-jeu vidéo !&lt;/p&gt;
&lt;p&gt;Dans &lt;a href="une-histoire-de-pizzas-2.html"&gt;le deuxième article&lt;/a&gt;, on ne s’était pas
trop embêté pour les graphismes : on avait fait de gros blocs de couleurs
moches. Il est toutefois temps de corriger ça en passant un coup de peinture
sur le jeu. Notre raton va bientôt ressembler à un raton !&lt;/p&gt;
&lt;p&gt;Le premier ingrédient qu’il nous faut, c’est un graphiste ; et surprise, je ne
le suis pas. Mes anciennes collègues de &lt;a href="https://twitter.com/UxShadow"&gt;uxShadow&lt;/a&gt;
ont fait appel à &lt;a href="https://twitter.com/GoulvenBARON"&gt;Goulven Barron&lt;/a&gt; pour
réaliser les graphismes du jeu (merci à lui !), je n’avais ainsi plus qu’à les
intégrer.&lt;/p&gt;
&lt;p&gt;Pour cet article, je me suis donc contenté de récupérer &lt;a href="https://gitlab.com/sogilis/ergogames.fr/tree/master/src/assets/img/pizzas"&gt;des images&lt;/a&gt;
du jeu d’origine et de les déposer dans un répertoire &lt;code&gt;assets&lt;/code&gt; (qu’on peut
traduire par « ressources » en bon françois).&lt;/p&gt;
&lt;p&gt;Ensuite, il ne nous reste plus qu’à attacher chaque entité à une image et à
l’afficher. Pour cela, on va tout simplement créer un nouveau composant au sein
des entités (&lt;code&gt;asset&lt;/code&gt;) qui contiendra l’&lt;abbr&gt;URL&lt;/abbr&gt; vers l’image et
ajouter cette dernière au &lt;abbr&gt;HTML&lt;/abbr&gt; à l’aide d’une balise &lt;code&gt;&amp;lt;img /&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;app&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;board&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="cm"&gt;&amp;lt;!-- ... --&amp;gt;&lt;/span&gt;

        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;
          &lt;span class="na"&gt;v-for&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;entity in store&amp;quot;&lt;/span&gt;
          &lt;span class="na"&gt;:key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;entity.id&amp;quot;&lt;/span&gt;
          &lt;span class="na"&gt;:class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;[&amp;#39;board-cell-entity&amp;#39;, entity.id]&amp;quot;&lt;/span&gt;
          &lt;span class="na"&gt;:style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;entityPosition(entity)&amp;quot;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="cm"&gt;&amp;lt;!-- On affiche une image si l&amp;#39;entité possède un composant &amp;quot;asset&amp;quot; --&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;img&lt;/span&gt;
                &lt;span class="na"&gt;v-if&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;entity.asset&amp;quot;&lt;/span&gt;
                &lt;span class="na"&gt;:src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;entity.asset&amp;quot;&lt;/span&gt;
                &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;
                &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;entity-asset&amp;quot;&lt;/span&gt;
            &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;

            &lt;span class="cm"&gt;&amp;lt;!-- Sinon, on continue d&amp;#39;afficher le label --&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;v-else-if&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;entity.label&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;entity-label&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                {{ entity.label }}
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

        &lt;span class="cm"&gt;&amp;lt;!-- ... --&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;gameStore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// On se contente d&amp;#39;ajouter un composant &amp;quot;asset&amp;quot; à chacune de nos&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// entités. Il s’agit juste d&amp;#39;une URL vers une image.&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;meiko&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;asset&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;assets/meiko-face.svg&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;mozza&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;asset&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;assets/pot-mozzarella.svg&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;tomato&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;asset&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;assets/sauce-tomate.svg&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;dough&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;asset&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;assets/pate-pizza-boule.png&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;oven&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;asset&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;assets/four.svg&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;hatch&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;asset&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;assets/passeplat.svg&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;fridge&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;asset&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;assets/refrigirateur.svg&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;workplan&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;asset&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;assets/plan-travail.svg&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;shelf&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;asset&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;assets/etagere-horizontale.svg&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;style&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;text/css&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c"&gt;/* ... */&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c"&gt;/*&lt;/span&gt;
&lt;span class="c"&gt;        On vire quasiment tout le CSS concernant les entités (sauf les z-index)&lt;/span&gt;
&lt;span class="c"&gt;        et on le remplace par... seulement ce max-width pour éviter que les&lt;/span&gt;
&lt;span class="c"&gt;        images débordent des cases. Vous vous attendiez à plus de CSS ? :)&lt;/span&gt;
&lt;span class="c"&gt;    */&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;board-cell-entity&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;img&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;max-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="kt"&gt;%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c"&gt;/* Bon OK, on en ajoute un pour que la mozza ne déborde pas trop du frigo */&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;board-cell-entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;mozza&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;img&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;max-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;85&lt;/span&gt;&lt;span class="kt"&gt;%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c"&gt;/* ... */&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;style&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Et voilà, en seulement quelques lignes, on a largement transformé notre jeu. On
est désormais visuellement très proches du jeu d’origine. Un petit détail
toutefois reste à régler : on aimerait bien que Meiko se tourne dans la
direction vers laquelle on vient de cliquer. Pour cela on va avoir besoin de 4
images représentant Meiko : une pour chaque direction. La question qui se pose
est : « comment changer d’image ? »&lt;/p&gt;
&lt;p&gt;Je vais aborder ici deux solutions possibles pour faire cela. Le choix que j’ai
fait n’est pas forcément le meilleur, mais il sera justifié. Libre à vous de
penser que c’est vraiment n’importe quoi et de préférer l’autre solution.&lt;/p&gt;
&lt;p&gt;La première façon de faire est de regrouper toutes les images au sein d’un seul
fichier : un « &lt;em&gt;sprite&lt;/em&gt; » (ou lutin, c’est &lt;a href="https://fr.wikipedia.org/wiki/Sprite_(jeu_vid%C3%A9o)"&gt;Wikipédia qui le dit&lt;/a&gt;,
j’ai toujours entendu parler que de &lt;em&gt;sprite&lt;/em&gt;). Ensuite, il faut afficher
seulement une partie de l’image, en fonction d’une classe &lt;abbr&gt;CSS&lt;/abbr&gt; par
exemple. Je ne rentre pas dans le détail de l’implémentation, les méthodes
sont de plus sensiblement différentes si vous avez un &lt;abbr&gt;PNG&lt;/abbr&gt; ou un
&lt;abbr&gt;SVG&lt;/abbr&gt;. Cette technique me posait plusieurs problèmes :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;générer un &lt;em&gt;sprite&lt;/em&gt; est un poil plus pénible (soit on complique la tâche de
  la personne qui génère l’image, soit on complique la chaîne de &lt;em&gt;build&lt;/em&gt; du
  projet)&lt;/li&gt;
&lt;li&gt;je ne savais pas faire avec des &lt;abbr&gt;SVG&lt;/abbr&gt; et n’avais pas envie de
  passer trop de temps là-dessus, ayant des choses plus intéressantes à
  développer par ailleurs (c’est important d’utiliser son temps à bon
  escient 😉)&lt;/li&gt;
&lt;li&gt;je pensais que ça me poserait des problèmes de &lt;em&gt;responsive design&lt;/em&gt; (problèmes
  grandement exagérés par le fait que je ne savais pas faire, tout est lié !)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Bref, je suis parti sur une seconde solution plus naïve, moins performante et
moins élégante, mais qui me permettait au moins d’avancer sans me poser trop de
questions.&lt;/p&gt;
&lt;p&gt;La technique est simple. Chaque image se trouve dans un fichier à part, et on
les rattache via un composant &lt;code&gt;assets&lt;/code&gt; (notez le « s » final, c’est un autre
composant !) qui va regrouper ces images, indexées par des directions. Lors de
l’affichage, on va calculer dynamiquement l’image à afficher en fonction de la
direction vers laquelle Meiko est dirigé. Ça ressemble à ça :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;app&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;board&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="cm"&gt;&amp;lt;!-- ... --&amp;gt;&lt;/span&gt;

        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;
          &lt;span class="na"&gt;v-for&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;entity in store&amp;quot;&lt;/span&gt;
          &lt;span class="na"&gt;:key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;entity.id&amp;quot;&lt;/span&gt;
          &lt;span class="na"&gt;:class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;[&amp;#39;board-cell-entity&amp;#39;, entity.id]&amp;quot;&lt;/span&gt;
          &lt;span class="na"&gt;:style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;entityPosition(entity)&amp;quot;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="cm"&gt;&amp;lt;!-- On affiche une image si l&amp;#39;entité possède un composant &amp;quot;asset&amp;quot; --&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;img&lt;/span&gt;
                &lt;span class="na"&gt;v-if&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;entity.asset&amp;quot;&lt;/span&gt;
                &lt;span class="na"&gt;:src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;entity.asset&amp;quot;&lt;/span&gt;
                &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;
                &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;entity-asset&amp;quot;&lt;/span&gt;
            &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;

            &lt;span class="cm"&gt;&amp;lt;!--&lt;/span&gt;
&lt;span class="cm"&gt;                Ou bien un composant &amp;quot;assets&amp;quot;, il faut alors calculer&lt;/span&gt;
&lt;span class="cm"&gt;                dynamiquement l&amp;#39;image à afficher.&lt;/span&gt;
&lt;span class="cm"&gt;            --&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;img&lt;/span&gt;
                &lt;span class="na"&gt;v-else-if&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;entity.assets&amp;quot;&lt;/span&gt;
                &lt;span class="na"&gt;:src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;entityAssetImage(entity)&amp;quot;&lt;/span&gt;
                &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;
                &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;entity-asset&amp;quot;&lt;/span&gt;
            &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;

            &lt;span class="cm"&gt;&amp;lt;!-- Sinon, on continue d&amp;#39;afficher le label --&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;v-else-if&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;entity.label&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;entity-label&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                {{ entity.label }}
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

        &lt;span class="cm"&gt;&amp;lt;!-- ... --&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;gameStore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;meiko&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;// Pour Meiko, on remplace le composant &amp;quot;asset&amp;quot; par &amp;quot;assets&amp;quot;. Cela&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;// nous permettra d&amp;#39;associer plusieurs images, la bonne sera&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;// choisie dynamiquement lors de l&amp;#39;affichage.&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;assets&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;bottom&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;assets/meiko-face.svg&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;assets/meiko-droite.svg&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;assets/meiko-gauche.svg&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;top&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;assets/meiko-dos.svg&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;// On ajoute également un composant &amp;quot;direction&amp;quot; à Meiko&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;direction&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;bottom&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Vue&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;methods&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;// Cette méthode JS calcule dynamiquement l&amp;#39;image à afficher pour&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;// les entités possédant un composant &amp;quot;assets&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;entityAssetImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;assets&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;direction&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="c1"&gt;// Comme le composant &amp;quot;assets&amp;quot; est indexé par les directions,&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="c1"&gt;// récupérer la bonne image se fait très facilement. Ce code&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="c1"&gt;// n’est pas très robuste mais comme le jeu est très simple&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="c1"&gt;// avec peu de contributeurices, on peut s’en contenter pour&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="c1"&gt;// l&amp;#39;instant.&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;assets&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;direction&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;La dernière étape consiste à changer effectivement la direction de Meiko en
fonction d’où le clic a été effectué. Vous l’aurez compris : on va modifier
l’état du store, cela se passe donc au sein de notre système &lt;code&gt;onClickSystem&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;onClickSystem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Notre code doit s&amp;#39;exécuter avoir vérifié que Meiko peut accéder à la&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// case ciblée, sinon il ne doit pas bouger du tout.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;meiko&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getEntity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;meiko&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;positionIsAccessibleFor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;meiko&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// On veut désormais changer la direction de Meiko : il suffit de&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// comparer sa position à la position de la case ciblée pour savoir&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// vers où Meiko doit se tourner.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;direction&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;meiko&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;direction&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;meiko&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;direction&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;right&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;meiko&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;direction&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;left&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;meiko&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;direction&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;top&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;meiko&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;direction&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;bottom&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;setEntityComponents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;meiko&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;direction&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// On fait bien attention à utiliser le updatedStore à partir d’ici au&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// lieu du store sinon Meiko ne se tournera pas.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;entitiesAtPosition&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;searchEntitiesAt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entitiesAtPosition&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;some&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;obstruct&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;setEntityComponents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;meiko&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Avec ça on a fini notre coup de peinture sur le jeu. D’ailleurs, on a même
terminé de toucher au &lt;abbr&gt;HTML&lt;/abbr&gt; concernant la zone de jeu elle-même :
même pas 50 lignes de code. Vous remarquerez sans doute en testant le jeu (&lt;a href="une-histoire-de-pizzas/etape5.html"&gt;le
résultat est ici&lt;/a&gt;) que Meiko ne change pas
immédiatement de direction : il s’agit du temps de charger l’image la première
fois. On corrigera ça plus tard dans un article bonus. Pour l’instant, on a
quelque chose de bien plus important à faire : ajouter les étapes ainsi que les
actions pour avancer dans le jeu. Ce sera l’objet des deux prochains articles
(au moins !)&lt;/p&gt;</content></entry><entry><title>Une histoire de pizzas : contraindre les mouvements</title><id>urn:uuid:ad8fbe57-b85b-5203-8599-8be6f8be4df1</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/une-histoire-de-pizzas-4.html" rel="alternate" type="text/html" /><published>2019-11-06T09:00:00+01:00</published><updated>2019-11-06T09:00:00+01:00</updated><content type="html">&lt;p&gt;Bienvenue sur le déjà quatrième article retraçant le développement d’un
mini-jeu web que j’ai développé pour les &lt;a href="https://ergogames.fr"&gt;Ergogames&lt;/a&gt;. Les
introductions se suivent et se ressemblent toutes alors commencez par lire &lt;a href="serie/ergogames.html"&gt;les
autres articles de la série&lt;/a&gt; avant d’aller plus loin si
vous voulez comprendre quelque chose.&lt;/p&gt;
&lt;p&gt;Bien, on a donc vu dans &lt;a href="une-histoire-de-pizzas-3.html"&gt;l’épisode précédent&lt;/a&gt;
comment mouvoir le petit corps de Meiko. Le problème qui se posait alors est
qu’il pouvait se déplacer n’importe où sur le terrain de jeu. Je vous propose
donc de voir comment le forcer à se déplacer de case en case, sans monter sur
le frigo ni l’étagère (c’est dangereux !!)&lt;/p&gt;
&lt;p&gt;Pour ce faire, on touchera uniquement au JavaScript cette fois-ci : tout se
passera dans notre système &lt;code&gt;onClickSystem&lt;/code&gt;, celui qui prend un clic en entrée
et modifie la position de Meiko. On commence par vérifier que le clic a bien
été fait sur une case du jeu :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;onClickSystem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ceil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;layerX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;CSS_CELL_SIZE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ceil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;layerY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;CSS_CELL_SIZE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// On vérifie que la position visée correspond bien à une case du jeu.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// En théorie c&amp;#39;est toujours le cas (souvenez-vous la modification&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// faite en CSS dans l&amp;#39;article précédent), mais c&amp;#39;est bien de le&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// vérifier en JS aussi.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;BOARD_SIZE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;BOARD_SIZE&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Si le clic est en dehors du terrain, on retourne le store tel quel, pas besoin
de faire autre chose.&lt;/p&gt;
&lt;p&gt;La seconde étape est de vérifier que Meiko a effectivement accès à la case sur
laquelle on vient de cliquer. Il faut pour cela qu’il s’agisse d’une case
adjacente. Avant de vous montrer le code, il me faut expliquer un peu comment
calculer ça.&lt;/p&gt;
&lt;p&gt;Pour une entité donnée, il existe un maximum de 4 cases accessibles (j’exclue
la case sur laquelle se trouve l’entité, mais un autre choix peut être
pertinent). Pour faciliter la représentation, prenez le tableau de 3x3 cases
suivant (l’entité est représentée par &lt;code&gt;e&lt;/code&gt; et les cases accessibles par les
&lt;code&gt;o&lt;/code&gt;) :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;   0 1 2
0 | |o| |
1 |o|e|o|
2 | |o| |
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Notre entité est donc en position &lt;code&gt;x=1, y=1&lt;/code&gt;. Si l’on fait la différence de son
abscisse avec n’importe quelle abscisse des cases accessibles, la valeur
absolue est égale soit à 0, soit à 1 (&lt;code&gt;1 - 0 = 1&lt;/code&gt; ; &lt;code&gt;1 - 1 = 0&lt;/code&gt; ;
&lt;code&gt;1 - 2 = -1&lt;/code&gt;). Le résultat est le même pour les ordonnées, mais on remarque que
lorsque la différence des abscisses est égale à 1, la différence des ordonnées
est égale à 0 (et inversement). Le cas où les deux différences sont égales à 0
correspond à la case où se trouve l’entité, et les cas où les deux sont égales
à 1 correspondent aux cases en diagonales.&lt;/p&gt;
&lt;p&gt;Pour savoir si Meiko a le droit d’accéder à la case ciblée, il nous faut donc
récupérer les deux positions, faire leur différence en valeur absolue en &lt;code&gt;x&lt;/code&gt; et
en &lt;code&gt;y&lt;/code&gt; et vérifier que la somme fait 1.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;onClickSystem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// On récupère notre entité Meiko. On a besoin de connaître sa position&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// pour vérifier que la case visée est accessible.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;meiko&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getEntity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;meiko&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// On teste que la position est bien accessible à Meiko grâce à une&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// fonction utilitaire. Si elle ne l&amp;#39;est pas, on retourne le store tel&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// quel.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;positionIsAccessibleFor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;meiko&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getEntity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Ici c&amp;#39;est un bête appel à une fonction JS (find) pour trouver notre&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// entité dans le store (qui est un tableau). Le `|| null` permet de&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// retourner null au lieu de undefined, simple coquetterie de ma part.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;find&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;===&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;positionIsAccessibleFor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Si l&amp;#39;entité passée en paramètre n&amp;#39;a pas de position, elle va&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// forcément pas avoir accès à la position donnée puisqu&amp;#39;elle n&amp;#39;est pas&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// présente dans notre tableau !&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// On fait la différence (en valeur absolue) de nos abscisses...&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;diff_x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// ... de nos ordonnées...&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;diff_y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// ... et on vérifie que seulement l&amp;#39;une des 2 différences est égale&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// à 1. On aurait aussi pu écrire ça `diff_x + diff_y === 1`, mais je&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// trouve ça un peu moins clair.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;diff_x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;===&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;diff_y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;===&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;diff_x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;===&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;diff_y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;===&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Avec ça, Meiko arrête de voler à travers le terrain et est obligé de se
déplacer sur une case adjacente. Il reste encore à régler sa manie de monter
sur tous les objets de la cuisine. On va faire ça en deux temps.&lt;/p&gt;
&lt;p&gt;La première chose à faire est d’ajouter un composant à nos entités stockées
dans le store pour indiquer qu’elles ne peuvent pas être franchies. J’ai décidé
de nommer celui-ci &lt;code&gt;obstruct&lt;/code&gt; : si sa valeur est &lt;code&gt;true&lt;/code&gt;, alors l’entité ne peut
pas être franchie.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;gameStore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;meiko&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Meiko&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;obstruct&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;oven&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Four&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;obstruct&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;hatch&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Passe-plat&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;obstruct&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;fridge&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Frigo&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;obstruct&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;workplan&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Plan de travail&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;obstruct&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;shelf&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Étagère&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;obstruct&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Ici j’ai déclaré le composant uniquement sur les gros objets ainsi que sur
Meiko. Si par exemple la sauce tomate traîne au milieu de la cuisine, Meiko
pourra passer au-dessus car je ne lui ai pas ajouté &lt;code&gt;obstruct: true&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;La deuxième étape est maintenant de récupérer les entités présentes sur la case
visée et de vérifier qu’aucune n’est bloquante.&lt;/p&gt;
&lt;p&gt;Avant de rentrer dans le code, une fois n’est pas coutume, on va décortiquer un
peu ce qu’on veut faire. En théorie, trouver les entités présentes sur une case
est facile : il suffit de sélectionner celles dont la position est égale à
celle de la case (c’est-à-dire lorsque les valeurs &lt;code&gt;x&lt;/code&gt; et &lt;code&gt;y&lt;/code&gt; sont identiques).
Mais vous avez sans doute remarqué que nos entités ont une taille qui n’est pas
toujours de 1x1 case ? La position d’une entité correspond en fait à son
angle haut-gauche. On a donc besoin de récupérer l’ensemble des positions
occupées par notre entité, et vérifier qu’au moins une correspond à la case
visée. Pour cela il faut faire un petit calcul. Prenons l’entité suivante qui
occupe quatre cases :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;   0 1
0 |e|e|
1 |e|e|
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Sa position est &lt;code&gt;x=0, y=0&lt;/code&gt;, sa largeur ainsi que sa hauteur sont de 2 chacune.
On veut récupérer les cases suivantes à partir de ces deux informations :
&lt;code&gt;x=0, y=0&lt;/code&gt;, &lt;code&gt;x=1, y=0&lt;/code&gt;, &lt;code&gt;x=0, y=1&lt;/code&gt; et &lt;code&gt;x=1, y=1&lt;/code&gt;. Pour cela, il suffit d’itérer
sur l’intervalle entre 0 et la largeur exclue (ici, « 2 exclu » est égal à 1) :
chaque valeur prise est ajoutée au &lt;code&gt;x&lt;/code&gt; de la position initiale et équivaut à
une position prise par l’entité. On fait évidemment la même chose avec la
hauteur et &lt;code&gt;y&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Ce n’est pas très simple à expliquer avec des mots, donc voici le code de cette
dernière partie :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;onClickSystem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// On récupère les entités présentes à la position donnée pour vérifier&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// qu&amp;#39;aucune n&amp;#39;est bloquante et empêche ainsi le déplacement.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;entitiesAtPosition&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;searchEntitiesAt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// `some` retournera `true` si au moins une entité possède `obstruct` à&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// `true`.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entitiesAtPosition&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;some&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;obstruct&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Et enfin, on met à jour la position de Meiko dans le store. Le seul&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// changement par rapport à la dernière fois est qu&amp;#39;on utilise&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// `meiko.id` au lieu de `&amp;#39;meiko&amp;#39;`.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;setEntityComponents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;meiko&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;searchEntitiesAt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// On filtre ici les entités présentes à la position donnée en&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// argument. La difficulté réside dans le fait qu&amp;#39;une entité à une&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// taille et peut donc être présente sur plusieurs positions à la fois.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;// Pas de position, pas de chocolat&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;// si l&amp;#39;entité n&amp;#39;a pas de taille, on considère quand même&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;// qu&amp;#39;elle a une présence de 1x1. On a juste à tester que les&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;// positions sont égales. En pratique dans ce jeu, ce cas de&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;// figure ne se présente pas.&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;===&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;===&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// getCoveredPositionsBy retourne l&amp;#39;ensemble des positions que&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// l&amp;#39;entité occupe, on vérifie juste que l&amp;#39;une de ces positions&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// correspond à la position recherchée.&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getCoveredPositionsBy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;some&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;coveredPosition&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;coveredPosition&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;===&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;coveredPosition&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;===&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getCoveredPositionsBy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Ici on collectionne les ~canards~ les positions prises par l’entité.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;coveredPositions&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// On itère sur l&amp;#39;intervalle entre 0 et la largeur exclue (ouais bon,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// le code JS est pas hyper accueillant)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// Puis sur l&amp;#39;intervalle entre 0 et la hauteur exclue&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;h&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;// On a plus qu’à additionner les valeurs à x et y pour obtenir&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;// une position occupée par l&amp;#39;entité&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;coveredPositions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;h&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;coveredPositions&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Et voilà ! Vous pouvez tester (&lt;a href="une-histoire-de-pizzas/etape4.html"&gt;le résultat final est ici&lt;/a&gt;),
Meiko ne peut plus monter sur le frigo, ni sur le plan de travail. Si vous
décidez de tripatouiller un peu le code, vous pourrez vérifier que Meiko peut
cependant allègrement marcher sur la Mozzarella si on la laisse trainer au
milieu de la cuisine (ce n’est pas le cas dans le jeu initial, mais ça me
permettait de mieux illustrer l’utilité des composants).&lt;/p&gt;
&lt;p&gt;Bien qu’il n’y ait pas eu « beaucoup » de code dans cet article, celui-ci était
sans doute assez dense pour la compréhension. Le prochain devrait traiter d’un
aspect un peu plus sympa : l’ajout des images. On pourra ainsi se débarrasser
de nos blocs moches dessinés à l’arrache.&lt;/p&gt;</content></entry><entry><title>Une histoire de pizzas : les déplacements</title><id>urn:uuid:e2582c72-c90c-5dc7-b488-b3525f84d65e</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/une-histoire-de-pizzas-3.html" rel="alternate" type="text/html" /><published>2019-11-01T20:30:00+01:00</published><updated>2019-11-01T20:30:00+01:00</updated><content type="html">&lt;p&gt;Je suis en forme alors voici le troisième article qui relate le développement
du jeu que j’ai conçu pour &lt;a href="https://ergogames.fr"&gt;les Ergogames&lt;/a&gt;. On
a déjà vu &lt;a href="une-histoire-de-pizzas-1.html"&gt;comment afficher la grille&lt;/a&gt;
et &lt;a href="une-histoire-de-pizzas-2.html"&gt;comment gérer les objets&lt;/a&gt;, nous
allons aujourd’hui voir comment déplacer notre personnage, Meiko.&lt;/p&gt;
&lt;p&gt;Je vous invite très fortement à &lt;a href="serie/ergogames.html"&gt;lire les autres articles&lt;/a&gt;
si ce n’est pas déjà fait, vous risquez autrement de ne rien piger à celui-ci.&lt;/p&gt;
&lt;p&gt;Le but ici est de pouvoir viser une case avec la souris et de déplacer Meiko en
cliquant. Là encore, on a tout un tas de solutions possibles. Ma première
approche a été de vouloir rendre les entités « cliquables », mais comme on veut
potentiellement cliquer sur des cellules sans entité, j’étais bloqué.&lt;/p&gt;
&lt;p&gt;Ma seconde approche a été de faire en sorte de pouvoir cliquer sur les
&lt;code&gt;.board-cell&lt;/code&gt; qui représentent les cellules de notre tableau (ce sont celles du
premier article). Le problème ici est que les entités survolent les cellules et
risquent de récupérer l’action du « clic » sans le propager aux cases en
dessous, pas cool. Alors on pourrait vouloir rendre tout ce petit monde
« cliquable », mais ça deviendrait galère à gérer parce que les clics ne
portent plus sur les mêmes types d’objets et il faudrait les distinguer.&lt;/p&gt;
&lt;p&gt;Bref, j’ai choisi une solution qui me semble plutôt élégante : j’ai posé un
lien unique (balise &lt;code&gt;&amp;lt;a /&amp;gt;&lt;/code&gt;) par-dessus la zone de jeu, puis j’ai déterminé en
JavaScript la case sur laquelle porte le clic.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;board&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="cm"&gt;&amp;lt;!-- ... --&amp;gt;&lt;/span&gt;

    &lt;span class="cm"&gt;&amp;lt;!--&lt;/span&gt;
&lt;span class="cm"&gt;        On ajoute un lien qui recouvre l’ensemble de la zone de jeu et qui&lt;/span&gt;
&lt;span class="cm"&gt;        va récupérer les clics du ou de la joueuse pour ensuite modifier&lt;/span&gt;
&lt;span class="cm"&gt;        l’état du jeu.&lt;/span&gt;
&lt;span class="cm"&gt;    --&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;#&amp;quot;&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="na"&gt;click&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;onBoardClick&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;board-click-zone&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Vue&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;methods&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;onBoardClick&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="c1"&gt;// C&amp;#39;est ici qu&amp;#39;on connecte le tout : onBoardClick est appelé&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="c1"&gt;// quand on clique sur le lien .board-click-zone. On passe&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="c1"&gt;// l&amp;#39;évènement généré à un &amp;quot;système&amp;quot; qui va modifier le store&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="c1"&gt;// (ou non) en conséquence. Le store retourné est réassigné à&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="c1"&gt;// notre objet VueJS, ce qui va entrainer un rafraichissement&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="c1"&gt;// du HTML si besoin. Magique.&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;onClickSystem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Notre premier &amp;quot;vrai&amp;quot; système. C&amp;#39;est une fonction qui prend un store&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// en entrée et en retourne un en sortie (modifié... ou non).&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// L&amp;#39;évènement qui est également passé en argument permet de déterminer&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// quelle zone du jeu a été &amp;quot;activée&amp;quot; par le ou la joueuse.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;onClickSystem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// On fait en sorte que le clic ne soit pas actionné (sinon l&amp;#39;écran va&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// remonter en haut de l&amp;#39;écran et ce sera pas agréable)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// e.layerX et e.layerY donnent la position en pixels de là où l’on a&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// cliqué. Il suffit de diviser cette valeur par la taille d’une&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// cellule et d&amp;#39;arrondir le résultat pour savoir sur quelle cellule on&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// a cliqué... enfin presque, on retranche encore &amp;quot;1&amp;quot; parce que notre&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// tableau commence à l&amp;#39;indice &amp;quot;0&amp;quot;.&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// Exemple : si la cellule à l’indice 0 fait 10px et que l’on clique&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// sur le pixel &amp;quot;10&amp;quot;, le calcul 10/10 est égal à 1 ; il faut donc&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// retrancher encore 1 pour retrouver notre indice &amp;quot;0&amp;quot;.&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// Et si vous avez rien compris c&amp;#39;est pas dramatique, en plus j&amp;#39;ai pas&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// fait comme ça dans le jeu de base :)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ceil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;layerX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;CSS_CELL_SIZE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ceil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;layerY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;CSS_CELL_SIZE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// On change la position de Meiko pour correspondre à l&amp;#39;endroit visé&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meiko&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// Et on retourne le store ainsi modifié&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;style&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;text/css&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c"&gt;/* ... */&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;board&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;relative&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c"&gt;/*&lt;/span&gt;
&lt;span class="c"&gt;           On limite la largeur du tableau pour ne pas pouvoir cliquer en&lt;/span&gt;
&lt;span class="c"&gt;           dehors de la zone de jeu. Ça aurait pu être fait plus tôt mais on&lt;/span&gt;
&lt;span class="c"&gt;           s’en fichait un peu puisque ça ne posait pas encore de problème.&lt;/span&gt;
&lt;span class="c"&gt;        */&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;calc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;--cell-size&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c"&gt;/*&lt;/span&gt;
&lt;span class="c"&gt;       Rien de compliqué : .board-click-zone est positionné relativement à&lt;/span&gt;
&lt;span class="c"&gt;       .board et le recouvre totalement, c&amp;#39;est donc bien lui qui va récupérer&lt;/span&gt;
&lt;span class="c"&gt;       tous les clics. Oh, et on n&amp;#39;oublie pas le z-index pour nous assurer que&lt;/span&gt;
&lt;span class="c"&gt;       ça passera par-dessus les entités.&lt;/span&gt;
&lt;span class="c"&gt;    */&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;board-click-zone&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;absolute&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;z-index&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c"&gt;/* ... */&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c"&gt;/* On s&amp;#39;assure que Meiko est toujours visible au-dessus des autres entités. */&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;board-cell-entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;meiko&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;z-index&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;#fff&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="kt"&gt;px&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;solid&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;green&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;style&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Avec ça, on pourrait être content puisque Meiko peut désormais se déplacer, et
cela avec peu de nouveau code. C’est sans compter un petit détail que les
personnes connaissant VueJS ou autres bibliothèques de ce type auront peut-être
remarquées : le store est un &lt;code&gt;Object&lt;/code&gt; que l’on passe par référence à
&lt;code&gt;onClickSystem&lt;/code&gt; (enfin presque, je rentre pas dans les détails). La conséquence
est que lorsqu’on modifie sa valeur, le store initial (stocké dans &lt;code&gt;data&lt;/code&gt;) est
également modifié et l’assignation dans &lt;code&gt;onBoardClick&lt;/code&gt; n’a absolument aucun
impact puisqu’on se contente de lui réassigner le même &lt;code&gt;Object&lt;/code&gt;. Une manière de
mieux comprendre est de modifier cette méthode :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nx"&gt;onBoardClick&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;newStore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;onClickSystem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;oldPosition&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meiko&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;newPosition&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;newStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meiko&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Ici j’ai logué la position de Meiko depuis le store initial ainsi que celle du
nouveau store. J’ai également enlevé l’assignation à &lt;code&gt;this.store&lt;/code&gt;. Si vous
regardez le résultat dans une console, vous remarquerez toutefois que les deux
valeurs sont identiques et que Meiko se déplace quand même : l’assignation
n’avait donc bien aucun intérêt ! Ici il faut comprendre que VueJS ne devrait
pas être capable de détecter un changement dans le store et donc d’actualiser
la vue ; ce qu’il fait pourtant. La réponse à cette bizarrerie est donnée
&lt;a href="https://vuejs.org/v2/guide/reactivity.html"&gt;dans la documentation de VueJS&lt;/a&gt;
qui nous explique que la valeur de l’objet &lt;code&gt;data&lt;/code&gt; est gérée d’une manière un
peu spéciale, permettant de surveiller les changements et donc de « réagir » à
ceux-ci. C’est pratique, mais c’est accompagné d’avertissements importants
concernant l’ajout ou la suppression de données dans cet objet qui ne sont pas,
eux, détectés à moins d’utiliser des méthodes particulières. On peut illustrer
cela en changeant légèrement le code de &lt;code&gt;onClickSystem&lt;/code&gt; :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;onClickSystem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Ici on ne change plus la position de Meiko mais on tente de la supprimer&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="ow"&gt;delete&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meiko&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Si vous tentez de voir ce que cela donne, vous verrez que Meiko ne bougera pas.
Le résultat attendu est toutefois qu’il disparaisse car la méthode
&lt;code&gt;entityPosition&lt;/code&gt; est censée retourner un objet vide pour les entités ne
possèdant pas de &lt;code&gt;position&lt;/code&gt; (voir &lt;a href="une-histoire-de-pizzas-2.html"&gt;le deuxième article&lt;/a&gt;
pour comprendre). Ici, VueJS n’a tout simplement pas détecté qu’il y avait eu
un changement dans le store. La bonne manière de faire serait en fait de
remplacer la ligne du &lt;code&gt;delete&lt;/code&gt; par :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nx"&gt;Vue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="ow"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meiko&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;position&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Ça marche, mais ce n’est finalement pas vraiment ce que je souhaite. En effet,
ici les modifications dans le store vont être directement (ou presque) prises
en compte par VueJS qui va impacter cela dans la vue. J’aimerais pour ma part
pouvoir faire celles-ci par « lots » et assigner le nouveau store dans
&lt;code&gt;onBoardClick&lt;/code&gt;, comme je l’ai fait dans mon code. Mon idée est également de ne
pas avoir d’effet de bord à l’intérieur de mon système. Celui-ci doit prendre
un store en entrée, puis en retourner un en sortie sans toucher au premier.
Cela facilite à mon sens la compréhension du code et l’écriture de tests.&lt;/p&gt;
&lt;p&gt;Pour réaliser cela il faut dupliquer le store, mais c’est un peu pénible avec
un &lt;code&gt;Object&lt;/code&gt; JavaScript (&lt;em&gt;c’était en tout cas mon avis à l’époque, mais je
réalise maintenant que j’ai totalement surestimé la complexité, je reviens
là-dessus en fin d’article&lt;/em&gt;). J’ai à ce moment-là pris la décision de revoir le
format de données de mon store en le transformant en un &lt;code&gt;Array&lt;/code&gt;, que j’aurai
plus de facilité à manipuler. Cela demande toutefois quelques adaptations et il
vaut mieux le faire dès maintenant alors que l’on a peu de code :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;board&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="cm"&gt;&amp;lt;!-- ... --&amp;gt;&lt;/span&gt;

    &lt;span class="cm"&gt;&amp;lt;!--&lt;/span&gt;
&lt;span class="cm"&gt;        Dans le template HTML, on change l&amp;#39;appel à `id` qui a été déplacé&lt;/span&gt;
&lt;span class="cm"&gt;        au sein des entités&lt;/span&gt;
&lt;span class="cm"&gt;    --&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;
      &lt;span class="na"&gt;v-for&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;entity in store&amp;quot;&lt;/span&gt;
      &lt;span class="na"&gt;:key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;entity.id&amp;quot;&lt;/span&gt;
      &lt;span class="na"&gt;:class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;[&amp;#39;board-cell-entity&amp;#39;, entity.id]&amp;quot;&lt;/span&gt;
      &lt;span class="na"&gt;:style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;entityPosition(entity)&amp;quot;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;v-if&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;entity.label&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;entity-label&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            {{ entity.label }}
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="cm"&gt;&amp;lt;!-- ... --&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// On revoit la structure de données du store en le transformant en un&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Array pour faciliter la manipulation des données.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Les anciennes clés qui servaient à identifier les entités sont déplacées&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// au sein des entités.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;gameStore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;meiko&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Meiko&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;mozza&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Mozzarella&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;tomato&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Sauce tomate&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;dough&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Pâte à pizza&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// etc.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Ce changement est relativement indolore et a finalement assez peu d’impact (si
ce n’est sur la rapidité d’exécution de certaines instructions). Par contre
Meiko ne peut malheureusement plus bouger ! On va devoir faire une dernière
adaptation au code :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;onClickSystem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ceil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;layerX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;CSS_CELL_SIZE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ceil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;layerY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;CSS_CELL_SIZE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// On change la position de Meiko pour correspondre à l&amp;#39;endroit visé à&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// l&amp;#39;aide de la fonction écrite juste en dessous.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;setEntityComponents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;meiko&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Et on retourne le store modifié&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;updatedStore&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Cette fonction permet de modifier les composants d&amp;#39;une entité présente&lt;/span&gt;
&lt;span class="c1"&gt;// au sein d&amp;#39;un store, sans modifier ce dernier directement : un nouveau&lt;/span&gt;
&lt;span class="c1"&gt;// store est en fait retourné.&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;setEntityComponents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;components&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// Je ne rentre par contre pas dans le détail de la syntaxe&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// JavaScript...&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;components&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Et voilà, avec ça Meiko a désormais la possibilité de se déplacer en toute
liberté dans sa cuisine. Et pour le coup il en a un peu trop puisqu’il est
capable de passer d’un coin à un autre en un seul clic. Il peut également
passer au-dessus des gros objets tels que le frigo, ce qui ne devrait pas être
autorisé. J’avais imaginé traiter de ce sujet dans cet article, mais je me
rends compte qu’il est déjà bien assez complet comme ça alors j’expliquerai
comment contraindre les mouvements de notre personnage dans un prochain
article !&lt;/p&gt;
&lt;p&gt;Le code final de cet article &lt;a href="une-histoire-de-pizzas/etape3.html"&gt;est accessible ici&lt;/a&gt;
(la console est toujours ton amie).&lt;/p&gt;
&lt;p&gt;Pour terminer, je voulais revenir sur mon choix de changer de structure de
données pour représenter mon store. Comme je l’ai précisé entre parenthèses, je
réalise aujourd’hui que mon choix était insuffisamment justifié et j’aurais pu
continuer avec un &lt;code&gt;Object&lt;/code&gt; plutôt qu’un &lt;code&gt;Array&lt;/code&gt;. L’impact immédiat est la
complexité du code : pour accéder à mon entité &lt;code&gt;meiko&lt;/code&gt;, je dois désormais
parcourir les éléments de mon tableau un par un (&lt;a href="https://fr.wikipedia.org/wiki/Comparaison_asymptotique"&gt;complexité en
&lt;code&gt;O(n)&lt;/code&gt;&lt;/a&gt;), alors que je
pouvais le récupérer directement avec un &lt;code&gt;Object&lt;/code&gt; indexé par les identifiants
des entités (complexité en &lt;code&gt;O(1)&lt;/code&gt;). Ce changement est toutefois assez peu
couteux dans ce jeu car nous aurons peu d’entités à manipuler (bien que nous en
rajouterons plus tard).&lt;/p&gt;
&lt;p&gt;J’ai décidé de conserver ce changement dans mon article pour trois raisons. La
première est très basique : je reste proche de mon code initial. La seconde est
d’illustrer que l’on ne fait pas toujours les bons choix d’implémentation du
premier coup (surtout quand on tâtonne) et qu’il est pertinent de prendre du
recul sur ce qu’on est en train de faire. C’est &lt;abbr&gt;OK&lt;/abbr&gt; de revoir une
structure de données, mais attention aux impacts que cela a sur le code ! Une
suite de tests aurait pu être pertinente ici pour valider que nous n’avons pas
de régressions dans les fonctionnalités.&lt;/p&gt;
&lt;p&gt;Ma dernière raison est plus discutable : l’utilisation d’un &lt;code&gt;Array&lt;/code&gt; permet de
complexifier l’accès et la modification des entités, encourageant par la même
occasion l’utilisation des fonctions utilitaires (ici, &lt;code&gt;setEntityComponents&lt;/code&gt;).
Je trouve cela utile car, comme on l’a vu, il faut absolument éviter d’ajouter
ou supprimer un composant « à la main » dans les entités (au risque que VueJS
ne détecte pas le changement). Un ou une nouvelle développeur·euse n’aura pas
forcément conscience de cette particularité et perdra du temps à tenter de
comprendre pourquoi son code ne marche pas. En lui empêchant certaines
facilités, on l’encourage à découvrir comment ont fait les autres et on la
pousse ainsi à utiliser les fonctions qui lui assure de le faire
« correctement ». C’est une sorte d’ergonomie pensée à travers la complexité,
je ne sais pas si ça a été théorisé mais c’est plutôt à-propos ! 😄&lt;/p&gt;</content></entry><entry><title>Une histoire de pizzas : les objets</title><id>urn:uuid:bad7c8a2-5a40-523a-9a6e-e078309c6d29</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/une-histoire-de-pizzas-2.html" rel="alternate" type="text/html" /><published>2019-10-28T17:30:00+01:00</published><updated>2019-10-28T17:30:00+01:00</updated><content type="html">&lt;p&gt;J’ai commencé la semaine dernière une série d’articles pour expliquer comment
j’ai développé un jeu pour &lt;a href="https://ergogames.com"&gt;les Ergogames&lt;/a&gt;. Il me semble
qu’il n’y a rien d’exceptionnel dans ce que j’explique, je vise plutôt un
public amateur qui chercherait à comprendre comment fonctionne un jeu. Mon but
est aussi de montrer ma démarche alors que je n’y connaissais rien au
développement de jeux vidéos (enfin « presque rien », j’y reviens plus loin).&lt;/p&gt;
&lt;p&gt;Dans &lt;a href="une-histoire-de-pizzas-1.html"&gt;l’article précédent&lt;/a&gt; nous avons commencé
par afficher une grille de 6 par 6 cases. Nous allons maintenant
afficher les éléments du jeu (le frigo, le four, Meiko, etc.) Ces
éléments vont interagir entre eux, il faut donc les représenter dans
notre code JavaScript pour gérer ces aspects « dynamiques » et l’« état » du
jeu. Cette représentation est importante et ne doit pas être prise à la légère
puisqu’elle va impliquer notre capacité à ajouter de nouvelles fonctionnalités
au jeu.&lt;/p&gt;
&lt;p&gt;C’est le moment où je révèle que j’ai légèrement triché dans mon précédent
article quand je disais que je n’y connaissais rien : je m’étais déjà un peu
amusé par le passé avec quelques concepts, et notamment l’architecture
« &lt;a href="https://en.wikipedia.org/wiki/Entity%E2%80%93component%E2%80%93system"&gt;entité-composant-système&lt;/a&gt; ».
J’avais découvert ce paradigme dans &lt;a href="https://linuxfr.org/news/je-cree-mon-jeu-video-e01-les-systemes-a-entites"&gt;une série d’articles sur LinuxFR&lt;/a&gt;
et j’avais même commencé à développé une bibliothèque Python, &lt;a href="https://github.com/marienfressinaud/pytity"&gt;Pytity&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Le principe est assez simple :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;les entités représentent les objets du jeu (ex. un frigo) mais ne possèdent
  pas de données ; on représente une entité par &lt;strong&gt;un identifiant&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;à ces entités, on associe des composants qui représentent l’état de l’entité
  (ex. une couleur, une position) ; il s’agit d’&lt;strong&gt;un ensemble de données&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;les systèmes contiennent &lt;strong&gt;le code&lt;/strong&gt; pour interagir avec notre tas de
  données comme, par exemple, pour afficher les entités, écouter les actions du
  joueur ou modifier les composants&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Alors comment on s’y prend pour représenter tout ça ? Ici on va faire simple et
même légèrement différent de ce que j’ai fait pour les Ergogames afin d’être
plus lisible. Il n’existe de toute façon pas de manière unique pour représenter
une architecture « entité-composant-système ».&lt;/p&gt;
&lt;p&gt;Commençons par lister les différents objets de notre jeu à l’état initial, nous
en avons 9 :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;// L&amp;#39;ensemble de nos entités avec leurs composants est stocké dans un gros&lt;/span&gt;
&lt;span class="c1"&gt;// objet JavaScript.&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;gameStore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// L&amp;#39;identifiant de l&amp;#39;entité est une clé (meiko) de l&amp;#39;objet JS. On lui&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// associe un ensemble de composants (label, size et position)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;meiko&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Meiko&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Et on fait la même chose avec toutes les entités de notre jeu&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;mozza&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Mozzarella&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;tomato&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Sauce tomate&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;dough&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Pâte à pizza&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;oven&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Four&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;hatch&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Passe-plat&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;fridge&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Frigo&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;workplan&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Plan de travail&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;shelf&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Étagère&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Vue&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;#app&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;BOARD_SIZE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// on ajoute le store à &amp;quot;data&amp;quot; pour pouvoir y accéder dans le html&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;gameStore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Ceci étant fait, nous pouvons créer notre premier « système » : celui qui va
afficher les objets. Dans notre cas, le rendu est géré par le navigateur ce qui
nous simplifie grandement la vie par rapport à un jeu « natif ». Ça n’a
d’ailleurs pas grand-chose à voir à mon avis et je ne sais pas si on peut
vraiment parler de « système ». On va se contenter ici d’écrire un peu de
&lt;abbr&gt;HTML&lt;/abbr&gt; et de &lt;abbr&gt;JS&lt;/abbr&gt; (pour positionner les entités au bon
endroit) :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;board&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="cm"&gt;&amp;lt;!-- Ça, ça ne change pas --&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;v-for&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;y in size&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;:key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;y&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;board-line&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;v-for&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;x in size&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;:key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;x&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;board-cell&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="cm"&gt;&amp;lt;!--&lt;/span&gt;
&lt;span class="cm"&gt;        On itère sur les entités (objets) du store pour les ajouter dans le&lt;/span&gt;
&lt;span class="cm"&gt;        HTML. Le truc important ici est la fonction &amp;quot;entityPosition&amp;quot; qui va&lt;/span&gt;
&lt;span class="cm"&gt;        retourner les dimensions et la position en CSS de l&amp;#39;entité pour que&lt;/span&gt;
&lt;span class="cm"&gt;        le navigateur l&amp;#39;affiche au bon endroit.&lt;/span&gt;
&lt;span class="cm"&gt;    --&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;
      &lt;span class="na"&gt;v-for&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;(entity, id) in store&amp;quot;&lt;/span&gt;
      &lt;span class="na"&gt;:key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;id&amp;quot;&lt;/span&gt;
      &lt;span class="na"&gt;:class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;[&amp;#39;board-cell-entity&amp;#39;, id]&amp;quot;&lt;/span&gt;
      &lt;span class="na"&gt;:style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;entityPosition(entity)&amp;quot;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="cm"&gt;&amp;lt;!-- Si l&amp;#39;entité a un composant &amp;quot;label&amp;quot;, on l’ajoute au HTML. --&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;v-if&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;entity.label&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;entity-label&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            {{ entity.label }}
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Cette valeur correspond à la variable --cell-size en CSS.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;CSS_CELL_SIZE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;128&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Vue&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;methods&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;// entityPosition retourne la position de l&amp;#39;entité en CSS.&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;entityPosition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="c1"&gt;// Si l&amp;#39;entité ne possède pas de taille ou de position,&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="c1"&gt;// cela signifie qu&amp;#39;on ne peut pas l&amp;#39;afficher : on ne&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="c1"&gt;// retourne donc rien.&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{};&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="c1"&gt;// on multiplie la taille de l&amp;#39;entité par la taille d&amp;#39;une&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="c1"&gt;// cellule pour obtenir sa taille en CSS.&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;CSS_CELL_SIZE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;px&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;CSS_CELL_SIZE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;px&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="c1"&gt;// et pareil pour obtenir sa position&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nx"&gt;top&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;CSS_CELL_SIZE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;px&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;CSS_CELL_SIZE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;px&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Une solution plus élégante serait de ne générer le &lt;abbr&gt;HTML&lt;/abbr&gt; que pour
les entités avec une taille et une position : en effet, quel intérêt y a-t-il à
ajouter une entité qui n’a pas d’existence visuelle ? J’ai choisi cette façon
de faire afin de garder le code plus simple et parce que je n’avais pas pensé à
cela initialement (je reste ainsi plus proche de ce que j’ai fait
initialement).&lt;/p&gt;
&lt;p&gt;Vous noterez aussi que je ne tente pas de placer les entités &lt;em&gt;dans&lt;/em&gt; les
cellules du tableau que l’on a généré lors de l’étape précédente. En effet, une
entité peut se trouver dans plusieurs cellules en même temps et ce serait
galère à gérer correctement en termes de &lt;abbr&gt;HTML&lt;/abbr&gt;. Je préfère donc
dissocier les entités des cellules et les superposer. Ça n’a pas beaucoup
d’importance ici puisqu’il s’agit uniquement de rendu visuel.&lt;/p&gt;
&lt;p&gt;À ce niveau on est pas mal, mais ça reste toujours moche et on ne voit pas
grand-chose. On va donc ajouter du &lt;abbr&gt;CSS&lt;/abbr&gt; pour rendre nos entités
correctement.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c"&gt;/* ... */&lt;/span&gt;

&lt;span class="c"&gt;/*&lt;/span&gt;
&lt;span class="c"&gt;   Ça c&amp;#39;est important pour pas se prendre la tête sur les dimensions mais&lt;/span&gt;
&lt;span class="c"&gt;   je ne rentre pas dans le détail du pourquoi du comment.&lt;/span&gt;
&lt;span class="c"&gt;*/&lt;/span&gt;
&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;box-sizing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;border-box&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/*&lt;/span&gt;
&lt;span class="c"&gt;   Les entités ont une position absolue *au sein* du tableau, donc on&lt;/span&gt;
&lt;span class="c"&gt;   précise le nécessaire pour éviter qu&amp;#39;elles ne volent n&amp;#39;importe où à&lt;/span&gt;
&lt;span class="c"&gt;   l&amp;#39;écran, et surtout pas en dehors du cadre de jeu.&lt;/span&gt;
&lt;span class="c"&gt;*/&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;board&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;relative&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;board-cell-entity&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;absolute&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* Puis on colorie nos entités pour les rendre plus visibles à l&amp;#39;écran */&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;board-cell-entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;oven&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;#333&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;board-cell-entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;fridge&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;#666&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;board-cell-entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;workplan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;#783f04&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;board-cell-entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;shelf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;#000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;board-cell-entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;hatch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;#cf2a27&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;board-cell-entity&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;entity-label&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;#fff&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;board-cell-entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;shelf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;entity-label&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;text-align&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;right&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/*&lt;/span&gt;
&lt;span class="c"&gt;   Certaines entités peuvent être superposées à d&amp;#39;autres (la pâte, la mozza&lt;/span&gt;
&lt;span class="c"&gt;   et la sauce tomate). On leur met un z-index pour être sûr qu&amp;#39;elles se&lt;/span&gt;
&lt;span class="c"&gt;   trouveront au-dessus.&lt;/span&gt;
&lt;span class="c"&gt;*/&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;board-cell-entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;dough&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;board-cell-entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;mozza&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;board-cell-entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;tomato&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;z-index&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;green&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/*&lt;/span&gt;
&lt;span class="c"&gt;   Meiko a droit à un style un peu différent mais ça change pas grand-chose&lt;/span&gt;
&lt;span class="c"&gt;   à la logique : on le colorie aussi !&lt;/span&gt;
&lt;span class="c"&gt;*/&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;board-cell-entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;meiko&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="kt"&gt;px&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;solid&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;green&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;board-cell-entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;meiko&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;entity-label&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;initial&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Notez ici que la majorité du code &lt;abbr&gt;CSS&lt;/abbr&gt; n’est pas très important
puisqu’on remplacera nos blocs colorés par des images plus tard.&lt;/p&gt;
&lt;p&gt;On arrive toutefois à la fin de cet article puisqu’on a vu comment représenter
les objets du jeu et comment les afficher. Le résultat final &lt;a href="une-histoire-de-pizzas/etape2.html"&gt;est visible ici&lt;/a&gt;
et, comme la dernière fois, n’hésitez pas à regarder le code source de la page.&lt;/p&gt;
&lt;p&gt;Nous verrons dans le prochain article comment déplacer Meiko de case en case
tout en faisant attention à ce qu’il ne puisse pas traverser les objets tel que
le frigo.&lt;/p&gt;</content></entry><entry><title>Une histoire de pizzas : la grille</title><id>urn:uuid:e9c2eeb7-11b7-583a-bda2-1217a24b2c5c</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/une-histoire-de-pizzas-1.html" rel="alternate" type="text/html" /><published>2019-10-24T13:30:00+02:00</published><updated>2019-10-24T13:30:00+02:00</updated><content type="html">&lt;p&gt;En début d’année, j’ai passé du temps à développer un mini-jeu pour les
&lt;a href="https://www.ergogames.fr"&gt;Ergogames&lt;/a&gt;. Le principe des Ergogames est simple :
faire découvrir des principes d’ergonomie à travers des jeux qui illustrent
différents concepts. Ceux-ci sont conçus par deux anciennes collègues
ergonomes, &lt;a href="https://twitter.com/mgeorges_"&gt;Marion&lt;/a&gt; et &lt;a href="https://twitter.com/Margauxlergo"&gt;Margaux&lt;/a&gt;,
via l’agence de design &lt;a href="https://twitter.com/UxShadow"&gt;uxShadow&lt;/a&gt; de &lt;a href="https://sogilis.com"&gt;Sogilis&lt;/a&gt;
(mon ancienne boite).&lt;/p&gt;
&lt;p&gt;Elles m’ont demandé si je pouvais leur donner un coup de main et j’ai accepté
à condition que le code soit ouvert (&lt;a href="https://gitlab.com/sogilis/ergogames.fr"&gt;ça se passe ici&lt;/a&gt; 😊).&lt;/p&gt;
&lt;p&gt;J’ai donc développé le mini-jeu « &lt;a href="https://www.ergogames.fr/game/pizzas"&gt;À vous les pizzas !&lt;/a&gt; »
en précisant bien que je n’avais jamais conçu de jeux mais que c’est pas grave,
« je vais apprendre ». Du coup j’ai effectivement appris, et c’est ce
cheminement que j’aimerais partager maintenant à travers une série d’articles.
Je préviens tout de suite : je n’ai aucune idée de si je finirai cette série,
mais enfin, je l’aurai au moins commencée. Si vous cherchez le code du jeu en
lui-même, &lt;a href="https://gitlab.com/sogilis/ergogames.fr/tree/master/src/views/games/pizzas"&gt;il se trouve ici&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Le but de la série va être de redévelopper le jeu pas à pas. Je n’irai pas
aussi loin que celui des Ergogames pour me simplifier la vie, mais nous verrons
quand même les principaux mécanismes. Le principe du jeu est de déplacer un
personnage (Meiko) dans une cuisine en cliquant de case en case pour lui
faire fabriquer une pizza. Je vous laisse jouer au jeu sur le site des
&lt;a href="https://ergogames.fr"&gt;Ergogames&lt;/a&gt; pour découvrir le principe d’ergonomie qui
est illustré ici. Le résultat ressemble à cela :&lt;/p&gt;
&lt;p&gt;&lt;img alt="Capture d’écran du jeu montrant Meiko au milieu d’une cuisine" src="images/ergogames/jeu.png" /&gt;&lt;/p&gt;
&lt;p&gt;Le jeu sera développé en HTML, CSS et JavaScript avec la librairie &lt;a href="https://vuejs.org"&gt;VueJS&lt;/a&gt;
afin de rester le plus proche possible de ce qui a été fait initialement.
J’éviterai tout de même toute étape de &lt;em lang="en"&gt;build&lt;/em&gt; qui
consisterait à transformer le code &lt;abbr&gt;JS&lt;/abbr&gt; en un seul fichier
optimisé : c’est ce qui est fait pour les Ergogames mais ça complexifierait la
compréhension sans rien apporter de plus. Je vais également m’éviter quelques
bonnes pratiques en mixant allègrement tout le code (HTML, JS et CSS) au sein
d’un même fichier (ne faites pas ça chez vous).&lt;/p&gt;
&lt;p&gt;Dans ce premier article qui servait essentiellement à introduire la série, on
va se contenter d’afficher un cadre de 6 par 6 cases. Comme je l’ai dit plus
haut, je n’avais encore jamais développé de jeu, donc j’ai avancé de manière
très naïve. Il me semblait évident que la première phase consisterait à
dessiner le tableau de jeu.&lt;/p&gt;
&lt;p&gt;Cela permet en plus d’introduire à la fois un peu de HTML, de CSS et de JS et
donc de poser les bases. Pour représenter le cadre, on va se contenter de 6
balises &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; pour les lignes, découpées elles-mêmes en 6 autres balises
&lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; pour les cellules. On va s’éviter tout de suite de copier-coller plein
de code HTML et on va donc ajouter VueJS immédiatement et répéter ces blocs
avec des boucles &lt;code&gt;v-for&lt;/code&gt;. Ça donne quelque chose que j’espère simple :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;app&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;board&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="cm"&gt;&amp;lt;!--&lt;/span&gt;
&lt;span class="cm"&gt;            la variable size est passée par VueJS et a pour valeur 6. On répète&lt;/span&gt;
&lt;span class="cm"&gt;            donc 6 fois la div &amp;quot;board-line&amp;quot;, au sein desquelles on répète 6&lt;/span&gt;
&lt;span class="cm"&gt;            fois la div &amp;quot;board-cell&amp;quot;.&lt;/span&gt;
&lt;span class="cm"&gt;        --&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;v-for&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;y in size&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;:key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;y&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;board-line&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;v-for&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;x in size&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;:key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;x&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;board-cell&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="cm"&gt;&amp;lt;!--&lt;/span&gt;
&lt;span class="cm"&gt;    J’ajoute la librairie VueJS via un CDN, mais dans la vraie vie préférez&lt;/span&gt;
&lt;span class="cm"&gt;    héberger le code vous-même, c’est meilleur pour la vie privée de vos&lt;/span&gt;
&lt;span class="cm"&gt;    visiteurs et visiteuses.&lt;/span&gt;
&lt;span class="cm"&gt;--&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;https://cdn.jsdelivr.net/npm/vue/dist/vue.js&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;BOARD_SIZE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;6&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Un tout petit peu de JS pour dire à VueJS de &amp;quot;monter&amp;quot; l&amp;#39;application sur&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// la balise possédant l&amp;#39;id #app et passer la variable size. Je ne rentre&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// pas dans le détail ici, ce n’est pas très important.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Vue&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;#app&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;BOARD_SIZE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Avec ça, on a la base de notre code HTML, par contre ça ne ressemble à rien. On
va donc ajouter un zeste de CSS pour rendre le tout visuel :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c"&gt;/*&lt;/span&gt;
&lt;span class="c"&gt;    Ici on définit quelques variables CSS, c&amp;#39;est pas forcé mais ça aidera à&lt;/span&gt;
&lt;span class="c"&gt;    la maintenance du code.&lt;/span&gt;
&lt;span class="c"&gt;*/&lt;/span&gt;
&lt;span class="p"&gt;#&lt;/span&gt;&lt;span class="nn"&gt;app&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;--cell-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="kt"&gt;px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;--color-floor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;#fff&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;--color-floor-border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;#ccc&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/*&lt;/span&gt;
&lt;span class="c"&gt;    Une ligne est un conteneur flex, ça permet de se simplifier la vie pour&lt;/span&gt;
&lt;span class="c"&gt;    aligner les cellules. La conséquence ici est que les .board-cell seront&lt;/span&gt;
&lt;span class="c"&gt;    affichées en lignes et non pas en colonnes.&lt;/span&gt;
&lt;span class="c"&gt;*/&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;board-line&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/*&lt;/span&gt;
&lt;span class="c"&gt;    Puis on définit la taille des cellules ainsi qu’une couleur de fond et&lt;/span&gt;
&lt;span class="c"&gt;    de bordure pour les mettre en évidence.&lt;/span&gt;
&lt;span class="c"&gt;*/&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;board-cell&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;--cell-size&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;--cell-size&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;--color-floor&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="kt"&gt;px&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;solid&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;--color-floor-border&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Avec ça on a un cadre que l’on va pouvoir améliorer par petites touches pour
arriver au jeu final. Le résultat final &lt;a href="une-histoire-de-pizzas/etape1.html"&gt;est visible ici&lt;/a&gt;
(n’hésitez pas à ouvrir la console de votre navigateur pour regarder le code).&lt;/p&gt;
&lt;p&gt;J’ai essayé ici de détailler au mieux ce que je faisais pour faciliter la
compréhension du code afin de rendre ma série d’articles accessible au plus de
monde possible, en particulier aux débutant·es. N’hésitez pas à me contacter si
des choses ne sont pas claires !&lt;/p&gt;
&lt;p&gt;Le prochain article &lt;a href="une-histoire-de-pizzas-2.html"&gt;explique comment afficher les éléments dans le
jeu&lt;/a&gt;.&lt;/p&gt;</content></entry><entry><title>Bretagne, le retour</title><id>urn:uuid:f932a82f-fb09-5557-906b-df0bbef76cab</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/bretagne-le-retour.html" rel="alternate" type="text/html" /><published>2019-10-21T11:50:00+02:00</published><updated>2019-10-21T11:50:00+02:00</updated><content type="html">&lt;p&gt;Je suis rentré de &lt;a href="bretagne.html"&gt;Bretagne&lt;/a&gt; un peu plus tôt que prévu. J’ai
finalement beaucoup moins randonné que ce que je voulais, mais j’ai dû me
rendre à l’évidence de trois choses :&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;la santé physique, ça se soigne ;&lt;/li&gt;
&lt;li&gt;un budget, ça explose vite ;&lt;/li&gt;
&lt;li&gt;marcher seul, c’est long.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;C’était néanmoins une chouette balade entre le Mont-Saint-Michel et
Saint-Brieuc, de superbes paysages (et des moins bien aussi, mais peu 😉),
quelques rencontres qui font plaisir (en particulier un groupe de quatre que
j’ai suivi presque tout du long), et des bonnes galettes. Je remercie également
Hervé de m’avoir montré Brest, ainsi que Thomas et Aline pour l’hébergement et
les croissants !&lt;/p&gt;
&lt;p&gt;Une chose m’a surpris : la Bretagne, c’est pas plat du tout ! Ça monte et ça
descend sans cesse, avec des marches (j’en ai compté 106 à Saint-Cast-le-Guildo
en fin de journée pour atteindre l’hôtel, pas cool) ou sans. J’avais clairement
mal anticipé ça et mes tendons d’Achille ont souffert plusieurs jours de suite
(d’où le fait de m’arrêter pour éviter de me blesser).&lt;/p&gt;
&lt;p&gt;La période à laquelle j’y suis allé n’était pas idéale, les établissements
commencent à fermer et il était parfois compliqué de se loger. Au pire ça
aurait été camping sauvage dans un coin, mais je voulais éviter. Je viserai la
prochaine fois la première quinzaine de septembre (des contraintes m’en ont
empêché cette fois-ci).&lt;/p&gt;
&lt;p&gt;À propos de la météo (comme la question revient souvent), j’ai eu droit à
quelques bonnes averses, mais je n’ai réellement fini trempé que deux fois.
J’étais équipé de vêtements qui sèchent rapidement donc, en général, le simple
fait de marcher suffisait pour redevenir sec (le vent aidant bien). J’ai quand
même eu du très beau temps la majorité du voyage, me permettant d’être en
t-shirt.&lt;/p&gt;
&lt;p&gt;Je me suis amélioré dans la préparation de mon sac par rapport à mes voyages
précédents. Bien qu’étant parti avec un sac d’environ 14 kg, j’aurais pu gagner
en m’évitant le matériel de camping (3 kg au total dont j’ai eu peu besoin) et
en emportant moins de nourriture au départ. Concernant ce deuxième point, il
est possible soit de manger au resto, soit de se ravitailler dans des
supérettes à intervalle régulier (ce n’est pas un problème sur ce chemin de
randonnée). J’ai calculé, je pense pouvoir viser un sac de 9 kg aisément, voire
encore moins si je veux vraiment voyager léger.&lt;/p&gt;
&lt;p&gt;Pour finir, j’aimerais bien retourner en Bretagne pour finir ce que je n’ai pas
fait et visiter d’autres coins. En revanche je ferai en sorte de ne pas voyager
seul et de mieux me préparer physiquement avant de partir. Et si vous étiez là
pour les photos : je n’en ai pas prises, désolé !&lt;/p&gt;</content></entry><entry><title>Gagner ma vie : FreshRSS ou Lessy ?</title><id>urn:uuid:022d1147-4947-57a5-9825-cdfc54392c19</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/freshrss-et-lessy.html" rel="alternate" type="text/html" /><published>2019-09-19T18:30:00+02:00</published><updated>2019-09-19T18:30:00+02:00</updated><content type="html">&lt;p&gt;Lorsque j’ai décidé de monter un service pour essayer de &lt;a href="mon-futur-service-de-veille.html"&gt;gagner ma vie&lt;/a&gt;,
j’étais parti dans l’idée de le faire avec &lt;a href="https://lessy.yuzu.ovh"&gt;Lessy&lt;/a&gt; (un
gestionnaire pour aider à gérer son temps). Les avantages étaient nombreux :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;une demande qui me semble plus importante ;&lt;/li&gt;
&lt;li&gt;des technologies que je connais mieux ;&lt;/li&gt;
&lt;li&gt;une base de code plus récente avec moins de dette technique ;&lt;/li&gt;
&lt;li&gt;un projet dont la gouvernance est super simple vu que je suis le seul à
  travailler (ahem…) dessus ;&lt;/li&gt;
&lt;li&gt;et j’en oublie sans doute.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Toutefois, en y réfléchissant un peu, je me suis dit que le but de Lessy était
d’avoir à l’utiliser le moins possible, voire d’être capable de s’en
passer totalement dans une démarche de réappropriation de son temps. Il me
semblait du coup malhonnête de générer de l’argent avec puisque cela impliquait
nécessairement de tenter de capter l’attention des gens (à minima pour les
faire venir sur le service, idéalement pour m’assurer qu’ils l’utilisent
effectivement).&lt;/p&gt;
&lt;p&gt;À l’inverse il me semble que &lt;a href="https://freshrss.org"&gt;FreshRSS&lt;/a&gt;, étant un outil
de veille, s’intègre plutôt bien dans une activité quotidienne. Je suis moins
gêné par le fait que les personnes utilisant le service payent pour l’utiliser
quotidiennement puisque c’est dans sa nature. Je crois également qu’un outil de
veille s’attaque à un problème plus ambitieux : l’information nous est
aujourd’hui pré-digérée principalement à travers des plateformes centralisées
et propriétaires, donc de manière plus ou moins uniforme, en tout cas opaque.
Il est pour moi plus que temps que l’on redonne leurs lettres de noblesse à des
technologies comme &lt;abbr&gt;RSS&lt;/abbr&gt; et Atom ; cela implique d’inventer de
nouveaux usages autour d’elles, et donc de développer des outils. En gagnant de
l’argent avec FreshRSS, je serai en mesure de l’améliorer en lui accordant du
temps. D’ailleurs, j’entérine ça dans &lt;a href="https://flus.io/i/?a=cgv"&gt;les conditions générales de vente de
Flus&lt;/a&gt; (le service que je mets en place pour fournir
un FreshRSS hébergé) :&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Le service est amené à évoluer régulièrement à travers des mises à jour du
logiciel, développées à la fois par une communauté de développeurs et
développeuses, et &lt;strong&gt;par le vendeur du service qui s’engage de ce fait à
contribuer au développement d’un bien commun&lt;/strong&gt;. Cet engagement sera tenu à
partir de et aussi longtemps que le vendeur pourra vivre du service.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Je n’ai plus qu’à espérer que les flux &lt;abbr&gt;RSS&lt;/abbr&gt; ne soient pas tout à
fait morts ;)&lt;/p&gt;</content></entry><entry><title>Bretagne</title><id>urn:uuid:18ef0731-5b75-5922-8530-a974423c026e</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/bretagne.html" rel="alternate" type="text/html" /><published>2019-09-16T12:00:00+02:00</published><updated>2019-09-16T12:00:00+02:00</updated><content type="html">&lt;p&gt;Je pars lundi prochain (le 23 septembre) pour un petit mois pédestre en
Bretagne. Initialement prévu pour l’automne 2017, j’ai réussi à repousser ce
voyage pendant deux ans pour diverses raisons, mais cette fois c’est bon !&lt;/p&gt;
&lt;p&gt;Mon trajet, qui évoluera sans doute en cours de route, consistera en :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;un passage (express) à Rennes ;&lt;/li&gt;
&lt;li&gt;une quinzaine de jours à marcher entre le Mont-Saint-Michel et Saint-Brieuc ;&lt;/li&gt;
&lt;li&gt;un passage à Brest ;&lt;/li&gt;
&lt;li&gt;une petite dizaine de jours à marcher sur la presqu’île de Crozon ;&lt;/li&gt;
&lt;li&gt;peut-être un saut à Vannes, puis à Nantes, avant de rentrer.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Les plus attentifs noteront que je vais plus ou moins suivre &lt;a href="https://www.mongr.fr/trouver-prochaine-randonnee/itineraire/gr-34-le-plus-maritime-des-sentiers-de-grande-randonnee"&gt;le sentier des
douaniers&lt;/a&gt;.
Je partirai sans PC et serai donc difficilement joignable. Si vous êtes sur la
route et voulez faire un coucou ou marcher un bout de chemin, n’hésitez pas à
&lt;a href="contact.html"&gt;me contacter&lt;/a&gt; avant que je ne parte.&lt;/p&gt;
&lt;p&gt;Je profiterai de ce voyage pour finaliser mon discours et mes idées autour de
&lt;a href="https://flus.fr"&gt;Flus&lt;/a&gt;, ce serait d’autant plus intéressant de pouvoir
rencontrer des gens en cours de route !&lt;/p&gt;</content></entry><entry><title>Phase de simplification</title><id>urn:uuid:3cbf554a-4d80-55ea-839f-f8e80df1a268</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/phase-de-simplification.html" rel="alternate" type="text/html" /><published>2019-09-11T10:15:00+02:00</published><updated>2019-09-11T10:15:00+02:00</updated><content type="html">&lt;p&gt;J’ai la mauvaise habitude de tenter de me compliquer la vie (c’est humain
j’imagine). La conception de ce site en est un bon exemple. Après quelques mois
de recul sur ce que j’ai réalisé, je me suis rendu compte que &lt;a href="index.html"&gt;la page d’accueil&lt;/a&gt;
notamment ne collait pas du tout avec ce que je voulais mettre en valeur. J’ai
pris 30 minutes ce matin pour changer tout ça, en me prenant moins la tête. Je
vais également me simplifier la vie et rédiger des articles (beaucoup) moins
longs. On verra bien si ça me motive à en écrire plus.&lt;/p&gt;</content></entry><entry><title>Mon (futur) service de veille</title><id>urn:uuid:5b72813e-af59-586c-969d-ee12e56932ec</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/mon-futur-service-de-veille.html" rel="alternate" type="text/html" /><published>2019-07-12T11:30:00+02:00</published><updated>2019-07-12T11:30:00+02:00</updated><content type="html">&lt;p&gt;J’ai &lt;a href="./questionnaire-agregateurs-dactualite.html"&gt;partagé&lt;/a&gt; il y a quelque temps
un questionnaire destiné à étudier le marché des agrégateurs d’actualité dans
le but d’une potentielle création d’entreprise. Mon objectif était de mieux
connaître le marché actuel, d’évaluer un début de tarification et de mieux
connaître les attentes de potentiel·les client·es. J’en profite d’ailleurs pour
remercier les 281 personnes qui ont pris le temps de répondre, ça m’a bien aidé
à y voir plus clair dans ce que j’allais faire !&lt;/p&gt;
&lt;p&gt;Je reviens dans cet article sur les raisons qui m’encouragent à mettre en place
un tel service et j’appuie certains éléments par les questions posées par le
questionnaire.&lt;/p&gt;
&lt;h2&gt;La raison de faire&lt;/h2&gt;
&lt;p&gt;Si vous suivez ce blog, vous savez sans doute que je suis au chômage depuis
décembre dernier. Loin d’être une situation subie, j’en ai profité pour poser à
plat mes envies à travers un &lt;a href="./serie/conception-du-site.html"&gt;travail d’introspection&lt;/a&gt;.
Je comptais alors, sans le dire explicitement, suivre une voie « par défaut »
qui était celle de me mettre en auto-entrepreneur pour faire du service auprès
d’entreprises. J’ai mis un moment avant de prendre réellement conscience que
&lt;strong&gt;ce métier ne m’intéressait absolument pas&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Mon chômage s’écoule doucement mais sûrement depuis maintenant 7 mois,
finançant d’une certaine manière mes activités bénévoles (en témoigne
l’évolution de ma page « &lt;a href="./now.html"&gt;En ce moment&lt;/a&gt; » ces derniers mois). Il
est toutefois temps que je commence à travailler concrètement sur mon futur
professionnel afin de me dégager un salaire. L’idée n’étant pas de générer un
salaire mirobolant, mais juste assez pour pouvoir vivre tranquillement (par
transparence, je vise entre 1 500 et 2 000 € par mois).&lt;/p&gt;
&lt;p&gt;Je n’envisage pas mon avenir professionnel en tant que salarié d’une entreprise
« traditionnelle » où l’on décide à ma place ce sur quoi je dois travailler.
J’ai toujours pris soin de ma liberté de choix et je compte bien continuer. En
avant donc pour créer ma propre structure. Aussi, l’envie de créer un service
en ligne de manière professionnelle me trotte dans la tête depuis plusieurs
années et cette remise en question m’a permis de la remettre au goût du jour.&lt;/p&gt;
&lt;p&gt;Pour terminer sur ma raison de « faire », je souhaite revenir sur la limitation
volontaire de mon salaire. J’ai à cœur de pouvoir travailler et être d’une
quelconque aide au monde associatif, en particulier celles œuvrant dans les
luttes pour le climat ou les luttes sociales. Le monde économique dans lequel
nous vivons ne valorisant pas (encore ?) le travail qui peut être fait dans ces
milieux-là, il s’agit bien souvent de bénévolat. Mon but en limitant mon
salaire est donc de générer du temps libre que je pourrai mettre à dispositon
d’associations : « gagner moins pour travailler plus utile » en quelque sorte.&lt;/p&gt;
&lt;h2&gt;Les raisons d’être&lt;/h2&gt;
&lt;p&gt;Se pose maintenant la question de la raison d’être du service en ligne.
Quelle raison me fait dire que le service aura une quelconque utilité ? À quel
besoin je réponds ?&lt;/p&gt;
&lt;p&gt;L’une des choses que j’observe depuis longtemps, en partie à travers mon action
au sein de &lt;a href="https://framasoft.org"&gt;Framasoft&lt;/a&gt;, c’est le cloisonnement de nos
données et notre assentiment à déléguer le choix de nos sources d’information à
des plateformes privées telles que Twitter ou Facebook. On l’a vu notamment
lors du &lt;a href="https://www.nextinpact.com/news/106349-retour-sur-scandale-cambridge-analytica-et-molle-reponse-facebook.htm"&gt;scandale de Cambridge Analytica&lt;/a&gt; :
cela peut avoir des conséquences désastreuses sans réelle réflexion politique
ni mesure de contre-pouvoir.&lt;/p&gt;
&lt;p&gt;Pourtant, il est important de pouvoir se tenir au courant de l’actualité. C’est
le cas pour toutes les personnes qui veulent s’informer de ce qu’il se passe
dans le monde, mais aussi à des échelles plus locales. Il peut s’agir de
politique, d’évènements festifs, de sport, etc. D’un point de vue
professionnel, la veille spécialisée permet de se tenir à jour des évolutions
de son domaine (on peut penser à l’informatique mais aussi au domaine
législatif par exemple).&lt;/p&gt;
&lt;p&gt;À travers notre veille, nous nous faisons influencer par les points de vue des
personnes qui publient l’information, voire par la pub qu’elles y insèrent.
Aucune information n’est totalement objective, mais nous décidons de suivre
tel ou tel site de manière encore à peu près consciente. Cela devient plus
pernicieux lorsque &lt;strong&gt;cette veille est orientée sans nous le dire par les
plateformes sur lesquelles nous l’effectuons&lt;/strong&gt;. Il me paraît par conséquent
important d’avoir confiance dans ces plateformes (et donc les outils techniques
sous-jacents).&lt;/p&gt;
&lt;p&gt;Dans ce que j’explique ici, j’identifie deux raisons d’être distinctes :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;celle de l’outil technique qui serait de &lt;strong&gt;proposer un outil de veille
  connecté, simple et respectueux de ses utilisateur·ices&lt;/strong&gt; ;&lt;/li&gt;
&lt;li&gt;et celle du service en ligne qui serait de &lt;strong&gt;permettre la promotion et le
  développement de cet outil en proposant un service transparent et de
  confiance&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Cela implique tout un tas de choses que je détaille dans la partie suivante en
me basant sur les chiffres qui ressortent de mon questionnaire.&lt;/p&gt;
&lt;h2&gt;La philosophie du service&lt;/h2&gt;
&lt;h3&gt;Connexion&lt;/h3&gt;
&lt;p&gt;J’ai eu beaucoup de réponses à mon questionnaire de personnes m’expliquant
qu’elles préféraient utiliser un logiciel sur leur propre PC, voire même une
personne m’a affirmé que les services en ligne étaient inutiles. Si je
comprends très bien que l’on puisse préférer un logiciel sur sa machine, il me
semble néanmoins que les outils de veille en ligne ont aussi leur utilité, ne
serait-ce que pour faire face aux usages liés à la mobilité (c’est-à-dire lire
sur différents terminaux en fonction de la journée tout en gardant synchronisé
ce que j’ai lu ou marqué en favori). La connexion est aussi intéressante dans
les interactions qu’elle peut apporter. Si notre suivi de l’actualité a migré
sur des plateformes sociales, ce n’est pas parce qu’elles sont meilleures pour
cet usage spécifique mais parce qu’elles permettent &lt;strong&gt;de réagir, compléter et
confronter l’information à d’autres avis&lt;/strong&gt;. Aujourd’hui les agrégateurs
d’actualité ne le permettent effectivement pas, mais il s’agit pour moi d’une
évolution qui aurait tout son sens.&lt;/p&gt;
&lt;h3&gt;Simplicité&lt;/h3&gt;
&lt;p&gt;Ensuite, la simplicité d’usage est importante si je veux toucher un public
autre que celui qui est prêt à creuser les fonctionnalités ou qui comprend
déjà le fonctionnement d’un agrégateur de flux &lt;abbr&gt;RSS&lt;/abbr&gt;. C’est une
composante essentielle si je veux poser mon service comme une véritable
alternative face à d’autres plateformes. Deux questions dans mon sondage
devaient d’ailleurs me permettre de valider cet aspect-là. À l’argument « Les
fonctionnalités du service sont très ciblées et restent volontairement
simples », 58% des personnes ont répondu qu’il les inciterait à utiliser le
service, et 32% non. L’argument corollaire « Le service dispose de nombreuses
fonctionnalités (au risque de devenir complexe) » a reçu 38% d’avis positifs et
54% négatifs. J’admets toutefois que ce deuxième argument était orienté,
j’aurais sans doute dû éviter. On voit néanmoins que les rapports s’inversent
de façon très claire. Et j’ajoute que le questionnaire a touché un public
plutôt geek, plus enclein à fouiller un logiciel, alors qu’il ne s’agira pas
forcément de ma cible finale (j’y reviens plus loin).&lt;/p&gt;
&lt;h3&gt;Transparence&lt;/h3&gt;
&lt;p&gt;La transparence du service m’apparaît comme une composante essentielle dans le
respect des utilisateur·ices car cela peut amener à comprendre certains choix
qui sont faits. Par exemple, une majorité de personnes sont prêtes à payer 1 ou
2 € par mois pour utiliser le service. Néanmoins, plus le prix sera bas, et
plus je devrais avoir de client·es pour générer mon chiffre d’affaire. Qui dit
plus de monde dit aussi plus de support à faire (donc moins de temps par
personne), un serveur plus puissant avec plus de capacités de stockage, etc.
Être transparent c’est aussi expliquer que le prix se calcule en fonction de
nombreux paramètres et que s’il peut paraître cher, il y a une raison derrière.
Cet argument sur la transparence des prix a d’ailleurs emporté l’adhésion de
70% des répondants à mon questionnaire, il y a donc une véritable demande.&lt;/p&gt;
&lt;p&gt;La transparence induit également &lt;strong&gt;l’utilisation de code libre&lt;/strong&gt;. Une telle
condition n’est pas une fin en soi mais permet à qui le souhaite et le peut de
vérifier que le code respecte ses utilisateur·ices et qu’il est effectivement à
leur service. Sans surprise vis-à-vis du public touché, le logiciel libre
est un argument pour utiliser le service pour 81% des répondants.&lt;/p&gt;
&lt;h3&gt;Confiance&lt;/h3&gt;
&lt;p&gt;La question de la confiance était posée sous différentes formes (et est
d’ailleurs déjà traitée à travers la transparence). La confiance, c’est ce qui
va convaincre les gens de venir, de rester (donc de payer) et de parler autour
d’eux de mon service. C’est aussi peut-être ce qu’il y a de plus compliqué à
assurer sur le long terme. Cela passe à la fois par le dialogue et par les
actes ; les critiques ne seront pas tendres en cas (d’accumulation) de
faux-pas.&lt;/p&gt;
&lt;p&gt;Les deux composantes essentielles du dialogue que je vois sont la communication
sur les médias sociaux et le support offert aux client·es. Une mauvaise
communication ou un mauvais support, c’est ce qui peut plomber une image de
marque ; à l’inverse d’un bon support, dont vous n’entendrez jamais parler.
Quant à l’excellent support, c’est les anciens de Captain Train / Trainline
qui &lt;a href="https://medium.com/@djo/obsession-service-client-captain-train-cb0b91467fd9"&gt;en parle le mieux&lt;/a&gt;.
À l’argument du support par email, j’ai d’abord été surpris de n’avoir que 51%
de réponses favorables… mais cela ne veut pas dire qu’il ne faut pas en faire,
juste que cela ne correspond pas à un argument marketing qui justifierait de
changer de service.&lt;/p&gt;
&lt;p&gt;Ensuite, je compte aligner mes actes avec mes paroles à travers au moins trois
actions :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;faciliter la portabilité des données (que ce soit pour arriver ou pour partir) ;&lt;/li&gt;
&lt;li&gt;contribuer au code du logiciel utilisé ;&lt;/li&gt;
&lt;li&gt;participer au collectif des &lt;a href="https://chatons.org/"&gt;&lt;abbr title="Collectif des Hébergeurs Alternatifs, Transparents, Ouverts, Neutres et Solidaires"&gt;CHATONS&lt;/abbr&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;D’un point de vue marketing, les deux premiers arguments sont sans appel : 82
et 85% d’avis favorables. Le troisième est intéressant car c’est celui qui a
recueilli le plus de personnes ne se prononçant pas (26% alors que les autres
arguments tournent plutôt entre 7 et 15%). Je l’analyse du fait que les
&lt;abbr&gt;CHATONS&lt;/abbr&gt; n’est pas (encore) un collectif très connu et que les
personnes ne savent donc pas quoi en penser. En revanche, 78% des avis
exprimés sont favorables, ce qui est plutôt positif dans l’ensemble !&lt;/p&gt;
&lt;h3&gt;Qualité de service&lt;/h3&gt;
&lt;p&gt;Pour terminer, la qualité du service (performances et maintenance du service en
ligne) devra être au cœur de mes préoccupations si je veux rester crédible. Sur
ce point néanmoins je dispose d’un peu moins de billes aujourd’hui, même si je
maintiens déjà &lt;a href="https://lessy.yuzu.ovh"&gt;Lessy&lt;/a&gt; sans trop de soucis.&lt;/p&gt;
&lt;p&gt;L’une de mes certitudes toutefois est qu’il ne faut pas lésiner sur les moyens
et notamment sur les capacités du serveur et la sécurité que ce soit
maintenance, &lt;em lang="en"&gt;monitoring&lt;/em&gt; ou &lt;em lang="en"&gt;backups&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Pour avoir vécu quelques applications en production douloureuses, j’ai
également conscience qu’il y a véritablement un changement d’esprit à opérer
entre un service offert (type &lt;a href="https://lessy.yuzu.ovh"&gt;lessy.yuzu.ovh&lt;/a&gt;) et un service
payant professionnel.&lt;/p&gt;
&lt;h2&gt;Marché et tarification envisagées&lt;/h2&gt;
&lt;p&gt;La définition d’un marché est un exercice compliqué car, d’une part, je ne l’ai
jamais fait et, d’autre part, c’est un peu naviguer à l’aveugle. Dans le cas
d’un agrégateur d’actualités, c’est encore plus casse-gueule car &lt;strong&gt;les
technologies comme &lt;abbr&gt;RSS&lt;/abbr&gt; semblent à la fois sur le déclin et déjà
fortement investies par l’auto-hébergement&lt;/strong&gt;. On me l’a d’ailleurs
(sous-)entendu de (très) nombreuses fois dans les commentaires de mon
questionnaire. 70% des répondants utilisent déjà un service hébergé ou sur leur
propre PC et seulement 37% se disent prêt·es à payer pour un tel service ; ce
qui ne signifie pas non plus qu’ils et elles viendront chez moi ! Qu’à cela ne
tienne, je vais tout de même tenter une réponse.&lt;/p&gt;
&lt;p&gt;Je vois très clairement deux périodes pour mon service. La première consistera
à proposer un service basé sur un logiciel existant (très certainement &lt;a href="https://freshrss.org"&gt;FreshRSS&lt;/a&gt;).
Je viserai alors un public déjà sensibilisé à ce genre d’outils, qui n’a pas
l’envie ni le temps de maintenir un service en ligne et qui est prêt à payer
pour déléguer ces tâches à quelqu’un d’autre. J’ai bon espoir d’arriver à
générer un peu de chiffre d’affaire, de quoi commencer à me sortir un salaire
(probablement pas énorme). En parallèle de cette période, je compte améliorer
le logiciel pour l’orienter vers quelque chose de plus grand public et moins
dépendant de technologies précises. Tout du moins, je pense qu’il sera
nécessaire de repenser la façon de s’abonner à des sites. Je dis « améliorer »
mais comme FreshRSS est déjà soutenu par une communauté, cela se fera
nécessairement en accord avec celle-ci. Ce qui m’amènera donc à la deuxième
période où je pourrai toucher un public élargi et qui ne se soucie pas des
technologies sous-jacentes. En résumé, &lt;strong&gt;plutôt que de lutter pour m’insérer
sur un marché hyper-concurrentiel, je compte en changer pour me permettre de
respirer&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Un autre point, qui rajoute peut-être une couche de complexité, c’est que je
compte m’adresser à un public exclusivement francophone. On peut trouver cette
décision un peu étrange à l’heure de la connexion mondiale, mais je fais ce
choix de manière pragmatique pour me faciliter la communication. Je ne serai
en effet jamais aussi efficace qu’en français pour véhiculer une idée ou pour
aider une personne sur le support. Je crois que ce choix me permettra de
m’économiser de l’énergie pour d’autres tâches plus importantes (et j’aurai
déjà beaucoup à faire !) Bien entendu, si le service se base sur FreshRSS, il
existe déjà de nombreuses traductions donc je ne m’amuserai pas à les enlever.
Je parle ici bien uniquement de la communication.&lt;/p&gt;
&lt;p&gt;Concernant la politique tarifaire, cela reste encore à valider mais je
partirais sur :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;une période d’essai d’un mois ;&lt;/li&gt;
&lt;li&gt;un abonnement mensuel (le prix reste à déterminer) ;&lt;/li&gt;
&lt;li&gt;un abonnement annuel avec réduction (idem) ;&lt;/li&gt;
&lt;li&gt;aucune limite sur le nombre de flux suivis.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Concernant le dernier point, plus de 90% des répondants se contentent de moins
de 500 flux ce qui me semble tout à fait gérable. Reste les 10% restants et les
abus éventuels qui pourraient faire exploser les coûts de stockage et de
traitement notamment. J’envisageais d’abord de mettre une limite à 500
abonnements, déblocable sur simple demande au support, mais d’un point de vue
marketing je trouve qu’il est plus efficace de ne pas mentionner de limite et
de gérer les abus au cas par cas. L’avenir me le dira !&lt;/p&gt;
&lt;p&gt;Aussi, j’ai décidé de ne pas appliquer de tarifs évolutifs en fonction du
nombre d’abonnements. Les avis étant très partagés sur la question, il me
semble qu’il est plus simple d’avoir un tarif unique.&lt;/p&gt;
&lt;h2&gt;Avenir envisagé sur le long terme&lt;/h2&gt;
&lt;p&gt;La grande question qui se pose lorsque l’on s’abonne à un service en ligne,
c’est celle de sa pérennité. Est-ce que le service sera toujours là dans un
an ou deux ? Vous aurez peut-être compris que je ne souhaite surtout pas me
lancer sur un modèle « startup » qui consiste pour beaucoup à cramer de
l’argent dans l’espoir de trouver un &lt;em lang="en"&gt;business model&lt;/em&gt;… bien au
contraire. Comme déjà évoqué plus haut, mon premier objectif sera de me générer
un revenu correct pour vivre. Cet objectif, j’aimerais l’atteindre globalement
seul afin de valider un certain niveau d’autonomie. Mais maintenir un service
seul sur le long terme ne me paraît absolument pas viable et extrêmement
fragile, c’est pourquoi j’envisage le long terme au sein d’une structure avec
plusieurs personnes. Il est bien sûr trop tôt pour m’avancer sur quoi que ce
soit, en particulier sur la forme que prendrait cette structure. J’ai toutefois
une ambition, directement inspirée par la société Basecamp : celle de
&lt;strong&gt;maintenir le service &lt;a href="https://basecamp.com/about/policies/until-the-end-of-the-internet"&gt;jusqu’à la fin d’Internet&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Cela ne peut rester qu’une ambition tant que je ne génère pas de revenu et que
la stabilité de l’entreprise n’est pas prouvée, mais je trouve que c’est une
vision juste et encourageante que ce soit pour moi ou pour mes (futur·es)
client·es. Là où beaucoup trop de services sont aujourd’hui éphémères, je
trouve qu’il est rassurant de savoir qu’un tel endroit est prévu pour durer.
J’espère également que cela me poussera à faire les choses « correctement » et
inspirera d’autres personnes à faire de même.&lt;/p&gt;
&lt;h2&gt;Prochaines étapes&lt;/h2&gt;
&lt;p&gt;Tout ce que je viens de raconter reste très théorique tant que je n’ai pas
commencé à avancer dessus. Je n’ai d’ailleurs pas encore de date à donner quant
à la sortie officielle du service. J’ai commencé un plan pour avoir une vue
d’ensemble de tout ce que j’ai à faire d’ici là. Si je suis assez confiant sur
le fait de pouvoir avancer relativement vite, &lt;strong&gt;le service ne devrait pas
sortir pour autant avant la fin de l’année&lt;/strong&gt;. J’ai notamment, avant ça, un
voyage à faire en Bretagne ; voyage que je repousse depuis plusieurs années…
mais cela risque bien d’être le dernier moment si je veux le réaliser sous la
forme que j’envisage.&lt;/p&gt;
&lt;p&gt;En parallèle de ce travail de définition de mon service, j’ai également réalisé
des documents prévisionnels pour connaître les coûts de mon projet et
comprendre mon chiffre d’affaire. Il me reste encore à affiner ces chiffres, en
particulier les objectifs en terme de nombre de client·es. La prochaine étape
que je vois est celle du choix du statut légal de l’entreprise. J’envisage
aujourd’hui deux possibilités : le statut de micro-entreprise ou rejoindre une
&lt;a href="https://fr.wikipedia.org/wiki/Coop%C3%A9rative_d%27activit%C3%A9s_et_d%27emploi"&gt;coopérative d’activité et d’emploi&lt;/a&gt;.
Je reste néanmoins toujours à l’écoute d’autres solutions.&lt;/p&gt;
&lt;p&gt;Quant au nom du service… je le garde pour plus tard 😉&lt;/p&gt;</content></entry><entry><title>Questionnaire sur votre utilisation des agrégateurs d’actualité</title><id>urn:uuid:278d8a7e-0516-5f5f-9742-5b12549ef55c</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/questionnaire-agregateurs-dactualite.html" rel="alternate" type="text/html" /><published>2019-05-29T17:50:00+02:00</published><updated>2019-05-29T17:50:00+02:00</updated><content type="html">&lt;p&gt;J’ai partagé hier matin sur les réseaux sociaux un questionnaire pour étudier
l’utilisation des agrégateurs d’actualité (ou « de flux &lt;abbr&gt;RSS&lt;/abbr&gt; »). Je
reviendrai plus longuement dans un autre article sur le pourquoi et le comment
mais, pour faire court, je souhaite me mettre à mon compte d’ici la fin de
l’année et j’ai pour cela besoin de connaître un peu mieux les attentes des
personnes utilisant de tels outils.&lt;/p&gt;
&lt;p&gt;J’ai pour le moment récupéré plus de 200 réponses, ce qui représente le double
de ce que j’espérais initialement. J’aurais toutefois souhaité un peu plus de
réponses de personnes prêtes à payer pour un tel service (un peu plus du tiers
des répondants pour le moment).&lt;/p&gt;
&lt;p&gt;Si vous souhaitez me donner un petit coup de main, n’hésitez donc pas à remplir
&lt;a href="https://framaforms.org/votre-utilisation-des-agregateurs-dactualite-1558172477"&gt;ce questionnaire&lt;/a&gt;
et à &lt;strong&gt;le partager auprès de vos proches et collègues&lt;/strong&gt;. Je l’ai pensé court
pour pouvoir le remplir en 5 minutes sans avoir à se creuser la tête. Je ferai
sans doute un questionnaire plus détaillé ensuite pour les personnes acceptants
de prendre un peu plus de temps.&lt;/p&gt;
&lt;p&gt;Je publierai l’analyse des résultats sous la forme probable d’un article de
blog afin que cela puisse bénéficier à n’importe qui.&lt;/p&gt;
&lt;p&gt;Merci d’avance !&lt;/p&gt;</content></entry><entry><title>Concevoir les logiciels de demain</title><id>urn:uuid:3df6366d-874d-5d76-81be-3d204d7836cb</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/talks/concevoir-les-logiciels-de-demain.html" rel="alternate" type="text/html" /><published>2019-04-16T11:05:00+02:00</published><updated>2019-04-16T11:05:00+02:00</updated><content type="html">&lt;p&gt;J’ai donné le dimanche 7 avril dernier une conférence à l’occasion des
&lt;a href="https://jdll.org"&gt;Journées du Logiciel Libre&lt;/a&gt; (&lt;abbr&gt;JdLL&lt;/abbr&gt;). L’article
qui suit correspond à la transcription de ce que j’y ai raconté. Je me
proposais de poser des réflexions autour de la conception des logiciels de
« demain », en intégrant à la fois des considérations environementales et
d’impact utilisateurice. Loin d’être exhaustive, cette présentation était
surtout l’occasion de jeter quelques pistes à défricher ensuite ensemble. Le
format lui-même tentait de faire intervenir les personnes venues m’écouter. Sur
ce point j’ai été particulièrement satisfait que les conversations se déroulent
de manière aussi fluide, sans accaparement de la parole ; vraiment merci aux
personnes qui étaient là ! J’ignore si elles sont reparties avec ce qu’elles
étaient venues chercher, c’était finalement assez éloigné de ce que j’avais en
tête au moment de proposer le sujet. J’ai en tout cas pris plaisir à donner
cette conférence (même pas stressé !) Pour bien faire, il faudrait maintenant
que je creuse chaque sujet dans des articles spécifiques, il y a de quoi faire.&lt;/p&gt;
&lt;p&gt;La transcription est plus complète que ce que j’ai raconté à l’oral vu que j’ai
nécessairement oublié de dire des choses. Je l’ai aussi annotée pour redonner
du contexte lorsque nécessaire. Les quelques diapos &lt;a href="concevoir-les-logiciels-de-demain/diapos.html"&gt;sont accessibles en suivant
ce lien&lt;/a&gt;.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Je vais commencer par vous poser une question : qui ici s’est déjà posé la
question d’adopter un mode de vie numérique plus en accord avec la planète ?&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Note : tout le monde ou presque a levé la main alors que la salle était
pleine. Très content de cette réponse même si du coup ça a augmenté mon
syndrome de l’imposteur. Ça a toutefois bien aidé à alimenter les discussions
qui ont suivi.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Si je vous pose la question, c’est parce qu’en préparant cette conférence, je
me suis rendu compte que je n’arriverais jamais à aborder tous les sujets qui
pourraient l’être. Je risque de perdre des gens, et je risque surtout de ne pas
répondre aux attentes de celleux qui se sont posées plus de questions que moi.
Alors j’aimerais faire de cette conférence un espace participatif en tentant un
format un peu particulier. Je vais introduire les deux parties de notre
conférence pendant 10 à 15 minutes chacune, et à la fin de chaque partie, je
vous poserai une question pour ouvrir le sujet. Le but étant de venir compléter
ce que j’aurais dit, ou de débattre selon les envies. Ce que je vais raconter
paraîtra sûrement incomplet aux yeux de certaines personnes, mon but n’est pas
forcément de rentrer dans le détail mais de défricher un certain nombre de
sujets… en les survolant donc.&lt;/p&gt;
&lt;p&gt;Mon objectif est que vous repartiez avec trois éléments. Le premier, c’est que
vous vous posiez la question de savoir si votre vie numérique est en accord
avec vos convictions. Le deuxième, ce sont des idées, des outils pour concevoir
plus simple, plus orienté « bien-être » utilisateurices. Enfin, je voudrais
tracer quelques sillons de sujets que vous auriez envie de creuser,
d’approfondir en sortant de cette salle.&lt;/p&gt;
&lt;p&gt;Je vous mets un pad à disposition pour retrouver la transcription de ce que je
vais raconter ainsi que les diapos. Mais je vous encourage, si vous prenez des
notes, à le faire de manière collaborative sur ce pad. Si vous avez des
questions, des retours à faire sur le fond comme sur la forme, allez-y. Si vous
voulez partager des liens, des ressources ou si vous voulez échanger des
coordonnées pour discuter de tout ça entre vous plus tard, faites-vous
plaisir !&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Note : personne n’avait son &lt;abbr&gt;PC&lt;/abbr&gt; sur les genoux du coup l’idée
du pad collaboratif est tombée à l’eau. Pas très grave, les gens étaient
d’autant plus à l’écoute.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Moi, super-héros et développeur de sites statiques&lt;/h2&gt;
&lt;p&gt;Pour commencer, je vais vous parler de moi. Et donc aussi un peu de vous, je
l’espère.&lt;/p&gt;
&lt;p&gt;L’autre jour en trainant sur Twitter, je suis tombé sur une photo montrant un
ours sur la banquise, rachétique et visiblement mal en point. Le commentaire
sous la photo laissait entendre que son état était dû au réchauffement de la
planète. Du coup, ni une ni deux, un sentiment de révolte m’envahit ! « Comment
peut-on laisser faire ça ? » Mais l’ours n’est pas la seule raison de cette
colère : chaque tweet, chaque article traitant d’inégalité, de racisme ou
d’effondrement vient alimenter ce sentiment d’injustice, et par la même
occasion, cette envie de vouloir tout résoudre. Ce syndrome, c’est celui du
super-héros, celui qui est capable de tout remettre dans l’ordre. Nous avons
tous envie d’être un super-héros pour résoudre les problèmes dans le monde.
Mais notre kryptonite à nous, ce n’est pas un caillou radioactif, c’est les
photos de chats « vraiment-trop-mignons ». Invariablement après une telle
photo, notre colère s’estompe.&lt;/p&gt;
&lt;p&gt;Heureusement, il y a celleux qui font. Celleux qui font pipi sous la douche
pour économiser l’eau de la planète. Celleux qui éteignent la télé avant de se
coucher pour sauver la banquise de ce pauvre ours famélique. Et il y a celleux
qui développent des sites statiques pour réduire leur impact carbone. Alors
oui, ça vous fait peut-être rire : « C’est pas comme ça qu’ils vont sauver le
monde, hé ! » Mais en attendant, est-ce qu’ils et elles ne font déjà pas un peu
plus que vous, en colère derrière votre écran ?&lt;/p&gt;
&lt;p&gt;Évidemment, je vous présente des situations caricaturales, on est toutes et
tous un peu des deux à la fois, et il est hors de question de confronter
celleux qui font à celleux qui se révolent. Nous ne sommes pas toutes et tous
égaux face à l’action politique (au sens large du terme), notamment à cause de
nos inégalités face au temps, aux ressources ou à notre position sociale. Je
propose que nous restions tous humble vis-à-vis de ce que l’on peut
entreprendre et d’accepter que nous avons tous une part d’incohérence que nous
travaillons chacun·e à notre rythme. Je suis convaincu par ailleurs (c’est donc
subjectif) que ce sont nos actions individuelles (bien que parfois un peu
ridicules) qui nous font avancer sur le chemin d’une action plus collective et
plus efficace. C’est parce que j’ai rejoint une &lt;abbr&gt;AMAP&lt;/abbr&gt; un jour que
j’ai eu l’idée de faire une conférence participative et que demain je
m’associerai peut-être à un collectif pour faire avancer les causes qui
m’importent, en espérant peut-être un effet boule de neige.&lt;/p&gt;
&lt;p&gt;Mais revenons-en à notre sujet : j’ai moi-même développé un générateur de sites
statiques avec dans l’idée de faire « mieux ». Évidemment, je sens bien que
c’est totalement insuffisant, mon site personnel notamment a une toute petite
visibilité, quel impact pourrait-il bien avoir sur la planète ? Alors si mon
site statique est insuffisant, qu’est-ce que je fais ? J’ai essayé de
formaliser un peu les problèmes que le numérique me pose.&lt;/p&gt;
&lt;p&gt;Partons de ce schéma représentant la répartition de notre empreinte carbone. On
y voit notamment que notre usage du numérique possède un impact aussi important
que celui de notre consommation de viande et de poisson et on peut parier sur
une augmentation au moins à court terme.&lt;/p&gt;
&lt;p&gt;&lt;img alt="schéma montrant que l’empreinte carbone des Français concernant nos achats et usage du numérique est de 1180 Kg eq CO2/an tandis que notre consommation de viande et de poisson est de
1144." src="concevoir-les-logiciels-de-demain/empreinte-carbone.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;Cet empreinte est notamment due à notre façon d’acheter compulsivement du
matériel et d’en changer sans réel besoin : on change de téléphone en moyenne
tous les 2 ans et d’ordinateur tous les 3 à 4 ans ! Mais je laisse ce sujet à
d’autres, je veux me concentrer sur le sujet du développement logiciel
aujourd’hui.&lt;/p&gt;
&lt;p&gt;Lorsqu’on cherche comment est réparti cet impact numérique, c’est la
consommation de vidéos qui ressort principalement. Ainsi, &lt;a href="https://theshiftproject.org/wp-content/uploads/2018/11/Rapport-final-v8-WEB.pdf"&gt;selon le Shift
Project&lt;/a&gt;,
« &lt;em&gt;Le visionnage d’une vidéo en ligne de dix minutes disponible dans le “Cloud”
induit par exemple une consommation électrique équivalente à la consommation
propre d’un smartphone sur dix jours&lt;/em&gt; ». Vous penserez à moi la prochaine fois
que vous regarderez une vidéo de « chatons-trop-mignons » en haute définition
sur Youtube !&lt;/p&gt;
&lt;p&gt;On pourra donc commencer à nous questionner sur nos usages un par un, en
commençant peut-être par regarder moins de vidéos et en qualité plus basse, le
but étant à terme d’avoir un usage plus respectueux de la planète. Mais je me
pose quand même une question : suis-je vraiment le fautif dans l’affaire ? Je
veux dire, nous sommes tout de même des millions d’utilisateurs et
utilisatrices à partager une consommation irraisonnée de vidéos en ligne et
nous partagerions un même usage &lt;strong&gt;sans s’être jamais concerté·es&lt;/strong&gt; ?
Excusez-moi mais je flaire quand même quelque chose de louche dans l’affaire !
Est-ce que ce ne serait pas plutôt l’outil qui me pousse à l’usage ? Mais
pourquoi ? Qui l’a conçu ? Dans quel but ?&lt;/p&gt;
&lt;p&gt;Lorsque je me rends sur Youtube, c’est facile : c’est Google qui a conçu cette
plateforme de divertissement. Mais moi, lorsque j’entends Google, j’ai un petit
drapeau qui se lève dans la tête et qui me dit « attention, Google est l’une
des plus grosses capitalisations boursières et génère la grande majorité de son
chiffre d’affaire à partir de la pub ! » Et pour que la pub génère de l’argent,
il faut des personnes pour la regarder. Idéalement beaucoup. Et qui reste
longtemps. Est-ce que j’ai réellement consenti à regarder beaucoup de vidéos à
la suite… ou est-ce Google qui m’a incité à le faire pour vendre du « temps de
cerveau disponible » (comme dirait l’autre) et donc m’incite à rester sur sa
plateforme ? Vous l’aurez compris, je touche du doigt un problème du
&lt;del&gt;capitalisme&lt;/del&gt; design de l’attention.&lt;/p&gt;
&lt;p&gt;Donc non seulement il y a des usages, des logiciels qui ne respectent pas
l’environnement, mais en plus ils ne respectent pas non plus leurs
utilisateurices ! Est-ce qu’on ne pourrait pas y faire quelque chose ? Par
exemple, si on commençait à virer cette colonne de suggestions de vidéos « qui
pourraient nous intéresser » ainsi que l’enchainement automatique de vidéos ?
Évidemment Youtube ne vous permet pas de le faire… mais est-ce qu’on aurait pas
inventé une chose qui se nomme « le logiciel libre » ? Si je n’aime pas ce que
fait telle ou telle plateforme de mon attention, alors je vais la modifier pour
qu’elle me respecte, n’est-ce pas la promesse du logiciel libre ?&lt;/p&gt;
&lt;p&gt;Nous sommes sauvé·es !&lt;br /&gt;
…&lt;br /&gt;
Vraiment ?&lt;/p&gt;
&lt;p&gt;Prenons une plateforme de vidéos libre comme Peertube, et imaginons qu’il y ait
au sein de Peertube un tel système de suggestions de vidéos ainsi que
l’enchainement automatique de vidéos. Qui dans la salle se sent capable de
modifier le code pour virer ces deux fonctionnalités ? Et en moins d’une heure
(le temps que je considère comme raisonnable pour ne pas avoir l’impression de
le perdre) ? Et bien je suis désolé de vous annoncer que toutes les personnes
qui ont levé la main ne sont pas vraiment libre ! Ils ou elles sont dépendantes
soit d’une personne externe, soit de temps et de ressources qu’elles devront
dépenser de façon disproportionnée vis-à-vis du gain consenti. La liberté 1 du
logiciel libre, celle qui implique que l’on peut modifier le code n’est
finalement peut-être pas si bien respectée.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Note : quelques mains se sont levées dans la salle lorsque j’ai posé la
première question, mais toutes se sont rabaissées lorsque j’ai précisé « en
moins d’une heure ». J’ai bien conscience qu’il s’agit d’un temps arbitraire,
mais j’avais à cœur de remettre en perspective le « temps disponible » que
nous n’avons pas toutes et tous à disposition de manière égale.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;J’ai donc posé lors de cette partie trois questions / problèmes qui se posent à
moi aujourd’hui dans le numérique : mon usage du numérique respecte-t-il la
planète ? Suis-je maître de mon attention lorsque j’utilise un logiciel ? Et
suis-je capable de modifier ce logiciel pour qu’il respecte l’usage que je
souhaite avoir de lui ?&lt;/p&gt;
&lt;p&gt;Mais vous, &lt;strong&gt;quels problèmes vous pose le numérique aujourd’hui et aimeriez
voir disparaître / résolu demain ?&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Note : la discussion a eu tendance à dévier vers des solutions aux problèmes
que j’ai soulevés. En cela le résultat de cette première question est mitigé,
bien qu’il y ait eu des prises de parole vraiment pertinentes. N’ayant pas
pris de notes, je ne serai pas capable de tout retranscrire ici cependant.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Cultivons notre jardin (ou une vision positive du numérique de demain)&lt;/h2&gt;
&lt;p&gt;Bien, maintenant que nous avons établi les problèmes que nous pose le
numérique, on voit un peu mieux ce dont on ne veut pas… mais du coup, on veut
quoi ?&lt;/p&gt;
&lt;p&gt;Essayons pour cela de commencer par déterminer ce qui nous fait vibrer. Pour ma
part, mon premier gros coup de cœur pour le numérique a été un jour d’hiver
lorsque j’étais en troisième et que j’ai reçu mon premier &lt;abbr&gt;PC&lt;/abbr&gt; à
Noël. Lorsque j’ai réalisé que j’allais pouvoir avoir Internet directement dans
ma chambre, je me suis tout de suite imaginé converser avec des personnes aux
quatres coins du monde. C’est difficile de définir ce que j’ai ressenti mais
je m’en souviens encore. Et c’était synonyme d’un numérique très positif.&lt;/p&gt;
&lt;p&gt;Mais bon, à l’époque c’était compliqué l’informatique pour moi, on était encore
en 56K avec le modem qui faisait du bruit dans le bureau de mes parents et
j’étais persuadé qu’il fallait que j’installe le cédérom fourni par Orange pour
que ça marche. Révélation : ça n’a jamais marché. Le temps est passé, Internet
s’est fait omniprésent et me vendait de moins en moins de rêve ; une sorte de
routine s’est installée.&lt;/p&gt;
&lt;p&gt;Mais voilà qu’en 2017, avec les copains de &lt;a href="https://framasoft.org/"&gt;Framasoft&lt;/a&gt;
on lançait la campagne &lt;a href="https://contributopia.org/"&gt;Contributopia&lt;/a&gt;. Je me
souviens très bien du sentiment positif que j’ai eu lorsque Pouhiou et pyg nous
ont présenté ce qu’ils avaient en tête. C’était le même sentiment que quelques
années plus tôt, et ça dessinait un numérique tout aussi positif, voire plus.&lt;/p&gt;
&lt;p&gt;Ce sont ces sentiments, ces imaginaires que j’aimerais qu’on arrive ensemble à
reconstruire. Si on pouvait appuyer sur un bouton &lt;em&gt;reset&lt;/em&gt;, il ressemblerait à
quoi notre monde numérique ? Plutôt que de faire une liste détaillée qui
prendrait des plombes à faire, je vais me contenter de parler de trois
« zones » que j’aimerais rebatir si je devais repartir de zéro. Cette liste est
donc très loin d’être exhaustive ! Notez que je vais mélanger alégrement
numérique et Internet dans cette partie, c’est voulu.&lt;/p&gt;
&lt;p&gt;Le premier point, c’est celui qui m’a fait vibrer au collège. C’est cette
possibilité de pouvoir faire des voyages culturels, le cul vissé sur ma chaise
et au prix d’une connexion Internet ; rencontrer son prochain sans contrainte
de distance. Peut-être que ça ne fait pas rêver tout le monde, mais ça faisait
rêver un garçon de 13 ans, donc pourquoi pas commencer par là ? Et de toute
façon demain sera sans avion, autant commencer à changer notre façon de
voyager.&lt;/p&gt;
&lt;p&gt;Le deuxième sujet numérique qui me donne ce sentiment « wahou ! », c’est le
partage des ressources et des connaissances. Vous connaissez peut-être ce petit
site qui se nomme Wikipédia : il s’agit d’une encyclopédie en ligne alimentée
uniquement par des bénévoles… je vous jure que ça marche ! Et tout le monde
peut participer, donc même des sujets hyper spécifiques peuvent se retrouver
être présentés en long et en large. Ce que j’aime, c’est ce pot commun, tout le
monde contribue et tout le monde peut se servir sans léser personne. Il n’y a
pas d’accaparement de la connaissance, c’est pour tout le monde.&lt;/p&gt;
&lt;p&gt;Enfin, le troisième coin d’Internet que je trouve « beau », ce sont les zones
d’information et d’entraide entre oppressé·es et personnes ayant besoin de se
renseigner pour « améliorer » leur cadre de vie, pour s’organiser ou tout
simplement pour discuter. L’anonymat notamment que permet Internet offre la
possibilité de se dégager d’une certaine honte et de se sentir plus en
confiance pour aborder certaines recherches et discussions. Les liens tissés
entre les individus sur Internet sont généralement décrits comme « virtuels »,
mais je vous assure que ça ne l’est pas du tout. Ces liens numériques se
prolongent d’ailleurs bien souvent dans la vie « réelle » (mais je préfère le
terme « vie physique »).&lt;/p&gt;
&lt;p&gt;Vous me rétorquerez alors : « ton Internet de demain il ressemble quand même
vachement à celui d’aujourd’hui » et vous aurez sans doute raison. Sauf que
dans celui d’aujourd’hui, ce ne sont pas ces aspects-là qui dominent.
J’aimerais que les logiques de communautés prennent le pas sur les logiques
individuelles en quelque sorte. Et l’élagage des usages que j’ai effectué
permet de rendre le numérique plus soutenable. Mais un réseau d’entraide basé
sur des vidéos en très haute qualité n’est pas forcément beaucoup plus
soutenable, il faut bien évidemment se poser aussi la question de la conception
en plus de celle des usages.&lt;/p&gt;
&lt;p&gt;Alors comment on conçoit pour demain ? Quel est le secret si bien gardé de
cette conférence ?&lt;/p&gt;
&lt;p&gt;Je vous propose de partir sur une idée que j’applique de temps en temps lorsque
je veux progresser dans ma pratique d’un sujet : je me pose des contraintes
fortes. Ces contraintes ne sont pas des axiomes de conception qu’il faudrait
appliquer coûte que coûte, mais des exercices qui doivent vous pousser à vous
questionner sur des pratiques que vous auriez plus ou moins intégrées comme
« normales ». Ces contraintes doivent répondre à un problème que vous cherchez
à résoudre. Et ça tombe bien, on a identifié au moins trois problèmes dans la
partie précédente !&lt;/p&gt;
&lt;p&gt;Concernant l’impact environnemental tout d’abord, quel genre de contraintes
peut-on imaginer ? Le poid des pages étant souvent pointé du doigt, commençons
par là. Première contrainte : transformer un site ou une application pour que
ses pages de fassent pas plus de 200Ko, images comprises ! Cette première
contrainte devrait déjà soulever des questions : est-ce que mon fichier HTML
est suffisamment simple ? Et mon fichier CSS ? Mais cette librairie JavaScript
pèse déjà 200Ko, quelles implications si je dois m’en passer ? Combien d’images
puis-je insérer ? Avec quelle qualité ? Et comment appliquer ça à un service de
partage de photos ou de vidéos ? Quels choix de conception cela implique-t-il ?
Peut-être que vous ne trouverez pas de réponse satisfaisante sans relacher
légèrement la contrainte, mais ce n’est pas grave car vous aurez déjà commencé
à vous poser la question et imaginer des solutions plus « simples ».&lt;/p&gt;
&lt;p&gt;Sur l’attention de l’utilisateurice maintenant. Je rappelle que son but dans la
vie n’est pas de passer son temps sur votre site ou application, il ou elle a
bien d’autres chats à fouetter (mais ne faites pas ça chez vous, c’est de la
maltraitance animale et c’est mal). Imaginons la contrainte suivante : au bout
de 5 minutes passées (durant une journée) sur votre application, celle-ci se
ferme automatiquement. Comment allez-vous la concevoir pour que
l’utilisateurice fasse tout de même ce qu’elle est censée faire ? Cela pose la
question de ce que doit faire votre application car il vous faut maintenant
définir quelles fonctionnalités sont maintenant essentielles. Par exemple,
comment appliquer cette contrainte à un réseau social ? Quels choix allez-vous
faire pour que la personne qui se rend sur Twitter ou Mastodon puisse toujours
lire ce qu’il ou elle l’intéresse ? Et au fait, à quoi ça doit servir un réseau
social ? Faire de la veille ? se détendre ? créer des liens ? organiser des
communautés ? tout à la fois ?&lt;/p&gt;
&lt;p&gt;Enfin, concernant la maintenabilité des logiciels, comment favoriseriez-vous la
possibilité pour un néophyte de rentrer dans votre code ? Exemple de contrainte :
votre programme doit faire moins de 500 lignes de code. Là encore peut-être
qu’il va devenir compliqué de recréer quelque chose comme un réseau social ou
une plateforme de partage de vidéos, mais posez-vous les questions que cela
engendre. Que doit faire mon programme ? Comment j’organise mon code ? Vous
réaliserez sans doute qu’on ne peut pas faire l’impasse sur une « éducation au
code » et tant mieux. Maintenant : quelles sont les actions que vous prendrez
pour qu’un minimum d’éducation soit nécessaire pour au moins comprendre
l’architecture de votre logiciel ? Et on voit que des tas de questions
peuvent découler d’une bête question (celle de rendre votre code accessible au
plus grand nombre).&lt;/p&gt;
&lt;p&gt;On peut évidemment imaginer des tas d’autres contraintes comme limiter le temps
de chargement de votre site ou application à moins de 0,5 seconde, limiter le
nombre d’écrans à 2, développer une application sans aucune dépendance
autres que celle du langage et de sa librairie standard ou encore limiter
l’accès au réseau au strict minimum. Vous pouvez aussi les mixer, les modifier,
etc. Ces contraintes vont sans doute vous paraître contre-productives par
moment, voire totalement opposées à leur objectif et c’est pour ça que
j’insiste sur le fait qu’il ne s’agit que de guides de conception. Le risque
étant d’appliquer aveuglément ces contraintes en perdant de vue votre objectif
initial.&lt;/p&gt;
&lt;p&gt;En appliquant ces différentes contraintes, j’ai bon espoir que vos logiciels
deviennent plus simples, plus respectueux d’un environnement mal en point et
d’utilisateurices souvent malmené·es. &lt;em&gt;In fine&lt;/em&gt;, ce sont vos logiciels qui
deviendront plus libres. Pour rappel, ce n’est pas vraiment le logiciel qui
doit être libre (lui il s’en fout, vous pouvez lui demander mais il y a peu de
chances qu’il réponde), c’est son utilisateur ou utilisatrice. Alors la
prochaine fois que vous concevrez un logiciel, merci de penser à sa liberté à
ellui.&lt;/p&gt;
&lt;p&gt;Et vous, &lt;strong&gt;quels usages vous semble prendre tout leur sens dans le numérique ?
Qu’est-ce qui vous fait vibrer là-dedans ? Et comment le concevriez-vous ?&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;J’ai évoqué à un moment donné que je faisais parti de l’association Framasoft.
Bien que les questions posées lors de cette conférence et les esquisses d’un
monde numérique plus sobre fassent parties des réflexions qu’on mène dans
l’asso et plus spécifiquement dans le cadre de notre campage Contributopia, je
voulais souligner le fait que le sujet ne nous appartient pas. À partir du
moment où vous vous sentez concerné·e, alors vous êtes légitime pour traiter le
sujet et probablement tout aussi pertinent·e que nous. Je voulais faire ce
petit &lt;em&gt;aparte&lt;/em&gt; car il semble y avoir de plus en plus d’attentes envers
l’association pour porter ces réflexions. Cette confiance nous fait certes
plaisir, mais notre monde à nous (celui de demain) est émancipé et ne repose
pas sur un groupe de quelques copain·ines. Alors n’hésitez surtout pas à
cogiter sur tout ça dans votre coin et à lancer ensuite d’autres structures
collectives pour imaginer d’autres imaginaires. C’est en les multipliant qu’on
avancera !&lt;/p&gt;</content></entry><entry><title>Conception de la v8 du site</title><id>urn:uuid:e0194dbd-5839-5108-946c-c74ffa3ba3a0</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/conception-de-la-v8-du-site.html" rel="alternate" type="text/html" /><published>2019-03-01T13:20:00+01:00</published><updated>2019-03-01T13:20:00+01:00</updated><content type="html">&lt;p&gt;Au fil des années, j’ai pris le temps d’annoncer les changements importants du
site, je ne vais donc pas non plus déroger à la règle cette fois-ci. Cette
huitième version (quand même) arrive presque deux ans après la dernière. C’est
avant tout pour moi un retour au « fait-maison » qui était la base lorsque j’ai
démarré. J’avais été lassé de maintenir des outils souvent complexes ; &lt;a href="mise-a-jour-du-site-la-v5-est-la-o.html"&gt;la
cinquième version&lt;/a&gt; introduisait
notamment une idée un peu fumeuse consistant à agréger les éléments que je
partageais via 3 outils que j’avais moi-même développé…&lt;/p&gt;
&lt;p&gt;En revenant à un outil plus simple (je vous renvoie à &lt;a href="serie/le-boop-blog.html"&gt;ma série d’articles&lt;/a&gt;),
je reviens aussi à une idée de l’informatique qui me plaît : maîtriser (ou au
moins comprendre) les outils que j’utilise.&lt;/p&gt;
&lt;p&gt;Cet article, donc, revient sur les grandes lignes directrices que j’ai
souhaitées pour cette énième version de mon site. Notez que le contenu n’est
pas terminé, il manque notamment le manifeste qu’il me reste à rédiger et la
liste des projets que je souhaite mettre en avant. J’envisage aussi une page
« à propos » mais je ne suis pas certain de son intérêt.&lt;/p&gt;
&lt;h2&gt;Une approche pédagogique et ouverte&lt;/h2&gt;
&lt;p&gt;Si j’ai toujours tenté d’adopter une démarche pédagogique, je crois que je
commence à avoir une certaine maturité sur le sujet. La série d’articles dans
laquelle s’inscrit celui-ci en est la preuve la plus évidente puisque j’y
explique toute la démarche qui se cache derrière ce site. Un autre exemple que
j’aime bien est celui de la partie « Traitement des données » de ma page
« &lt;a href="mentions-legales.html"&gt;Mentions légales&lt;/a&gt; » dans laquelle j’explique que
malgré le fait que je ne collecte pas de données… et bien j’en collecte quand
même ; j’en profite pour expliquer la raison et les circonstances.&lt;/p&gt;
&lt;p&gt;Le côté ouverture est quant à lui illustré par les liens qui renvoient à chaque
fois vers les articles qui décrivent la raison de tel ou tel paragraphe, ou
pour compléter en informations. J’ai aussi insisté sur les liens renvoyant au
code source. J’envisage, pour aller plus loin, d’ajouter pour chaque page des
liens discrets vers les fichiers sources correspondants.&lt;/p&gt;
&lt;p&gt;L’une des conséquences de cette approche est que cela rend le site plus
verbeux. C’est voulu. Celleux qui me connaissent savent que j’écris facilement
de gros pavés et cela fait partie intégrante de qui je suis, j’assume. Pour
équilibrer cela, j’ai appliqué une série de bonnes pratiques de typographie
pour que le contenu reste agréable à lire, notamment le principe du « &lt;a href="https://css-tricks.com/equilateral-triangle-perfect-paragraph/"&gt;&lt;em&gt;triangle
équilatéral du paragraphe parfait&lt;/em&gt;&lt;/a&gt; »
(c’est-à-dire équilibrer la taille de la police d’écriture avec la largeur et
l’espacement des lignes). Le choix de couleurs qui contrastent bien entre elles
a pris un peu de temps, mais &lt;a href="https://developer.mozilla.org/fr/docs/Outils/Inspecteur_accessibilite"&gt;l’outil d’accessibilité intégré à Firefox&lt;/a&gt;
a été d’une aide précieuse.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Capture d’écran qui montre que le ratio de contraste du titre de cet article avec l’arrière-plan est de 14,32" src="images/site/v8-contraste-titre.png" /&gt;&lt;/p&gt;
&lt;p&gt;Le but de tout cela est aussi d’apposer une « patte » particulière sur mon
site, pour faire en sorte que la forme du blog épouse le fond de ce que je veux
promouvoir.&lt;/p&gt;
&lt;h2&gt;Navigation restreinte&lt;/h2&gt;
&lt;p&gt;Deux choses m’agacent souvent dans la navigation des sites :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;trop de liens différents donnés sans aucun contexte (pourquoi cliquerais-je
  sur tel ou tel lien ?) ;&lt;/li&gt;
&lt;li&gt;et le menu « hamburger » (du moins sur grand écran), celui caché derrière une
  icône représentée par trois barres horizontales.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Pour cette nouvelle version du site, la navigation se passe en majorité « dans
le texte ». C’est-à-dire que la majorité des liens vers les autres pages sont
(ou seront) contextualisés au sein du texte de la page d’accueil. Dans
l’en-tête du site, seulement deux liens : l’un pour revenir à l’accueil,
l’autre pour accéder au blog (qui reste le « lieu de vie » du site). Cette
économie de navigation m’évite en plus le fameux menu « hamburger ».&lt;/p&gt;
&lt;p&gt;Conscient que ce type de navigation est là encore verbeux, les différents liens
sont accessibles depuis le pied de page pour avoir une vue d’ensemble du site.&lt;/p&gt;
&lt;p&gt;Le dernier élément de navigation présent sur le site est le bouton qui apparaît
en bas de la page une fois que vous l’avez faite défiler un peu et qui permet
de remonter en haut de la page. Pour le créer, je me suis basé sur un article
de &lt;a href="https://m.signalvnoise.com/how-to-back-to-top-button-without-scroll-events/"&gt;&lt;i lang="en"&gt;Signal v. Noise&lt;/i&gt;&lt;/a&gt;.
J’ai dû légérement adapter le code qui s’appuie sur leur cadriciel JavaScript,
ce qui donne &lt;a href="https://framagit.org/marienfressinaud/marienfressinaud.fr/blob/master/static/scripts/back-to-top.js"&gt;un petit script d’une dizaine de lignes&lt;/a&gt;.
Le &lt;a href="https://framagit.org/marienfressinaud/marienfressinaud.fr/blob/master/static/style/herisson.css#L213-254"&gt;code &lt;abbr&gt;CSS&lt;/abbr&gt;&lt;/a&gt;
quant à lui est un peu plus long, mais principalement pour l’apparence.&lt;/p&gt;
&lt;h2&gt;Un thème moins bleu&lt;/h2&gt;
&lt;p&gt;Le thème de ce site a toujours été bleu, voire très bleu. Chose révolue donc
puisque je suis parti sur du rouge brique (il y aura bien quelqu’un·e pour me
dire que c’est orange, non ? /private-jock). Pourquoi ce rouge ? Pas de raison
particulière pour le coup, ça ne transmet pas de message particulier. On pourra
toujours disserter sur la signification des couleurs qui irait, dans le cas
présent, à l’encontre de ce que je veux transmettre ; mon pari est que ça ne
joue qu’à la marge et qu’on peut bien choisir un peu les couleurs que l’on veut
tant qu’elles nous plaisent ! Si quelqu’un vient argumenter sur le fait qu’il
trouve le thème agressif, je reconsidèrerai toutefois volontier mon sentiment.&lt;/p&gt;
&lt;p&gt;La « charte » se décline ainsi :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;la couleur principale (&lt;code class="color-primary"&gt;#2a2230&lt;/code&gt;), utilisée
  principalement pour le texte, ainsi qu’une variante légèrement plus clair (&lt;code class="color-primary-muted"&gt;#665e6c&lt;/code&gt;) ;&lt;/li&gt;
&lt;li&gt;une couleur secondaire (&lt;code class="color-secondary"&gt;#c02b43&lt;/code&gt;) pour réhausser le ton du site ;&lt;/li&gt;
&lt;li&gt;une couleur spécifique pour les liens (&lt;code class="color-link"&gt;#a6253a&lt;/code&gt;), proche de la couleur
  secondaire ;&lt;/li&gt;
&lt;li&gt;et une couleur de contraste (&lt;code class="color-contrast"&gt;#f8f6ff&lt;/code&gt;), utilisée notamment en arrière-plan.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;La règle est de ne jamais superposer deux couleurs différentes, à part la
couleur de contraste qui est prévue pour cela (son ratio avec les autres
couleurs est suffisant pour assurer une bonne lisibilité).&lt;/p&gt;
&lt;h2&gt;Mobile avant tout&lt;/h2&gt;
&lt;p&gt;J’ai pensé le site pour fonctionner sur mobile. Même si je n’utilise plus que
très peu le téléphone pour aller sur Internet, il est toujours plus agréable de
naviguer sur les sites prévus pour (c’est quand même l’une des promesses des
technologies web, de pouvoir être accessibles quel que soit le périphérique).&lt;/p&gt;
&lt;p&gt;Pour cela j’ai utilisé le mode « mobile » de Firefox (le raccourci pour
l’utiliser est &lt;code&gt;ctrl+maj+M&lt;/code&gt;). J’ai commencé par faire en sorte de supporter la
largeur d’écran la plus petite que je souhaitais pouvoir gérer (360 pixels),
puis j’ai ajouté quelques points de « rupture » (c’est-à-dire des largeurs
d’écran pour lesquelles le style doit changer). Par exemple, pour les blocs des
séries sur la page de blog, les blocs sont affichés en colonne par défaut :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;blog-series&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;flex-direction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;column&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;blog-serie&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;margin-bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="kt"&gt;rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Ce qui donne :&lt;/p&gt;
&lt;p&gt;&lt;img alt="Capture d’écran de la page principale du blog où l’on voit les blocs des séries en colonne" src="images/site/v8-blog-petit-ecran.png" /&gt;&lt;/p&gt;
&lt;p&gt;Mais à partir d’une largeur de &lt;code&gt;40rem&lt;/code&gt; (qui correspond à 640 pixels dans ce
cas), on les affiche en lignes avec retour à la ligne autorisée.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="k"&gt;media&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;min-width&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;40rem&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;blog-series&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;flex-direction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;row&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;flex-wrap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;wrap&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;justify-content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;blog-serie&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="kt"&gt;%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;margin-right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;.5&lt;/span&gt;&lt;span class="kt"&gt;%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;margin-left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;.5&lt;/span&gt;&lt;span class="kt"&gt;%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Ce qui donne donc :&lt;/p&gt;
&lt;p&gt;&lt;img alt="Capture d’écran de la page principale du blog où l’on voit les blocs des séries qui sont passés en lignes" src="images/site/v8-blog-grand-ecran.png" /&gt;&lt;/p&gt;
&lt;h2&gt;Mise en production imminente&lt;/h2&gt;
&lt;p&gt;Ayant suffisamment repoussé la mise en production jusque-là, j'envisage de le
faire dès la semaine prochaine même si je n’ai pas tout à fait fini le contenu
du site. Tout viendra en temps et en heure. J’ai pu tester que l’importation
des articles de l’ancien site se faisait sans soucis. À part quelques flux
&lt;abbr&gt;RSS&lt;/abbr&gt;, les liens ne devraient donc pas se casser.&lt;/p&gt;
&lt;p&gt;Vous pouvez donc supprimer ce site de votre agrégateur de flux &lt;abbr&gt;RSS&lt;/abbr&gt;
et repasser sur celui du &lt;a href="https://marienfressinaud.fr/"&gt;site initial&lt;/a&gt;, tous les
articles y seront transférés.&lt;/p&gt;</content></entry><entry><title>Construire un site complet à base de Boop!</title><id>urn:uuid:60ae50d1-5815-5b11-8f15-afe9a5f5ccc3</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/construire-un-site-complet-a-base-de-boop.html" rel="alternate" type="text/html" /><published>2019-02-26T09:30:00+01:00</published><updated>2019-02-26T09:30:00+01:00</updated><content type="html">&lt;p&gt;Après une petite pause d’un mois sur la refonte de ce site, il est temps pour
moi de m’y remettre. La dernière phase avait consisté à imaginer &lt;a href="demo-prochain-site/index.html"&gt;un
prototype&lt;/a&gt; pour me donner une vision globale de
l’architecture du site. Cela devait aussi me permettre de pointer du doigt les
manques de &lt;span lang="en"&gt;Boop!&lt;/span&gt;, mon générateur de sites statiques.
Et il y en avait, des manques ! Je reviendrai prochainement sur les évolutions
du contenu du site ainsi que sur son habillage (qui n’est d’ailleurs pas
terminé). Pour l’instant je vais me contenter de détailler les
dernières évolutions techniques.&lt;/p&gt;
&lt;h2&gt;Des améliorations dans le processus de développement&lt;/h2&gt;
&lt;p&gt;L’une des choses qui me tenait à cœur avec &lt;span lang="en"&gt;Boop!&lt;/span&gt; était
de pouvoir travailler de la manière la plus agréable possible sur mon site. Le
mieux dans cette situation étant de &lt;strong&gt;s’observer râler&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Premièrement, lors de la génération du site, je voulais pouvoir ouvrir
rapidement les fichiers générés. Comme la plupart du temps je travaille sur un
article, je veux pouvoir l’ouvrir immédiatement. J’ai donc &lt;a href="https://framagit.org/marienfressinaud/boop/commit/4732f1b50c48d68a6410966edf35fbfe3348e87c"&gt;fini&lt;/a&gt;
par afficher le nom des fichiers dans la console, et comme il s’agit de chemins
absolus commençant par &lt;code&gt;file://&lt;/code&gt;, je n’ai plus qu’à cliquer dessus pour ouvrir
mon article. Une exécution de &lt;span lang="en"&gt;Boop!&lt;/span&gt; ressemble
grosso-modo à ça :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;marien&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="n"&gt;pizza&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;marienfressinaud&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;boop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;development&lt;/span&gt;
&lt;span class="n"&gt;Written&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;///&lt;/span&gt;&lt;span class="n"&gt;home&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;marien&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;marienfressinaud&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;site&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;
&lt;span class="n"&gt;Written&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;///&lt;/span&gt;&lt;span class="n"&gt;home&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;marien&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;marienfressinaud&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;site&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;blog&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;
&lt;span class="n"&gt;Written&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;article&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;///&lt;/span&gt;&lt;span class="n"&gt;home&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;marien&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;marienfressinaud&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;site&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;construire&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;un&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;site&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;complet&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;de&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;boop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;
&lt;span class="n"&gt;Written&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;article&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;///&lt;/span&gt;&lt;span class="n"&gt;home&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;marien&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;marienfressinaud&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;site&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;suivre&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;le&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;boop&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;blog&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;
&lt;span class="n"&gt;Written&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;article&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;///&lt;/span&gt;&lt;span class="n"&gt;home&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;marien&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;marienfressinaud&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;site&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;simplifier&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;la&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;redaction&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;darticles&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;dans&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;boop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;
&lt;span class="n"&gt;Written&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;article&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;///&lt;/span&gt;&lt;span class="n"&gt;home&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;marien&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;marienfressinaud&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;site&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;boop&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;une&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;introduction&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;
&lt;span class="n"&gt;Written&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;feed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;///&lt;/span&gt;&lt;span class="n"&gt;home&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;marien&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;marienfressinaud&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;site&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;feeds&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;all&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;atom&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;xml&lt;/span&gt;
&lt;span class="n"&gt;Static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;files&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;copied&lt;/span&gt;
&lt;span class="n"&gt;Boop&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Ici vous ne pouvez évidemment pas cliquer sur les noms des fichiers, mais ça
fonctionne dans un terminal.&lt;/p&gt;
&lt;p&gt;À noter que lorsque je génère les fichiers pour la mise en production, ce sont
les &lt;abbr&gt;URL&lt;/abbr&gt; finales qui sont affichées (&lt;a href="https://framagit.org/marienfressinaud/boop/commit/0b0f035da29cca4d473322e8db5412ba3bcedbcd"&gt;voir le code&lt;/a&gt;),
ce qui me permet d’ouvrir l’article directement une fois en ligne.&lt;/p&gt;
&lt;p&gt;Le deuxième point agaçant était que je devais quitter mon éditeur de texte
régulièrement pour générer les fichiers et vérifier que le résultat me
convenait. Lors de la phase de relecture d’un article par exemple, je peux vouloir
regénérer le site plusieurs fois en quelques secondes : passer de la fenêtre de
mon éditeur à celle de mon terminal pour revenir de nouveau à l’éditeur est très
pénible. Utilisant Vim, j’ai ajouté deux raccourcis dans mon &lt;a href="https://framagit.org/marienfressinaud/dotfiles/blob/master/.vimrc#L285-290"&gt;&lt;code&gt;.vimrc&lt;/code&gt;&lt;/a&gt; :
l’un pour générer le site (&lt;code&gt;,,&lt;/code&gt;) et un autre pour publier le site en ligne (&lt;code&gt;,p&lt;/code&gt;).&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;autocmd &lt;span class="nb"&gt;BufRead&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nb"&gt;BufNewFile&lt;/span&gt; *&lt;span class="sr"&gt;/*marienfressinaud.fr/&lt;/span&gt;* &lt;span class="nb"&gt;nnoremap&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;leader&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;leader&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;!&lt;/span&gt;boop.&lt;span class="k"&gt;py&lt;/span&gt; &lt;span class="p"&gt;--&lt;/span&gt;development&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;CR&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
autocmd &lt;span class="nb"&gt;BufRead&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nb"&gt;BufNewFile&lt;/span&gt; *&lt;span class="sr"&gt;/*marienfressinaud.fr/&lt;/span&gt;* &lt;span class="nb"&gt;nnoremap&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;leader&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="k"&gt;p&lt;/span&gt; &lt;span class="k"&gt;make&lt;/span&gt; publish&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;CR&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Habituellement les générateurs de sites statiques proposent un serveur
surveillant les changements faits dans les fichiers et qui les regénère à la
volée… mais je trouvais cette solution bien compliquée pour un intérêt limité.
Cela me permet aussi de garder &lt;span lang="en"&gt;Boop!&lt;/span&gt; concentré sur une
seule tâche : générer un site statique.&lt;/p&gt;
&lt;p&gt;Enfin, notons que je dispose d’un fichier &lt;a href="https://framagit.org/marienfressinaud/marienfressinaud.fr/blob/master/Makefile"&gt;&lt;code&gt;Makefile&lt;/code&gt;&lt;/a&gt;
dans le répertoire du site qui me permet d’effectuer des tâches usuelles de
manière unifiée :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;make&lt;span class="w"&gt; &lt;/span&gt;boop&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;# génère le site en mode développement&lt;/span&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;make&lt;span class="w"&gt; &lt;/span&gt;publish&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# génère le site en mode production et le téléverse sur le serveur&lt;/span&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;make&lt;span class="w"&gt; &lt;/span&gt;clean&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="c1"&gt;# nettoie le répertoire `site`&lt;/span&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;make&lt;span class="w"&gt; &lt;/span&gt;open&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;# ouvre la page d&amp;#39;index du site dans le navigateur&lt;/span&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;make&lt;span class="w"&gt; &lt;/span&gt;tree&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;# affiche la structure des fichiers en excluant le répertoire `site`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;Une réécriture partielle de &lt;span lang="en"&gt;Boopsy&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;Si vous vous souvenez, &lt;span lang="en"&gt;Boopsy&lt;/span&gt; est mon système de
&lt;i lang="en"&gt;template&lt;/i&gt; maison. Jusque-là, il se contentait d’afficher des
variables au sein de fichiers &lt;abbr&gt;HTML&lt;/abbr&gt;. Cependant, j’ai très vite eu
besoin de pouvoir écrire des conditions (&lt;code&gt;if&lt;/code&gt;) et des boucles (&lt;code&gt;for&lt;/code&gt;). Ces
structures ont cela de particulier qu’elles ont un impact sur la portée des
variables. La boucle en particulier pose un problème, par exemple dans le cas
suivant :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nv"&gt;article&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nv"&gt;liste_articles&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
&lt;span class="x"&gt;    &amp;lt;div&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;article.title&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="x"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;endfor&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Avant d’entrer dans la boucle &lt;code&gt;for&lt;/code&gt;, la variable &lt;code&gt;article&lt;/code&gt; n’existe pas, il
faut donc gérer le contexte. &lt;a href="http://aosabook.org/en/500L/a-template-engine.html"&gt;L’article sur lequel je me base&lt;/a&gt;
depuis le début gère cela de manière relativement maline : il transforme le
&lt;i lang="en"&gt;template&lt;/i&gt; en mini-programme Python. Le &lt;code&gt;for&lt;/code&gt; est donc
transformé en syntaxe Python, ce qui permet de déléguer la gestion de la portée
des variables à l’interpréteur de ce dernier. J’avais fort justement décidé de
ne pas partir sur cette solution initialement (ne la comprenant pas, j’étais
allé au plus simple), et j’ai donc &lt;a href="https://framagit.org/marienfressinaud/boop/commit/b7bdd945f8dfbc071659be408039064fe308920e"&gt;réécrit&lt;/a&gt;
en partie ce que j’avais fait.&lt;/p&gt;
&lt;p&gt;Une fois ce travail fait, l’ajout du &lt;code&gt;if&lt;/code&gt; et du &lt;code&gt;for&lt;/code&gt; a ensuite été &lt;a href="https://framagit.org/marienfressinaud/boop/commit/faca81998a3a3bba91f4c7b95f6da3332da6a8ee"&gt;très facile&lt;/a&gt;
vu que je n’avais plus qu’à traduire le code récupéré depuis le &lt;i lang="en"&gt;template&lt;/i&gt;
en code Python.&lt;/p&gt;
&lt;h2&gt;L’apparition des pages…&lt;/h2&gt;
&lt;p&gt;J’en avais besoin pour avancer : les pages ont été &lt;a href="https://framagit.org/marienfressinaud/boop/commit/fa2f5f473f9aa46895f3ec3b3971c8e8ebc33e41"&gt;ajoutées&lt;/a&gt;
très rapidement après mon dernier article. Jusque-là, je ne pouvais avoir
qu’une unique page (d’accueil) et des articles. Pourtant, les pages statiques
sont bien pratiques pour donner des informations « intemporelles ».&lt;/p&gt;
&lt;p&gt;Contrairement aux articles, les pages sont écrites exclusivement en &lt;abbr&gt;HTML&lt;/abbr&gt;
et se trouvent dans un répertoire qui se nomme… &lt;code&gt;pages&lt;/code&gt;. Elles peuvent partager
elles-aussi un &lt;i lang="en"&gt;template&lt;/i&gt; commun (&lt;a href="https://framagit.org/marienfressinaud/boop/commit/6f6d63c9ce31b6166f0abfff09fa2bb9b746057b"&gt;voir le code&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Le problème auquel j’ai alors fait face a été de pouvoir définir des variables
dans les pages pour pouvoir les utiliser dans le &lt;i lang="en"&gt;template&lt;/i&gt;. En
effet, le &lt;abbr&gt;HTML&lt;/abbr&gt; ne permet pas de définir de variables. Je &lt;a href="https://framagit.org/marienfressinaud/boop/commit/81ff584af1ec4e60be67efa02ca887718eaa4fee"&gt;suis
donc parti&lt;/a&gt;
sur la solution utilisée par &lt;a href="https://jekyllrb.com/docs/step-by-step/03-front-matter/"&gt;Jekyll&lt;/a&gt;,
celle d’accepter un en-tête &lt;abbr&gt;YAML&lt;/abbr&gt; en haut des fichiers
&lt;abbr&gt;HTML&lt;/abbr&gt;. Je trouvais cette solution d’autant plus élégante qu’au
final il s’agissait de la même façon de faire dans les fichiers &lt;span lang="en"&gt;Markdown&lt;/span&gt;.&lt;/p&gt;
&lt;h2&gt;… d’une page de blog…&lt;/h2&gt;
&lt;p&gt;Une fois tout cela en place, je n’avais plus grand chose à faire pour avoir le
site de mes rêves. Une chose toutefois continuait de m’embêter : je devais
lister les articles à la main, un par un, manuellement sur une page de blog.&lt;/p&gt;
&lt;p&gt;Disposant désormais de tout ce qu’il me fallait pour construire une liste
d’articles automatiquement, il m’a fallu très peu de temps pour &lt;a href="https://framagit.org/marienfressinaud/boop/commit/bc9410d0f9b97c8f5178be4265687b1f5b45b876"&gt;ajouter&lt;/a&gt;
une page de blog générée par &lt;span lang="en"&gt;Boop!&lt;/span&gt;.&lt;/p&gt;
&lt;h2&gt;… et des séries.&lt;/h2&gt;
&lt;p&gt;La dernière fonctionnalité que j’ai &lt;a href="https://framagit.org/marienfressinaud/boop/commit/694c4e3fb7ae380aa69195d1127b06f04d496f45"&gt;développée&lt;/a&gt;
a été celle des « séries ». Une série est une sorte de catégorie regroupant une
liste d’articles. La différence avec le système de catégories que l’on peut
retrouver ailleurs est que la série liste les articles dans un ordre décidé par
l’auteur. C’est-à-dire, dans mon cas actuel, du plus ancien au plus récent
(l’inverse donc de la page de blog). Mais on pourrait imaginer que cet ordre
soit encore différent ; c’est à l’auteur de voir ce qu’il préfère.&lt;/p&gt;
&lt;p&gt;La conséquence de cela est que les liens vers les articles sont aujourd’hui à
faire manuellement sur les pages des séries (c’est dommage alors que je viens
de vanter les mérites de l’automatisation dans la partie d’avant). J’envisage
toutefois un système un peu plus sympathique à terme, sans perdre pour autant
en flexibilité.&lt;/p&gt;
&lt;p&gt;Une série dispose aussi d’un flux Atom spécifique, de la même manière que les
catégories dans &lt;a href="https://blog.getpelican.com/"&gt;Pelican&lt;/a&gt;. Je sais qu’ils étaient
utilisés sur mon ancien site (pour Lessy notamment), je voulais donc retrouver
ce système sur le nouveau. Dans le flux, les articles continuent par contre
d’être listés du plus récent au plus ancien.&lt;/p&gt;
&lt;p&gt;Une série est créée en regroupant des articles dans un répertoire et en créant
une page nommée &lt;code&gt;serie.html&lt;/code&gt; dans ce répertoire (&lt;a href="https://framagit.org/marienfressinaud/marienfressinaud.fr/tree/master/articles/le-boop-blog"&gt;voir l’exemple du « &lt;span lang="en"&gt;Boop!
blog&lt;/span&gt; »&lt;/a&gt;).&lt;/p&gt;
&lt;h2&gt;Et une grosse réorganisation du code&lt;/h2&gt;
&lt;p&gt;Vous vous doutez que tous ces changements ont apporté leur lot de &lt;a href="https://fr.wikipedia.org/wiki/Dette_technique"&gt;dette
technique&lt;/a&gt; et le fichier presque
unique qui contenait le code de &lt;span lang="en"&gt;Boop!&lt;/span&gt; commençait à
devenir hors de contrôle (500 lignes de code dont 220 pour la seule fonction
principale). Il était grand temps de faire quelque chose, mais pas n’importe
comment.&lt;/p&gt;
&lt;p&gt;Une chose que je n’aime pas quand je lis le code d’une autre personne, c’est
lorsqu’il y a des indirections dans tous les sens et que je dois ouvrir 5
fichiers pour comprendre ce qu’il se passe. Dans mon cas, je voulais que &lt;a href="https://framagit.org/marienfressinaud/boop/blob/9b59566f0bba0a4dafa6a522a8641c703803f455/boop.py#L32"&gt;le
fichier principal&lt;/a&gt;
contienne l’ensemble de la logique métier, c’est-à-dire :&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;chargement de la configuration du site ;&lt;/li&gt;
&lt;li&gt;collecte de l’ensemble des articles et des pages ;&lt;/li&gt;
&lt;li&gt;écriture des articles et des pages ;&lt;/li&gt;
&lt;li&gt;écriture des flux Atom (le principal ainsi que ceux des séries) ;&lt;/li&gt;
&lt;li&gt;copie des fichiers contenus dans &lt;code&gt;static&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Ensuite, les fonctions qui ne revêtent pas un caractère important dans la
logique métier sont extraites vers un fichier &lt;a href="https://framagit.org/marienfressinaud/boop/blob/9b59566f0bba0a4dafa6a522a8641c703803f455/boop/utils.py"&gt;&lt;code&gt;utils.py&lt;/code&gt;&lt;/a&gt;.
Ce fichier apporte néanmoins des informations importantes quant au
fonctionnement de &lt;span lang="en"&gt;Boop!&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://framagit.org/marienfressinaud/boop/tree/9b59566f0bba0a4dafa6a522a8641c703803f455/boop"&gt;Les derniers fichiers&lt;/a&gt;
quant à eux contiennent quelques classes utiles au fonctionnement, notamment
&lt;code&gt;Article&lt;/code&gt;, &lt;code&gt;Page&lt;/code&gt; et &lt;code&gt;Feed&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Pour les plus curieuses et curieux d’entre vous, vous pouvez retrouver les
différents &lt;i lang="en"&gt;commits&lt;/i&gt; de cette réorganisation de code de cette
manière :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gp"&gt;$ &lt;/span&gt;git&lt;span class="w"&gt; &lt;/span&gt;clone&lt;span class="w"&gt; &lt;/span&gt;git@framagit.org:marienfressinaud/boop.git&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;boop
&lt;span class="gp"&gt;$ &lt;/span&gt;git&lt;span class="w"&gt; &lt;/span&gt;log&lt;span class="w"&gt; &lt;/span&gt;--reverse&lt;span class="w"&gt; &lt;/span&gt;--oneline&lt;span class="w"&gt; &lt;/span&gt;694c4e3f..7bfac8f4
&lt;span class="go"&gt;e3c382a Move extension filtering in utility functions&lt;/span&gt;
&lt;span class="go"&gt;9a2c645 Extract function to build an article from filepath&lt;/span&gt;
&lt;span class="go"&gt;...&lt;/span&gt;
&lt;span class="go"&gt;7bfac8f Refactor feeds generation&lt;/span&gt;
&lt;span class="gp"&gt;$ &lt;/span&gt;git&lt;span class="w"&gt; &lt;/span&gt;show&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;le&lt;span class="w"&gt; &lt;/span&gt;commit&lt;span class="w"&gt; &lt;/span&gt;que&lt;span class="w"&gt; &lt;/span&gt;vous&lt;span class="w"&gt; &lt;/span&gt;voulez&lt;span class="w"&gt; &lt;/span&gt;voir&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Je pense toutefois que l’intérêt reste limité, mais c’est vous qui voyez si ça
vous intéresse.&lt;/p&gt;
&lt;h2&gt;Un outil taillé au poil&lt;/h2&gt;
&lt;p&gt;&lt;span lang="en"&gt;Boop!&lt;/span&gt; a cela de bien qu’il fait très exactement ce dont
j’ai besoin : pas une fonctionnalité n’est superflue. Et s’il manque très
certainement des choses, &lt;strong&gt;ce sont pour d’autres besoins que les miens&lt;/strong&gt;.
Alors, oui, ça m’a pris un certain temps à développer ; je ne conseille
évidemment pas à tout le monde de développer son propre générateur de sites
statiques. Il y avait avant tout une visée pédagogique dans ma démarche, en
montrant comment en partant de zéro on peut concevoir un outil qui fonctionne
tout aussi bien qu’un « plus connu ». J’ai d’ailleurs pris le soin au fur et à
mesure de l’article (&lt;a href="serie/le-boop-blog.html"&gt;ainsi que des précédents&lt;/a&gt;)
d’ajouter des liens vers les &lt;i lang="en"&gt;commits&lt;/i&gt; correspondants à ce dont
je parlais, pour comprendre « comment j’ai fait ». Je voulais aussi montrer
qu’en restant le plus simple possible, on obtient une meilleure maîtrise sur
l’outil et on peut le faire évoluer plus facilement. &lt;strong&gt;On favorise ainsi &lt;a href="https://fr.wikipedia.org/wiki/Logiciel_libre#D%C3%A9finition_de_la_Free_Software_Foundation_(FSF)"&gt;la
liberté 1 du logiciel libre&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;span lang="en"&gt;Boop!&lt;/span&gt; n’est pas pour autant totalement terminé. Il me
reste à l’utiliser régulièrement sur une longue période de temps, comprendre là
où ça bloque, fluidifier mon processus de travail, fignoler les morceaux de
code toujours pas très élégants, améliorer la documentation que je n’ai jamais
pris le temps de structurer correctement… Cela pourrait presque être comparé à
du travail d’orfèvre à ce niveau de précision, mais j’aime être pointilleux
quand je peux me le permettre. Et je peux.&lt;/p&gt;</content></entry><entry><title>Introspection professionnelle : communication et site</title><id>urn:uuid:5ef7221c-31be-5890-aab8-4e83ff6059ae</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/introspection-professionnelle-communication-et-site.html" rel="alternate" type="text/html" /><published>2019-01-11T11:45:00+01:00</published><updated>2019-01-11T11:45:00+01:00</updated><content type="html">&lt;p&gt;Pour ce dernier article de mon « introspection professionnelle », je vais
aborder le sujet de la communication et dessiner une esquisse de ce que sera
l’architecture du site. Pour rappel, &lt;a href="introspection-professionnelle-valeurs-et-raison-detre.html"&gt;le premier article&lt;/a&gt;
définissait mes valeurs et ma raison d’être, tandis que &lt;a href="introspection-professionnelle-competences-et-objectif.html"&gt;le second&lt;/a&gt;
décrivait les compétences que je souhaite appliquer dans mon futur métier ainsi
que l’objectif que je me fixe.&lt;/p&gt;
&lt;p&gt;Les choses commencent doucement à se clarifier pour moi, ce troisième article
aborde enfin la phase concrète de la démarche et &lt;strong&gt;les premiers traits du site
seront tirés dans la dernière partie&lt;/strong&gt;. J’ignore encore qu’elles seront les
missions sur lesquelles je serai amené à travailler, mais l’accueil qui a été
réservé à mes deux premiers articles me conforte dans la voie que j’ai commencé
à emprunter.&lt;/p&gt;
&lt;h2&gt;Différents supports pour communiquer&lt;/h2&gt;
&lt;p&gt;J’ai commencé à me poser la question du support de communication lorsque j’ai
réalisé la diversité des médias que j’utilisais jusque-là : mon site
évidemment, Twitter, Mastodon, Diaspora* (plus trop maintenant), mais aussi
GitHub, sans compter les différents blogs ou espaces où j’ai été amené à écrire
au compte-goutte. Je me posais régulièrement la question de quelle information
devait être partagée où et sur quel ton. Il est grand temps de remettre tout
cela à plat.&lt;/p&gt;
&lt;p&gt;Pour commencer, parlons de ce dont je ne veux plus avoir à m’occuper : GitHub
et Gitlab, et en particulier du premier. Il s’agit là de forges logicielles,
c’est-à-dire d’espaces où l’on dépose du code source, agrémentés d’outils pour
contribuer à ce code (notamment un &lt;span lang="en"&gt;&lt;em&gt;bugtracker&lt;/em&gt;&lt;/span&gt; ainsi
qu’un système de &lt;span lang="en"&gt;&lt;em&gt;pull requests&lt;/em&gt;&lt;/span&gt; permettant de proposer
des modifications du code). Mais ce n’est pas tout : GitHub en particulier
n’est pas une simple forge, ce qui en fait sa force se trouve aussi dans ses
aspects communautaires. On y met en avant les projets sur lesquels on
travaille, notre activité quantifiée sous forme de beaux diagrammes et on peut
même suivre ou être suivi par d’autres développeurs et développeuses pour voir
ce qu’ils font. Gitlab est sans doute légèrement moins orienté vers cela, mais
intègre tout de même certains de ces méchanismes. Le défaut de ces deux
plateformes, c’est qu’elles sont orientées exclusivement vers le code, vers la
technique. Si vous avez suivi mes articles précédents, vous aurez compris que
cela m’intéresse assez peu au final. Quantifier le nombre de lignes de code ou
de tickets que j’ai ouverts ne m’intéresse pas, cela flatte tout juste l’égo
lorsque l’on est « productif ». Utiliser GitHub ou Gitlab pour communiquer
m’apparaît donc comme &lt;strong&gt;trop restrictif et orienté vers un but qui n’est pas le
mien&lt;/strong&gt;. Je ferai donc désormais le minimum pour maintenir mes profils à jour
sur ces plateformes.&lt;/p&gt;
&lt;p&gt;Ensuite, le couple Twitter / Mastodon est légèrement plus compliqué. Ces deux
médias sociaux se ressemblent énormément dans leur mode de fonctionnement
(c’est-à-dire le partage de courts messages instantanés). Toutefois, Mastodon
possède une communauté plus petite et plus ouverte où l’on trouve des personnes
avec qui échanger de façon plus proche. Twitter me fait l’impression d’une
population très (trop ?) hétérogène, où n’importe qui peut s’immiscer dans une
conversation dans laquelle il n’est pas le ou la bienvenu·e (et s’y accrocher
en plus, le bougre !) Dans les deux cas, l’argumentation est compliquée de part
la limite du nombre de caractères dans les messages (280 sur Twitter, 500 sur
Mastodon), alors &lt;strong&gt;autant privilégier la plateforme qui offre le cadre le plus
accueillant pour échanger&lt;/strong&gt;. Par conséquent, j’utiliserai Mastodon pour
partager des choses professionnelles et plus personnelles. Je conserverai
toutefois mon compte Twitter pour partager des choses exclusivement
professionnelles et pour continuer ma veille de l’actualité. Quant à mon compte
Diaspora* qui est à l’abandon depuis un moment, il risque de disparaître pour
de bon un de ces jours.&lt;/p&gt;
&lt;p&gt;Le dernier support de communication d’importance que je souhaite utiliser est
bien entendu mon site Internet. Je le souhaite au centre de mes partages, en
espérant écrire plus qu’auparavant (la fin de l’année 2018 m’a montré que j’en
étais capable). Je détaille plus en détails comment j’imagine mon site dans la
dernière partie de cet article.&lt;/p&gt;
&lt;h2&gt;Les petits à-côtés de la communication&lt;/h2&gt;
&lt;p&gt;En travaillant les supports de communication, quelques éléments sont ressortis
que je n’ai pas encore traités.&lt;/p&gt;
&lt;p&gt;En premier lieu, le &lt;abbr&gt;CV&lt;/abbr&gt; est un support que je trouve intéressant.
Il est surtout utilisé pour postuler en tant que salarié, mais aussi pour faire
de la prestation chez des clients. J’aime bien y jeter un coup d’œil pour
savoir comment les gens se présentent de manière succincte. D’un point de vue
plus personnel, je trouve qu’il s’agit d’un exercice de synthèse assez
intéressant et j’aime bien me limiter à une page &lt;abbr&gt;A4&lt;/abbr&gt; bien
qu’aujourd’hui j’aurais sans doute matière à déborder un peu. Il ne s’agit
toutefois pas d’un besoin urgent, bien que je m’y pencherai sans doute avec
intérêt d’ici quelques mois.&lt;/p&gt;
&lt;p&gt;Un autre sujet facultatif dans l’immédiat est celui des cartes de visite. Je
vais sans doute rencontrer des gens qui chercheront à me contacter et la carte
est dans ces cas-là intéressante pour donner les informations essentielles.
Je devrais toutefois être capable de découper un bout de papier dans un coin de
nappe et y écrire mon nom ainsi qu’une adresse courriel. Il manquera l’aspect
« objet à collectionner », mais je suis persuadé que les gens sauront s’en
passer. La fin du monde &lt;a href="https://fr.wikipedia.org/wiki/Th%C3%A9ories_sur_les_risques_d%27effondrement_de_la_civilisation_industrielle"&gt;est pour demain&lt;/a&gt;
après tout.&lt;/p&gt;
&lt;p&gt;En parlant d’adresse courriel, se pose la question du moyen de me contacter. Je
ne privilégie pas Twitter et je risque d’oublier des choses si les gens me
contactent par Mastodon. De plus, j’aime centraliser ma correspondance, et le
courriel est idéal pour cela. Ainsi, je compte mettre en évidence sur mon site
une adresse unique pour me contacter. Certains préfèrent passer par un
formulaire pour éviter que des personnes ne récupèrent leur adresse et limiter
ainsi le spam, mais la mienne traîne déjà depuis plusieurs années sur mon site
et j’arrive à peu près à limiter le spam. Je me suis aussi posé la question de
proposer un numéro de téléphone, à Sogilis cela était fait car certains clients
appellent plus volontiers qu’ils ne rédigent un courriel. Le téléphone est
toutefois pour moi un élément relativement intrusif de par la présence physique
qu’il requiert et je le réserve à un cadre privé.&lt;/p&gt;
&lt;p&gt;Enfin, le dernier sujet que je souhaitais aborder est la photo de profil. Si je
ne compte pas en mettre une en évidence sur le site, j’apprécie toujours de
pouvoir me faire une idée du visage d’une personne avant de la rencontrer, ne
serait-ce que pour la reconnaître plus facilement. La photo que j’utilise
aujourd’hui commence à dater un petit peu, et les personnes qui m’ont croisé
récement seront sans doute d’accord pour dire qu’elle n’est plus vraiment au
goût du jour. J’ai vu à plusieurs reprises le conseil de passer par un
photographe professionnel, mais je vais encore laisser le sujet de côté
quelques semaines avant de me décider sur ce que je fais.&lt;/p&gt;
&lt;h2&gt;L’architecture du site, pour me représenter&lt;/h2&gt;
&lt;p&gt;Mon futur site aura deux objectifs : me servir de vitrine professionnelle (et
donc me présenter) et à partager ce sur quoi je travaille. La structure de base
de la page d’accueil que j’envisage n’a rien de très originale :&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;présentation en une phrase de &lt;strong&gt;qui je suis&lt;/strong&gt;, ainsi que mise en avant de
   &lt;strong&gt;mon objectif&lt;/strong&gt; ;&lt;/li&gt;
&lt;li&gt;énumération de &lt;strong&gt;mes compétences&lt;/strong&gt; pour indiquer sur quoi je peux travailler
   et comment ;&lt;/li&gt;
&lt;li&gt;présentation de &lt;strong&gt;mon manifeste&lt;/strong&gt; pour mettre en évidence mes valeurs et
   préciser que je ne travaille pas sur n’importe quoi ;&lt;/li&gt;
&lt;li&gt;indication de &lt;strong&gt;mon adresse courriel&lt;/strong&gt; ainsi que &lt;strong&gt;les médias sociaux&lt;/strong&gt; sur
   lesquels on peut me trouver ;&lt;/li&gt;
&lt;li&gt;enumération &lt;strong&gt;des projets&lt;/strong&gt; sur lesquels j’ai travaillé et que je souhaite
   mettre en avant (limités à environ 5) ;&lt;/li&gt;
&lt;li&gt;enfin, un pied de page pour servir de rappel (liens vers les différentes
   pages du site, rappel des informations de contact, etc.)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Il existera des pages supplémentaires pour détailler certaines parties,
notamment mes compétences et mon manifeste (qu’il me reste à écrire !)
J’intégrerai aussi au niveau de la liste des projets, un lien amenenant vers ma
page « &lt;a href="https://marienfressinaud.fr/now.html"&gt;&lt;span lang="en"&gt;now&lt;/span&gt;&lt;/a&gt; » que
je tiens à jour pour indiquer ce sur quoi je travaille en ce moment.&lt;/p&gt;
&lt;p&gt;J’aimerais limiter le nombre de liens dans la barre de navigation en haut de la
page, et je me contenterais d’ailleurs bien d’un simple lien vers le blog. Au
passage, j’essayerai d’effacer la frontière qui peut exister habituellement
entre la partie site et le blog. Il paraîtrait en effet logique qu’un lien
partant de la liste des projets amène vers une série d’articles liée à un
projet en particulier. La page de blog en elle-même se contenterait de
présenter la liste complète des articles, mais deviendrait optionnelle pour
accéder aux articles. Je souhaite de ce fait les placer dans leur contexte.&lt;/p&gt;
&lt;p&gt;Afin d’illustrer ce vers quoi je veux tendre, &lt;strong&gt;j’ai créé &lt;a href="demo-prochain-site/index.html"&gt;une page de
démonstration&lt;/a&gt;&lt;/strong&gt; relativement complète. Avec
cela, j’ai déjà une bonne base de travail pour avancer rapidement. Il me reste
encore pas mal de contenu à écrire et &lt;a href="https://framagit.org/marienfressinaud/boop"&gt;&lt;span lang="en"&gt;Boop!&lt;/span&gt;&lt;/a&gt;,
mon générateur de sites statiques, va encore devoir évoluer un peu, mais je
peux dorénavant envisager une mise en ligne à la fin du mois.&lt;/p&gt;</content></entry><entry><title>Introspection professionnelle : compétences et objectif</title><id>urn:uuid:9502ede6-90e6-5537-8c59-35d719e50768</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/introspection-professionnelle-competences-et-objectif.html" rel="alternate" type="text/html" /><published>2019-01-02T15:15:00+01:00</published><updated>2019-01-02T15:15:00+01:00</updated><content type="html">&lt;p&gt;En 2019, je change de vie professionnelle. Afin d’accompagner ce changement, je
souhaitais entreprendre la refonte de mon site pour qu’il mette mieux en avant
mes aspirations. Dans &lt;a href="introspection-professionnelle-valeurs-et-raison-detre.html"&gt;mon précédent article&lt;/a&gt;,
j’ai décrit mes valeurs et ma raison d’être (c’est-à-dire ce qui me motive au
quotidien), à travers une démarche d’introspection professionnelle. Pour
rappel, les différentes étapes que je prévois dans le cadre de cette démarche
sont :&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;définition de &lt;strong&gt;mes valeurs&lt;/strong&gt; ;&lt;/li&gt;
&lt;li&gt;définition de &lt;strong&gt;ma raison d’être&lt;/strong&gt; ;&lt;/li&gt;
&lt;li&gt;définition de &lt;strong&gt;mes compétences&lt;/strong&gt; ;&lt;/li&gt;
&lt;li&gt;établissement d’&lt;strong&gt;un objectif&lt;/strong&gt; personnel ;&lt;/li&gt;
&lt;li&gt;définition de mes moyens de &lt;strong&gt;communication&lt;/strong&gt; ;&lt;/li&gt;
&lt;li&gt;conception de &lt;strong&gt;l’architecture du site&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Les deux premiers points ont donc été détaillés dans le précédent article, je
vais désormais aborder les deux points suivants, à savoir mes compétences et
mon objectif personnel afin d’étudier comment je compte mettre en œuvre ma
raison d’être. Dis autrement, je vois mes compétences comme des outils à mon
service pour atteindre un objectif qui saura satisfaire ma raison d’être et mes
valeurs.&lt;/p&gt;
&lt;p&gt;Aujourd’hui mes compétences sont essentiellement techniques, orientées
spécifiquement dans le développement web. À ce niveau-là, je suis plutôt
polyvalent et capable d’apprendre assez aisément. Ce qui m’importe toutefois
aujourd’hui concerne plutôt le champ de compétences que je &lt;strong&gt;souhaite&lt;/strong&gt; être
capable de couvrir en totale autonomie. J’ai relevé trois points principaux
(vous remarquerez que j’aime bien ce chiffre !) ainsi que quatre transversaux
pour arriver à &lt;strong&gt;un total de sept compétences que je pourrai mettre en œuvre au
sein d’un projet&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;Des compétences fondamentales pour définir mon métier&lt;/h2&gt;
&lt;p&gt;Tout d’abord, je souhaite monter en compétences dans le domaine de
&lt;strong&gt;l’acquisition des besoins métiers orientés utilisateurs&lt;/strong&gt;. Je pense que c’est
une démarche saine que de d’abord chercher à comprendre les enjeux d’un métier
et en mesurer sa complexité avant de développer une solution logicielle. Cela
permet notamment d’être force de propositions pertinentes. J’ai par ailleurs
trop souvent vu des clients qui fonçaient bille en tête avec une idée bien
définie, sans questionner les usages des autres utilisateurs et utilisatrices.
J’ai dans ces moments-là eu l’impression de ne développer que pour une personne
et que l’outil ne serait jamais pleinement utilisé ou adopté. Je crois que ce
n’est pas une démarche toujours évidente que de questionner un client sur ce
qu’il a muri en lui-même, en particulier en tant que développeur, et de lui
faire comprendre que &lt;strong&gt;sa solution n’est pas forcément la meilleure pour tout
le monde&lt;/strong&gt;. Il sera essentiel que je sache établir une confiance quant à ma
capacité à comprendre le métier.&lt;/p&gt;
&lt;p&gt;Ensuite, la deuxième compétence que je saurai mettre en pratique au sein d’un
projet est celle du &lt;strong&gt;développement logiciel&lt;/strong&gt;. Comme je le disais plus haut,
il s’agit d’un domaine où je suis polyvalent et capable d’apprendre ; c’est le
cœur de mon expertise aujourd’hui. Je suis à l’aise à la fois en &lt;span lang="en"&gt;frontend&lt;/span&gt;
comme en &lt;span lang="en"&gt;backend&lt;/span&gt;. Je connais un certain nombre de bonnes
pratiques en matière de déploiement automatisé/continu et connais relativement
bien les problèmes qui peuvent se poser aux administrateurs système. J’essaye
notamment de mettre en pratique les recommandations de la méthodologie
« &lt;a href="https://12factor.net/"&gt;&lt;span lang="en"&gt;The Twelve-Factor App&lt;/span&gt;&lt;/a&gt; ».
Ainsi, lorsque je développe une fonctionnalité, je pense à ce qu’elle deviendra
une fois en production. Dans cette optique, j’essaye aussi de faire en sorte
que ce que je développe arrive le plus rapidement possible en production afin
d’éviter un décalage trop important entre mon code et la base initiale. En
terme de langages, cela a relativement peu d’importance pour moi vu que je suis
capable d’apprendre si la situation le demande. J’ai toutefois plus
d’expérience en Ruby (très orienté Ruby on Rails), Python, JavaScript et PHP.
Il s’agit là de compétences que &lt;strong&gt;je maîtrise suffisamment pour être autonome
sur un projet sans aucun soucis&lt;/strong&gt;. Bien entendu, mon code s’accompagne de tests
et je fonctionne souvent en &lt;abbr&gt;TDD&lt;/abbr&gt; (pour &lt;a href="https://fr.wikipedia.org/wiki/Test_driven_development"&gt;&lt;span lang="en"&gt;&lt;em&gt;Test-Driven
Development&lt;/em&gt;&lt;/span&gt;&lt;/a&gt;).
Par ailleurs, j’ai un attachement particulier aux logiciels simples, qui ne
cherchent pas à faire trop de choses et dont on peut fouiller le code pour y
trouver rapidement ce que l’on cherche.&lt;/p&gt;
&lt;p&gt;Enfin, la dernière compétence fondamentale que j’aimerais mettre en application
au sein des projets où j’aurai à intervenir porte sur &lt;strong&gt;l’accompagnement à la
mise en place d’une méthodologie documentaire&lt;/strong&gt;. J’en parlais lorsque je
détaillais mes valeurs, la transmission des connaissances est primordiale pour
qu’un groupe ne dépende pas de quelques personnes clés. Je crois qu’il y a
aujourd’hui un manque énorme de culture écrite dans nos modes de fonctionnement
(je l’ai retrouvé à différents niveaux professionnel et associatif) ou alors
cette culture n’est pas orientée vers le partage et la conservation des
connaissances. C’est un sujet que j’ai commencé à toucher du doigt et sur
lequel j’aimerais véritablement progresser. Et pour progresser, rien de tel que
de pratiquer. Les wikis et les blogs sont pour moi deux outils très puissants
dans cette recherche du partage mais qui ont le défaut de figer la connaissance
à un instant T. J’aimerais étudier &lt;strong&gt;des modes de fonctionnement qui font vivre
cette connaissance&lt;/strong&gt;, qui lui permettent véritablement d’évoluer dans le temps
et qui replacent la documentation au centre des préoccupations.&lt;/p&gt;
&lt;h2&gt;Des compétences transverses, au bénéfice des projets&lt;/h2&gt;
&lt;p&gt;En plus des trois compétences fondamentales listées au-dessus et qui forment un
tout dans la vie d’un projet, j’ai voulu ajouter quatre compétences que je
peux appliquer de façon générale sur tout type de projet.&lt;/p&gt;
&lt;p&gt;Tout d’abord, &lt;strong&gt;une communication que je décrirais de transparente&lt;/strong&gt;. Je
parlais plus haut de confiance à établir avec les client·es, cela passe avant
tout par la communication (écrite comme orale). Il est notamment important de
ne pas cacher des éléments dont on pourrait avoir « honte ». Par exemple, la
production est tombée, on l’a réparée en catimini sans que la cliente n’en
sache rien mais on la tient quand même informée de ce qu’il s’est passé, par
transparence. Savoir communiquer peut notamment servir à désamorcer des sujets
qui pourraient être tabous et donc dangereux dans la vie d’un projet. Afin de
communiquer de façon efficace, j’essaye de me placer tout d’abord dans une
position d’écoute. Cette position me sert à comprendre mon interloteur ou
interlocutrice, comprendre comment il ou elle intéragit avec moi, quel degré de
familiarité je peux me permettre, si elle est sensible à mon argumentaire ou
s’il est plutôt fermé à des approches différentes. Ce n’est pas toujours chose
aisée, mais &lt;strong&gt;en exprimant aussi ce que l’on ressent, en partageant les doutes
qui peuvent surgir en nous&lt;/strong&gt;, on arrive à poser un terrain propice à la
collaboration.&lt;/p&gt;
&lt;p&gt;La deuxième compétence dont je pense pouvoir tirer partie est ma capacité à
&lt;strong&gt;rendre compte de façon claire et argumentée&lt;/strong&gt; un travail que j’ai produit.
Que ce soit à l’oral ou à l’écrit, j’essaye toujours de me rendre
compréhensible et je n’hésite pas à reformuler si je sens que je ne suis pas
clair. Cela peut toutefois me demander un certain temps de préparation pour me
laisser le temps de répéter ou de me relire au minimum deux à trois fois. Je
suis par ailleurs très attaché à la pratique de la langue française et j’aime
jouer sur les nuances que peuvent porter des mots ou la construction d’une
phrase. Cela peut paraître anecdotique vis-à-vis d’autres compétences, mais
j’ai réalisé il y a peu que le fait de &lt;strong&gt;savoir exprimer correctement ses
idées&lt;/strong&gt; joue un rôle très important dans la façon dont on est perçu par les
autres. Cela affecte notre capacité à convaincre et à être suivi.&lt;/p&gt;
&lt;p&gt;Ensuite, &lt;strong&gt;la gestion de projet&lt;/strong&gt; intervient à tout les instants d’un projet.
Afin d’être efficaces, il me semble que &lt;a href="https://fr.wikipedia.org/wiki/M%C3%A9thode_agile"&gt;les méthodes agiles&lt;/a&gt;
sont idéales. Je n’ai commencé à pratiquer qu’en arrivant au sein de Sogilis où
j’ai pratiqué un mélange de &lt;a href="https://fr.wikipedia.org/wiki/Scrum_(d%C3%A9veloppement)"&gt;&lt;span lang="en"&gt;Scrum&lt;/span&gt;&lt;/a&gt;
et d’&lt;a href="https://fr.wikipedia.org/wiki/Extreme_programming"&gt;&lt;span lang="en"&gt;Extreme programming&lt;/span&gt;&lt;/a&gt;,
mais j’ai très rapidement saisi un certain nombre d’avantages que ces pratiques
offraient. Ce que j’en retire avant tout, c’est le fait de partir du constat
que nos méthodes de travail ne fonctionneront pas parfaitement au démarrage
d’un projet, et donc d’intégrer dans le processus de travail les outils qui
permettront d’améliorer et corriger le processus lui-même, en cours de route.
De plus, et cela rejoint mon premier point, la communication est placée au
centre des préoccupations ce qui permet une bonne compréhension des enjeux par
tout le monde et facilite la détection des problèmes qui ne manquent pas
d’arriver au fil de l’eau. &lt;strong&gt;Les méthodes agiles offrent donc un cadre sain et
malléable&lt;/strong&gt; pour gérer et faire vivre un projet, elles seront donc au cœur de
ma façon de travailler.&lt;/p&gt;
&lt;p&gt;Enfin, le dernier point que je souhaitais aborder est &lt;strong&gt;l’intégration aux
équipes&lt;/strong&gt;. Il est pour moi important de faire partie d’une équipe et de ne pas
travailler dans mon coin. Cela aide à mieux communiquer (encore !), à partager
les connaissances pour ne pas devenir indispensable et à améliorer la qualité
du produit final. La confrontation des points de vue sur un sujet donné, un
bout de code par exemple, aide à &lt;strong&gt;penser un problème sous différents angles et
prendre du recul sur ce que l’on fait&lt;/strong&gt;. Je n’ai quasiment jamais travaillé ces
trois dernières années tout seul sur un projet, et même sur &lt;a href="https://lessy.yuzu.ovh"&gt;Lessy&lt;/a&gt;
qui reste un projet très personnel, j’ai eu à cœur de demander conseil autour
de moi. Je pense être capable de m’intégrer facilement à une équipe, mais cela
dépend aussi beaucoup des personnalités au sein de l’équipe ; je ne saurais
donc en faire une règle absolue.&lt;/p&gt;
&lt;h2&gt;Un objectif au service de ma raison d’être&lt;/h2&gt;
&lt;p&gt;Arrive donc le moment où je dois résumer les quelques 3 200 mots de mes deux
articles abordant mon introspection professionnelle ainsi qu’un an de
réflexions plus ou moins poussées, en une phrase d’accroche qui définira la
façon dont je veux aborder mon travail durant les prochains mois et/ou
prochaines années.&lt;/p&gt;
&lt;p&gt;Après plusieurs reformulations, je suis arrivé à déterminer un objectif qui me
convient plutôt bien :&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;J’accompagne les humain·es de &lt;strong&gt;notre société de demain&lt;/strong&gt; dans une démarche
de résilience en participant à &lt;strong&gt;la conception de leurs outils numériques&lt;/strong&gt;
et en les aidant à &lt;strong&gt;améliorer leurs méthodes de travail&lt;/strong&gt;, le tout dans &lt;strong&gt;un
esprit de sobriété&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;J’ai essayé d’y insuffler un maximum d’éléments issus des étapes précédentes
sans pour autant en abuser pour que le message reste clair. Tout d’abord, la
notion de « société de demain » fait directement référence à un monde
post-effondrement que j’évoquais dans mon article précédent. J’y fais aussi
référence en tentant de dessiner une première esquisse d’une société que je
souhaite &lt;strong&gt;résiliente et sobre&lt;/strong&gt;. La sobriété fait aussi référence à ma volonté
de développer des logiciels simples et « bidouillables ». Mes compétences sont
lisibles au creux de mon objectif : la conception d’outils numériques et
l’amélioration des méthodes de travail qui incluent les méthodes agiles et une
démarche de documentation. Aussi, je m’inscris dans &lt;strong&gt;une position de
complémentarité&lt;/strong&gt; (à l’inverse d’être indispensable) des équipes déjà en place en
« accompagnant », « participant » et en « aidant ».&lt;/p&gt;
&lt;p&gt;Cet objectif pourra être amené à évoluer dans le futur, mais j’espère qu’il
saura m’accompagner dans mes premières missions et qu’il permettra de poser sur
la table des sujets de discussion que l’on aborde trop peu dans le monde de la
technologie. J’espère qu’il véhicule correctement le message politique que je
lui ai imaginé.&lt;/p&gt;
&lt;p&gt;J’entrevois d’ailleurs déjà des limites à cet objectif très orienté vers un
métier que je pense voué à être marginalisé à long terme. Métier par ailleurs
pratiqué par et pour une population privilégiée dans le sens où elle possède et
maitrise des outils informatiques. Je crois que ces outils doivent
s’accompagner d’une démarche complémentaire &lt;strong&gt;au risque d’abandonner sur le
bord de la route les personnes les moins à l’aise avec le numérique&lt;/strong&gt;.
L’informatique reste un outil à notre service, en aucun cas il ne s’agit d’une
fin en soi. Je souhaiterai à terme évoluer vers un métier plus ancré dans le
réel. Aujourd’hui je vais toutefois profiter des compétences acquises durant
ces dernières années pour orienter le domaine au sein duquel j’agis (le
développement logiciel, principalement) vers un horizon qui me semble plus
enviable. Ce sera l’occasion aussi de rencontrer des personnes qui pourront me
guider vers des voies que je n’imagine pas encore. Mon objectif, tout imparfait
soit-il, est une image à cet instant précis de mes envies et une piste à
explorer pour pouvoir imaginer et construire « autre chose » par la suite.&lt;/p&gt;
&lt;p&gt;Avec cet objectif défini, je considère que le gros du travail introspectif est
terminé. Il reste toutefois quelques étapes supplémentaires avant d’attaquer la
refonte du site à proprement parler. J’aborderai dans le prochain article les
deux derniers points de ma démarche, à savoir de quelle manière je souhaite
communiquer et, enfin, la conception de l’architecture du site.&lt;/p&gt;</content></entry><entry><title>Introspection professionnelle : valeurs et raison d’être</title><id>urn:uuid:0ba64522-e440-5d7a-9d8d-8eec8019d2ec</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/introspection-professionnelle-valeurs-et-raison-detre.html" rel="alternate" type="text/html" /><published>2018-12-28T11:45:00+01:00</published><updated>2018-12-28T11:45:00+01:00</updated><content type="html">&lt;p&gt;Comme je le disais dans &lt;a href="boop-une-introduction.html"&gt;un précédent article&lt;/a&gt;, la
fin de cette année 2018 est pour moi l’occasion de reposer à plat mes
motivations professionnelles. Si j’ai décidé de quitter mon emploi chez
&lt;a href="http://sogilis.com"&gt;Sogilis&lt;/a&gt; afin de tracer ma propre route, c’est pour
différentes raisons parmi lesquelles :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;le sens que je ne trouvais pas à mon travail ;&lt;/li&gt;
&lt;li&gt;des problèmes sociétaux qui me parlent de plus en plus (ex. urgence
  climatique, fractures sociale et démocratique) ;&lt;/li&gt;
&lt;li&gt;mon implication dans &lt;a href="https://framasoft.org"&gt;Framasoft&lt;/a&gt; qui m’a fait réaliser
  la dimension politique qui sous-tend le développement logiciel ;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.mcpaccard.com/"&gt;des&lt;/a&gt; &lt;a href="http://www.maiwann.net/"&gt;rencontres&lt;/a&gt;
  &lt;a href="https://estcequecestdutravail.xyz/"&gt;multiples&lt;/a&gt; qui m’ont aidé à envisager
  mon travail sous un autre angle ;&lt;/li&gt;
&lt;li&gt;de nombreuses discussions avec des amis proches qui n’ont fait que renforcer
  mes choix.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;J’envisage aujourd’hui le travail que je peux fournir uniquement à travers un
prisme politique (au sens d’engagement). Les logiciels que je conçois ont un
impact sur les personnes qui les utilisent, &lt;strong&gt;il est important pour moi qu’ils
fonctionnent à leur service et non pas contre eux&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;C’est ce genre de réflexions que j’aimerais arriver à faire transparaître sur
mon site. Le but est de le transformer en « vitrine » professionnelle  en
mettant en avant mes valeurs, mon mode de fonctionnement, mes compétences, etc.
Mais avant d’entamer cette refonte, je souhaite passer par une phase de
réflexions plus approfondie.&lt;/p&gt;
&lt;h2&gt;Le design de soi, ou l’introspection professionnelle&lt;/h2&gt;
&lt;p&gt;J’ai découvert le concept de « &lt;strong&gt;design de soi&lt;/strong&gt; » il y a un peu plus d’un an
grâce à &lt;a href="http://www.mcpaccard.com/"&gt;Marie-Cécile Paccard&lt;/a&gt; lorsque je l’ai
contactée par rapport à &lt;a href="https://lessy.yuzu.ovh"&gt;Lessy&lt;/a&gt;. Le but est d’effectuer un
travail de recherche afin de mieux connaître ses aspirations et de mieux
communiquer en conséquence. Vous pouvez en apprendre plus dans &lt;a href="https://speakerdeck.com/mcpaccard/se-reinventer-et-etre-soi-a-lere-du-numerique"&gt;sa présentation&lt;/a&gt;
ou via &lt;a href="https://marieguillaumet.com/design-de-soi-paris-web-2015/"&gt;la présentation de Marie Guillaumet&lt;/a&gt;
qui en a parlé lors de l’évènement &lt;a href="https://www.paris-web.fr/"&gt;Paris Web&lt;/a&gt; 2015.&lt;/p&gt;
&lt;p&gt;J’étais personnellement un peu dubitatif sur ce que pouvait m’apporter
concrètement une telle démarche. Je me suis toutefois prêté au jeu pour Lessy
et le fait de voir émerger le contenu aussi naturellement pour la page
d’accueil et les éléments destinés à la communauté m’a encouragé à retenter
l’expérience sur moi-même (en le documentant, cette fois-ci !)&lt;/p&gt;
&lt;p&gt;Sur le sens toutefois, je suis peu à l’aise avec l’expression « design de
soi ». D’une part, le mot « design » continue de véhiculer une confusion avec
le graphisme ; d’autre part, et de façon plus ennuyante, même en prenant le
mot dans son sens de « conception », ce n’est pas tellement l’objet de la
démarche. Cela pourrait en effet laisser penser que le « design de soi » vise à
créer (concevoir) une nouvelle personne qui ne correspond pas forcément à
l’ancienne. Or, je crois que le but est de tirer des traits qui nous
correspondent, à la manière d’un caricaturiste qui cherche à représenter une
personne à travers quelques caractéristiques qui ressortent. Dans la suite de
ma série d’articles, je troquerai donc l’expression par celle d’introspection
professionnelle. Dans mon cas, le but est bien d’&lt;strong&gt;identifier les traits de ma
personnalité&lt;/strong&gt; sur lesquels je souhaite communiquer dans un cadre
professionnel.&lt;/p&gt;
&lt;p&gt;Pour cela, je vais procéder en plusieurs étapes qui devraient me permettre de
créer le contenu du site :&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;définition de &lt;strong&gt;mes valeurs&lt;/strong&gt; ;&lt;/li&gt;
&lt;li&gt;définition de &lt;strong&gt;ma raison d’être&lt;/strong&gt; ;&lt;/li&gt;
&lt;li&gt;définition de &lt;strong&gt;mes compétences&lt;/strong&gt; ;&lt;/li&gt;
&lt;li&gt;établissement d’&lt;strong&gt;un objectif&lt;/strong&gt; personnel (c’est-à-dire comment j’honore ma
   raison d’être) ;&lt;/li&gt;
&lt;li&gt;définition de mes moyens de &lt;strong&gt;communication&lt;/strong&gt; ;&lt;/li&gt;
&lt;li&gt;conception de &lt;strong&gt;l’architecture du site&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Le dernier point me permettra d’organiser les différents éléments qui auront
émergé lors des phases précédentes et potentiellement d’en faire émerger de
nouveaux.&lt;/p&gt;
&lt;p&gt;Les deux premiers points sont traités dans la suite de cet article.&lt;/p&gt;
&lt;h2&gt;Des valeurs pour guider mes choix&lt;/h2&gt;
&lt;p&gt;J’ai en vérité entamé la première phase, celle de la définition de mes valeurs,
il y a plusieurs mois. Je souhaitais voir comment la perception que j’avais de
moi-même évoluait dans le temps, identifier les éléments qui revenaient,
comprendre pourquoi je n’étais pas à l’aise avec d’autres, etc. À titre
d’exemple, je n’ai pas conservé l’« éthique » dans mes valeurs car ça ne
signifiait pas grand chose pour moi : tout le monde possède une éthique sans
pour autant placer la même chose derrière. Revendiquer avoir une éthique est
nécessairement perçu à travers un prisme différent selon les personnes avec qui
j’intéragis.&lt;/p&gt;
&lt;p&gt;À l’éthique, j’ai préféré le terme &lt;strong&gt;d’intégrité&lt;/strong&gt;. Affirmer son intégrité
permet de garder un cap et de faciliter la définition de ses priorités. Par
exemple, j’ai comme conviction que les licences libres ainsi que le respect de
la vie privée sont des conditions &lt;em&gt;sine qua non&lt;/em&gt; pour qu’un logiciel soit
réellement au service de ses utilisateurs et utilisatrices (c’est-à-dire qu’il
fasse bien ce qu’on lui demande, sans malveillance). Vous ne me verrez donc pas
demain accepter une mission qui ne respecte pas ces conditions parce qu’elle
est mieux payée qu’une autre. Cette notion d’intégrité sera par la suite
&lt;strong&gt;complétée par un manifeste&lt;/strong&gt; qui détaillera mieux mes engagements.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Le respect&lt;/strong&gt; dans mes échanges ou envers les utilisatrices et utilisateurs
d’un logiciel m’apparaît ensuite nécessaire à toute relation. Rester à
l’écoute, savoir exprimer ses sentiments, considérer la personne en face sur un
pied d’égalité ; je n’imagine pas d’autre manière de fonctionner pour tirer le
meilleur de mes échanges. D’un point de vue technique cela signifie aussi, pour
moi, considérer les techniques d’expérience utilisateur et d’accessibilité
comme intrinsèques à un projet, pas seulement comme des ajouts selon un budget
sur lequel je n’ai pas la main. À l’inverse, d’un point de vue global, cela
signifie prendre aussi en compte les externalités de ce que je développe : hors
de question de développer un outil qui nuirait encore un peu plus à
l’environnement par exemple.&lt;/p&gt;
&lt;p&gt;Enfin, &lt;strong&gt;la transmission&lt;/strong&gt; doit faire partie de chaque processus de création.
Après avoir lu un peu autour du &lt;a href="https://ressources.osons.cc/?PetitPrecisDeCompostabiliteDesprojets"&gt;concept de
compostabilité&lt;/a&gt;
en septembre (via la super présentation de &lt;a href="https://marges.clairezuliani.com/good_job/2018/05/27/melange-cultures-professionnelles.html"&gt;Claire Zuliani à Sud
Web&lt;/a&gt;),
j’ai mieux réalisé la finitude de notre présence au sein d’un groupe.
Transmettre mes connaissances et mes compétences m’est alors apparu comme bien
plus essentiel pour ne plus être un rouage « indispensable » sans lequel rien
ne fonctionne. Mécaniquement, j’ai le sentiment que cela pousse aussi à plus
d’humilité. Nous devenons uniques non pas par nos compétences techniques mais
par notre vécu.&lt;/p&gt;
&lt;p&gt;En me limitant à trois valeurs, je me suis forcé à creuser toujours plus ce qui
compte vraiment pour moi. J’ai écarté plusieurs points qui me tenaient à cœur
mais que je n’arrivais pas à définir correctement (notamment le principe de
remise en question). Ces valeurs sont évidemment fluctuantes : il s’agit d’un
travail sur moi-même à un instant T et je m’attends à redéfinir leur contour
dans le futur. En revanche, &lt;strong&gt;je ne pense pas m’en départir à moins de changer
fondamentalement la personne que je suis&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;Une raison d’être pour comprendre où je vais&lt;/h2&gt;
&lt;p&gt;Se trouver une raison d’être n’est pas la chose la plus évidente à faire. C’est
pourtant une question qui me taraude depuis un moment car elle questionne sur
le sens que l’on souhaite donner à sa vie. Lorsque j’ai pris une année
sabbatique en 2015, c’est quelque chose qui m’a travaillé sans que je n’y
trouve une réponse qui me convenait.&lt;/p&gt;
&lt;p&gt;Ces derniers mois ont toutefois été plus efficaces, au point que j’arrive à la
résumer en une courte phrase : &lt;strong&gt;concevoir les outils dont la société aura
besoin demain&lt;/strong&gt;. Pour comprendre cette raison d’être, il me paraît important de
bien définir ce dont je parle.&lt;/p&gt;
&lt;p&gt;Tout d’abord, lorsque je parle de « concevoir [des] outils », je fais le choix
conscient de ne pas utiliser le terme de « développer ». Pour moi, &lt;strong&gt;un
logiciel n’est pas une fin en soi&lt;/strong&gt;. Il y a avant tout une phase d’acquisition
des besoins et de réflexion qui peut notamment mener à la conclusion qu’un
outil informatique ne serait pas une bonne solution. Cela implique aussi que je
dois étendre mes compétences au delà de la technique informatique, en acquérant
notamment plus de compétences liées à l’expérience utilisateur. Je dispose pour
cela de précieuses ressources, notamment deux articles de Raphaël
Yharrassarry : « &lt;a href="https://blocnotes.iergo.fr/articles/competences-ux-et-modele-en-t/"&gt;Compétences &lt;abbr&gt;UX&lt;/abbr&gt; et modèle en T&lt;/a&gt; »
et « &lt;a href="https://blocnotes.iergo.fr/articles/se-former-en-ux-design/"&gt;Se former en &lt;abbr&gt;UX&lt;/abbr&gt; Design ?&lt;/a&gt; ».&lt;/p&gt;
&lt;p&gt;Ensuite, lorsque je parle de « demain », j’y cache derrière la notion de
« &lt;a href="https://fr.wikipedia.org/wiki/Collapsologie"&gt;collapsologie&lt;/a&gt; » (ou
d’effondrement). Je ne me suis pas encore énormément penché sur le sujet, mais
il revient régulièrement dans les discussions qui m’entourent. Je ressens dans
mes échanges &lt;strong&gt;une notion d’urgence et d’inévitabilité d’une société en
mutation profonde&lt;/strong&gt;. La question n’est pas forcément de savoir « quand ?»,
encore moins « si ? », mais plutôt « comment ?». À quoi ressembleront nos
sociétés dites « modernes » dans un monde où les catastrophes écologiques
prédominent, où la faune et la flore fondent comme neige au soleil et où les
mouvements migratoires s’accélèrent ? Et si l’on se prenait en main pour
imaginer nous-mêmes ce monde de demain et l’accompagner en douceur ? Il existe
trois axes que j’ai identifié et dans lesquels j’aimerais m’investir :&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;accompagner l’inévitable désastre écologique ;&lt;/li&gt;
&lt;li&gt;aider les populations en lutte pour affirmer leur légitimité aux yeux du
   reste de la société ;&lt;/li&gt;
&lt;li&gt;repenser nos espaces démocratiques et l’expression du pouvoir.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Vaste programme que celui-là, j’ignore encore quelles formes peuvent prendre
mes actions dans chacun de ces domaines mais je ne me fais pas de soucis pour
savoir identifier les missions qui entreront en résonance avec ces sujets.&lt;/p&gt;
&lt;p&gt;Enfin, le tout fait référence à ce qui se produit dans la sphère technologique
depuis des années : les outils qui sont conçus n’émanent pas de réels besoins
mais le deviennent une fois bien installés. &lt;span lang="en"&gt;Apple&lt;/span&gt; est
notamment championne dans ce domaine, imposant avec brio et comme évidentes des
technologies comme le &lt;span lang="en"&gt;smartphone&lt;/span&gt; ou la tablette. On peut
toutefois questionner leurs répercussions sur notre société comme une
accoutumance à l’instantanéité ou une addiction aux écrans difficiles à jauger.
C’est le fameux « &lt;a href="https://fr.wikipedia.org/wiki/Temps_de_cerveau_humain_disponible"&gt;temps de cerveau humain disponible&lt;/a&gt; »
qui est attaqué ici. En vérité, &lt;strong&gt;le futur de nos sociétés est aujourd’hui
dessiné par des sociétés commerciales&lt;/strong&gt; qui souhaitent avant tout vendre leurs
produits plutôt que de réfléchir au bien commun ; cela me gêne tout
particulièrement.&lt;/p&gt;
&lt;h2&gt;Une conclusion partielle pour préparer une suite plus concrète&lt;/h2&gt;
&lt;p&gt;Ce premier article était un peu abstrait : je n’ai abordé ici que des sujets
qui me serviront de base pour construire le futur contenu du site. Cet article
m’est apparu un peu pompeux à plusieurs reprises lors de sa rédaction, mais je
crois que le résultat est avant tout un travail honnête sur mes aspirations et
me permettra réellement d’affirmer ma manière de travailler avec d’autres
personnes.&lt;/p&gt;
&lt;p&gt;Je crois ces engagements indispensables dans nos sociétés toujours plus
numériques, où nous perdons peu à peu la main sur nos données et leur
traitement. Je suis partisan de réinsuffler plus d’échanges humains et une
vision positive dans nos vies numériques, et donc nos vies tout court.&lt;/p&gt;
&lt;p&gt;Cet article a une saveure particulière pour moi car j’ai réussi à y condenser
toutes les réflexions que je mène depuis plusieurs mois ; réflexions notamment
alimentées par mes échanges au sein de &lt;a href="https://framasoft.org/"&gt;Framasoft&lt;/a&gt; qui
est, pour une bonne partie, à l’origine des graines qui commencent à germer sur
ce site.&lt;/p&gt;
&lt;p&gt;Le prochain article devrait aborder des sujets un peu plus concrets et mener
notamment à la rédaction de contenu qui apparaîtra par la suite sur le site.&lt;/p&gt;</content></entry><entry><title>Suivre le Boop! blog</title><id>urn:uuid:3580b833-c94c-58da-9905-2f7f7aaa126f</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/suivre-le-boop-blog.html" rel="alternate" type="text/html" /><published>2018-12-13T11:10:00+01:00</published><updated>2018-12-13T11:10:00+01:00</updated><content type="html">&lt;p&gt;J’ai décidé de faire vite pour ajouter le flux d’actualités à &lt;span lang="en"&gt;Boop!&lt;/span&gt;,
mon générateur de sites statiques, et c’est donc chose faite. Vous pouvez
désormais &lt;strong&gt;vous abonner à ce site&lt;/strong&gt; en ajoutant l’adresse dans votre
&lt;a href="https://freshrss.org"&gt;agrégateur d’actualités préféré&lt;/a&gt; (qui devrait être
capable de trouver l’adresse du flux tout seul, si si, mais si ça ne marche pas
le flux est accessible &lt;a href="http://marienfressinaud.fr/feeds/all.atom.xml"&gt;ici&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Petit retour sur comment je m’y suis pris.&lt;/p&gt;
&lt;h2&gt;Distinguer les pages des articles&lt;/h2&gt;
&lt;p&gt;La première étape à laquelle je me suis trouvé confronté a été de distinguer
les pages (en l’occurence, la page d’accueil) des articles. Jusqu’à maintenant,
je n’avais pas eu besoin de faire une telle distinction, mais je ne veux pas me
trouver avec la page d’accueil dans mon flux &lt;abbr&gt;RSS&lt;/abbr&gt;. Pour cela,
&lt;strong&gt;j’ai réorganisé toute la structure des répertoires&lt;/strong&gt;, en m’inspirant cette
fois-ci de ce qui pouvait se faire dans &lt;a href="https://jekyllrb.com/docs/structure/"&gt;Jekyll&lt;/a&gt;
(au lieu de &lt;a href="https://blog.getpelican.com/"&gt;Pelican&lt;/a&gt; qui me servait de base
jusqu’à maintenant).&lt;/p&gt;
&lt;p&gt;Auparavant, tout le contenu du site était déposé dans un répertoire &lt;code&gt;./content&lt;/code&gt;
puis copié dans &lt;code&gt;./output&lt;/code&gt; (via une phase de transformation dans le cas des
fichiers &lt;span lang="en"&gt;Markdown&lt;/span&gt;), désormais la structure est la
suivante :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;un fichier &lt;code&gt;index.html&lt;/code&gt; à la racine ;&lt;/li&gt;
&lt;li&gt;les articles, nécessairement au format &lt;span lang="en"&gt;Markdown&lt;/span&gt;, sont
  dans un répertoire &lt;code&gt;./articles&lt;/code&gt; (c’est original) ;&lt;/li&gt;
&lt;li&gt;le &lt;span lang="en"&gt;&lt;em&gt;template&lt;/em&gt;&lt;/span&gt; des articles se trouve dans
  un répertoire &lt;code&gt;./templates&lt;/code&gt; (toujours très original) ;&lt;/li&gt;
&lt;li&gt;les fichiers à copier tels quels, comme les fichiers &lt;abbr&gt;CSS&lt;/abbr&gt;, sont
  placés dans &lt;code&gt;./static&lt;/code&gt; ;&lt;/li&gt;
&lt;li&gt;et le tout est copié/généré dans un répertoire &lt;code&gt;./site&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Je trouve personnellement cette structure un poil plus compliquée que la
précédente, mais beaucoup plus explicite sur &lt;strong&gt;les intentions de chaque
répertoire&lt;/strong&gt;. Vous pouvez voir à quoi cela ressemble &lt;a href="https://framagit.org/marienfressinaud/marienfressinaud.fr/tree/f3200d89523d4a4ed618310170bcb5c946ceca25"&gt;en suivant ce lien&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Vous pouvez aussi voir le &lt;a href="https://framagit.org/marienfressinaud/boop/commit/c37fe01d8da8a71cb16c1de649e342dcbb92c4d0#b8c037ff8ab16c431251e16173af8e9ec6b1cbcf"&gt;&lt;span lang="en"&gt;commit&lt;/span&gt; introduisant le
changement&lt;/a&gt;
sachant qu’il en existe quelques autres mais que je n’ai pas envie de faire un
lien vers chacun d’entre eux.&lt;/p&gt;
&lt;p&gt;Dorénavant, les articles sont donc identifiables aisément car déposés dans un
répertoire spécifique. J’ai décidé, en plus de cela, de les abstraire dans une
classe particulière (&lt;code&gt;Article&lt;/code&gt;) pour qu’ils soient plus faciles à manipuler par
la suite (&lt;a href="https://framagit.org/marienfressinaud/boop/commit/303d11926116109ac8929a7bfb6d254839dcaa6d"&gt;voir le &lt;span lang="en"&gt;commit&lt;/span&gt;&lt;/a&gt;).&lt;/p&gt;
&lt;h2&gt;Récupérer les informations manquantes via la configuration&lt;/h2&gt;
&lt;p&gt;Les flux &lt;abbr&gt;RSS&lt;/abbr&gt; et Atom demandent &lt;strong&gt;des informations supplémentaires&lt;/strong&gt;
que je ne pouvais pas encore récupérer, notamment l’&lt;abbr&gt;URL&lt;/abbr&gt; et le
titre du site. Je devais aussi &lt;strong&gt;figer certains attributs présents dans les
métadonnées&lt;/strong&gt; des articles &lt;span lang="en"&gt;Markdown&lt;/span&gt; comme le titre,
l’auteur et la date de publication. Par ailleurs, j’ai voulu &lt;strong&gt;correctement
gérer les fuseaux horaires&lt;/strong&gt; sachant la complexité que cela pouvait être par la
suite. Il me fallait donc aussi récupérer le fuseau de l’auteur (pour ma part,
&lt;code&gt;Europe/Paris&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;Je suis tout d’abord parti sur un simple fichier de configuration au format
&lt;abbr lang="en"&gt;YAML&lt;/abbr&gt; pour indiquer les informations générales du site et
alimenter une variable &lt;code&gt;configuration&lt;/code&gt; (&lt;a href="https://framagit.org/marienfressinaud/boop/commit/39c7a809ad6f39e0f9c0295c3c58345ae30a135c"&gt;voir le &lt;span lang="en"&gt;commit&lt;/span&gt;&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;J’ai ensuite créé quelques méthodes sur ma classe &lt;code&gt;Article&lt;/code&gt; pour accéder
facilement aux informations stockées dans les métadonnées. Ça leur donne ainsi
un rôle particulier et me permet de faire des manipulations dessus à la volée
(&lt;a href="https://framagit.org/marienfressinaud/boop/commit/e0e669e186047d2d94043b34061238600d20f3ee"&gt;voir le &lt;span lang="en"&gt;commit&lt;/span&gt;&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Enfin, les fuseaux horaires sont gérés grâce au paquet externe &lt;a href="https://pypi.org/project/pytz/"&gt;pytz&lt;/a&gt;.
Connaissant la complexité du sujet, je ne me suis pas amusé à développer mon
propre module donc, là encore, petite entorse à ma règle de ne pas dépendre de
code externe.&lt;/p&gt;
&lt;p&gt;Les informations sont toutes facultatives, des valeurs par défaut étant
générées à chaque fois, mais il est tout de même recommandé de les renseigner.&lt;/p&gt;
&lt;h2&gt;Générer le flux Atom, enfin !&lt;/h2&gt;
&lt;p&gt;Avec toutes ces informations en main, je pouvais enfin générer le flux
&lt;abbr&gt;RSS&lt;/abbr&gt; tant attendu. Mais encore un petit choix à faire avant : il
existe deux formats « concurrents » pour générer des flux d’actualités,
&lt;a href="https://fr.wikipedia.org/wiki/RSS"&gt;&lt;abbr&gt;RSS&lt;/abbr&gt;&lt;/a&gt; et &lt;a href="https://fr.wikipedia.org/wiki/Atom_Syndication_Format"&gt;Atom&lt;/a&gt;.
D’un point de vue simple utilisateur, les deux se valent et les deux sont très
bien supportés par tous les agrégateurs d’actualités. &lt;strong&gt;Mon choix s’est porté
sur Atom&lt;/strong&gt; qui se voulait être pendant un temps une amélioration de
&lt;abbr&gt;RSS&lt;/abbr&gt;, mais surtout parce que mon site précédent utilisait déjà ce
format. Et pourquoi pas les deux ? Parce que ça ne servirait à rien et que j’ai
mieux à faire de mon temps, tout simplement.&lt;/p&gt;
&lt;p&gt;Il ne me restait donc plus qu’à générer un document &lt;abbr&gt;XML&lt;/abbr&gt; suivant le
format Atom et l’écrire dans un fichier dans le répertoire &lt;code&gt;./site&lt;/code&gt; (&lt;a href="https://framagit.org/marienfressinaud/boop/commit/edfcf8220f725c1b4f3d5099b191d17ea807a5cd"&gt;voir le
&lt;span lang="en"&gt;commit&lt;/span&gt;&lt;/a&gt;
suivi de près &lt;a href="https://framagit.org/marienfressinaud/boop/commit/c9eff5a1c0df05b97c6162505e1bf7d5a8ddaee4"&gt;par un autre&lt;/a&gt;
destiné à abstraire la génération du &lt;abbr&gt;XML&lt;/abbr&gt; dans un module nommé
&lt;span lang="en"&gt;Boopfeed&lt;/span&gt;).&lt;/p&gt;
&lt;p&gt;Et voilà, plus qu’à &lt;a href="https://framagit.org/marienfressinaud/marienfressinaud.fr/commit/8a43fca999a3b0a237e7cf7377f5718a4e5dfe19"&gt;incorporer un lien&lt;/a&gt;
dans l’en-tête de mes fichiers &lt;abbr&gt;HTML&lt;/abbr&gt; vers ce fichier Atom, et c’est
terminé !&lt;/p&gt;
&lt;h2&gt;Dans la tête d’un développeur&lt;/h2&gt;
&lt;p&gt;Bien entendu, je n’ai pas développé tout cela d’une traite. Entre poser à plat
les problèmes que posaient l’implémentation initiale, décider d’une nouvelle
structure après plusieurs essais, réfléchir à la meilleure manière de récupérer
les informations manquantes, etc., ce travail m’a pris une journée entière
durant laquelle je n’ai pas chômé.&lt;/p&gt;
&lt;p&gt;Si &lt;a href="https://framagit.org/marienfressinaud/boop/commits/master"&gt;mon historique &lt;span lang="en"&gt;Git&lt;/span&gt;&lt;/a&gt;
paraît relativement linéaire, c’est que j’ai pris le soin de le réécrire avant
de le publier, cela pour deux raisons :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;un rôle pédagogique&lt;/strong&gt;, si de futurs développeuses ou développeurs veulent
  comprendre ce que j’ai fait, l’enchaînement des &lt;span lang="en"&gt;commits&lt;/span&gt;
  leur paraîtront plus logiques ;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;un rôle de débogage&lt;/strong&gt;, si jamais j’ai introduit des &lt;span lang="en"&gt;bugs&lt;/span&gt;
  à un moment donné, il sera plus simple de retrouver à quel moment et pour
  quelle raison.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;J’ai d’ailleurs &lt;strong&gt;fonctionné de manière totalement inverse&lt;/strong&gt; lors du
développement. En effet, j’ai commencé à écrire le code générant le flux Atom,
en mettant les valeurs manquantes en dur dans le code, puis en le retravaillant
au fur et à mesure.&lt;/p&gt;
&lt;p&gt;Je fais cette petite précision pour les développeurs et développeuses moins
expérimenté·es qui pourraient se dire qu’il leur est impossible d’arriver à ce
résultat de façon aussi directe. Ça l’est effectivement, mais pour les autres
aussi !&lt;/p&gt;
&lt;h2&gt;La technique, c’est fini&lt;/h2&gt;
&lt;p&gt;Je suis donc arrivé à un point du développement de &lt;span lang="en"&gt;Boop!&lt;/span&gt;
qui me satisfait. Il manque bien évidemment plein de choses, et notamment il
n’est pas possible de créer des pages qui ne soient pas des articles ; cela
viendra plus tard.&lt;/p&gt;
&lt;p&gt;Je souhaite désormais me consacrer au contenu du site car il ne sert à rien
d’avoir une belle vitrine si ce qu’il transmet est creux et vide de sens. Les
prochains articles devraient donc porter sur &lt;strong&gt;des réflexions plus
personnelles&lt;/strong&gt; : quel but je souhaite donner à ma vie, quelles sont mes
valeurs, quelles pratiques je compte appliquer, etc. ; tout cela pour concevoir
une vitrine cohérente avec mes aspirations à la fois personnelles et
professionnelles.&lt;/p&gt;</content></entry><entry><title>Simplifier la rédaction d’articles dans Boop!</title><id>urn:uuid:a200d976-8e58-5916-a640-2c5b5535566a</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/simplifier-la-redaction-darticles-dans-boop.html" rel="alternate" type="text/html" /><published>2018-12-11T22:00:00+01:00</published><updated>2018-12-11T22:00:00+01:00</updated><content type="html">&lt;p&gt;Fin octobre j’inaugurais la refonte de mon site web personnel en promettant
d’expliquer pas à pas les étapes qui mèneraient à une nouvelle version de
celui-ci. Le mois de novembre a cependant défilé bien plus vite que je ne le
pensais. Mon chômage ayant débuté début décembre, je peux enfin replacer mes
priorités sur les projets qui me tiennent à cœur. Alors reprenons.&lt;/p&gt;
&lt;h2&gt;Simplifier le balisage avec &lt;span lang="en"&gt;Markdown&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;La première chose qui m’a émerveillé lorsque j’ai appris à faire du web il y a
quelques années, c’est qu’il suffisait d’écrire du texte dans un fichier et de
l’ouvrir dans un navigateur pour avoir un site fonctionnel. Mais pour rendre ce
site Internet lisible par les navigateurs, il est aussi nécessaire de
structurer vos fichiers &lt;a href="https://fr.wikipedia.org/wiki/Hypertext_Markup_Language"&gt;au format &lt;abbr&gt;HTML&lt;/abbr&gt;&lt;/a&gt;.
En soi rien de bien compliqué, mais cela peut vite devenir lourd. Un
paragraphe, par exemple, doit être entouré de « balises » &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Mon paragraphe.&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Une liste quant à elle se définit de cette manière :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Un élément de la liste&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Un autre élément&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Et un troisième&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Personnellement, j’ai autre chose à faire que de toujours penser à définir
correctement mes balises. C’est là que &lt;a href="https://fr.wikipedia.org/wiki/Markdown"&gt;le &lt;span lang="en"&gt;Markdown&lt;/span&gt;&lt;/a&gt;
rentre en jeu. Il s’agit aussi d’un langage de balisage, mais celui-ci se veut
plus léger et naturel pour un humain. Mes deux exemples précédents deviennent
ainsi :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;Mon paragraphe.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Il n’y a aucun balisage, c’est normal. Et pour la liste :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Un élément de la liste
&lt;span class="k"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Un autre élément
&lt;span class="k"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Et un troisième
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;De simples tirets, c’est beaucoup plus simple, non ? Ce fut donc la première
amélioration que j’ai apporté à &lt;a href="https://framagit.org/marienfressinaud/boop"&gt;&lt;span lang="en"&gt;Boop!&lt;/span&gt;&lt;/a&gt;,
mon générateur de sites statiques. Pour cela, il me suffit de tester
l’extension d’un fichier, si celui-ci se termine par &lt;code&gt;.md&lt;/code&gt;, je passe le contenu
du fichier au parseur &lt;span lang="en"&gt;Markdown&lt;/span&gt; pour qu’il le transforme
en &lt;abbr&gt;HTML&lt;/abbr&gt;, puis j’écris enfin le résultat dans un nouveau fichier
(&lt;a href="https://framagit.org/marienfressinaud/boop/commit/a069ecbce2fb89107064679f2a4f27fef15143da#b8c037ff8ab16c431251e16173af8e9ec6b1cbcf"&gt;voir le &lt;span lang="en"&gt;commit&lt;/span&gt; introduisant le changement&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Ce fut aussi l’occasion de déroger à ma règle non-officielle de ne reposer sur
aucun code extérieur : j’avais mieux à faire que de réécrire un parseur complet
de &lt;span lang="en"&gt;Markdown&lt;/span&gt; depuis zéro. Je me base donc sur le paquet
&lt;a href="https://pypi.org/project/Markdown/"&gt;&lt;span lang="en"&gt;Markdown&lt;/span&gt;&lt;/a&gt;,
disponible via la commande &lt;code&gt;pip&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;&lt;span lang="en"&gt;Boopsy&lt;/span&gt;, mon système de templating&lt;/h2&gt;
&lt;p&gt;J’avais ensuite un autre soucis. En effet, je souhaitais que tous les articles
partagent la même structure &lt;abbr&gt;HTML&lt;/abbr&gt; et notamment :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;le même fichier de style &lt;abbr&gt;CSS&lt;/abbr&gt; ;&lt;/li&gt;
&lt;li&gt;le titre de l’article dans la balise &lt;code&gt;&amp;lt;title /&amp;gt;&lt;/code&gt; ainsi que dans une balise
  &lt;code&gt;&amp;lt;h1 /&amp;gt;&lt;/code&gt; ;&lt;/li&gt;
&lt;li&gt;l’affichage de la date de publication de l’article ;&lt;/li&gt;
&lt;li&gt;des liens pour revenir à l’accueil en haut et en bas de page.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Pour cela j’ai pas mal tergiversé sur la meilleure manière de faire afin de
répondre du mieux possible à mon besoin tout en limitant le plus possible le
code à écrire. J’aurais pu me baser sur un système de &lt;span lang="en"&gt;&lt;em&gt;templating&lt;/em&gt;&lt;/span&gt;
déjà existant tel que &lt;a href="http://jinja.pocoo.org/"&gt;&lt;span lang="en"&gt;Jinja2&lt;/span&gt;&lt;/a&gt;,
mais j’avais envie de créer quelque chose de plus simple.&lt;/p&gt;
&lt;p&gt;Après avoir longuement lu l’article de Ned Batchelder, « &lt;a href="http://aosabook.org/en/500L/a-template-engine.html"&gt;&lt;span lang="en"&gt;A
template engine&lt;/span&gt;&lt;/a&gt; »
sur &lt;a href="http://aosabook.org/"&gt;&lt;abbr title="The Architecture of Open Source Applications" lang="en"&gt;AOSA&lt;/span&gt;&lt;/a&gt;,
et avoir joué un petit peu de mon côté, j’ai sorti un système de
&lt;span lang="en"&gt;&lt;em&gt;template&lt;/em&gt;&lt;/span&gt; (nommé &lt;span lang="en"&gt;Boopsy&lt;/span&gt;) très
simplifié par rapport à l’original : en à peine 60 lignes de code, j’avais déjà
un système fonctionnel (&lt;a href="https://framagit.org/marienfressinaud/boop/commit/1d4ab7d18460b0cff72f21cb30102f3999a20fea#b8c037ff8ab16c431251e16173af8e9ec6b1cbcf"&gt;voir le &lt;span lang="en"&gt;commit&lt;/span&gt; introduisant le
changement&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Ce système est évidemment largement améliorable mais constitue une bonne
première étape qui fait exactement ce dont j’ai besoin.&lt;/p&gt;
&lt;h2&gt;Encore un petit effort&lt;/h2&gt;
&lt;p&gt;Il va me rester une dernière petite étape à terminer avant de commencer à
réfléchir au contenu du site : la génération du flux &lt;abbr&gt;RSS&lt;/abbr&gt; des
articles pour permettre de suivre ce blog facilement. Le reste des
fonctionnalités que je pourrais envisager ensuite sont plutôt de l’ordre du
confort et pourront attendre.&lt;/p&gt;
&lt;p&gt;Je devrais en principe mettre moins de temps cette fois-ci pour donner des
nouvelles !&lt;/p&gt;</content></entry><entry><title>Boop! Une introduction</title><id>urn:uuid:245f1b7b-7fb1-548c-b3f1-fa4d41762680</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/boop-une-introduction.html" rel="alternate" type="text/html" /><published>2018-10-29T20:00:00+01:00</published><updated>2018-10-29T20:00:00+01:00</updated><content type="html">&lt;p&gt;Cette fin d’année 2018 marque pour moi un tournant professionnel. Après avoir
travaillé trois années chez &lt;a href="http://sogilis.com/"&gt;Sogilis&lt;/a&gt;, j’ai décidé, pour
diverses raisons, de sortir du sentier qui se dessinait devant moi pour me
mettre à mon compte. Ce changement s’accompagne pour moi d’une nécessaire
remise en question de mes motivations et engagements : à quoi souhaité-je
consacrer mon temps ?&lt;/p&gt;
&lt;p&gt;Pour accompagner ce cheminement, j’ai souhaité créer un nouveau site à partir
de zéro. Si je ne sais pas encore exactement ce qu’il contiendra, je sais que
j’ai envie de renouer avec mes premiers pas sur Internet : c’est-à-dire
l’apprentissage et le partage de connaissances.&lt;/p&gt;
&lt;p&gt;L’une des choses que j’ai tout de suite aimé en informatique, c’est cette
capacité que l’on a de pouvoir nous forger facilement nos propres outils. Mon
site Internet en est un que j’ai longtemps laissé de côté mais que je
souhaitais ramener dans ma stratégie pour contrôler mon image numérique. Pour
cela, j’aurais pu continuer d’utiliser &lt;a href="https://getpelican.com/"&gt;Pelican&lt;/a&gt; que
j’utilisais jusque-là, mais quelque chose me titillais : et si j’en profitais
pour comprendre comment fonctionne un générateur de sites statiques ? La
mécanique interne ne me semble pas si compliquée…&lt;/p&gt;
&lt;h2&gt;Un générateur de sites statiques, pour quoi faire ?&lt;/h2&gt;
&lt;p&gt;L’une des premières choses à laquelle j’ai pensé a été de me faire un site
uniquement à base de HTML et CSS. Quitte à repartir de zéro, autant utiliser
les technologies les plus simples du web ; aucun élément généré dynamiquement,
uniquement du code moulé au clavier. Mais je me suis vite rendu compte que cela
deviendrait très pénible à maintenir : un changement dans la structure HTML ?
C’est toutes les pages qu’il faudra modifier. Un nouvel article ? Il faudra
écrire le flux RSS à la main. Beurk.&lt;/p&gt;
&lt;p&gt;L’avantage du générateur de sites statiques est qu’il peut rester léger tout en
automatisant certaines tâches et en facilitant la maintenance. Certaines
fonctionnalités deviennent toutefois plus compliquées à gérer, notamment la
gestion des commentaires et la recherche, mais le compromis me semble
acceptable.&lt;/p&gt;
&lt;h2&gt;Les premiers pas de &lt;span lang="en"&gt;Boop!&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;Je sous-entendais plus haut que je n’y connais rien en générateur de sites
statiques. En vérité, &lt;span lang="en"&gt;Boop!&lt;/span&gt; a déjà quatre mois ! En
effet, j’ai développé début juillet une première version destinée à générer &lt;a href="https://photos.marienfressinaud.fr"&gt;ma
galerie de photos&lt;/a&gt; (le code est disponible
sur &lt;a href="https://framagit.org/marienfressinaud/photos.marienfressinaud.fr"&gt;Framagit&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Son but n’était alors pas tout à fait le même, et comme il s’agissait surtout
d’une preuve de concept, ça ne me dérange pas plus que ça de repartir de zéro.
À terme, j’aimerais que les fonctionnalités de la première version soient
intégrées dans ce que je vais désormais développer.&lt;/p&gt;
&lt;h2&gt;Implémentation d’une version zéro&lt;/h2&gt;
&lt;p&gt;Bien, maintenant que je sais que je veux me faire un site qui sera généré par
un outil du doux nom de &lt;span lang="en"&gt;Boop!&lt;/span&gt;, il est temps de rentrer
dans le vif du sujet : par quoi je commence pour obtenir une version zéro ?&lt;/p&gt;
&lt;p&gt;Le principe de base d’un générateur de sites statiques est qu’il lit le contenu
depuis un répertoire source, qui est passé dans une moulinette qui va
transformer ce contenu en fichiers HTML pour les déposer ensuite dans un
répertoire destination.&lt;/p&gt;
&lt;p&gt;Pour cette première version de &lt;span lang="en"&gt;Boop!&lt;/span&gt;, j’ai décidé de
rester extrêmement simple : les fichiers sources seront des fichiers HTML et
CSS. Il n’y a donc pas besoin de les transformer et on peut se contenter de les
copier dans le répertoire destination. Oui OK, ça ne sert à rien pour le
moment, mais c’était histoire de me mettre dans le (petit) bain.&lt;/p&gt;
&lt;p&gt;Le code écrit en Python est disponible sur &lt;a href="https://framagit.org/marienfressinaud/boop/blob/0.0.0/boop.py"&gt;Framagit&lt;/a&gt;
avec le tag &lt;code&gt;0.0.0&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Les esprits taquins (et techniques) noteront peut-être que cette première
version, aussi simple soit-elle, n’est pas exempt de bugs : on corrigera cela
dans la prochaine version !&lt;/p&gt;
&lt;h2&gt;La mise en ligne du site&lt;/h2&gt;
&lt;p&gt;Une fois la version zéro de &lt;span lang="en"&gt;Boop!&lt;/span&gt; prête, il est temps de
réaliser la première version du site. Une &lt;a href="https://framagit.org/marienfressinaud/marienfressinaud.fr/blob/8f1ea7653b1c6856afa53effda32e33d7288641a/content/index.html"&gt;page HTML&lt;/a&gt;
et un &lt;a href="https://framagit.org/marienfressinaud/marienfressinaud.fr/blob/8f1ea7653b1c6856afa53effda32e33d7288641a/content/style/herisson.css"&gt;fichier CSS&lt;/a&gt;
plus tard, le site est prêt pour être mis en ligne. C’est minimaliste mais ça
fait bien le boulot tout en étant lisible.&lt;/p&gt;
&lt;p&gt;Pour la mise en ligne, je dispose déjà d’un serveur web capable de servir du
contenu statique (un serveur &lt;a href="http://nginx.org/"&gt;nginx&lt;/a&gt;), je n’ai qu’à ajouter
une entrée DNS de &lt;code&gt;next.marienfressinaud.fr&lt;/code&gt; vers mon serveur et ajouter le
fichier de configuration qui va bien pour nginx :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# version simplifiée&lt;/span&gt;
&lt;span class="k"&gt;server&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kn"&gt;listen&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kn"&gt;listen&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;[::]:80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kn"&gt;server_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;next.marienfressinaud.fr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kn"&gt;root&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;/var/www/next.marienfressinaud.fr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kn"&gt;index&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;index.html&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Il ne me reste plus qu’à faciliter le téléversement des fichiers générés par
&lt;span lang="en"&gt;Boop!&lt;/span&gt; sur le serveur. Pour cela j’ai créé un fichier
&lt;a href="https://framagit.org/marienfressinaud/marienfressinaud.fr/blob/8f1ea7653b1c6856afa53effda32e33d7288641a/Makefile"&gt;&lt;code&gt;Makefile&lt;/code&gt;&lt;/a&gt;
contenant quatre règles :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;build&lt;/code&gt; qui appelle &lt;span lang="en"&gt;Boop!&lt;/span&gt; pour générer le contenu ;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;clean&lt;/code&gt; qui supprime les fichiers générés dans &lt;code&gt;./output&lt;/code&gt; ;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;publish&lt;/code&gt; qui téléverse sur mon serveur avec &lt;code&gt;rsync&lt;/code&gt; les fichiers générés ;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;help&lt;/code&gt; qui affiche une aide générée automatiquement pour la commande &lt;code&gt;make&lt;/code&gt;
  (si je ne dis pas de bêtise, cette commande est issue à la base &lt;a href="https://marmelab.com/blog/2016/02/29/auto-documented-makefile.html"&gt;de chez
  Marmelab&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Avec ça, j’ai donc désormais un site disponible à l’adresse &lt;a href="http://next.marienfressinaud.fr/"&gt;next.marienfressinaud.fr&lt;/a&gt;.
Rien de bien compliqué, mais on a déjà les bases pour la suite.&lt;/p&gt;
&lt;h2&gt;Prochaines étapes&lt;/h2&gt;
&lt;p&gt;La suite d’ailleurs, quelle est-elle ? J’ai déjà noté quelques besoins liés à
l’écriture de cet article :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;j’ai dû dupliquer la structure du HTML depuis le fichier &lt;code&gt;index.html&lt;/code&gt;, si
  cela reste gérable avec deux fichiers, je vais vite avoir envie de factoriser
  mon code ;&lt;/li&gt;
&lt;li&gt;pour l’instant j’ai ajouté le lien vers cet article de blog à l’accueil
  manuellement, ce serait bien si je pouvais automatiser cela ;&lt;/li&gt;
&lt;li&gt;je n’ai pas de flux RSS, ce qui va se révéler nécessaire pour que des
  personnes extérieures s’abonnent au blog ;&lt;/li&gt;
&lt;li&gt;lié à l’ajout d’un flux RSS, je vais devoir dissocier le contenu des articles
  de la structure HTML.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Lorsque cela sera prêt, je pourrai alors aborder des sujets moins techniques
pour expliquer où je veux emmener ce nouveau site.&lt;/p&gt;</content></entry><entry><title>Nouvelle version de Lessy : Ara</title><id>urn:uuid:9d27ceb2-550e-5cbc-9d08-53f9ffa1c258</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/lessy-ara.html" rel="alternate" type="text/html" /><published>2018-09-09T14:35:00+02:00</published><updated>2018-09-09T14:35:00+02:00</updated><content type="html">&lt;p&gt;Quelques jours seulement après l’annonce de &lt;a href="https://marienfressinaud.fr/lessy-aries.html"&gt;la version précédente&lt;/a&gt;,
voici déjà une nouvelle version. Les deux derniers weekends ont été
particulièrement productifs bien que n'abordant pas le cœur de métier de
l’application.&lt;/p&gt;
&lt;p&gt;Pour rappel, Lessy est un gestionnaire de temps destiné à vous aider à mieux
vous organiser en associant à vos tâches des indicateurs clairs sur ce que vous
avez de plus urgent à réaliser (ou abandonner) dans l’immédiat. Un service est
mis à disposition gratuitement sur &lt;a href="https://lessy.yuzu.ovh"&gt;lessy.yuzu.ovh&lt;/a&gt; et le code est
&lt;a href="https://github.com/marienfressinaud/lessy"&gt;hébergé sur GitHub&lt;/a&gt;, le tout sous
&lt;a href="https://github.com/marienfressinaud/lessy/blob/master/LICENSE"&gt;licence libre&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Cette fois-ci, les améliorations ont autant porté sur l’interface que sur
l’architecture technique. Les principales nouveautés d’un point de vue
utilisateur sont :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;la possibilité de réinitialiser son mot de passe en cas d’oubli ;&lt;/li&gt;
&lt;li&gt;la possibilité de renvoyer le mail pour activer son compte ;&lt;/li&gt;
&lt;li&gt;l’ajout d'une page de profil permettant de mettre à jour son identifiant, son
  adresse email et son mot de passe ;&lt;/li&gt;
&lt;li&gt;il est également possible de choisir la langue de l’interface (anglais ou
  français pour le moment) ;&lt;/li&gt;
&lt;li&gt;et la possibilité de supprimer son compte.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Autant vous dire que cela fait un petit paquet de changements.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Écran pour modifier son profil dans Lessy" src="images/lessy/2018-09-09-ara-profile.png" /&gt;&lt;/p&gt;
&lt;p&gt;Au niveau de l’architecture technique, j’ai revu l’organisation des composants
de l’interface qui gèrent l’affichage des pages. Ce fut là aussi un gros
morceau, mais nécessaire pour garder l’application maintenable sur le long
terme. J’envisage d’écrire un article technique pour détailler ma façon de
faire.&lt;/p&gt;
&lt;p&gt;Cette version marque aussi la fin des travaux portant sur les « à-côtés » de
l’application. Je les aurai donc répartis sur deux versions de Lessy, mais en
réalité sur neuf mois à cause de la pause que j’ai prise dans le développement.
Je vais donc désormais pouvoir me reconcentrer sur le cœur de Lessy en
repensant le tableau de bord ainsi que l’accueil des nouveaux
utilisateur·trices. Encore une fois, l’avancement est visible &lt;a href="https://github.com/lessy-community/lessy/projects/9"&gt;sur GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;N’hésitez pas à me faire des retours sur les nouvelles fonctionnalités, comme
elles sont toutes neuves, j’ai peut-être oublié de gérer certains cas
particuliers !&lt;/p&gt;</content></entry><entry><title>Nouvelle version de Lessy : Aries</title><id>urn:uuid:569b3156-a6e0-5aa3-81a9-2e78d7988818</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/lessy-aries.html" rel="alternate" type="text/html" /><published>2018-08-30T17:45:00+02:00</published><updated>2018-08-30T17:45:00+02:00</updated><content type="html">&lt;p&gt;Lessy a connu une période de ralentissement ces derniers mois, due à des
raisons externes (fonctionnement qui me correspond globalement bien, des choses
plus urgentes sur le feu et petit coup de fatigue). Cette pause dans le
développement m’a tout de même permis de prendre un peu de recul sur l’outil et
me permettra ainsi de réorienter certaines fonctionnalités qui existent
aujourd’hui… peut-être. Autant ne pas trop s’avancer sur le sujet.&lt;/p&gt;
&lt;p&gt;Pour rappel, Lessy est un gestionnaire de temps destiné à vous aider à mieux
vous organiser en associant à vos tâches des indicateurs clairs sur ce que vous
avez de plus urgent à réaliser (ou abandonner) dans l’immédiat. Un service est
mis à disposition gratuitement sur &lt;a href="https://lessy.yuzu.ovh"&gt;lessy.yuzu.ovh&lt;/a&gt; et le code est
&lt;a href="https://github.com/marienfressinaud/lessy"&gt;hébergé sur GitHub&lt;/a&gt;, le tout sous
&lt;a href="https://github.com/marienfressinaud/lessy/blob/master/LICENSE"&gt;licence libre&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Dashboard de Lessy" src="images/lessy/2017-11-26-apus-dashboard.png" /&gt;&lt;/p&gt;
&lt;p&gt;Malgré le ralentissement évoqué plus haut, j’ai tout de même avancé un petit
peu sur quelques fonctionnalités, notamment&amp;nbsp;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;une administration basique&amp;nbsp;;&lt;/li&gt;
&lt;li&gt;la possibilité de bloquer les inscriptions&amp;nbsp;;&lt;/li&gt;
&lt;li&gt;l’arrivée de conditions d’utilisation.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Cette dernière fonctionnalité m’a pris plus de temps que prévu, mais je suis
assez fier de ce que j’ai fait. Les conditions en elles-mêmes sont accessibles
sur &lt;a href="https://lessy.yuzu.ovh/terms-of-service"&gt;lessy.yuzu.ovh&lt;/a&gt;. En résumé&amp;nbsp;: je fais du
mieux que je peux, mais je ne m’engage ni sur la qualité, ni sur la pérennité
du service (je ne fais pas ça dans un cadre professionnel). Je m’engage
évidemment à ne pas toucher à vos données personnelles ni à les revendre.&lt;/p&gt;
&lt;p&gt;Pour celles et ceux qui avaient souhaité s’inscrire alors que j’avais fermé les
inscriptions, ces conditions d’utilisation marquent la réouverture du service.
Notez toutefois que je risque de les refermer au-delà d’un certain nombre
d’inscrit·es (mais je ferai du tri avant dans les comptes non activés ou dans
ceux qui n’auront pas accepté les conditions d’utilisation d’ici 6 mois).&lt;/p&gt;
&lt;p&gt;Les prochains développements porteront sur un espace pour modifier son profil
et sur la possibilité de choisir la langue de l’interface (enfin&amp;nbsp;!). Vous
pouvez suivre l’avancement sur &lt;a href="https://github.com/lessy-community/lessy/projects/9"&gt;le projet GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Je remercie encore une fois celles et ceux qui parlent de Lessy autour
d’elleux, qui l’utilisent ou qui me suggèrent des améliorations. C’est aussi
ça, contribuer&amp;nbsp;:). Et merci à Sarah pour avoir pris le temps de relire mes
conditions d’utilisation et Erwan pour… avoir essayé&amp;nbsp;;).&lt;/p&gt;</content></entry><entry><title>Un homme sans rêve</title><id>urn:uuid:a49d874c-4d20-579f-b950-94818dca69d2</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/un-homme-sans-reve.html" rel="alternate" type="text/html" /><published>2018-05-31T00:10:00+02:00</published><updated>2018-05-31T00:10:00+02:00</updated><content type="html">&lt;p&gt;Écrire un bouquin de 50 000 mots en un mois, c’était le défi que je m’étais
fixé en &lt;a href="https://marienfressinaud.fr/en-novembre-cest-nanowrimo.html"&gt;novembre 2014&lt;/a&gt;.
Ces mots, je ne les ai jamais publiés nulle part. Ils étaient pourtant là,
couchés sur de multiples octets, ces 50 000 mots et le défi du
&lt;a href="https://fr.wikipedia.org/wiki/National_Novel_Writing_Month"&gt;NaNoWriMo&lt;/a&gt;
relevé. Mais l’excitation redescendue, les deux pieds à nouveau sur Terre, il
fallait se rendre à l’évidence : ce n’était vraiment pas terrible. Des fautes,
des incohérences, des dialogues pourris, des éléments de l’intrigue avec
lesquels je n’étais pas à l’aise… et même une intrigue pas intrigante pour un
sou !&lt;/p&gt;
&lt;p&gt;Pourtant, au milieu de tout ça il y avait forcément moyen de sauver quelques
meubles. En 50 000 mots, il y a forcément des fulgurances, des choses qui
fonctionnent mieux que d’autres, un ensemble de mots et de phrases qui
« sonnent » bien. C’est en mars 2016 que je relus l’histoire d’&lt;em&gt;Asmara&lt;/em&gt;, avec
beaucoup de recul et que je reprenais un certain plaisir à me plonger dans un
univers que j’avais créé (hey ! C’est pas rien non plus). Un chapitre en
particulier (le dernier écrit) retint mon attention : il y avait matière à en
tirer une mini-nouvelle.&lt;/p&gt;
&lt;p&gt;Quelques relectures et corrections plus tard, elle était prête. Cela m’avait
pris seulement 9 jours à retravailler ce court texte, mais il me fallut deux
ans de plus pour trouver le courage de le publier. Alors voilà, je pose tout ça
là, ignorant si ma nouvelle sera lue ou non. Pour moi il s’agit surtout de
mener un peu plus loin ce que j’ai entamé il y a 3 ans et demi avec le
NaNoWriMo, bien qu’il reste encore beaucoup de chemin à parcourir avant d’en
dévoiler plus sur &lt;em&gt;Asmara&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;La nouvelle se nomme &lt;em&gt;Un homme sans rêve&lt;/em&gt; et est placée sous licence &lt;a href="https://creativecommons.org/licenses/by/4.0/"&gt;CC BY&lt;/a&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="files/Un_homme_sans_reve.pdf"&gt;fichier PDF&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="files/Un_homme_sans_reve.epub"&gt;fichier EPUB&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://framagit.org/marienfressinaud/un-homme-sans-reve"&gt;le dépôt Git&lt;/a&gt;
  (l’historique peut être intéressant si vous vous questionnez sur le processus
  de réécriture)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ce chapitre/nouvelle est en fait une réinterprétation d’un chapitre de
&lt;a href="https://fr.wikipedia.org/wiki/1984_(roman)"&gt;&lt;em&gt;1984&lt;/em&gt;&lt;/a&gt; de Georges Orwell, toute
ressemblance n’est absolument pas fortuite. Le défi lors de cette réécriture
était surtout de travailler les dialogues et l’évolution psychologique du
personnage. Comme la nouvelle s’inscrit dans un contexte plus global, il
subsiste des références au reste de l’histoire que vous ne saisirez
probablement pas. J’ai décidé de les conserver pour me laisser des pistes à
explorer de nouveau lorsque je souhaiterai me replonger dans &lt;em&gt;Asmara&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Je vous souhaite une bonne lecture !&lt;/p&gt;</content></entry><entry><title>Ce qui nous pousse au Libre</title><id>urn:uuid:06496b1d-b820-5b7d-aecb-dfe135e48f3d</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/ce-qui-nous-pousse-au-Libre.html" rel="alternate" type="text/html" /><published>2018-05-01T16:00:00+02:00</published><updated>2018-05-01T16:00:00+02:00</updated><content type="html">&lt;p&gt;Il y a quelques jours, Maiwann proposait dans un article, de &lt;a href="http://maiwann.net/blog/designers-&amp;amp;-logiciels-libres-si-on-collaborait/"&gt;réconcilier
&lt;em&gt;designers&lt;/em&gt; et logiciels libres&lt;/a&gt;.
L’article ne manque pas d’intérêt, ne serait-ce que par ses suggestions
d’actions. Bien que je partage bon nombre des constats, je souhaitais le
« compléter » d’un point de vue de développeur. Je vous propose donc d’entamer
une petite mise en perspective à travers mes expériences personnelles, que ce
soit celles sur &lt;a href="https://freshrss.org"&gt;FreshRSS&lt;/a&gt;, &lt;a href="https://lessy.yuzu.ovh"&gt;Lessy&lt;/a&gt;,
les actions menées au nom de &lt;a href="https://framasoft.org"&gt;Framasoft&lt;/a&gt; ou encore à
travers les écrits que j’ai pu lire à droite à gauche.&lt;/p&gt;
&lt;p&gt;J’ai décidé de découper ces réflexions en une suite de plusieurs articles (sans
me forcer à tenir sur la durée). Et comme l’idée me trottait depuis un moment,
j’en profite pour inaugurer une nouvelle catégorie sur ce blog intitulée
« Libres ? ».&lt;/p&gt;
&lt;p&gt;Le premier sujet que je souhaite aborder en est un que Maiwann n’aborde
quasiment pas : &lt;strong&gt;pourquoi faire du logiciel libre ?&lt;/strong&gt; J’aurais en effet aimé
mieux comprendre ce qui motive des &lt;em&gt;designers&lt;/em&gt; à vouloir contribuer au Libre.
J’essaye donc dans mon article de faire le tour de ce qui peut pousser un
développeur à en faire, sans prétendre être exhaustif.&lt;/p&gt;
&lt;h2&gt;Apprentissage&lt;/h2&gt;
&lt;p&gt;De l’article de Maiwann, la seule référence à une potentielle motivation se
trouve au détour d’un paragraphe :&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Lors de nos études, […] alors que nous cherchons à nous entraîner, sur notre
temps libre ou pour des projets de fin d’année, nous nous plaignons de ne
connaître aucun développeur avec qui co-créer des sites ou logiciels.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Voilà une raison qui devrait parler à bon nombre d’étudiants et d’étudiantes !
Appliquer ce que l’on a pu apprendre en cours et donc, par extension,
&lt;strong&gt;apprendre par la pratique&lt;/strong&gt; est souvent moteur chez les développeurs. J’ai
moi-même développé un certain nombre de programmes avec cette simple
motivation. Par exemple, &lt;a href="https://github.com/marienfressinaud/MINZ"&gt;Minz&lt;/a&gt; fut
ma tentative de comprendre le fonctionnement interne des frameworks web.
FreshRSS a été l’occasion de travailler véritablement en communauté, et donc en
équipe travaillant à distance et asynchrone. &lt;em&gt;Petit aparté&lt;/em&gt; : paraît-il que ce
mode de travail est compliqué à mettre en place dans les boîtes, mais
cela se fait très naturellement sur les projets communautaires ; peut-être y
a-t-il des choses à en tirer ? Sur Lessy, j’ai pu consolider tout un paquet de
connaissances que j’ai ensuite pu proposer et appliquer au boulot. Le logiciel
libre est une formidable source d’apprentissage que je recommande fortement à
toutes et tous.&lt;/p&gt;
&lt;p&gt;Cela étant dit, considérer l’apprentissage comme seul moteur dans le
développement d’un logiciel libre est bien entendu extrêmement réducteur et
j’aurais tendance à dire que ce n’est pas la raison principale (bien qu’il
s’agisse probablement de la porte d’entrée principale pour bon nombre d’entre
nous). Cherchons donc ailleurs d’autres raisons qui nous poussent, nous
développeurs et développeuses, à produire du logiciel libre.&lt;/p&gt;
&lt;h2&gt;Plaisir&lt;/h2&gt;
&lt;p&gt;Dans le prologue du bouquin &lt;a href="https://fr.wikipedia.org/wiki/L%27%C3%89thique_hacker"&gt;&lt;em&gt;L’Éthique hacker&lt;/em&gt;&lt;/a&gt;,
Linus Torvalds explique les motivations des hackers derrière le système
d’exploitation Linux comme ceci :&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;La raison pour laquelle les hackers derrière Linux se lancent dans quelque
chose, c’est qu’ils trouvent ça très intéressant et qu’ils veulent le
partager avec d’autres. Tout d’un coup, vous avez le plaisir parce que vous
faites quelque chose d’intéressant et vous avez aussi le pendant social.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Il nous dit plusieurs choses ici. Tout d’abord, le développement d’un tel
système relève avant tout &lt;strong&gt;du plaisir&lt;/strong&gt;. Et il est vrai qu’on peut se demander
ce qui pousse des milliers de développeurs à partager leurs savoirs et leur
temps, généralement de façon gratuite, si ce n’est le plaisir de le faire ?
D’ailleurs Pekka Himanen (l’auteur du bouquin) cite un peu plus loin Éric
Raymond, à l’origine de la popularisation du terme « open source » (j’aurai
l’occasion de revenir sur ce terme plus tard) :&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;La conception de logiciel et sa mise en œuvre devraient être un art
jubilatoire, et une sorte de jeu haut de gamme. Si cette attitude te paraît
absurde ou quelque peu embarrassante, arrête et réfléchis un peu. Demande-toi
ce que tu as pu oublier. Pourquoi développes-tu un logiciel au lieu de faire
autre chose pour gagner de l’argent ou passer le temps ?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;On y retrouve la notion de plaisir à travers le « jeu haut de gamme ». Je
prends souvent l’exemple du Sudoku ou de la grille de mots-croisés : il n’y a,
à priori, aucune raison de remplir ces cases de chiffres ou de lettres, si ce
n’est le plaisir de résoudre un problème, parfois complexe. Je trouve
personnellement que le développement de logiciel peut amener à un état de
satisfaction similaire lorsqu’on se trouve face à un problème et qu’on arrive
finalement à le résoudre après plusieurs &lt;del&gt;heures&lt;/del&gt; &lt;del&gt;jours&lt;/del&gt;
semaines de recherche.&lt;/p&gt;
&lt;p&gt;D’un point de vue personnel, j’ai toujours été attiré par les domaines de
« création ». J’ai immédiatement accroché au développement lorsque j’ai
découvert que créer un site web était aussi simple que créer un fichier texte
avec quelques mots dedans. Les balises HTML ? un simple jeu de légo. Le CSS ?
quelques directives de base à connaître et on arrive rapidement à quelque chose
de totalement différent. Un serveur web ? un ordinateur avec un logiciel
spécifique qui tourne dessus. Un bug ? une « chasse » durant laquelle on
déroule le programme qui nous semblait &lt;em&gt;si&lt;/em&gt; logique au moment de l’écrire (mais
qui l’est maintenant beaucoup moins !). Pour moi, la beauté de l’informatique
réside dans sa simplicité et sa logique : il y a un véritable plaisir à
comprendre comment toutes ces petites boîtes s’agencent entre elles et que tout
devient plus clair.&lt;/p&gt;
&lt;h2&gt;Partage&lt;/h2&gt;
&lt;p&gt;Si l’on se tient aux notions d’apprentissage et de plaisir, il n’y a rien qui
distingue le logiciel libre du logiciel propriétaire. Vous pouvez très bien
apprendre et éprouver du plaisir en développant du code fermé. Il nous faut
revenir à la citation de Torvalds pour commencer à percevoir ce qui les
différencie :&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[…] ils veulent le partager avec d’autres.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Le &lt;strong&gt;partage&lt;/strong&gt; : on a là une valeur fondamentale du logiciel libre qui ne
trouve pas véritablement son pendant du côté du logiciel propriétaire. Bien que
j’ai plus de mal à identifier clairement ce qui peut motiver l’être humain à
partager ses savoirs, c’est quelque chose que je ressens effectivement. Cet
aspect coopératif — Torvalds parle d’un « pendant social » — peut créer ou
renforcer des liens avec d’autres personnes ce qui rend cette activité
profondément humaine.&lt;/p&gt;
&lt;p&gt;Partager, c’est donc transmettre. Transmettre à une communauté, donner les clés
pour que celle-ci soit indépendante. Partager ses savoirs qui permettront
peut-être à d’autres de bâtir autre chose par-dessus. Cela permet aussi de
créer du lien humain, rencontrer des personnes et ouvrir ses perspectives en
créant son propre réseau. C’est aussi s’offrir un coin de canapé quand on
voyage (coucou &lt;a href="https://f.a80.fr/profile/alkarex"&gt;Alex&lt;/a&gt; 👋). Je me suis rendu
compte assez récemment de ce que m’offrait aujourd’hui cette décision en IUT de
partager les petits programmes que je pouvais développer sur mon temps libre.
La liberté n’est pas que celle du code.&lt;/p&gt;
&lt;p&gt;Il y a certainement une forme de fierté à avoir exploré un domaine le premier,
ou développé une application que d’autres vont utiliser (« Quoi ? Ce que j’ai
fabriqué de mes propres mains t’est &lt;em&gt;aussi&lt;/em&gt; utile ? »). Si cette fierté est par
essence un peu narcissique (je suis toujours un peu pénible lorsque je suis
cité &lt;a href="https://www.nextinpact.com/news/106286-intelligence-social-freshrss-veut-redonner-coup-fouet-aux-agregateurs-flux.htm"&gt;chez NextInpact&lt;/a&gt;
ou chez &lt;a href="https://korben.info/lessy-gestionnaire-de-temps-ethique-respectueux.html"&gt;Korben&lt;/a&gt; 😇),
elle est aussi bénéfique car elle encourage à rendre son travail public et
donc… partager encore.&lt;/p&gt;
&lt;h2&gt;Éthique&lt;/h2&gt;
&lt;p&gt;On retrouve aussi cette notion de partage dans les écrits de Richard Stallman
lorsqu’&lt;a href="https://www.gnu.org/philosophy/open-source-misses-the-point.fr.html"&gt;il nous parle des quatre libertés&lt;/a&gt;
du logiciel :&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Elles sont essentielles, pas uniquement pour les enjeux individuels des
utilisateurs, mais parce qu’elles favorisent le partage et la coopération qui
fondent la solidarité sociale.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Ces mots, pris du point de vue de Stallman, sont bien évidemment à interpréter
sous &lt;strong&gt;la dimension éthique&lt;/strong&gt; (et donc &lt;strong&gt;politique&lt;/strong&gt;) du logiciel libre, ce qui
n’est pas forcément le cas de Torvalds (je ne saurais néanmoins l’affirmer).
Puisque Stallman est à l’origine du mouvement du logiciel libre, on ne peut
évidemment pas enlever l’éthique de son équation ou alors vous obtenez de
l’open source (comme il l’explique dans l’article cité plus haut).
On peut toutefois raisonnablement penser que les partisans du logiciel libre
sont moins nombreux que ceux de l’open source, ce que j’explique par une peur
ou un désintérêt envers cet objet politisé.&lt;/p&gt;
&lt;p&gt;Je trouve toutefois dommage de ne pas plus s’y intéresser. En effet, la
dimension éthique aide à répondre à une question que beaucoup de personnes
peuvent se poser : « &lt;strong&gt;ce que je fais au quotidien a-t-il du sens ?&lt;/strong&gt; ».
Stallman y répond par la défense et le respect des utilisateurs et
utilisatrices :&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Le mouvement du logiciel libre fait campagne pour la liberté des utilisateurs
de l’informatique depuis 1983.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Ou encore :&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Pour qu’on puisse dire d’un logiciel qu’il sert ses utilisateurs, il doit
respecter leur liberté. Que dire s’il est conçu pour les enchaîner ?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Si je souhaitais conclure par cet argument, c’est parce qu’il aide à boucler la
boucle avec l’article de Maiwann. En effet, en tant qu’&lt;em&gt;UX designer&lt;/em&gt;, elle va
avoir à cœur de répondre aux besoins de ses utilisateur·trices et donc
d’imaginer des mécanismes pour rendre l’outil le plus &lt;strong&gt;utilisable&lt;/strong&gt; et
&lt;strong&gt;accessible&lt;/strong&gt; possible. Aujourd’hui il me semble percevoir dans cette
communauté un mouvement de prise de conscience que ces mécanismes doivent
&lt;strong&gt;respecter&lt;/strong&gt; (on y revient !) les personnes utilisant le logiciel. Cela est
superbement bien illustré par la vidéo « &lt;a href="https://www.arte.tv/fr/videos/071494-003-A/tr-oppresse-3-10/"&gt;Temps de cerveau disponible&lt;/a&gt; »
(de la série « (Tr)oppressé » que je recommande vivement) dans laquelle un
ancien employé de Google, expert en éthique, témoigne :&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Le but est de capter et d’exploiter au maximum l’attention.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Il l’illustre ensuite par le lancement automatique de l’épisode suivant sur
Netflix et par le défilement infini sur Facebook ou Twitter (incitant de ce
fait à parcourir son fil d’actualité dans son ensemble) ; ces petits riens
qui font que nous revenons sans cesse à ces applications et nous en rendent
dépendant alors qu’elles n’ont d’intérêt que de nous divertir.&lt;/p&gt;
&lt;p&gt;L’un des problèmes que j’identifie aujourd’hui est que le logiciel libre
copie beaucoup (trop) ce qui se fait dans le propriétaire, et en particulier
chez GAFAM et consorts… jusque dans leurs mécanismes nocifs. On peut ici
reprendre l’exemple du mécanisme de défilement infini que l’on retrouve chez
&lt;a href="https://joinmastodon.org/"&gt;Mastodon&lt;/a&gt; ou &lt;a href="https://diasporafoundation.org/"&gt;Diaspora&lt;/a&gt;
(et même sur FreshRSS !). Une certaine forme de dépendance peut donc
s’installer au sein même de logiciels libres.&lt;/p&gt;
&lt;h2&gt;Convergence des buts ?&lt;/h2&gt;
&lt;p&gt;Les &lt;em&gt;designers&lt;/em&gt; peuvent aujourd’hui nous aider, développeurs et développeuses,
à repenser l’éthique de nos logiciels &lt;strong&gt;en replaçant les usages au centre de
nos préoccupations&lt;/strong&gt; et en imaginant et proposant des mécanismes permettant
« d’endiguer » ce flux permanent d’informations qu’il nous faut ingurgiter.&lt;/p&gt;
&lt;p&gt;Elles et ils peuvent aussi nous aider à atteindre véritablement nos
utilisateurs en rendant nos outils utilisables et… utilisés. Car &lt;strong&gt;un logiciel
non utilisable peut-il véritablement être considéré comme Libre ?&lt;/strong&gt; Je ne peux
m’empêcher de faire ici le parallèle avec l’association &lt;a href="http://liberte0.org/"&gt;Liberté 0&lt;/a&gt;
qui a pour objet de « sensibiliser et de promouvoir le numérique libre et
accessible à toutes et tous ». Dans &lt;a href="http://liberte0.org/charte.html"&gt;leur charte&lt;/a&gt;,
il est explicité :&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Les membres du groupe « Liberté 0 » considèrent que la liberté d’exécuter un
programme n’a de sens que si celui-ci est utilisable effectivement.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;L’association est donc dans cette même démarche de promouvoir l’utilisabilité
des logiciels, au même titre que les &lt;em&gt;UX designers&lt;/em&gt; (mais sous le prisme de
l’accessibilité).&lt;/p&gt;
&lt;p&gt;N’y aurait-il pas ici une convergence des buts ? N’existe-t-il pas un lieu où
nous pourrions nous regrouper tou·tes ensemble pour imaginer des outils autres que
ceux issus du « &lt;a href="https://framablog.org/2016/07/04/les-nouveaux-leviathans-i-histoire-dune-conversion-capitaliste-a/"&gt;capitalisme de surveillance&lt;/a&gt; » ?&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Merci à &lt;a href="http://maiwann.net/"&gt;Maiwann&lt;/a&gt; pour sa relecture attentive !&lt;/p&gt;</content></entry><entry><title>Nouvelle version de Lessy : Aquila</title><id>urn:uuid:e781d64d-64b3-521f-b6e0-ed8433dc2e38</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/lessy-aquila.html" rel="alternate" type="text/html" /><published>2018-01-27T17:35:00+01:00</published><updated>2018-01-27T17:35:00+01:00</updated><content type="html">&lt;p&gt;J’ai désormais adopté un petit rythme de croisière quant aux sorties des
nouvelles versions de Lessy et je peux donc annoncer la sortie de la version
Aquila.&lt;/p&gt;
&lt;p&gt;Pour rappel, Lessy est un gestionnaire de temps destiné à vous aider à mieux
vous organiser en associant à vos tâches des indicateurs clairs sur ce que vous
avez de plus urgent à réaliser (ou abandonner) dans l’immédiat. Un service est
mis à disposition gratuitement sur &lt;a href="https://lessy.yuzu.ovh"&gt;lessy.yuzu.ovh&lt;/a&gt; et le code est
&lt;a href="https://github.com/marienfressinaud/lessy"&gt;hébergé sur GitHub&lt;/a&gt;, le tout sous
&lt;a href="https://github.com/marienfressinaud/lessy/blob/master/LICENSE"&gt;licence libre&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Cette nouvelle version n’apporte pas énormément de nouvelles fonctionnalités
mais le mois de janvier a tout de même été chargé pour moi.&lt;/p&gt;
&lt;p&gt;Tout d’abord, l’amélioration phare de cette nouvelle version est l’arrivée d’un
mécanisme pour synchroniser différents navigateurs : concrêtement, si vous
modifiez une tâche dans un navigateur, cette modification sera aussitôt
répercutée si vous avez ouvert Lessy dans un autre navigateur. Cette
fonctionnalité est encore expérimentale et elle n’est pas aussi aboutie que ce
que je souhaiterais, mais elle impliquait un gros changement dans
l’infrastructure du projet (un serveur Redis est maintenant nécessaire). Je
souhaitais donc m’en occuper avant d’aller plus loin dans le développement.&lt;/p&gt;
&lt;p&gt;Ce qui m’a le plus occupé au final est le soudain coup de projecteur qu’a reçu
le projet au début du mois avec la parution d’&lt;a href="https://korben.info/lessy-gestionnaire-de-temps-ethique-respectueux.html"&gt;un article chez Korben&lt;/a&gt;.
Celui-ci n’a pas eu pour effet de faire tomber mon serveur (ouf !) mais a
permis une augmentation du nombre de retours ainsi qu’une apparition temporaire
dans le &lt;em&gt;trending&lt;/em&gt; Ruby de GitHub. Les retours que j’ai eu ont été
particulièrement intéressants puisqu’ils m’ont fait réaliser que je suis encore
très loin d’avoir l’outil idéal que je souhaite développer et qu’il y a encore
beaucoup à faire malgré le travail réalisé jusqu’à maintenant. Les efforts à
fournir vont aussi bien se situer au niveau des fonctionnalités, de l’ergonomie
ou encore de l’accueil au sein de la communauté.&lt;/p&gt;
&lt;p&gt;Je suis tout de même ravi qu’au bout de seulement un an le projet obtienne un
tel coup de projecteur, ça avait été plus compliqué pour &lt;a href="https://freshrss.org"&gt;FreshRSS&lt;/a&gt;
par exemple (qui par contre vit très bien aujourd’hui sans mon implication).
J’espère que l’intérêt manifesté saura se transformer en contributions actives
et régulières ! Merci au passage à toutes celles et tous ceux qui m’ont fait
des retours et/ou ont contribué d’une façon ou d’une autre (commentaires dans
les tickets GitHub, ouverture de &lt;em&gt;pull requests&lt;/em&gt;, etc.)&lt;/p&gt;
&lt;p&gt;La prochaine version verra l’apparition d’une administration afin de me
permettre de mieux surveiller ce qu’il se passe sur le serveur. Aujourd’hui il
y a quelques 2200 comptes sur lessy.yuzu.ovh, dont la moitié ont été activés. J’en
profite pour rappeler l’existence d’&lt;a href="https://liberapay.com/Lessy"&gt;une page sur Liberapay&lt;/a&gt;
si vous souhaitez participer aux frais du serveur (merci au passage aux
trois valeureux donateurs actuels).&lt;/p&gt;
&lt;p&gt;J’ai aussi ouvert &lt;a href="https://framateam.org/lessy/channels/town-square"&gt;un espace sur Framateam&lt;/a&gt;
si vous souhaitez venir discuter du projet directement avec moi. J’aimerais que
les échanges sur celui-ci se déroulent essentiellement en anglais puisque c’est
la langue par défaut que j’ai choisi pour le projet, mais un canal pour les
Français a été ouvert donc n’hésitez pas à venir et vous présenter !&lt;/p&gt;
&lt;p&gt;Pour terminer, je remercie &lt;a href="https://social.tcit.fr/@Gavy"&gt;Gavy&lt;/a&gt; pour avoir
ouvert une notice &lt;a href="https://framalibre.org/content/lessy"&gt;sur Framalibre à propos de Lessy&lt;/a&gt;,
non seulement ça permet de faire vivre ce projet historique de Framasoft, mais
en plus ça permet de faire encore un peu plus connaître Lessy :).&lt;/p&gt;</content></entry><entry><title>Nouvelle version de Lessy : Aquarius</title><id>urn:uuid:a6598393-50ac-516c-88a7-273b03b3ffb4</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/lessy-aquarius.html" rel="alternate" type="text/html" /><published>2017-12-29T12:15:00+01:00</published><updated>2017-12-29T12:15:00+01:00</updated><content type="html">&lt;p&gt;À peine plus d’un an après l’écriture des premières lignes de code de
l’application, je sors la septième version de Lessy. Nom de code : Aquarius.&lt;/p&gt;
&lt;p&gt;Pour rappel, Lessy est un gestionnaire de temps destiné à vous aider à mieux
vous organiser en associant à vos tâches des indicateurs clairs sur ce que vous
avez de plus urgent à réaliser (ou abandonner) dans l’immédiat. Un service est
mis à disposition gratuitement sur &lt;a href="https://lessy.yuzu.ovh"&gt;lessy.yuzu.ovh&lt;/a&gt; et le code est
&lt;a href="https://github.com/marienfressinaud/lessy"&gt;hébergé sur GitHub&lt;/a&gt;, le tout sous
&lt;a href="https://github.com/marienfressinaud/lessy/blob/master/LICENSE"&gt;licence libre&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;La principale amélioration qui m’a le plus été demandée est la suppression des
contraintes sur les noms des projets : c’est désormais fait ! Il reste des
bricoles à peaufiner pour que ça ne pose plus du tout de soucis mais je verrai
en fonction des retours.&lt;/p&gt;
&lt;p&gt;Ensuite, trois nouveautés liées aux tâches font leur apparition.&lt;/p&gt;
&lt;p&gt;Tout d’abord, les tâches liées à des projets non démarrés ne sont plus listées
dans le backlog : le projet n’étant pas démarré, inutile de s’encombrer
l’esprit avec des tâches qu’on n’a pas besoin de réaliser. Il est toutefois
toujours possible de les planifier pour le jour même en se rendant dans le
projet, auquel cas celles-ci reprendront le comportement initial. Toutefois,
afin de ne pas oublier ces tâches, un indicateur a été ajouté à côté des
projets non démarrés.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Un projet (Lessy) non démarré avec à sa droite le nombre de tâches associées" src="images/lessy/2017-12-29-aquarius-inbox-project.png" /&gt;&lt;/p&gt;
&lt;p&gt;La seconde nouveauté est que l’on peut désormais changer le projet auquel est
attachée une tâche. Très utile si comme moi vous oubliez de créer vos tâches à
partir des projets. La dernière nouveauté est la possibilité de transformer une
tâche en projet en deux clics. Si vous vous rendez compte que vos tâches
sont plus compliquées que prévu, c’est sans doute qu’il faut les redécouper ;
vous pourrez maintenant transformer celles-ci en projet puis leur créer des
tâches associées ! Ces deux fonctionnalités sont disponibles à partir du menu
contextuel, à droite des tâches.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Le menu des tâches avec deux nouvelles options : &amp;quot;Attach to a project&amp;quot; et &amp;quot;Transform in project&amp;quot;" src="images/lessy/2017-12-29-aquarius-task-popover.png" /&gt;&lt;/p&gt;
&lt;p&gt;D’autres améliorations mineures sont aussi disponibles, le tout est détaillé
dans &lt;a href="https://github.com/marienfressinaud/lessy/releases/tag/aquarius"&gt;l’annonce sur GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Suite à la sortie de la version précédente (Apus), j’avais annoncé avoir ouvert
&lt;a href="https://liberapay.com/Lessy"&gt;un compte sur Liberapay&lt;/a&gt;. Suite à cette annonce,
trois personnes m’ont fait le plaisir de participer aux dépenses liées à Lessy
à hauteur de 1,35 € par semaine. Merci à elles et eux ! Plus que 65 centimes
par semaine et les frais du serveur + nom de domaine seront couverts :).&lt;/p&gt;
&lt;p&gt;La prochaine version (&lt;a href="https://github.com/marienfressinaud/lessy/projects/5"&gt;Aquila&lt;/a&gt;),
ne sera pas énorme mais devrait voir l’amélioration de la synchronisation
backend - frontend. Plus besoin de rafraîchir votre navigateur sur PC si vous
avez modifié des choses depuis votre tablette, tout devrait se faire
automatiquement !&lt;/p&gt;</content></entry><entry><title>Lessy Apus</title><id>urn:uuid:1abae4da-8b69-5276-9e31-3431816a0a04</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/lessy-apus.html" rel="alternate" type="text/html" /><published>2017-11-26T17:00:00+01:00</published><updated>2017-11-26T17:00:00+01:00</updated><content type="html">&lt;p&gt;Après un mois de travail il est enfin temps pour moi de sortir cette nouvelle
version&amp;nbsp;: &lt;strong&gt;Lessy Apus&lt;/strong&gt;&amp;nbsp;!&lt;/p&gt;
&lt;p&gt;&lt;img alt="Dashboard de Lessy Apus" src="images/lessy/2017-11-26-apus-dashboard.png" /&gt;&lt;/p&gt;
&lt;p&gt;Je dois bien avouer que je ne savais pas trop où je mettais les pieds en
démarrant cette refonte complète. J’ai failli me contenter de publier un guide
de design et de faire la migration des différents composants au fil de l’eau.
Mais un problème s’est rapidement posé. Souhaitant que le guide reste au plus
proche du code, celui-ci a été développé directement au sein de Lessy. De ce
fait, modifier le guide signifiait aussi modifier le reste de l’application. De
fil en aiguille, je me suis ainsi trouvé à tout redévelopper.&lt;/p&gt;
&lt;p&gt;Travail de longue haleine s’il en est, la refonte a consisté à&amp;nbsp;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;créer un guide accessible sur &lt;a href="https://lessy.yuzu.ovh/design"&gt;lessy.yuzu.ovh/design&lt;/a&gt;&amp;nbsp;;&lt;/li&gt;
&lt;li&gt;réécrire (tous) les composants de base pour qu’ils correspondent aux règles
  édictées dans le guide&amp;nbsp;;&lt;/li&gt;
&lt;li&gt;réorganiser le code pour le rendre plus modulaire et plus maintenable&amp;nbsp;;&lt;/li&gt;
&lt;li&gt;mettre en place des tests automatisés pour l’interface (très basiques pour le
  moment)&amp;nbsp;;&lt;/li&gt;
&lt;li&gt;revoir un certain nombre d’éléments ergonomiques (des boutons plus
  explicites, une meilleure gestion des erreurs, des comportements moins
  surprenants, etc.)&amp;nbsp;;&lt;/li&gt;
&lt;li&gt;corriger de nouveaux bugs ou identifier des problèmes de performance (sinon
  c’est pas marrant)&amp;nbsp;;&lt;/li&gt;
&lt;li&gt;repenser la page d’accueil pour la rendre plus accueillante et présenter le
  projet.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Il existe toujours des éléments dont je ne suis pas entièrement satisfait, mais
l’essentiel est là, le reste suivra durant les prochains jours. Je suis en tout
cas extrêmement satisfait d’avoir désormais un guide de design qui rend ce
dernier plus facile à faire évoluer et rend plus difficile de sortir des clous.&lt;/p&gt;
&lt;p&gt;J’ai profité de sortir cette version pour ouvrir &lt;a href="https://liberapay.com/Lessy"&gt;un compte sur Liberapay&lt;/a&gt;
afin d’essayer de rembourser au moins les frais de serveur + nom de domaine
puis éventuellement pouvoir plus tard me dégager un peu plus de temps pour le
projet. Il y a mine de rien plus de 250 comptes ouverts sur lessy.yuzu.ovh dont
quelques 65 activés, sachant que je suis très loin encore d’avoir mis en place
tous les outils pour assurer un service satisfaisant. De la supervision&amp;nbsp;?
Non. Des conditions générales d’utilisation&amp;nbsp;? Ah ah&amp;nbsp;! Des
backups&amp;nbsp;? Ah ça oui&amp;nbsp;! Et ils fonctionnent&amp;nbsp;? Heuuu… Vous voyez
l’idée donc.&lt;/p&gt;
&lt;p&gt;Le service est toujours disponible sur &lt;a href="https://lessy.yuzu.ovh"&gt;lessy.yuzu.ovh&lt;/a&gt;, il reste
ouvert et gratuit pour le moment, mais sans doute plus pour très longtemps
donc. Le code reste &lt;a href="https://github.com/marienfressinaud/lessy"&gt;hébergé sur GitHub&lt;/a&gt;
et toujours (et à jamais) &lt;a href="https://github.com/marienfressinaud/lessy/blob/master/LICENSE"&gt;sous licence libre&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Pour la prochaine version (&lt;a href="https://github.com/marienfressinaud/lessy/projects/4"&gt;Aquarius&lt;/a&gt;),
je reviendrai à du développement dans le dur en améliorant le lien entre les
tâches et les projets.&lt;/p&gt;</content></entry><entry><title>Lessy Antlia</title><id>urn:uuid:c2db86b6-a7c9-5842-9ac7-0d29747778bd</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/lessy-antlia.html" rel="alternate" type="text/html" /><published>2017-10-31T13:30:00+01:00</published><updated>2017-10-31T13:30:00+01:00</updated><content type="html">&lt;p&gt;J’expliquais dans &lt;a href="https://marienfressinaud.fr/project-zero-devient-lessy.html"&gt;mon article du 8 octobre&lt;/a&gt;
que je souhaitais que Lessy soit un projet s’adressant à une large portion de
la population non-geek. Pour cela, je voulais le rendre plus accueillant et
plus communautaire. C’est pourquoi je suis très fier d’annoncer la sortie de
Lessy Antlia (le nom de cette nouvelle version). Au menu, énormément de
documentation.&lt;/p&gt;
&lt;p&gt;J’ai passé les dernières semaines à travailler les valeurs que je voulais
défendre avec Lessy. Après avoir dessiné, trié et organisé toutes les idées que
j’avais en tête, j’ai abouti à une première version de la vision de Lessy (en
anglais)&amp;nbsp;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Lessy is a time manager application built upon strong principles. It is
designed to be as &lt;strong&gt;intuitive and inclusive&lt;/strong&gt; as possible. Its goal is to
return people their &lt;strong&gt;power to manage time&lt;/strong&gt;, instil &lt;strong&gt;self-confidence&lt;/strong&gt; and
challenge their &lt;strong&gt;capacity to question themselves&lt;/strong&gt;. It is built by a
&lt;strong&gt;diverse and welcoming community&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;On peut traduire cela par&amp;nbsp;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Lessy est un gestionnaire de temps basé sur des principes forts. Il est
conçu pour être aussi &lt;strong&gt;intuitif et inclusif&lt;/strong&gt; que possible. Son objectif est
de redonner à ses utilisateurs et utilisatrices &lt;strong&gt;leur capacité à gérer leur
temps&lt;/strong&gt;, &lt;strong&gt;leur confiance en eux&lt;/strong&gt; et &lt;strong&gt;leur capacité à se remettre en
question&lt;/strong&gt;. Il est développé par &lt;strong&gt;une communauté accueillante et
diversifiée&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Cette vision est donnée en préambule &lt;a href="https://github.com/marienfressinaud/lessy/blob/master/README.md"&gt;du fichier &lt;code&gt;README&lt;/code&gt; de Lessy&lt;/a&gt;
et est immédiatement suivi d’une précision&amp;nbsp;: toute fonctionnalité
développée, toute discussion que nous avons au sein de la communauté, toute
décision que nous prenons doit aller dans le sens de cette vision.&lt;/p&gt;
&lt;p&gt;Voilà donc pour la mise en bouche. Je regrette souvent le manque de direction
dans les projets communautaires qui mène bien souvent à des logiciels qui font
beaucoup de choses mais qui manquent de personnalité. Avec Lessy, je veux
donner un cap au logiciel et mes engagements personnels transparaissent dans
cette vision. Lorsque j’ai commencé à développer cette application, c’était
pour me redonner la main sur le temps qui m’échappait, alors pourquoi ne pas
complètement l’assumer jusque dans l’ADN de Lessy&amp;nbsp;?&lt;/p&gt;
&lt;p&gt;On m’a demandé l’autre jour en quoi Lessy est-il éthique. J’étendrais la
question à en quoi Lessy correspond aujourd’hui à la vision que je viens
de donner. Et c’est vrai qu’en utilisant Lessy on voit difficilement une
application éthique, inclusive, redonnant un peu de pouvoir à ses utilisateurs
et utilisatrices&amp;nbsp;; tout au plus une todo-list un peu originale. Et c’est
effectivement le défi que je me donne pour les mois à venir&amp;nbsp;: faire
transparaître la vision dans l’interface. Cependant, je ne pense pas être
capable de faire cela à moi seul et c’est pourquoi je voulais rapidement me
concentrer sur la documentation communautaire. Cette documentation contient
donc désormais&amp;nbsp;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/marienfressinaud/lessy/blob/master/README.md"&gt;le README&lt;/a&gt;,
  véritable porte d’entrée du projet&amp;nbsp;;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/marienfressinaud/lessy/blob/master/CONTRIBUTING.md"&gt;un fichier de contribution&lt;/a&gt;
  expliquant comment participer à Lessy, j’ai pris le soin de lister une
  majorité d’activités ne nécessitant pas de connaissances en développement
  informatique&amp;nbsp;;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/marienfressinaud/lessy/blob/master/CODE_OF_CONDUCT.md"&gt;un code de bonne conduite&lt;/a&gt;
  pour assurer qu’aucun comportement déplacé ne sera &lt;strong&gt;jamais accepté&lt;/strong&gt; au sein
  de cette communauté&amp;nbsp;;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/marienfressinaud/lessy/blob/master/CONTRIBUTORS.md"&gt;une liste des contributeurs&lt;/a&gt;
  pour remercier celles et ceux ayant contribué de près ou de loin au projet.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href="https://github.com/marienfressinaud/lessy/blob/master/docs/index.md"&gt;La documentation technique&lt;/a&gt;
a elle aussi été largement revue pour aborder plus de sujets différents.&lt;/p&gt;
&lt;p&gt;J’espère que tous ces documents sauront attirer une population hétérogène de
contributeurs et contributrices, bien que je ne me fasse pas d’illusion&amp;nbsp;:
il faut désormais que je me bouge pour rendre l’application réellement
attrayante.&lt;/p&gt;
&lt;p&gt;Tout cela m’a pris beaucoup de temps à rédiger, surtout que tout a été fait en
anglais alors que ce n’est pas ma langue de prédilection. J’ai fait ce choix
volontairement en me disant qu’il serait plus facile de trouver des personnes
souhaitant contribuer en visant large qu’en visant un public uniquement
francophone. De plus, j’ai le sentiment que les Français·e·s sont de plus en
plus à l’aise avec l’anglais. Seul l’avenir me le dira&amp;nbsp;!&lt;/p&gt;</content></entry><entry><title>Lessy : versions et itérations</title><id>urn:uuid:c36929ef-c2ec-5a3b-b052-7fce805a8031</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/lessy-versions-et-iterations.html" rel="alternate" type="text/html" /><published>2017-10-29T10:00:00+01:00</published><updated>2017-10-29T10:00:00+01:00</updated><content type="html">&lt;p&gt;Je me suis intéressé ces derniers jours au système de sortie des nouvelles
versions de &lt;a href="https://github.com/marienfressinaud/lessy"&gt;Lessy&lt;/a&gt;. Cela peut
paraître étonnant, mais décider d’un tel système est parfois compliqué et pose
plusieurs problèmes.&lt;/p&gt;
&lt;p&gt;Pour commencer, on peut se poser la question «&amp;nbsp;pourquoi versionner&amp;nbsp;?&amp;nbsp;».
J’y vois personnellement quatre intérets en particulier&amp;nbsp;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;montre que le projet vit (&lt;strong&gt;marketing&lt;/strong&gt;)&amp;nbsp;;&lt;/li&gt;
&lt;li&gt;donne une indication sur le niveau de modifications au sein du logiciel
  depuis la version précédente (&lt;strong&gt;dépendances&lt;/strong&gt;)&amp;nbsp;;&lt;/li&gt;
&lt;li&gt;permet de revenir à une version plus ancienne en cas de soucis avec la
  nouvelle (&lt;strong&gt;sécurité&lt;/strong&gt;)&amp;nbsp;;&lt;/li&gt;
&lt;li&gt;donne l’occasion de célébrer quelque chose au sein de la communauté
  (&lt;strong&gt;motivation&lt;/strong&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Lorsque je travaillais encore sur &lt;a href="https://freshrss.org"&gt;FreshRSS&lt;/a&gt;, nous nous
étions souciés de la question de la visibilité. Nous avions alors trois
versions distinctes&amp;nbsp;: une stable, sortant à intervalles plutôt longs, la
bêta qui sortait tous les… hum… deux mois (?) et la version de développement.
Nous avions décidé de mettre en avant la version bêta qui était alors moins
testée que la version stable mais qui avait l’avantage de garder les
utilisateurs accrochés à «&amp;nbsp;l’actualité&amp;nbsp;» de FreshRSS. Ce système
avait toutefois &lt;strong&gt;le désavantage d’être lourd à maintenir&lt;/strong&gt;. Je souhaitais par
conséquent un système plus simple pour Lessy tout en continuant de mettre en
avant le travail quotidien effectué.&lt;/p&gt;
&lt;p&gt;Concernant le deuxième point, à savoir que le versionnage donne une indication
sur le niveau de modifications depuis la version précédente, je pense
évidemment au système «&amp;nbsp;&lt;a href="http://semver.org/"&gt;semantic versioning&lt;/a&gt;&amp;nbsp;».
Si ce système possède &lt;strong&gt;un intéret évident dans le cas de dépendances&lt;/strong&gt; (ex. le
logiciel A dépend du logiciel B dans sa version X), je ne le vois pas dans le
cas d’un logiciel en «&amp;nbsp;bout de chaine&amp;nbsp;» tel que Lessy. C’est pourquoi
je suis parti sur un système de nommage totalement différent.&lt;/p&gt;
&lt;p&gt;La raison consistant à donner des numéros de version pour permettre de revenir
en arrière en cas de soucis me paraît évidemment légitime bien que le cas se
présente à mon avis de façon assez rare.&lt;/p&gt;
&lt;p&gt;Enfin, sortir une nouvelle version est loin d’être uniquement une tâche
technique. Il s’agit avant tout de &lt;strong&gt;fêter une nouvelle étape franchie dans le
développement&lt;/strong&gt; et de marquer d’une pierre blanche l’avancement pour pouvoir
constater plus tard tout le chemin parcouru. Célébrer une nouvelle version,
&lt;strong&gt;ça motive énormément&lt;/strong&gt;&amp;nbsp;!&lt;/p&gt;
&lt;p&gt;Concrêtement, comment cela va-t-il se passer pour Lessy&amp;nbsp;?&lt;/p&gt;
&lt;p&gt;L’ensemble des tâches à effectuer (fonctionnalités, tâches techniques,
corrections de bugs, etc.) sont listées en vrac dans &lt;a href="https://github.com/marienfressinaud/lessy/projects"&gt;&lt;strong&gt;les tickets GitHub&lt;/strong&gt;&lt;/a&gt;,
ce qui me sert par conséquent de boite d’entrée. Ces tâches sont ensuite triées
par petits groupes &lt;strong&gt;au sein d’itérations&lt;/strong&gt; représentées par &lt;a href="https://github.com/marienfressinaud/lessy/projects"&gt;les projets
GitHub&lt;/a&gt;. Les tâches d’une
itération forment un ensemble de fonctionnalités ou tâches techniques
&lt;strong&gt;similaires&lt;/strong&gt; et leur temps de développement total effectif ne doit pas être
excessif (je me fixe 2 ou 3 semaines comme maximum). Ces itérations permettent
ainsi de dessiner une pseudo feuille de route du projet. Et comme chacune
d’entre elles est nommée (&lt;a href="https://fr.wikipedia.org/wiki/Liste_des_constellations"&gt;d’après les constellations astronomiques&lt;/a&gt;),
&lt;strong&gt;la fin d’une itération donne son nom à une nouvelle version de Lessy&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Ainsi, des quatre points que je listais plus haut, seule la problématique des
dépendances n’est pas du tout adressée. Pour les trois autres&amp;nbsp;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;marketing&amp;nbsp;: des versions sortent régulièrement et leurs noms sont plus
  sympas qu’un simple nombre&amp;nbsp;;&lt;/li&gt;
&lt;li&gt;sécurité&amp;nbsp;: revenir à une version antérieure est évidemment toujours
  possible, renforcé par le fait que chaque «&amp;nbsp;commit&amp;nbsp;» dans
  «&amp;nbsp;master&amp;nbsp;» peut être considéré comme stable&amp;nbsp;;&lt;/li&gt;
&lt;li&gt;motivation&amp;nbsp;: savoir qu’une itération est courte par principe permet de
  savoir qu’à la fin du mois je pourrais éventuellement passer à autre chose.
  De plus sortir une version est un processus relativement simple.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Pour terminer, si j’ai choisi de nommer les versions de Lessy par les noms des
constellations astronomiques, c’est avant tout parce que je cherchais un
système de nommage original permettant de penser à autre chose qu’à seulement
du code. Comme lever le nez du clavier ne suffit pas toujours à se changer les
idées, je me disais que le lever vers le ciel serait une bonne idée.&lt;/p&gt;</content></entry><entry><title>Project Zero devient Lessy</title><id>urn:uuid:fee20e38-4a84-524d-afe9-075dc43bd1ab</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/project-zero-devient-lessy.html" rel="alternate" type="text/html" /><published>2017-10-08T21:00:00+02:00</published><updated>2017-10-08T21:00:00+02:00</updated><content type="html">&lt;p&gt;Il y a quelques jours, j’ai annoncé sur Mastodon que Project Zero devenait
officiellement Lessy, il était temps je l’officialise aussi sur ce blog. La
raison est multiple et je vais essayer de la détailler ici.&lt;/p&gt;
&lt;p&gt;Pour rappel, Lessy (donc) est un gestionnaire de temps à base de gestion de
projets et de liste de tâches.&lt;/p&gt;
&lt;p&gt;Tout d’abord, cela fait maintenant neuf mois (clairement pas à plein
temps&amp;nbsp;!) que je travaille sur ce projet. Cela me prouve que je suis
motivé par son développement, d’autant plus que j’ai tout juste gratté les
fonctionnalités dont j’ai envie/besoin. Project Zero m’est devenu au fil des
mois &lt;strong&gt;un outil indispensable&lt;/strong&gt;. J’en parlerai probablement dans un autre
article, mais en très bref, j’ai réussi grâce à lui à démarrer (et mener à
bien) plusieurs projets que je laissais trainer depuis des années. Aussi,
depuis mai, ma liste de tâches n’en contient plus datant de plus de deux
semaines, ce qui est une grande victoire pour moi&amp;nbsp;!&lt;/p&gt;
&lt;p&gt;De l’usage de cet outil, j’en ai tiré un tas d’idées un peu en vrac et j’avais
besoin de remettre un peu d’ordre dans tout cela. C’est pourquoi j’ai voulu
faire appel à une personne sensible à ma démarche et qui pourrait m’apporter un
regard extérieur. J’ai eu la chance le mois dernier d’avoir les retours et
idées de la part de &lt;a href="http://www.mcpaccard.com/"&gt;Marie-Cécile Paccard&lt;/a&gt; qui est,
en &lt;del&gt;deux&lt;/del&gt; quatre mots, UX designer à Lyon. Cela a eu pour effet de
rediriger mes efforts vers une toute autre direction… pour le mieux&amp;nbsp;! En
effet, nous avons commencé à identifer ensemble une liste de valeurs et de
«&amp;nbsp;missions&amp;nbsp;» que pouvait se donner Project Zero. J’ai ensuite
continué de mon côté pour essayer d’identifier un objectif qui n’est pas encore
totalement défini (le travail est encore en cours). En revanche, j’ai déjà une
bonne vision de l’ensemble et l’un des éléments qui est revenu plusieurs fois
est &lt;strong&gt;la notion de réduction de la «&amp;nbsp;charge cognitive&amp;nbsp;»&lt;/strong&gt;. Ce sera en
effet l’un des points fondamentaux qui dirigeront les développements futurs du
projet. J’y reviendrai en détails dans un futur article.&lt;/p&gt;
&lt;p&gt;En parallèle de ce travail, je me suis rendu compte qu’il était essentiel que
j’obtienne plus de retours, plus variés, afin de faire émerger d’autres besoins
essentiels. Il est important pour moi que Project Zero soit utile à une portion
importante de la population non-geek, j’ai donc pour objectif d’orienter mes
prochaines actions pour rendre le projet &lt;strong&gt;plus accueillant, plus
communautaire&lt;/strong&gt;. C’est pourquoi les deux prochaines «&amp;nbsp;itérations&amp;nbsp;»
(j’y reviendrai aussi) seront orientées vers une documentation plus aboutie
pour les nouveaux venus et une interface plus accueillante. Dans un tel
contexte, le nom devenait donc important pour ne pas rebuter les gens.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Project Zero devient donc Lessy.&lt;/strong&gt; Le nom ne me plaisait pas depuis le
début&amp;nbsp;: je l’avais plutôt utilisé comme nom de code, signifiant qu’il
faudrait que je commence par développer celui-ci avant d’attaquer un autre
projet. Il était clair depuis le début qu’il ne serait pas définitif. En
devenant Lessy, je souhaite faire passer la notion de «&amp;nbsp;moins&amp;nbsp;» (i.e.
&lt;em&gt;less&lt;/em&gt; en anglais)&amp;nbsp;: moins de stress, moins de charge cognitive. Je
souhaite que ce nom soit apaisant en quelque sorte. De plus, Lessy est un nom
particulièrement court, qui se retient et qui n’est quasiment pas utilisé
aujourd’hui ce qui permettra d’en faciliter le référencement sur Internet.&lt;/p&gt;
&lt;p&gt;Le nouveau dépôt de code est toujours sur GitHub (&lt;a href="https://github.com/marienfressinaud/lessy"&gt;github.com/marienfressinaud/lessy&lt;/a&gt;)
mais le service que je mets (pour le moment, gracieusement) à disposition
&lt;strong&gt;s'est déplacé vers l’adresse &lt;a href="https://lessy.yuzu.ovh"&gt;lessy.yuzu.ovh&lt;/a&gt;&lt;/strong&gt;. Ceci dit, ne
vous jetez pas dessus, c’est toujours aussi moche.&lt;/p&gt;</content></entry><entry><title>Project Zero 0.3</title><id>urn:uuid:63d072b8-86de-53d1-aab8-e89d23e97f28</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/project-zero-0-3.html" rel="alternate" type="text/html" /><published>2017-07-23T21:00:00+02:00</published><updated>2017-07-23T21:00:00+02:00</updated><content type="html">&lt;p&gt;Un mois et demi après la 0.2, je suis très content d’annoncer la sortie de la
version 0.3 de Project Zero. Pour rappel, il s’agit d’un gestionnaire de
projets et de tâches avec un fort parti pris sur la façon de gérer tout cela.&lt;/p&gt;
&lt;p&gt;Le code source se trouve &lt;a href="https://github.com/marienfressinaud/project-zero"&gt;sur GitHub&lt;/a&gt;,
sous licence MIT et vous pouvez l’utiliser sur &lt;a href="https://zero.marienfressinaud.fr"&gt;zero.marienfressinaud.fr&lt;/a&gt;,
en attendant de migrer vers un nouveau (sous-)domaine que j’ai (enfin !)
acheté.&lt;/p&gt;
&lt;h2&gt;Les nouveautés&lt;/h2&gt;
&lt;p&gt;Lorsque j’ai annoncé le mois dernier ce que je comptais inclure dans la
prochaine version, j’avais prévu toute une liste de choses à faire :
« meilleure gestion des petits écrans, emails de rappel, joli logo,
amélioration de l’ergonomie et refonte du design, éventuellement
ludification ». De tout ça, je n’ai quasiment rien retenu pour me concentrer
sur ce qui comptait vraiment dans mon usage, l’idée étant que je l’utilise
réellement au quotidien.&lt;/p&gt;
&lt;p&gt;Premièrement, le « responsive design » était quasiment primordial vu que
j’utilise beaucoup Project Zero sur tablette, voire sur téléphone. Ce n’est pas
encore parfait, surtout sur mobile, mais tout est fonctionnel.&lt;/p&gt;
&lt;p&gt;Ensuite, j’avais absolument besoin de lier des tâches aux projets pour
m’assurer qu’ils avancent correctement. En effet, jusqu’à maintenant ma liste
de projets servait surtout de déco et beaucoup d’entre eux dépassaient leur
date de fin. Désormais, avec les tâches associées ainsi que les deux
indicateurs qui viennent avec, il est désormais beaucoup plus facile de savoir
ce qui avance ou non. Les indicateurs sont de deux types :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;le nombre de tâches terminées vs. le nombre de tâches associées, cet
  indicateur devient orange s’il n’y a aucune tâche à faire et est rouge s’il
  n’y a aucune tâche associée ;&lt;/li&gt;
&lt;li&gt;une barre de progression montrant où l’on en est (càd. le jour courant) par
  rapport à l’échéance de fin.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ces deux indicateurs se sont révélés indispensables pour mon usage.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Dashboard de Project Zero 0.3" src="images/projectzero/2017-07-23-0.3-dashboard.png" /&gt;&lt;/p&gt;
&lt;p&gt;Une fonctionnalité de la version 0.3 s’est en revanche montrée moins utile. En
effet, les tâches non terminées le jour même se retrouvaient dans une « pending
list » qui n’était pas facilement accessible. De ce fait, je perdais de vue bon
nombre des tâches qui se trouvaient donc non résolues. J’ai décidé de renvoyer
ces tâches dans le « backlog » dans le but de toujours démarrer une journée
avec une liste de tâches vide. J’en ai profité pour rendre les tâches du
« backlog » directement plannifiable ce qui a rendu le bouton « &lt;em&gt;What will you
work on today ?&lt;/em&gt; » inutile. C‘est donc un écran qui a sauté.&lt;/p&gt;
&lt;p&gt;En résumé, il n’y a plus que deux listes de tâches : la liste du jour même et
le « backlog ». Chaque début de journée, vous pouvez aller piocher dans
celui-ci les tâches que vous pensez pouvoir réaliser le jour même.&lt;/p&gt;
&lt;p&gt;Pour terminer, une fonctionnalité pas tellement essentielle mais que je
trouvais sympa : une page de statistiques permettant de retracer sur les 15
derniers jours le nombre de tâches créées comparé au nombre de tâches
terminées. Cela permet de me rassurer sur le fait que j’avance dans ce que j’ai
à faire.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Dashboard de Project Zero 0.3" src="images/projectzero/2017-07-23-0.3-statistics.png" /&gt;&lt;/p&gt;
&lt;p&gt;Pour les plus vigilants, vous noterez que le style est très proche de celui des
graphiques GitHub (ceux de l’onglet « Traffic »).&lt;/p&gt;
&lt;p&gt;Avec cette nouvelle version, j’ai désormais un outil pleinement fonctionnel
pour mon usage quotidien. Je vais désormais sans doute mettre un (petit) coup
de frein au développement du projet pour préparer un gros morceau :
l’amélioration globale de l’expérience utilisateur et la mise en place d’une
charte graphique pour le projet. Je ne sais pas encore quand je pourrai faire
cela et il n’est pas impossible que je développe deux trois fonctionnalités
autres, mais ce n’est pas dans mes priorités immédiates.&lt;/p&gt;</content></entry><entry><title>Project Zero 0.2</title><id>urn:uuid:3daa22ef-bcbd-50d4-b9cb-f1ea4fa28d24</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/project-zero-0-2.html" rel="alternate" type="text/html" /><published>2017-06-05T21:10:00+02:00</published><updated>2017-06-05T21:10:00+02:00</updated><content type="html">&lt;p&gt;Après &lt;a href="https://marienfressinaud.fr/project-zero-0-1.html"&gt;une version 0.1&lt;/a&gt;
sortie fin janvier, je sors aujourd’hui (avec seulement un mois de retard) la
version 0.2 de Project Zero, mon mini-système de gestion de projets et de
tâches.&lt;/p&gt;
&lt;p&gt;Le code source se trouve &lt;a href="https://github.com/marienfressinaud/project-zero"&gt;sur GitHub&lt;/a&gt;,
sous licence MIT et vous pouvez toujours l’utiliser sur &lt;a href="https://zero.marienfressinaud.fr"&gt;zero.marienfressinaud.fr&lt;/a&gt;.
L’adresse n’a pas (encore) changé mais passe désormais en HTTPS.&lt;/p&gt;
&lt;h2&gt;Les nouveautés de la 0.2&lt;/h2&gt;
&lt;p&gt;Cette nouvelle version apporte la gestion de listes de tâches (ou « todo
lists »), fonctionnalité dont j’avais le plus besoin. J’utilisais auparavant
&lt;a href="https://todoist.com"&gt;Todoist&lt;/a&gt; qui me convenait plutôt bien, mais je souhaitais
un système plus proche de mon mode de fonctionnement. Qu’apporte vraiment
Project Zero par rapport à n’importe quel autre gestionnaire de tâches ?&lt;/p&gt;
&lt;p&gt;Tout d’abord, l’ajout des tâches a été pensé pour se faire le jour même. La
plupart du temps, en arrivant le matin au boulot, je me prépare une liste des
choses que j’aimerais régler pendant la journée. Quel meilleur moment pour
savoir ce que l’on souhaite faire que le matin ?&lt;/p&gt;
&lt;p&gt;Bien sûr, il m’arrive aussi souvent d’avoir des idées de choses à faire que je
ne réaliserai pas le jour même, pour cela une seconde liste appelée « backlog »
vient s’ajouter à la première dans laquelle je peux venir piocher pour préparer
ma liste de la journée.&lt;/p&gt;
&lt;p&gt;Les tâches que je n’arrive pas à terminer sont marquées en attente et viennent
alimenter une troisième liste. En préparant ma liste de la journée, les tâches
non réalisées la veille me sont proposées à nouveau et je peux soit indiquer
que je l’ai en fait déjà terminée, soit la replanifier pour aujourd’hui. Si je
la replanifie, un indicateur est incrémenté. Cet indicateur me sert à me
prévenir que j’ai trop replanifié une tâche et me propose au bout de 2 fois de
découper la tâche ou de la renommer pour la rendre plus facile à terminer.&lt;/p&gt;
&lt;p&gt;Un second indicateur particulièrement utile pour les tâches du « backlog »
indique le nombre de semaines depuis que la tâche a été créée. Au bout de 2
semaines, l’indicateur me propose d’abandonner la tâche vu qu’il y a de fortes
chances que je ne la termine jamais.&lt;/p&gt;
&lt;p&gt;Ces deux indicateurs me permettent d’éviter de conserver des tâches pendant
trop longtemps. Cela me permet d’avoir un système de priorisation non basé sur
une appréciation subjective mais basé sur le temps et sur la répétition ; ainsi
je peux réordonner les tâches au fil du temps.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Dashboard de Project Zero 0.2" src="images/projectzero/2017-06-05-0.2-dashboard.png" /&gt;&lt;/p&gt;
&lt;h2&gt;Les dates d’échéance ?&lt;/h2&gt;
&lt;p&gt;J’ai décidé de ne pas gérer les dates d’échéance. C’est encore une réflexion en
cours car j’avais vraiment dans l’idée de les gérer mais j’ai finalement conclu
à la non nécessité de la fonctionnalité. Une date d’échéance peut avoir deux
significations :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;une date limite permettant d’éviter que la tâche reste indéfiniment dans la
  liste, rôle déjà porté par les indicateurs ;&lt;/li&gt;
&lt;li&gt;une date de réalisation et, dans ce cas, un calendrier fait très bien
  l’affaire.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;De plus, j’avais peur de la complexité car cela m’aurait mené à devoir
(vouloir ?) gérer la répétition des tâches dans le temps et la saisie intuitive
des dates (taper « demain » pour saisir la date du lendemain par exemple).&lt;/p&gt;
&lt;h2&gt;En prévoyant la suite…&lt;/h2&gt;
&lt;p&gt;Cette nouvelle version apporte un gros morceau qui fait que Project Zero me
devient de plus en plus utile. Pour autant, je n’ai pas encore vraiment le
réflexe de m’y connecter et je n’y ai d’ailleurs pas du tout touché pendant le
mois d’avril (ce qui explique le retard pris pour cette sortie). J’ai tout de
même ajouté pas mal de choses en mai qui me facilite l’usage (ordonnancement,
édition, abandon et indicateurs).&lt;/p&gt;
&lt;p&gt;La version à venir (la 0.3 donc) me servira surtout à consolider ce que j’ai
fait jusqu’à maintenant et devrait ajouter des mécanismes poussant à la
« fidélisation » (meilleure gestion des petits écrans, emails de rappel, joli
logo, amélioration de l’ergonomie et refonte du design, éventuellement
ludification). Je n’ai aucune idée de la date de la prochaine sortie car j’ai
d’abord besoin d’identifier ce qui bloque mon usage.&lt;/p&gt;
&lt;p&gt;J’ai pas mal d’idées de ce que pourrait devenir Project Zero et des
fonctionnalités qui pourraient m’être utiles, mais je souhaite vraiment monter
ce projet petite brique par petite brique en m’assurant que le tout est
utilisable et utilisé.&lt;/p&gt;</content></entry><entry><title>Project Zero 0.1</title><id>urn:uuid:056ba3b7-6629-5235-9115-496ff256836b</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/project-zero-0-1.html" rel="alternate" type="text/html" /><published>2017-01-29T19:00:00+01:00</published><updated>2017-01-29T19:00:00+01:00</updated><content type="html">&lt;p&gt;J’en parlais lors de &lt;a href="https://marienfressinaud.fr/projet-zero-2016.html"&gt;ma rétrospective 2016&lt;/a&gt;
 sur ma méthodologie de travail, j’ai commencé à bosser sur une application qui
devrait me servir de cadre méthodologique. Jusqu’à maintenant j’utilisais le
système de fichiers de l’ordinateur pour organiser mes projets, mais c’était
trop contraignant et je n’arrivais pas à assurer un suivi suffisant.&lt;/p&gt;
&lt;p&gt;Après un mois de travail acharné, j’ai enfin terminé la version 0.1 de
«&amp;nbsp;Project Zero&amp;nbsp;». Le code source est disponible &lt;a href="https://github.com/marienfressinaud/project-zero"&gt;sur
GitHub&lt;/a&gt; sous licence MIT et
vous pouvez même vous créer un compte sur le service que je mets à
disposition&amp;nbsp;: &lt;a href="http://zero.marienfressinaud.fr"&gt;zero.marienfressinaud.fr&lt;/a&gt;.
Attention, l’application n’est pas encore disponible en HTTPS&amp;nbsp;!&lt;/p&gt;
&lt;h2&gt;Pourquoi Project Zero&amp;nbsp;?&lt;/h2&gt;
&lt;p&gt;Cela fait longtemps maintenant que j’imagine un outil de gestion de mes
projets. Bien sûr, je suis un éternel insatisfait des outils que j’utilise et
il fallait absolument que je développe mon propre logiciel&amp;nbsp;:). Comme il
devait s’agir du projet à la base de tous mes autres projets, je l’appelais
«&amp;nbsp;Projet Zéro&amp;nbsp;». Fin 2015 je donnais un coup de frein à ma
contribution à &lt;a href="https://freshrss.org/"&gt;FreshRSS&lt;/a&gt; pour commencer à bosser sur ce
fameux outil… chose que je n’ai jamais concrétisée car mes idées à l’époque
n’étaient absolument pas claires sur ce que je voulais faire.&lt;/p&gt;
&lt;p&gt;C’est en août, pris dans la tourmente de mes nombreux projets commencés mais
dont aucun n’avançait, que je mettais en place quelques actions pour me
reconcentrer sur ce que je faisais. Cela a donné &lt;a href="https://marienfressinaud.fr/projet-zero-readme-md.html"&gt;une pré-version&lt;/a&gt;
de ce que je voulais obtenir.&lt;/p&gt;
&lt;p&gt;Fin décembre, voyant que ma méthodologie avait globalement bien fonctionné mais
que j’avais toujours des soucis à assurer le suivi, j’ai dessiné les premiers
écrans d’une application que j’ai donc nommé «&amp;nbsp;Project Zero&amp;nbsp;» (notez
le passage à l’anglais).&lt;/p&gt;
&lt;h2&gt;Les (quelques) fonctionnalités&lt;/h2&gt;
&lt;p&gt;Il y a aujourd’hui très peu de fonctionnalités car je veux d’abord voir comment
évoluent mes besoins. Je préfère avoir très peu de fonctionnalités qui me
servent toutes que beaucoup qui ne me servent pas. Ce qu’il est possible de
faire&amp;nbsp;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;créer un compte (et s’authentifier, évidemment)&amp;nbsp;;&lt;/li&gt;
&lt;li&gt;gérer ses projets (qui ne consistent qu’en un nom, une description en
  MarkDown et quelques dates)&amp;nbsp;;&lt;/li&gt;
&lt;li&gt;démarrer jusqu’à trois projets en même temps en précisant une date de
  fin&amp;nbsp;;&lt;/li&gt;
&lt;li&gt;stopper les projets qui stagnent&amp;nbsp;;&lt;/li&gt;
&lt;li&gt;terminer les projets… terminés.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt="Dashboard de Project Zero 0.1" src="images/projectzero/2017-01-29-0.1-dashboard.png" /&gt;
&lt;img alt="Vue d’un project dans Project Zero 0.1" src="images/projectzero/2017-01-29-0.1-project-show.png" /&gt;&lt;/p&gt;
&lt;p&gt;Il s’agit de la version 0.1 bien sûr, tout reste encore à construire… et j’ai
pas mal d’idées pour ça&amp;nbsp;:).&lt;/p&gt;
&lt;h2&gt;Sous le capôt&lt;/h2&gt;
&lt;p&gt;J’ai pas mal tergiversé avant de me décider sur les technologies à utiliser
pour développer Project Zero. Voulant au départ découvrir de nouvelles choses,
je partais sur un backend &lt;a href="http://djangoproject.com/"&gt;Django&lt;/a&gt;, le frontend en
&lt;a href="http://elm-lang.org/"&gt;Elm&lt;/a&gt; et une API à base de &lt;a href="http://graphql.org/"&gt;GraphQL&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Mais plus j’hésitais plus je me convainquais que j’allais accumuler les
difficultés et que je n’avancerais pas. Au final j’ai décidé de partir sur des
bases que je connais et avec lesquelles je suis à l’aise&amp;nbsp;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://rubyonrails.org/"&gt;Ruby on Rails&lt;/a&gt; pour le backend comme cela fait
  presque 1 an et demi que j’en fais quotidiennement, pas de difficulté à ce
  niveau&amp;nbsp;;&lt;/li&gt;
&lt;li&gt;une API classique en Json, je savais que j’avais encore besoin de progresser
  là-dessus mais je n‘exclue pas d’inclure du GraphQL à terme&amp;nbsp;;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://vuejs.org/"&gt;VueJS&lt;/a&gt; pour le frontend, pour le coup que je ne
  connaissais pas mais qui n’est pas trop éloigné conceptuellement de React.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Pour ce qui est de VueJS, la lecture de la documentation m’a convaincu que tous
les problèmes que j’avais avec React allaient disparaître comme par magie… et
ce n’est pas tout à fait faux&amp;nbsp;:). Bien sûr d’autres questions se sont
posées au fur et à mesure que j’avançais, mais je suis tout de même
content du résultat&amp;nbsp;! L’époque où j’écrivais du JS imbitable sur FreshRSS
est révolue&amp;nbsp;:D.&lt;/p&gt;
&lt;p&gt;Comme je le disais plus haut, le code est hébergé &lt;a href="https://github.com/marienfressinaud/project-zero"&gt;sur GitHub&lt;/a&gt;
mais il n’est pas exclu que je le déplace sur &lt;a href="http://framagit.org/"&gt;Framagit&lt;/a&gt;.
Ce qui me retient de le faire actuellement est de deux ordres&amp;nbsp;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;j’ai dans l’espoir de trouver une troisième solution. Le but de Framasoft
  n’étant pas de tout centraliser sur ses serveurs, j’aimerais aller voir
  ailleurs et de préférence chez un &lt;a href="https://chatons.org/"&gt;chaton&lt;/a&gt; local&amp;nbsp;;&lt;/li&gt;
&lt;li&gt;GitHub reste à des années lumières de Gitlab au niveau expérience
  utilisateur. Gitlab a beau avoir des fonctionnalités (très) intéressantes,
  son interface reste foutraque et j’ai du mal à m’y faire.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Le service Project Zero&lt;/h2&gt;
&lt;p&gt;J’expliquais plus haut que j’ai mis à disposition un service à l’adresse
&lt;a href="http://zero.marienfressinaud.fr"&gt;zero.marienfressinaud.fr&lt;/a&gt;. Si l’adresse est
temporaire, j’ai dans l’espoir que le service ne le soit pas. Je ne me fais pas
trop d’illusions, actuellement Project Zero est beaucoup trop limité
fonctionnellement pour être utile à qui que ce soit, mais je pense qu’à terme
il pourrait plaire à quelques-uns.&lt;/p&gt;
&lt;p&gt;Attention, le service est aujourd’hui ouvert à n’importe qui et gratuit, mais
je n’exclu pas à terme de &lt;strong&gt;le rendre payant&lt;/strong&gt;. On ne pourra pas dire que je
n’ai pas prévenu&amp;nbsp;! Bien sûr le logiciel restera sous licence libre et je
ne prévois absolument pas de version alternative «&amp;nbsp;closed-source&amp;nbsp;».
L’idée serait plutôt de rembourser les coûts du serveur et de mettre un petit
quelque chose de côté pour me donner un peu plus de temps libre, absolument pas
de faire fortune.&lt;/p&gt;
&lt;h2&gt;Mes idées pour la suite&lt;/h2&gt;
&lt;p&gt;Voici une liste non-exhaustive de ce que j’ai en tête pour le moment&amp;nbsp;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;gestion de listes de tâches à faire (communément appelées «&amp;nbsp;todo
  lists&amp;nbsp;»)&amp;nbsp;;&lt;/li&gt;
&lt;li&gt;gestion d’environnements pour distinguer les projets personnels des projets
  professionels&amp;nbsp;;&lt;/li&gt;
&lt;li&gt;envoi de mails de rappels&amp;nbsp;;&lt;/li&gt;
&lt;li&gt;gestion de sous-projets&amp;nbsp;;&lt;/li&gt;
&lt;li&gt;client en ligne de commande pour notamment synchroniser des dossiers en
  local, ça permettrait d’avoir par exemple un dépôt Git en local associé à un
  projet&amp;nbsp;;&lt;/li&gt;
&lt;li&gt;gestion du profil utilisateur et projets publics.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ma priorité numéro 1 va être la gestion des tâches. J’utilise actuellement
&lt;a href="https://todoist.com"&gt;Todoist&lt;/a&gt; et j’en suis vraiment très satisfait. Ceci dit
il y a parfois des petits bugs et je n’aime pas la façon dont il gère le
système de karma qui pousse parfois à bacler des tâches seulement pour garder
de bonnes statistiques. Et puis c’est toujours rigolo de redévelopper des
choses qui existent déjà, non&amp;nbsp;?&amp;nbsp;:). Je cogite encore pour réfléchir à
comment m’y prendre et ne pas faire quelque chose de trop bâteau.&lt;/p&gt;</content></entry><entry><title>Les projets 2016 de Projet Zéro</title><id>urn:uuid:b1766d28-d58c-52da-9a7b-ad8e73335e90</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/projet-zero-2016.html" rel="alternate" type="text/html" /><published>2016-12-29T21:00:00+01:00</published><updated>2016-12-29T21:00:00+01:00</updated><content type="html">&lt;p&gt;En septembre
&lt;a href="https://marienfressinaud.fr/projet-zero-readme-md.html"&gt;j’expliquais&lt;/a&gt; comment
j’allais essayer de m’organiser pour enfin produire les choses qui me
trottaient dans la tête. J’avais mis cela en place un mois plus tôt et je
manquais donc nécessairement de recul dessus. Pour rappel, cette méthodologie
repose sur les points suivants&amp;nbsp;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;un carton contient l’ensemble de mes projets et est restreint par les quatre
  règles suivantes&amp;nbsp;:&lt;ul&gt;
&lt;li&gt;je n’ai pas le droit de toucher ou d’avancer les projets qui sont dedans&amp;nbsp;;&lt;/li&gt;
&lt;li&gt;j’ai le droit d’en sortir trois maximum à la fois&amp;nbsp;;&lt;/li&gt;
&lt;li&gt;un projet sorti du carton ne peut pas y retourner avant une date limite que
  j’ai fixée au préalable (ou alors je dois l’avoir terminé)&amp;nbsp;;&lt;/li&gt;
&lt;li&gt;tout nouveau projet doit le rejoindre&amp;nbsp;;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;chacun des projets en dehors du carton doit avoir un objectif ainsi qu’une
  date limite de fin&amp;nbsp;;&lt;/li&gt;
&lt;li&gt;un article de blog est publié à chaque fin de projet.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Concernant ce dernier point, je n’ai publié que deux articles concernant mes
projets durant ces 4 derniers mois… cela fait donc seulement 2 projets
terminés sur pas moins de 7 projets&amp;nbsp;! Alors, que s’est-il passé&amp;nbsp;?&lt;/p&gt;
&lt;h2&gt;SogiMood, l’article qui a eu du mal à sortir&lt;/h2&gt;
&lt;p&gt;Bien que SogiMood soit un projet que je considère comme terminé, il n’en a pas
moins été problématique. En effet, je l’ai terminé fin septembre (donc peu de
temps après avoir expliqué ma méthodologie) mais &lt;a href="https://marienfressinaud.fr/sogimood.html"&gt;son
article&lt;/a&gt; est paru au début du mois
de décembre. La raison est assez simple&amp;nbsp;: l’article a été réécrit au moins 2
fois en entier et puis est resté en gestation un certain temps. J’ai d’abord eu
du mal à trouver le ton et le contenu avant d’avoir l’idée de le proposer sur
&lt;a href="http://sogilis.com/blog/sogimood-appli-sante-projets"&gt;le blog de Sogilis&lt;/a&gt;.
Après relecture et correction par les collègues, je me suis retrouvé trop
occupé pour avoir vraiment la motivation de m’occuper de la publication finale.
1 mois puis 2 mois sont ainsi passés sans que je ne publie rien.&lt;/p&gt;
&lt;p&gt;Conclusion&amp;nbsp;: prévoir un article final n’est pas forcément une bonne idée
et je pense que je ne me forcerai plus de la sorte à l’avenir.&lt;/p&gt;
&lt;h2&gt;Le dessin et le sport, stoppés par perte de motivation&lt;/h2&gt;
&lt;p&gt;En février je commençais à m’intéresser à la pratique du dessin et en août je
me remettais une énième fois à aller courir, plus motivé que jamais.&lt;/p&gt;
&lt;p&gt;Dans le premier cas, je me suis même acheté des bouquins et je souhaitais finir
un livre d’exercices d’ici février prochain. La pratique assidue ne me faisait
pas plus peur que ça et je voyais déjà mes progrès. Autre objectif&amp;nbsp;: changer le
dessin moche en arrière-plan du site par quelque chose de plus travaillé.
Chaque année devait venir compléter et améliorer cette «&amp;nbsp;fresque&amp;nbsp;».
Je n’avais malheureusement pas pris en compte un élément fondamental&amp;nbsp;:
j’ai toujours eu horreur des exercices et je n’avais pas l’impression de
m’amuser en suivant les instructions d’un bouquin. Cela a freiné net ma
motivation et je me suis arrêté en septembre.&lt;/p&gt;
&lt;p&gt;Dans le cas du sport, je ne vous referai pas la même rengaine de la motivation
à bloc, etc. J’allais principalement courir le soir voire un petit peu les
matins avec des collègues. En revanche, fin octobre, lorsque la nuit a
commencé à se faire plus longue et que je n’avais plus le choix que d’aller
courir de nuit, j’ai commencé à me démotiver pour faire une pause d’un mois en
novembre. Au début du mois toutefois j’ai réussi à me remotiver pour… une seule
séance avant de me restopper aussi net à cause de la pollution (bienvenue à
Grenoble).&lt;/p&gt;
&lt;p&gt;Quoi qu’il en soit, ce sont deux projets que j’ai encore à cœur et il est
certain que je les reprendrai, peut-être sous d’autres formes pour ne pas me
démotiver à nouveau.&lt;/p&gt;
&lt;p&gt;J’ai en revanche abandonné la règle qui m’interdisait de replacer un projet
dans le carton&amp;nbsp;: ça n’a aucun sens de s’acharner sur un projet que l’on
n’avance pas.&lt;/p&gt;
&lt;h2&gt;Contribution à Framasoft, les contours trop flous&lt;/h2&gt;
&lt;p&gt;Ici, à l’inverse des deux précédents, je suis encore sur ce
«&amp;nbsp;projet&amp;nbsp;». Je m’étais fixé plusieurs objectifs&amp;nbsp;: contribuer à
l’écriture des articles du lancement de la saison 3 de Dégooglisons, mettre à
jour Framaboard avec quelques contributions upstream, aider au support et
participer éventuellement à plus d’événements pour tenir les stands. Je
souhaitais faire cela durant environ deux mois avant de repasser au régime
habituel.&lt;/p&gt;
&lt;p&gt;Ce qu’il s’est concrêtement passé, c’est que j’ai légèrement augmenté mon
activité sur les projets Framasoft sans pour autant trouver la motivation de
m’y impliquer autant que je le souhaitais. De plus, je bloque depuis fin
septembre sur ma contribution à Kanboard pour faire en sorte de simplifier les
mises à jour de Framaboard. À vrai dire je crois que je ne suis pas hyper
emballé à l’idée de devoir faire du PHP&amp;nbsp;;). J’ai repoussé cela pour après les
fêtes, en espérant que je sois plus motivé que pour le moment.&lt;/p&gt;
&lt;p&gt;Framasoft reste un projet un peu particulier puisque j’essaye de contribuer
tout au long de l’année, ne serait-ce que pour répondre aux questions sur le
support ou pour participer aux évènements.&lt;/p&gt;
&lt;p&gt;La morale de tout ça c’est qu’il faut que je me force à mieux définir ce que je
compte faire au sein du projet pour me donner les moyens de savoir quand
celui-ci est véritablement fini.&lt;/p&gt;
&lt;h2&gt;Voyage et Projet Zéro, les projets pas encore terminés&lt;/h2&gt;
&lt;p&gt;Pour finir, les projets qui sont en cours. Le premier est un voyage au
Royaume-Uni&amp;nbsp;: j’ai dû commencer les préparatifs assez tôt afin d’avoir une
réduction sur mon billet Interrail et donc planifier des dates. Rien de très
compliqué mais tout ça pour dire que je terminerai ce «&amp;nbsp;projet&amp;nbsp;» en
juin, lorsque je serai revenu.&lt;/p&gt;
&lt;p&gt;Concernant Projet Zéro, j’ai enfin attaqué une version applicative (web) afin
de donner un cadre à ma méthodologie. Ma version actuelle ne me permet pas
d’être suffisamment rigoureux dans l’avancement de mes projets et je souhaitais
avoir un outil plus manipulable ainsi qu’un système de rappels. L’application
est encore dans une version préliminaire mais j’en parlerai dès que j’aurai
quelque chose d’utilisable. À l’inverse de Taglibro, je souhaite fournir une
version hébergée et permettre à n’importe qui de s’y inscrire… mais j’y
reviendrai&amp;nbsp;!&lt;/p&gt;
&lt;p&gt;Cela fait donc le tour de mes projets que je m’étais fixé sur cette moitié
d’année 2016. Rendez-vous l’année prochaine si jamais je continue à appliquer
ma méthodologie «&amp;nbsp;Projet Zéro&amp;nbsp;»&amp;nbsp;:).&lt;/p&gt;</content></entry><entry><title>Taglibro</title><id>urn:uuid:b1744864-3493-53de-90df-08d530782f35</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/taglibro.html" rel="alternate" type="text/html" /><published>2016-12-21T19:00:00+01:00</published><updated>2016-12-21T19:00:00+01:00</updated><content type="html">&lt;p&gt;Vers le milieu de ma seconde année en école d’ingénieur, j’avais eu l’idée un
peu bizarre d’un réseau social anonyme. L’idée a longtemps trainé avant que je
décide il y a peu de temps de sortir un premier jet de ce que j’avais en tête.
Toujours dans le cadre de &lt;a href="https://marienfressinaud.fr/projet-zero-readme-md.html"&gt;Projet Zéro&lt;/a&gt;,
j’ai sorti une petite application en une semaine de boulot&amp;nbsp;: Taglibro.&lt;/p&gt;
&lt;p&gt;Je ne ferai pas de long article sur ce projet car il s’agit avant tout de
répondre à un besoin personnel&amp;nbsp;: celui de pouvoir consigner des pensées
divers en un endroit. Voyez Taglibro avant tout comme un carnet de bord ou un
journal intime (Taglibro en Esperanto). Je souhaitais penser l’outil pour un
usage avant tout personnel.&lt;/p&gt;
&lt;p&gt;Évidemment je n’ai pas fait grand chose en une semaine, juste ce qu’il faut
pour permettre de saisir ses pensées, les lister et les publier. Quelques
contraintes viennent s’ajouter à cela&amp;nbsp;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;on ne peut publier qu’une fois par jour dans l’optique de favoriser les
  écrits de qualité (mais c’est quelque chose qui évoluera dans le futur)&amp;nbsp;;&lt;/li&gt;
&lt;li&gt;les pensées publiques ne sont visibles que durant 24h avec dans l’idée de
  rencontres et d’échanges qui se font de manière ponctuelle&amp;nbsp;;&lt;/li&gt;
&lt;li&gt;toutes les pensées sont anonymisées, aucun nom, aucun signe distinctif si ce
  n’est le texte que vous tapez.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Imaginez rencontrer un(e) inconnu(e) dans le train, discuter de tout et de
rien, prendre du plaisir à parler avec cette personne. Le train arrive à la
gare et vous vous dites au revoir. Ce n’est qu’une fois perdu de vue que vous
vous rendez compte que vous ne savez pas le nom de votre inconnu(e). Tout ce
que vous conservez, c’est cette sensation d’avoir passé un bon moment, riche en
échanges, avec cette personne. C’est un peu cet état d’esprit que je souhaite
faire émerger dans Taglibro. Exit donc tout système de popularité, tout ce
qu'il reste ce sont des mots. Vous vous fondez dans la masse et personne ne
sait qui vous êtes.&lt;/p&gt;
&lt;p&gt;Pour les aspects plus techniques, Taglibro a été écrit en Rails, a été placé
sous licence MIT et le code est hébergé &lt;a href="https://github.com/marienfressinaud/taglibro"&gt;sur GitHub&lt;/a&gt;.
Pour le moment, le déploiement se fait automatiquement sur Heroku et c’est
pourquoi &lt;strong&gt;je déconseille fortement l’utilisation de Taglibro&lt;/strong&gt;, puisque Heroku
repose sur AWS de Amazon et que ce n’est pas du tout «&amp;nbsp;&lt;a href="http://degooglisons-internet.org/"&gt;Dégooglisons
Internet&lt;/a&gt;&amp;nbsp;»-compliant&amp;nbsp;! (je ne
partagerai même pas l'URL directement pour tout dire)&lt;/p&gt;
&lt;p&gt;Bref, Taglibro n’a pour le moment pas beaucoup d’intérêt (si ce n’est pour moi)
et je déconseille même son utilisation. Par contre je suis preneur de
suggestions donc n’hésitez pas&amp;nbsp;:).&lt;/p&gt;</content></entry><entry><title>SogiMood</title><id>urn:uuid:90a65407-6bad-556b-b0ba-c207ef2c28e0</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/sogimood.html" rel="alternate" type="text/html" /><published>2016-12-13T21:30:00+01:00</published><updated>2016-12-13T21:30:00+01:00</updated><content type="html">&lt;p&gt;J’ai commencé cet été une petite application que je voulais utiliser dans le
cadre du boulot. Le but était de surveiller la santé des projets sur lesquels
nous travaillons. Comme on aime bien le logiciel libre chez Sogilis et qu’on
est assez libre de faire ce que l’on veut, j’ai proposé de libérer le code de
ce logiciel&amp;nbsp;: SogiMood (oui, c’est original).&lt;/p&gt;
&lt;p&gt;Il s’agit d’une application web avec un backend écrit en Go et un frontend
écrit en ReactJS (il paraît que c’est «&amp;nbsp;hype&amp;nbsp;», c’est donc forcément
bien)&amp;nbsp;; le code est placé sous licence MIT. Plutôt que de faire deux longs
articles sur SogiMood, je vous invite à lire &lt;a href="http://sogilis.com/blog/sogimood-appli-sante-projets/"&gt;l’article que j’ai
publié&lt;/a&gt; sur le blog de
Sogilis où je détaille un peu plus le pourquoi et le comment de SogiMood.&lt;/p&gt;
&lt;p&gt;En espérant que ça intéresse&amp;nbsp;!&lt;/p&gt;
&lt;p&gt;Note&amp;nbsp;: ce projet s’inscrit dans ma démarche «&amp;nbsp;Projet Zéro&amp;nbsp;».
J’aurais dû publier cet article fin septembre mais comme j’attendais de d’abord
écrire celui sur le blog de Sogilis et que je devais attendre mon tour pour
être publié, cela a pris un peu plus de temps que prévu ;). En attendant je
continue de gérer mes différents projets de la même manière que ce que je
décrivais dans &lt;a href="http://marienfressinaud.fr/projet-zero-readme-md.html"&gt;mon dernier article&lt;/a&gt;
bien que cela demande un peu plus de rigueur que ce que j’avais imaginé à la
base&amp;nbsp;!&lt;/p&gt;</content></entry><entry><title>Projet Zéro/README.md</title><id>urn:uuid:e84c3e76-ce71-55e1-89c1-b7d8af675290</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/projet-zero-readme-md.html" rel="alternate" type="text/html" /><published>2016-09-14T20:00:00+02:00</published><updated>2016-09-14T20:00:00+02:00</updated><content type="html">&lt;p&gt;Cela fait bien longtemps que je n’ai rien publié sur ce site. En toute logique
et parce que je suis fait de plein de contradictions, j’ouvre aujourd’hui une
nouvelle catégorie sur celui-ci&amp;nbsp;: &lt;strong&gt;Projet Zéro&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Avant de présenter cette catégorie et de m’auto-persuader que je vais l’alimenter, un peu de contexte s’impose.&lt;/p&gt;
&lt;p&gt;En septembre de l’année dernière, après un joli petit tour d’Europe, j’ai
rejoint la société de services Sogilis (attendez, &lt;a href="http://sogilis.com/blog/sogilis-vs-ssii/"&gt;ce n’est pas ce que vous
croyez&amp;nbsp;!&lt;/a&gt;). Rejoindre cette boîte a
été l’occasion pour moi d’apprendre beaucoup de choses&amp;nbsp;: Ruby et Rails, JavaScript
via React, approfondir mes connaissances de Git, me mettre à Vim sous
l’impulsion des &lt;a href="http://tuppervim.org/"&gt;TupperVims&lt;/a&gt;, gratouiller du Go, apprendre et mettre en place pas
mal de bonnes pratiques dans différents domaines, etc. Forcément, engranger
toutes ces choses m’a donné des idées de projets et des envies d’améliorer
ceux existants (si si, j’envisage toujours de revenir sur FreshRSS pour le
faire évoluer&amp;nbsp;:)). À côté de ça j’ai eu envie d’apprendre à dessiner, j’ai
toujours des projets de nouvelles que je souhaite publier sur ce site et j’ai
réussi à me motiver à aller courir régulièrement pour me remettre en forme.
Si on n’oublie pas le fait que j’essaye toujours de contribuer aux actions de
Framasoft en tant que bénévole, vous comprendrez qu’à un moment je ne savais
plus où donner de la tête.&lt;/p&gt;
&lt;p&gt;Il y a donc un peu moins d’un mois, après m’être dispersé une nouvelle fois
dans un énième projet qui n’aboutira jamais, je me suis amusé à compter les
différents projets que j’avais en tête. Après un court brainstorming pour
coucher sur papier l’ensemble des choses que j’avais en tête, je finissais avec
une grosse vingtaine de projets&amp;nbsp;: des voyages, des nouvelles, des
contributions à des logiciels opensource, d’autres plus personnels, etc. Un
joyeux fourre-tout que j’ai entièrement rangé… dans un carton. À ce carton j’ai
assorti quatre règles simples&amp;nbsp;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;je n’ai pas le droit de toucher ou d’avancer les projets qui sont dedans&amp;nbsp;;&lt;/li&gt;
&lt;li&gt;j’ai le droit d’en sortir trois maximum à la fois&amp;nbsp;;&lt;/li&gt;
&lt;li&gt;un projet sorti du carton ne peut pas y retourner avant une date limite que
  j’ai fixée au préalable (ou alors je dois l’avoir terminé)&amp;nbsp;;&lt;/li&gt;
&lt;li&gt;tout nouveau projet "méga-top-génial" doit le rejoindre.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ce carton, c’est ma manière de m’empêcher de me disperser dans tous les sens.
Ça fait maintenant un mois que j’ai mis cette méthodologie en place, je manque
évidemment encore de recul dessus (j’ignore si cela va durer ou si cela est
même efficace) mais j’en suis pour le moment entièrement satisfait.&lt;/p&gt;
&lt;p&gt;Le plus intéressant dans la mise en place de ce carton c’est que je me suis rendu
compte que j’avais en fait réalisé une première version minimale d’un projet
qui se trouvait au sein même du carton&amp;nbsp;! Son petit nom, c’est
«&amp;nbsp;Projet Zéro&amp;nbsp;».&lt;/p&gt;
&lt;p&gt;Projet Zéro part du constat que j’ai toujours trop de projets en parallèle&amp;nbsp;: il
me fallait donc un projet pour les gérer tous &lt;strike&gt;et dans les ténèbres les
lier&lt;/strike&gt;. Projet Zéro c’était le premier projet que je me devais de terminer…
Devant la tâche immense qui m’attendait, je n’ai néanmoins jamais trouvé le
courage de m’y atteler. Son développement a été repoussé de semaines en
semaines et les mois se sont transformés en années.&lt;/p&gt;
&lt;p&gt;Alors cette première version de Projet Zéro n’est pas vraiment un logiciel que
j’ai développé, mais il ne s’agit pas non plus d’un carton physique. Projet
Zéro pour le moment, c’est un banal système de fichiers&amp;nbsp;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;marien@pizza&lt;span class="w"&gt; &lt;/span&gt;~$&lt;span class="w"&gt; &lt;/span&gt;tree&lt;span class="w"&gt; &lt;/span&gt;-L&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;ProjetZéro/
ProjetZéro/
├──&lt;span class="w"&gt; &lt;/span&gt;Blog
├──&lt;span class="w"&gt; &lt;/span&gt;Carton
├──&lt;span class="w"&gt; &lt;/span&gt;Dessin
├──&lt;span class="w"&gt; &lt;/span&gt;SogiMood
└──&lt;span class="w"&gt; &lt;/span&gt;Sport

&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;directories,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;files
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;On y trouve 5 répertoires&amp;nbsp;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Carton/&lt;/code&gt; est mon carton numérique contenant tous les autres projets (de simples
  fichiers texte)&amp;nbsp;;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Dessin/&lt;/code&gt;, &lt;code&gt;SogiMood/&lt;/code&gt; et &lt;code&gt;Sport/&lt;/code&gt; sont mes trois projets en cours. Chacun contient un
  fichier &lt;code&gt;README.md&lt;/code&gt; qui décrit le projet, donne des liens utiles et fixe une
  date limite de fin ainsi qu’un objectif (celui qui me fera dire «&amp;nbsp;j’ai fini
  ce projet&amp;nbsp;»)&amp;nbsp;;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Blog/&lt;/code&gt; est un raccourci vers les articles du blog. Je me suis dit que ce serait
  une bonne idée, à chaque fois que j’atteindrai un objectif (i.e. à chaque fin
  d’un projet), de partager mon expérience sur le blog. Il ne s’agit donc pas
  vraiment d’un projet mais d’une tâche transversale me servant à poser une
  vraie conclusion à mes projets.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Projet Zéro c’est donc pour moi le début d’une expérimentation qui se base sur
trois points&amp;nbsp;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;un carton contenant l’ensemble de mes projets et restreint par les quatre règles
  citées plus haut&amp;nbsp;;&lt;/li&gt;
&lt;li&gt;trois projets maximum en dehors du carton avec chacun un objectif ainsi
  qu’une date limite de fin&amp;nbsp;;&lt;/li&gt;
&lt;li&gt;un article de blog à chaque fin de projet.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Le prochain article ne devrait d’ailleurs pas trop tarder&amp;nbsp;!&lt;/p&gt;</content></entry><entry><title>La v7 est faite !</title><id>urn:uuid:b19c3175-3678-5468-8c2e-7967fba2ef46</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/la-v7-est-faite.html" rel="alternate" type="text/html" /><published>2016-04-21T00:00:00+02:00</published><updated>2016-04-21T00:00:00+02:00</updated><content type="html">&lt;p&gt;La précédente version du site qui tournait sous PluXML m’aura survécu plus de deux ans et demi, un record pour moi. Malheureusement, force est de constater que je ne publiais plus grand chose. L’envie me manquait certes un peu, mais j’avoue que devoir me connecter à une interface administateur m’a toujours beaucoup ennuyé alors que je pouvais rédiger mes articles tranquillement sur mon PC.&lt;/p&gt;
&lt;p&gt;Écrire en Markdown, le transformer en HTML, vérifier que tout fonctionne, penser à &lt;em&gt;téléverser&lt;/em&gt; les images sur le serveur&amp;nbsp;: non seulement c’était casse-pieds, mais en plus c’était idiot&amp;nbsp;! En effet cela fait un an que j’ai mis en place un blog pour FreshRSS (certes pas très actif) tournant &lt;a href="http://getpelican.com"&gt;sous Pelican&lt;/a&gt; et j’avais déjà réalisé un thème auparavant pour ce moteur de sites statiques, pourquoi ne pas en profiter&amp;nbsp;?&lt;/p&gt;
&lt;p&gt;Prenant mon courage à deux mains, j’ai donc réalisé un nouveau thème à partir de zéro. Objectif&amp;nbsp;: faire quelque chose de simple et joli. Le résultat se trouve sous vos yeux. Pour l’anecdote, je bosse sur cette nouvelle version depuis janvier et j’ai d’ailleurs failli me convaincre moi-même de faire appel à un professionnel pour le design&amp;nbsp;! Ça aurait été tout de même dommage ;).&lt;/p&gt;
&lt;p&gt;Profitant de ce changement je me suis dit que, tant qu’à faire, je pouvais bien faire le tri dans les articles. Ce sont donc 89 articles qui viennent vous dire au revoir. Les 33 articles qui ont survécu correspondaient tous à l’une des trois catégories du blog (informatique, nouvelles et vie du site) et possédaient un intérêt dans mon parcours personnel. Pour chacun d’eux j’ai pris le temps d’écrire un très court résumé (ok, ils sont pour beaucoup identiques), de réparer les liens cassés, de virer des parties plus du tout d’actualité et de corriger quelques fautes d’orthographe. C’était long, c’était fastidieux et j’espère bien que c’est la dernière fois que je fais ça&amp;nbsp;!&lt;/p&gt;
&lt;p&gt;Aussi, la partie blog se trouve reléguée en seconde partie du site. La raison est que si je n’ai pas envie de publier pendant plusieurs mois / années, cela se verra un peu moins que lorsque la liste des articles stagnait en première page :).&lt;/p&gt;
&lt;p&gt;Pour terminer, je vous propose trois captures d’écran. Il s’agit respectivement des versions 3 (22 novembre 2011, merci &lt;a href="https://archive.org/web/"&gt;Internet Archive&lt;/a&gt;), 6 (17 avril 2016) et 7 (21 avril 2016) de ce site.&lt;/p&gt;
&lt;p&gt;&lt;img alt="capture d’écran du site marienfressinaud.fr le 22 novembre 2011" src="images/site/v3.png" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="capture d’écran du site marienfressinaud.fr le 17 avril 2016" src="images/site/v6.png" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="capture d’écran du site marienfressinaud.fr le 21 avril 2016" src="images/site/v7.png" /&gt;&lt;/p&gt;
&lt;p&gt;Notez que le lien de l’ancien flux RSS est redirigé vers &lt;a href="http://marienfressinaud.fr/feeds/all.atom.xml"&gt;le nouveau&lt;/a&gt;.&lt;/p&gt;</content></entry><entry><title>Ray’s day : Celui pour qui sonnent les cloches.</title><id>urn:uuid:e3a86daa-4dcf-5b97-9d71-4f99222b7fec</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/rays-day-celui-pour-qui-sonnent-les-cloches.html" rel="alternate" type="text/html" /><published>2015-08-21T12:32:00+02:00</published><updated>2015-08-21T12:32:00+02:00</updated><content type="html">&lt;p&gt;&lt;img alt="Bannière Ray’s Day" src="images/raysday/raysday-basic-banniere-noir-transparent-1024x293.png" /&gt;&lt;/p&gt;
&lt;p&gt;On y est, le « &lt;em&gt;Ray’s day&lt;/em&gt; » c’est aujourd’hui. Initié l’année dernière par l’auteur &lt;a href="http://page42.org"&gt;Neil Jomunsi&lt;/a&gt;, l’évènement regroupe &lt;a href="https://raysday.net"&gt;autour d’un site&lt;/a&gt; les différentes initiatives visant à promouvoir la passion de la lecture. L’occasion est donnée d’écrire, de lire, de découvrir et, surtout, de partager. Si vous êtes curieux — et vous l’êtes assurément, non ? —, je vous donne rendez-vous sur le site &lt;a href="https://raysday.net"&gt;raysday.net&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;En novembre dernier, souvenez-vous, je participais au NaNoWriMo. De cette expérience intense, je ne publiais qu’une liste d’intentions (&lt;em&gt;oui, je publierai l’histoire dans X semaines / mois / années&lt;/em&gt;). Manque de temps, manque de confiance dans la qualité de mon écrit, prise de risques dans la rédaction qui me laissait dubitatif : je ne suis toujours pas prêt à publier le résultat. Un jour peut-être ?&lt;/p&gt;
&lt;p&gt;En attendant, je profite de ce jour un peu spécial pour soumettre à votre lecture attentive un petit essai. J’ai décidé de partir d’une page blanche, d’une idée toute neuve — ou presque —, afin de ne me poser aucune limite. Le résultat ? Une nouvelle qui s’intitule &lt;em&gt;Celui pour qui sonnent les cloches&lt;/em&gt;. Il s’agissait pour moi d’expérimenter une forme de récit un peu spéciale (vous comprendrez en lisant la nouvelle ;)) et j’ignore si le résultat est compréhensible ; je l’espère ! Il s’agit pour moi d’une première publication et j’implore donc votre indulgence ! :)&lt;/p&gt;
&lt;p&gt;Je vous invite à télécharger le fichier PDF, le fichier EPUB (pour liseuses électroniques) ou encore les sources MarkDown de &lt;a href="https://git.framasoft.org/marienfressinaud/celui-pour-qui-sonnent-les-cloches"&gt;mon histoire sur Framagit&lt;/a&gt;. Celle-ci est publiée sous licence CC-BY. Si vous avez des retours à me faire, mon courriel pour l’occasion est &lt;a href="mailto:raysday@marienfressinaud.fr"&gt;raysday@marienfressinaud.fr&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;De plus, l’opportunité m’a été donnée d’ajouter mon histoire à un recueil publié à l’occasion par les membres de Framasoft — dont je fais partie depuis janvier. Nous &lt;a href="http://framablog.org/2015/08/22/framasoft-fait-son-rays-day-avec-8-nouvelles-libres/"&gt;proposons ainsi 8 histoires&lt;/a&gt; toutes (ou presque) inédites. Je me dois de les remercier même si la visibilité donnée à ma nouvelle (et donc la pression :)) risque d’être plus importante que ce que j’imaginais au début.&lt;/p&gt;
&lt;p&gt;Je vous souhaite un bon Ray’s Day à tous !&lt;/p&gt;</content></entry><entry><title>freshrss.org se dote d’un blog !</title><id>urn:uuid:b476432a-aec7-56be-ab54-02140378742a</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/freshrss-org-se-dote-dun-blog.html" rel="alternate" type="text/html" /><published>2015-03-07T10:06:00+01:00</published><updated>2015-03-07T10:06:00+01:00</updated><content type="html">&lt;p&gt;Je l’avais annoncé dans l’article présentant FreshRSS 1.0, c’est désormais chose faite : freshrss.org possède son propre blog !&lt;/p&gt;
&lt;p&gt;Par conséquent :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cet article sera le dernier de ce blog parlant de FreshRSS ;&lt;/li&gt;
&lt;li&gt;Cet article sera le dernier en français à propos de FreshRSS ;&lt;/li&gt;
&lt;li&gt;Le flux RSS à suivre devient &lt;a href="http://freshrss.org/feeds/all.atom.xml"&gt;http://freshrss.org/feeds/all.atom.xml&lt;/a&gt; ;&lt;/li&gt;
&lt;li&gt;Le processus d’écriture devient plus communautaire puisque les articles seront annoncés &lt;a href="https://github.com/FreshRSS/freshrss.org/issues?q=label%3AArticle"&gt;sur GitHub&lt;/a&gt; et pourront être rédigés à plusieurs.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Pour plus de détails, vous pouvez vous rendre sur &lt;a href="http://freshrss.org/freshrss-gets-a-new-website.html"&gt;le premier article paru&lt;/a&gt; !&lt;/p&gt;
&lt;p&gt;Si vous avez des retours à faire, vous pouvez les faire &lt;a href="https://github.com/FreshRSS/freshrss.org/issues"&gt;sur GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Désormais les articles publiés ici seront beaucoup plus personnels, probablement liés dans un premier temps à mes voyages en France puis en Europe, sûrement peu à peu à mes projets d’écriture aussi. Le temps en jugera :).&lt;/p&gt;</content></entry><entry><title>FreshRSS un point zéro</title><id>urn:uuid:bd3dcf2f-0954-533a-a264-a0a8625f5cfb</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/freshrss-un-point-zero.html" rel="alternate" type="text/html" /><published>2015-01-31T15:35:00+01:00</published><updated>2015-01-31T15:35:00+01:00</updated><content type="html">&lt;p&gt;Elle est là, enfin ! La version 1.0 de FreshRSS, meilleur agrégateur à auto-héberger au monde (du moins selon moi), est sortie.&lt;/p&gt;
&lt;p&gt;Ceux qui me suivent un peu savent que je tenais tout particulièrement à cette version. En effet, je ne pouvais considérer mon logiciel terminé sans cette version qui venait clôre un cycle particulièrement important de développement (deux ans et trois mois tout de même !). Cette nouvelle version vient changer un petit paquet de choses. J’expliquerai néanmoins dans un prochain article plus personnel pourquoi j’ai (un peu) précipité la sortie de cette version.&lt;/p&gt;
&lt;p&gt;Les liens habituels :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Le site officiel : &lt;a href="http://freshrss.org"&gt;freshrss.org&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;La démo en version 1.0 : &lt;a href="http://demo.freshrss.org"&gt;demo.freshrss.org&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Le dépôt de code &lt;a href="https://github.com/FreshRSS/FreshRSS"&gt;sur GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Le bugtracker aussi &lt;a href="https://github.com/FreshRSS/FreshRSS/issues"&gt;sur GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Les différentes versions bêta&lt;/h2&gt;
&lt;p&gt;Depuis fin septembre, quatre versions différentes sont sorties. La dernière fut la 0.9.4 sortie à la mi-janvier. Voici un petit tour des ajouts et modifications de chaque version.&lt;/p&gt;
&lt;h3&gt;FreshRSS 0.9.1&lt;/h3&gt;
&lt;p&gt;Sortie en même temps que la discrète 0.8.1, il s’agissait en fait d’une version de stabilisation. Pas grand chose de neuf si ce n’est des corrections de bugs et quelques ajouts au système de statistiques.&lt;/p&gt;
&lt;h3&gt;FreshRSS 0.9.2&lt;/h3&gt;
&lt;p&gt;Une version qui a demandé pas mal de boulot puisqu’il s’agissait de réécrire toute la partie de gestion des abonnements avec, notamment, la possibilité de réorganiser ses flux par « drag and drop ».&lt;/p&gt;
&lt;p&gt;J’en profitai aussi pour revoir la colonne de gauche listant les catégories et flux lors de la consultation des articles. Plus jolie, plus pratique.&lt;/p&gt;
&lt;p&gt;Les changements sous le capot n’étaient pas en reste car c’était l’occasion de réécrire des parties importantes comme l’authentification et la récupération des articles. Toute la partie coding style était aussi améliorée.&lt;/p&gt;
&lt;h3&gt;FreshRSS 0.9.3&lt;/h3&gt;
&lt;p&gt;Une version un peu moins conséquente que la précédente et pour cause, je participais au NaNoWriMo durant le mois de novembre. Je n’ai pas pu être aussi présent pour cette version. Néanmoins on a vu arriver un nouveau sélecteur de thème (made by &lt;a href="https://github.com/aledeg"&gt;@aledeg&lt;/a&gt;) et le nouveau thème BlueLagoon (made by &lt;a href="https://github.com/misterair"&gt;@Mister aiR&lt;/a&gt;). Une fonctionnalité assez démandée arrivait aussi : la disparition des articles une fois lus.&lt;/p&gt;
&lt;p&gt;Sous le capot, j’ai tout de même profité de la première quinzaine de décembre pour réécrire toute la partie qui gérait l’internationalisation de FreshRSS. Un travail long et pénible mais qui facilite pas mal la gestion des langues.&lt;/p&gt;
&lt;h3&gt;FreshRSS 0.9.4&lt;/h3&gt;
&lt;p&gt;Une version bien sympathique puisqu’elle apportait avec elle le système d’extensions. Celui-ci n’était pas aussi complet que je l’avais voulu mais ça m’aurait demandé tellement de travail que j’ai préféré le sortir un peu limité dès la mi-janvier. Quelques extensions &lt;a href="https://github.com/FreshRSS/Extensions"&gt;sont disponibles sur Github&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;J’en ai profité pour faire quelques gros changements sous le capot comme la réécriture du système de configuration et du système de partage (qui devrait encore évoluer dans le futur) et une réorganisation des fichiers utilisateurs.&lt;/p&gt;
&lt;h2&gt;FreshRSS 1.0.0&lt;/h2&gt;
&lt;p&gt;Pour ceux qui tournent en 0.9.4, vous ne verrez rien de très neuf. En effet, je n’ai pas voulu intégrer trop de changements pour éviter une version majeure toute cassée. La version 1.0 sera donc uniquement une version de stabilisation de la 0.9.4 avec quelques jolis et moins jolis bugs en moins (et notamment &lt;a href="https://github.com/FreshRSS/FreshRSS/issues/700"&gt;celui qui m’aura valu la plus belle prise de tête&lt;/a&gt; depuis que je fais du PHP).&lt;/p&gt;
&lt;p&gt;Une nouveauté tout de même intéressante, c’est l’arrivée de l’Allemand comme langue supportée par FreshRSS ! (j’en reparle plus loin)&lt;/p&gt;
&lt;h3&gt;Mise à jour&lt;/h3&gt;
&lt;p&gt;Depuis la version 0.8.0, FreshRSS dispose d’un système de mise à jour automatique (et ça c’est la grande classe !). Aussi vous n’avez qu’à vous rendre dans l’interface d’administration pour lancer la mise à jour. &lt;strong&gt;Note importante&lt;/strong&gt; : je déconseille fortement d’utiliser une autre méthode au risque de casser votre instance ! Seul le système de mise à jour automatique permet de mettre à jour facilement les fichiers situés dans votre répertoire &lt;code&gt;./data&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Précision : deux versions sont sorties en même temps, la 1.0.0 (stable) et la 1.1.0 (la même mais dans la branche bêta). Cela permet d’avoir une vraie distinction entre les branches et surtout de faciliter le processus de mise à jour.&lt;/p&gt;
&lt;h2&gt;La suite : un projet plus communautaire&lt;/h2&gt;
&lt;p&gt;J’en parlerai plus en détail dans l’article qui suivra mais je compte m’effacer un peu du projet FreshRSS afin de bosser sur d’autres choses et voyager. Je sais que ça sonne un peu comme un Mozilla annonçant l’arrêt des améliorations de Thunderbird ou les développeurs de Diaspora* annonçant leur retrait du projet qu’ils avaient initié, mais cela a plutôt bien réussi pour ce dernier. Comme il serait idiot que FreshRSS coule à cause de mon absence, j’ai déjà entreprit quelques taches pour rendre le projet plus ouvert aux contributions.&lt;/p&gt;
&lt;p&gt;Tout d’abord, j’ai déplacé le dépôt de l’adresse &lt;a href="https://github.com/marienfressinaud/FreshRSS"&gt;https://github.com/marienfressinaud/FreshRSS&lt;/a&gt; à l’adresse &lt;a href="https://github.com/FreshRSS/FreshRSS"&gt;https://github.com/FreshRSS/FreshRSS&lt;/a&gt;. Ça peut paraître assez peu mais cela m’a permis de donner les « clés » officiellement à @Alkarex et @aledeg qui peuvent gérer tous les dépôts associés &lt;a href="https://github.com/FreshRSS"&gt;à l’organisation FreshRSS&lt;/a&gt;. De plus cela a impliqué de détacher FreshRSS de mon nom : ça peut paraître assez égoïste mais je suis assez fier d’avoir eu ce succès avec cet agrégateur ; le lier à un compte « global » signifie que je ne suis plus qu’un contributeur comme les autres. Au final je suis content de ce choix qui permet de ne pas avoir une tête qui dépasse mais seulement un projet global avec des contributeurs, c’est la continuation logique d’un projet Libre selon moi.&lt;/p&gt;
&lt;p&gt;La prochaine étape va être d’ouvrir un blog spécifique à l’actualité de FreshRSS plutôt que de publier ici.&lt;/p&gt;
&lt;p&gt;Une tâche importante que je dois terminer va être de documenter conséquemment le code ainsi que les fonctionnalités pour favoriser les contributions externes. J’ai déjà commencé mais il faut finir maintenant.&lt;/p&gt;
&lt;p&gt;Le fait que je me retire un peu du projet ne signifie pas non plus que je ne vais plus y participer : je continuerai de donner mes idées, mes avis et surement même quelques lignes de code. Je me propose aussi pour continuer de gérer les scripts de mise à jour et les sorties de version (mais j’écrirai des tutoriels pour faire ça).&lt;/p&gt;
&lt;p&gt;Par contre très concrètement, j’aimerais désormais éviter que l’on me contacte directement par mail par rapport à FreshRSS (même si ça fait toujours plaisir ;)).&lt;/p&gt;
&lt;p&gt;Pour conclure, j’ai une véritable volonté de faire de FreshRSS un projet plus communautaire. Je crois qu’il n’existe pas aujourd’hui d’agrégateur libre véritablement bati autour d’une communauté : &lt;a href="http://tontof.net/kriss/feed/"&gt;Kriss Feed&lt;/a&gt; et &lt;a href="http://leed.idleman.fr/"&gt;Leed&lt;/a&gt; n’ont pas donné signe de vie depuis plusieurs mois, &lt;a href="http://tt-rss.org/redmine/projects/tt-rss/wiki"&gt;TinyTinyRSS&lt;/a&gt; est un gros projet mais son développeur principal est « assez peu ouvert » de ce que j’en ai compris et par contre je ne sais pas ce qu’il en est vraiment de &lt;a href="http://selfoss.aditu.de/"&gt;selfoss&lt;/a&gt;. Dans tous les cas ces projets restent batis autour d’une personnalité et non pas du logiciel en lui-même.&lt;/p&gt;
&lt;h2&gt;Les remerciements&lt;/h2&gt;
&lt;p&gt;Comme à chaque fois, je tiens à remercier les différents contributeurs. En plus d’&lt;a href="https://github.com/Alkarex"&gt;@Alkarex&lt;/a&gt; et d’&lt;a href="https://github.com/aledeg"&gt;@aledeg&lt;/a&gt;, &lt;a href="https://github.com/Alwaysin"&gt;@Alwaysin&lt;/a&gt; et &lt;a href="https://github.com/Draky50110"&gt;@Draky50110&lt;/a&gt; continuent toujours de beaucoup commenter, tester et donner leur avis. Leur présence permet de tester différents cas et trouver des bugs oubliés.&lt;/p&gt;
&lt;p&gt;Nous avons eu aussi dernièrement une forte présence du côté de l’Allemagne avec deux articles &lt;a href="http://www.robbenradio.de/dc/index.php?post/53"&gt;coup&lt;/a&gt; sur &lt;a href="http://linuxundich.de/gnu-linux/tiny-alternative-freshrss-installieren-news-plus-handy/"&gt;coup&lt;/a&gt; et l’arrivée d’un contributeur (&lt;a href="https://github.com/ealdraed"&gt;@ealdraed&lt;/a&gt;) qui a traduit l’ensemble du projet en très peu de temps. Une très bonne surprise !&lt;/p&gt;
&lt;p&gt;Autre énorme surprise, celle d’avoir été cité en octobre sur le site &lt;a href="http://opensource.com"&gt;opensource.com&lt;/a&gt; dans &lt;a href="http://opensource.com/life/14/10/five-open-source-alternatives-popular-web-apps"&gt;un article de blog présentant cinq logiciels&lt;/a&gt; (dont &lt;a href="https://www.wallabag.org/"&gt;wallabag&lt;/a&gt; et &lt;a href="http://sebsauvage.net/wiki/doku.php?id=php:shaarli"&gt;shaarli&lt;/a&gt;). Trois jours plus tard &lt;a href="https://twitter.com/nixcraft/status/523303778041077761"&gt;c’était un tweet&lt;/a&gt; de &lt;a href="https://twitter.com/nixcraft"&gt;@nixCraft&lt;/a&gt; (+40 000 abonnés) qui ramenait du monde.&lt;/p&gt;
&lt;p&gt;Suite à la série d’articles qu’il y a pu avoir autour de FreshRSS, j’ai ouvert &lt;a href="https://github.com/FreshRSS/freshrss.org/issues/9"&gt;un ticket spécial&lt;/a&gt; listant ces articles. Vous êtes libres de pointer les votres ou ceux que vous croisez :).&lt;/p&gt;
&lt;p&gt;Il y a encore des tas de personnes à remercier : &lt;a href="http://www.dadall.info/blog/"&gt;dada&lt;/a&gt; pour ses articles, &lt;a href="https://github.com/plopoyop"&gt;@plopoyop&lt;/a&gt; pour l’intégration dans &lt;a href="http://yunohost.org/"&gt;Yunohost&lt;/a&gt;, toutes les personnes qui remontent des bugs, qui envoient des mails pour remercier et féliciter, &lt;a href="http://cyrille-borne.com/"&gt;Cyrille Borne&lt;/a&gt; qui a écrit quelques mots sur son (ses ?) blog, &lt;a href="http://remitaines.com/"&gt;Mister aiR&lt;/a&gt; pour ses thèmes et ses idées de continuité du projet (avec &lt;a href="https://github.com/dhoko"&gt;@dhoko&lt;/a&gt;), &lt;a href="https://fiat-tux.fr/"&gt;Luc Didry&lt;/a&gt; qui a apporté des pistes pour améliorer l’aspect multi-utilisateurs… et tous ceux que j’oublie !&lt;/p&gt;</content></entry><entry><title>NaNoWriMo, deux semaines plus tard.</title><id>urn:uuid:16333b34-16c2-5e09-9b05-b1071a62f18a</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/nanowrimo-deux-semaines-plus-tard.html" rel="alternate" type="text/html" /><published>2014-11-18T00:09:00+01:00</published><updated>2014-11-18T00:09:00+01:00</updated><content type="html">&lt;p&gt;Petite mise à jour par rapport au NaNoWriMo. J’avais prévu un article à la fin de la première semaine mais je n’ai jamais réussi à le terminer. Je l’ai donc jeté et commencé un nouveau !&lt;/p&gt;
&lt;p&gt;Pour rappel, le NaNo c’est avant tout un défi &lt;strong&gt;personnel&lt;/strong&gt;. Je me suis fixé comme objectif d’écrire un bouquin que j’imagine depuis plusieurs mois déjà pour l’occasion. Son nom sera probablement &lt;em&gt;Asmara&lt;/em&gt;. Il s’agit d’un roman de science fiction et d’anticipation. Pour donner une idée de quoi ça va parler, sachez que j’ai commencé à imaginer l’histoire en partant de zéro mais en référence au roman &lt;em&gt;1984&lt;/em&gt; de George Orwell. Au fur et à mesure que le scénario s’est mis en place, je me suis rendu compte que l’histoire se rapprochait de plus en plus du film culte des frères (et sœur maintenant) Wachowski, &lt;em&gt;Matrix&lt;/em&gt;. Au final, je crois que &lt;em&gt;Asmara&lt;/em&gt; tient plus de &lt;em&gt;Matrix&lt;/em&gt; alors que ce n’était absolument pas mon but initial ! Je ne prétends pas arriver à une histoire de la qualité et de la profondeur de &lt;em&gt;1984&lt;/em&gt; ou &lt;em&gt;Matrix&lt;/em&gt;, je me suis simplement inspiré de ces œuvres et permis quelques (nombreux ?) clins d’œil ;).&lt;/p&gt;
&lt;p&gt;Premier point à retenir sur mon NaNo : ça avance ! Le NaNo c’est (au moins) 50 000 mots en un mois, j’en suis pour l’instant à 36 213, ce qui constitue déjà en soi un petit exploit. Si je devais donner un unique conseil pour le NaNo, c’est de se fixer une limite minimale de nombre de mots à écrire par jour. Cette planification m’a énormément aidé à avancer jusque-là en me forçant, les jours où j’étais moins motivé, à écrire quand même. Si je m’étais fixé au départ 2 000 mots par jour pendant le mois, j’ai décidé de passer en cette troisième semaine à un objectif de 2 700 mots pour finir d’ici dimanche. Ça peut sembler être une augmentation superficielle, mais c’est déjà pas mal sachant que ma moyenne est de 2 130 mots par jour (avec une jolie pointe à 4 156 jeudi dernier !).&lt;/p&gt;
&lt;p&gt;La plus grosse difficulté est certainement de gérer correctement sa motivation. Il faut avouer que lorsqu’on se prend une ou deux journées de pause, la reprise est compliquée. Entre le doute (« &lt;em&gt;Est-ce que mon histoire est bonne ?&lt;/em&gt; ») et le manque d’inspiration, ce n’est pas toujours facile d’avancer. En un peu plus de deux semaines de NaNo, j’ai tout de même mis en place un certain nombre de mécanismes. Le premier, c’est d’écrire le soir et la nuit : je suis beaucoup moins distrait et donc plus performant entre 17h et 23h que le reste de la journée. Autre point important, c’est la musique. J’évite les chansons dont les paroles ne font que de me distraire. Je me concentre principalement sur des artistes comme Massive Attack, Archive, EZ3kiel (qui vient de sortir un nouvel album au passage :p) ou UNKLE que j’ai découvert pour l’occasion. Le fait de les passer en boucle n’est pas dérangeant car lorsqu’on est concentré sur l’histoire, on n’y fait presque plus attention. À l’inverse, quand on est en perte de motivation, la musique peut avoir un effet dopant qui booste la concentration ! Dernier point pour me motiver et concentrer, c’est de m’enlever le maximum de distraction autour de moi. Ça peut passer par ranger le bureau ou écrire dans un éditeur de texte en plein écran sans aucune notification pour déranger. La semaine dernière, j’ai même rangé l’appartement et fait la vaisselle parce que l’idée que ce n’était pas fait m’obnubilait. Une fois terminé, je me suis rendu compte que je n’avais plus aucun mal à écrire. Alors oui c’est purement psychologique, mais si ça marche, moi, ça me va !&lt;/p&gt;
&lt;p&gt;Une chose intéressante dans le NaNo, c’est aussi de voir les autres avancer. Il y a ceux qui peinent et abandonnent rapidement (non non, je ne vise personne :)). Il y a ceux qui doutent, qui avancent difficilement (non je ne vise toujours personne :p). Il y a ceux qui, comme moi, avancent assez bien, tiennent le cap et finiront légèrement en avance. Et enfin, il y a les fusées : eux, ce sont les plus déprimants (je déconseille d’ailleurs d’aller lire certains topics des forums du NaNo si on est en pleine démotivation !). Ceux-là se sont les habitués : ils écrivent leurs 50 000 mots en moins d’une semaine, voire moins d’une journée. J’avoue que je n’ai aucune idée de comment ils font, mais c’est assez beau à voir. Bref, le NaNo ce n’est pas uniquement un défi personnel, c’est aussi une communauté. Pour ma part j’essaye de retranscrire chaque soir mon humeur d’après-séance sur le réseau social Diaspora* pour faire le point sur mon avancement, sur les difficultés, mes bonnes nouvelles et sur comment je sens la suite. Je tiens une sorte de journal de bord et je pense que je remettrai tout ça au propre à la fin et que je le diffuserai en même temps que le bouquin.&lt;/p&gt;
&lt;p&gt;En parlant de diffusion, j’ai décidé de placer &lt;em&gt;Asmara&lt;/em&gt; sous licence &lt;a href="http://creativecommons.org/publicdomain/zero/1.0/deed.fr"&gt;Creative Commons Zéro&lt;/a&gt;, c’est-à-dire de l’&lt;em&gt;élever&lt;/em&gt; dans le domaine public. On m’a régulièrement demandé ce que je comptais faire du bouquin après l’avoir écrit et le choix de la licence a semblé surprendre (surtout ma famille en fait) : l’écriture de ce roman est pour moi juste l’envie de réaliser un rêve de gosse, je n’ai jamais eu envie de faire de l’argent avec ça (surtout que je ne suis pas encore certain que ça puisse marcher). Plus que l’argent, c’est les lecteurs qui m’importent : avoir un retour construit pour me faire progresser. Diffuser un roman dans le domaine public permet l’accès à l’histoire à un maximum de personnes. Le choix du domaine public c’est une histoire de partage, pas d’argent. C’est aussi une affaire de convictions : je trouve plus « juste » qu’une œuvre soit dans le domaine public que dépendant d’un auteur unique voire de ses descendants. Si vraiment l’histoire vaut le coup d’être publiée chez un éditeur (encore une fois, je n’en suis pas sûr), je verrai ce qu’il est possible de faire.&lt;/p&gt;
&lt;p&gt;D’un point de vue technique, comment se passera la mise à disposition du roman ? Je suis encore en train de me tâter mais je pense relire et mettre à disposition un chapitre par semaine sur ce blog. Ça me permettra de corriger les fautes et incohérences au fil de l’eau tout en permettant de ne pas noyer les lecteurs. J’ai essayé de terminer chaque chapitre par une pointe de suspens ce qui, je l’espère, maintiendra l’intérêt pour &lt;em&gt;Asmara&lt;/em&gt; durant les semaines de « livraison ». Il devrait y avoir 19 chapitres donc 19 semaines. Une fois que tous les chapitres auront été publiés je referai une dernière grosse relecture et publierai les sources du roman, une version PDF et probablement une version EPUB (format de fichiers pour les livres numériques).&lt;/p&gt;
&lt;p&gt;Je vais donc essayer d’augmenter le rythme d’écriture pour essayer de terminer dimanche et commencer la relecture dans la foulée. Ça va être une grosse semaine, mais ça vaut vraiment le coup ! En attendant, j’ai écrit le synopsis du roman sur &lt;a href="http://nanowrimo.org/participants/marien-fressinaud/novels/asmara"&gt;le site du NaNo&lt;/a&gt; (et pour le coup, je n’en suis pas satisfait du tout !).&lt;/p&gt;</content></entry><entry><title>En novembre, c’est NaNoWriMo</title><id>urn:uuid:e2c48728-b547-50c2-a9e5-4b7106250b1e</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/en-novembre-cest-nanowrimo.html" rel="alternate" type="text/html" /><published>2014-10-31T19:51:00+01:00</published><updated>2014-10-31T19:51:00+01:00</updated><content type="html">&lt;p&gt;Alors que j’ai débuté depuis mi-septembre mes neuf mois sabbatiques sur les chapeaux de roues (développement de FreshRSS principalement), le mois de novembre est maintenant à ma porte.&lt;/p&gt;
&lt;p&gt;Comme je l’avais évoqué dans mon article du 14 juin, je me lance dans le NaNoWriMo (que j’abrègerai par NaNo désormais). Le NaNo c’est quoi ? C’est avant tout un défi personnel. Chaque mois de novembre, des milliers de personnes se lancent dans l’écriture d’un roman d’au moins 50 000 mots. Il n’y a pas de sujet imposé, pas de contrainte particulière, seulement 50 000 mots à écrire en l’espace d’un mois.&lt;/p&gt;
&lt;p&gt;Ayant découvert ce défi l’année dernière à travers les expériences de &lt;a href="https://ploum.net/9-ans-de-blog-le-defi-nanowrimo/"&gt;Ploum&lt;/a&gt; et de &lt;a href="http://www.framablog.org/index.php/?q=Nanowrimo"&gt;Pouhiou&lt;/a&gt;, j’ai eu envie de me lancer pour renouer avec une passion que j’avais au collège et au lycée : l’écriture. J’ai donc eu un an pour me motiver et, maintenant, on y est ! Le sujet de mon histoire est désormais arrêté. Je ne détaillerai pas le scénario ici (ni même de visu, j’attends d’avoir fini l’histoire et d’en être satisfait pour cela ! ;)) mais ce sera de la science fiction et l’histoire se nommera probablement &lt;em&gt;Asmara&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Pour le suivi de ce défi, j’essayerai d’écrire régulièrement ici pour tenir au courant mais comme je me connais, je risque de ne pas être très productif. Le mieux reste encore de venir faire un tour sur Diaspora&lt;em&gt; (vous pouvez vous inscrire sur &lt;a href="https://framasphere.org/"&gt;Framasphère&lt;/a&gt;, mon identifiant est marienfr@diaspora-fr.org) où je serai probablement plus bavard. Un autre avantage de Diaspora&lt;/em&gt; c’est qu’il y a tout un tas de gens qui se sont lancés dans le NaNo cette année que vous pouvez rencontrer en suivant le tag &lt;a href="https://framasphere.org/tags/nanowrimo"&gt;#NaNoWriMo&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Pour finir ce court article, j’ai vraiment hâte de voir le résultat final. Cela doit faire plus de cinq ans que je n’ai pas pris le temps d’écrire une vraie histoire et je me demande vraiment comment je vais gérer le rythme (je me suis fixé 2 000 mots par jour). Vous pourrez me retrouver sur le site du Nano sous le nom de… &lt;a href="http://nanowrimo.org/participants/marien-fressinaud"&gt;Marien Fressinaud&lt;/a&gt; !&lt;/p&gt;</content></entry><entry><title>FreshRSS 0.8 : retour sur sept mois de travail</title><id>urn:uuid:e8ed730c-4308-5160-aeb4-09baa8c4d78a</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/freshrss-0-8-retour-sur-sept-mois-de-travail.html" rel="alternate" type="text/html" /><published>2014-09-23T23:46:00+02:00</published><updated>2014-09-23T23:46:00+02:00</updated><content type="html">&lt;p&gt;Nous y voilà, la nouvelle version de la branche master de FreshRSS sort aujourd’hui, sept mois après la version 0.7.1 !&lt;/p&gt;
&lt;p&gt;Comme les grosses nouveautés de cette version ont déjà été annoncées lors des sorties des versions bêta (0.7.2, 0.7.3 et 0.7.4), je ne vais faire qu’un rappel des grosses nouveautés.&lt;/p&gt;
&lt;p&gt;Avant de débuter, quelques liens utiles :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Le site officiel : &lt;a href="http://freshrss.org/"&gt;freshrss.org&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;La démo en version 0.8 : &lt;a href="http://demo.freshrss.org/"&gt;demo.freshrss.org&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Le dépôt de code &lt;a href="https://github.com/FreshRSS/FreshRSS"&gt;sur GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Le bugtracker aussi &lt;a href="https://github.com/FreshRSS/FreshRSS/issues"&gt;sur GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Retour sur les versions bêta&lt;/h2&gt;
&lt;p&gt;La version 0.7.2 (première bêta) voyait l’arrivée de l’API compatible avec les applications Google Reader. Un gros travail a été fait par Alkarex ici et qui a mené à la possibilité d’utiliser deux applications mobiles différentes sur Android (&lt;a href="https://github.com/Alkarex/EasyRSS"&gt;EasyRSS&lt;/a&gt; et &lt;a href="https://play.google.com/store/apps/details?id=com.noinnion.android.newsplus.extension.google_reader"&gt;News+&lt;/a&gt;). Je profitai aussi de cette version pour introduire le nouveau système d’import / export des flux et des articles. Ce nouveau système permet notamment d’exporter ses favoris pour les réimporter ailleurs. Le format utilisé est celui de feu Google Reader (encore lui !) et il est donc possible d’importer les articles que vous avez potentiellement gardé dans un coin de votre &lt;del&gt;disque dur&lt;/del&gt; SSD.&lt;/p&gt;
&lt;p&gt;La version 0.7.3 ajoutait le support de SQLite pour le système de stockage en plus de MySQL/MariaDB. C’était une &lt;strong&gt;très&lt;/strong&gt; forte demande de la part de nombreuses personnes et j’avoue que c’est agréable de ne pas avoir à taper toutes les informations de base de données à chaque fois (SQLite génère un simple fichier par utilisateur).&lt;/p&gt;
&lt;p&gt;La grande nouveauté de la version 0.7.4 était le magnifique thème Screwdriver de Mister aiR. Beaucoup de compliments ont été fait à son sujet et je trouve qu’il permet bien de mettre en valeur FreshRSS.&lt;/p&gt;
&lt;h2&gt;La version 0.8&lt;/h2&gt;
&lt;p&gt;Aujourd’hui sort donc la version 0.8, une grande étape pour la suite puisqu’elle signe le début d’une forte activité de ma part dans le développement de FreshRSS. En effet, comme je l’expliquais en juin dernier, j’ai débuté neuf mois sabbatiques (dont trois de voyage) pour me consacrer à mes projets personnels. Une priorité que je me suis donné et de sortir un version 1.0 d’ici la fin de l’année. Cette version 0.8 marque donc la fin de mes études (avec deux semaines de retard, certes). J’ai pas mal travaillé dessus pour corriger des petits détails qui avaient leur importance (que ce soit en termes de sécurité, de design ou de fonctionnalités).&lt;/p&gt;
&lt;p&gt;La grosse nouveautés de cette version, c’est le nouveau système de mise à jour. Si auparavant il était nécessaire de faire pas mal de manipulations à la main, désormais il vous suffira de cliquer sur un bouton, éventuellement préciser certaines informations et confirmer la mise à jour. Le reste, c’est FreshRSS qui s’en chargera.&lt;/p&gt;
&lt;p&gt;Une plus petite amélioration qui me tenait à cœur, c’est l’affichage des statistiques (que l’on doit par ailleurs à aledeg qui a fait du très bon travail à ce niveau-là !). J’ai donc réorganisé les différents blocs pour une meilleure utilisation de l’écran ce qui, j’espère, rend les choses plus agréables à regarder.&lt;/p&gt;
&lt;p&gt;Pour terminer sur les nouveautés de cette version 0.8, j’ai intégré ce matin même un nouveau thème : &lt;a href="https://github.com/plopoyop/FreshRSS/tree/dev/p/themes/Pafat"&gt;Pafat&lt;/a&gt; par &lt;a href="https://github.com/plopoyop"&gt;plopoyop&lt;/a&gt;. Merci à lui !&lt;/p&gt;
&lt;h2&gt;Passer d’une 0.7.x en 0.8&lt;/h2&gt;
&lt;p&gt;Comme le nouveau système de mise à jour n’est présent qu’à partir de la 0.8, il va vous falloir faire une dernière mise à jour à la main ! Avant cela je vous conseille, si vous ne l’avez pas fait régulièrement, de vous assurer d’être en version 0.7.4 (visible dans "À propos"). Changer de version se fait facilement :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Téléchargez FreshRSS : &lt;a href="https://github.com/FreshRSS/FreshRSS/archive/0.7.4.zip"&gt;0.7.4&lt;/a&gt; ou &lt;a href="https://github.com/FreshRSS/FreshRSS/archive/0.8.0.zip"&gt;0.8.0 (stable)&lt;/a&gt; ou &lt;a href="https://github.com/FreshRSS/FreshRSS/archive/0.9.0.zip"&gt;0.9.0 (bêta)&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Décompressez l’archive.&lt;/li&gt;
&lt;li&gt;Supprimez les fichiers et répertoires de votre installation précédente &lt;strong&gt;à l'exception du répertoire &lt;code&gt;./data&lt;/code&gt;&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Remplacez ce que vous venez de supprimer par les fichiers extraits de l'archive à l'étape 2.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Une communauté qui s’agrandit&lt;/h2&gt;
&lt;p&gt;Si je pouvais déjà compter sur le fort soutien d’Alkarex et d’aledeg pour le code et d’Alwaysin pour remonter les bugs et les demandes de fonctionnalités, je remarque que les contributions ponctuelles sont de plus en plus nombreuses. Il y a notamment eu, fin août, en l’espace d’une semaine un Anglais, un Pakistanais et un Allemand qui m’ont chacun envoyé un mail. Fou !&lt;/p&gt;
&lt;p&gt;On notera aussi une certaine activité du tag &lt;a href="https://diaspora-fr.org/tags/freshrss"&gt;#FreshRSS sur Diaspora*&lt;/a&gt;, initié par moi-même évidemment mais avec pas mal de personnes qui semblent en être satisfait :)&lt;/p&gt;
&lt;p&gt;En tout cas, je me répète à chaque fois, si vous avez une question, une proposition, un soucis, envie de remercier ou que sais-je d’autre, GitHub et mon adresse mail vous sont ouverts !&lt;/p&gt;
&lt;h2&gt;Une démarche qualité&lt;/h2&gt;
&lt;p&gt;Comme je sais que mon maître d’apprentissage de ces trois dernières années a toutes les chances de passer par là, j’en profite pour aborder un sujet qui lui est cher :).&lt;/p&gt;
&lt;p&gt;Depuis quelques temps, nous commençons à travailler Alkarex, aledeg et moi à améliorer la qualité globale de FreshRSS. J’avais débuté mon agrégateur comme quelque chose de personnel qui n’intéresserait probablement pas grand monde et cela se ressent. C’est pourquoi :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Les règles de "coding style" &lt;a href="http://doc.freshrss.org/fr/developers/01_First_steps/"&gt;ont bien été définies&lt;/a&gt; et je m’applique à rendre peu à peu tout le code conforme à celui-ci.&lt;/li&gt;
&lt;li&gt;J’ai commencé à m’attaquer plus sérieusement à &lt;a href="http://doc.freshrss.org"&gt;la documentation sur doc.freshrss.org&lt;/a&gt; (en français pour le moment).&lt;/li&gt;
&lt;li&gt;Nous allons prochainement &lt;a href="https://github.com/FreshRSS/FreshRSS/issues/577"&gt;mettre en place des tests&lt;/a&gt; pour éviter les régressions.&lt;/li&gt;
&lt;li&gt;aledeg a initié un mouvement "&lt;a href="https://github.com/FreshRSS/FreshRSS/pull/630/files"&gt;Commentons le code !&lt;/a&gt;".&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;J’espère que ces différentes initiatives permettront d’y voir plus clair et de faciliter les modifications du code source… C’est le but en tout cas !&lt;/p&gt;
&lt;h2&gt;La suite&lt;/h2&gt;
&lt;p&gt;Je l’ai dit : la version 1.0 est prévue d'ici la fin de l'année. Pour être plus précis, voici ce que je prévois pour les mois qui approchent :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Aujourd'hui : sortie des versions 0.8 et 0.9 (son pendant dans la branche bêta).&lt;/li&gt;
&lt;li&gt;10 octobre : sortie des versions 0.8.1 et 0.9.1, les versions de maintenance (je ne me fais pas trop d’illusion, il reste toujours quelques bugs).&lt;/li&gt;
&lt;li&gt;31 octobre : sortie de la version 0.9.2, uniquement une version bêta donc.&lt;/li&gt;
&lt;li&gt;30 novembre : sortie de la version 0.9.3. À noter que durant cette période je participerai aussi au Nanowrimo qui me prendra énormément de temps.&lt;/li&gt;
&lt;li&gt;19 décembre : sortie de la version 1.0. J'évite une sortie le 25 décembre parce que je risque d’avoir moins de retours même si la date m'aurait bien plu.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Au programme, beaucoup de choses :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Un système de plugins&lt;/li&gt;
&lt;li&gt;Refonte de la gestion des catégories&lt;/li&gt;
&lt;li&gt;Un système de web-cron&lt;/li&gt;
&lt;li&gt;Une meilleure gestion du mode multi-utilisateurs (qui reste basique actuellement)&lt;/li&gt;
&lt;li&gt;Support de PostgreSQL&lt;/li&gt;
&lt;li&gt;Le support de l’allemand (initialement prévu pour la 0.8 mais finalement reporté)&lt;/li&gt;
&lt;li&gt;Une nouvelle API (basée sur celle de TTRSS) ?&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/FreshRSS/FreshRSS/milestones/0.9.0"&gt;Et plein d’autres choses !&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Beaucoup de travail donc, mais contre-balancé par une très forte motivation de ma part. Je vais bientôt fêter les deux ans du projet et je vois enfin le bout du tunnel ! Le plus motivant est que j’ai réussi à amener FreshRSS à un niveau de maturité que je n’imaginais même pas au départ et que mon application connait apparemment un certain succès dans le milieu francophone.&lt;/p&gt;
&lt;p&gt;Comme je suis motivé, je prévois quelques suprises pour la sortie de la 1.0 (voire avant) qui devrait permettre à FreshRSS de s’imposer comme une solution incontournable dans le monde des agrégateurs de flux RSS. Ouais, rien que ça. &lt;em&gt;Trust me, I’m an engineer&lt;/em&gt;.&lt;/p&gt;</content></entry><entry><title>FreshRSS 0.7.4 (bêta) : ne ratez plus aucune news</title><id>urn:uuid:30e054f7-3b00-5e56-ac62-5e89948c4a4e</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/freshrss-0-7-4-beta-ne-ratez-plus-aucune-news.html" rel="alternate" type="text/html" /><published>2014-08-24T15:35:00+02:00</published><updated>2014-08-24T15:35:00+02:00</updated><content type="html">&lt;p&gt;Un mois est déjà passé depuis la dernière version et voici donc &lt;a href="https://github.com/FreshRSS/FreshRSS/releases/tag/0.7.4"&gt;une nouvelle bêta&lt;/a&gt; qui apporte son lot de nouveautés qui, comme d’habitude, devraient vous plaire ;)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Les notifications sont de la partie avec la gestion des notifications HTML5. Cette fonctionnalité est vraiment top pour savoir quand de nouveaux articles sont disponibles et marche parfaitement bien sous Firefox et FirefoxOS.&lt;/li&gt;
&lt;li&gt;Combiné à cela, le favicon devient dynamique et affiche le nombre d’articles non lus ! Joli et pratique :)&lt;/li&gt;
&lt;li&gt;Petite nouveauté qui est devenue urgente avec l’acquisition d’un FirefoxOS : la case à cocher pour rester connecté. Plus besoin de se reconnecter à chaque lancement du navigateur.&lt;/li&gt;
&lt;li&gt;La page de statistiques continue de s’étoffer en permettant de visualiser la répartition des articles par heure, jour et mois.&lt;/li&gt;
&lt;li&gt;La grosse nouveauté dont j’ai déjà parlé dans mon Shaarli, c’est le nouveau thème magnifique proposé par &lt;a href="https://github.com/misterair/"&gt;Mister aiR&lt;/a&gt; déjà à l’origine d’un thème pour Shaarli et… Leed :) Grâce à lui j’ai d’ailleurs pu noter quelques limitations dans la création des thèmes, j’en parlerai dans la documentation.&lt;/li&gt;
&lt;li&gt;Tout un tas d’autres petites nouveautés dont des corrections de petits bugs (encore !).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Un mot sur l’avenir de FreshRSS maintenant. Comme déjà évoqué dans mon article "C’est l’histoire d’un break." (&lt;strong&gt;edit&lt;/strong&gt; : cet article n’existe plus), le 14 septembre je termine mes études et mon contrat d’apprentissage pour entamer entre six à douze mois sabbatiques. Je compte bien consacrer le début à FreshRSS afin de sortir une version 1.0 avant la fin de l’année. Pour marquer le coup, je compte sortir la prochaine version stable (la 0.8) le jour de la fin de mon contrat. Comme cela, &lt;del&gt;je&lt;/del&gt; on pourra ensuite commencer des gros travaux dont le système de plugins qui attend depuis longtemps.&lt;/p&gt;
&lt;p&gt;Pour la version 0.8 je compte notamment sortir un nouveau système de mise à jour &lt;strong&gt;complètement automatique&lt;/strong&gt;. J’ai déjà commencé à travailler dessus dans &lt;a href="https://github.com/FreshRSS/FreshRSS/tree/411-update-system"&gt;une branche à part mais accessible&lt;/a&gt;. Un &lt;a href="https://github.com/FreshRSS/update.freshrss.org"&gt;dépôt supplémentaire a été créé&lt;/a&gt; pour gérer la partie serveur de ce nouveau système de mise à jour. Tout est fonctionnel actuellement mais pas trop testé. Je pense d’ailleurs que ce sera la dernière (voire la seule) grosse amélioration de cette version.&lt;/p&gt;
&lt;p&gt;Je tiens encore (et toujours) à remercier les différents contributeurs très actifs (Alexandre, Alexis, Alwaysin, que des A !), les personnes qui parlent de FreshRSS, ceux qui soutiennent, qui font des propositions, qui envoient des mails, qui font des dons, etc. Je suis vraiment ébahi qu’autant de monde participe à FreshRSS :) J’en profite d’ailleurs pour rappeler, si vous voulez donner un coup de pouce, que j’ai ajouté le projet &lt;a href="http://alternativeto.net/software/freshrss/"&gt;sur AlternativeTo.net&lt;/a&gt;. J’étais un peu dubitatif de l’intérêt au début mais finalement j’ai pas mal de visites en provenance de ce site donc ça vaut le coup "de liker" le projet pour le faire connaître encore un peu plus ;)&lt;/p&gt;</content></entry><entry><title>FreshRSS 0.7.3 (bêta) : libérez-vous de MySQL</title><id>urn:uuid:62ad0aea-1d34-53cc-b642-d99c291baf71</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/freshrss-0-7-3-beta-liberez-vous-de-mysql.html" rel="alternate" type="text/html" /><published>2014-07-21T18:47:00+02:00</published><updated>2014-07-21T18:47:00+02:00</updated><content type="html">&lt;p&gt;Comme prévu dans l’un de mes derniers articles, voici, avec (à peine) plus de cinq semaines de développement, une nouvelle version bêta de FreshRSS !&lt;/p&gt;
&lt;p&gt;Au programme, des petites nouveautés :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Réécriture des thèmes Flat et Dark pour mieux correspondre aux "standards" définis&lt;/li&gt;
&lt;li&gt;Ajout d’une limite configurable pour la fréquence de synchronisation des flux. Je vois souvent des gens qui rafraîchissent leur flux toutes les une ou deux minutes : ça ne sert à rien et vous bouffez les ressources des sites ! Avec cette fonctionnalité, nous vous limitons cette possibilité en vous imposant une fréquence d’au moins 20 minutes entre deux actualisations (une heure par défaut).&lt;/li&gt;
&lt;li&gt;Ajout d’un système de filtres (queries en anglais). Ce sont, en gros, des raccourcis que vous créez à partir de vos recherches. Imaginons que vous recherchiez le thème "FreshRSS" apparu dans les articles de la semaine dernière (&lt;code&gt;date:P1W FreshRSS&lt;/code&gt;) dans la catégorie "Les trucs que j’aime". Au lieu de devoir taper ça à chaque fois, vous n’avez qu’à créer un filtre à partir de la page courante et le raccourci se glisse dans la barre des filtres.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ça c’était pour les petites news. Il en reste une qui devrait faire plaisir à pas mal de monde : &lt;strong&gt;&lt;a href="https://github.com/FreshRSS/FreshRSS/issues/100"&gt;le support de SQLite ! \o/&lt;/a&gt;&lt;/strong&gt; Il s’agissait d’une demande de longue date mais qui nécessitait plus de travail que prévu (le langage SQL, bien que standardisé, se trouve géré bien différemment selon les moteurs SQL). Notez bien que SQLite n’est pas la solution que je recommande si vous avez de grosses quantités de données : nos premiers tests sont plutôt concluant mais les requêtes ne sont pas particulièrement optimisées. Si par contre vous ne suivez que quelques flux et / ou que vous ne stockez pas les articles sur de longues durées, ça peut sans doute vous convenir.&lt;/p&gt;
&lt;p&gt;Avec le support de SQLite, à priori FreshRSS devrait attirer plus de monde. Par conséquent j’espère avoir encore plus de retours :)&lt;/p&gt;
&lt;p&gt;Avec tout ça, j’ai aussi débuté en parallèle &lt;a href="http://doc.freshrss.org/"&gt;la documentation&lt;/a&gt; un peu plus sérieusement. Pas grand chose de plus, mais ça va prendre forme au fur et à mesure. Si certains sont motivés pour donner un coup de main, &lt;a href="https://github.com/FreshRSS/FreshRSS/issues/123"&gt;un ticket est ouvert pour en parler&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Niveau communauté, je remercie une fois de plus les contributeurs les plus actifs, &lt;a href="https://github.com/Alkarex"&gt;Alexandre&lt;/a&gt; et &lt;a href="https://github.com/aledeg"&gt;Alexis&lt;/a&gt;, pour leur super travail ! Il y a aussi tous ceux qui remontent les bugs : je ne les nomme pas individuellement parce que, mine de rien, il commence à y en avoir pas mal. Ce serait d’ailleurs sympa que GitHub propose un système pour voir les plus gros contributeurs en nombre de commentaires dans les tickets. En attendant vous pouvez toujours &lt;a href="https://github.com/FreshRSS/FreshRSS/issues"&gt;tous les retrouver sur GitHub&lt;/a&gt;… Enfin presque : n’oublions pas tous ceux qui m’envoient des mails que ce soit pour encourager, remercier, remonter des problèmes ou pour suggérer des améliorations.&lt;/p&gt;
&lt;p&gt;En guise de conclusion, j’en profite pour diriger les âmes aventureuses vers &lt;a href="https://github.com/FreederTeam/Freeder"&gt;le projet Freeder&lt;/a&gt; que j’ai découvert suite à une discussion (par mail) avec &lt;a href="http://phyks.me/"&gt;Phyks&lt;/a&gt; et qui cherche à "réinventer" le concept d’agrégateur de flux RSS. Ça me semble un projet intéressant et ça pourrait être l’occasion de mettre en application des idées que je ne pourrai pas mettre en place dans FreshRSS.&lt;/p&gt;</content></entry><entry><title>Nouveau système de sortie pour FreshRSS</title><id>urn:uuid:c6f31809-0873-5cd6-bd31-8d6db0adc577</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/nouveau-systeme-de-sortie-pour-freshrss.html" rel="alternate" type="text/html" /><published>2014-06-13T19:52:00+02:00</published><updated>2014-06-13T19:52:00+02:00</updated><content type="html">&lt;p&gt;Il y a environ quatre mois et demi sortait FreshRSS 0.7 et une vingtaine de jours plus tard le patch 0.7.1. Depuis ? Rien de visible à priori puisque la page principale de Github n’affichait plus aucune activité. Néanmoins ne vous méprenez pas : même si je ne suis pas tout le temps très actif, le projet continue de vivre activement grâce à de fantastiques contributeurs ! Tout se passe dans les tréfonds de &lt;a href="https://github.com/FreshRSS/FreshRSS/tree/dev"&gt;la branche de développement&lt;/a&gt;…&lt;/p&gt;
&lt;p&gt;Partant du constat que l’activité n’était pas suffisamment visible, nous avons décidé de créer une branche bêta qui sera mise à jour tous les mois avec les nouveautés de la branche de développement. La branche bêta est désormais celle par défaut, celle qui est visible en atterrissant sur &lt;a href="https://github.com/FreshRSS/FreshRSS"&gt;https://github.com/marienfressinaud/FreshRSS&lt;/a&gt;. J’espère que cela montrera que FreshRSS est bel et bien vivant !&lt;/p&gt;
&lt;p&gt;Voici le nouveau fonctionnement de sortie des versions (inspiré du système mis en place par Gnome) :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Les numéros impairs (0.7.x, 0.9.x) correspondent aux versions bêta et les numéros pairs (0.8.x, 0.10.x) aux versions "stables"&lt;/li&gt;
&lt;li&gt;Nous travaillons sur la branche &lt;code&gt;dev&lt;/code&gt; avec une feuille de route menant vers une version stable&lt;/li&gt;
&lt;li&gt;Chaque mois, la branche dev est stabilisée &lt;strong&gt;un minimum&lt;/strong&gt; et est mergée dans la branche &lt;code&gt;beta&lt;/code&gt; avec un nouveau numéro de version (0.7.2 par exemple)&lt;/li&gt;
&lt;li&gt;Une fois que toutes les nouveautés prévues pour la version stable sont présentes, on stabilise un maximum le tout et on merge dans la branche &lt;code&gt;master&lt;/code&gt; avec un nouveau numéro de version (0.8.0 par exemple)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;En résumé : vous préférez la stabilité ? Utilisez la branche &lt;code&gt;master&lt;/code&gt;. Vous aimez connaître les nouveautés avant les autres ? Préférez la branche &lt;code&gt;beta&lt;/code&gt; qui est celle par défaut. Vous êtes un fou dans votre tête et vous aimez quand tout est cassé ? Alors essayez la branche &lt;code&gt;dev&lt;/code&gt; !&lt;/p&gt;
&lt;p&gt;Note : je ne préviendrai pas des sorties des versions bêta donc si vous voulez vous tenir au courant, abonnez-vous &lt;a href="https://github.com/FreshRSS/FreshRSS/commits/beta.atom"&gt;au flux RSS dédié sur Github&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Les dernières nouveautés&lt;/h2&gt;
&lt;p&gt;Pour me démentir je vous annonce quand même la sortie de la version bêta 0.7.2. Petite exception car il y a quelques nouveautés sympathiques :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Une API compatible Google Reader pour brancher des applications Android dessus (&lt;a href="https://github.com/FreshRSS/FreshRSS/issues/13#issuecomment-36046833"&gt;ça reste peut-être un peu compliqué à utiliser la première fois&lt;/a&gt; mais ça fonctionne)&lt;/li&gt;
&lt;li&gt;Des boutons pour filtrer plus facilement (le menu se situant au-dessus des articles a été entièrement remanié)&lt;/li&gt;
&lt;li&gt;Un système de recherche plus poussé (&lt;a href="https://github.com/FreshRSS/FreshRSS/issues/511#issuecomment-44776991"&gt;faites-vous plaisir en filtrant au niveau de la date&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Un nouveau système d’import/export qui permet de sauvegarder aussi les articles ! (basé sur le format Google Reader, normalement compatible)&lt;/li&gt;
&lt;li&gt;Le thème Origine a été remanié (entièrement réécrit mais ça ne devrait pas trop se voir ;))&lt;/li&gt;
&lt;li&gt;Une option pour ajuster la largeur du contenu des articles (4 options : fine, moyenne, large et pas de limite)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Malgré tout ça, il reste encore pas mal de boulot avant la 0.8 et quelques bugs à corriger. Je reviens avec un nouvel article dans les prochains jours pour prévenir de la suite des événements car il se pourrait que la tant attendue version 1.0 arrive plus tôt que prévu… Wait and see!&lt;/p&gt;</content></entry><entry><title>Sortie de FreshRSS 0.7.1</title><id>urn:uuid:027b83c5-988b-5401-93c6-161e5a50417a</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/sortie-de-freshrss-0-7-1.html" rel="alternate" type="text/html" /><published>2014-02-19T21:12:00+01:00</published><updated>2014-02-19T21:12:00+01:00</updated><content type="html">&lt;p&gt;Un court article pour vous prévenir que FreshRSS 0.7.1 vient tout juste de sortir.&lt;/p&gt;
&lt;p&gt;C’est un peu plus qu’une version de maintenance vu qu’il y a quelques nouveautés intéressantes comme les raccourcis pour naviguer dans la liste des catégories / flux, des performances accrues au niveau du cache et quelques corrections visuelles. Toutes les modifications sont indiquées dans le &lt;a href="https://github.com/FreshRSS/FreshRSS/blob/master/CHANGELOG"&gt;changelog&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Ce qu’apporte vraiment cette version, c’est une correction d’un bug de rechargement infini de la page au niveau de Persona et &lt;em&gt;J’ESPÈRE&lt;/em&gt; aussi un bug de redirection infinie au niveau de PHP. Pour ce dernier bug je n’ai pas été capable de le reproduire mais j’ai amélioré le système de redirection de la page d’accueil donc ça devrait fonctionner.&lt;/p&gt;
&lt;p&gt;Pour ce qui est du "bug" qui fait que les tables sont dupliquées : en fait ce n’en est pas un. Cela survient lorsque vous changez le préfixe des tables (typiquement en 0.6 vous n’en aviez pas et en 0.7 vous en avez ajouté un) : il est considéré alors qu’on fait une nouvelle installation et les tables ne sont donc pas migrées. Ce sera plus clair pour la 0.8 :)&lt;/p&gt;
&lt;p&gt;Pour installer cette version, c’est simple : soit vous faites une installation toute neuve en écrasant tout, soit vous faites un &lt;code&gt;git pull&lt;/code&gt; (je suppose que ceux qui ne comprennent pas ce que je dis ne sont pas concernés par cette deuxième méthode) ou alors vous pouvez faire une mise à jour :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Supprimez tous les fichiers sauf ceux du répertoire &lt;code&gt;./data&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/FreshRSS/FreshRSS/releases/tag/0.7.1"&gt;Récupérez le code&lt;/a&gt; et déployez le tout comme avant&lt;/li&gt;
&lt;li&gt;Si vous utilisiez la version 0.7.0, vous pouvez vous permettre de supprimer le fichier &lt;code&gt;./p/i/install.php&lt;/code&gt;, sinon je vous renvois sur mon article précédent pour migrer proprement.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Et comme d’habitude si vous avez une question, une suggestion ou simplement envie de m’envoyer un message pour le plaisir vous avez les commentaires, Github ou encore mon adresse mail :)&lt;/p&gt;</content></entry><entry><title>FreshRSS 0.7, ça casse et ça passe !</title><id>urn:uuid:1f302a37-9c49-524f-b63a-7049bcd9f91f</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/freshrss-0-7-ca-casse-et-ca-passe.html" rel="alternate" type="text/html" /><published>2014-01-29T21:31:00+01:00</published><updated>2014-01-29T21:31:00+01:00</updated><content type="html">&lt;p&gt;FreshRSS, l’agrégateur de flux RSS qui déboite tout, sort aujourd’hui en version 0.7. Au menu, des tas de bonnes choses : un mode multi-utilisateurs, des statistiques, un script de mise à jour et des performances qui s’améliorent encore et encore, parmi tant d’autres (j’y reviens dans le reste de cet article). Comme je sais que vous ne tenez déjà plus en place, je vous invite à vous rendre immédiatement sur &lt;a href="http://demo.freshrss.org"&gt;la démo&lt;/a&gt; (demo / demodemo).&lt;/p&gt;
&lt;h2&gt;Un nouveau site fait maison&lt;/h2&gt;
&lt;p&gt;Le précédent site était géré via le système de GitHub. Dans un soucis d’auto-hébergement, j’ai créé un site (en anglais) fait maison avec &lt;a href="http://knacss.com/"&gt;des saucisses bien de chez nous à l’intérieur&lt;/a&gt;. Je pense que celui-ci est plus clair que le précédent et présente mieux les choses. Le lien du site : &lt;a href="http://freshrss.org"&gt;freshrss.org&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Sauvez votre serveur, lâchez TTRSS !&lt;/h2&gt;
&lt;p&gt;FreshRSS était déjà du genre plutôt rapide par rapport à certaines alternatives (&lt;em&gt;keuf&lt;/em&gt;TTRSS&lt;em&gt;keuf&lt;/em&gt;) mais souffrait quand même sur le long terme de ralentissements. Avec les améliorations au niveau de la base de données et des requêtes SQL, FreshRSS semble maintenant pouvoir gérer plus de 100 000 articles sans broncher.&lt;/p&gt;
&lt;p&gt;Des améliorations au niveau du code PHP sont aussi au rendez-vous mais je ne rentrerai pas dans les détails (le &lt;a href="https://github.com/FreshRSS/FreshRSS/blob/master/CHANGELOG"&gt;changelog&lt;/a&gt; est là pour ça).&lt;/p&gt;
&lt;p&gt;TTRSS n’est pas connu pour ses performances, mais grâce à l’ami &lt;a href="https://github.com/konfiot"&gt;@konfiot&lt;/a&gt;, on peut se faire une idée des gains qu’apportent FreshRSS. Voici quelques graphiques représentant l’activité de son serveur. Faut-il vous indiquer explicitement le moment de sa migration ?&lt;/p&gt;
&lt;p&gt;&lt;img alt="activité des entrées-sorties" src="images/freshrss/ttrss_freshrss_io_activity.png" /&gt;&lt;/p&gt;
&lt;p&gt;Activité des entrées-sorties sur le disque dur&lt;/p&gt;
&lt;p&gt;&lt;img alt="requêtes MySQL" src="images/freshrss/ttrss_freshrss_mysql_queries.png" /&gt;&lt;/p&gt;
&lt;p&gt;Activité des requêtes MySQL&lt;/p&gt;
&lt;p&gt;&lt;img alt="Charge sur serveur" src="images/freshrss/ttrss_freshrss_load.png" /&gt;&lt;/p&gt;
&lt;p&gt;Charge du serveur (c’est un peu moins marqué… mais quand même !)&lt;/p&gt;
&lt;p&gt;On me souffle dans &lt;a href="https://github.com/FreshRSS/FreshRSS/blob/master/README.md"&gt;le README&lt;/a&gt; qu’un Raspberry Pi permet de faire tourner une instance de FreshRSS avec 150 flux (~22k articles) en moins d’une seconde.&lt;/p&gt;
&lt;h2&gt;Partagez votre instance de FreshRSS&lt;/h2&gt;
&lt;p&gt;Parmi les demandes récurrentes, on trouvait le mode multi-utilisateurs. Et bien ce mode est désormais disponible ! :) Vous pourrez désormais inviter vos amis, votre famille ou n’importe qui vous rejoindre sur votre instance FreshRSS.&lt;/p&gt;
&lt;p&gt;Petit point technique tout de même pour ne pas que vous soyez surpris. FreshRSS n’a pas été pensé à la base pour du multi-utilisateurs. Aussi, nous n’avons pas touché à la structure de la base de données car ça aurait demandé beaucoup de changements. La solution choisie est de créer de nouvelles tables en BDD, préfixées du nom d’utilisateur. Aussi la taille de votre base de données risque d’exploser si vous invitez beaucoup de monde. Vous êtes prévenus ;).&lt;/p&gt;
&lt;p&gt;Une autre petite nouveauté : un nouveau moyen d’authentification, plus traditionnel (formulaire à remplir). C’est donc aussi une demande de longue date qui a été comblée là. Petit bonus sécurité : si vous ne possédez pas une instance sécurisée de FreshRSS (protocole HTTPS), le mot de passe ne transite pas pour autant en clair sur le réseau. Celui-ci est d’abord hashé côté client en JavaScript avant d’être envoyé. C’est cadeau, mais ça force l’utilisation du JavaScript (m’enfin, vous me direz, ça fait un moment que JavaScript est requis pour l’utilisation de FreshRSS).&lt;/p&gt;
&lt;h2&gt;Lisez l’actualité, même la nuit !&lt;/h2&gt;
&lt;p&gt;La nuit, tous les chats sont gris, mais votre écran d’ordinateur continue d’être blanc comme neige quand vous êtes sur FreshRSS. Dans un soucis de santé publique, un nouveau thème sombre a été développé en association avec les meilleurs contributeurs du moment (merci à &lt;a href="https://github.com/aledeg"&gt;@aledeg&lt;/a&gt; !). Vos yeux vous remercieront.&lt;/p&gt;
&lt;h2&gt;Partagez les articles qui vous intéressent&lt;/h2&gt;
&lt;p&gt;Facebook, Google+, Twitter ? Vous ne connaissez pas et vous préférez &lt;a href="http://sebsauvage.net/wiki/doku.php?id=php:shaarli"&gt;Shaarli&lt;/a&gt;, &lt;a href="https://diasporafoundation.org/"&gt;Diaspora*&lt;/a&gt; ou encore &lt;a href="http://www.wallabag.org/"&gt;wallabag&lt;/a&gt; ? Ces six moyens de partage sont désormais disponibles. Nous avons aussi pensé à ceux qui n’en ont rien à faire : vous pouvez les faire disparaître de la liste si vous n’en voulez pas.&lt;/p&gt;
&lt;h2&gt;Migrez de la 0.6 à la 0.7 sans tout casser&lt;/h2&gt;
&lt;p&gt;Il y aurait bien encore des tas de choses à ajouter sur cette version qui est sans doute la plus conséquente de toutes (nous avons dépassé la barre des 1000 commits !), mais je vais finir en évoquant la mise à jour. Comme évoqué plus haut, il y a eu de gros changements tant au niveau base de données qu’architecture des fichiers. J'avais prévenu lors de la sortie de la 0.6 : tout a été cassé.&lt;/p&gt;
&lt;p&gt;Attention : VOUS NE POURREZ PAS FAIRE CETTE MISE À JOUR SIMPLEMENT À LA MAIN.&lt;/p&gt;
&lt;p&gt;Mais on ne vous laisse pas tout seul pour autant et un script de mise à jour est fourni. Suivez bien ces étapes si vous ne voulez pas tout casser :&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Vérifiez que vous êtes bien en version 0.6. Un moyen simple de le savoir est de regarder dans la configuration si vous pouvez gérer les icônes de lecture. Si oui, alors vous êtes en 0.6 (ou alors déjà en 0.7 mais alors vous saurez très bien vous débrouiller tout seul :)).&lt;/li&gt;
&lt;li&gt;Faites une copie de &lt;code&gt;./app/configuration/application.ini&lt;/code&gt; et de &lt;code&gt;./public/data/Configuration.array.php&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Supprimez le reste&lt;/li&gt;
&lt;li&gt;Déployez la version v0.7 (depuis &lt;a href="https://github.com/FreshRSS/FreshRSS/archive/master.zip"&gt;l’archive ZIP&lt;/a&gt; ou par &lt;a href="https://github.com/FreshRSS/FreshRSS"&gt;git&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Placez &lt;code&gt;application.ini&lt;/code&gt; et &lt;code&gt;Configuration.array.php&lt;/code&gt; dans &lt;code&gt;./data/&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Si vous avez peur, faites une sauvegarde de votre base de données via phpMyAdmin ou grâce à la commande MySQL : &lt;code&gt;mysqldump -u utilisateur -p --databases freshrss &amp;gt; freshrss.sql&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Lancez l’installation de la version 0.7 qui fera la mise à jour automatiquement (cette fois donc, il NE FAUT PAS supprimer le fichier d’installation)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Il n’y a eu aucun soucis lors de nos tests, il n’y a pas de raison que vous en ayez :) Et sinon, ce sont les risques de ne pas utiliser les versions 1.0 :p&lt;/p&gt;
&lt;h2&gt;Ces contributeurs sans qui rien n’aurait été possible&lt;/h2&gt;
&lt;p&gt;Alors que je révisais, passais mes partiels, rentrais en France, passais les fêtes en famille, déménageais et vivais dans le froid à la recherche d’un appartement, le projet a été maintenu à bout de bras, une fois de plus, par &lt;a href="https://github.com/Alkarex"&gt;@alkarex&lt;/a&gt;. Je veux dire, VRAIMENT. Une (très) grosse partie (quasiment la totalité) des améliorations que vous verrez dans cette version est de son propre crû.&lt;/p&gt;
&lt;p&gt;Cette version 0.7 aura aussi vu l’arrivée des contributions d’@aledeg, évoqué plus haut pour son thème "Dark". Ce n’est pas sa seule contribution vu qu’il a aussi ajouté un raccourci pour refermer l’article en cours (la navigation est plus sympa comme ça), créé de nouveaux filtres pour la vue et surtout commencé un travail que j’avais prévu de commencer il y a un petit moment : la page de statistiques ! (j’en parle dans la partie suivante). &lt;a href="https://github.com/Bubbendorf"&gt;@Bubbendorf&lt;/a&gt; n’est pas à oublier non plus puisqu’il a aidé au formatage des nombres et participé à de nombreuses reprises aux tickets de bug.&lt;/p&gt;
&lt;p&gt;Enfin je n’oublie pas, comme toujours, toutes les personnes qui remontent des petits bugs par-ci par-là et/ou qui encouragent et qui font avancer mine de rien FreshRSS. Même si ce n’est pas toujours grand chose, ce sont ces petits trucs qui permettent de parfaire le logiciel. La version 1.0 n’en sera que meilleure ! Puis quand je vois, à chaque nouvelle version, le nombre toujours grandissant d’utilisateurs, on ne peut qu’être confiant dans la qualité de FreshRSS :]&lt;/p&gt;
&lt;h2&gt;Bonus : tout savoir sur vos abonnements en un clin d’œil&lt;/h2&gt;
&lt;p&gt;C’est tout chaud, ça sort du four et c’est la dernière "killer feature" de FreshRSS : la page des statistiques. Vous pourrez dorénavant savoir d’un coup d’œil tout un tas de choses sur vos abonnements. Pour l’instant ça reste limité à la répartition des articles (globalement ou par catégorie), à la répartition des flux par catégorie, au nombre d’articles parus par jour sur les 30 derniers jours et aux flux les plus productifs.&lt;/p&gt;
&lt;p&gt;D’autres graphiques devraient apparaître dans les prochaines versions, mais si vous avez des idées, n’hésitez pas à nous les faire savoir !&lt;/p&gt;
&lt;h2&gt;0.8 en approche&lt;/h2&gt;
&lt;p&gt;Sortir une nouvelle version est synonyme de développement d’une autre. Si vous avez aimé la 0.7, la 0.8 devrait le confirmer. La grosse nouveauté sera &lt;a href="https://github.com/FreshRSS/FreshRSS/issues/13"&gt;l’arrivée d’une API&lt;/a&gt; qui permettra donc de connecter d’autres applications sur FreshRSS. Cela sera utile surtout sur mobile où tout le monde ne veut pas utiliser la version mobile de FreshRSS (qui est parfaitement responsive design, je le rappelle).&lt;/p&gt;
&lt;p&gt;Je ne m’étend pas sur les autres nouveautés qui pourraient éventuellement arriver (catégories arborescentes, gestion de SQLite, import/export des favoris, etc.) car c’est le genre de choses que j’ai tendance à toujours renvoyer à la version d’après :p&lt;/p&gt;
&lt;p&gt;En tout cas, la version 1.0 n’a jamais été aussi proche et j’aimerais la voir arriver dans les six prochains mois ! Y a plus qu’à coder !&lt;/p&gt;</content></entry><entry><title>FreshRSS 0.6 prend son envol</title><id>urn:uuid:30ed88c5-c5fd-5e99-ac74-936ecc9ce5ae</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/freshrss-0-6-prend-son-envol.html" rel="alternate" type="text/html" /><published>2013-11-17T13:28:00+01:00</published><updated>2013-11-17T13:28:00+01:00</updated><content type="html">&lt;p&gt;Un mois après la sortie de la version 0.5, je vous présente FreshRSS 0.6. Toujours plus stable, toujours plus performant, toujours plus utile, FreshRSS deviendra très vite votre plus fidèle compagnon au quotidien. Vous ne pourrez bientôt plus vous en passer !&lt;/p&gt;
&lt;p&gt;Pour vous en faire une première idée, &lt;a href="http://demo.freshrss.org"&gt;la démo a été mise à jour&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Des performances accrues&lt;/h2&gt;
&lt;p&gt;Le gros du travail a porté cette fois-ci sur les performances coté client. On saluera le travail fantastique réalisé par &lt;a href="https://github.com/Alkarex"&gt;Alexandre Alapetite&lt;/a&gt; (à vrai dire, c'est lui qui a quasiment tout fait), désormais contributeur régulier. Les performances ont été améliorées sur deux axes :&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Le code JavaScript : celui-ci a été remanié en grande partie et son chargement grandement amélioré. Ce n’est pas encore parfait, mais une grande étape a été franchie&lt;/li&gt;
&lt;li&gt;La mise en cache : l’utilisation d’un fichier .htaccess permet de garder en cache de manière plus fine les différents fichiers pour les utilisateurs d’Apache. De plus, pour limiter les requêtes inutiles coté serveur, les pages de FreshRSS sont désormais mises en cache de "manière globale" si aucun changement n'a été effectué depuis le dernier chargement.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Du sucre fonctionnel&lt;/h2&gt;
&lt;p&gt;En plus des performances, on notera en vrac quelques améliorations sympathiques (issues du changelog) :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Mise à jour automatique du nombre d’articles non lus&lt;/li&gt;
&lt;li&gt;Amélioration des retours utilisateur lorsque la configuration n’est pas bonne (vous savez, cette fameuse page blanche...)&lt;/li&gt;
&lt;li&gt;Meilleure prise en charge des flux RSS invalides&lt;/li&gt;
&lt;li&gt;Amélioration de la vue globale (toujours un peu plus à chaque version)&lt;/li&gt;
&lt;li&gt;Possibilité de personnaliser les icônes de lecture&lt;/li&gt;
&lt;li&gt;Suppression de deux champs "inutiles" lors de l'installation (base_url et sel)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Toujours pas de version 1.0 !&lt;/h2&gt;
&lt;p&gt;L’arrivée d’Alexandre en contributeur régulier a amené aussi pas mal de conseils pour améliorer les performances. Ceci a donc encore repoussé en partie certaines fonctionnalités et, par conséquent, l’arrivée de la version 1.0. Je ne m’en plains absolument pas car FreshRSS est de plus en plus agréable à utiliser et cela signifie que lors de la sortie de la version finale, il devrait être particulièrement stable et performant.&lt;/p&gt;
&lt;h2&gt;Mise à jour&lt;/h2&gt;
&lt;p&gt;Pas de modification au niveau de la base de données cette fois-ci, tout va bien. Du coup comme d’habitude :&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://github.com/FreshRSS/FreshRSS/archive/0.6.0.zip"&gt;Téléchargez la nouvelle version&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Écrasez les fichiers des répertoires "app", "lib" et "public". Faites attention à garder vos anciens &lt;code&gt;app/configuration/application.ini&lt;/code&gt; et &lt;code&gt;public/data/Configuration.array.php&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Supprimez le fichier &lt;code&gt;public/install.php&lt;/code&gt; car vous n’en avez pas besoin dans le cas d’une mise à jour&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Ou un simple &lt;code&gt;git pull&lt;/code&gt; si vous préférez utiliser Git ;)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Attention :&lt;/strong&gt; je vous préviens tout de suite, mais ce ne sera pas aussi facile pour mettre à jour vers la version 0.7. Il y aura de &lt;strong&gt;très&lt;/strong&gt; gros changements au niveau de la base de données et de l’architecture des fichiers. Si vous suivez la version de dev, faites attention !&lt;/p&gt;
&lt;h2&gt;La version 0.7, celle qui va tout casser&lt;/h2&gt;
&lt;p&gt;Contrairement à ce que je fais d’habitude, je ne vais pas faire de liste des fonctionnalités pour la version 0.7. Je vous redirige plutôt vers le &lt;a href="https://github.com/FreshRSS/FreshRSS/issues?milestone=6"&gt;gestionnaire de bugs&lt;/a&gt; sur Github qui est toujours à jour.&lt;/p&gt;
&lt;p&gt;Néanmoins, comme je le disais juste au-dessus, cette version devrait casser pas mal de choses, donc prenez garde, notamment sur la version de développement.&lt;/p&gt;
&lt;h2&gt;Pour finir&lt;/h2&gt;
&lt;p&gt;Merci encore une fois pour tous les retours que vous m’avez fait, c’est très encourageant et je le répète, c’est grâce à ça que FreshRSS est ce qu’il est aujourd’hui. Je profite aussi de cet article pour vous renvoyer sur &lt;a href="http://linuxfr.org/users/fargo/journaux/freshrss-1-an-et-quelques-dents"&gt;un journal que j’ai écrit sur LinuxFR&lt;/a&gt; pendant que mon site était mort. Je parle surtout de l’année passée à développer mon agrégateur de flux RSS et sur ce que m’a apporté ce travail. C’est un peu long, mais ça peut valoir le coup de le lire si vous souhaitez vous lancer dans un projet personnel.&lt;/p&gt;</content></entry><entry><title>Puzzle solver et intelligence artificielle</title><id>urn:uuid:bb49edd6-eb15-51a8-9a23-358fe6b38cb5</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/puzzle-solver-et-intelligence-artificielle.html" rel="alternate" type="text/html" /><published>2013-11-09T11:07:00+01:00</published><updated>2013-11-09T11:07:00+01:00</updated><content type="html">&lt;p&gt;Une semaine après avoir publié le code de mon jeu de Quarto, il est temps que je vous parle de mon résolveur de puzzles.&lt;/p&gt;
&lt;p&gt;Ce "puzzle solver" a aussi été écrit dans le cadre de mon cours de programmation d’IA et c’est donc mon deuxième projet. Je l’ai écrit pendant le mois d’octobre cette fois-ci. Le code est publié sous licence MIT et est disponible &lt;a href="https://github.com/marienfressinaud/IA_Puzzle-Solver"&gt;sur Github&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Le principe de ce projet est assez simple : le but est juste de proposer un algorithme permettant de résoudre des jeux (aussi appelés "problèmes") de façon modulaire. Ainsi, l’algo en lui-même doit être capable de résoudre un maximum de jeux avec un minimum d’adaptations.&lt;/p&gt;
&lt;p&gt;Deux jeux étaient imposés à la base : &lt;a href="https://fr.wikipedia.org/wiki/Probl%C3%A8me_des_huit_dames"&gt;le problème des huit dames&lt;/a&gt; et &lt;a href="https://fr.wikipedia.org/wiki/Coloration_de_graphe"&gt;le problème de coloration de graphe&lt;/a&gt;. Le troisième jeu était libre et j’ai choisi &lt;a href="https://fr.wikipedia.org/wiki/Carr%C3%A9_magique_%28math%C3%A9matiques%29"&gt;le carré magique&lt;/a&gt; qui me semblait bien adapté au sujet (après coup, ce n’était pas forcément le plus simple :p).&lt;/p&gt;
&lt;p&gt;Il y avait encore une autre contrainte, et c’est d’ailleurs là le cœur du projet. En fait il s’agissait d’implémenter non pas un seul algorithme, mais deux. Mais avant d'aller plus loin il me faut expliquer comment sont représentés les jeux. Comme je le disais plus haut, un jeu est aussi appelé "problème". Un problème peut donc être défini par :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Des variables.&lt;/strong&gt; Une variable est la donnée qu’on manipule et est définie par un domaine. Typiquement dans le problème des 8 dames, une variable représente une reine. On va donc avoir 8 dames, chacune positionnée sur une ligne différente des autres. Ainsi, le domaine de ces variables va être représenté par les indices des colonnes (une reine étant assignée à une ligne, elle ne peut se déplacer que de colonne en colonne)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Des contraintes.&lt;/strong&gt; C’est ce qui va déterminer les règles du jeu. Dans le jeu des 8 dames, le but est qu’aucune des dames ne puisse en "manger" une autre, ni en ligne, ni en colonne, ni en diagonale. Ainsi on va assigner à chacune des dames la contrainte qu’elle ne doit pas se trouver dans la ligne de mir d’une autre dame. Il s’agit simplement d’une petite fonction qui va vérifier l’emplacement des différentes reines.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Au début d’un jeu, on assigne à chaque variable une valeur aléatoire issue de son domaine. Aussi il y a de fortes chances que certaines variables "violent" des contraintes. Le jeu n'est donc pas dans son état optimal et il va falloir appliquer un algorithme pour faire en sorte de réduire le nombre de violations de contrainte.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Min-conflicts_algorithm"&gt;Min conflicts&lt;/a&gt; (minimisation de conflits [&lt;em&gt;il n’y a pas de page Wikipédia en français ! :o&lt;/em&gt;]) : ce premier algorithme est assez simple et aussi, la plupart du temps, plus efficace. Il va choisir une variable aléatoirement pourvu qu’elle viole au moins une contrainte. Elle va chercher dans le domaine la valeur qui minimise le nombre de violations et va l’assigner à la variable. Et on continue ainsi jusqu’à ce que plus aucune variable ne viole de contrainte.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Simulated_annealing"&gt;Simulated annealing&lt;/a&gt; (&lt;a href="https://fr.wikipedia.org/wiki/Recuit_simul%C3%A9"&gt;recuit simulé&lt;/a&gt;) : un peu plus compliqué que le premier algorithme, mais ingénieux ! Le principe est d’évaluer le jeu à chacune de ses étapes et de faire en sorte de faire évoluer le jeu de façon à maximiser cette évaluation. Pour faire évoluer le jeu on va simuler des états voisins (un changement de valeurs pour certaines variables). On va ensuite choisir soit d’assigner aléatoirement un de ces états pour la prochaine étape du jeu, soit d’assigner l’état qui possède la meilleure évaluation. Plus on va faire tourner l’algorithme, plus on va choisir l’état maximisant l’évaluation. Pour cela on a à notre disposition une "température" que l’on va réduire au fur et à mesure (d’où l’idée de recuit simulé). Plus la température est basse, plus on va se diriger vers l’état maximal.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;L’algorithme du recuit simulé est beaucoup trop compliqué pour arriver à en faire une bonne explication en quelques lignes, je vous invite donc à lire &lt;a href="https://fr.wikipedia.org/wiki/Recuit_simul%C3%A9"&gt;sa page Wikipédia&lt;/a&gt; si vous voulez plus d’information dessus :p&lt;/p&gt;
&lt;p&gt;Pour y voir plus clair dans l’architecture de mon programme, j’ai fait un diagramme de classes assez global. Il y a pas mal de classes reliées entre elles du coup ce n’était pas super simple de faire un beau diagramme. Sachez juste que la partie "implémentation" (qui représente la phase d’adaptation à un jeu en particulier) ne représente pour chacun des jeux que quelques lignes de code, consistant à assigner les domaines aux variables et à définir les contraintes.&lt;/p&gt;
&lt;p&gt;Je m’arrêterai là pour les explications. Sachez juste que je me suis bien éclaté sur ce projet. Au départ j’étais un peu affolé par l’algorithme du recuit simulé sur lequel on avait pas mal bloqué l’année dernière (les explications étaient assez confuses). Finalement je me suis rendu compte qu’il est plutôt simple à implémenter :) (reste le choix de certaines valeurs qui est assez compliqué et c’est là où je n’ai pas été très bon). Au final le projet m’a valu un 100/100, je suppose donc que mon boulot n’est pas mauvais :D&lt;/p&gt;
&lt;p&gt;Le dernier projet parlera de &lt;a href="https://fr.wikipedia.org/wiki/Optimisation_par_essaims_particulaires"&gt;particules et d’oiseaux&lt;/a&gt; et sera encore plus rigolo :)&lt;/p&gt;</content></entry><entry><title>Quarto et intelligence artificielle</title><id>urn:uuid:9efff09d-51dc-5610-a66f-62ce59f040d9</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/quarto-et-intelligence-artificielle.html" rel="alternate" type="text/html" /><published>2013-11-02T12:35:00+01:00</published><updated>2013-11-02T12:35:00+01:00</updated><content type="html">&lt;p&gt;Maintenant que j’ai à peu près fini de réparer mon serveur, je prends un peu de temps pour partager le code source d’un projet que j’ai réalisé pour mon cours de programmation d’Intelligence Artificielle (IA) en septembre : un jeu basique de Quarto.&lt;/p&gt;
&lt;p&gt;Pour présenter le Quarto, rien de mieux que de &lt;a href="https://fr.wikipedia.org/wiki/Quarto"&gt;citer Wikipédia&lt;/a&gt; :&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;L’objectif : aligner quatre pièces ayant au moins un point commun entre elles. Mais ne croyez pas que vous jouerez celles que vous voudrez : c’est l’adversaire qui choisit pour vous !&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Les seize pièces du jeu, toutes différentes, possèdent chacune quatre caractères distincts : haute ou basse, ronde ou carrée, claire ou foncée, pleine ou creuse. Chacun à son tour choisit et donne une pièce à l’adversaire, qui doit la jouer sur une case libre. Le gagnant est celui qui, avec une pièce reçue, crée un alignement de quatre pièces ayant au moins un caractère commun [...]&lt;/p&gt;
&lt;p&gt;Je ne sais pas pour vous, mais je trouve le principe très sympa :) Une sorte de puissance 4 mais avec quelques contraintes supplémentaires. Vous pouvez &lt;a href="http://quarto.freehostia.com/fr/"&gt;le tester directement en ligne&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Mon projet, quant à lui, se focalisait sur l’aspect IA et je me suis contenté du strict nécessaire niveau interface utilisateur. L’objectif était d’implémenter &lt;a href="https://fr.wikipedia.org/wiki/Algorithme_minimax"&gt;l’algorithme Minimax&lt;/a&gt; avec &lt;a href="https://fr.wikipedia.org/wiki/%C3%89lagage_alpha-beta"&gt;optimisation alpha-bêta&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Je crois que j’ai fait quelque chose de pas trop mal mais la fonction d’évaluation (qui est censée donner une "note" à un coup) est loin d’être parfaite et c’est là que j’ai perdu des points. Le code n’est pas non plus spécialement propre, mais il reste lisible (c’est du Python en même temps :p).&lt;/p&gt;
&lt;p&gt;Le code est disponible &lt;a href="https://github.com/marienfressinaud/AI_quarto"&gt;sur Github&lt;/a&gt; et est sous licence MIT. J’ai accompagné le code source d’un diagramme de classes très général pour montrer l’architecture globale du jeu.&lt;/p&gt;</content></entry><entry><title>FreshRSS 0.5, pour ceux qui en veulent toujours plus</title><id>urn:uuid:06127d27-be6c-5075-ae00-0a1d95d59550</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/freshrss-0-5-pour-ceux-qui-en-veulent-toujours-plus.html" rel="alternate" type="text/html" /><published>2013-10-12T11:17:00+02:00</published><updated>2013-10-12T11:17:00+02:00</updated><content type="html">&lt;p&gt;FreshRSS continue son petit bonhomme de chemin 3 mois après la sortie de la version 0.4. C’est donc avec plaisir que je vous annonce une nouvelle version plus stable que la précédente et quelques nouveautés qui devrait être appréciées (comme d’habitude, évidemment).&lt;/p&gt;
&lt;p&gt;&lt;img alt="Logo de FreshRSS" src="http://freshrss.org/images/freshrss_logo.png" /&gt;&lt;/p&gt;
&lt;h2&gt;Ce que vous devez savoir...&lt;/h2&gt;
&lt;p&gt;... car il est toujours bon de le rappeler avant de continuer. FreshRSS est un agrégateur de flux RSS à auto-héberger, écrit en PHP et utilisant une base de données MySQL (ou MariaDB). Sa plus grande limitation est, à l’heure actuelle, qu’il n’est pas possible de gérer plusieurs comptes. Cela vient bien évidemment contre-balancer les points positifs :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Une ergonomie pensée par et pour les utilisateurs&lt;/li&gt;
&lt;li&gt;Responsive design : FreshRSS s’adapte parfaitement à votre mobile&lt;/li&gt;
&lt;li&gt;Recherche par mots ou par #tags (et génération de flux RSS correspondants)&lt;/li&gt;
&lt;li&gt;Actualisation possible via CRON&lt;/li&gt;
&lt;li&gt;Possibilité de récupérer des flux RSS tronqués (à consommer avec modération !)&lt;/li&gt;
&lt;li&gt;Possibilité de changer de thème&lt;/li&gt;
&lt;li&gt;Marquage des articles comme lus au défilement de la page&lt;/li&gt;
&lt;li&gt;Et bien d’autres ! ☺&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Une fois encore, la démo a été mise à jour et est accessible &lt;a href="http://demo.freshrss.org"&gt;à la même adresse&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Les nouveautés&lt;/h2&gt;
&lt;p&gt;FreshRSS 0.5 c’est quelques 130 commits de plus que la 0.4, au moins &lt;a href="https://github.com/FreshRSS/FreshRSS/issues?milestone=4&amp;amp;state=closed"&gt;50 tickets de bugs fermés&lt;/a&gt; (je pense que j’en oublie) et 3 mois de développement... Non je déconne, je suis loin d’avoir bossé dessus non-stop. Ça n’en reste pas moins, à l’heure actuelle, la plus grosse version que j’ai eu à développer, bien que n’ayant pas été seul cette fois-ci.&lt;/p&gt;
&lt;h3&gt;Fonctionnalités&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Possibilité d’interdire la lecture anonyme&lt;/li&gt;
&lt;li&gt;Option pour garder l’historique d’un flux&lt;/li&gt;
&lt;li&gt;Lors d’un clic sur "Marquer tous les articles comme lus", FreshRSS peut désormais sauter à la prochaine catégorie / prochain flux avec des articles non lus. Cela évite bien des clics inutiles !&lt;/li&gt;
&lt;li&gt;Ajout d’un token pour accéder aux flux RSS générés par FreshRSS sans nécessiter de connexion. Cela permettra aussi d’accéder à l’API... prochainement ;)&lt;/li&gt;
&lt;li&gt;Possibilité de partager vers Facebook, Twitter et Google+&lt;/li&gt;
&lt;li&gt;Possibilité de changer de thème, le thème Flat design étant fourni en alternative au thème par défaut&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Design&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;La police OpenSans est désormais appliquée&lt;/li&gt;
&lt;li&gt;Amélioration de la page de configuration&lt;/li&gt;
&lt;li&gt;Une meilleure sortie pour l’imprimante&lt;/li&gt;
&lt;li&gt;Quelques retouches du design par défaut&lt;/li&gt;
&lt;li&gt;Un nouveau logo&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Base de données&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Possibilité d’ajouter un préfixe aux tables lors de l’installation&lt;/li&gt;
&lt;li&gt;Ajout d’un champ en base de données (voir la partie sur la mise à jour de la base de données)&lt;/li&gt;
&lt;li&gt;Si possible, création automatique de la base de données si elle n’existe pas lors de l’installation&lt;/li&gt;
&lt;li&gt;L’utilisation d’UTF-8 est forcée. Cela peut entraîner &lt;strong&gt;des problèmes d’encodage&lt;/strong&gt; lors de la mise à jour, j’en suis sincèrement désolé !&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Améliorations&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Le marquage automatique au défilement de la page a été amélioré&lt;/li&gt;
&lt;li&gt;La vue globale a été énormément améliorée et est beaucoup plus utile&lt;/li&gt;
&lt;li&gt;Amélioration des requêtes SQL&lt;/li&gt;
&lt;li&gt;Amélioration du Javascript&lt;/li&gt;
&lt;li&gt;Et des corrections de bugs en tout genre, comme d’habitude ☺&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Et ce qui manque&lt;/h3&gt;
&lt;p&gt;Malgré tout ça, je n’ai pas intégré tout ce que j’avais prévu au départ. On notera parmi les manques : la page de statistiques, la possibilité d’utiliser SQLite (bien que ça n’était pas dans mes plans initiaux, s’en est devenu une affaire personnelle !) et le nettoyage en profondeur du code Javascript.&lt;/p&gt;
&lt;p&gt;Ces manques s’expliquent par le fait qu’il y a eu énormément d’ajouts que je n’avais pas prévu et que j’avais besoin d’une nouvelle version pour stabiliser le tout avant de passer à la suite.&lt;/p&gt;
&lt;h2&gt;Mise à jour&lt;/h2&gt;
&lt;p&gt;Attention ! Cette nouvelle version inclut une mise à jour de la base de données et nécessite des actions de votre part.&lt;/p&gt;
&lt;h3&gt;Base de données&lt;/h3&gt;
&lt;p&gt;Dans la table &lt;strong&gt;&lt;code&gt;entry&lt;/code&gt;&lt;/strong&gt;, il faut &lt;strong&gt;supprimer&lt;/strong&gt; (si ils existent) les champs :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;is_public&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;lastUpdate&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;annotation&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Dans la table &lt;strong&gt;&lt;code&gt;feed&lt;/code&gt;&lt;/strong&gt;, il faut &lt;strong&gt;ajouter&lt;/strong&gt; le champ &lt;strong&gt;&lt;code&gt;keep_history INT(1)&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Pour la prochaine version j’essayerai d’automatiser les mises à jour de base de données ce qui nous simplifiera la vie à tous ☺&lt;/p&gt;
&lt;h3&gt;Application&lt;/h3&gt;
&lt;p&gt;une fois la BDD à jour, vous n’avez plus qu’à mettre à jour l’application comme d’habitude, à savoir :&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://github.com/FreshRSS/FreshRSS/archive/0.5.0.zip"&gt;Téléchargez la nouvelle version&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Écrasez les fichiers des répertoires "app", "lib" et "public". Faites attention à garder vos anciens &lt;code&gt;app/configuration/application.ini&lt;/code&gt; et &lt;code&gt;public/data/Configuration.array.php&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Supprimez le fichier &lt;code&gt;public/install.php&lt;/code&gt; car vous n’en avez pas besoin dans le cas d’une mise à jour&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Et n’hésitez pas à &lt;a href="https://github.com/FreshRSS/FreshRSS/issues"&gt;remonter le moindre soucis&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Quelques remerciements&lt;/h2&gt;
&lt;p&gt;Clairement, cette version a été boostée par les contributions externes et je tiens à remercier tout particulièrement :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Alexandre Alapetite (&lt;a href="https://github.com/Alkarex"&gt;Alkarex&lt;/a&gt;) qui a proposé pas moins de 25 pull requests. Il a notamment amélioré les requêtes SQL, le code Javascript, le saut automatique aux catégories non lues suivantes ainsi que... beaucoup d’autres choses ! D’un coté je trouve ça un peu fou que quelqu’un ait pu passer autant de temps à améliorer FreshRSS, de l’autre je trouve ça génial ! ☺&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Cypouz"&gt;Cypouz&lt;/a&gt; qui a proposé le nouveau logo beaucoup plus sympa que le précédent.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://influence-pc.fr/"&gt;Vincent&lt;/a&gt; qui a aussi un peu participé au logo, mais qui est surtout très encourageant et remonte régulièrement des soucis.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;J’aimerais d’ailleurs faire remarquer que c’est grâce aux différentes contributions que le projet évolue le plus. Sans cette aide externe et ces retours, sans doute que FreshRSS serait déjà abandonné car je ne verrais pas l’intérêt d’en faire plus. Si c’est le développeur qui insuffle la vie à un projet, c’est la communauté autour qui le fait vivre. Merci donc à tous pour votre aide !&lt;/p&gt;
&lt;h2&gt;À propos du logo&lt;/h2&gt;
&lt;p&gt;Tout logo se doit de représenter une idée, un concept. Extraits &lt;a href="https://github.com/FreshRSS/FreshRSS/issues/119"&gt;des discussions&lt;/a&gt; à propos du nouveau logo :&lt;/p&gt;
&lt;p&gt;&lt;img alt="Le logo FreshRSS sous différentes tailles" src="images/freshrss/logos.png" /&gt;&lt;/p&gt;
&lt;p&gt;Le nouveau logo de FreshRSS&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;J’ai finalement gardé le logo RSS (principe central du programme), entouré d’autres logo RSS (les autres sections des cercles, symbolisant la multitude de flux à suivre), le tout sous forme circulaire concentrique (symbolisant l’aspect rassembleur du programme, qui centralise les flux suivis). Le côté « fresh » est rappelé par la couleur bleu.&lt;/p&gt;
&lt;p&gt;L’avantage [de ce logo] [...] est aussi qu’il est ouvert. [...] Le fait qu’il soit ouvert peut sous-entendre beaucoup de choses : l’ouverture du code source, l’invitation à participer, une porte pour les flux RSS qui peuvent ainsi « entrer », etc.&lt;/p&gt;
&lt;p&gt;Le rond pourrait représenter le noyau qu’est FreshRSS et qui agrège les différents flux&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Vers la 0.6 et au-delà !&lt;/h2&gt;
&lt;p&gt;Comme à chaque publication de nouvelle version je rajoute une nouvelle étape avant la version 1.0, je ne ferai donc pas de pronostics cette fois-ci sur une version stable. Voici néanmoins mes plans pour la prochaine version qui sera donc la 0.6 :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ajout de la page de statistiques prévue pour la 0.5 (&lt;a href="https://github.com/FreshRSS/FreshRSS/issues/90"&gt;#90&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Ajout d’une API "compatible Google Reader" (&lt;a href="https://github.com/FreshRSS/FreshRSS/issues/13"&gt;#13&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Gestion de SQLite en plus de MySQL (+ PostgreSQL ?) (&lt;a href="https://github.com/FreshRSS/FreshRSS/issues/100"&gt;#100&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Refonte du code Javascript (&lt;a href="https://github.com/FreshRSS/FreshRSS/issues/121"&gt;#121&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Permettre l’import / export des articles favoris (&lt;a href="https://github.com/FreshRSS/FreshRSS/issues/163"&gt;#163&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Possibilité de partager un article vers Diaspora* et Poche (&lt;a href="https://github.com/FreshRSS/FreshRSS/issues/175"&gt;#175&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Script de mise à jour automatique de la base de données&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Du gros boulot en perspective donc, mais qui devrait me rapprocher toujours plus d’une version finale. Si vous avez des demandes, n’hésitez pas à m’en faire part &lt;a href="https://github.com/FreshRSS/FreshRSS/issues"&gt;sur Github&lt;/a&gt;. Pour le moment les seules demandes que j’ai refusées (ou reportées à une version ultérieure à la 1.0) sont la gestion multi-utilisateurs et une interface alternative de connexion : ça demanderait beaucoup trop de boulot en profondeur.&lt;/p&gt;
&lt;p&gt;J’ai aussi dans mes cartons l’idée de fournir un wiki sous forme de documentation utilisateur ou de FAQ pour présenter les différentes options de FreshRSS et expliquer comment l’utiliser au maximum de ses capacités. Le dernier délai pour m’en occuper est la date de sortie de la version 1.0... autant dire que j’ai le temps :D&lt;/p&gt;
&lt;h2&gt;En guise de conclusion&lt;/h2&gt;
&lt;p&gt;J’espère que FreshRSS saura vous satisfaire autant qu’il me satisfait moi-même. Je n’ai pour le moment eu aucun retour réellement négatif, j’ai quelques utilisateurs pleinement (?) satisfaits et je vois même fleurir sur Internet, de temps en temps, quelques articles parlant de mon agrégateur. Ce qui est, disons-le, très bon pour mon ego ☺&lt;/p&gt;
&lt;p&gt;Aussi, je vais bientôt fêter les un an du projet (le premier commit date du 21 octobre 2012) et c’est toujours encourageant de voir que de plus en plus de personnes trouvent de l’utilité dans mon travail. Travail qui était au départ totalement personnel et n’était pas parti pour durer dans le temps. Force est de constater que FreshRSS a mué peu à peu vers un projet un peu plus communautaire et ouvert et je suis pleinement satisfait de cette transformation.&lt;/p&gt;
&lt;h2&gt;Edit&lt;/h2&gt;
&lt;p&gt;Suite à un bug assez important dans la gestion des catégories (les catégories vides n’apparaissaient plus), je suis passé en version 0.5.1. J’en ai profité pour inclure quelques patchs de traduction et correction ;)&lt;/p&gt;</content></entry><entry><title>DesperadOS, le système qui fait bang!</title><id>urn:uuid:d09145ee-48c3-5e84-9b4d-8d6bcd16b49e</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/desperados-le-systeme-qui-fait-bang.html" rel="alternate" type="text/html" /><published>2013-10-05T11:16:00+02:00</published><updated>2013-10-05T11:16:00+02:00</updated><content type="html">&lt;p&gt;Aujourd'hui le monde de l'informatique se sépare entre Windows et Mac. Parfois il arrive qu'un barbu sorte de sa salle de serveurs pour râler "&lt;em&gt;Gnu/Linux, pas Linux&lt;/em&gt;", mais ça reste anecdotique. Si je prends le clavier ce jour, c'est pour vous parler d'un nouveau système d'exploitation qui va très certainement révolutionner votre vie.&lt;/p&gt;
&lt;h2&gt;Fonctionnalités&lt;/h2&gt;
&lt;p&gt;Un système innovant se doit de proposer des technologies à la pointe. DesperadOS ne se contente pas d'être innovant, il est révolutionnaire !&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Système multi-processus avec ordonnancement de type &lt;a href="https://fr.wikipedia.org/wiki/Round-robin_%28informatique%29"&gt;Round-Robin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Gestion bas-niveau des sémaphores&lt;/li&gt;
&lt;li&gt;Gestion du clavier, de l'écran ET du temps&lt;/li&gt;
&lt;li&gt;Écran de veille en mode VGA&lt;/li&gt;
&lt;li&gt;Système de fichiers avec arborescence en mémoire&lt;/li&gt;
&lt;li&gt;Shell incluant pas moins de &lt;strong&gt;21 commandes&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;L'authentification par empreinte biométrique est en cours d'intégration, la révolution est en marche.&lt;/p&gt;
&lt;h2&gt;La vidéo qui va bien&lt;/h2&gt;
&lt;p&gt;Vous pouvez bien entendu douter de ma parole et remettre en cause le bien-fondé de mon enthousiasme. C'est sans compter que je ne suis pas venu les mains dans les poches. Cette vidéo saura très certainement vous faire changer d'avis.&lt;/p&gt;
&lt;iframe src="http://www.youtube.com/embed/R-NDlywRZQY" allowfullscreen="" width="640" frameborder="0" height="360"&gt;&lt;/iframe&gt;

&lt;h2&gt;Genèse du projet&lt;/h2&gt;
&lt;p&gt;En juin dernier, alors que le soleil et la pluie se faisaient la cour, un certain nombre d'individus savourait les joies de ne pas pouvoir profiter de leur temps libre. Une mission les réunissait : développer le système d'exploitation qui allait maximiser leur note de projet.&lt;/p&gt;
&lt;p&gt;Si je vous en parle, c'est parce que j'ai moi-même participé à ce grand beau projet. J'étais là quand les profs ont présenté le sujet. J'étais là aux premières lignes de code. J'étais encore là lors du premier bug. J'étais aussi là les midis, au moment de faire le grand choix "pâtes ou sandwichs". Oui, je peux affirmer que j'étais là car j'ai moi-même subi la première semaine sans clim' en haut de ce bâtiment exposé au soleil en plein milieu de l'après-midi.&lt;/p&gt;
&lt;p&gt;Bien entendu, je n'étais pas seul : &lt;a href="http://unpetitfrancaisaprague.com/"&gt;Paul&lt;/a&gt; et &lt;a href="http://fr.linkedin.com/in/mikolajpawlikowski"&gt;Micko&lt;/a&gt; complétaient notre groupe.&lt;/p&gt;
&lt;h2&gt;Le concept&lt;/h2&gt;
&lt;p&gt;Pour ceux qui ne l'ont pas encore compris, bien entendu DesperadOS n'est en rien révolutionnaire. Encore que sa façon de planter durant la démo... mais Microsoft nous a devancé. Deux fois.&lt;/p&gt;
&lt;p&gt;Durant deux semaines et demi en juin dernier, par groupe de trois, nous avons donc eu à développer un système d'exploitation. À savoir que nous partions d'une base de code fournie mais qui ne faisait basiquement... rien (ce qui n'est qu'à moitié faux). À partir de ce rien du tout, il nous a donc fallu gérer l'affichage à l'écran, le temps, l'ordonnancement des processus, le clavier et j'en passe. Autant dire que c'était bien fun ☺&lt;/p&gt;
&lt;h2&gt;La gestion du projet&lt;/h2&gt;
&lt;p&gt;Nous étions seulement trois pour ce projet donc la gestion fut assez simple. Nous avons utilisé &lt;a href="https://trello.com/"&gt;Trello&lt;/a&gt; pour tout ce qui fut gestion des tâches et je dois avouer que c'était plutôt efficace. Selon moi, ça reste néanmoins un outil à utiliser en groupe et je n'ai jamais réussi à l'utiliser (trouvé l'utilité ?) dans un projet perso.&lt;/p&gt;
&lt;p&gt;Git fut bien entendu aussi de la partie pour la gestion du code et comme nous avions tous un minimum d'expérience avec, ça n'a pas posé de soucis particulier (j'aime Git &amp;lt;3)&lt;/p&gt;
&lt;h2&gt;Rapide retour d'expérience&lt;/h2&gt;
&lt;p&gt;Les deux semaines et demi passées sur ce projet ont vraiment été géniales. Nous avons &lt;em&gt;enfin&lt;/em&gt; pu comprendre comment fonctionne un système d'exploitation au plus bas niveau (les joies de l'assembleur :D), la gestion des processus et des ressources. C'est vraiment un projet à ne pas rater et où l'on peut prendre son pied si on s'applique.&lt;/p&gt;
&lt;p&gt;Bien sûr il y a eu quelques (nombreuses) difficultés qui nous ont fait désespérer de finir le projet... mais les surmonter ne fut que plus enthousiasmant. Notons tout de même que notre code ne fut pas parfait et nous sommes passés à côté d'un ou deux éléments importants. Mais je pense que le plus important reste d'avoir compris dans les grandes lignes le fonctionnement d'un système d'exploitation.&lt;/p&gt;
&lt;p&gt;Depuis j'ai rapidement essayé de me plonger dans le code de Linux. Force est de constater que le code est... dense. J'ai abandonné. Il y a eu quelques articles d'introduction sur &lt;a href="http://linuxfr.org/"&gt;LinuxFR&lt;/a&gt; à l'époque, mais impossible de les retrouver.&lt;/p&gt;
&lt;p&gt;Sans doute plus intéressant et plus facile d'accès, &lt;a href="http://www.manux.info/fr/"&gt;Manux&lt;/a&gt; (non, il ne s'agit pas d'un mauvais &lt;a href="http://doug.letough.free.fr/images/manux.jpg"&gt;jeu de mot&lt;/a&gt;). Système d'exploitation purement français (les fichiers, le code, les commentaires : tout est en Français) et issu... du projet système de l'Ensimag, il y a déjà quelques années de ça ! Le développeur avait fait &lt;a href="http://linuxfr.org/users/ecolbus/journaux/annonce-manux-0-0-1"&gt;une annonce lors de la sortie de la version 0.0.1&lt;/a&gt; sur LinuxFR.&lt;/p&gt;
&lt;h2&gt;Et la suite&lt;/h2&gt;
&lt;p&gt;J'aurais voulu pouvoir partager le code qui devrait d'ailleurs être en grande partie (voire totalement) sous licence libre, néanmoins je n'ai pas le droit de fournir les solutions aux futurs étudiants. Et dans le cas où ils passeraient par ici, je ne peux évidemment pas vous mettre le code à disposition. Dans le cas où il m'arriverait &lt;strong&gt;par hasard&lt;/strong&gt; de vouloir reprendre en totalité le projet pour obtenir quelque chose de plus abouti (hum...) et différent du projet de base, je me ferai une joie de partager le code... Mais je ne me fais pas trop d'illusions ;)&lt;/p&gt;
&lt;p&gt;Si vous voulez plus d'infos sur ce projet, &lt;a href="https://ensiwiki.ensimag.fr/index.php/Projet_syst%C3%A8me_PC_:_2013_-_Mikolaj_PAWLIKOWSKI,_Marien_FRESSINAUD_et_Paul_AMAR"&gt;notre page de (ensi)wiki&lt;/a&gt; décrit un peu mieux l'OS. Vous pouvez aussi voir &lt;a href="https://ensiwiki.ensimag.fr/index.php/Projet_syst%C3%A8me_:_r%C3%A9sultats"&gt;le travail des autres groupes&lt;/a&gt; (il y en a des vraiment &lt;a href="https://ensiwiki.ensimag.fr/index.php/Projet_syst%C3%A8me_PC_:_2010_-_Damien_Dejean_et_Gaetan_Morin"&gt;impressionants&lt;/a&gt;, mais ils avaient plus de temps :p). Et enfin, la page qui présente &lt;a href="https://ensiwiki.ensimag.fr/index.php/Projet_syst%C3%A8me"&gt;le sujet du projet&lt;/a&gt;. C'était en tout cas le projet le plus intéressant que l'on ne m'ait jamais proposé et ce serait avec joie de continuer encore un peu. Je me demande juste pourquoi j'ai mis autant de temps à écrire cet article.&lt;/p&gt;</content></entry><entry><title>Une v6 qui carbure</title><id>urn:uuid:c557e64a-70f5-5a9b-b833-00ca606970da</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/une-v6-qui-carbure.html" rel="alternate" type="text/html" /><published>2013-08-29T14:22:00+02:00</published><updated>2013-08-29T14:22:00+02:00</updated><content type="html">&lt;p&gt;6 mois. 6 mois seulement que j'avais fait évoluer mon site vers sa cinquième version. Faut dire que j'étais parti dans un petit délire qui rendait le tout pas très pratique à manipuler. Mais c'est de l'histoire ancienne ! Aujourd'hui j'officialise cette v6 de mon cher petit site.&lt;/p&gt;
&lt;p&gt;Qu'est ce qui se cache donc sous le capot cette fois-ci ?&lt;/p&gt;
&lt;h2&gt;Un blog PluXML&lt;/h2&gt;
&lt;p&gt;Ça y est, j'ai enfin décidé qu'il était temps d'arrêter de vouloir tout redévelopper alors qu'il existe des CMS et des logiciels qui font les choses très bien et même mieux. Depuis le début de ce site je me suis refusé à utiliser un moteur de blog tel que &lt;a href="http://www.pluxml.org/"&gt;PluXML&lt;/a&gt;, Dotclear ou Wordpress parce que je voulais faire les choses moi-même. Force est de constater qu'il est beaucoup plus simple d'utiliser le produit d'un autre quand il est maintenu correctement.&lt;/p&gt;
&lt;p&gt;PluXML a tout pour lui : léger, sans base de données, facile à adapter à ses besoins, système de plugins, (vraiment) bien codé. Je peux enfin respirer après des années à utiliser une interface d'administration pour mon site pas terrible.&lt;/p&gt;
&lt;p&gt;J'ai quand même pu récupérer l'ensemble de mes anciens articles pour les gérer via PluXML. Bien sûr, les URL pour y accéder ont changé et certains liens dans les articles ne fonctionneront plus. Et vu que cette fois j'ai la flemme de tout vérifier, ça restera ainsi (sauf si la motivation revient).&lt;/p&gt;
&lt;h2&gt;Un Shaarli&lt;/h2&gt;
&lt;p&gt;&lt;a href="marienfressinaud.fr/shaarli/"&gt;C'est un grand retour.&lt;/a&gt; Alors que je l'avais abandonné durant la v5 pour un outil fait maison, j'ai assez vite déchanté. Les bugs et l'interface (là encore assez peu glamour) m'ont forcé à repasser à &lt;a href="http://sebsauvage.net/wiki/doku.php?id=php:shaarli"&gt;Shaarli&lt;/a&gt;. Mêmes explications que plus haut, ne pas avoir à se charger de la maintenance d'un produit est une épine enlevée du pied.&lt;/p&gt;
&lt;p&gt;Je vais donc pouvoir recommencer à partager mes liens comme avant ! :)&lt;/p&gt;
&lt;p&gt;Les plus attentifs remarqueront que j'ai abandonné le flux unifié de mes articles de blog / liens partagés. À vrai dire, le fait que mes liens arrivent en première page, de la même manière qu'un article, me gênait. En effet, un lien partagé est censé être moins important qu'un article et devrait rester en seconde page.&lt;/p&gt;
&lt;h2&gt;Un design fait avec amour&lt;/h2&gt;
&lt;p&gt;Je parlais de design glamour, et ceux qui connaissent l'interface standard d'un Shaarli me diront que s'en est tout l'inverse. Le design par défaut de PluXML n'est pas non plus des plus enthousiasmant. Et le design précédent de ce site était sans commune mesure plus laid que les autres (alors qu'étrangement j'avais réussi à faire quelque chose de pas mal avec la v4).&lt;/p&gt;
&lt;p&gt;Heureux que vous devez être alors d'apprendre que je vous propose au téléchargement le design tout beau (enfin j'espère) que j'ai développé pour ce site. Une partie pour PluXML et une autre pour Shaarli. Attention tout de même pour le Shaarli, j'ai fait des modifications dans le &lt;code&gt;index.php&lt;/code&gt; et j'ai remanié entièrement les fichiers TPL (la création d'un thème à part entière pour Shaarli n'est pas encore au point).&lt;/p&gt;
&lt;p&gt;Pour les couleurs, le fantastique site &lt;a href="http://flatuicolors.com/"&gt;Flat UI Colors&lt;/a&gt; m'a énormément aidé. Je me suis aussi inspiré de ce que j'ai fait pour FreshRSS pour compléter. Bref, j'espère que ça vous plaira !&lt;/p&gt;
&lt;h2&gt;Un nouveau départ&lt;/h2&gt;
&lt;p&gt;Je n'écrit jamais beaucoup sur ce site / blog (à peu près un article par mois depuis le début de l'année !). J'espère que cette nouvelle version avec un vrai moteur de blog va me motiver un peu plus. De toute façon, ce site reste mon site et ma vitrine, aucune chance que je l'abandonne lâchement ! :D&lt;/p&gt;
&lt;p&gt;Si toutefois vous souhaitez (me) lire, j'essaye d'être plus régulier (et plus compréhensible) sur &lt;a href="http://marienfressinaud.fr/norge/"&gt;mon blog dédié à mon voyage en Norvège&lt;/a&gt;.&lt;/p&gt;</content></entry><entry><title>FreshRSS 0.4, une release qu’elle est bien</title><id>urn:uuid:df695fb3-a471-5e8b-809c-d423a5fb276f</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/freshrss-0-4-une-release-qu-elle-est-bien.html" rel="alternate" type="text/html" /><published>2013-07-04T20:38:00+02:00</published><updated>2013-07-04T20:38:00+02:00</updated><content type="html">&lt;p&gt;Cher toutes et tous,&lt;/p&gt;
&lt;p&gt;séchez vos larmes, l’an 0 après Google Reader vient de commencer. Séchez vos larmes car vient vers vous une foultitude de nouveaux agrégateurs qui ont essayé de rivaliser ces derniers mois en terme de choix, de fonctionnalités et d’ergonomie. Séchez vos larmes vous dis-je car &lt;a href="http://freshrss.org"&gt;FreshRSS vient de sortir en version 0.4&lt;/a&gt; et vous apporte plein de bien belles nouveautés.&lt;/p&gt;
&lt;h2&gt;Les infos utiles&lt;/h2&gt;
&lt;p&gt;FreshRSS est un agrégateur de flux RSS à auto-héberger sur son propre serveur. Il est relativement rapide et puissant. Il se différencie des autres agrégateurs par quelques fonctionnalités bien utiles et une ergonomie pensée pour un usage quotidien. À titre d’exemple, quelques points forts de mon application :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Une version mobile (que j’adore !)&lt;/li&gt;
&lt;li&gt;Chaque recherche (par mot-clé ou par tag) possède son propre flux RSS. Vous pouvez donc vous abonner à un flux RSS généré par FreshRSS avec tous les articles contenant le mot "Linux".&lt;/li&gt;
&lt;li&gt;Actualisation possible par CRON&lt;/li&gt;
&lt;li&gt;Internationalisation : anglais et français supportés&lt;/li&gt;
&lt;li&gt;Marquage des articles comme lu au défilement de la page (optionnel)&lt;/li&gt;
&lt;li&gt;Différents modes d’affichage (normal, lecture et global)&lt;/li&gt;
&lt;li&gt;Chargement des images en mode lazyload (chargement uniquement lorsque l’image doit apparaître à l’écran)&lt;/li&gt;
&lt;li&gt;Possibilité de récupérer des flux RSS tronqués&lt;/li&gt;
&lt;li&gt;Et bien d’autres !&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Qui dit nouvelle version, dit mise à jour de la démo, &lt;a href="http://demo.freshrss.org"&gt;toujours accessible à la même adresse&lt;/a&gt; pour les plus pressés.&lt;/p&gt;
&lt;h2&gt;Les grandes nouveautés&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Ajout de deux modes de vue&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Jusque là, il n’existait qu’un mode de lecture "par défaut" permettant de parcourir, lire, mettre en favoris, etc. les articles. Désormais il y aura aussi la "vue lecture" qui se veut plus agréable quand vous ne souhaitez que lire (pas marquer comme lu ni rien. Juste lire). La troisième vue est la "vue globale" vous permettant de voir d’un coup d’œil les flux possédant des articles non lus. Cette dernière est largement perfectible mais a le mérite d’exister.&lt;/p&gt;
&lt;p&gt;Personnellement je continue d’utiliser la vue normale par défaut car plus pratique &lt;strong&gt;pour moi&lt;/strong&gt;, mais sur mobile, la vue lecture est plus agréable par exemple.
Le but est de vous proposer différentes approches de FreshRSS pour ne pas vous enfermer dans un mode de fonctionnement unique. Je suis ouvert à toutes suggestions d’amélioration de ces vues, notamment la vue globale que je trouve finalement assez inutile en l’état, bien que j’ai déjà des idées pour l’améliorer.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Possibilité d’optimiser la base de données&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;L’optimisation de la base de données est une chose d’assez peu connue, et je pense très rarement utilisée dans les applications web "basiques". Ceci dit, à l’aide d’un simple bouton vous pourrez désormais réduire la taille utilisée par votre base de données : je suis passé d’une base de 28Mo à une base de 20Mo. En revanche, j’ignore si toutes les bases de données supportent bien cette commande SQL et je suis intéressé par d’éventuels retours !&lt;/p&gt;
&lt;p&gt;Pour information, la requête SQL qui se cache derrière tout ça est (&lt;a href="https://dev.mysql.com/doc/refman/5.5/en/optimize-table.html"&gt;voir la doc MySQL&lt;/a&gt;) :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;OPTIMIZE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nom_de_la_table&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Mode endless&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Le mode endless fait son grand retour. Ce mode permet de charger les articles suivants le dernier de la liste en les rajoutant à la suite, sans avoir à recharger la page complètement.&lt;/p&gt;
&lt;p&gt;Ça marche beaucoup mieux qu’avant (il y avait des soucis quand on marquait les articles comme (non) lu) mais il se peut qu’il reste quelques soucis car je ne l’utilise pas trop de mon côté.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Chargement des images en mode lazyload&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Cette fonctionnalité j’en suis particulièrement content parce que j’étais très dubitatif sur son intérêt avant de l’intégrer... puis finalement je ne peux plus m’en passer !&lt;/p&gt;
&lt;p&gt;Le principe est de ne charger les images des articles qu’à partir du moment où elles sont censées apparaître à l’écran. Le gain de temps au chargement de la page est énorme. Le seul soucis est que l’on se retrouve de temps en temps avec un rectangle gris, le temps de charger l’image. Pour cela, il est possible de désactiver la fonction de lazyload, mais je vous conseille quand même de la garder ;)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Possibilité de marquer les articles comme lu au défilement&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Là encore une fonctionnalité très intéressante. Grâce à celle-ci, il est possible de marquer un article comme lu lorsque vous en avez lu à peu près les 3/4. Cette fonctionnalité marche très bien lorsqu’on lit avec les articles "dépliés" par défaut, mais peut se coupler aussi avec les articles pliés. Il ne tient qu’à vous de définir les réglages qui vous conviennent le mieux !&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Et bien d’autres !&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Des corrections de bugs, des améliorations au niveau du design et de l’ergonomie, des petits ajouts par-ci par-là. Je vous laisse découvrir cette nouvelle version qui devrait plaire à pas mal d’entre vous ☺&lt;/p&gt;
&lt;h2&gt;Mettre à jour votre FreshRSS&lt;/h2&gt;
&lt;p&gt;Comme pour le passage de la v0.2 à la v0.3, la mise à jour devrait être assez facile puisqu’il n’y a pas de modification de la base de données.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://github.com/FreshRSS/FreshRSS/archive/0.4.0.zip"&gt;Téléchargez la nouvelle version&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Écrasez les fichiers des répertoires &lt;code&gt;app&lt;/code&gt;, &lt;code&gt;lib&lt;/code&gt; et &lt;code&gt;public&lt;/code&gt;. Faites attention de garder vos anciens &lt;code&gt;app/configuration/application.ini&lt;/code&gt;, &lt;code&gt;public/data/Configuration.array.php&lt;/code&gt; et tout fichier que vous avez pu modifier de votre côté.&lt;/li&gt;
&lt;li&gt;Enfin, supprimez le fichier &lt;code&gt;public/install.php&lt;/code&gt; car vous n’en avez pas besoin dans le cas de la mise à jour (sauf si vous tenez à refaire l’installation :p)&lt;/li&gt;
&lt;li&gt;Un soucis ? &lt;a href="https://github.com/FreshRSS/FreshRSS/issues"&gt;Nos équipes se chargent de vous répondre au plus vite.&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Fonctionnalités futures (v0.5 ou v1.0 ?)&lt;/h2&gt;
&lt;p&gt;Autant vous le dire, je pense que FreshRSS n’a plus besoin de beaucoup d’ajouts. Aussi, si je n’ai pas trop de demandes pour la prochaine version, il se peut qu’il s’agisse de la version 1.0 (enfin !)&lt;/p&gt;
&lt;p&gt;Et donc, au menu ce que je vous prépare (pas grand chose au final) :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Un sélecteur de thèmes (&lt;a href="https://github.com/FreshRSS/FreshRSS/issues/86"&gt;bug 86&lt;/a&gt;). J’essayerai de proposer au moins 3 thèmes différents pour varier les goûts.&lt;/li&gt;
&lt;li&gt;Une page de statistiques (&lt;a href="https://github.com/FreshRSS/FreshRSS/issues/90"&gt;bug 90&lt;/a&gt;). Au delà du côté bling-bling de la fonctionnalité, je pense que ça peut être utile (/ intéressant) de voir quels sont les sites qui publient le plus, quels jours, etc. J’essayerai de ne pas surcharger en graphiques tout de même ;)&lt;/li&gt;
&lt;li&gt;Correction de bugs... comme d’habitude !&lt;/li&gt;
&lt;li&gt;Amélioration des nouvelles vues&lt;/li&gt;
&lt;li&gt;Et je pense que ce sera tout.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Par la suite (si je m’arrête là) j’assurerai évidemment la maintenance pour corriger les bugs, mais je ne pense pas ajouter de nouvelles fonctionnalités... si vous êtes intéressés par des nouveautés, faites m’en part au plus vite !&lt;/p&gt;
&lt;h2&gt;N’oublions pas les autres&lt;/h2&gt;
&lt;p&gt;Car si FreshRSS ne vous convient pas, il existe bien d’autres agrégateurs. Donnez au moins une chance à &lt;a href="https://github.com/tontof/kriss_feed"&gt;Kriss Feed&lt;/a&gt; ou &lt;a href="http://projet.idleman.fr/leed/"&gt;Leed&lt;/a&gt; qui évoluent aussi pas mal de leur côté avec des développeurs à l’écoute des remarques qu’on peut leur faire (c’est important !). Je suis fan du côté facilité d’installation de Kriss Feed et du système de plugins de Leed (ce ne sera pas suffisant pour me faire abandonner FreshRSS ceci dit :p)&lt;/p&gt;
&lt;h2&gt;Remerciements&lt;/h2&gt;
&lt;p&gt;J’aimerais remercier toutes les personnes qui m’ont fait des retours ou des suggestions, notamment &lt;a href="https://github.com/4nti-7rust"&gt;4nti-7rust&lt;/a&gt; pour l’idée du marquage au défilement de la page, &lt;a href="https://github.com/rplanelles"&gt;rplanelles&lt;/a&gt; pour l’idée du chargement des images en mode lazyload et &lt;a href="http://influence-pc.fr/"&gt;Vincent&lt;/a&gt; pour parler de FreshRSS un peu partout !&lt;/p&gt;
&lt;p&gt;Je n’oublie pas les autres qui m’ont demandé de l’aide par mail, notamment la courageuse personne qui a essayé d’installer FreshRSS sur un espace Free (pour information, il n’y a pas PDO sur les serveurs de Free apparemment, on ne peut donc pas y installer FreshRSS -_-)&lt;/p&gt;
&lt;p&gt;J’en profite pour conclure que c’est vraiment agréable d’avoir tous ces retours car ça motive le développement et me permet de savoir pour "qui" je travaille (c’est encore plus gratifiant que &lt;a href="https://github.com/FreshRSS/FreshRSS"&gt;les 15 étoiles sur Github&lt;/a&gt; :p)&lt;/p&gt;
&lt;h2&gt;Le mot de la fin&lt;/h2&gt;
&lt;p&gt;Agrégateur. (et non pas a&lt;strong&gt;gg&lt;/strong&gt;régateur comme je peux le voir régulièrement !)&lt;/p&gt;</content></entry><entry><title>RunPG et géolocalisation font bon ménage</title><id>urn:uuid:0ad5e88e-58d1-516a-a304-d443ae3ec5c6</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/runpg-et-geolocalisation-font-bon-menage.html" rel="alternate" type="text/html" /><published>2013-06-19T19:20:00+02:00</published><updated>2013-06-19T19:20:00+02:00</updated><content type="html">&lt;p&gt;Voilà bien longtemps que je n’avais rien écrit et aujourd’hui je m’en viens vous parler donc d’un petit projet : &lt;a href="https://github.com/marienfressinaud/RunPG"&gt;RunPG&lt;/a&gt;. Il s’agit d’un projet web que j’ai réalisé pour l’Ensimag, mais avant tout c’est surtout un petit PoC de jeu (Proof of Concept, un petit jeu permettant de mettre en application une idée) auquel je pensais depuis quelques temps. L’idée donc était à la base de "faire courir les geeks" (ou pas). Le concept est simple : vous allez courir avec votre smartphone, une application (web ici) enregistre votre parcours grâce à la géolocalisation et fait progresser votre personnage en fonction de votre vitesse / durée de course / distance parcourue. Pour compléter la présentation, je vais laisser la parole à mon README :&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Description&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;RunPG est un jeu type RPG utilisant la géolocalisation pour faire évoluer votre personnage. Les quêtes consistent à parcourir un certain nombre de kilomètres en un minimum de temps. L’enregistrement se fait grâce à la version web de RunPG et utilise les possibilités de géolocalisation du téléphone et du HTML5.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Les contraintes&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Il s’agit d’un projet web pour l’Ensimag, un certain nombre de contraintes m’ont été imposées :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Utilisation du &lt;a href="http://www.playframework.com/"&gt;framework Java, Play&lt;/a&gt; (obligatoire) : OK&lt;/li&gt;
&lt;li&gt;Gestion de droits avec différents niveaux d’utilisateurs (obligatoire) : OK (visiteur, joueur, admin)&lt;/li&gt;
&lt;li&gt;Gestion d’un flux RSS (optionnel) : OK (classement et joueur)&lt;/li&gt;
&lt;li&gt;Utilisation d’un webservice (souhaitable) : OK (maps et données de OpenStreetMaps)&lt;/li&gt;
&lt;li&gt;Une partie du site en GWT (souhaitable) : NOK (choix assumé)&lt;/li&gt;
&lt;li&gt;Version mobile de l’application (optionnel) : OK (tout le site est full responsive design)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Voilà donc ce qu’il y a dire sur le projet. Il me faut quand même préciser quelques petites choses :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Comme je le disais plus haut il s’agit d’un PoC, je n’ai donc pas poussé les fonctionnalités jusqu’au bout. L’administration par exemple est vraiment très basique, ne permettant que de supprimer des joueurs ou de modifier leur score / expérience. Néanmoins, la base est là. Il s’agissait en effet de vraiment se concentrer sur l’aspect géolocalisation vers évolution du personnage.&lt;/li&gt;
&lt;li&gt;On ne peut pas courir plus de 30 minutes sinon la requête qui synchronise votre parcours avec le serveur est trop grosse (trop de points GPS) et ne passe pas (oups :$)&lt;/li&gt;
&lt;li&gt;Il n’y a (pour le moment) aucun serveur hébergeant ce mini-jeu&lt;/li&gt;
&lt;li&gt;Mais &lt;a href="https://github.com/marienfressinaud/RunPG"&gt;le code de RunPG est disponible sur Github&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;J’ai placé le tout sous licence &lt;a href="http://copyheart.org"&gt;Copyheart&lt;/a&gt; mais tout ce qui est images et code incorporé garde sa licence d’origine&lt;/li&gt;
&lt;li&gt;Le tout est basé sur le framework Java, Play (version 2.1.1), basé sur les concepts MVC. Il vous faudra donc installer le framework sur votre PC. Je pense qu’en s’y connaissant un peu, on prend rapidement ses marques pour comprendre le code. Si jamais je dois reprendre le concept un jour néanmoins, ce sera en Python (j’ai envie de me mettre à ce langage pour de bon ☺)&lt;/li&gt;
&lt;li&gt;Si vous êtes intéressés pour reprendre le code / l’idée du jeu, n’hésitez pas à me poser des questions (notamment pour la phase de débogage qui peut être assez pénible)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Et pour finir, quelques images de la bête :&lt;/p&gt;
&lt;p&gt;&lt;img alt="L’accueil" src="images/runpg/accueil.png" /&gt;&lt;/p&gt;
&lt;p&gt;L’accueil&lt;/p&gt;
&lt;p&gt;&lt;img alt="La page de classement" src="images/runpg/classement.png" /&gt;&lt;/p&gt;
&lt;p&gt;La page de classement (oui il n’y a que quatre joueurs)&lt;/p&gt;
&lt;p&gt;&lt;img alt="La vue mobile lorsqu’on enregistre un parcours" src="images/runpg/mobile.png" /&gt;&lt;/p&gt;
&lt;p&gt;La vue mobile lorsqu’on enregistre un parcours (j’utilise ici le simulateur de Firefox OS, très utile lors du débogage)&lt;/p&gt;
&lt;p&gt;&lt;img alt="La page d’administration" src="images/runpg/admin.png" /&gt;&lt;/p&gt;
&lt;p&gt;La page d’administration (très basique)&lt;/p&gt;
&lt;p&gt;Amusez-vous bien ! ☺&lt;/p&gt;</content></entry><entry><title>Welcome to FreshRSS 0.3!</title><id>urn:uuid:66a0b07b-3dab-5181-b6e7-53cc903c33e2</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/welcome-to-freshrss-0-3.html" rel="alternate" type="text/html" /><published>2013-05-05T13:03:00+02:00</published><updated>2013-05-05T13:03:00+02:00</updated><content type="html">&lt;p&gt;Non je n’écrirai pas cet article en anglais comme peux le laisser penser ce titre, mais il s’agit d’introduire la plus grosse nouveauté de cette nouvelle version toute fraîche de mon agrégateur de flux RSS : l’internationalisation de l’application ! L’anglais et le français sont donc désormais pris en charge intégralement ; FreshRSS va pouvoir partir à la conquête du nouveau continent. N’étant pas forcément bon en orthographe en anglais, n’hésitez pas à me remonter les erreurs de traduction ☺&lt;/p&gt;
&lt;h2&gt;Nouveautés&lt;/h2&gt;
&lt;p&gt;Mais s’il s’agit de la plus grosse nouveauté, il ne faut pas oublier toutes les autres qui ne sont pas non plus en reste. Au programme de cette nouvelle version donc :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Une page dédiée qui sert de site officiel&lt;/li&gt;
&lt;li&gt;Internationalisation&lt;/li&gt;
&lt;li&gt;Création d’un logo &lt;strong&gt;temporaire&lt;/strong&gt;. Je trouve celui que j’ai fait à l’arrache de plus en plus laid mais le problème est que je n’ai aucun talent de graphiste ☹ Je prendrai le temps d’en faire un mieux pour la version 1.0 ou je ferai appel à quelqu’un peut-être...&lt;/li&gt;
&lt;li&gt;Meilleure gestion CSS3 pour les navigateurs ne supportant pas les dégradés ou les transitions de façon "officielle" (utilisation des préfixes propriétaires bien que j’en ai horreur)&lt;/li&gt;
&lt;li&gt;Possibilité de s’abonner à des flux derrière une authentification HTTP (c’était déjà le cas, mais pas réellement de façon officielle, et les identifiants apparaissaient totalement en clair)&lt;/li&gt;
&lt;li&gt;Mise en cache des favicons (le site &lt;a href="http://g.etfv.co/"&gt;getFavicon&lt;/a&gt; va être soulagé)&lt;/li&gt;
&lt;li&gt;Affichage des vidéos incluses dans les articles (SimplePie les enlevait par défaut)&lt;/li&gt;
&lt;li&gt;Une bien meilleure gestion de la recherche et du filtrage par tags ! Ça m’a demandé beaucoup de temps et une bonne prise de tête pour en arriver là mais j’en suis assez content. Problème : il se peut que les performances soient fortement dégradées. Si vous vous rendez compte que votre serveur ne tient pas la charge, faites-le moi savoir, j’essayerai de voir ce que je peux faire. Ceci dit, sur mon instance qui stocke pour le moment 1600 articles ça passe très bien. Petit plus : vous pouvez accéder au flux RSS d’une recherche ou d’un filtre. Une fois votre recherche lancée, il suffit de rajouter le paramètre "&amp;amp;output=rss" dans l’url ou de cliquer simplement sur le bouton à côté de "Gestion des abonnements"&lt;/li&gt;
&lt;li&gt;J’ai créé un "vrai" script CRON de façon à pouvoir mettre tous les flux à jour d’un coup sans que le serveur vous rejette avec un timeout.&lt;/li&gt;
&lt;li&gt;Et bien sûr, divers corrections de bugs avec une revue du code pour qu’il soit plus clair&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Mise à jour&lt;/h2&gt;
&lt;p&gt;À priori la mise à jour se fait très simplement : il vous suffit de télécharger la nouvelle version et d’écraser les anciens fichiers avec les nouveaux. Pensez à supprimer le fichier &lt;code&gt;./public/install.php&lt;/code&gt; qui ne vous sert à rien si vous faites une mise à jour, ou alors on vous redemandera les informations que vous aviez rentré à la première installation (ça marchera quand même, mais ça ne sert à rien ;)). Pas de mise à jour de la base de données cette fois-ci, donc si vous tourniez correctement avec la version 0.2, c’est tout bon.&lt;/p&gt;
&lt;h2&gt;Et la suite ?&lt;/h2&gt;
&lt;p&gt;La version 0.4 est en approche, mais il se pourrait que ce soit aussi la version 1.0, tout dépend des idées qui me viendront pour la suite. Les nouveautés à prévoir sont les suivantes :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Changer un flux de catégorie par drag and drop&lt;/li&gt;
&lt;li&gt;Version mobile : passer à l’article suivant/précédent par effet de slide (glissement du doigt vers la gauche pour aller à l’article suivant, vers la droite pour passer au précédent)&lt;/li&gt;
&lt;li&gt;Ajout de vues "Lecture" et "Globale" : la vue "Lecture" sera dépourvue d’éléments "perturbateurs", la vue "Globale" offrira une vue permettant de voir en un coup d’œil quels sites ont publié depuis votre dernière visite&lt;/li&gt;
&lt;li&gt;Optimisation de la table en base de données : c’est un petit truc que j’utilise personnellement pour réduire la place utilisée en base de données par les articles (voir &lt;a href="https://dev.mysql.com/doc/refman/5.5/en/optimize-table.html"&gt;https://dev.mysql.com/doc/refman/5.5/en/optimize-table.html&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Gérer les soucis de flux : permettra de voir quels sont les flux qui n’ont pas réussi à se mettre à jour en le mettant en rouge par exemple&lt;/li&gt;
&lt;li&gt;Possibilité de filtrer les tags en cliquant dessus (via "Tags associés" dans un article)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Si vous souhaitez voir apparaître d’autres fonctionnalités, n’hésitez pas à me les soumettre, je suis preneur ! Mais de préférence faites-le d’ici dimanche prochain : après, les demandes seront prises en compte pour la version 0.5.&lt;/p&gt;</content></entry><entry><title>Mise à jour du site - la v5 est là \o/</title><id>urn:uuid:d0fc5618-53e2-5ceb-b3d1-e0e2be7fcdfc</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/mise-a-jour-du-site-la-v5-est-la-o.html" rel="alternate" type="text/html" /><published>2013-02-28T19:20:00+01:00</published><updated>2013-02-28T19:20:00+01:00</updated><content type="html">&lt;p&gt;J’ai mis mon site à jour en fin de semaine dernière. Cette dernière version est très inspirée par &lt;a href="http://sebsauvage.net/links/"&gt;Shaarli de Sebsauvage&lt;/a&gt;, tout en allant un poil plus loin. Le principe de Shaarli est de partager des liens qui nous paraissent pertinent et de faire un rapide commentaire dessus, le tout, sans se prendre la tête. Mon problème étant que je n’ai pas que des liens à partager, et même si je n’avais que ça, ils se retrouvent assez dispersés.&lt;/p&gt;
&lt;p&gt;En gros il m’arrive de publier des liens, mais aussi des articles de blog ainsi que ce que j’appelle des statuts (oui oui, à la façon Facebook). Les liens que je partage passent soit par ma version maison de Shaarli (Links), soit par &lt;a href="https://github.com/FreshRSS/FreshRSS"&gt;mon lecteur (maison) de flux RSS (FreshRSS)&lt;/a&gt;. De plus, je pourrais envisager d’autres outils de partage.&lt;/p&gt;
&lt;p&gt;Je me retrouve donc pour le moment avec 3 outils de partage différents. Mon soucis était de tout publier automatiquement sur le site, dans un flux uni. C’est là qu’intervient mon outil Uniflux. Celui-ci permet de s’abonner à différents flux de type Uniflux et regroupe tout ce qu’il trouve dans un flux unique. Je n’ai plus qu’à afficher côté client (le site) les articles, les liens et les statuts.&lt;/p&gt;
&lt;p&gt;Ça c’était pour l’introduction... mais maintenant plusieurs questions peuvent se poser et je vais essayer d’y répondre.&lt;/p&gt;
&lt;h2&gt;Un schéma, un schéma !&lt;/h2&gt;
&lt;p&gt;Oui, de suite !&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; : il n’y a aujourd’hui plus de schéma, mais ce n’est pas grave, Uniflux n’existe plus :)&lt;/p&gt;
&lt;h2&gt;Pourquoi avoir développé un Shaarli maison ?&lt;/h2&gt;
&lt;p&gt;Bien que je pense que Sebsauvage ait fait du bon travail, tout ne me satisfait pas dans Shaarli. Tout d’abord, quasiment tout le code se trouve dans le fichier principal : il en devient presque in-maintenable et pas du tout modulaire. J’ai eu à plusieurs reprises besoin d’un morceau de code venant de Shaarli (génération du nuage de tags, récupération des thumbnails externes, etc.) et bien vite on se retrouve à devoir récupérer d’innombrables fonctions pour que ça fonctionne. C’est dommage parce que ça pourrait être super utile en étant mieux découpé ☹&lt;/p&gt;
&lt;p&gt;Autre argument, il y a trop de fonctionnalités que je n’utilise pas du tout et que je ne juge pas pertinentes pour mon usage... d’autant plus que je n’avais besoin de mon côté que de la partie "serveur".&lt;/p&gt;
&lt;p&gt;Enfin... j’aime bien tout refaire de mon côté pour manipuler un peu et apprendre par moi-même, et ça, c’est la meilleure des excuses ☺&lt;/p&gt;
&lt;h2&gt;Pourquoi avoir inventé un nouveau format (Uniflux) alors que RSS pourrait très bien faire l’affaire ?&lt;/h2&gt;
&lt;p&gt;Oui parce qu’au final Uniflux n’est qu’un agrégateur d’articles et de liens... Il y a tout de même quelques soucis avec RSS (bien que j’en sois un fervent défenseur !). Déjà, le format est lourd (le XML a du bon, mais pas sa verbosité). Uniflux se contente d’une API en JSON que je trouve certes moins lisible, mais plus légère et tout aussi efficace. De plus ça me permet de faire évoluer le format comme je l’entends.&lt;/p&gt;
&lt;p&gt;Si j’ai le courage de continuer, Uniflux gérera aussi un jour le flux de commentaires associé à un post (du coup mon site ne gère plus les commentaires, mais le ratio spam / commentaires pertinents était trop élevé pour que je passe du temps là-dessus)&lt;/p&gt;
&lt;h2&gt;Quel est l’intérêt ?&lt;/h2&gt;
&lt;p&gt;Mon soucis comme je l’ai dit est que je possède différents outils pour communiquer (le blog, Links et FreshRSS. Vu que j’ai incorporé à chacun l’export au format Uniflux, il me suffit d’ajouter l’url de l’API d’export et mon flux est automatiquement alimenté. Si jamais un jour je décide de créer un outil de gestion de fichiers, je n’aurai qu’à ajouter un export au format Uniflux pour partager des fichiers que je souhaite rendre public. Automatiquement le partage sera disponible sur mon site. À vrai dire, il me suffit d’ajouter un export au format Uniflux à n’importe quelle application web, et mon outil pourra s’y connecter naturellement et alimentera mon site.&lt;/p&gt;
&lt;p&gt;C’est un peu ma bataille à moi contre la dispersion de nos informations. En effet, je suis parti du constat que je partageais des choses sur Facebook, Google+, Diaspora*, etc. et que j’aurais bien voulu que tout se retrouve dans un flux unique. Alors j’ai décidé d’arrêter d’utiliser ces outils et de me contenter de mes propres outils. Et ça me convient parfaitement. C’est ce que je cherchais et ça répond à mes besoins. C’est simple, efficace et je l’ai fait avec mes petites mains ☺&lt;/p&gt;
&lt;h2&gt;Mais... c’est utilisable ?&lt;/h2&gt;
&lt;p&gt;Franchement ? Non. Enfin si, mais pour le moment, que par moi je pense. Ça manque de documentation, ça manque d’une idée claire sur ce que je veux gérer, ça manque d’une bonne utilisation et ça manque surtout d’énormément de recul. Je publierai le code de tout ça un de ces jours à l’état de proof of concept mais je compte remanier un peu le bouzin afin d’avoir un truc exportable. Si finalement j’arrive à clarifier mes idées, j’intégrerai tout ça dans Minz (mon framework PHP) afin de pouvoir créer des applications connectées en quelques lignes. Maiiis... ça attendra encore un peu, j’ai des partiels avant :p&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Voilà donc un rapide état des lieux du boulot fourni depuis plusieurs mois (ça fait quand même pas mal d’applications écrites). J’aime autant préciser (je le fais à la fin, mais j’aurais peut-être dû le faire au début...) : je n’assure aucun suivi sur aucune des applications que j’ai développées, mise à part Minz. Tout ce que j’ai fait a été développé dans un but personnel pour répondre à mes besoins. Néanmoins j’envisage de refondre un peu mon lecteur de flux RSS et d’assurer de la maintenance dessus.&lt;/p&gt;</content></entry><entry><title>FreshRSS : un agrégateur simple et léger</title><id>urn:uuid:b70dc675-d95f-5a81-8344-6eb7d4d0660d</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/freshrss-un-agregateur-simple-et-leger.html" rel="alternate" type="text/html" /><published>2012-10-28T14:15:00+01:00</published><updated>2012-10-28T14:15:00+01:00</updated><content type="html">&lt;p&gt;&lt;strong&gt;Note importante du 16 mai 2013&lt;/strong&gt; : le projet a &lt;strong&gt;beaucoup&lt;/strong&gt; évolué depuis cet article. Comme je vois toujours beaucoup de liens pointant ici, je tiens à vous rediriger vers des liens plus actuels.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://freshrss.org"&gt;Le site officiel&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/FreshRSS/FreshRSS"&gt;Le dépôt Github&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://demo.freshrss.org"&gt;La démo&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;L’article original du 28 octobre 2012&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Quand on parle d’agrégateurs de flux RSS, on a souvent en tête &lt;a href="http://rsslounge.aditu.de/"&gt;RSSLounge&lt;/a&gt; et &lt;a href="http://tt-rss.org"&gt;TinyTinyRSS&lt;/a&gt;, les deux poids lourds du secteur (j’exclue volontairement les solutions qu’on ne peut pas auto-héberger, vous l’avais compris). Pour certains d’entre vous, il y aura aussi &lt;a href="http://blog.idleman.fr/?p=1233"&gt;Leed&lt;/a&gt;, le petit dernier développé par Idleman. Mais aujourd’hui, je vous offre ma propre solution faite maison : FreshRSS (licence AGPL3).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tout d’abord, expliquons le pourquoi.&lt;/strong&gt; Ceux qui ont déjà manipulé RSSLounge savent que ce n’est pas franchement ce qu’il y a de plus léger. Je n’ai jamais essayé TinyTinyRSS mais tout le monde s’accorde pour dire qu’il est encore plus lourd que le précédent. J’utilisais personnellement RSSLounge tant bien que mal, en pestant plus qu’autre chose lorsque je voulais ajouter un flux RSS. La surcouche javascript rendant les choses particulièrement indigeste.
Puis vint Leed, promesse d’un agrégateur plus clair, plus léger, plus simple. Je pense que cette promesse a été tenue par Idleman. Mais voilà, je suis un éternel insatisfait et il ne m’a pas convaincu, notamment à cause de l’espace pris sur l’écran mal optimisé et le manque de raccourcis.&lt;/p&gt;
&lt;p&gt;…&lt;/p&gt;
&lt;p&gt;Bon d’accord, je me cherchais juste une excuse pour me développer mon propre agrégateur ! C’était aussi une occasion de prouver que mon framework PHP pouvait s’adapter à plusieurs usages de façon très modulaire.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bref, pour éviter de tourner autour du pot&lt;/strong&gt;, voilà ce que peut vous apporter FreshRSS :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Un système léger, non alourdi par une tonne de javascript (beaucoup de choses se font en PHP). Il y a du javascript certes, mais il sert à faciliter la navigation et tout peut fonctionner sans.&lt;/li&gt;
&lt;li&gt;Une interface que j’espère optimisée pour la lecture de vos flux&lt;/li&gt;
&lt;li&gt;Des raccourcis pour naviguer et pour marquer les articles comme lu / non lus, favoris / non favoris. &lt;strong&gt;Ces raccourcis sont paramétrables&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;L’importation / exportation OPML (attention, j’ai eu des soucis d’importation avec le fichier exporté par RSSLounge)&lt;/li&gt;
&lt;li&gt;La possibilité de lancer une tâche CRON sur l’url mettant à jour les flux&lt;/li&gt;
&lt;li&gt;Système d’authentification basé sur &lt;a href="https://persona.org/"&gt;Persona&lt;/a&gt; de Mozilla (bon, c’est encore assez bancal je trouve et ça utilise du javascript...) Personnellement je bloque l’accés à mon flux RSS par une authentification HTTP.&lt;/li&gt;
&lt;li&gt;Catégorisation des flux (comme la plupart des agrégateurs)&lt;/li&gt;
&lt;li&gt;Un affichage correct sur écran de smartphones (mais pas optimisé)&lt;/li&gt;
&lt;li&gt;Et surtout, pas trop de trucs "bling bling" ☺&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Le mieux reste de &lt;a href="http://demo.freshrss.org"&gt;tester FreshRSS&lt;/a&gt;.&lt;/strong&gt; J’ai bien évidemment bloqué l’accés à la configuration ici pour éviter que vous ne changiez tout (ce sont mes propres flux qui s’affichent ;)). Pour les touches de raccourcis, vous pouvez utiliser :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;page down&lt;/code&gt; et &lt;code&gt;page up&lt;/code&gt; pour naviguer entre les articles&lt;/li&gt;
&lt;li&gt;&lt;code&gt;gauche&lt;/code&gt; et &lt;code&gt;droit&lt;/code&gt; pour naviguer entre les pages&lt;/li&gt;
&lt;li&gt;&lt;code&gt;espace&lt;/code&gt; pour ouvrir l’article sélectionné dans un nouvel onglet&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Petite précision avant de terminer : FreshRSS a été développé dans un but strictement personnel, sans aucune prétention et s’adapte à mes propres besoins. Je n’ai pas immédiatement cherché à faire en sorte qu’il s’adapte à d’autres usages que le mien (l’ajout de la connexion via Persona est la seule exception car je ne l’utilise pas). Néanmoins, si vous souhaitez voir apparaître de nouvelles fonctionnalités vous pouvez me les soumettre... mais ce n’est pas dit que j’y réponde dans l’immédiat :p&lt;/p&gt;
&lt;p&gt;Oh, et puis ce n’est qu’une version alpha pour le moment ;)&lt;/p&gt;</content></entry><entry><title>Le changement, c’est maintenant !</title><id>urn:uuid:079344c7-aa98-51e8-93f9-4211c8e0afee</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/le-changement-c-est-maintenant.html" rel="alternate" type="text/html" /><published>2012-05-19T15:48:00+02:00</published><updated>2012-05-19T15:48:00+02:00</updated><content type="html">&lt;p&gt;Au moins pour le design de mon site. Comme je le disais dans un article précédent, je suis un éternel insatisfait du design de mon site. Mais bon, cette fois-ci c’est la bonne ! (jusqu’à la prochaine) Au menu, une simple épuration du haut du site, l’utilisation d’une police d’écriture plus agréable à l’œil, et une révision de l’affichage des articles du blog.&lt;/p&gt;
&lt;p&gt;Sans oublier quelques corrections de bugs et d’une grosse (grosse) faille (je considère que l’affichage de la configuration pour accéder comme on veut à la base de données est une faille ☺)&lt;/p&gt;</content></entry><entry><title>Sortie de MINZ 1.0 - framework PHP</title><id>urn:uuid:4e3dfcf5-33f5-562e-b9c6-f2201b2db334</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/sortie-de-minz-1-0-framework-php.html" rel="alternate" type="text/html" /><published>2012-03-24T22:53:00+01:00</published><updated>2012-03-24T22:53:00+01:00</updated><content type="html">&lt;p&gt;Et bien voilà, après quasiment un an de développement plus qu’irrégulier, j’ai le plaisir d’annoncer la version 1.0 de mon framework PHP : &lt;a href="https://github.com/marienfressinaud/MINZ"&gt;MINZ Is Not Zend&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Pour la petite histoire&lt;/h2&gt;
&lt;p&gt;J’ai commencé à développer ce framework à la base dans un but totalement personnel. Ayant pratiqué un petit peu Zend durant ma dernière année de DUT informatique, sa lourdeur m’a vite agacé. Puis voulant voir comment développer un framework, je suis parti des idées de Zend pour me bâtir ma propre architecture et manipuler un peu plus de PHP.&lt;/p&gt;
&lt;p&gt;Ainsi MINZ a été à la base de mon site personnel depuis tout ce temps, me permettant de tester à plus ou moins grande échelle les fonctionnalités dont j’avais besoin.&lt;/p&gt;
&lt;h2&gt;La présentation tirée du (court) wiki&lt;/h2&gt;
&lt;p&gt;MINZ est un framework PHP, c’est-à-dire qu’il propose une architecture particulière pour l’écriture d’applications PHP. On peut le voir comme un squelette, et l’application comme les muscles, cerveaux, peau, etc. Ce framework repose lui-même sur la modélisation MVC (pour Model View Controller). Le modèle MVC permet de séparer logiquement les données (un utilisateur avec un nom, un prénom, un mot de passe par exemple), leur représentation (la façon dont on va les afficher) et leur traitement. Cela permet d’avoir une application facile à maintenir.&lt;/p&gt;
&lt;p&gt;MINZ est fortement inspiré de &lt;a href="http://framework.zend.com/"&gt;Zend Framework&lt;/a&gt;, qui est un autre framework PHP. Bien qu’inspiré, il s’en éloigne par bien des aspects, d’où son nom en clin d’oeil : MINZ Is Not Zend. Il se veut notamment bien plus léger et plus facile à mettre en place afin de faciliter le déploiement d’applications MINZ. De par ce soucis de légèreté, il existe quelques contraintes qui le rendent moins puissant, ce qui n’est pas vraiment un soucis pour des applications simples (un blog, un site ou une galerie photos par exemple). Si vous connaissez déjà Zend Framework, il est certain que vous y trouverez de nombreuses similitudes, notamment au niveau de l’architecture.&lt;/p&gt;
&lt;p&gt;Le code de MINZ est sous licence &lt;a href="https://www.gnu.org/licenses/agpl.html"&gt;AGPL 3&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Les fonctionnalités en vrac&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Routage des urls avec url rewriting géré par PHP. Cela permet de simplifier le processus de réécriture d’urls sans se prendre la tête avec Apache. En contrepartie, le système est moins puissant, même si j’ai pensé à quelques améliorations, qui ne verront sans doute jamais le jour...&lt;/li&gt;
&lt;li&gt;En complément du routage, j’ai mis en place un système d’écriture d’urls. Ainsi, on a la possibilité d’activer ou de désactiver l’url rewriting à la volée, sans casser les liens internes au site.&lt;/li&gt;
&lt;li&gt;L’historisation du parcours des visiteurs permet de garder un fil de leur visite, permettant de mettre en place facilement des liens de retour aux pages précédentes. Je ne suis pas bien sûr de conseiller cette fonctionnalité puisqu’elle est sujette à pas mal de difficultés de mise en place.&lt;/li&gt;
&lt;li&gt;La mise en cache des pages du site basé sur MINZ est gérée automatiquement par le framework sans avoir rien à faire.&lt;/li&gt;
&lt;li&gt;L’internationalisation des applications a aussi été prise en compte à travers une classe dédiée permettant de mettre facilement en place différentes langues pour le site.&lt;/li&gt;
&lt;li&gt;Un système a été développé pour faciliter la pagination de listes (d’articles de blog par exemple)&lt;/li&gt;
&lt;li&gt;Et enfin, une classe pour logguer les erreurs, warnings et autres actions nécessitant d’être logguées ;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Et la suite ?&lt;/h2&gt;
&lt;p&gt;Aujourd’hui j’ai sorti la version 1.0 après plus d’un mois en version alpha... J’avoue que j’ai pris mon temps : j’attendais d’avoir terminé la documentation (sous licence &lt;a href="https://creativecommons.org/licenses/by-sa/2.0/"&gt;CC BY-SA&lt;/a&gt;), et ça ne me motivait plus du tout. Alors la suite, je ne pense pas faire de gros changements au framework, seulement des mises à jour de bugs. Même si une roadmap est en place sur la page GitHub dédiée, ce qui y est indiqué ne verra sans doute pas le jour. Sauf si quelqu’un a envie de se lancer là-dedans ;)&lt;/p&gt;
&lt;p&gt;À vrai dire je commence à en avoir marre de développer uniquement des applications web, et j’ai envie de passer à autre chose. J’ai d’autres projets qui cogitent, et j’ai envie de me lancer là-dedans.&lt;/p&gt;
&lt;h2&gt;Au final et en guise de conclusion&lt;/h2&gt;
&lt;p&gt;Je suis vraiment content d’en être arrivé là avec mon "semblant de framework" comme je l’appelais il y a un an. Au départ c’était totalement un projet pour moi-même, pour voir ce dont j’étais capable et en étant persuadé que j’arrêrais 1 mois plus tard. C’est mon premier vrai gros projet qui peut avoir une réelle utilité. J’ai appris nettement plus de choses en développant mon framework que ce que tous les sites et profs ont pu essayer de m’apprendre en PHP (bien qu’ils m’aient appris beaucoup de choses !). Et puis ça fait toujours du bien d’arriver à mener un projet à son terme, surtout après un an de développement ☺&lt;/p&gt;</content></entry><entry><title>Sortie de MINZ 0.5</title><id>urn:uuid:46fcd9ec-e7a3-55d2-998c-0b29a76c464e</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/sortie-de-minz-0-5.html" rel="alternate" type="text/html" /><published>2012-02-12T23:12:00+01:00</published><updated>2012-02-12T23:12:00+01:00</updated><content type="html">&lt;p&gt;Après la mise à jour du site hier, j’ai décidé de mettre à jour mon framework PHP, MINZ.&lt;/p&gt;
&lt;p&gt;Au programme, pas mal de grosses nouveautés plus ou moins utiles : gestion de l’internationalisation, amélioration de la gestion des sessions, ajout d’un historique de navigation, des classes toutes faites pour gérer les utilisateurs, arrivée des exceptions et de nombreuses corrections de bugs.&lt;/p&gt;
&lt;p&gt;L’application de tests a été revue au passage pour montrer les nouveautés. La connexion se fait à travers le système OpenID que je prends en charge nativement dans MINZ (en plus du protocole XMPP). Ces deux systèmes font leur arrivée par la petite porte ; à comprendre que MINZ ne prend en charge que la phase de connexion. De plus, pour ce qui est de XMPP il y a un problème lorsque je l’utilise sur ce serveur et je suppose que c’est le port 5222 qui est bloqué, ce qui m’empêche de l’utiliser.&lt;/p&gt;
&lt;p&gt;Pour ce qui est des exceptions, je n’ai pas encore trop poussé le concept et il y a encore un gros boulot à faire de ce côté là. Mais je pense que dans le futur ce sera bien plus efficace et très utile pour le coeur du framework.&lt;/p&gt;
&lt;p&gt;Un petit mot sur l'internationalisation : la classe &lt;code&gt;Translate&lt;/code&gt; me permet à partir d'une "clé" d’aller piocher dans des fichiers de traduction la valeur correspondante à la langue désirée. Je ne l’utilise pas sur le site, mais l’application de test permet de montrer le principe.&lt;/p&gt;
&lt;p&gt;Un autre petit plus à l’application de tests, c’est l’affichage des logs de l’application.&lt;/p&gt;
&lt;p&gt;Pour finir dans les choses importantes, l’historique de navigation permet de créer un lien pointant vers une page déjà visitée précédemment. Je l’utilise sur le site pour mes liens de retour. Cela permet de ne pas perdre la navigation et ça fonctionne à peu près comme l’historique du navigateur (même si des problèmes techniques m’empêchent de pousser le concept jusqu’au bout). Par exemple, si vous cliquez sur le lien pour accéder à la page de présentation de MINZ, le lien "retour" présent sur la page vous permettra de revenir à la page où vous êtes actuellement ☺&lt;/p&gt;
&lt;p&gt;Ce qui est prévu pour la suite : amélioration de la structure du framework avec l’utilisation poussée des exceptions PHP, création d’une classe permettant de gérer facilement la mise en cache, création de nouveaux &lt;code&gt;Models&lt;/code&gt;, de la documentation (/!) et bien sûr, l’habituelle correction de bugs ☺&lt;/p&gt;
&lt;p&gt;À bientôt j’espère pour une version 0.6 !&lt;/p&gt;</content></entry><entry><title>La v4 nouvelle est arrivée</title><id>urn:uuid:08030e9e-1a7c-5f66-aed9-dc82188ef2f9</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/la-v4-nouvelle-est-arrivee.html" rel="alternate" type="text/html" /><published>2012-02-11T16:52:00+01:00</published><updated>2012-02-11T16:52:00+01:00</updated><content type="html">&lt;p&gt;La dernière grosse mise à jour du site datait de juillet dernier. Aujourd’hui, je passe à la v4 du site, et ce n’est pas pour me déplaîre !&lt;/p&gt;
&lt;p&gt;Au menu, de nombreuses améliorations pour faciliter la navigation sur le site, et l’administration de mon côté.&lt;/p&gt;
&lt;h2&gt;Une nouvelle manière de me connecter&lt;/h2&gt;
&lt;p&gt;C’est une chose qui me trottait en tête depuis un moment, et c’est chose (plus ou moins) faite. L’identification sur le site passe par XMPP. Je n’ai qu’à entrer mes identifiants, le serveur se charge alors d’interroger le serveur XMPP correspondant qui dit si oui ou non les identifiants sont ok.
Trouvant la chose bien utile, et permettant de démocratiser le XMPP, j’ai décidé d’intégrer cette façon de faire nativement dans MINZ.
Mais malheureusement, vu qu’une bonne nouvelle n’arrive jamais seule, cela ne fonctionne pas comme il faut actuellement sur le serveur. Je suppose que c’est une histoire de pare-feu qui bloque le port 5222 (le port utilisé par XMPP) ☹&lt;/p&gt;
&lt;p&gt;Du coup, poussé par ce besoin de ne pas éparpiller mes identifiants, et l’envie de découvrir d’autres choses, je me suis penché sur &lt;a href="https://fr.wikipedia.org/wiki/Openid"&gt;OpenId&lt;/a&gt;... et finalement, ça marche plutôt bien ☺ L’identification se passera donc ainsi, mais j’ai dans l’idée d’offrir le choix. Puis ça me permettra de mettre en place le &lt;a href="https://fr.wikipedia.org/wiki/Fabrique_%28patron_de_conception%29"&gt;design pattern Factory&lt;/a&gt; :p&lt;/p&gt;
&lt;h2&gt;Une refonte partielle du design&lt;/h2&gt;
&lt;p&gt;C’est un de mes principaux défauts, je suis un éternel insatisfait du design. Il me faut toujours le reprendre. Celui-ci, se basant grandement sur le thème précédent voit disparaître la colonne de droite pour l’insérer dans le footer. Le header voit sa place réduite au strict minimum. Du coup, le contenu du site se retrouve vraiment mis en avant.&lt;/p&gt;
&lt;p&gt;La flèche permettant de remonter en haut de la page reste désormais toujours affichée en bas à droite de l’écran.
À part ça, j’ai essayé d’homogénéiser toute l’interface afin de ne pas avoir une interface trop brouillone.&lt;/p&gt;
&lt;h2&gt;Du nouveau pour le blog&lt;/h2&gt;
&lt;p&gt;Le blog se dote aussi de son lot de nouveautés. Les tags tout d’abord : afin de décrire plus précisément mes articles, j’ai toujours trouvé les tags super pratiques. J’ai eu un peu de mal à me décider sur une implémentation mais j’ai décidé de m’inspirer du Shaarli de SebSauvage au final. Un nuage de tags a été intégré en bas de la page, et &lt;del&gt;le gros du travail va être désormais de mettre à jour les différents articles déjà publiés pour les tagger.&lt;/del&gt; -&amp;gt; c’est fait ☺&lt;/p&gt;
&lt;p&gt;De plus, désormais j’aurai la possibilité d’enregistrer mes articles à venir sous forme de brouillons. Très pratique si je veux revenir sur mes articles tout en pouvant les prévisualiser, sans avoir à passer par un autre éditeur.&lt;/p&gt;
&lt;p&gt;Enfin, depuis un petit moment j’ai enlevé les commentaires sur le blog. Le choix s’expliquant par le fait que je n’ai aucun commentaire réellement "intéressant" et que je me fais polluer par le spam (oui je pourrais ajouter un captcha, mais je n’aime pas ce système). Sur le coup je l’ai fait assez "salement", mais désormais, j’ai une option codée à peu près correctement et je pourrai les (dés)activer comme bon me semble. Et pour la peine, ceux-ci sont réouverts (d’autant plus que la suppression du spam n’aura jamais été aussi simple que maintenant ☺)&lt;/p&gt;
&lt;h2&gt;Des nouveautés en vrac&lt;/h2&gt;
&lt;p&gt;L’habituelle correction de bugs est bien entendue au rendez-vous. Quelques ajouts par-ci par-là au niveau de l’administration ainsi que quelques révisions dans la manière de coder me permettent d’avoir un code plus propre et un site plus stable ☺&lt;/p&gt;
&lt;h2&gt;En conclusion&lt;/h2&gt;
&lt;p&gt;J’ai hésité à estampiller cette version de "4", mais vu que la mécanique du site ressent quand même un gros changement et que j’ai ajouté à peu près toutes les idées qui me restaient en tête, je pense que cette version le mérite ☺&lt;/p&gt;</content></entry><entry><title>Màj du site sous MINZ 0.4</title><id>urn:uuid:da420cc0-f4bd-5c70-8d93-efe0b75cf183</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/maj-du-site-sous-minz-0-4.html" rel="alternate" type="text/html" /><published>2011-11-11T20:43:00+01:00</published><updated>2011-11-11T20:43:00+01:00</updated><content type="html">&lt;p&gt;Article rapide pour indiquer que j’ai passé mon site sous la dernière version de mon framework. Avec ça arrive ma nouvelle galerie photos développée par mes soins.
Notez que tout ce qui est url rewriting est géré par le framework, et ça c’est top ☺&lt;/p&gt;
&lt;p&gt;Bref, la migration s’est bien passée ;)&lt;/p&gt;
&lt;p&gt;EDIT. J’en ai profité pour mettre à jour l’application MINZ de tests, et je l’ai passé en version... 0.5 beta ! ☺ C’est donc la version encore en développement. Au programme notamment, l’internationalisation, qui a été plus facile à mettre en place que ce que je ne croyais. J’en ai aussi profité pour épurer encore plus le design de base ^^ ... oh :O je viens de découvrir une grosse faille en l’installant ☺&lt;/p&gt;</content></entry><entry><title>Sortie de Minz 0.4</title><id>urn:uuid:6126890d-d2dd-5fa0-8996-817e799f9b54</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/sortie-de-minz-0-4.html" rel="alternate" type="text/html" /><published>2011-10-30T16:31:00+01:00</published><updated>2011-10-30T16:31:00+01:00</updated><content type="html">&lt;p&gt;Suite à la version 0.3 du mois précédent j’avais quelques améliorations à apporter à mon framework.&lt;/p&gt;
&lt;p&gt;Tout d’abord, le routage des urls internes au site avait été un gros morceau, mais très incomplet à mes yeux. Aussi j’avais vraiment besoin d’améliorer ceci. C’est désormais chose faite : quelques bugs ont été corrigés et surtout, le routage d’urls dynamiques est désormais possible ! ☺
Ainsi, si on définit le code suivant (tiré de mon appli de galeries photos) dans la table de routage :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="x"&gt;array(&lt;/span&gt;
&lt;span class="x"&gt;    &amp;#39;route&amp;#39;       =&amp;gt; &amp;#39;/see/galerie/*/photo/*&amp;#39;,&lt;/span&gt;
&lt;span class="x"&gt;    &amp;#39;controller&amp;#39;  =&amp;gt; &amp;#39;index&amp;#39;,&lt;/span&gt;
&lt;span class="x"&gt;    &amp;#39;action&amp;#39;      =&amp;gt; &amp;#39;see&amp;#39;,&lt;/span&gt;
&lt;span class="x"&gt;    &amp;#39;params&amp;#39;      =&amp;gt; array(&amp;#39;gal&amp;#39;, &amp;#39;photo&amp;#39;)&lt;/span&gt;
&lt;span class="x"&gt;),&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;l’url &lt;code&gt;http://test.exemple/see/galerie/2/photo/42&lt;/code&gt; (par exemple) sera routée vers le contrôleur &lt;code&gt;index&lt;/code&gt;, l’action &lt;code&gt;see&lt;/code&gt;, et avec les paramètres &lt;code&gt;$_GET['gal']=2&lt;/code&gt; et &lt;code&gt;$_GET['photo']=42&lt;/code&gt;. C’était vraiment un gros morceau, pas facile à mettre en place, mais je suis content de l’avoir fait !&lt;/p&gt;
&lt;p&gt;Un autre morceau que je voulais coder était une classe de configuration, au lieu de passer par des constantes globales. J’en ai profité pour revoir le fichier de configuration qui sera désormais un fichier &lt;code&gt;.ini&lt;/code&gt; (même si le fichier de constantes est pris en charge). Les paramètres &lt;code&gt;environment&lt;/code&gt; et &lt;code&gt;use_url_rewriting&lt;/code&gt; ont été ajoutés et sont indispensables. &lt;code&gt;environment&lt;/code&gt; permet de définir un niveau de verbosité (les logs et les erreurs seront plus ou moins bavards). &lt;code&gt;use_url_rewriting&lt;/code&gt; quant à lui sert à dire si on souhaite utiliser l’url_rewriting ou non. D’ailleurs il n’existe pas de fonction php servant à savoir si ce module est activé ou non, et c’est bien dommage ☹&lt;/p&gt;
&lt;p&gt;Je viens de citer les logs. En effet, je trouvais ça intéressant de les intégrer au cœur du framework afin de débugguer une application. Pour le moment c’est perfectible, mais je suis content du résultat.&lt;/p&gt;
&lt;p&gt;J’ai ajouté une classe &lt;code&gt;Url&lt;/code&gt; permettant de créer dynamiquement les urls internes au site. En effet, à cause de l’url rewriting et de mon système de routage, il pouvait y avoir des problèmes si jamais le serveur ne permet pas de réécrire les url. Mais maintenant c’est de l’histoire ancienne ! ☺ La classe &lt;code&gt;Url&lt;/code&gt;, à travers sa méthode statique &lt;code&gt;display()&lt;/code&gt; va s’occuper de voir si on utilise l’url rewriting (à travers le paramètre de configuration déjà nommé plus haut). Si oui, il va chercher dans la table de routage si l’url que l’on souhaite écrire possède une route et si oui, la construit pour l’affichage. Si non, il construit l’url de façon plus basique (du type &lt;code&gt;http://test.exemple/?c=blog&amp;amp;a=voir&amp;amp;id=42&lt;/code&gt; ). Au final ça rend le framework très puissant car il gère tout seul l’url rewriting, et on n’a plus à se soucier de savoir si le module est activé sur le serveur ☺
Et pour construire l’url, la ligne suivante suffit :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="x"&gt;echo $this-&amp;gt;url-&amp;gt;display(array(&lt;/span&gt;
&lt;span class="x"&gt;    &amp;#39;c&amp;#39; =&amp;gt; &amp;#39;blog&amp;#39;,&lt;/span&gt;
&lt;span class="x"&gt;    &amp;#39;a&amp;#39; =&amp;gt; &amp;#39;see&amp;#39;,&lt;/span&gt;
&lt;span class="x"&gt;    &amp;#39;params&amp;#39; =&amp;gt; array(&amp;#39;id&amp;#39; =&amp;gt; 42)&lt;/span&gt;
&lt;span class="x"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;... bon d’accord, ça peut paraître lourd, mais au vu des bénéfices, je pense que ça vaut largement le coup ;)&lt;/p&gt;
&lt;p&gt;Enfin, dernière amélioration importante, la gestion des pages d’erreurs a été améliorée. Avant, je me contentais d’afficher une page blanche avec les messages d’erreurs. Désormais, les erreurs peuvent être intégrées au design du site. Comme dit précédemment, les erreurs affichées sont gérées grâce au niveau de verbosité défini par le paramètre de configuration &lt;code&gt;environment&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Et sinon j’ai corrigé plusieurs petits bugs, fait quelques retouches, bricolé par-ci par-là. Bref, cette version 0.4 n’est plus vraiment compatible avec les versions précédentes, bien qu’une migration puisse sans doute se faire sans trop de mal. Je l’ai bien fait pour mon appli de galeries photos ;)
Le plus compliqué sera de migrer mon site sur cette version, mais ça vaudra surement le coup ! J’ai vraiment hâte d’intégrer les urls dynamiques et ma galerie photos... malheureusement ma connexion Internet ne me permet pas de faire du ftp ni sftp. Bref, ça va encore devoir attendre ;)&lt;/p&gt;
&lt;p&gt;Pour la prochaine version, j’espère pouvoir intégrer une classe pour gérer l’internationalisation du site (ce qui va demander pas mal de boulot), corriger des bugs (en espérant que cela ne soit pas nécessaire :p), améliorer tout ce qui est &lt;code&gt;Model&lt;/code&gt; et &lt;code&gt;DAO&lt;/code&gt; et surtout, proposer de la documentation conséquente ! J’ai déjà commencé à réaliser un document, mais ça demande pas mal de boulot pour synthétiser, faire des exemples, des schémas, etc. Puis avec cette nouvelle version, il y a quelques bidules à remanier...&lt;/p&gt;</content></entry><entry><title>Minz 0.3</title><id>urn:uuid:35b768a7-1c77-54f1-a175-2134429cca6c</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/minz-0-3.html" rel="alternate" type="text/html" /><published>2011-09-11T11:30:00+02:00</published><updated>2011-09-11T11:30:00+02:00</updated><content type="html">&lt;p&gt;Quelques jours seulement après la version 0.2, je sors cette version 0.3.&lt;/p&gt;
&lt;p&gt;Quelles nouveautés alors ? Et bien deux gros morceaux que je voulais absolument implémenter et qui me limitaient un peu dans mes divers développement.&lt;/p&gt;
&lt;p&gt;Tout d’abord, la réécriture d’url à travers un module de routes. Comment ça marche ? Et bien regardez l’url dans la barre de votre navigateur qui doit être ici du genre &lt;code&gt;http://marienfressinaud.fr/?c=blog&lt;/code&gt;, ce qui signifie que le controller de l’application se nomme &lt;code&gt;blog&lt;/code&gt;. Avec cette version, j’aurai la possibilité de transformer cette url en &lt;code&gt;http://marienfressinaud.fr/blog&lt;/code&gt;. Ce n’est pas grand chose, et c’est facilement faisable avec un fichier &lt;code&gt;.htaccess&lt;/code&gt;, mais j’avais la volonté de le faire directement à travers le framework. Le morceau de code qui fera ça est on ne peut plus simple :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="x"&gt;return array(&lt;/span&gt;
&lt;span class="x"&gt;    array(&lt;/span&gt;
&lt;span class="x"&gt;        &amp;#39;route&amp;#39;       =&amp;gt; &amp;#39;/blog&amp;#39;,&lt;/span&gt;
&lt;span class="x"&gt;        &amp;#39;controller&amp;#39;  =&amp;gt; &amp;#39;blog&amp;#39;,&lt;/span&gt;
&lt;span class="x"&gt;        &amp;#39;action&amp;#39;      =&amp;gt; &amp;#39;index&amp;#39;&lt;/span&gt;
&lt;span class="x"&gt;    )&lt;/span&gt;
&lt;span class="x"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;avec possibilité de rajouter autant de routes que l’on veut évidemment ;) Ainsi, lorsque l’on regarde un article en particulier, par exemple à l’url &lt;code&gt;http://marienfressinaud.fr/?c=blog&amp;amp;a=voir&amp;amp;id=62&lt;/code&gt;, on peut rajouter un peu de code :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="x"&gt;return array(&lt;/span&gt;
&lt;span class="x"&gt;    array(&lt;/span&gt;
&lt;span class="x"&gt;        &amp;#39;route&amp;#39;       =&amp;gt; &amp;#39;/blog&amp;#39;,&lt;/span&gt;
&lt;span class="x"&gt;        &amp;#39;controller&amp;#39;  =&amp;gt; &amp;#39;blog&amp;#39;,&lt;/span&gt;
&lt;span class="x"&gt;        &amp;#39;action&amp;#39;      =&amp;gt; &amp;#39;index&amp;#39;&lt;/span&gt;
&lt;span class="x"&gt;    ),&lt;/span&gt;
&lt;span class="x"&gt;    array(&lt;/span&gt;
&lt;span class="x"&gt;        &amp;#39;route&amp;#39;       =&amp;gt; &amp;#39;/blog/voir&amp;#39;,&lt;/span&gt;
&lt;span class="x"&gt;        &amp;#39;controller&amp;#39;  =&amp;gt; &amp;#39;blog&amp;#39;,&lt;/span&gt;
&lt;span class="x"&gt;        &amp;#39;action&amp;#39;      =&amp;gt; &amp;#39;voir&amp;#39;&lt;/span&gt;
&lt;span class="x"&gt;    )&lt;/span&gt;
&lt;span class="x"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;et l'url &lt;code&gt;http://marienfressinaud.fr/blog/voir?id=62&lt;/code&gt; emmènera au même article. On voit d'ailleurs ici la limitation avec les urls un peu dynamiques, je ne gère pas encore les paramètres supplémentaires comme ici &lt;code&gt;id&lt;/code&gt;, mais j'y pense ;)
Bon, je n'utilise pas encore cette nouvelle version sur ce site parce que ça demandera un peu plus de travail pour l'intégrer et que ma connexion internet ne me le permet pas :p&lt;/p&gt;
&lt;p&gt;Deuxième fonctionnalité, aussi importante à mes yeux, l'ajout d'un bootstrap d'application. À quoi il sert celui-là ? En fait ce bootstrap pourra être modifié directement par le développeur pour automatiser certaines tâches. Par exemple, dans chacun de mes controllers, j'ai les lignes (entre autres)&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="x"&gt;$this-&amp;gt;view-&amp;gt;prependStyle(DOMAIN.&amp;#39;/themes/default/base.css&amp;#39;);&lt;/span&gt;
&lt;span class="x"&gt;$this-&amp;gt;view-&amp;gt;prependScript(DOMAIN.&amp;#39;/scripts/jquery.js&amp;#39;);&lt;/span&gt;
&lt;span class="x"&gt;$this-&amp;gt;view-&amp;gt;user = new User();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;ce qui devient très vite rébarbatif. Et bien ce bootstrap me permettra de les charger automatiquement grâce à sa méthode &lt;code&gt;run()&lt;/code&gt;. De ce fait, je n’aurai qu’à l’écrire une fois, et tous mes controllers seront impactés donc il y a quand même un certain gain en temps ☺&lt;/p&gt;
&lt;p&gt;J’espère que ça intéressera quelqu’un, surtout que d’un point de vue personnel, je trouve mon framework très bien et de plus en plus puissant (oui oui, je suis très objectif ! :D)&lt;/p&gt;</content></entry><entry><title>MINZ 0.2</title><id>urn:uuid:ce53ea95-9c32-56f6-9237-d667ed023556</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/minz-0-2.html" rel="alternate" type="text/html" /><published>2011-08-26T22:14:00+02:00</published><updated>2011-08-26T22:14:00+02:00</updated><content type="html">&lt;p&gt;Voilà voilà, j’ai fait quelques améliorations du code aujourd’hui de mon petit framework. Deux ajouts importants : l’ajout de la classe &lt;code&gt;Paginator&lt;/code&gt; pour faciliter la pagination et la gestion des &lt;code&gt;magic_quotes&lt;/code&gt;.
J’en ai aussi profité pour commenter la librairie (pas la partie application qui sert un peu moins je pense) et pour ajouter un fichier FEATURES : en gros ce que j’aimerais ajouter avant de sortir la version 1.0 comme la possibilité de créer des "routes" (indiquer que &lt;code&gt;bidule.com/test/index&lt;/code&gt; correspond au contrôleur &lt;code&gt;test&lt;/code&gt; et l’action &lt;code&gt;index&lt;/code&gt; par exemple et étendre le bootstrap pour que l’utilisateur puisse gérer directement dans son propre bootstrap des actions exécutées fréquemment. Ça ferait que je pourrais avoir de jolies url et, aussi, automatiser certaines tâches qui sont souvent pénibles à recopier.&lt;/p&gt;
&lt;p&gt;Vous remarquerez aussi que je ne m’embête pas avec la numérotation des versions... Du moment que ça monte de toutes façons, moi, ça me va ;)&lt;/p&gt;
&lt;p&gt;P.S. Si vous comptez l’utiliser, ou juste le tester, n’hésitez pas à me laisser un commentaire histoire que je sache si je bosse que pour moi ou non ☺&lt;/p&gt;</content></entry><entry><title>MINZ Is Not Zend</title><id>urn:uuid:b52548d5-6fa6-5375-84fa-33147a124812</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/minz-is-not-zend.html" rel="alternate" type="text/html" /><published>2011-08-12T08:55:00+02:00</published><updated>2011-08-12T08:55:00+02:00</updated><content type="html">&lt;p&gt;Voilà voilà ☺
Ça fait un moment que je devais le faire, c’est chose faite : j’ai mis en ligne mon petit framework PHP. Pour son nom c’est évidemment un clin d’oeil au &lt;a href="https://secure.wikimedia.org/wikipedia/fr/wiki/Gnu"&gt;projet GNU&lt;/a&gt; (pour GNU’s Not UNIX) et à &lt;a href="http://framework.zend.com/"&gt;Zend Framework&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Pour la petite histoire, j’ai découvert Zend cette année durant mon projet tuteuré de DUT et ça m’a pas mal inspiré. J’avais plein de projets en tête et il me fallait un framework. Trouvant que ceux existant ne s’appliquaient pas à mes petits projets, j’ai décidé de m’en coder un tout seul. C’est comme ça qu’est donc né ce framework. À vrai dire ça a été très intéressant car j’ai pu me pencher sur tout un tas de trucs que je ne connaissais pas et qui sont vraiment géniaux ! ☺&lt;/p&gt;
&lt;p&gt;Ceci dit, MINZ est certes très léger, mais il manque encore un peu de flexibilité. J’aurai tout un tas de petites choses à ajouter (notamment étendre le bootstrap pour l’application elle-même). Cependant, il se tient déjà très bien comme ça, la preuve, mon site personnel tourne sous MINZ ;)&lt;/p&gt;
&lt;p&gt;Je n’ai pas (encore) écrit de documentation, cependant, vu qu’il repose sur plusieurs mécanismes de Zend, si vous connaissez déjà ce dernier, l’utilisation de MINZ en sera très facile. Il repose d’ailleurs aussi sur le modèle &lt;a href="https://secure.wikimedia.org/wikipedia/fr/wiki/Mod%C3%A8le-Vue-Contr%C3%B4leur"&gt;MVC&lt;/a&gt;. De plus, la mini-application fournie avec celui-ci permet d’en comprendre très facilement le fonctionnement... en tout cas je l’espère. J’ai commenté la partie qui permet de gérer la base de données (dans la configuration et dans le modèle "User") afin que même si je n’utilise pas la BD ici, vous puissiez comprendre facilement comment l’utiliser.&lt;/p&gt;
&lt;p&gt;Bref ! N’hésitez pas à l’utiliser, à le modifier, le sécuriser, etc. Je n’ai qu’un souhait, ne pas l’avoir fait pour moi seul. Le code est bien évidemment placé sous licence &lt;a href="https://www.gnu.org/licenses/agpl.html"&gt;AGPL 3&lt;/a&gt; comme mes autres applications ;)&lt;/p&gt;</content></entry><entry><title>v3 du site</title><id>urn:uuid:5e13e043-2496-5e0e-988f-c685216bf390</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/v3-du-site.html" rel="alternate" type="text/html" /><published>2011-07-10T20:38:00+02:00</published><updated>2011-07-10T20:38:00+02:00</updated><content type="html">&lt;p&gt;Sinon, niveau nouveautés, j'ai atteint je crois la v3 de mon site (2 mois après la précédente :D) En fait ça devenait assez urgent parce que la structure précédente n'était pas suffisamment "modulable". Donc en nouveautés, on peut retrouver : le design général (toujours assez bleu, mais avec une pointe de orange), des liens pour me suivre (dans la colonne à droite), une mise en avant de mes projets et de ma galerie photos sur la page d'accueil, l'utilisation de la dernière version de mon "framework" PHP maison (oui il faut que je le mette en ligne lui aussi :$), et enfin, l'utilisation de nouveaux smileys ! :D Pour ces derniers je tiens à remercier &lt;a href="http://graphism.fr/"&gt;Geoffrey Dorne&lt;/a&gt; qui m'a gentiment autorisé à utiliser ses smileys sur mon site. Je l'ai ajouté dans ma liste "crédits" de la page "À propos". Les précédents étaient assez encombrants, et vu que j'en utilise toujours en grand nombre, je trouvais ceux de Geoffrey plus sobres et donc mieux adaptés à mon site. Et donc si vous souhaitez pouvoir les utiliser, il faut d'abord lui demander l'autorisation (via son site par exemple), merci de respecter son travail ;)&lt;/p&gt;
&lt;p&gt;Tout ça m'a demandé quand même pas mal de travail parce que la dernière version de mon framework m'a imposé de nouvelles règles donc je me suis amusé à tout recoder... Au final je suis plutôt content parce que je trouve le rendu plus sûr et surtout plus "pro".
J'ai aussi modifié ma méthode de coder le CSS afin de le rendre plus clair et plus lisible. J'essaye désormais de faire ressortir l'aspect html du site, et je sépare aussi la structure de l'aspect graphique.&lt;/p&gt;
&lt;p&gt;Pour terminer, je vous demanderai simplement, si vous remarquez des bugs d'affichage sur le site, de me les indiquer par mail (l'adresse est à droite ;)). Je n'ai en fait testé que sous Mozilla Firefox 5, et Chromium 12, le tout sous Gnu/Linux, donc pas vraiment représentatif ^^ Mais je ne pense pas qu'il y ait &lt;strong&gt;trop&lt;/strong&gt; de problèmes... mais avec Internet Explorer hein :p&lt;/p&gt;
&lt;p&gt;P.S. depuis quelques temps j'ai la chance d'avoir une série de spams dans les commentaires, donc il ne faut pas s'inquiéter des messages bizarres. J'ai pas vraiment envie de mettre en place un captcha (trop contraignant), mais si le problème dure trop, j'activerai la modération (un &lt;code&gt;false&lt;/code&gt; à passer à &lt;code&gt;true&lt;/code&gt; et hop ! :D)&lt;/p&gt;
&lt;p&gt;&lt;del&gt;Ah oui puis pour le moment le flux rss n'a pas été recodé donc pas accessible, désolé ☹&lt;/del&gt; Corrigé ☺&lt;/p&gt;</content></entry><entry><title>marienfressinaud.fr v2</title><id>urn:uuid:00888d58-ed7b-5bf6-bf47-b8140dae6a27</id><author><name>Marien Fressinaud</name></author><link href="https://marienfressinaud.fr/2011-04-01-marienfressinaud-fr-v2.html" rel="alternate" type="text/html" /><published>2011-04-01T20:08:00+02:00</published><updated>2011-04-01T20:08:00+02:00</updated><content type="html">&lt;p&gt;Et voilà une petite v2 du site ! ☺&lt;/p&gt;
&lt;p&gt;Côté visiteurs, pas grand chose qui change (mise à part sans doute au niveau du blog qui est mieux intégré, avec possibilité maintenant de laisser des commentaires ;))&lt;/p&gt;
&lt;p&gt;Par contre, désormais j’ai une petite zone "administration" qui est tout à fait sympathique et beaucoup plus agréable que de taper du texte en dur !&lt;/p&gt;
&lt;p&gt;Tout ça m’aura pris un certain nombre d’heures, mais le jeu en valait la chandelle ☺ J’ai pu améliorer mon &lt;strong&gt;semblant&lt;/strong&gt; de framework pour le sécuriser un peu plus. En effet j’ai récupéré ce que j’avais commencé à faire pour mon projet MyCalendar, qui ne demande pas beaucoup de sécurité puisqu’il est censé être installé uniquement en local dans un but personnel ;) Mais là vu que le site est accessible à n’importe qui, il a fallu que je m’assure de la sécurité... et je suis plutôt content ☺&lt;/p&gt;
&lt;p&gt;Le passage de local au serveur s’est très bien passé et j’ai été plutôt bluffé d’ailleurs. Mais je suppose que ça vient du fait que je suis de plus au plus au point niveau PHP et que j’ai pensé à pas mal de choses au préalable.
Bon par contre c’est sûr, il reste encore un peu de boulot avant de pouvoir partager les sources, mais une fois que ce sera bon, je mettrai à jour la zone "projets" ;)&lt;/p&gt;</content></entry></feed>